annotated tag v1.7.1 created (now 77a4814)
This is an automated email from the git hooks/post-receive script. New change to annotated tag v1.7.1 in repository jaxx. See https://gitlab.nuiton.org/nuiton/jaxx.git at 77a4814 (tag) tagging dd03db66a2bd680fa71f3dc97aed37a17f109b20 (commit) replaces jaxx-1.6.0-alpha-1@1425 tagged by Tony Chemit on Tue Aug 25 20:12:25 2009 +0000 - Log ----------------------------------------------------------------- [maven-scm] copy for tag jaxx-1.7.1 ----------------------------------------------------------------------- This annotated tag includes the following new commits: new d76800c [maven-scm] copy for tag jaxx-1.7.1 new baab588 [maven-scm] copy for tag jaxx-1.7.1 new ef6ee08 fix mavenpom... new afc92c8 fix pom... new dd03db6 [maven-scm] copy for tag jaxx-1.7.1 The 5 revisions listed above as "new" are entirely new to this repository and will be described in separate emails. The revisions listed as "adds" were already present in the repository and have only been added to this reference. Detailed log of new commits: commit dd03db66a2bd680fa71f3dc97aed37a17f109b20 Merge: afc92c8 de1aac7 Author: Tony Chemit <chemit@codelutin.com> Date: Tue Aug 25 20:12:25 2009 +0000 [maven-scm] copy for tag jaxx-1.7.1 commit afc92c822c3fffed8a4e929f725351b523a5a9af Author: Tony Chemit <chemit@codelutin.com> Date: Mon Aug 24 10:21:25 2009 +0000 fix pom... commit ef6ee08492e8bdc2a9e78b29af34ec15efe54197 Author: Tony Chemit <chemit@codelutin.com> Date: Mon Aug 24 10:03:02 2009 +0000 fix mavenpom... commit baab58817b78e5d0d21664ff9e0444a9f381f020 Author: Tony Chemit <chemit@codelutin.com> Date: Sun Aug 23 16:16:50 2009 +0000 [maven-scm] copy for tag jaxx-1.7.1 commit d76800ca0a3e3d9640edbdee09198d651c125f9c Author: Sylvain Letellier <???> Date: Wed Jul 15 11:24:55 2009 +0000 [maven-scm] copy for tag jaxx-1.7.1 -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.
This is an automated email from the git hooks/post-receive script. New commit to annotated tag v1.7.1 in repository jaxx. See https://gitlab.nuiton.org/nuiton/jaxx.git commit d76800ca0a3e3d9640edbdee09198d651c125f9c Author: Sylvain Letellier <???> Date: Wed Jul 15 11:24:55 2009 +0000 [maven-scm] copy for tag jaxx-1.7.1 -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.
This is an automated email from the git hooks/post-receive script. New commit to annotated tag v1.7.1 in repository jaxx. See https://gitlab.nuiton.org/nuiton/jaxx.git commit baab58817b78e5d0d21664ff9e0444a9f381f020 Author: Tony Chemit <chemit@codelutin.com> Date: Sun Aug 23 16:16:50 2009 +0000 [maven-scm] copy for tag jaxx-1.7.1 --- trunk/LICENSE.txt | 166 + trunk/README.txt | 2 + trunk/changelog.txt | 41 + trunk/jaxx-compiler/LICENSE.txt | 166 + trunk/jaxx-compiler/README.txt | 2 + trunk/jaxx-compiler/changelog.txt | 120 + trunk/jaxx-compiler/pom.xml | 54 + .../jaxx-compiler/src/main/java/jaxx/ClassMap.java | 96 + .../src/main/java/jaxx/CompilerException.java | 52 + .../src/main/java/jaxx/DefaultInitializer.java | 52 + .../src/main/java/jaxx/PrintTagInfo.java | 118 + .../src/main/java/jaxx/ScriptException.java | 45 + .../src/main/java/jaxx/SwingInitializer.java | 127 + .../java/jaxx/UnsupportedAttributeException.java | 49 + .../main/java/jaxx/UnsupportedTagException.java | 45 + .../src/main/java/jaxx/beaninfos/BeanInfoUtil.java | 36 + .../compiler/BoxedCompiledObjectDecorator.java | 27 + .../main/java/jaxx/compiler/CompiledObject.java | 638 ++ .../jaxx/compiler/CompiledObjectDecorator.java | 76 + .../main/java/jaxx/compiler/CompilerOptions.java | 406 + .../src/main/java/jaxx/compiler/DataBinding.java | 92 + .../src/main/java/jaxx/compiler/DataSource.java | 454 + .../compiler/DefaultCompiledObjectDecorator.java | 128 + .../src/main/java/jaxx/compiler/EventHandler.java | 61 + .../src/main/java/jaxx/compiler/Generator.java | 14 + .../compiler/HelpRootCompiledObjectDecorator.java | 93 + .../src/main/java/jaxx/compiler/I18nHelper.java | 70 + .../src/main/java/jaxx/compiler/JAXXCompiler.java | 1550 +++ .../java/jaxx/compiler/JAXXCompilerLaunchor.java | 451 + .../java/jaxx/compiler/JAXXObjectGenerator.java | 598 ++ .../src/main/java/jaxx/compiler/JAXXProfile.java | 240 + .../src/main/java/jaxx/compiler/JavaArgument.java | 86 + .../src/main/java/jaxx/compiler/JavaField.java | 187 + .../src/main/java/jaxx/compiler/JavaFile.java | 344 + .../src/main/java/jaxx/compiler/JavaMethod.java | 499 + .../main/java/jaxx/compiler/ScriptInitializer.java | 20 + .../src/main/java/jaxx/compiler/ScriptManager.java | 336 + .../src/main/java/jaxx/compiler/SwingCompiler.java | 73 + .../main/java/jaxx/compiler/SwingGenerator.java | 26 + .../src/main/java/jaxx/compiler/SymbolTable.java | 56 + .../java/jaxx/compiler/ValidatorGenerator.java | 89 + trunk/jaxx-compiler/src/main/java/jaxx/css/CSS.jj | 587 ++ trunk/jaxx-compiler/src/main/java/jaxx/css/CSS.jjt | 256 + .../src/main/java/jaxx/css/CSSParser.java | 799 ++ .../src/main/java/jaxx/css/CSSParserConstants.java | 72 + .../main/java/jaxx/css/CSSParserTokenManager.java | 1152 +++ .../main/java/jaxx/css/CSSParserTreeConstants.java | 40 + .../src/main/java/jaxx/css/JJTCSSParserState.java | 123 + .../jaxx-compiler/src/main/java/jaxx/css/Node.java | 51 + .../src/main/java/jaxx/css/ParseException.java | 20 + .../src/main/java/jaxx/css/SimpleCharStream.java | 398 + .../src/main/java/jaxx/css/SimpleNode.java | 122 + .../src/main/java/jaxx/css/StylesheetHelper.java | 563 ++ .../src/main/java/jaxx/css/Token.java | 76 + .../src/main/java/jaxx/css/TokenMgrError.java | 126 + .../jaxx/introspection/JAXXBeanDescriptor.java | 14 + .../main/java/jaxx/introspection/JAXXBeanInfo.java | 36 + .../jaxx/introspection/JAXXEventSetDescriptor.java | 39 + .../jaxx/introspection/JAXXFeatureDescriptor.java | 55 + .../java/jaxx/introspection/JAXXIntrospector.java | 176 + .../jaxx/introspection/JAXXPropertyDescriptor.java | 96 + .../main/java/jaxx/parser/JJTJavaParserState.java | 123 + .../src/main/java/jaxx/parser/Java1.5.jj | 5125 ++++++++++ .../src/main/java/jaxx/parser/Java1.5.jjt | 2150 ++++ .../src/main/java/jaxx/parser/JavaCharStream.java | 530 + .../src/main/java/jaxx/parser/JavaParser.java | 10048 +++++++++++++++++++ .../main/java/jaxx/parser/JavaParserConstants.java | 260 + .../java/jaxx/parser/JavaParserTokenManager.java | 2072 ++++ .../java/jaxx/parser/JavaParserTreeConstants.java | 230 + .../src/main/java/jaxx/parser/Node.java | 51 + .../src/main/java/jaxx/parser/ParseException.java | 214 + .../src/main/java/jaxx/parser/SimpleNode.java | 135 + .../src/main/java/jaxx/parser/Token.java | 79 + .../src/main/java/jaxx/parser/TokenMgrError.java | 126 + .../main/java/jaxx/reflect/ClassDescriptor.java | 166 + .../java/jaxx/reflect/ClassDescriptorLoader.java | 431 + .../main/java/jaxx/reflect/FieldDescriptor.java | 27 + .../src/main/java/jaxx/reflect/JavaFileParser.java | 230 + .../main/java/jaxx/reflect/MemberDescriptor.java | 40 + .../main/java/jaxx/reflect/MethodDescriptor.java | 54 + .../src/main/java/jaxx/spi/Initializer.java | 15 + .../java/jaxx/tags/DefaultComponentHandler.java | 322 + .../main/java/jaxx/tags/DefaultObjectHandler.java | 1184 +++ .../src/main/java/jaxx/tags/ScriptHandler.java | 81 + .../src/main/java/jaxx/tags/StyleHandler.java | 180 + .../src/main/java/jaxx/tags/TagHandler.java | 46 + .../src/main/java/jaxx/tags/TagManager.java | 479 + .../java/jaxx/tags/swing/ApplicationHandler.java | 41 + .../src/main/java/jaxx/tags/swing/CellHandler.java | 154 + .../jaxx/tags/swing/CompiledItemContainer.java | 53 + .../java/jaxx/tags/swing/EnumEditorHandler.java | 56 + .../src/main/java/jaxx/tags/swing/ItemHandler.java | 144 + .../main/java/jaxx/tags/swing/JAXXTabHandler.java | 28 + .../java/jaxx/tags/swing/JCheckBoxHandler.java | 25 + .../java/jaxx/tags/swing/JComboBoxHandler.java | 62 + .../jaxx/tags/swing/JInternalFrameHandler.java | 54 + .../main/java/jaxx/tags/swing/JListHandler.java | 64 + .../main/java/jaxx/tags/swing/JMenuHandler.java | 26 + .../jaxx/tags/swing/JPasswordFieldHandler.java | 25 + .../java/jaxx/tags/swing/JPopupMenuHandler.java | 31 + .../java/jaxx/tags/swing/JProgressBarHandler.java | 26 + .../java/jaxx/tags/swing/JRadioButtonHandler.java | 81 + .../java/jaxx/tags/swing/JScrollPaneHandler.java | 41 + .../main/java/jaxx/tags/swing/JSliderHandler.java | 45 + .../main/java/jaxx/tags/swing/JSpinnerHandler.java | 92 + .../java/jaxx/tags/swing/JSplitPaneHandler.java | 69 + .../java/jaxx/tags/swing/JTabbedPaneHandler.java | 135 + .../jaxx/tags/swing/JTextComponentHandler.java | 70 + .../main/java/jaxx/tags/swing/JToolBarHandler.java | 38 + .../main/java/jaxx/tags/swing/JTreeHandler.java | 69 + .../main/java/jaxx/tags/swing/JWindowHandler.java | 61 + .../java/jaxx/tags/swing/LocaleEditorHandler.java | 56 + .../src/main/java/jaxx/tags/swing/RowHandler.java | 85 + .../src/main/java/jaxx/tags/swing/TabHandler.java | 175 + .../main/java/jaxx/tags/swing/TableHandler.java | 124 + .../jaxx/tags/validator/BeanValidatorHandler.java | 734 ++ .../validator/ExcludeFieldValidatorHandler.java | 85 + .../jaxx/tags/validator/FieldValidatorHandler.java | 78 + .../jaxx/tags/validator/ValidatorInitializer.java | 22 + .../tools/jaxxcapture/AbstractContextNode.java | 17 + .../jaxx/tools/jaxxcapture/CapturedObject.java | 146 + .../java/jaxx/tools/jaxxcapture/ContextNode.java | 7 + .../java/jaxx/tools/jaxxcapture/JAXXCapture.java | 404 + .../java/jaxx/tools/jaxxcapture/LiteralNode.java | 20 + .../java/jaxx/tools/jaxxcapture/MethodNode.java | 19 + .../java/jaxx/tools/jaxxcapture/PropertyNode.java | 19 + .../java/jaxx/tools/jaxxcapture/ValueNode.java | 14 + .../jaxxcapture/handlers/JTabbedPaneHandler.java | 25 + .../tools/jaxxcapture/handlers/ObjectHandler.java | 323 + .../tools/jaxxcapture/handlers/TableHandler.java | 12 + .../src/main/java/jaxx/types/ColorConverter.java | 35 + .../jaxx/types/GridBagConstraintsConverter.java | 22 + .../src/main/java/jaxx/types/InsetsConverter.java | 37 + .../main/java/jaxx/types/KeyStrokeConverter.java | 22 + .../main/java/jaxx/types/PrimitiveConverter.java | 78 + .../src/main/java/jaxx/types/TypeConverter.java | 11 + .../src/main/java/jaxx/types/TypeManager.java | 45 + .../META-INF/services/jaxx.compiler.Generator | 3 + .../META-INF/services/jaxx.spi.Initializer | 3 + trunk/jaxx-compiler/src/site/rst/BeanValidator.rst | 181 + trunk/jaxx-compiler/src/site/rst/I18n.rst | 56 + trunk/jaxx-compiler/src/site/rst/Interface.rst | 38 + trunk/jaxx-compiler/src/site/rst/JAXXContext.rst | 161 + trunk/jaxx-compiler/src/site/rst/JavaBean.rst | 50 + .../src/site/rst/NavigationTreeModel.rst | 168 + trunk/jaxx-compiler/src/site/rst/Todo.rst | 15 + trunk/jaxx-compiler/src/site/rst/index.rst | 41 + trunk/jaxx-compiler/src/site/site.xml | 25 + .../test/java/jaxx/beaninfos/BeanIntoUtilTest.java | 34 + .../test/java/jaxx/junit/ClassDescriptorTest.java | 63 + .../test/java/jaxx/junit/ColorConverterTest.java | 51 + .../test/java/jaxx/junit/InsetsConverterTest.java | 50 + .../test/java/jaxx/junit/JavaFileParserTest.java | 57 + .../src/test/java/jaxx/junit/JavaMethodTest.java | 52 + .../java/jaxx/junit/PrimitiveConverterTest.java | 113 + .../src/test/java/jaxx/junit/TagManagerTest.java | 143 + .../swing/navigation/NavigationTreeModelTest.java | 394 + .../src/test/resources/log4j.properties | 8 + trunk/jaxx-example/LICENSE.txt | 166 + trunk/jaxx-example/README.txt | 2 + trunk/jaxx-example/changelog.txt | 18 + trunk/jaxx-example/pom.xml | 294 + .../main/java/jaxx/demo/BaseBeanDataBinding.jaxx | 21 + .../main/java/jaxx/demo/BeanDataBindingDemo.jaxx | 47 + .../main/java/jaxx/demo/BoxedDecoratorDemo.jaxx | 91 + .../src/main/java/jaxx/demo/Calculator.css | 68 + .../src/main/java/jaxx/demo/CalculatorDemo.jaxx | 89 + .../src/main/java/jaxx/demo/CalculatorEngine.java | 177 + .../src/main/java/jaxx/demo/ComboEditorDemo.jaxx | 35 + .../src/main/java/jaxx/demo/CounterDemo.jaxx | 12 + .../src/main/java/jaxx/demo/DemoPanel.jaxx | 45 + .../src/main/java/jaxx/demo/EmptyDemo.jaxx | 5 + .../src/main/java/jaxx/demo/I18nEditorDemo.jaxx | 46 + .../src/main/java/jaxx/demo/Identity.java | 103 + .../src/main/java/jaxx/demo/JAXXDemo.jaxx | 132 + .../src/main/java/jaxx/demo/JButtonDemo.jaxx | 29 + .../src/main/java/jaxx/demo/JCheckBoxDemo.jaxx | 38 + .../main/java/jaxx/demo/JCheckBoxMenuItemDemo.jaxx | 59 + .../src/main/java/jaxx/demo/JComboBoxDemo.jaxx | 22 + .../src/main/java/jaxx/demo/JDialogDemo.jaxx | 79 + .../src/main/java/jaxx/demo/JListDemo.jaxx | 59 + .../src/main/java/jaxx/demo/JMenuItemDemo.jaxx | 23 + .../main/java/jaxx/demo/JPasswordFieldDemo.jaxx | 10 + .../src/main/java/jaxx/demo/JProgressBarDemo.jaxx | 77 + .../src/main/java/jaxx/demo/JRadioButtonDemo.jaxx | 11 + .../java/jaxx/demo/JRadioButtonMenuItemDemo.jaxx | 14 + .../src/main/java/jaxx/demo/JSliderDemo.jaxx | 12 + .../src/main/java/jaxx/demo/JSpinnerDemo.jaxx | 13 + .../src/main/java/jaxx/demo/JSplitPaneDemo.jaxx | 13 + .../src/main/java/jaxx/demo/JTextAreaDemo.jaxx | 33 + .../src/main/java/jaxx/demo/JTextFieldDemo.jaxx | 22 + .../src/main/java/jaxx/demo/JToggleButtonDemo.jaxx | 9 + .../src/main/java/jaxx/demo/LabelStyle.css | 43 + .../src/main/java/jaxx/demo/LabelStyleDemo.jaxx | 85 + .../src/main/java/jaxx/demo/Model.java | 66 + .../src/main/java/jaxx/demo/NumberEditorDemo.jaxx | 132 + .../main/java/jaxx/demo/NumberEditorDemoModel.java | 78 + .../java/jaxx/demo/StatusMessagePanelDemo.jaxx | 11 + .../src/main/java/jaxx/demo/Validation.css | 5 + .../main/java/jaxx/demo/ValidationListDemo.jaxx | 325 + .../main/java/jaxx/demo/ValidationTableDemo.jaxx | 331 + trunk/jaxx-example/src/main/jnlp/jxlayer.jnlp | 12 + trunk/jaxx-example/src/main/jnlp/sun.jnlp | 12 + .../resources/i18n/jaxx-example-en_GB.properties | 142 + .../resources/i18n/jaxx-example-fr_FR.properties | 134 + .../src/main/resources/icons/action-accept.png | Bin 0 -> 781 bytes .../src/main/resources/icons/action-block.png | Bin 0 -> 576 bytes .../jaxx/demo/Identity-error-validation.xml | 49 + .../jaxx/demo/Identity-info-validation.xml | 49 + .../jaxx/demo/Identity-warning-validation.xml | 49 + .../resources/jaxx/demo/Model-error-validation.xml | 35 + .../resources/jaxx/demo/Model-info-validation.xml | 13 + .../jaxx/demo/Model-warning-validation.xml | 18 + .../main/resources/jaxx/demo/images/Amethyst.jpg | Bin 0 -> 24619 bytes .../src/main/resources/jaxx/demo/images/Lynx.jpg | Bin 0 -> 40463 bytes .../src/main/resources/jaxx/demo/images/Tomato.jpg | Bin 0 -> 22862 bytes .../resources/jaxx/demo/images/pencil_black.gif | Bin 0 -> 190 bytes .../src/main/resources/log4j.properties | 10 + .../src/site/rst/images/Components-screenshot.gif | Bin 0 -> 46663 bytes .../jaxx-example/src/site/rst/images/webstart.gif | Bin 0 -> 1806 bytes trunk/jaxx-example/src/site/rst/index.rst | 40 + trunk/jaxx-example/src/site/site.xml | 27 + .../java/jaxx/demo/BeanValidatorDetectorTest.java | 34 + trunk/jaxx-runtime-api/LICENSE.txt | 166 + trunk/jaxx-runtime-api/README.txt | 2 + trunk/jaxx-runtime-api/changelog.txt | 109 + trunk/jaxx-runtime-api/pom.xml | 138 + .../src/main/java/jaxx/Base64Coder.java | 240 + .../src/main/java/jaxx/css/Rule.java | 54 + .../src/main/java/jaxx/css/Selector.java | 99 + .../src/main/java/jaxx/css/Stylesheet.java | 45 + .../main/java/jaxx/runtime/BeanValidatorUtil.java | 176 + .../java/jaxx/runtime/ComponentDescriptor.java | 49 + .../java/jaxx/runtime/DataBindingListener.java | 46 + .../jaxx/runtime/DataBindingUpdateListener.java | 46 + .../src/main/java/jaxx/runtime/DataContext.java | 400 + .../src/main/java/jaxx/runtime/Decorator.java | 36 + .../src/main/java/jaxx/runtime/DecoratorUtils.java | 111 + .../jaxx/runtime/DefaultApplicationContext.java | 281 + .../main/java/jaxx/runtime/DefaultJAXXContext.java | 214 + .../src/main/java/jaxx/runtime/JAXXAction.java | 19 + .../src/main/java/jaxx/runtime/JAXXContext.java | 99 + .../java/jaxx/runtime/JAXXContextEntryDef.java | 118 + .../main/java/jaxx/runtime/JAXXInitialContext.java | 93 + .../src/main/java/jaxx/runtime/JAXXObject.java | 52 + .../java/jaxx/runtime/JAXXObjectDescriptor.java | 42 + .../src/main/java/jaxx/runtime/JAXXValidator.java | 25 + .../main/java/jaxx/runtime/JXPathDecorator.java | 278 + .../java/jaxx/runtime/MultiJXPathDecorator.java | 129 + .../main/java/jaxx/runtime/PropertyDecorator.java | 94 + .../src/main/java/jaxx/runtime/Util.java | 465 + .../main/java/jaxx/runtime/css/DataBinding.java | 31 + .../main/java/jaxx/runtime/css/Pseudoclasses.java | 176 + .../java/jaxx/runtime/validator/BeanValidator.java | 490 + .../runtime/validator/BeanValidatorDetector.java | 208 + .../jaxx/runtime/validator/BeanValidatorEvent.java | 52 + .../jaxx/runtime/validator/BeanValidatorField.java | 239 + .../runtime/validator/BeanValidatorListener.java | 17 + .../runtime/validator/BeanValidatorMessage.java | 72 + .../jaxx/runtime/validator/BeanValidatorScope.java | 46 + .../jaxx/runtime/validator/XWorkBeanValidator.java | 252 + .../field/CollectionFieldExpressionValidator.java | 448 + .../field/CollectionUniqueKeyValidator.java | 208 + .../field/ExistingDirectoryFieldValidator.java | 72 + .../field/ExistingFileFieldValidator.java | 72 + .../field/FieldExpressionWithParamsValidator.java | 175 + .../field/NotExistingDirectoryFieldValidator.java | 72 + .../field/NotExistingFileFieldValidator.java | 73 + .../field/RequiredFileFieldValidator.java | 72 + .../i18n/jaxx-runtime-api-en_GB.properties | 3 + .../i18n/jaxx-runtime-api-fr_FR.properties | 3 + .../src/main/resources/validators.xml | 18 + trunk/jaxx-runtime-api/src/site/site.xml | 25 + .../runtime/DefaultApplicationContextTest.java | 117 + .../java/jaxx/runtime/DefaultJAXXContextTest.java | 299 + .../java/jaxx/runtime/JXPathDecoratorTest.java | 163 + .../jaxx/runtime/MultiJXPathDecoratorTest.java | 184 + .../src/test/java/jaxx/runtime/UtilTest.java | 29 + .../AbstractBeanValidatorDetectorTest.java | 108 + .../validator/BeanValidatorDetectorTest.java | 101 + .../jaxx/runtime/validator/BeanValidatorTest.java | 198 + .../java/jaxx/runtime/validator/SimpleBean.java | 51 + .../runtime/validator/XWorkBeanValidatorTest.java | 156 + .../field/AbstractFieldValidatorTest.java | 97 + .../AbstractValidatorBeanFieldValidatorTest.java | 14 + .../CollectionFieldExpressionValidatorTest.java | 234 + .../field/CollectionUniqueKeyValidatorTest.java | 86 + .../field/ExistingDirectoryFieldValidatorTest.java | 30 + .../field/ExistingFileFieldValidatorTest.java | 30 + .../validator/field/FieldExpressionBean.java | 103 + .../FieldExpressionWithParamsValidatorTest.java | 116 + .../NotExistingDirectoryFieldValidatorTest.java | 33 + .../field/NotExistingFileFieldValidatorTest.java | 37 + .../field/RequiredFileFieldValidatorTest.java | 29 + .../runtime/validator/field/ValidatorBean.java | 149 + .../validator/SimpleBean-error-validation.xml | 19 + .../validator/SimpleBean-info-validation.xml | 13 + .../validator/SimpleBean-simple-validation.xml | 19 + .../validator/SimpleBean-warning-validation.xml | 13 + .../field/FieldExpressionBean-error-validation.xml | 99 + .../field/ValidatorBean-error-validation.xml | 155 + .../src/test/resources/log4j.properties | 8 + .../src/test/resources/validators.xml | 36 + trunk/jaxx-runtime-swing-widget/LICENSE.txt | 166 + trunk/jaxx-runtime-swing-widget/README.txt | 2 + trunk/jaxx-runtime-swing-widget/changelog.txt | 5 + trunk/jaxx-runtime-swing-widget/pom.xml | 123 + .../main/java/jaxx/runtime/swing/AboutPanel.jaxx | 224 + .../main/java/jaxx/runtime/swing/ClockWidget.jaxx | 55 + .../java/jaxx/runtime/swing/EntityComboBox.jaxx | 131 + .../jaxx/runtime/swing/EntityComboBoxHandler.java | 470 + .../java/jaxx/runtime/swing/ErrorDialogUI.jaxx | 88 + .../jaxx/runtime/swing/MemoryStatusWidget.jaxx | 113 + .../jaxx/runtime/swing/StatusMessagePanel.jaxx | 84 + .../runtime/swing/StatusMessagePanelHandler.java | 75 + .../jaxx/runtime/swing/editor/ColumnSelector.jaxx | 152 + .../java/jaxx/runtime/swing/editor/I18nEditor.jaxx | 211 + .../jaxx/runtime/swing/editor/NumberEditor.jaxx | 167 + .../runtime/swing/editor/NumberEditorHandler.java | 468 + .../runtime/swing/editor/NumberEditorPopup.css | 43 + .../java/jaxx/runtime/swing/editor/TimeEditor.css | 49 + .../java/jaxx/runtime/swing/editor/TimeEditor.jaxx | 78 + .../runtime/swing/editor/TimeEditorHandler.java | 222 + .../swing/editor/config/ConfigCategoryUI.css | 60 + .../swing/editor/config/ConfigCategoryUI.jaxx | 120 + .../swing/editor/config/ConfigTableEditor.java | 125 + .../swing/editor/config/ConfigTableRenderer.java | 112 + .../jaxx/runtime/swing/editor/config/ConfigUI.css | 27 + .../jaxx/runtime/swing/editor/config/ConfigUI.jaxx | 72 + .../swing/editor/config/ConfigUIBuilder.java | 246 + .../swing/editor/config/model/CategoryModel.java | 175 + .../editor/config/model/ConfigTableModel.java | 134 + .../swing/editor/config/model/ConfigUIModel.java | 224 + .../swing/editor/config/model/OptionModel.java | 112 + .../jaxx-runtime-swing-widget-en_GB.properties | 71 + .../jaxx-runtime-swing-widget-fr_FR.properties | 72 + .../main/resources/icons/action-config-quit.png | Bin 0 -> 688 bytes .../main/resources/icons/action-config-reset.png | Bin 0 -> 587 bytes .../main/resources/icons/action-config-save.png | Bin 0 -> 838 bytes .../src/main/resources/icons/action-i18n-be.png | Bin 0 -> 449 bytes .../src/main/resources/icons/action-i18n-ca.png | Bin 0 -> 628 bytes .../src/main/resources/icons/action-i18n-ch.png | Bin 0 -> 367 bytes .../src/main/resources/icons/action-i18n-de.png | Bin 0 -> 545 bytes .../src/main/resources/icons/action-i18n-dk.png | Bin 0 -> 495 bytes .../src/main/resources/icons/action-i18n-es.png | Bin 0 -> 469 bytes .../src/main/resources/icons/action-i18n-fi.png | Bin 0 -> 489 bytes .../src/main/resources/icons/action-i18n-fr.png | Bin 0 -> 545 bytes .../src/main/resources/icons/action-i18n-gb.png | Bin 0 -> 599 bytes .../src/main/resources/icons/action-i18n-it.png | Bin 0 -> 420 bytes .../src/main/resources/icons/action-i18n-nl.png | Bin 0 -> 453 bytes .../src/main/resources/icons/action-i18n-no.png | Bin 0 -> 512 bytes .../src/main/resources/icons/action-i18n-se.png | Bin 0 -> 542 bytes .../src/main/resources/icons/action-i18n-us.png | Bin 0 -> 609 bytes .../icons/action-numbereditor-calculator.png | Bin 0 -> 543 bytes .../resources/icons/action-numbereditor-reset.png | Bin 0 -> 396 bytes .../icons/action-numbereditor-validate.png | Bin 0 -> 537 bytes .../src/site/rst/images/Components-screenshot.gif | Bin 0 -> 46663 bytes .../src/site/rst/images/webstart.gif | Bin 0 -> 1806 bytes .../src/site/rst/index.rst | 40 + trunk/jaxx-runtime-swing-widget/src/site/site.xml | 25 + trunk/jaxx-runtime-swing/LICENSE.txt | 166 + trunk/jaxx-runtime-swing/README.txt | 2 + trunk/jaxx-runtime-swing/changelog.txt | 114 + trunk/jaxx-runtime-swing/pom.xml | 53 + .../src/main/java/jaxx/beaninfos/HBoxBeanInfo.java | 58 + .../src/main/java/jaxx/beaninfos/VBoxBeanInfo.java | 58 + .../src/main/java/jaxx/runtime/JaxxHelpUI.java | 23 + .../src/main/java/jaxx/runtime/SwingUtil.java | 739 ++ .../main/java/jaxx/runtime/SwingValidatorUtil.java | 200 + .../main/java/jaxx/runtime/swing/Application.java | 56 + .../java/jaxx/runtime/swing/BlockingLayerUI.java | 259 + .../java/jaxx/runtime/swing/BlockingLayerUI2.java | 217 + .../jaxx/runtime/swing/BooleanCellRenderer.java | 61 + .../main/java/jaxx/runtime/swing/CardLayout2.java | 221 + .../java/jaxx/runtime/swing/CardLayout2Ext.java | 99 + .../runtime/swing/DecoratorTableCellRenderer.java | 33 + .../swing/EmptyNumberTableCellRenderer.java | 37 + .../jaxx/runtime/swing/EnumTableCellRenderer.java | 47 + .../src/main/java/jaxx/runtime/swing/GBC.java | 151 + .../src/main/java/jaxx/runtime/swing/HBox.java | 94 + .../main/java/jaxx/runtime/swing/HBoxLayout.java | 127 + .../jaxx/runtime/swing/I18nTableCellRenderer.java | 66 + .../src/main/java/jaxx/runtime/swing/Item.java | 192 + .../java/jaxx/runtime/swing/JAXXButtonGroup.java | 222 + .../main/java/jaxx/runtime/swing/JAXXComboBox.java | 224 + .../src/main/java/jaxx/runtime/swing/JAXXList.java | 309 + .../src/main/java/jaxx/runtime/swing/JAXXTab.java | 25 + .../java/jaxx/runtime/swing/JAXXToggleButton.java | 92 + .../src/main/java/jaxx/runtime/swing/JAXXTree.java | 220 + .../java/jaxx/runtime/swing/JaxxHelpBroker.java | 500 + .../jaxx/runtime/swing/LocaleListCellRenderer.java | 114 + .../jaxx/runtime/swing/MyDefaultCellEditor.java | 104 + .../runtime/swing/OneClicListSelectionModel.java | 181 + .../src/main/java/jaxx/runtime/swing/Spacer.java | 12 + .../src/main/java/jaxx/runtime/swing/TabInfo.java | 165 + .../swing/TabInfoPropertyChangeListener.java | 44 + .../src/main/java/jaxx/runtime/swing/Table.java | 58 + .../src/main/java/jaxx/runtime/swing/VBox.java | 94 + .../main/java/jaxx/runtime/swing/VBoxLayout.java | 127 + .../jaxx/runtime/swing/editor/ClassCellEditor.java | 119 + .../java/jaxx/runtime/swing/editor/EnumEditor.java | 57 + .../jaxx/runtime/swing/editor/LocaleEditor.java | 64 + .../navigation/NavigationTreeCellRenderer.java | 93 + .../swing/navigation/NavigationTreeHandler.java | 249 + .../NavigationTreeHandlerWithCardLayout.java | 119 + .../swing/navigation/NavigationTreeModel.java | 589 ++ .../navigation/NavigationTreeModelBuilder.java | 152 + .../navigation/NavigationTreeSelectionAdapter.java | 243 + ...vigationTreeSelectionAdapterWithCardLayout.java | 108 + .../runtime/swing/navigation/NavigationUtil.java | 159 + .../jaxx/runtime/swing/wizard/WizardModel.java | 244 + .../swing/wizard/WizardOperationAction.java | 108 + .../swing/wizard/WizardOperationActionThread.java | 204 + .../runtime/swing/wizard/WizardOperationModel.java | 269 + .../runtime/swing/wizard/WizardOperationState.java | 32 + .../runtime/swing/wizard/WizardOperationStep.java | 34 + .../java/jaxx/runtime/swing/wizard/WizardStep.java | 20 + .../jaxx/runtime/swing/wizard/WizardStepUI.java | 14 + .../java/jaxx/runtime/swing/wizard/WizardUI.java | 94 + .../jaxx/runtime/swing/wizard/WizardUILancher.java | 162 + .../java/jaxx/runtime/swing/wizard/WizardUtil.java | 157 + .../java/jaxx/runtime/swing/wizard/package.html | 9 + .../runtime/validator/swing/SwingValidator.java | 279 + .../validator/swing/SwingValidatorMessage.java | 66 + .../swing/SwingValidatorMessageListModel.java | 142 + .../SwingValidatorMessageListMouseListener.java | 60 + .../swing/SwingValidatorMessageListRenderer.java | 90 + .../swing/SwingValidatorMessageTableModel.java | 327 + .../SwingValidatorMessageTableMouseListener.java | 94 + .../swing/SwingValidatorMessageTableRenderer.java | 84 + .../swing/ui/AbstractBeanValidatorUI.java | 37 + .../validator/swing/ui/IconValidationUI.java | 86 + .../validator/swing/ui/ImageValidationUI.java | 78 + .../swing/ui/TranslucentValidationUI.java | 65 + .../i18n/jaxx-runtime-swing-en_GB.properties | 9 + .../i18n/jaxx-runtime-swing-fr_FR.properties | 9 + .../src/main/resources/icons/action-delete.png | Bin 0 -> 783 bytes .../resources/icons/action-wizard-config-16.png | Bin 0 -> 611 bytes .../main/resources/icons/action-wizard-config.png | Bin 0 -> 4639 bytes .../resources/icons/action-wizard-message-16.png | Bin 0 -> 778 bytes .../main/resources/icons/action-wizard-message.png | Bin 0 -> 4433 bytes .../main/resources/icons/action-wizard-next-16.png | Bin 0 -> 676 bytes .../main/resources/icons/action-wizard-next.png | Bin 0 -> 4458 bytes .../resources/icons/action-wizard-pause-16.png | Bin 0 -> 598 bytes .../main/resources/icons/action-wizard-pause.png | Bin 0 -> 4323 bytes .../resources/icons/action-wizard-previous-16.png | Bin 0 -> 655 bytes .../resources/icons/action-wizard-previous.png | Bin 0 -> 4449 bytes .../resources/icons/action-wizard-refresh-16.png | Bin 0 -> 685 bytes .../main/resources/icons/action-wizard-refresh.png | Bin 0 -> 4761 bytes .../resources/icons/action-wizard-start-16.png | Bin 0 -> 592 bytes .../main/resources/icons/action-wizard-start.png | Bin 0 -> 4469 bytes .../icons/action-wizard-state-canceled-16.png | Bin 0 -> 587 bytes .../icons/action-wizard-state-canceled.png | Bin 0 -> 4340 bytes .../icons/action-wizard-state-failed-16.png | Bin 0 -> 701 bytes .../resources/icons/action-wizard-state-failed.png | Bin 0 -> 4197 bytes .../icons/action-wizard-state-need_fix-16.png | Bin 0 -> 666 bytes .../icons/action-wizard-state-need_fix.png | Bin 0 -> 4567 bytes .../icons/action-wizard-state-pending-16.png | Bin 0 -> 403 bytes .../icons/action-wizard-state-pending.png | Bin 0 -> 4284 bytes .../icons/action-wizard-state-running-16.png | Bin 0 -> 592 bytes .../icons/action-wizard-state-running.png | Bin 0 -> 4483 bytes .../icons/action-wizard-state-successed-16.png | Bin 0 -> 537 bytes .../icons/action-wizard-state-successed.png | Bin 0 -> 4447 bytes .../src/main/resources/icons/error.png | Bin 0 -> 701 bytes .../src/main/resources/icons/info.png | Bin 0 -> 778 bytes .../src/main/resources/icons/warning.png | Bin 0 -> 666 bytes trunk/jaxx-runtime-swing/src/site/site.xml | 25 + trunk/jaxx-swing-action/LICENSE.txt | 166 + trunk/jaxx-swing-action/README.txt | 2 + trunk/jaxx-swing-action/changelog.txt | 10 + trunk/jaxx-swing-action/pom.xml | 85 + .../AbstractActionConfigurationResolver.java | 77 + .../jaxx/action/ActionAnnotationProcessing.java | 398 + .../java/org/nuiton/jaxx/action/ActionConfig.java | 122 + .../action/ActionConfigConfigurationResolver.java | 68 + .../jaxx/action/ActionConfigurationResolver.java | 54 + .../java/org/nuiton/jaxx/action/ActionFactory.java | 150 + .../jaxx/action/ActionFactoryFromProvider.java | 470 + .../org/nuiton/jaxx/action/ActionNameProvider.java | 34 + .../org/nuiton/jaxx/action/ActionProvider.java | 36 + .../jaxx/action/ActionProviderAnnotation.java | 34 + .../jaxx/action/ActionProviderFromProperties.java | 135 + .../org/nuiton/jaxx/action/MyAbstractAction.java | 260 + .../org/nuiton/jaxx/action/SelectActionConfig.java | 95 + .../SelectActionConfigConfigurationResolver.java | 54 + .../org/nuiton/jaxx/action/ToggleActionConfig.java | 156 + .../ToggleActionConfigConfigurationResolver.java | 79 + .../java/org/nuiton/jaxx/tab/TabContentConfig.java | 54 + .../main/java/org/nuiton/jaxx/tab/TabFactory.java | 219 + .../main/java/org/nuiton/jaxx/tab/TabModel.java | 30 + .../org/nuiton/jaxx/util/AbstractUIAction.java | 55 + .../main/java/org/nuiton/jaxx/util/DialogUI.java | 137 + .../java/org/nuiton/jaxx/util/DialogUIDef.java | 238 + .../java/org/nuiton/jaxx/util/DialogUIHandler.java | 72 + .../java/org/nuiton/jaxx/util/DialogUIModel.java | 97 + .../nuiton/jaxx/util/FactoryWindowListener.java | 84 + .../java/org/nuiton/jaxx/util/FormElement.java | 31 + .../java/org/nuiton/jaxx/util/ShowUIAction.java | 140 + .../main/java/org/nuiton/jaxx/util/UIFactory.java | 184 + .../main/java/org/nuiton/jaxx/util/UIHelper.java | 71 + .../main/java/org/nuiton/jaxx/util/UIProvider.java | 86 + .../org/nuiton/jaxx/util/config/CancelAction.java | 43 + .../nuiton/jaxx/util/config/DialogConfigUI.java | 105 + .../jaxx/util/config/DialogConfigUIHandler.java | 156 + .../jaxx/util/config/DialogConfigUIModel.java | 220 + .../org/nuiton/jaxx/util/config/ResetAction.java | 43 + .../org/nuiton/jaxx/util/config/SaveAction.java | 50 + .../services/javax.annotation.processing.Processor | 1 + .../i18n/jaxx-swing-action-en_GB.properties | 10 + .../i18n/jaxx-swing-action-fr_FR.properties | 10 + trunk/jaxx-swing-action/src/site/rst/Todo.rst | 4 + trunk/jaxx-swing-action/src/site/rst/index.rst | 13 + trunk/jaxx-swing-action/src/site/site.xml | 25 + trunk/maven-jaxx-plugin/LICENSE.txt | 166 + trunk/maven-jaxx-plugin/README.txt | 2 + trunk/maven-jaxx-plugin/changelog.txt | 37 + trunk/maven-jaxx-plugin/pom.xml | 143 + .../java/org/nuiton/jaxx/AbstractJaxxMojo.java | 170 + .../java/org/nuiton/jaxx/JaxxGeneratorMojo.java | 652 ++ .../org/nuiton/jaxx/JaxxHelpGeneratorMojo.java | 792 ++ .../src/main/java/org/nuiton/jaxx/NodeItem.java | 137 + .../java/org/nuiton/jaxx/TemplateGenerator.java | 142 + .../src/main/resources/defaultContent.html.vm | 14 + .../src/main/resources/defaultHelpSet.hs.vm | 44 + .../src/main/resources/defaultI18n.java.vm | 16 + .../src/main/resources/defaultIndex.xml.vm | 21 + .../src/main/resources/defaultMap.jhm.vm | 16 + .../src/main/resources/defaultToc.xml.vm | 20 + .../src/main/resources/log4j.properties | 9 + trunk/maven-jaxx-plugin/src/site/rst/Todo.rst | 4 + trunk/maven-jaxx-plugin/src/site/rst/index.rst | 13 + trunk/maven-jaxx-plugin/src/site/site.xml | 41 + .../src/test/java/org/nuiton/jaxx/Bug1722Test.java | 12 + .../src/test/java/org/nuiton/jaxx/Bug1750Test.java | 44 + .../src/test/java/org/nuiton/jaxx/Bug1751Test.java | 14 + .../test/java/org/nuiton/jaxx/CompilerTest.java | 227 + .../org/nuiton/jaxx/CompilerValidatorTest.java | 72 + .../test/java/org/nuiton/jaxx/DecoratorTest.java | 11 + .../src/test/java/org/nuiton/jaxx/I18nTest.java | 39 + .../test/java/org/nuiton/jaxx/JaxxBaseTest.java | 85 + .../test/java/org/nuiton/jaxx/NodeItemTest.java | 54 + .../src/test/resources/testcases/Bug_1722.xml | 23 + .../src/test/resources/testcases/Bug_1750.xml | 24 + .../src/test/resources/testcases/Bug_1751.xml | 25 + .../src/test/resources/testcases/CSSTests.xml | 23 + .../resources/testcases/CSSTests/CSSTests.jaxx | 24 + .../test/resources/testcases/CSSTests/Child.jaxx | 1 + .../test/resources/testcases/CSSTests/Child2.jaxx | 1 + .../resources/testcases/CSSTests/GrandChild.jaxx | 28 + .../testcases/CSSTests/GrandChildButton.jaxx | 1 + .../testcases/CSSTests/Pseudoclasses.jaxx | 99 + .../resources/testcases/CSSTests/SimpleCSS.jaxx | 29 + .../test/resources/testcases/ClassReferences.xml | 22 + .../testcases/ClassReferences/ClassReferences.jaxx | 18 + .../ClassReferences/ConstructorReferenceTest.jaxx | 7 + .../ClassReferences/JAXXReferenceTest.jaxx | 7 + .../testcases/ClassReferences/JAXXTest.jaxx | 7 + .../testcases/ClassReferences/JavaTaist.java | 9 + .../ClassReferences/StaticMethodTest.jaxx | 7 + .../testcases/ClassReferences/TypeReference.jaxx | 1 + .../test/resources/testcases/ClientProperty.xml | 23 + .../src/test/resources/testcases/Decorator.xml | 23 + .../testcases/ErrorJaxxContextImplementorClass.xml | 20 + .../src/test/resources/testcases/Errors.xml | 25 + .../src/test/resources/testcases/Force.xml | 22 + .../src/test/resources/testcases/I18nText.xml | 23 + .../src/test/resources/testcases/I18nTitle.xml | 23 + .../test/resources/testcases/I18nToolTipText.xml | 23 + .../src/test/resources/testcases/Icon.xml | 25 + .../src/test/resources/testcases/Initializers.xml | 22 + .../testcases/Initializers/Initializers.jaxx | 37 + .../src/test/resources/testcases/InnerClasses.xml | 22 + .../testcases/InnerClasses/InnerClasses.jaxx | 17 + .../src/test/resources/testcases/NoLog.xml | 23 + .../resources/testcases/OverridingDataBindings.xml | 22 + .../OverridingDataBindings/CurrentTime.jaxx | 17 + .../OverriddenCurrentTime.jaxx | 1 + .../OverridingDataBindings.jaxx | 12 + .../src/test/resources/testcases/Script.xml | 22 + .../testcases/Script/JScriptInitializer.jaxx | 19 + .../resources/testcases/SpecialSubclassing.xml | 22 + .../SpecialSubclassing/JComboBoxTest1.jaxx | 3 + .../SpecialSubclassing/JComboBoxTest2.jaxx | 3 + .../testcases/SpecialSubclassing/JListTest1.jaxx | 3 + .../testcases/SpecialSubclassing/JListTest2.jaxx | 3 + .../testcases/SpecialSubclassing/JTreeTest1.jaxx | 3 + .../testcases/SpecialSubclassing/JTreeTest2.jaxx | 3 + .../SpecialSubclassing/SpecialSubclassing.jaxx | 26 + .../test/resources/testcases/ValidatorErrors.xml | 22 + .../src/test/resources/testcases/ValidatorOk.xml | 22 + .../src/test/resources/testcases/WithLog.xml | 23 + .../resources/testcases/bug_1722/DemoPanel.jaxx | 7 + .../resources/testcases/bug_1722/JButtonDemo.jaxx | 5 + .../resources/testcases/bug_1750/ComboBox.jaxx | 18 + .../test/resources/testcases/bug_1751/Test1.jaxx | 1 + .../test/resources/testcases/bug_1751/Test2.jaxx | 1 + .../test/resources/testcases/bug_1751/Test3.jaxx | 1 + .../testcases/clientProperty/TestOne.jaxx | 3 + .../testcases/decorator/BoxedDecorator.jaxx | 3 + .../resources/testcases/errors/AmbiguousName.jaxx | 10 + .../testcases/errors/BadTypeConversions.jaxx | 4 + .../testcases/errors/CellOutsideOfRow.jaxx | 5 + .../testcases/errors/ChildrenInNonContainer.jaxx | 4 + .../resources/testcases/errors/ClassNotFound.jaxx | 3 + .../testcases/errors/ConflictingPackages.jaxx | 1 + .../testcases/errors/ConstraintsParseError.jaxx | 5 + .../testcases/errors/DataBindingParseError.jaxx | 6 + .../resources/testcases/errors/DuplicateIDs.jaxx | 4 + .../testcases/errors/EventHandlerParseError.jaxx | 4 + .../test/resources/testcases/errors/InvalidID.jaxx | 3 + .../resources/testcases/errors/InvalidRootTag.jaxx | 1 + .../resources/testcases/errors/InvalidXML.jaxx | 4 + .../testcases/errors/ItemDuplicateValues.jaxx | 8 + .../resources/testcases/errors/ItemNoValue.jaxx | 4 + .../resources/testcases/errors/MixedContent.jaxx | 19 + .../testcases/errors/RowOutsideOfTable.jaxx | 9 + .../resources/testcases/errors/RowWrongChild.jaxx | 9 + .../resources/testcases/errors/ScriptNotFound.jaxx | 1 + .../testcases/errors/ScriptParseError.jaxx | 6 + .../testcases/errors/ScriptSourceAndInline.jaxx | 3 + .../resources/testcases/errors/StyleNotFound.jaxx | 1 + .../testcases/errors/StyleParseError.jaxx | 9 + .../testcases/errors/StyleSourceAndInline.jaxx | 3 + .../testcases/errors/TabOutsideOfTabbedPane.jaxx | 9 + .../testcases/errors/TabbedPaneWrongChild.jaxx | 6 + .../testcases/errors/TableWrongChild.jaxx | 6 + .../testcases/errors/TooManyCellChildren.jaxx | 15 + .../errors/TooManyScrollPaneChildren.jaxx | 5 + .../testcases/errors/TooManySplitPaneChildren.jaxx | 7 + .../testcases/errors/TooManyTabChildren.jaxx | 13 + .../testcases/errors/UnsupportedAttribute.jaxx | 3 + .../testcases/errors/UnsupportedEvent.jaxx | 3 + .../testcases/errors/UnsupportedPseudoclass.jaxx | 5 + .../testcases/errors/dependencies/test.css | 1 + .../testcases/errors/dependencies/test.script | 1 + .../test/resources/testcases/force/JButton.jaxx | 1 + .../resources/testcases/i18n/text/JButton.jaxx | 1 + .../resources/testcases/i18n/title/JDialog.jaxx | 1 + .../testcases/i18n/title/JTabbedPane.jaxx | 3 + .../testcases/i18n/title/JTabbedPane2.jaxx | 5 + .../testcases/i18n/tooltiptext/JButton.jaxx | 1 + .../testcases/i18n/tooltiptext/JTabbedPane.jaxx | 3 + .../testcases/i18n/tooltiptext/JTabbedPane2.jaxx | 3 + .../testcases/i18n/tooltiptext/JTabbedPane3.jaxx | 5 + .../src/test/resources/testcases/icon/Test1.jaxx | 4 + .../test/resources/testcases/log/nolog/NoLog.jaxx | 1 + .../resources/testcases/log/nolog/NoLogSon.jaxx | 1 + .../resources/testcases/log/withlog/NoLog.jaxx | 1 + .../resources/testcases/log/withlog/WithLog.jaxx | 1 + .../errors/AutoFieldComponentNotFound.jaxx | 5 + .../testcases/validator/errors/DuplicatedBean.jaxx | 3 + .../validator/errors/DuplicatedBean2.jaxx | 5 + .../validator/errors/DuplicatedErrorListModel.jaxx | 4 + .../errors/DuplicatedErrorTableModel.jaxx | 4 + .../errors/DuplicatedFieldInSameValidator.jaxx | 7 + .../errors/FieldBeanPropertyNotFound.jaxx | 5 + .../validator/errors/FieldComponentDuplicated.jaxx | 7 + .../validator/errors/FieldComponentNotFound.jaxx | 5 + .../validator/errors/FieldComponentNotFound2.jaxx | 5 + .../testcases/validator/errors/FieldNoName.jaxx | 5 + .../testcases/validator/errors/FieldNoName2.jaxx | 5 + .../testcases/validator/errors/Model.java | 66 + .../testcases/validator/errors/NoBean.jaxx | 5 + .../testcases/validator/errors/UnfoundBean.jaxx | 3 + .../validator/errors/UnfoundErrorList.jaxx | 3 + .../validator/errors/UnfoundErrorListModel.jaxx | 3 + .../validator/errors/UnfoundErrorTable.jaxx | 3 + .../validator/errors/UnfoundErrorTableModel.jaxx | 3 + .../validator/errors/UnfoundParentValidator.jaxx | 3 + .../resources/testcases/validator/ok/Identity.java | 79 + .../resources/testcases/validator/ok/Model.java | 66 + .../testcases/validator/ok/Validation.jaxx | 274 + .../validator/ok/ValidationBeanClass.jaxx | 112 + trunk/pom.xml | 219 + trunk/src/site/resources/images/jrst-logo.png | Bin 0 -> 608 bytes trunk/src/site/resources/jaxx.png | Bin 0 -> 9503 bytes trunk/src/site/rst/BeanValidator.rst | 181 + trunk/src/site/rst/Core.rst | 154 + trunk/src/site/rst/I18n.rst | 56 + trunk/src/site/rst/JAXXContext.rst | 161 + trunk/src/site/rst/NavigationTreeModel.rst | 169 + trunk/src/site/rst/Todo.rst | 8 + trunk/src/site/rst/index.rst | 46 + trunk/src/site/site.xml | 37 + 684 files changed, 80951 insertions(+) diff --git a/trunk/LICENSE.txt b/trunk/LICENSE.txt new file mode 100644 index 0000000..3f7b8b1 --- /dev/null +++ b/trunk/LICENSE.txt @@ -0,0 +1,166 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/trunk/README.txt b/trunk/README.txt new file mode 100644 index 0000000..d2e50d3 --- /dev/null +++ b/trunk/README.txt @@ -0,0 +1,2 @@ +To deploy new version of pom: mvn deploy +To install localy: mvn install diff --git a/trunk/changelog.txt b/trunk/changelog.txt new file mode 100644 index 0000000..745ec8d --- /dev/null +++ b/trunk/changelog.txt @@ -0,0 +1,41 @@ +1.7.1 + +1.7.0 + * reorganize modules + +1.6.0-rc-6 + * migrate to nuiton + +1.5.1 chemit 20090511 + * 20090511 [chemit] - bump versions (lutinproject, jrst, lutinutil, maven-i18n-plugin, maven-license-switcher-plugin) + +1.5 + * 20090506 [chemit] - super-pom has no dependencies, use lutinutil 1.0.5 + * 20090404 [chemit] - introduce module jaxx-runtime-swing-widget for swing widgets designed with jaxx. + +1.4 + * 20090402 [chemit] - use lutinproject 3.5.3 + - use doxia-module-jrst 1.0.0 (instead of maven-jrst-plugin) + - use maven-i18n-plugin 0.11 + - use maven-license-switcher 0.7 + +1.3 chemit 20090409 + * 20090329 [chemit] - add java help mojo + * 20090313 [chemit] - use i18n 0.10 + +1.2 ??? 2009???? + * 20090223 [chemit] - move sources from jaxx-util to jaxx-swing-action module + - delete jaxx-util module + +1.1 chemit 20090220 + * 20090203 [chemit] - use i18n 0.9 (zeroConf) + * 20090203 [chemit] - use lutinproject 3.4 + * 20090122 [chemit] - refactor poms (sibling dependencies, pluginsManagment,...) + +1.0 chemit 20090111 + * 20081210 [chemit] - integrate new architecture to allow to have runtime code with NO link with compiler :) + - use lutinproject 3.3 + +0.7 chemit 20081210 + * 20081210 [chemit] use lutinutil 1.0 and lutinproject 3.2 + * 20081207 [chemit] use lutinproject 3.1 \ No newline at end of file diff --git a/trunk/jaxx-compiler/LICENSE.txt b/trunk/jaxx-compiler/LICENSE.txt new file mode 100644 index 0000000..3f7b8b1 --- /dev/null +++ b/trunk/jaxx-compiler/LICENSE.txt @@ -0,0 +1,166 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/trunk/jaxx-compiler/README.txt b/trunk/jaxx-compiler/README.txt new file mode 100644 index 0000000..d2e50d3 --- /dev/null +++ b/trunk/jaxx-compiler/README.txt @@ -0,0 +1,2 @@ +To deploy new version of pom: mvn deploy +To install localy: mvn install diff --git a/trunk/jaxx-compiler/changelog.txt b/trunk/jaxx-compiler/changelog.txt new file mode 100644 index 0000000..cbc701b --- /dev/null +++ b/trunk/jaxx-compiler/changelog.txt @@ -0,0 +1,120 @@ +1.3 chemit 20090409 + * 20090327 [chemit] - refactor clientProperties (no more generation in handler but in decorator) + - add javax help mecanism + + * 20090321 [chemit] - add compilerCount in launchro to known how mush files where generated + * 20090313 [chemit] - can now use geneticType on javaBean object + - add an extra method $afterCompleteSetup method to be included if find in script at last statement of $completeSetup method + + * 20090309 [chemit] - must get the goal property from the event id to make possible inheritance + - improve override properties create method : when same type do not re-instanciate it + * 20090229 [chemit] - fix bug in ClassDescriptorLoader when searching for an arrayof primitive type + - add a profile mode + * 20090228 [chemit] - fix bug in MethodDescriptor when no returnType defined (constructor method) in getReturnType method invocation + - generate default constructors only if none defined in script + - add primitive type void in ClassDescriptorLoader + - add a contextInitialized property in JAXX generated file to control JAXXContext initialization + * 20090225 [chemit] - add a mecanism to make possible injection of client properties + +1.2 letellier 20090225 (release for isis) + +1.1 chemit 20090220 + * 20090202 [chemit] - can now generate abstract and generic classes + * 20090202 [chemit] - introduce a property validatorFQN in CompilerOptions to specify the validator implementation + * 20090124 [chemit] - introduce a flag useUIManagerForIcon to retreave icons from UIManager + * 20090123 [chemit] - cache the lineSeparator property in JAXXCompiler + - can directly give the icon relatif path (in /icons/ directory) + - add an actionIcon attribute to be surronded in the Util.createActionIcon + + * 20090122 [chemit] - refactor poms (sibling dependencies, pluginsManagment,...) + +1.0 chemit 20090111 + * 20081228 [chemit] - generify ClassDescriptor + - introduce StylesheetHelper helper class to detach Stylesheet, Rule and Selector classes from + JAXXCompiler and make possible to extract compiler engine from runtime + + * 20081227 [chemit] - add PCS on ValidatorErrorTable to be used by table validation + * 20081218 [chemit] - improve generation of methods + * 20081214 [chemit] - can now in validation, put error with args (all args must be separated by a ##) + - improve event naming : replace the $evXXX by doMEthodName__on__field (except with optimize option) + - add jaww.runtime.swing.Utils.fillComboBox to fill a combobox model from a collection + - add addSourcesToClassPath property to add sources directories in class-path + - improve classloader managment + - keep in DataSource objetCode + - fix bug when processDataBinding on a null objectCode + - always clean node cached values when selected it + - add usefull databinding method in Util + + * 20081213 [chemit] - improve navigation tree node rendering with some caches + - introduce a ChildBuilder to simplify building of child nodes from a collection or array + +0.7 chemit 20081210 + * 20081210 [chemit] - fix bug 1751 + * 20081210 [chemit] - improve JAXXButtonGroup (add ActionChangeListener and toolTipText mecanism) + * 20081208 [chemit] - javabBean attribute use to initialize bean + - introduce Base64Coder to fix bug 1750 and control serailVersionUI (put them to 1L for the moment) + - introduce MultiJXPathDecorator + - add a resetAfterCompile parameter toCompilerOption to keep in test used compilers + + * 20081207 [chemit] - use lutinproject 3.1 + - can exclude field from validator + * 20081202 [chemit] - add strategy for loading ui in NavigationTreeSelectionAdapter + - fix bug when searching for a inner class + + * 20081201 [chemit] - implements jaxx.runtime.JXPathDecorator + - add setcontextValue and removeContextValue on JAXXContextEntryDef + - introduce scope in BeanValidator (ERROR or WARNING) and related swing stuff + - only enter once in $initialize method in generated code + + 0.6 chemit 20081117 + * 20081118 [chemit] introduce NavigationUtil, save in context selected node + * 20081107 [chemit] improve data binding and code generation : + - make possible inheritance in binding + - add an attribute javaBean to an object : will generate a full java bean support property + - make possible binding to the javaBean added properties + - clean generated code + + * 20081105 [chemit] - introduce a CardLayout2 to extends awt CardLayout + - introduce a NavigationTreeModel + - introduce a Decorator to render Object + - propagate constructor JAXXContext(JAXXContext) in JAXXObject generation + - begin of rst documentation + + * 20081104 [chemit] can add extra beanInfoSearchPath in SwingInitializer + * 20081104 [chemit] add jaxxContextImplementorClass in option to make possible use of other JAXXContext implementor. + * 20081102 [chemit] improve JAXXContext : + - introduce a JAXXContextEntryDef to qualify an entry of a JAXXContext + - do javadoc in JAXXContext + - add logic in DefaultJAXXContext : seek in parent context if entry not found + * 20081102 [chemit] improve tests : + - fix the last failed test from Jaxx original version :) + - dumps tests to JUnit4 :) + * 20081030 [chemit] improve BeanValidator : + - add full PropertyChangeEvent java-bean support and a property valid + - when remove bean from validator, must remove errors from model + - make possible to have a dynamic errorListModel in jaxx files + * 20081030 [chemit] improve JAXXContext : + - fix setContextValue bug when setting twice a same type for a same key + - implements a DefaultJAXXContext + - use this default implementation with delegate pattern in JAXXObject + * 20081030 [chemit] add JAXXAction contract to simplify init of ui with JAXXInitialContext + * 20081027 [chemit] fix bug 1722 + * 20081027 [chemit] add conversion support in validator + * 20081025 [chemit] improve BeanValidator tag : + - add a errorList attribute for set a ErrorListMouseListener on the errorList + - add a beanInitializer attribute for set the validator's bean at runtime + - add a default errorListModel value 'errors' + * 20081025 [chemit] introduce JAXXInitialContext to fill JAXXContext at runtime before $initialize() method + * 20081024 [chemit] fix validator context lost if UI is launched from another thread + + 0.5 chemit 20081002 + * 20081017 [chemit] add validator support + * 20081013 [chemit] can generate logger on jaxx files + * 20081011 [chemit] improve site + * 20081011 [chemit] fix bug on JavaFileParser : works again + * 20081002 [chemit] Using lutinproject 3.0, changing groupId to org.codelutin + * 20081002 [chemit] use a single module jaxx-core (no more core, runtime and jaxx-swing modules) + * 20081002 [chemit] Introduce JAXXContext + * 20081002 [chemit] Fix bug on method creation via scripting + * 20081002 [chemit] Improve i18n integration (works now also for tabs) + * 20081002 [chemit] Improve i18n integration (works now also for tabs) diff --git a/trunk/jaxx-compiler/pom.xml b/trunk/jaxx-compiler/pom.xml new file mode 100644 index 0000000..5ae7f62 --- /dev/null +++ b/trunk/jaxx-compiler/pom.xml @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <!-- ************************************************************* --> + <!-- *** POM Relationships *************************************** --> + <!-- ************************************************************* --> + + <parent> + <groupId>org.nuiton</groupId> + <artifactId>jaxx</artifactId> + <version>1.7.1</version> + </parent> + + <groupId>org.nuiton.jaxx</groupId> + <artifactId>jaxx-compiler</artifactId> + + <dependencies> + + <!-- sibling dependencies --> + + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>jaxx-runtime-api</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>jaxx-runtime-swing</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </dependency> + + </dependencies> + + <!-- ************************************************************* --> + <!-- *** Project Information ************************************* --> + <!-- ************************************************************* --> + + <name>${project.artifactId}</name> + <description>Jaxx compiler api</description> + + <!-- ************************************************************* --> + <!-- *** Build Settings ****************************************** --> + <!-- ************************************************************* --> + <packaging>jar</packaging> + +</project> diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/ClassMap.java b/trunk/jaxx-compiler/src/main/java/jaxx/ClassMap.java new file mode 100644 index 0000000..df3f358 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/ClassMap.java @@ -0,0 +1,96 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx; + +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +/** + * A Map implementation which uses Classes as keys. <code>ClassMap</code> differs from typical maps + * in that it takes subclasses into account; mapping a class to a value also maps all subclasses of + * that class to the value. + * <p/> + * A <code>get</code> operation will return the value associated with the class itself, or failing + * that, with its nearest ancestor for which there exists a mapping. + * @param <T> type of the class + */ +public class ClassMap<T> extends HashMap<ClassDescriptor, T> { + /** log */ + protected static final Log log = LogFactory.getLog(ClassMap.class); + + /** + * Keeps track of automatically-added Classes so we can distinguish them from user-added + * Classes. Unknown Classes are automatically added to the map during <code>get</code> + * calls to speed up subsequent requests, but they must be updated when the mappings + * for their superclasses are modified. + */ + private List<ClassDescriptor> autoKeys = new ArrayList<ClassDescriptor>(); + private static final long serialVersionUID = 5149779660675529037L; + + + /** + * Returns the value associated with the key <code>Class</code>. If the class itself does not have + * a mapping, its superclass will be checked, and so on until an ancestor class with a mapping is + * located. If none of the class' ancestors have a mapping, <code>null</code> is returned. + * + * @param key the class to check + * @return the mapping for the class + */ + @Override + public T get(Object key) { + T result = null; + ClassDescriptor c = (ClassDescriptor) key; + while (c != null) { + result = super.get(c); + if (result != null) { + break; + } + c = c.getSuperclass(); + } + + if (result == null && ((ClassDescriptor) key).isInterface()) { + result = get(ClassDescriptorLoader.getClassDescriptor(Object.class)); + } + + if (c != key && result != null) { // no mapping for the class itself, but found one for a superclass + put((ClassDescriptor) key, result); + autoKeys.add((ClassDescriptor) key); + } + return result; + } + + + /** + * Associates a value with a class and all of its descendents. + * + * @param key the class to map + * @param value the value to map to the class + * @return the old value associated with the class + */ + @Override + public T put(ClassDescriptor key, T value) { + //if (!(key instanceof ClassDescriptor)) { + // throw new IllegalArgumentException("expected ClassDescriptor, got " + key); + //} + if (autoKeys.size() > 0) { // remove all automatic keys which descend from the class being modified + Iterator<ClassDescriptor> i = autoKeys.iterator(); + while (i.hasNext()) { + ClassDescriptor auto = i.next(); + if (key.isAssignableFrom(auto)) { + i.remove(); + remove(auto); + } + } + } + return super.put(key, value); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/CompilerException.java b/trunk/jaxx-compiler/src/main/java/jaxx/CompilerException.java new file mode 100644 index 0000000..27a6c72 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/CompilerException.java @@ -0,0 +1,52 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx; + +/** Thrown by the compiler when an error occurs. */ +public class CompilerException extends RuntimeException { + private static final long serialVersionUID = -9099889519671482440L; + + /** Creates a new <code>ParseException</code>. */ + public CompilerException() { + } + + + /** + * Creates a new <code>ParseException</code> with the specified detail message. + * + * @param msg the exception's detail message + */ + public CompilerException(String msg) { + super(msg); + } + + + /** + * Creates a new <code>ParseException</code> with the specified cause. + * + * @param initCause the exception's initCause + */ + public CompilerException(Throwable initCause) { + super(initCause); + } + + + /** + * Creates a new <code>ParseException</code> with the specified detail message and cause. + * + * @param msg the exception's detail message + * @param initCause the exception's initCause + */ + public CompilerException(String msg, Throwable initCause) { + super(msg, initCause); + } + + + public void printStackTrace() { + super.printStackTrace(); + System.err.println("CompilerException printed from:"); + Thread.dumpStack(); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/DefaultInitializer.java b/trunk/jaxx-compiler/src/main/java/jaxx/DefaultInitializer.java new file mode 100644 index 0000000..762f5af --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/DefaultInitializer.java @@ -0,0 +1,52 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx; + +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.tags.DefaultComponentHandler; +import jaxx.tags.DefaultObjectHandler; +import jaxx.tags.ScriptHandler; +import jaxx.tags.StyleHandler; +import jaxx.tags.TagManager; +import jaxx.types.PrimitiveConverter; +import jaxx.types.TypeManager; + +import java.awt.Component; +import jaxx.compiler.CompiledObjectDecorator; +import jaxx.compiler.DefaultCompiledObjectDecorator; + +/** Initializes support for java. */ +public class DefaultInitializer implements jaxx.spi.Initializer { + + @Override + public void initialize() { + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(Object.class), DefaultObjectHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(Component.class), DefaultComponentHandler.class); + TagManager.registerTag(JAXXCompiler.JAXX_NAMESPACE, "script", new ScriptHandler()); + TagManager.registerTag(JAXXCompiler.JAXX_NAMESPACE, "style", new StyleHandler()); + + PrimitiveConverter primitiveConverter = new PrimitiveConverter(); + TypeManager.registerTypeConverter(boolean.class, primitiveConverter); + TypeManager.registerTypeConverter(Boolean.class, primitiveConverter); + TypeManager.registerTypeConverter(byte.class, primitiveConverter); + TypeManager.registerTypeConverter(Byte.class, primitiveConverter); + TypeManager.registerTypeConverter(short.class, primitiveConverter); + TypeManager.registerTypeConverter(Short.class, primitiveConverter); + TypeManager.registerTypeConverter(int.class, primitiveConverter); + TypeManager.registerTypeConverter(Integer.class, primitiveConverter); + TypeManager.registerTypeConverter(long.class, primitiveConverter); + TypeManager.registerTypeConverter(Long.class, primitiveConverter); + TypeManager.registerTypeConverter(float.class, primitiveConverter); + TypeManager.registerTypeConverter(Float.class, primitiveConverter); + TypeManager.registerTypeConverter(double.class, primitiveConverter); + TypeManager.registerTypeConverter(Double.class, primitiveConverter); + TypeManager.registerTypeConverter(char.class, primitiveConverter); + TypeManager.registerTypeConverter(Character.class, primitiveConverter); + TypeManager.registerTypeConverter(String.class, primitiveConverter); + + CompiledObjectDecorator.registerDecorator("default", DefaultCompiledObjectDecorator.class); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/PrintTagInfo.java b/trunk/jaxx-compiler/src/main/java/jaxx/PrintTagInfo.java new file mode 100644 index 0000000..b02003c --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/PrintTagInfo.java @@ -0,0 +1,118 @@ +package jaxx; + +import jaxx.compiler.JAXXCompiler; +import jaxx.compiler.JAXXCompilerLaunchor; +import jaxx.introspection.JAXXPropertyDescriptor; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.reflect.MethodDescriptor; +import jaxx.tags.DefaultObjectHandler; +import jaxx.tags.TagManager; + +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; +import java.io.OutputStreamWriter; + +/** Generates information about a tag for use on the jaxxframework.org web site. */ +public class PrintTagInfo { + /** + * Displays information about the class name in arg[0]. + * + * @param arg command-line arguments + * @throws Exception if an error occurs + */ + public static void main(String[] arg) throws Exception { + if (arg.length < 1) { + throw new IllegalArgumentException("programm needs at least two parameters : the file where to put the result, and at least one fqn class to treate"); + } + String firstarg = arg[0]; + boolean toFile = false; + BufferedWriter w; + if (firstarg.startsWith("file:")) { + w = new BufferedWriter(new FileWriter(firstarg.substring(5))); + toFile = true; + } else { + w = new BufferedWriter(new OutputStreamWriter(System.out)); + } + + try { + JAXXCompilerLaunchor.loadLibraries(false); + for (int i = toFile ? 1 : 0; i < arg.length; i++) { + String className = arg[i]; + treateClass(w, className); + } + } finally { + w.flush(); + w.close(); + } + + } + + protected static void treateClass(BufferedWriter w, String className) throws ClassNotFoundException, IOException { + + ClassDescriptor beanClass = ClassDescriptorLoader.getClassDescriptor(className); + DefaultObjectHandler handler = TagManager.getTagHandler(beanClass); + + DefaultObjectHandler superHandler = TagManager.getTagHandler(beanClass.getSuperclass()); + + // dump all bean properties + w.append("Properties in ").append(String.valueOf(beanClass)); + w.newLine(); + JAXXPropertyDescriptor[] properties = handler.getJAXXBeanInfo().getJAXXPropertyDescriptors(); + JAXXPropertyDescriptor[] superProperties = superHandler.getJAXXBeanInfo().getJAXXPropertyDescriptors(); + for (JAXXPropertyDescriptor property : properties) { + if (property.getWriteMethodDescriptor() == null) { + continue; + } + + boolean found = false; + String name = property.getName(); + for (JAXXPropertyDescriptor superProperty : superProperties) { + if (superProperty.getName().equals(name)) { + found = true; + break; + } + } + if (!found) { + if (property.getPropertyType() == null) { + System.err.println(name + " has null type"); + } else { + w.append("{{EquivalentAttribute|"); + w.append(name); + w.append("|"); + w.append(className.replace('.', '/')); + w.append("|set"); + w.append(org.apache.commons.lang.StringUtils.capitalize(name)); + w.append("|"); + w.append(JAXXCompiler.getCanonicalName(property.getPropertyType())); + w.append("}}"); + w.append("|-"); + w.newLine(); + } + } + } + + w.newLine(); + w.newLine(); + + // dump all bound methods + dumpMethods(w, beanClass, handler); + } + + protected static void dumpMethods(BufferedWriter w, ClassDescriptor beanClass, DefaultObjectHandler handler) throws IOException { + MethodDescriptor[] methods = beanClass.getMethodDescriptors(); + w.append("Bound methods in ").append(String.valueOf(beanClass)); + w.newLine(); + for (MethodDescriptor method : methods) { + try { + if (handler.isMemberBound(method.getName())) { + w.append("* <tt>").append(method.getName()).append("()</tt>"); + w.newLine(); + } + } catch (Throwable e) { + // ignore ? + } + } + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/ScriptException.java b/trunk/jaxx-compiler/src/main/java/jaxx/ScriptException.java new file mode 100644 index 0000000..1a4ea3d --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/ScriptException.java @@ -0,0 +1,45 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx; + +/** Thrown by the runtime engine when a script error occurs. */ +public class ScriptException extends RuntimeException { + private static final long serialVersionUID = 5687529939397610336L; + + /** Creates a new <code>ScriptException</code>. */ + public ScriptException() { + } + + + /** + * Creates a new <code>ScriptException</code> with the specified detail message. + * + * @param msg the exception's detail message + */ + public ScriptException(String msg) { + super(msg); + } + + + /** + * Creates a new <code>ScriptException</code> with the specified cause. + * + * @param initCause the exception's initCause + */ + public ScriptException(Throwable initCause) { + super(initCause); + } + + + /** + * Creates a new <code>ScriptException</code> with the specified detail message and cause. + * + * @param msg the exception's detail message + * @param initCause the exception's initCause + */ + public ScriptException(String msg, Throwable initCause) { + super(msg, initCause); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/SwingInitializer.java b/trunk/jaxx-compiler/src/main/java/jaxx/SwingInitializer.java new file mode 100644 index 0000000..cdd4663 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/SwingInitializer.java @@ -0,0 +1,127 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx; + +import jaxx.tags.swing.JTextComponentHandler; +import jaxx.tags.swing.JTabbedPaneHandler; +import jaxx.tags.swing.TabHandler; +import jaxx.tags.swing.CellHandler; +import jaxx.tags.swing.JComboBoxHandler; +import jaxx.tags.swing.JSliderHandler; +import jaxx.tags.swing.RowHandler; +import jaxx.tags.swing.JSpinnerHandler; +import jaxx.tags.swing.TableHandler; +import jaxx.tags.swing.JScrollPaneHandler; +import jaxx.tags.swing.JProgressBarHandler; +import jaxx.tags.swing.JInternalFrameHandler; +import jaxx.tags.swing.JToolBarHandler; +import jaxx.tags.swing.JRadioButtonHandler; +import jaxx.tags.swing.JSplitPaneHandler; +import jaxx.tags.swing.LocaleEditorHandler; +import jaxx.tags.swing.JCheckBoxHandler; +import jaxx.tags.swing.EnumEditorHandler; +import jaxx.tags.swing.JWindowHandler; +import jaxx.tags.swing.JAXXTabHandler; +import jaxx.tags.swing.JPasswordFieldHandler; +import jaxx.tags.swing.ApplicationHandler; +import jaxx.tags.swing.JMenuHandler; +import jaxx.tags.swing.ItemHandler; +import jaxx.tags.swing.JListHandler; +import jaxx.tags.swing.JPopupMenuHandler; +import jaxx.tags.swing.JTreeHandler; +import jaxx.tags.swing.*; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.runtime.swing.Application; +import jaxx.runtime.swing.JAXXButtonGroup; +import jaxx.runtime.swing.JAXXComboBox; +import jaxx.runtime.swing.JAXXList; +import jaxx.runtime.swing.JAXXTab; +import jaxx.runtime.swing.JAXXTree; +import jaxx.runtime.swing.Table; +import jaxx.spi.Initializer; +import jaxx.tags.DefaultObjectHandler; +import jaxx.tags.TagManager; +import jaxx.types.ColorConverter; +import jaxx.types.GridBagConstraintsConverter; +import jaxx.types.InsetsConverter; +import jaxx.types.KeyStrokeConverter; +import jaxx.types.TypeManager; +import jaxx.beaninfos.BeanInfoUtil; + +import javax.swing.*; +import javax.swing.text.JTextComponent; +import java.awt.Color; +import java.awt.GridBagConstraints; +import java.awt.Insets; +import jaxx.compiler.BoxedCompiledObjectDecorator; +import jaxx.compiler.CompiledObjectDecorator; +import jaxx.compiler.HelpRootCompiledObjectDecorator; +import jaxx.runtime.swing.editor.EnumEditor; +import jaxx.runtime.swing.editor.LocaleEditor; + +public class SwingInitializer implements Initializer { + + @Override + public void initialize() { + + BeanInfoUtil.addJaxxBeanInfoPath("jaxx.beaninfos"); + + TagManager.registerTag("java.awt.*", "ButtonGroup", new DefaultObjectHandler(ClassDescriptorLoader.getClassDescriptor(JAXXButtonGroup.class))); + + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(Application.class), ApplicationHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JCheckBox.class), JCheckBoxHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JCheckBoxMenuItem.class), JCheckBoxHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(EnumEditor.class), EnumEditorHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(LocaleEditor.class), LocaleEditorHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JAXXComboBox.class), JComboBoxHandler.class); + TagManager.registerTag("javax.swing.*", "JComboBox", new JComboBoxHandler(ClassDescriptorLoader.getClassDescriptor(JAXXComboBox.class))); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JDialog.class), JWindowHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JFrame.class), JWindowHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JInternalFrame.class), JInternalFrameHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JAXXList.class), JListHandler.class); + TagManager.registerTag("javax.swing.*", "JList", new JListHandler(ClassDescriptorLoader.getClassDescriptor(JAXXList.class))); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JMenu.class), JMenuHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JPasswordField.class), JPasswordFieldHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JPopupMenu.class), JPopupMenuHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JProgressBar.class), JProgressBarHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JRadioButton.class), JRadioButtonHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JRadioButtonMenuItem.class), JRadioButtonHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JScrollPane.class), JScrollPaneHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JSlider.class), JSliderHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JSpinner.class), JSpinnerHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JSplitPane.class), JSplitPaneHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JTabbedPane.class), JTabbedPaneHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JTextComponent.class), JTextComponentHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JToggleButton.class), JRadioButtonHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JToolBar.class), JToolBarHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JAXXTree.class), JTreeHandler.class); + TagManager.registerTag("javax.swing.*", "JTree", new JTreeHandler(ClassDescriptorLoader.getClassDescriptor(JAXXTree.class))); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JWindow.class), JWindowHandler.class); + + TagManager.registerDefaultNamespace("JEditorPane", "javax.swing.*"); + TagManager.registerDefaultNamespace("JFormattedTextField", "javax.swing.*"); + TagManager.registerDefaultNamespace("JPasswordField", "javax.swing.*"); + TagManager.registerDefaultNamespace("JTextArea", "javax.swing.*"); + TagManager.registerDefaultNamespace("JTextField", "javax.swing.*"); + TagManager.registerDefaultNamespace("JTextPane", "javax.swing.*"); + + TagManager.registerTag(JAXXCompiler.JAXX_NAMESPACE, "tab", new TabHandler()); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(Table.class), TableHandler.class); + TagManager.registerTag(JAXXCompiler.JAXX_NAMESPACE, "row", new RowHandler()); + TagManager.registerTag(JAXXCompiler.JAXX_NAMESPACE, "cell", new CellHandler()); + TagManager.registerTag(JAXXCompiler.JAXX_NAMESPACE, "item", new ItemHandler()); + + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JAXXTab.class), JAXXTabHandler.class); + + TypeManager.registerTypeConverter(Color.class, new ColorConverter()); + TypeManager.registerTypeConverter(GridBagConstraints.class, new GridBagConstraintsConverter()); + TypeManager.registerTypeConverter(Insets.class, new InsetsConverter()); + TypeManager.registerTypeConverter(KeyStroke.class, new KeyStrokeConverter()); + + CompiledObjectDecorator.registerDecorator("boxed", BoxedCompiledObjectDecorator.class); + CompiledObjectDecorator.registerDecorator("help", HelpRootCompiledObjectDecorator.class); + } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/UnsupportedAttributeException.java b/trunk/jaxx-compiler/src/main/java/jaxx/UnsupportedAttributeException.java new file mode 100644 index 0000000..95890a8 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/UnsupportedAttributeException.java @@ -0,0 +1,49 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx; + +/** + * Thrown by <code>TagHandler</code> when an unsupported attribute is encountered. + * + * @see jaxx.tags.TagHandler + */ +public class UnsupportedAttributeException extends CompilerException { + private static final long serialVersionUID = -6919583037172920343L; + + /** Creates a new <code>UnsupportedAttributeException</code>. */ + public UnsupportedAttributeException() { + } + + + /** + * Creates a new <code>UnsupportedAttributeException</code> with the specified detail message. + * + * @param msg the exception's detail message + */ + public UnsupportedAttributeException(String msg) { + super(msg); + } + + + /** + * Creates a new <code>UnsupportedAttributeException</code> with the specified cause. + * + * @param initCause the exception's initCause + */ + public UnsupportedAttributeException(Throwable initCause) { + super(initCause); + } + + + /** + * Creates a new <code>UnsupportedAttributeException</code> with the specified detail message and cause. + * + * @param msg the exception's detail message + * @param initCause the exception's initCause + */ + public UnsupportedAttributeException(String msg, Throwable initCause) { + super(msg, initCause); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/UnsupportedTagException.java b/trunk/jaxx-compiler/src/main/java/jaxx/UnsupportedTagException.java new file mode 100644 index 0000000..c0db4f2 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/UnsupportedTagException.java @@ -0,0 +1,45 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx; + +/** Thrown by the compiler when an unregistered tag is encountered. */ +public class UnsupportedTagException extends CompilerException { + private static final long serialVersionUID = 3199732135804426699L; + + /** Creates a new <code>UnsupportedTagException</code>. */ + public UnsupportedTagException() { + } + + + /** + * Creates a new <code>UnsupportedTagException</code> with the specified detail message. + * + * @param msg the exception's detail message + */ + public UnsupportedTagException(String msg) { + super(msg); + } + + + /** + * Creates a new <code>UnsupportedTagException</code> with the specified cause. + * + * @param initCause the exception's initCause + */ + public UnsupportedTagException(Throwable initCause) { + super(initCause); + } + + + /** + * Creates a new <code>UnsupportedTagException</code> with the specified detail message and cause. + * + * @param msg the exception's detail message + * @param initCause the exception's initCause + */ + public UnsupportedTagException(String msg, Throwable initCause) { + super(msg, initCause); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/beaninfos/BeanInfoUtil.java b/trunk/jaxx-compiler/src/main/java/jaxx/beaninfos/BeanInfoUtil.java new file mode 100644 index 0000000..c99297a --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/beaninfos/BeanInfoUtil.java @@ -0,0 +1,36 @@ +package jaxx.beaninfos; + +import java.beans.Introspector; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** @author chemit */ +public class BeanInfoUtil { + + public static String[] originalBeanInfoSearchPath; + + public static void addJaxxBeanInfoPath(String... packageNames) { + + String[] searchPath = Introspector.getBeanInfoSearchPath(); + if (originalBeanInfoSearchPath == null) { + originalBeanInfoSearchPath = searchPath; + } + List<String> listSearchPath = new ArrayList<String>(Arrays.asList(searchPath)); + for (String packageName : packageNames) { + if (!listSearchPath.contains(packageName)) { + listSearchPath.add(packageName); + } + } + + Introspector.setBeanInfoSearchPath(listSearchPath.toArray(new String[listSearchPath.size()])); + } + + public static void reset() { + if (originalBeanInfoSearchPath != null) { + Introspector.setBeanInfoSearchPath(originalBeanInfoSearchPath); + originalBeanInfoSearchPath = null; + } + } + +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/compiler/BoxedCompiledObjectDecorator.java b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/BoxedCompiledObjectDecorator.java new file mode 100644 index 0000000..2c7861e --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/BoxedCompiledObjectDecorator.java @@ -0,0 +1,27 @@ +package jaxx.compiler; + +import jaxx.compiler.CompiledObject.ChildRef; +import jaxx.runtime.SwingUtil; + +/** + * A decorator to surround a compiled object (should be a component at least) + * with a JXLayer. + * + * @author tony + * @since 1.2 + */ +public class BoxedCompiledObjectDecorator extends DefaultCompiledObjectDecorator { + + @Override + public void finalizeCompiler(JAXXCompiler compiler, CompiledObject root, CompiledObject object, JavaFile javaFile, String packageName, String className, String fullClassName) { + CompiledObject parent = object.getParent(); + for (ChildRef child : parent.getChilds()) { + if (child.getChild() == object) { + String javaCode = child.getChildJavaCode(); + child.setChildJavaCode(SwingUtil.class.getName()+".boxComponentWithJxLayer(" + javaCode + ")"); + break; + } + } + super.finalizeCompiler(compiler, root, object, javaFile, packageName, className, fullClassName); + } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/compiler/CompiledObject.java b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/CompiledObject.java new file mode 100644 index 0000000..0473f5a --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/CompiledObject.java @@ -0,0 +1,638 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.compiler; + +import jaxx.CompilerException; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.reflect.MethodDescriptor; +import jaxx.tags.DefaultComponentHandler; +import jaxx.tags.TagHandler; +import jaxx.tags.TagManager; +import jaxx.types.TypeManager; + +import java.awt.Container; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Represents an object in the <code>.java</code> file being generated during compilation. There is + * a <code>CompiledObject</code> for each class tag encountered, and certain tags may generate + * additional objects for various reasons. + */ +public class CompiledObject { + + /** The object's id. */ + private String id; + /** Java code referring to the object. */ + private String javaCode; + /** The object's class. */ + private ClassDescriptor objectClass; + /** The style class. */ + private String styleClass; + /** The container containing this CompiledObject. */ + private CompiledObject parent; + /** true if this object overrides an object of the same id in a superclass of the object being compiled */ + private boolean override; + /** + * Comma-separated Java code snippets representing the parameters that should be passed to the object's + * constructor. + */ + private String constructorParams; + /** + * Java code snippet which performs basic initialization of the object (after it has already been constructed). + * Because CompiledObject initialization order cannot be guaranteed, it is not safe to refer to other + * CompiledObjects from initializationCode -- you must refer to them from additionCode instead. + */ + private StringBuffer initializationCode = new StringBuffer(); + /** + * Java code snippet which completes setup by adding any child objects, or otherwise manipulates any refererenced + * objects. Because CompiledObject initialization order cannot be guaranteed, it is not safe to refer to other + * CompiledObjects from initializationCode -- you must refer to them from additionCode instead. + */ + private StringBuffer additionCode = new StringBuffer(); + /** List of all registered event handlers. */ + private List<EventHandler> eventHandlers = new ArrayList<EventHandler>(); + /** All properties that have been applied to this CompiledObject. */ + private Map<String, String> properties = new HashMap<String, String>(); + /** generic types of the compiled object */ + private String[] genericTypes; + /** a flag to indicate if javaBean full support must be support for this object by root object */ + private boolean javaBean; + /** code to initialize the bean (can be null) */ + private String javaBeanInitCode; + /** the type of the override object (can be null if no oveeride) */ + private ClassDescriptor overrideType; + /** + * the decorator (if null will use {@link DefaultCompiledObjectDecorator}). + */ + private CompiledObjectDecorator decorator; + /** + * client properties + */ + private Map<String,String> clientProperties; + + public class ChildRef { + + CompiledObject child; + String constraints; + String childJavaCode; + String delegateCode; + + public ChildRef(CompiledObject child, String constraints, String childJavaCode, String delegateCode) { + this.child = child; + this.constraints = constraints; + this.childJavaCode = childJavaCode; + this.delegateCode = delegateCode; + } + + public CompiledObject getChild() { + return child; + } + + public void setChild(CompiledObject child) { + this.child = child; + } + + public String getConstraints() { + return constraints; + } + + public void setConstraints(String constraints) { + this.constraints = constraints; + } + + public String getChildJavaCode() { + return childJavaCode; + } + + public void setChildJavaCode(String childJavaCode) { + this.childJavaCode = childJavaCode; + } + + public String getDelegateCode() { + return delegateCode; + } + + public void setDelegateCode(String delegateCode) { + this.delegateCode = delegateCode; + } + + public void addToAdditionCode(StringBuffer buffer) { + if (constraints != null) { + buffer.append(javaCode).append(delegateCode).append(".add(").append(childJavaCode).append(", ").append(constraints).append(");"); + } else { + buffer.append(javaCode).append(delegateCode).append(".add(").append(childJavaCode).append(");"); + } + buffer.append(JAXXCompiler.getLineSeparator()); + } + } + private List<ChildRef> childs; + + /** + * Creates a new <code>CompiledObject</code>. To be useful, the object should be registered with a + * <code>JAXXCompiler</code> using {@link JAXXCompiler#registerCompiledObject registerCompiledObject}. + * + * @param id the object's id + * @param objectClass the object's class + * @param compiler the current <code>JAXXCompiler</code> + * @throws NullPointerException if id or class is null + */ + public CompiledObject(String id, ClassDescriptor objectClass, JAXXCompiler compiler) { + this(id, objectClass, compiler, false); + } + + /** + * Creates a new <code>CompiledObject</code>. To be useful, the object should be registered with a + * <code>JAXXCompiler</code> using {@link JAXXCompiler#registerCompiledObject registerCompiledObject}. + * + * @param id the object's id + * @param objectClass the object's class + * @param compiler the current <code>JAXXCompiler</code> + * @param force <code>true</code> to force acceptance of invalid ids + * @throws NullPointerException if id or class is null + */ + public CompiledObject(String id, ClassDescriptor objectClass, JAXXCompiler compiler, boolean force) { + this(id, id, objectClass, compiler, force); + } + + /** + * Creates a new <code>CompiledObject</code>. To be useful, the object should be registered with a + * <code>JAXXCompiler</code> using {@link JAXXCompiler#registerCompiledObject registerCompiledObject}. + * + * @param id the object's id + * @param javaCode Java code referring to the object + * @param objectClass the object's class + * @param force <code>true</code> to force acceptance of invalid ids + * @param compiler the current <code>JAXXCompiler</code> + * @throws CompilerException if the id is not a valid Java identifier + * @throws NullPointerException if id or class is null + */ + public CompiledObject(String id, String javaCode, ClassDescriptor objectClass, JAXXCompiler compiler, boolean force) throws CompilerException { + if (!force) { + if (!isValidID(id)) { + compiler.reportError("the id '" + id + "' is not a valid Java identifier"); + } + } + this.id = id; + this.javaCode = javaCode; + + if (objectClass == null) { + throw new NullPointerException(); + } + this.objectClass = objectClass; + this.childs = new ArrayList<ChildRef>(); + } + + public static boolean isValidID(String id) { + boolean valid = true; + if (id.length() == 0) { + valid = false; + } + if (valid) { + if (!Character.isJavaIdentifierStart(id.charAt(0))) { + valid = false; + } + if (valid) { + for (int i = 1; i < id.length(); i++) { + if (!Character.isJavaIdentifierPart(id.charAt(i))) { + valid = false; + break; + } + } + } + } + return valid; + } + + /** + * True if this object overrides an object in the superclass of the class being compiled. For this to be true, the + * class currently being compiled must be a subclass of another <code>JAXXObject</code> which has an + * identically-named object. + * + * @return <code>true</code> if this object is an override + * @see #setOverride + */ + public boolean isOverride() { + return override; + } + + /** + * Sets whether this class overrides an identically-named object in the parent class. + * + * @param override <code>true</code> if this object is an override + * @see #isOverride + */ + public void setOverride(boolean override) { + this.override = override; + } + + /** + * Returns this object's CSS style class. + * + * @return the value of the <code>styleClass</code> attribute + */ + public String getStyleClass() { + return styleClass; + } + + /** + * Sets this object's CSS style class. + * + * @param styleClass the new style class + */ + public void setStyleClass(String styleClass) { + this.styleClass = styleClass; + } + + /** + * Returns this object's parent container. Non-visual components (and the root container) return <code>null</code>. + * + * @return the object's parent container + */ + public CompiledObject getParent() { + return parent; + } + + /** + * Sets this object's parent container. + * + * @param parent the parent container + */ + public void setParent(CompiledObject parent) { + if (!ClassDescriptorLoader.getClassDescriptor(Container.class).isAssignableFrom(parent.getObjectClass())) { + throw new IllegalArgumentException("parent must descend from java.awt.Container"); + } + this.parent = parent; + } + + /** + * Returns the name of the method that should be generated in the compiled <code>.java</code> file + * in order to create this object. This is just a suggestion and may be ignored. + * + * @return the suggested name of the method which initializes this object + */ + public String getCreationMethodName() { + return "create" + org.apache.commons.lang.StringUtils.capitalize(getId()); + } + + /** + * Returns the name of the method that should be generated in the compiled <code>.java</code> file + * in order to add children to this object. This is just a suggestion and may be ignored. + * + * @return the suggested name of the method which completes this object's setup + */ + public String getAdditionMethodName() { + return "addChildrenTo" + org.apache.commons.lang.StringUtils.capitalize(getId()); + } + + /** + * Returns the type of this object. + * + * @return the class this <code>CompiledObject</code> represents + */ + public ClassDescriptor getObjectClass() { + return objectClass; + } + + /** + * Returns this object's id. Generally, a field with this name will be created in the compiled <code>.java</code> + * file in order to represent this object. + * + * @return the id used to refer to this object + */ + public String getId() { + return id; + } + + /** + * Returns Java code used to refer to this object in the compiled Java file. This is usually the same as its + * id. + * + * @return the Java code for this object + */ + public String getJavaCode() { + String result = javaCode; + if (isOverride()) { + // handle cases where object is overridden to be a different class + result = "((" + JAXXCompiler.getCanonicalName(getObjectClass()) + ") " + javaCode + ")"; + } + return result; + } + + public String getJavaCodeForProperty(String property) { + if (!override) { + return javaCode; + } + String result = "((" + JAXXCompiler.getCanonicalName(getObjectClass()) + ") " + javaCode + ")"; + + String methodName = org.apache.commons.lang.StringUtils.capitalize(property); + try { + MethodDescriptor methodDescriptor = overrideType.getMethodDescriptor("get" + methodName); + if (methodDescriptor != null) { + if (overrideType.getMethodDescriptor("set" + methodName, methodDescriptor.getReturnType()) != null) { + // handle cases where object is overridden to be a different class + result = javaCode; + } + } + } catch (NoSuchMethodException e) { + // lazy error, do nothing + } + return result; + } + + /** + * Returns a list of comma-separated Java code snippets that represent the parameters to pass to this + * object's constructor. + * + * @return the raw constructor params + * @see #setConstructorParams + */ + public String getConstructorParams() { + return constructorParams; + } + + /** + * Sets the parameters to pass to this object's constructor. + * + * @param constructorParams comma-separated Java code snippets representing constructor params + * @see #getConstructorParams + */ + public void setConstructorParams(String constructorParams) { + this.constructorParams = constructorParams; + } + + /** + * Returns the code that performs basic initialization of this object, after it has already been constructed. + * This basic code should not reference any other <code>CompiledObjects</code> as they may not have + * been created yet. + * + * @param compiler compiler to use + * @return the code which initializes this object + */ + public String getInitializationCode(JAXXCompiler compiler) { + StringBuffer result = new StringBuffer(initializationCode.toString()); + for (Object eventHandler : eventHandlers) { + EventHandler handler = (EventHandler) eventHandler; + result.append(getInitializationCode(handler, compiler)); + } + return result.toString(); + } + + protected String getInitializationCode(EventHandler handler, JAXXCompiler compiler) { + MethodDescriptor addMethod = handler.getAddMethod(); + ClassDescriptor listenerClass = addMethod.getParameterTypes()[0]; + return getJavaCode() + '.' + addMethod.getName() + "((" + JAXXCompiler.getCanonicalName(listenerClass) + + ") jaxx.runtime.Util.getEventListener(" + JAXXCompiler.getCanonicalName(listenerClass) + ".class, " + + TypeManager.getJavaCode(handler.getListenerMethod().getName()) + ", " + compiler.getRootObject().getJavaCode() + ", " + + TypeManager.getJavaCode(compiler.getEventHandlerMethodName(handler)) + "));" + JAXXCompiler.getLineSeparator(); + } + + /** + * Returns Java code to complete final setup on this object. This code may reference other + * <code>CompiledObjects</code>, as they are guaranteed to have all been created by this point. + * + * @return code which adds children and performs final setup + */ + public String getAdditionCode() { + return additionCode.toString(); + } + + /** + * Appends code to the initialization code block. A line separator is automatically appended to the end. + * + * @param code the code to add to the initialization block + * @see #getInitializationCode + */ + public void appendInitializationCode(String code) { + this.initializationCode.append(code); + this.initializationCode.append(JAXXCompiler.getLineSeparator()); + } + + /** + * Appends code to the addition code block. A line separator is automatically appended to the end. + * + * @param code the code to add to the addition block + * @see #getAdditionCode + */ + public void appendAdditionCode(String code) { + this.additionCode.append(code); + this.additionCode.append(JAXXCompiler.getLineSeparator()); + } + + /** + * Stores a property for this object. The only effect of calling this method is that the property will + * be returned by <code>getProperties()</code>. + * + * @param property the name of the property + * @param value the property's value + * @see #getProperties + */ + public void addProperty(String property, String value) { + properties.put(property, value); + } + + public boolean hasClientProperties() { + return clientProperties != null && !clientProperties.isEmpty(); + } + + public void addClientProperty(String property, String value) { + getClientProperties().put(property, value); + } + + public String getClientProperty(String key) { + if (!hasClientProperties()) { + return null; + } + return clientProperties.get(key); + } + + public Map<String, String> getClientProperties() { + if (clientProperties == null) { + clientProperties = new HashMap<String, String>(); + } + return clientProperties; + } + + + /** + * Returns all properties which have been set for this object. + * + * @return a <code>Map</code> containing all properties defined for this object + * @see #addProperty + */ + public Map/*<String, String>*/ getProperties() { + return properties; + } + + // TODO: remove this temporary method and complete switchover to MethodDescriptors + public void addEventHandler(String eventId, Method addMethod, Method listenerMethod, String code, JAXXCompiler compiler) { + try { + ClassDescriptor descriptor = ClassDescriptorLoader.getClassDescriptor(getObjectClass().getName()); + String listenerClassName = addMethod.getParameterTypes()[0].getName(); + ClassDescriptor listenerDescriptor = ClassDescriptorLoader.getClassDescriptor(listenerClassName); + MethodDescriptor addMethodDescriptor = descriptor.getMethodDescriptor(addMethod.getName(), listenerDescriptor); + MethodDescriptor listenerMethodDescriptor = listenerDescriptor.getMethodDescriptor(listenerMethod.getName(), ClassDescriptorLoader.getClassDescriptor(listenerMethod.getParameterTypes()[0].getName())); + addEventHandler(eventId, addMethodDescriptor, listenerMethodDescriptor, code, compiler); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Adds an event listener to this object. The generated code will appear in the initialization block. + * + * @param eventId unique (per CompiledObject) identifier for the event handler + * @param addMethod the method which adds the event listener + * @param listenerMethod the method (in the listener class) which is called when the event is fired + * @param code the Java code for the listenerMethod's body + * @param compiler the current <code>JAXXCompiler</code> + * @see #getInitializationCode + */ + public void addEventHandler(String eventId, MethodDescriptor addMethod, MethodDescriptor listenerMethod, String code, JAXXCompiler compiler) { + EventHandler handler = new EventHandler(getId() + "." + eventId, getJavaCode(), addMethod, addMethod.getParameterTypes()[0], listenerMethod, code); + compiler.registerEventHandler(handler); + eventHandlers.add(handler); + + if (getJavaCode().indexOf(".") != -1) { // object lives in another JAXX file and consequently its initialization code won't be output + compiler.appendInitializerCode(getInitializationCode(handler, compiler)); + } + } + + /** + * Adds a child component to this container. The child is added without layout constraints. + * + * @param child the component to add + * @param compiler the current <code>JAXXCompiler</code> + * @throws CompilerException if this object is not a container + * @see #addChild(CompiledObject, String, JAXXCompiler) + */ + public void addChild(CompiledObject child, JAXXCompiler compiler) throws CompilerException { + addChild(child, null, compiler); + } + + /** + * Adds a child component to this container. This variant allows the Java code for a layout constraints + * object to be specified. + * + * @param child the component to add + * @param constraints Java code for the layout constraints object + * @param compiler the current <code>JAXXCompiler</code> + * @throws CompilerException if this object is not a container + * @see #addChild(CompiledObject, JAXXCompiler) + */ + public void addChild(CompiledObject child, String constraints, JAXXCompiler compiler) throws CompilerException { + try { + if (constraints != null) { + constraints = compiler.checkJavaCode(constraints); + } + } catch (CompilerException e) { + compiler.reportError("While parsing 'constraints' attribute: " + e.getMessage()); + } + + if (!child.isOverride()) { + TagHandler tagHandler = TagManager.getTagHandler(getObjectClass()); + if (tagHandler instanceof DefaultComponentHandler && !((DefaultComponentHandler) tagHandler).isContainer()) { + compiler.reportError("component " + this + " may not have children"); + } + + String containerDelegate = ((DefaultComponentHandler) tagHandler).getContainerDelegate(); + String delegateCode = containerDelegate != null ? "." + containerDelegate + "()" : ""; + + child.setParent(this); + + childs.add(new ChildRef(child, constraints, child.getJavaCode(), delegateCode)); + } + } + + @Override + public String toString() { + return getObjectClass().getName() + "[id='" + id + "']"; + } + + public void registerDataBinding(String src, String property, String assignment, JAXXCompiler compiler) throws CompilerException { + compiler.registerDataBinding(src, getId() + "." + property, assignment); + } + public String getGenericTypes() { + if (getGenericTypesLength() == 0) { + // not using it + return ""; + } + String result = ""; + for (int i = 0, j = getGenericTypesLength(); i < j; i++) { + result += ", " + genericTypes[i]; + } + return "< " + result.substring(2) + " >"; + } + + public void setGenericTypes(String[] genericTypes) { + if (genericTypes == null) { + this.genericTypes = null; + return; + } + this.genericTypes = new String[genericTypes.length]; + for (int i = 0, j = genericTypes.length; i < j; i++) { + this.genericTypes[i] = genericTypes[i].trim(); + } + } + + public boolean isJavaBean() { + return javaBean; + } + + public void setJavaBean(boolean javaBean) { + this.javaBean = javaBean; + } + + public ClassDescriptor getOverrideType() { + return overrideType; + } + + public void setOverrideType(ClassDescriptor overrideType) { + this.overrideType = overrideType; + } + + public String getJavaBeanInitCode() { + return javaBeanInitCode; + } + + public void setJavaBeanInitCode(String javaBeanInitCode) { + this.javaBeanInitCode = javaBeanInitCode; + } + + public List<ChildRef> getChilds() { + return childs; + } + + public CompiledObjectDecorator getDecorator() { + return decorator; + } + + public void setDecorator(CompiledObjectDecorator decorator) { + this.decorator = decorator; + } + + public void finalizeCompiler() { + StringBuffer buffer = new StringBuffer(); + + List<CompiledObject.ChildRef> refList = getChilds(); + if (refList == null || refList.isEmpty()) { + return; + } + + for (ChildRef childRef : refList) { + childRef.addToAdditionCode(buffer); + } + + additionCode = buffer.append(additionCode); + } + + public int getGenericTypesLength() { + return genericTypes == null ? 0 : genericTypes.length; + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/compiler/CompiledObjectDecorator.java b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/CompiledObjectDecorator.java new file mode 100644 index 0000000..d9d7dd9 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/CompiledObjectDecorator.java @@ -0,0 +1,76 @@ +package jaxx.compiler; + +import java.util.Map; +import java.util.TreeMap; +import jaxx.CompilerException; + +/** + * + * A class to decorate a compiled object at generation time. + * + * Contains also a cache of decorator in a dictonnary indexed by fqn of decorator. + * + * Use the {@link #getDecorator(java.lang.String)} to obtain the cached decorator. + * + * Note : The implementation of this class must be stateless. + * + * @author tony + * @since 1.2 + */ +public abstract class CompiledObjectDecorator { + + protected static Map<String, CompiledObjectDecorator> cache; + + public static void registerDecorator(String key, Class<? extends CompiledObjectDecorator> klass) { + synchronized (getCache()) { + if (getCache().containsKey(key)) { + throw new IllegalArgumentException("the decorator with key [" + key + "] is already registred! use another key name"); + } + try { + getCache().put(key, klass.newInstance()); + } catch (InstantiationException ex) { + throw new IllegalArgumentException("could not create decorator " + klass + " for reason " + ex.getMessage(), ex); + } catch (IllegalAccessException ex) { + throw new IllegalArgumentException("could not create decorator " + klass + " for reason " + ex.getMessage(), ex); + } + } + } + + public static CompiledObjectDecorator getDecorator(String name) { + CompiledObjectDecorator decorator = getCache().get(name); + if (decorator == null) { + throw new IllegalArgumentException("could not find decorator with key " + name + " (known decorators : " + getCache().keySet()); + } + return decorator; + } + + public static CompiledObjectDecorator getDecorator(Class<?> type) { + for (CompiledObjectDecorator decorator : getCache().values()) { + if (type == decorator.getClass()) { + return decorator; + } + } + return null; + } + + protected static synchronized Map<String, CompiledObjectDecorator> getCache() { + if (cache == null) { + cache = new TreeMap<String, CompiledObjectDecorator>(); + } + return cache; + } + + public static void reset() { + if (cache != null) { + cache.clear(); + } + } + + public abstract void finalizeCompiler(JAXXCompiler compiler, CompiledObject root, CompiledObject object, JavaFile javaFile, String packageName, String className, String fullClassName); + + public abstract String getCreationCode(JAXXCompiler compiler, CompiledObject object) throws CompilerException; + + public abstract boolean createInitializer(JAXXCompiler compiler, CompiledObject root, CompiledObject object, StringBuffer code, boolean lastWasMethodCall); + + public abstract String createCompleteSetupMethod(JAXXCompiler compiler, CompiledObject object, JavaFile javaFile, StringBuffer initDataBindings); +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/compiler/CompilerOptions.java b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/CompilerOptions.java new file mode 100644 index 0000000..9f73694 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/CompilerOptions.java @@ -0,0 +1,406 @@ +package jaxx.compiler; + +import org.apache.commons.lang.builder.ToStringBuilder; + +import java.io.File; + +/** + * Stores options which affect the jaxxc tool's operation. These options are generally specified by the + * user on the command line. + */ +public class CompilerOptions { + private File targetDirectory; + private File javacTargetDirectory; + private String classPath; + private String javacOpts; + private boolean keepJavaFiles; + private boolean optimize; + private boolean verbose; + private boolean profile; + /** a flag to enable or disable i18n generation */ + private boolean i18nable; + + /** a flag to add or not logger on generated jaxx files */ + private boolean addLogger; + + /** a flag to not reset compiler after a compile */ + private boolean resetAfterCompile; + + /** the name of implementation of {@link jaxx.runtime.JAXXContext} to be used on {@link jaxx.runtime.JAXXObject}. */ + protected String jaxxContextImplementorClass; + + /** list of fqn of class toimport for all generated jaxx files */ + protected String[] extraImports; + + /** default error ui */ + private Class<?> defaultErrorUI; + + private ClassLoader classLoader; + + private Class<? extends JAXXCompiler> compilerClass; + + /** + * @deprecated prefer use {@link #validatorClass} + */ + @Deprecated + private String validatorFQN; + /** + * the validator class to use. + * + * @since 1.6.0 + */ + private Class<?> validatorClass; + + /** a flag to use {@link javax.swing.UIManager} to retreave icons. */ + private boolean useUIManagerForIcon; + + /** a flag to generate javax help for any */ + private boolean generateHelp; + + private String helpBrokerFQN; + /** + * The prefix to add to i18n key for any help i18n key. + * + * @since 1.3 + */ + protected String helpsetI18nPrefix; + /** + * The suffix to add to i18n key for an help Id. + * + * @since 1.3 + */ + protected String helpsetTitleI18nSuffix; + /** + * The suffix to add to i18n key for an toc Id. + * + * @since 1.3 + */ + protected String helpsetTocI18nSuffix; + /** + * The suffix to add to i18n key for an toc Id. + * + * @since 1.3 + */ + protected String helpsetIndexI18nSuffix; + /** + * The helpset name + * + * @since 1.3 + */ + protected String helpSetName; + /** the default compiled object decorator to use if none specifed via decorator attribute */ + private Class<? extends CompiledObjectDecorator> defaultDecoratorClass; + + /** + * Returns the target directory, generally specified with the "-d" option on the command line. + * + * @return the target directory + * @see #setTargetDirectory + */ + public File getJavacTargetDirectory() { + if (javacTargetDirectory == null) { + // to use the old way : if javacTargetDirectory not specified, + // use same directory as targetDirectory (says where the java sources + // are generated) + return targetDirectory; + } + return javacTargetDirectory; + } + + /** + * Returns the target directory, generally specified with the "-d" option on the command line. + * + * @return the target directory + * @see #setTargetDirectory + */ + public File getTargetDirectory() { + return targetDirectory; + } + + + /** + * Sets the target directory into which compiled classes will be placed. + * + * @param targetDirectory the target directory + * @see #getTargetDirectory + */ + public void setTargetDirectory(File targetDirectory) { + this.targetDirectory = targetDirectory; + } + + public void setJavacTargetDirectory(File javacTargetDirectory) { + this.javacTargetDirectory = javacTargetDirectory; + } + + /** + * Returns the class path to be used during compilation. + * + * @return the class path to be used during compilation + * @see #setClassPath + */ + public String getClassPath() { + return classPath; + } + + /** + * Sets the class path to be used during compilation. + * + * @param classPath the compilation class path + * @see #getClassPath + */ + public void setClassPath(String classPath) { + this.classPath = classPath; + } + + + /** + * Returns the options to be passed into <code>javac</code>. + * + * @return options to be passed into <code>javac</code> + * @see #setJavacOpts + */ + public String getJavacOpts() { + return javacOpts; + } + + + /** + * Sets options to be passed into <code>javac</code>. + * + * @param javacOpts options to be passed into <code>javac</code> + * @see #getJavacOpts + */ + public void setJavacOpts(String javacOpts) { + this.javacOpts = javacOpts; + } + + + /** + * Returns whether or not generated Java files should be preserved after compilation. + * + * @return <code>true</code> if generated Java files should be preserved, <code>false</code> to delete + * @see #setKeepJavaFiles + */ + public boolean getKeepJavaFiles() { + return keepJavaFiles; + } + + + /** + * Sets whether or not generated Java files should be preserved after compilation. + * + * @param keepJavaFiles <code>true</code> if generated Java files should be preserved, <code>false</code> to delete + * @see #getKeepJavaFiles + */ + public void setKeepJavaFiles(boolean keepJavaFiles) { + this.keepJavaFiles = keepJavaFiles; + } + + + /** + * Returns whether or not optimization should be performed. + * + * @return whether or not optimizations should be performed + */ + public boolean getOptimize() { + return optimize; + } + + + /** + * Sets whether or not optimizations should be performed. + * + * @param optimize <code>true</code> to perform optimizations during compilation + * @see #getOptimize + */ + public void setOptimize(boolean optimize) { + this.optimize = optimize; + } + + public boolean isVerbose() { + return verbose; + } + + public void setVerbose(boolean verbose) { + this.verbose = verbose; + } + + public boolean isI18nable() { + return i18nable; + } + + public boolean isUseUIManagerForIcon() { + return useUIManagerForIcon; + } + + public void setI18nable(boolean i18nable) { + this.i18nable = i18nable; + } + + public boolean isAddLogger() { + return addLogger; + } + + public void setAddLogger(boolean addLogger) { + this.addLogger = addLogger; + } + + public String getJaxxContextImplementorClass() { + return jaxxContextImplementorClass; + } + + public void setJaxxContextImplementorClass(String jaxxContextImplementorClass) { + this.jaxxContextImplementorClass = jaxxContextImplementorClass; + } + + public String[] getExtraImports() { + return extraImports; + } + + public void setExtraImports(String[] extraImports) { + this.extraImports = extraImports; + } + + public boolean isResetAfterCompile() { + return resetAfterCompile; + } + + public void setResetAfterCompile(boolean resetAfterCompile) { + this.resetAfterCompile = resetAfterCompile; + } + + public void setUseUIManagerForIcon(boolean useUIManagerForIcon) { + this.useUIManagerForIcon = useUIManagerForIcon; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + + + public void setDefaultErrorUI(Class<?> defaultErrorUI) { + this.defaultErrorUI = defaultErrorUI; + } + + public boolean isKeepJavaFiles() { + return keepJavaFiles; + } + + public boolean isOptimize() { + return optimize; + } + + public Class<?> getDefaultErrorUI() { + return defaultErrorUI; + } + + public ClassLoader getClassLoader() { + return classLoader; + } + + public void setClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + public Class<? extends JAXXCompiler> getCompilerClass() { + return compilerClass; + } + + public void setCompilerClass(Class<? extends JAXXCompiler> compilerClass) { + this.compilerClass = compilerClass; + } + + @Deprecated + public String getValidatorFQN() { + return validatorClass.getName(); + } + + @Deprecated + public void setValidatorFQN(String validatorFQN) { + this.validatorFQN = validatorFQN; + } + + public Class<? extends CompiledObjectDecorator> getDefaultDecoratorClass() { + return defaultDecoratorClass; + } + + public void setDefaultDecoratorClass(Class<? extends CompiledObjectDecorator> defaultDecoratorClass) { + this.defaultDecoratorClass = defaultDecoratorClass; + } + + public boolean isProfile() { + return profile; + } + + public void setProfile(boolean profile) { + this.profile = profile; + } + + public boolean isGenerateHelp() { + return generateHelp; + } + + public void setGenerateHelp(boolean generateHelp) { + this.generateHelp = generateHelp; + } + + public String getHelpBrokerFQN() { + return helpBrokerFQN; + } + + public void setHelpBrokerFQN(String helpBrokerFQN) { + this.helpBrokerFQN = helpBrokerFQN; + } + + public String getHelpsetIndexI18nSuffix() { + return helpsetIndexI18nSuffix; + } + + public void setHelpsetIndexI18nSuffix(String helpsetIndexI18nSuffix) { + this.helpsetIndexI18nSuffix = helpsetIndexI18nSuffix; + } + + public String getHelpsetTitleI18nSuffix() { + return helpsetTitleI18nSuffix; + } + + public void setHelpsetTitleI18nSuffix(String helpsetTitleI18nSuffix) { + this.helpsetTitleI18nSuffix = helpsetTitleI18nSuffix; + } + + public String getHelpsetTocI18nSuffix() { + return helpsetTocI18nSuffix; + } + + public void setHelpsetTocI18nSuffix(String helpsetTocI18nSuffix) { + this.helpsetTocI18nSuffix = helpsetTocI18nSuffix; + } + + public String getHelpSetName() { + return helpSetName; + } + + public void setHelpSetName(String helpSetName) { + this.helpSetName = helpSetName; + } + + public String getHelpsetI18nPrefix() { + return helpsetI18nPrefix; + } + + public void setHelpsetI18nPrefix(String helpsetI18nPrefix) { + this.helpsetI18nPrefix = helpsetI18nPrefix; + } + + public Class<?> getValidatorClass() { + return validatorClass; + } + + public void setValidatorClass(Class<?> validatorClass) { + this.validatorClass = validatorClass; + } + + + +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/compiler/DataBinding.java b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/DataBinding.java new file mode 100644 index 0000000..5aceb84 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/DataBinding.java @@ -0,0 +1,92 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.compiler; + +import jaxx.CompilerException; +import jaxx.types.TypeManager; + +/** + * Represents a data binding in a JAXX file. <code>DataBinding</code> uses {@link DataSource} to + * track changes to a source expression and update the destination. + */ +public class DataBinding { + private String id; + + /** The DatSource which tracks source expression changes. */ + private DataSource dataSource; + + /** The data binding destination in the form <code><id>.<propertyName></code>. */ + private String dest; + + /** + * A Java snippet which will cause the destination property to be updated with the current value of + * the binding. + */ + private String assignment; + + /** The current <code>JAXXCompiler</code>. */ + private JAXXCompiler compiler; + + + /** + * Creates a new data binding. + * + * @param source the Java source code for the data binding expression + * @param dest the data binding destination in the form <code><id>.<propertyName></code> + * @param assignment Java snippet which will cause the destination property to be updated with the current value of the binding + * @param compiler the current <code>JAXXCompiler</code> + */ + public DataBinding(String source, String dest, String assignment, JAXXCompiler compiler) { + this.id = dest; + this.dataSource = new DataSource(id, source, compiler); + this.dest = dest; + this.assignment = assignment; + this.compiler = compiler; + } + + + public String getId() { + return id; + } + + + /** + * Compiles the data binding expression. This method calls methods in <code>JAXXCompiler</code> + * to add the Java code that performs the data binding setup. + * + * @param quickNoDependencies true to optimize bindings with no dependencies by simply running them at startup time + * @return <code>true</code> if the expression has dependencies, <code>false</code> otherwise + * @throws CompilerException if a compilation error occurs + */ + public boolean compile(boolean quickNoDependencies) throws CompilerException { + // DataSource.compile handles all of the listener additions + boolean result = dataSource.compile("new jaxx.runtime.DataBindingListener(" + compiler.getRootObject().getJavaCode() + ", " + TypeManager.getJavaCode(id) + ")"); + + if (!result && quickNoDependencies) { + if (!dest.endsWith(".layout")) // layout is specially handled early in the chain + { + compiler.appendInitDataBindings(assignment + JAXXCompiler.getLineSeparator()); + } + return false; // no dependencies, just a static expression + } + if (compiler.haveProcessDataBinding()) { + compiler.appendProcessDataBinding(" else "); + } else { + compiler.appendProcessDataBinding(" "); + } + compiler.appendProcessDataBinding("if (" + TypeManager.getJavaCode(id) + ".equals($dest)) {" + JAXXCompiler.getLineSeparator()); + String objectCode = dataSource.getObjectCode(); + if (objectCode != null) { + compiler.appendProcessDataBinding(" if (" + objectCode + " != null) {" + JAXXCompiler.getLineSeparator()); + compiler.appendProcessDataBinding(" "); + } + compiler.appendProcessDataBinding(" " + assignment.trim()); + if (objectCode != null) { + compiler.appendProcessDataBinding(JAXXCompiler.getLineSeparator() + " }"); + } + compiler.appendProcessDataBinding(JAXXCompiler.getLineSeparator() + " }"); + return true; + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/compiler/DataSource.java b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/DataSource.java new file mode 100644 index 0000000..0f88ea2 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/DataSource.java @@ -0,0 +1,454 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.compiler; + +import jaxx.CompilerException; +import jaxx.UnsupportedAttributeException; +import jaxx.parser.JavaParser; +import jaxx.parser.JavaParserConstants; +import jaxx.parser.JavaParserTreeConstants; +import jaxx.parser.SimpleNode; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.reflect.FieldDescriptor; +import jaxx.reflect.MethodDescriptor; +import jaxx.tags.DefaultObjectHandler; +import jaxx.tags.TagManager; +import jaxx.types.TypeManager; + +import java.beans.Introspector; +import java.beans.PropertyChangeListener; +import java.io.StringReader; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * Represents a Java expression which fires a <code>PropertyChangeEvent</code> when it can be + * determined that its value may have changed. Events are fired on a "best effort" basis, and events + * may either be fired too often (the value has not actually changed) or not often enough (the value + * changed but no event was fired). + */ +public class DataSource { + private class NULL { + } // type attached to "null" constants in parsed expressions + + private String id; + + /** The Java source code for the expression. */ + private String source; + + /** The current <code>JAXXCompiler</code>. */ + private JAXXCompiler compiler; + + /** List of symbols which this data source expression depends on. */ + private List<String> dependencySymbols = new ArrayList<String>(); + + private StringBuffer addListenerCode = new StringBuffer(); + private StringBuffer removeListenerCode = new StringBuffer(); + private boolean compiled; + + /** the delegate of property to be required */ + private String objectCode; + + /** + * Creates a new data source. After creating a <code>DataSource</code>, use {@link #compile} + * to cause it to function at runtime. + * + * @param id the DataSource's id + * @param source the Java source code for the data source expression + * @param compiler the current <code>JAXXCompiler</code> + */ + public DataSource(String id, String source, JAXXCompiler compiler) { + this.id = id; + this.source = source; + this.compiler = compiler; + } + + + public String getId() { + return id; + } + + public String getSource() { + return source; + } + + public String getObjectCode() { + return objectCode; + } + + /** + * Compiles the data source expression and listener. This method calls methods in <code>JAXXCompiler</code> + * to add the Java code that performs the data source setup. Adding listeners to <code>DataSource</code> is + * slightly more complicated than with ordinary classes, because <code>DataSource</code> only exists at compile + * time. You must pass in a Java expression which evaluates to a <code>PropertyChangeListener</code>; this + * expression will be compiled and evaluated at runtime to yield the <code>DataSource's</code> listener. + * + * @param propertyChangeListenerCode Java code snippet which evaluates to a <code>PropertyChangeListener</code> + * @return <code>true</code> if the expression has dependencies, <code>false</code> otherwise + * @throws CompilerException if a compilation error occurs + */ + public boolean compile(String propertyChangeListenerCode) throws CompilerException { + if (compiled) { + throw new IllegalStateException(this + " has already been compiled"); + } + String id = compiler.getAutoId(ClassDescriptorLoader.getClassDescriptor(getClass())); + JavaParser p = new JavaParser(new StringReader(source + ";")); + while (!p.Line()) { + SimpleNode node = p.popNode(); + scanNode(node, id); + } + + if (dependencySymbols.size() > 0) { + //TC 20081108 prefer add a real JavaField instead of raw code + //compiler.appendBodyCode("private PropertyChangeListener " + id + " = " + propertyChangeListenerCode + ";\n"); + compiler.addSimpleField(new JavaField(Modifier.PRIVATE, PropertyChangeListener.class.getName(), id, propertyChangeListenerCode)); + } + + compileListeners(); + compiled = true; + + return dependencySymbols.size() > 0; + } + + /** @return a list of symbols on which this data source depends. */ + public Collection<String> getDependencies() { + return Collections.unmodifiableList(dependencySymbols); + } + + /** + * Examines a node to identify any dependencies it contains. + * + * @param node node to scan + * @param listenerId id of listener + * @throws jaxx.CompilerException ? + */ + private void scanNode(SimpleNode node, String listenerId) throws CompilerException { + switch (node.getId()) { + case JavaParserTreeConstants.JJTMETHODDECLARATION: + break; + case JavaParserTreeConstants.JJTFIELDDECLARATION: + break; + + default: + int count = node.jjtGetNumChildren(); + for (int i = 0; i < count; i++) { + scanNode(node.getChild(i), listenerId); + } + determineNodeType(node, listenerId); + } + } + + private ClassDescriptor determineLiteralType(SimpleNode node) { + assert node.getId() == JavaParserTreeConstants.JJTLITERAL; + if (node.jjtGetNumChildren() == 1) { + int id = node.getChild(0).getId(); + if (id == JavaParserTreeConstants.JJTBOOLEANLITERAL) { + return ClassDescriptorLoader.getClassDescriptor(boolean.class); + } + if (id == JavaParserTreeConstants.JJTNULLLITERAL) { + return ClassDescriptorLoader.getClassDescriptor(NULL.class); + } + throw new RuntimeException("Expected BooleanLiteral or NullLiteral, found " + JavaParserTreeConstants.jjtNodeName[id]); + } + int id = node.firstToken.kind; + switch (id) { + case JavaParserConstants.INTEGER_LITERAL: + if (node.firstToken.image.toLowerCase().endsWith("l")) { + return ClassDescriptorLoader.getClassDescriptor(long.class); + } + return ClassDescriptorLoader.getClassDescriptor(int.class); + case JavaParserConstants.CHARACTER_LITERAL: + return ClassDescriptorLoader.getClassDescriptor(char.class); + case JavaParserConstants.FLOATING_POINT_LITERAL: + if (node.firstToken.image.toLowerCase().endsWith("f")) { + return ClassDescriptorLoader.getClassDescriptor(float.class); + } + return ClassDescriptorLoader.getClassDescriptor(double.class); + case JavaParserConstants.STRING_LITERAL: + return ClassDescriptorLoader.getClassDescriptor(String.class); + default: + throw new RuntimeException("Expected literal token, found " + JavaParserConstants.tokenImage[id]); + } + } + + /** + * Scans through a compound symbol (foo.bar.baz) to identify and track all trackable pieces of it. + * + * @param symbol symbol to scan + * @param contextClass current class context + * @param isMethod flag to search a method + * @param listenerId id of the listener + * @return the type of the symbol (or null if it could not be determined). + */ + private ClassDescriptor scanCompoundSymbol(String symbol, ClassDescriptor contextClass, boolean isMethod, String listenerId) { + String[] tokens = symbol.split("\\s*\\.\\s*"); + StringBuffer currentSymbol = new StringBuffer(); + StringBuffer tokensSeenSoFar = new StringBuffer(); + boolean accepted; // if this ends up false, it means we weren't able to figure out + // which object the method is being invoked on + boolean recognizeClassNames = true; + for (int j = 0; j < tokens.length - (isMethod ? 1 : 0); j++) { + accepted = false; + + if (tokensSeenSoFar.length() > 0) { + tokensSeenSoFar.append('.'); + } + tokensSeenSoFar.append(tokens[j]); + if (currentSymbol.length() > 0) { + currentSymbol.append('.'); + } + currentSymbol.append(tokens[j]); + + if (currentSymbol.indexOf(".") == -1) { + String memberName = currentSymbol.toString(); + CompiledObject object = compiler.getCompiledObject(memberName); + if (object != null) { + contextClass = object.getObjectClass(); + currentSymbol.setLength(0); + accepted = true; + recognizeClassNames = false; + } else { + try { + FieldDescriptor field = contextClass.getFieldDescriptor(memberName); + trackMemberIfPossible(tokensSeenSoFar.toString(), contextClass, field.getName(), false, listenerId); + contextClass = field.getType(); + currentSymbol.setLength(0); + accepted = true; + recognizeClassNames = false; + } + catch (NoSuchFieldException e) { + if (j == 0 || j == 1 && tokens[0].equals(compiler.getRootObject().getId())) { // still in root context + FieldDescriptor[] newFields = compiler.getScriptFields(); + for (FieldDescriptor newField : newFields) { + if (newField.getName().equals(memberName)) { + addListener(tokensSeenSoFar.toString(), + null, + "addPropertyChangeListener(\"" + memberName + "\", " + listenerId + ");" + JAXXCompiler.getLineSeparator(), + "removePropertyChangeListener(\"" + memberName + "\", " + listenerId + ");" + JAXXCompiler.getLineSeparator()); + contextClass = newField.getType(); + assert contextClass != null : "script field '" + memberName + "' is defined, but has type null"; + currentSymbol.setLength(0); + accepted = true; + recognizeClassNames = false; + break; + } + } + } + } + } + } + if (currentSymbol.length() > 0 && recognizeClassNames) { + contextClass = TagManager.resolveClass(currentSymbol.toString(), compiler); + if (contextClass != null) { + currentSymbol.setLength(0); + //accepted = true; + //recognizeClassNames = false; + // TODO: for now we don't handle statics + return null; + } + } + if (!accepted) { + return null; + } + } + + return contextClass; + } + + /** + * Adds type information to nodes where possible, and as a side effect adds event listeners to nodes which + * can be tracked. + * + * @param expression the node to scan + * @param listenerId id of the listener + * @return the class descriptor of the return type or null + */ + private ClassDescriptor determineExpressionType(SimpleNode expression, String listenerId) { + assert expression.getId() == JavaParserTreeConstants.JJTPRIMARYEXPRESSION; + SimpleNode prefix = expression.getChild(0); + if (prefix.jjtGetNumChildren() == 1) { + int type = prefix.getChild(0).getId(); + if (type == JavaParserTreeConstants.JJTLITERAL || type == JavaParserTreeConstants.JJTEXPRESSION) { + prefix.setJavaType(prefix.getChild(0).getJavaType()); + } else if (type == JavaParserTreeConstants.JJTNAME && expression.jjtGetNumChildren() == 1) // name with no arguments after it + { + prefix.setJavaType(scanCompoundSymbol(prefix.getText().trim(), compiler.getRootObject().getObjectClass(), false, listenerId)); + } + } + + if (expression.jjtGetNumChildren() == 1) { + return prefix.getJavaType(); + } + + ClassDescriptor contextClass = prefix.getJavaType(); + if (contextClass == null) { + contextClass = compiler.getRootObject().getObjectClass(); + } + String lastNode = prefix.getText().trim(); + + for (int i = 1; i < expression.jjtGetNumChildren(); i++) { + SimpleNode suffix = expression.getChild(i); + if (suffix.jjtGetNumChildren() == 1 && suffix.getChild(0).getId() == JavaParserTreeConstants.JJTARGUMENTS) { + if (suffix.getChild(0).jjtGetNumChildren() == 0) { // at the moment only no-argument methods are trackable + contextClass = scanCompoundSymbol(lastNode, contextClass, true, listenerId); + if (contextClass == null) { + return null; + } + int dotPos = lastNode.lastIndexOf("."); + String objectCode = dotPos == -1 ? "" : lastNode.substring(0, dotPos); + for (int j = i - 2; j >= 0; j--) { + objectCode = expression.getChild(j).getText() + objectCode; + } + if (objectCode.length() == 0) { + objectCode = compiler.getRootObject().getJavaCode(); + } + String methodName = lastNode.substring(dotPos + 1).trim(); + try { + MethodDescriptor method = contextClass.getMethodDescriptor(methodName); + trackMemberIfPossible(objectCode, contextClass, method.getName(), true, listenerId); + return method.getReturnType(); + } + catch (NoSuchMethodException e) { + // happens for methods defined in the current JAXX file via scripts + String propertyName = null; + if (methodName.startsWith("is")) { + propertyName = Introspector.decapitalize(methodName.substring("is".length())); + } else if (methodName.startsWith("get")) { + propertyName = Introspector.decapitalize(methodName.substring("get".length())); + } + if (propertyName != null) { + MethodDescriptor[] newMethods = compiler.getScriptMethods(); + for (MethodDescriptor newMethod : newMethods) { + if (newMethod.getName().equals(methodName)) { + addListener(compiler.getRootObject().getId(), + null, + "addPropertyChangeListener(\"" + propertyName + "\", " + listenerId + ");" + JAXXCompiler.getLineSeparator(), + "removePropertyChangeListener(\"" + propertyName + "\", " + listenerId + ");" + JAXXCompiler.getLineSeparator()); + contextClass = newMethod.getReturnType(); + break; + } + } + } + } + } + } + lastNode = suffix.getText().trim(); + if (lastNode.startsWith(".")) { + lastNode = lastNode.substring(1); + } + } + + return null; + } + + private void trackMemberIfPossible(String objectCode, ClassDescriptor objectClass, String memberName, boolean method, String listenerId) { + if (objectClass.isInterface()) // might be technically possible to track in some cases, but for now + { + return; // we can't create a DefaultObjectHandler for interfaces + } + + DefaultObjectHandler handler = TagManager.getTagHandler(objectClass); + try { + if (handler.isMemberBound(memberName)) { + addListener(objectCode + "." + memberName + (method ? "()" : ""), + objectCode, + handler.getAddMemberListenerCode(objectCode, id, memberName, listenerId, compiler), + handler.getRemoveMemberListenerCode(objectCode, id, memberName, listenerId, compiler)); + } + } + catch (UnsupportedAttributeException e) { + // ignore -- this is thrown for methods like toString(), for which there is no tracking and + // no setting support + } + } + + /** + * Adds type information to nodes where possible, and as a side effect adds event listeners to nodes which + * can be tracked. + * + * @param node node to scan + * @param listenerId the listener id + */ + private void determineNodeType(SimpleNode node, String listenerId) { + ClassDescriptor type = null; + if (node.jjtGetNumChildren() == 1) { + type = node.getChild(0).getJavaType(); + } + switch (node.getId()) { + case JavaParserTreeConstants.JJTCLASSORINTERFACETYPE: + type = ClassDescriptorLoader.getClassDescriptor(Class.class); + break; + case JavaParserTreeConstants.JJTPRIMARYEXPRESSION: + type = determineExpressionType(node, listenerId); + break; + case JavaParserTreeConstants.JJTLITERAL: + type = determineLiteralType(node); + break; + case JavaParserTreeConstants.JJTCASTEXPRESSION: + type = TagManager.resolveClass(node.getChild(0).getText(), compiler); + break; + } + node.setJavaType(type); + } + + private void addListener(String dependencySymbol, String objectCode, String addCode, String removeCode) { + this.objectCode = objectCode; + if (!dependencySymbols.contains(dependencySymbol)) { + dependencySymbols.add(dependencySymbol); + if (objectCode != null) { + addListenerCode.append("if (").append(objectCode).append(" != null) {").append(JAXXCompiler.getLineSeparator()); + addListenerCode.append(" "); + } + addListenerCode.append(" ").append(addCode); + if (objectCode != null) { + addListenerCode.append(" ").append("}"); + } + + if (objectCode != null) { + removeListenerCode.append("if (").append(objectCode).append(" != null) {").append(JAXXCompiler.getLineSeparator()); + removeListenerCode.append(" "); + } + removeListenerCode.append(" ").append(removeCode); + if (objectCode != null) { + removeListenerCode.append(" }"); + } + } + } + + private void compileListeners() { + String javaCodeId = TypeManager.getJavaCode(id); + if (addListenerCode.length() > 0) { + if (compiler.haveApplyDataBinding()) { + compiler.appendApplyDataBinding(" else "); + } + compiler.appendApplyDataBinding("if (" + javaCodeId + ".equals($binding)) {" + JAXXCompiler.getLineSeparator()); + compiler.appendApplyDataBinding(" " + addListenerCode + JAXXCompiler.getLineSeparator()); + compiler.appendApplyDataBinding("}"); + //if (compiler.applyDataBinding.length() > 0) + // compiler.applyDataBinding.append("else "); + //compiler.applyDataBinding.append("if ($binding.equals(").append(TypeManager.getJavaCode(id)).append(")) {").append(JAXXCompiler.getLineSeparator()); + //compiler.applyDataBinding.append(" ").append(addListenerCode).append(JAXXCompiler.getLineSeparator()); + //compiler.applyDataBinding.append("}").append(JAXXCompiler.getLineSeparator()); + } + + if (removeListenerCode.length() > 0) { + if (compiler.haveRemoveDataBinding()) { + compiler.appendRemoveDataBinding(" else "); + } + compiler.appendRemoveDataBinding("if (" + javaCodeId + ".equals($binding)) {" + JAXXCompiler.getLineSeparator()); + compiler.appendRemoveDataBinding(" " + removeListenerCode + JAXXCompiler.getLineSeparator()); + compiler.appendRemoveDataBinding("}"); + //if (compiler.removeDataBinding.length() > 0) + // compiler.removeDataBinding.append("else "); + //compiler.removeDataBinding.append("if ($binding.equals(").append(TypeManager.getJavaCode(id)).append(")) {").append(JAXXCompiler.getLineSeparator()); + //compiler.removeDataBinding.append(" ").append(removeListenerCode).append(JAXXCompiler.getLineSeparator()); + //compiler.removeDataBinding.append("}").append(JAXXCompiler.getLineSeparator()); + } + } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/compiler/DefaultCompiledObjectDecorator.java b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/DefaultCompiledObjectDecorator.java new file mode 100644 index 0000000..5e0144a --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/DefaultCompiledObjectDecorator.java @@ -0,0 +1,128 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package jaxx.compiler; + +import java.lang.reflect.Modifier; +import java.util.Map.Entry; +import jaxx.CompilerException; +import jaxx.types.TypeManager; + +/** + * The default compiledObjectDecorator. + * + * @author tony + * @since 1.2 + */ +public class DefaultCompiledObjectDecorator extends CompiledObjectDecorator { + + @Override + public void finalizeCompiler(JAXXCompiler compiler, CompiledObject root, CompiledObject object, JavaFile javaFile, String packageName, String className, String fullClassName) { + + if (!object.isOverride() && !(object instanceof ScriptInitializer)) { + String id = object.getId(); + int access = id.startsWith("$") ? Modifier.PRIVATE : Modifier.PROTECTED; + if (object == root) { + javaFile.addField(new JavaField(access, fullClassName, id, "this")); + } else { + //TC -20081017 can have generic on compiled Object + javaFile.addField(JavaField.newField(access, JAXXCompiler.getCanonicalName(object), id), object.isJavaBean()); + } + } + + if (!compiler.inlineCreation(object) && object != root) { + javaFile.addMethod(JavaMethod.newMethod(Modifier.PROTECTED, "void", object.getCreationMethodName(), getCreationCode(compiler, object))); + } + } + + @Override + public String getCreationCode(JAXXCompiler compiler, CompiledObject object) throws CompilerException { + if (object instanceof ScriptInitializer) { + return object.getInitializationCode(compiler); + } + StringBuffer result = new StringBuffer(); + if (object.isOverride() && object.getOverrideType()==object.getObjectClass()) { + //TC-20090309 on utilise le super code quand l'objet est de meme type + result.append("super.").append(object.getCreationMethodName()).append("();"); + } else { + result.append(object.getId()); + result.append(" = "); + if (object.isJavaBean() && object.getJavaBeanInitCode() != null) { + result.append(object.getJavaBeanInitCode()).append(";"); + } else { + String constructorParams = object.getConstructorParams(); + if (constructorParams != null) { + //TC - 20081017 compiledObject can have generics + result.append(" new ").append(JAXXCompiler.getCanonicalName(object)).append("(").append(constructorParams).append(");"); + //result.append("(").append(getCanonicalName(object.getObjectClass())).append(") new ").append(getCanonicalName(object.getObjectClass())).append("(").append(constructorParams).append(");"); + } else { + //TC - 20081017 compiledObject can have generics + result.append("new ").append(JAXXCompiler.getCanonicalName(object)).append("();"); + } + } + result.append(JAXXCompiler.getLineSeparator()); + result.append("$objectMap.put(").append(TypeManager.getJavaCode(object.getId())).append(", ").append(object.getId()).append(");"); + } + result.append(JAXXCompiler.getLineSeparator()); + String initCode = object.getInitializationCode(compiler); + if (initCode != null && initCode.length() > 0) { + result.append(initCode); + } + + return result.toString(); + } + + @Override + public String createCompleteSetupMethod(JAXXCompiler compiler, CompiledObject object, JavaFile javaFile, StringBuffer initDataBindings) { + StringBuffer code = new StringBuffer(); + //TC-20090327 generate client properties + if (object.hasClientProperties()) { + // generate putClientProperty invocations + for (Entry<String,String> entry : object.getClientProperties().entrySet()) { + object.appendAdditionCode(object.getJavaCode() + ".putClientProperty(\"" + entry.getKey() + "\", " + entry.getValue() + ");"); + } + + } + //TC - 20081017 only generate the method if not empty ? + if (object.getId().startsWith("$")) { + code.append(object.getAdditionCode()).append(JAXXCompiler.getLineSeparator()); + } else { + String additionCode = object.getAdditionCode(); + if (additionCode.length() > 0) { + code.append(object.getAdditionMethodName()).append("();").append(JAXXCompiler.getLineSeparator()); + additionCode = "if (!allComponentsCreated) {" + JAXXCompiler.getLineSeparator() + " return;" + JAXXCompiler.getLineSeparator() + "}" + JAXXCompiler.getLineSeparator() + additionCode; + javaFile.addMethod(JavaMethod.newMethod(Modifier.PROTECTED, "void", object.getAdditionMethodName(), additionCode)); + } + } + //code.append(getLineSeparator()); + return code.toString(); + } + + @Override + public boolean createInitializer(JAXXCompiler compiler, CompiledObject root, CompiledObject object, StringBuffer code, boolean lastWasMethodCall) { + if (object == root) { + String rootCode = root.getInitializationCode(compiler); + if (rootCode != null && rootCode.length() > 0) { + code.append(rootCode); + code.append(JAXXCompiler.getLineSeparator()); + } + } else { + if (!object.isOverride()) { + if (compiler.inlineCreation(object)) { + if (lastWasMethodCall) { + lastWasMethodCall = false; + code.append(JAXXCompiler.getLineSeparator()); + } + code.append(getCreationCode(compiler, object)); + code.append(JAXXCompiler.getLineSeparator()); + } else { + code.append(object.getCreationMethodName()).append("();"); + code.append(JAXXCompiler.getLineSeparator()); + lastWasMethodCall = true; + } + } + } + return lastWasMethodCall; + } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/compiler/EventHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/EventHandler.java new file mode 100644 index 0000000..01a54a8 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/EventHandler.java @@ -0,0 +1,61 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.compiler; + +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.MethodDescriptor; + +public class EventHandler { + private String eventId; + private String objectCode; + private ClassDescriptor listenerClass; + private MethodDescriptor addMethod; + private MethodDescriptor listenerMethod; + private String javaCode; + + public EventHandler(String eventId, String objectCode, MethodDescriptor addMethod, ClassDescriptor listenerClass, MethodDescriptor listenerMethod, String javaCode) { + this.eventId = eventId; + this.objectCode = objectCode; + this.addMethod = addMethod; + this.listenerClass = listenerClass; + this.listenerMethod = listenerMethod; + this.javaCode = javaCode; + } + + + public String getEventId() { + return eventId; + } + + + public String getObjectCode() { + return objectCode; + } + + + public MethodDescriptor getAddMethod() { + return addMethod; + } + + + public ClassDescriptor getListenerClass() { + return listenerClass; + } + + + public MethodDescriptor getListenerMethod() { + return listenerMethod; + } + + + public String getJavaCode() { + return javaCode; + } + + + public String toString() { + return "EventHandler[" + eventId + ", " + listenerClass.getName() + ", " + objectCode + ", " + javaCode + "]"; + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/compiler/Generator.java b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/Generator.java new file mode 100644 index 0000000..a3c4fe7 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/Generator.java @@ -0,0 +1,14 @@ +package jaxx.compiler; + +/** + * TODO javadoc! + * + * @author chemit + */ +public interface Generator { + + void finalizeCompiler(CompiledObject root, JAXXCompiler compiler, JavaFile javaFile, String packageName, String className); + + void prepareJavaFile(CompiledObject root, JAXXCompiler compiler, JavaFile javaFile, String packageName, String className) throws ClassNotFoundException; + +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/compiler/HelpRootCompiledObjectDecorator.java b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/HelpRootCompiledObjectDecorator.java new file mode 100644 index 0000000..14cd185 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/HelpRootCompiledObjectDecorator.java @@ -0,0 +1,93 @@ +package jaxx.compiler; + +import java.lang.reflect.Modifier; +import java.util.Iterator; +import java.util.Set; + +/** + * A decorator to place on a root compiled object to process javaHelp on the file. + * + * @author tony + * @since 1.2 + */ +public class HelpRootCompiledObjectDecorator extends DefaultCompiledObjectDecorator { + + /** + * the list of discovered helpId + */ + protected static Set<String> helpIds = new java.util.HashSet<String>(); + + protected String getBrokerFQN(JAXXCompiler compiler) { + String helpBrokerFQN = compiler.getOptions().getHelpBrokerFQN(); + return helpBrokerFQN; + } + + protected String getHelpId(CompiledObject o) { + String helpID = null; + if (o.hasClientProperties()) { + helpID = o.getClientProperty("help"); + } + return helpID; + } + + @Override + public void finalizeCompiler(JAXXCompiler compiler, CompiledObject root, CompiledObject object, JavaFile javaFile, String packageName, String className, String fullClassName) { + super.finalizeCompiler(compiler, root, object, javaFile, packageName, className, fullClassName); + CompilerOptions options = compiler.getOptions(); + + if (options.isGenerateHelp()) { + + // add JaxxHelpUI interface + Class<?> validatorInterface = jaxx.runtime.JaxxHelpUI.class; + String helpBrokerFQN = getBrokerFQN(compiler); + javaFile.addInterface(JAXXCompiler.getCanonicalName(validatorInterface) + "<" + helpBrokerFQN + ">"); + + javaFile.addMethod(JavaMethod.newMethod(Modifier.PUBLIC, "void", "registerHelpId", + "broker.installUI(component, helpId);", + new JavaArgument(helpBrokerFQN, "broker"), + new JavaArgument("Component", "component"), + new JavaArgument("String", "helpId"))); + + javaFile.addMethod(JavaMethod.newMethod(Modifier.PUBLIC, "void", "showHelp", + "getBroker().showHelp(this, helpId);", + new JavaArgument("String", "helpId"))); + + StringBuilder buffer = new StringBuilder(); + + String lineSeparator = JAXXCompiler.getLineSeparator(); + + if (options.isGenerateHelp()) { + + // add code to init javax help system + Iterator<CompiledObject> itr = compiler.getObjectCreationOrder(); + + for (; itr.hasNext();) { + CompiledObject o = itr.next(); + String helpID = getHelpId(o); + if (helpID != null) { + buffer.append(lineSeparator); + // detects a helpId to register + buffer.append("registerHelpId(_broker, " + o.getJavaCode() + ", " + helpID + ");"); + //keep the helpID for helpSet generation + helpIds.add(helpID); + } + } + } + if (buffer.length() > 0) { + + StringBuilder extraCode = new StringBuilder(helpBrokerFQN).append(" _broker = getBroker();"); + + buffer.append(lineSeparator).append("_broker.prepareUI(this);"); + buffer.append(lineSeparator); + + // add the calls + compiler.appendLateInitializer(extraCode.toString()); + compiler.appendLateInitializer(buffer.toString()); + } + } + } + + public static Set<String> getHelpIds() { + return helpIds; + } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/compiler/I18nHelper.java b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/I18nHelper.java new file mode 100644 index 0000000..c928cbd --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/I18nHelper.java @@ -0,0 +1,70 @@ +package jaxx.compiler; + +import jaxx.tags.DefaultComponentHandler; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.Arrays; +import java.util.List; + +/** + * I18n methods to add {@link org.nuiton.i18n.I18n#_(String, Object[])} method on some attributes. + * <p/> + * Make sure to set an i18nable compiler to have his {@link CompilerOptions#isI18nable()} returning true. + * + * @author chemit + */ +public class I18nHelper { + + protected static final Log log = LogFactory.getLog(DefaultComponentHandler.class); + + public static final List<String> I18N_ATTRIBUTES = Arrays.asList("text", "title", "toolTipText"); + + /** + * Test if we have an active i18n attribute (says an i18n attribute on a i18neable compiler). + * + * @param attributeName name of attribute to test + * @param compiler current used compiler (contains options) + * @return <code>true</code> if wa have an active i18n attribute, <code>false</code> otherwise. + */ + public static boolean isI18nableAttribute(String attributeName, JAXXCompiler compiler) { + return compiler.getOptions().isI18nable() && isI18nAttribute(attributeName); + } + + /** + * Test if we have an i18n attribute. + * + * @param attributeName name of attribute to test + * @return <code>true</code> if wa have an active i18n attribute, <code>false</code> otherwise. + */ + public static boolean isI18nAttribute(String attributeName) { + return I18N_ATTRIBUTES.contains(attributeName); + } + /** + * Add the i18n on a attribute. + * <p/> + * Note: <b>Be ware : </b> no test is done here to ensure we are on a i18neable attribute for an i18nable compiler. + * <p/> + * Make sure with the method {@link jaxx.compiler.I18nHelper#isI18nableAttribute(String, JAXXCompiler)} returns + * <code>true</code< before using this method. + * + * @param widgetId the id of the widget + * @param attributeName the name of the attribute + * @param attributeValueCode the value code of the attribute value + * @param compiler the current used compile + * @return the surrender i18n call if attribute name is matchrf the attributeValueCode otherwise + */ + public static String addI18nInvocation(String widgetId, String attributeName, String attributeValueCode, JAXXCompiler compiler) { + + if (log.isDebugEnabled()) { + log.debug(" try i18n support for [" + widgetId + ":" + attributeName + "] : " + attributeValueCode); + } + if (attributeValueCode.contains("_(") && attributeValueCode.contains(")")) { + compiler.reportWarning("\n\tjaxx supports i18n, no need to add explicit call to I18n._ for attribute '" + attributeName + "' in component '" + widgetId + "' : ["+attributeValueCode+"]"); + } else { + attributeValueCode = "_(" + attributeValueCode + ")"; + } + + return attributeValueCode; + } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/compiler/JAXXCompiler.java b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/JAXXCompiler.java new file mode 100644 index 0000000..6a22bb0 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/JAXXCompiler.java @@ -0,0 +1,1550 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.compiler; + +import jaxx.CompilerException; +import jaxx.UnsupportedAttributeException; +import jaxx.UnsupportedTagException; +import jaxx.css.Rule; +import jaxx.css.Stylesheet; +import jaxx.css.StylesheetHelper; +import jaxx.parser.ParseException; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.reflect.FieldDescriptor; +import jaxx.reflect.MethodDescriptor; +import jaxx.runtime.ComponentDescriptor; +import jaxx.runtime.JAXXObjectDescriptor; +import jaxx.tags.DefaultObjectHandler; +import jaxx.tags.TagHandler; +import jaxx.tags.TagManager; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.helpers.AttributesImpl; +import org.xml.sax.helpers.XMLFilterImpl; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.transform.ErrorListener; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.sax.SAXSource; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Modifier; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Stack; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Compiles JAXX files into Java classes. + * <p/> + * use {@link Generator} ... todo finish javadoc + */ +public class JAXXCompiler { + + /** log */ + protected static final Log log = LogFactory.getLog(JAXXCompiler.class); + + /** + * True to throw exceptions when we encounter unresolvable classes, false to ignore. + * This is currently set to false until JAXX has full support for inner classes + * (including enumerations), because currently they don't always resolve (but will + * generally compile without error anyway). + */ + public static final boolean STRICT_CHECKS = false; + public static final String JAXX_NAMESPACE = "http://www.jaxxframework.org/"; + public static final String JAXX_INTERNAL_NAMESPACE = "http://www.jaxxframework.org/internal"; + + /** Maximum length of an inlinable creation method. */ + public static final int INLINE_THRESHOLD = 300; + + protected final DefaultObjectHandler firstPassClassTagHandler; + + protected List<String> staticImports = new ArrayList<String>(); + + /*---------------------------------------------------------------------------------*/ + /*-- compiler fields --------------------------------------------------------------*/ + /*---------------------------------------------------------------------------------*/ + + /** flag to detec if an error occurs while compiling jaxx file */ + protected boolean failed; + + /** Object corresponding to the root tag in the document. */ + protected CompiledObject root; + + /** Contains strings of the form "javax.swing." */ + protected Set<String> importedPackages = new HashSet<String>(); + + /** Contains strings of the form "javax.swing.Timer" */ + protected Set<String> importedClasses = new HashSet<String>(); + + /** Keeps track of open components (components still having children added). */ + protected Stack<CompiledObject> openComponents = new Stack<CompiledObject>(); + + /** Sequence number used to create automatic variable names. */ + protected int autogenID = 0; + + protected List<DataBinding> dataBindings = new ArrayList<DataBinding>(); + + protected SymbolTable symbolTable = new SymbolTable(); + + /** Base directory used for path resolution (normally the directory in which the .jaxx file resides). */ + protected File baseDir; + + /** .jaxx file being compiled. */ + protected File src; + + /** Parsed XML of src file. */ + protected Document document; + + /** Name of class being compiled. */ + protected String outputClassName; + + protected ScriptManager scriptManager = new ScriptManager(this); + + /** Combination of all stylesheets registered using {@link #registerStylesheet}. */ + protected Stylesheet stylesheet; + + /** Contains all attributes defined inline on class tags. */ + protected List<Rule> inlineStyles = new ArrayList<Rule>(); + + /** + * Maps objects (expressed in Java code) to event listener classes (e.g. MouseListener) to Lists of EventHandlers. The final list + * contains all event handlers of a particular type attached to a particular object (again, as represented by a Java expression). + */ + protected Map<String, Map<ClassDescriptor, List<EventHandler>>> eventHandlers = new HashMap<String, Map<ClassDescriptor, List<EventHandler>>>(); + + /** Maps of uniqued id for objects used in compiler */ + protected Map<Object, String> uniqueIds = new HashMap<Object, String>(); + + /** Map of event handler method names used in compiler */ + protected Map<EventHandler, String> eventHandlerMethodNames = new HashMap<EventHandler, String>(); + + /** ClassLoader which searches the user-specified class path in addition to the normal class path */ + protected ClassLoader classLoader; + + /** + * A list of Runnables which will be run after the first compilation pass. This is primarily used + * to trigger the creation of CompiledObjects, which cannot be created during the first pass and must be + * created in document order. + */ + protected List<Runnable> initializers = new ArrayList<Runnable>(); + + /** left brace matcher */ + protected Matcher leftBraceMatcher = Pattern.compile("^(\\{)|[^\\\\](\\{)").matcher(""); + + /** right brace matcher */ + protected Matcher rightBraceMatcher = Pattern.compile("^(\\})|[^\\\\](\\})").matcher(""); + + /** extra interfaces which can by passed to root object via the 'implements' attribute */ + private String[] extraInterfaces; + + /** a flag to generate a abstract class */ + private boolean abstractClass; + + /** the possible generic type of the class */ + private String genericType; + + /** thepossible generic type of the super class */ + private String superGenericType; + + /** Extra code to be added to the instance initializer. */ + protected StringBuffer initializer = new StringBuffer(); + + /** Extra code to be added at the end of the instance initializer. */ + protected StringBuffer lateInitializer = new StringBuffer(); + + /** Extra code to be added to the class body. */ + protected StringBuffer bodyCode = new StringBuffer(); + + /** Code to initialize data bindings. */ + protected StringBuffer initDataBindings = new StringBuffer(); + + /** Body of the applyDataBinding method. */ + protected StringBuffer applyDataBinding = new StringBuffer(); + + /** Body of the removeDataBinding method. */ + protected StringBuffer removeDataBinding = new StringBuffer(); + + /** Body of the processDataBinding method. */ + protected StringBuffer processDataBinding = new StringBuffer(); + + /** true if a main() method has been declared in a script */ + protected boolean mainDeclared; + + /** the file to be generated */ + protected JavaFile javaFile; + + + protected CompilerOptions options; + + /** Used for error reporting purposes, so we can report the right line number. */ + protected Stack<Element> tagsBeingCompiled = new Stack<Element>(); + + /** Used for error reporting purposes, so we can report the right source file. */ + protected Stack<File> sourceFiles = new Stack<File>(); + + /** Maps object ID strings to the objects themselves. These are created during the second compilation pass. */ + protected Map<String, CompiledObject> objects = new LinkedHashMap<String, CompiledObject>(); + + /** Maps objects to their ID strings. These are created during the second compilation pass. */ + protected Map<CompiledObject, String> ids = new LinkedHashMap<CompiledObject, String>(); + + protected CompiledObjectDecorator defaultDecorator; + + /*---------------------------------------------------------------------------------*/ + /*-- Constructor methods ----------------------------------------------------------*/ + /*---------------------------------------------------------------------------------*/ + + protected JAXXCompiler(ClassLoader classLoader, DefaultObjectHandler firstPassClassTagHandler, String... staticImports) { + this.firstPassClassTagHandler = firstPassClassTagHandler; + this.options = new CompilerOptions(); + this.classLoader = classLoader; + if (staticImports == null || staticImports.length == 0) { + staticImports = new String[0]; + } + this.staticImports = Arrays.asList(staticImports); + addImport("java.lang.*"); + } + + /** + * Creates a new JAXXCompiler. + * + * @param baseDir classpath location + * @param src location of file to compile + * @param outputClassName the out file name + * @param options options to pass to javac + * @param firstPassClassTagHandler handler to use for first pass + * @param staticImports statics imports + */ + protected JAXXCompiler(File baseDir, File src, String outputClassName, CompilerOptions options, DefaultObjectHandler firstPassClassTagHandler, String... staticImports) { + this.baseDir = baseDir; + this.src = src; + this.firstPassClassTagHandler = firstPassClassTagHandler; + this.staticImports = Arrays.asList(staticImports); + sourceFiles.push(src); + this.outputClassName = outputClassName; + this.options = options; + addImport(outputClassName.substring(0, outputClassName.lastIndexOf(".") + 1) + "*"); + if (staticImports == null || staticImports.length == 0) { + staticImports = new String[]{"java.lang.*"}; + } + for (Object staticImport : staticImports) { + addImport((String) staticImport); + } + // add extra imports from options + if (options.getExtraImports() != null) { + for (String extraImport : options.getExtraImports()) { + addImport(extraImport); + } + } + defaultDecorator = CompiledObjectDecorator.getDecorator(options.getDefaultDecoratorClass()); + if (defaultDecorator == null) { + log.error("could not find default decorator : "+options.getDefaultDecoratorClass()); + throw new IllegalArgumentException("could not find default decorator : " + options.getDefaultDecoratorClass()); + } + } + + /*---------------------------------------------------------------------------------*/ + /*-- Initializer methods -----------------------------------------------------------*/ + /*---------------------------------------------------------------------------------*/ + + public void runInitializers() { + for (Runnable runnable : initializers) { + if (log.isDebugEnabled()) { + log.debug(runnable); + } + try { + runnable.run(); + } catch (Exception e) { + //TC - 20081018 report error and quit + reportError(e.getMessage()); + return; + } + } + initializers.clear(); + } + + + /** + * Registers a <code>Runnable</code> which will be executed after the first + * compilation pass is complete. + * + * @param r runnable to register + */ + public void registerInitializer(Runnable r) { + initializers.add(r); + } + + /*---------------------------------------------------------------------------------*/ + /*-- Compile methods --------------------------------------------------------------*/ + /*---------------------------------------------------------------------------------*/ + + public void compileFirstPass(final Element tag) throws IOException { + tagsBeingCompiled.push(tag); + + String namespace = tag.getNamespaceURI(); + String fullClassName; + String localName = tag.getLocalName(); + boolean namespacePrefix = tag.getPrefix() != null; + // resolve class tags into fully-qualified class name + if (namespace != null && namespace.endsWith("*")) { + String packageName = namespace.substring(0, namespace.length() - 1); + if (localName.startsWith(packageName)) // class name is fully-qualified already + { + fullClassName = TagManager.resolveClassName(localName, this); + } else { // namespace not included in class name, probably need the namespace to resolve + fullClassName = TagManager.resolveClassName(packageName + localName, this); + if (fullClassName == null && !namespacePrefix) // it was just a default namespace, try again without using the namespace + { + fullClassName = TagManager.resolveClassName(localName, this); + } + } + } else { + fullClassName = TagManager.resolveClassName(localName, this); + } + + if (fullClassName != null) { // we are definitely dealing with a class tag + addDependencyClass(fullClassName); + namespace = fullClassName.substring(0, fullClassName.lastIndexOf(".") + 1) + "*"; + if (symbolTable.getSuperclassName() == null) { + symbolTable.setSuperclassName(fullClassName); + } + String id = tag.getAttribute("id"); + if (id.length() > 0) { + symbolTable.getClassTagIds().put(id, fullClassName); + if (tag.getAttributeNode("javaBean") != null) { + // add java bean support for this property + String capitalizeName = org.apache.commons.lang.StringUtils.capitalize(id); + // add method + symbolTable.getScriptMethods().add(new MethodDescriptor("get" + capitalizeName, Modifier.PUBLIC, fullClassName, new String[0], classLoader)); + if (Boolean.class.getName().equals(fullClassName)) { + symbolTable.getScriptMethods().add(new MethodDescriptor("is" + capitalizeName, Modifier.PUBLIC, fullClassName, new String[0], classLoader)); + } + symbolTable.getScriptMethods().add(new MethodDescriptor("set" + capitalizeName, Modifier.PUBLIC, "void", new String[]{fullClassName}, classLoader)); + } + } + } + // during the first pass, we can't create ClassDescriptors for JAXX files because they may not have been processed yet + // (and we can't wait until they have been processed because of circular dependencies). So we don't do any processing + // during the first pass which requires having a ClassDescriptor; here we determine whether we have a class tag or not + // (class tag namespaces end in "*") and use a generic handler if so. The real handler is used during the second pass. + TagHandler handler = (namespace != null && namespace.endsWith("*")) ? firstPassClassTagHandler : TagManager.getTagHandler(tag.getNamespaceURI(), localName, namespacePrefix, this); + if (handler != firstPassClassTagHandler && handler instanceof DefaultObjectHandler) { + fullClassName = ((DefaultObjectHandler) handler).getBeanClass().getName(); + //namespace = fullClassName.substring(0, fullClassName.lastIndexOf(".") + 1) + "*"; + handler = firstPassClassTagHandler; + } + if (handler == firstPassClassTagHandler) { + final String finalClassName = fullClassName; + registerInitializer(new Runnable() { // register an initializer which will create the CompiledObject after pass 1 + + public void run() { + DefaultObjectHandler handler = (DefaultObjectHandler) TagManager.getTagHandler(null, finalClassName, JAXXCompiler.this); + if (handler == null) { + throw new CompilerException("Internal error: missing TagHandler for '" + finalClassName + "'"); + } + handler.registerCompiledObject(tag, JAXXCompiler.this); + } + }); + } + if (handler != null) { + try { + handler.compileFirstPass(tag, this); + } + catch (CompilerException e) { + reportError(e); + } + } else { + reportError("Could not find a Java class corresponding to: <" + tag.getTagName() + ">"); + failed = true; + } + + Element finished = tagsBeingCompiled.pop(); + if (finished != tag) { + throw new RuntimeException("internal error: just finished compiling " + tag + ", but top of tagsBeingCompiled stack is " + finished); + } + } + + + public void compileSecondPass(Element tag) throws IOException { + tagsBeingCompiled.push(tag); + + TagHandler handler = TagManager.getTagHandler(tag.getNamespaceURI(), tag.getLocalName(), tag.getPrefix() != null, this); + if (handler != null) { + handler.compileSecondPass(tag, this); + } else { + reportError("Could not find a Java class corresponding to: <" + tag.getTagName() + ">"); + assert false : "can't-happen error: error should have been reported during the fast pass and caused an abort"; + failed = true; + } + + Element finished = tagsBeingCompiled.pop(); + if (finished != tag) { + throw new RuntimeException("internal error: just finished compiling " + tag + ", but top of tagsBeingCompiled stack is " + finished); + } + + } + + protected void compileFirstPass() throws IOException { + try { + InputStream in = new FileInputStream(src); + document = parseDocument(in); + in.close(); + compileFirstPass(document.getDocumentElement()); + } + catch (SAXParseException e) { + reportError(e.getLineNumber(), "Invalid XML: " + e.getMessage()); + } + catch (SAXException e) { + reportError(null, "Error parsing XML document: " + e); + } + } + + protected void compileSecondPass() throws IOException { + if (!tagsBeingCompiled.isEmpty()) { + throw new RuntimeException("Internal error: starting pass two, but tagsBeingCompiled is not empty: " + tagsBeingCompiled); + } + compileSecondPass(document.getDocumentElement()); + } + + /*---------------------------------------------------------------------------------*/ + /*-- CompiledObject methods -------------------------------------------------------*/ + /*---------------------------------------------------------------------------------*/ + + public void openComponent(CompiledObject component) throws CompilerException { + openComponent(component, null); + } + + public void openComponent(CompiledObject component, String constraints) throws CompilerException { + CompiledObject parent = getOpenComponent(); + openInvisibleComponent(component); + if (parent != null && !component.isOverride()) { + parent.addChild(component, constraints, this); + } + } + + public void openInvisibleComponent(CompiledObject component) { + if (!ids.containsKey(component)) { + registerCompiledObject(component); + } + openComponents.push(component); + } + + public CompiledObject getOpenComponent() { + if (openComponents.isEmpty()) { + return null; + } + return openComponents.peek(); + } + + public void closeComponent(CompiledObject component) { + if (openComponents.pop() != component) { + throw new IllegalArgumentException("can only close the topmost open object"); + } + } + + public void registerCompiledObject(CompiledObject object) { + assert JAXXCompilerLaunchor.get().symbolTables.values().contains(symbolTable) : "attempting to register CompiledObject before pass 1 is complete"; + if (root == null) { + root = object; + } + + String id = object.getId(); + if (ids.containsKey(object)) { + reportError("object '" + object + "' is already registered with id '" + ids.get(object) + "', cannot re-register as '" + id + "'"); + } + if (objects.containsKey(id) && !(objects.get(id) instanceof Element)) { + reportError("id '" + id + "' is already registered to component " + objects.get(id)); + } + objects.put(id, object); + ids.put(object, id); + if (object.getDecorator() == null) { + // use compiler decorator + object.setDecorator(defaultDecorator); + } + } + + public CompiledObject getCompiledObject(String id) { + runInitializers(); + assert JAXXCompilerLaunchor.get().symbolTables.values().contains(symbolTable) : "attempting to retrieve CompiledObject before pass 1 is complete"; + return objects.get(id); + } + + + public boolean inlineCreation(CompiledObject object) { + return object.getId().startsWith("$") && object.getInitializationCode(this).length() < INLINE_THRESHOLD; + } + + public void checkOverride(CompiledObject object) throws CompilerException { + if (object.getId().startsWith("$")) { + return; + } + ClassDescriptor ancestor = root.getObjectClass(); + if (ancestor == object.getObjectClass()) { + return; + } + while (ancestor != null) { + try { + FieldDescriptor f = ancestor.getDeclaredFieldDescriptor(object.getId()); + if (!f.getType().isAssignableFrom(object.getObjectClass())) { + reportError("attempting to redefine superclass member '" + object.getId() + "' as incompatible type (was " + f.getType() + ", redefined as " + object.getObjectClass() + ")"); + } + object.setOverride(true); + object.setOverrideType(f.getType()); + break; + } + catch (NoSuchFieldException e) { + ancestor = ancestor.getSuperclass(); + } + } + } + + /*---------------------------------------------------------------------------------*/ + /*-- DataBinding methods ----------------------------------------------------------*/ + /*---------------------------------------------------------------------------------*/ + + /** + * Examine an attribute value for data binding expressions. Returns a 'cooked' expression which + * can be used to determine the resulting value. It is expected that this expression will be used + * as the source expression in a call to {@link #registerDataBinding}. + * If the attribute value does not invoke data binding, this method returns <code>null</code> + * + * @param stringValue the string value of the property from the XML + * @param type the type of the property, from the <code>JAXXPropertyDescriptor</code> + * @return a processed version of the expression + * @throws jaxx.CompilerException ? + */ + public String processDataBindings(String stringValue, ClassDescriptor type) throws CompilerException { + int pos = getNextLeftBrace(stringValue, 0); + if (pos != -1) { + StringBuffer expression = new StringBuffer(); + int lastPos = 0; + while (pos != -1 && pos < stringValue.length()) { + if (pos > lastPos) { + if (expression.length() > 0) { + expression.append(" + "); + } + expression.append('"'); + expression.append(escapeJavaString(stringValue.substring(lastPos, pos))); + expression.append('"'); + } + + if (expression.length() > 0) { + expression.append(" + "); + } + expression.append('('); + int pos2 = getNextRightBrace(stringValue, pos + 1); + if (pos2 == -1) { + reportError("unmatched '{' in expression: " + stringValue); + return ""; + } + expression.append(stringValue.substring(pos + 1, pos2)); + expression.append(')'); + pos2++; + if (pos2 < stringValue.length()) { + pos = getNextLeftBrace(stringValue, pos2); + lastPos = pos2; + } else { + pos = stringValue.length(); + lastPos = pos; + } + } + if (lastPos < stringValue.length()) { + if (expression.length() > 0) { + expression.append(" + "); + } + expression.append('"'); + expression.append(escapeJavaString(stringValue.substring(lastPos))); + expression.append('"'); + } + return type == ClassDescriptorLoader.getClassDescriptor(String.class) ? "String.valueOf(" + expression + ")" : expression.toString(); + } + return null; + } + + + public void registerDataBinding(String src, String dest, String assignment) { + try { + src = checkJavaCode(src); + dataBindings.add(new DataBinding(src, dest, assignment, this)); + } + catch (CompilerException e) { + reportError("While parsing data binding for '" + dest.substring(dest.lastIndexOf(".") + 1) + "': " + e.getMessage()); + } + } + + public void registerEventHandler(EventHandler handler) { + String objectCode = handler.getObjectCode(); + Map<ClassDescriptor, List<EventHandler>> listeners = eventHandlers.get(objectCode); + if (listeners == null) { + listeners = new HashMap<ClassDescriptor, List<EventHandler>>(); + eventHandlers.put(objectCode, listeners); + } + ClassDescriptor listenerClass = handler.getListenerClass(); + List<EventHandler> handlerList = listeners.get(listenerClass); + if (handlerList == null) { + handlerList = new ArrayList<EventHandler>(); + listeners.put(listenerClass, handlerList); + } + handlerList.add(handler); + } + + public String getEventHandlerMethodName(EventHandler handler) { + String result = eventHandlerMethodNames.get(handler); + if (result == null) { + if (getOptions().isOptimize()) { + result = "$ev" + eventHandlerMethodNames.size(); + } else { + //TC-20090309 must get the goal property from the event id + // to make possible inheritance + String id = handler.getEventId().substring(0,handler.getEventId().indexOf(".")); + + result = "do" + org.apache.commons.lang.StringUtils.capitalize(handler.getListenerMethod().getName()) + "__on__" + id; + //result = "do" + org.apache.commons.lang.StringUtils.capitalize(handler.getListenerMethod().getName()) + "__on__" + handler.getObjectCode(); + } + eventHandlerMethodNames.put(handler, result); + } + return result; + } + + /*---------------------------------------------------------------------------------*/ + /*-- Script methods ---------------------------------------------------------------*/ + /*---------------------------------------------------------------------------------*/ + + public void addScriptField(FieldDescriptor field) { + symbolTable.getScriptFields().add(field); + } + + public void addScriptMethod(MethodDescriptor method) { + if (method.getName().equals("main") && method.getParameterTypes().length == 1 && method.getParameterTypes()[0].getName().equals("[Ljava.lang.String;")) { + setMainDeclared(true); + } + symbolTable.getScriptMethods().add(method); + } + + public void registerScript(String script) throws CompilerException { + registerScript(script, null); + } + + public void registerScript(String script, File sourceFile) throws CompilerException { + if (sourceFile != null) { + sourceFiles.push(sourceFile); + } + script = script.trim(); + if (!"".equals(script) && !script.endsWith("}") && !script.endsWith(";")) { + script += ";"; + } + scriptManager.registerScript(script); + + if (sourceFile != null) { + File pop = sourceFiles.pop(); + if (pop != sourceFile) { + throw new RuntimeException("leaving registerScript(), but " + sourceFile + " was not the top entry on the stack (found " + pop + " instead)"); + } + } + } + + public String preprocessScript(String script) throws CompilerException { + return scriptManager.preprocessScript(script); + } + + /*---------------------------------------------------------------------------------*/ + /*-- StyleSheet methods -----------------------------------------------------------*/ + /*---------------------------------------------------------------------------------*/ + + public void applyStylesheets() { + for (Object o : new ArrayList<CompiledObject>(objects.values())) { + CompiledObject object = (CompiledObject) o; + TagManager.getTagHandler(object.getObjectClass()).applyStylesheets(object, this); + } + } + + public void registerStylesheet(Stylesheet stylesheet) { + if (this.stylesheet == null) { + this.stylesheet = stylesheet; + } else { + this.stylesheet.add(stylesheet.getRules()); + } + } + + public void addInlineStyle(CompiledObject object, String propertyName, boolean dataBinding) { + inlineStyles.add(StylesheetHelper.inlineAttribute(object, propertyName, dataBinding)); + } + + /*---------------------------------------------------------------------------------*/ + /*-- Report methods ---------------------------------------------------------------*/ + /*---------------------------------------------------------------------------------*/ + + public void reportWarning(String warning) { + Element currentTag = null; + if (!tagsBeingCompiled.isEmpty()) { + currentTag = tagsBeingCompiled.peek(); + } + reportWarning(currentTag, warning, 0); + } + + + public void reportWarning(Element tag, String warning, int lineOffset) { + String lineNumber = null; + if (tag != null) { + String lineAttr = tag.getAttributeNS(JAXX_INTERNAL_NAMESPACE, "line"); + if (lineAttr.length() > 0) { + lineNumber = lineAttr; + } + } + File src = sourceFiles.peek(); + try { + src = src.getCanonicalFile(); + } + catch (IOException e) { + // ignore ? + } + + System.err.print(src); + if (lineNumber != null) { + System.err.print(":" + ((sourceFiles.size() == 1) ? Integer.parseInt(lineNumber) + lineOffset : lineOffset + 1)); + } + System.err.println(": Warning: " + warning); + JAXXCompilerLaunchor.get().warningCount++; + } + + + public void reportError(String error) { + Element currentTag = null; + if (!tagsBeingCompiled.isEmpty()) { + currentTag = tagsBeingCompiled.peek(); + } + reportError(currentTag, error); + } + + public void reportError(CompilerException ex) { + reportError(null, ex); + } + + public void reportError(String extraMessage, CompilerException ex) { + String message = ex.getMessage(); + if (ex.getClass() == UnsupportedAttributeException.class || ex.getClass() == UnsupportedTagException.class) { + message = ex.getClass().getName().substring(ex.getClass().getName().lastIndexOf(".") + 1) + ": " + message; + } + int lineOffset; + if (ex instanceof ParseException) { + lineOffset = Math.max(0, ((ParseException) ex).getLine() - 1); + } else { + lineOffset = 0; + } + Element currentTag = null; + if (!tagsBeingCompiled.isEmpty()) { + currentTag = tagsBeingCompiled.peek(); + } + reportError(currentTag, extraMessage != null ? extraMessage + message : message, lineOffset); + } + + public void reportError(Element tag, String error) { + reportError(tag, error, 0); + } + + public void reportError(Element tag, String error, int lineOffset) { + int lineNumber = 0; + if (tag != null) { + String lineAttr = tag.getAttributeNS(JAXX_INTERNAL_NAMESPACE, "line"); + if (lineAttr.length() > 0) { + lineNumber = Integer.parseInt(lineAttr); + } + } + lineNumber = Math.max(lineNumber, 1) + lineOffset; + reportError(lineNumber, error); + } + + public void reportError(int lineNumber, String error) { + File src = sourceFiles.isEmpty() ? null : sourceFiles.peek(); + try { + if (src != null) { + src = src.getCanonicalFile(); + } + } + catch (IOException e) { + // ignore ? + } + + System.err.print(src != null ? src.getPath() : "<unknown source>"); + if (lineNumber > 0) { + System.err.print(":" + lineNumber); + } + System.err.println(": " + error); + JAXXCompilerLaunchor.get().errorCount++; + failed = true; + } + + /*---------------------------------------------------------------------------------*/ + /*-- Getter methods ---------------------------------------------------------------*/ + /*---------------------------------------------------------------------------------*/ + + public Map<String, CompiledObject> getObjects() { + return objects; + } + + public List<DataBinding> getDataBindings() { + return dataBindings; + } + + /*public List<CompiledBeanValidator> getValidators() { + return validators; + }*/ + + public Map<String, Map<ClassDescriptor, List<EventHandler>>> getEventHandlers() { + return eventHandlers; + } + + public CompilerOptions getOptions() { + return options; + } + + public String getOutputClassName() { + return outputClassName; + } + + public File getBaseDir() { + return baseDir; + } + + public Set<String> getImportedClasses() { + return importedClasses; + } + + public Set<String> getImportedPackages() { + return importedPackages; + } + + public Iterator<CompiledObject> getObjectCreationOrder() { + return objects.values().iterator(); + } + + public CompiledObject getRootObject() { + return root; + } + + public Stack<File> getSourceFiles() { + return sourceFiles; + } + + public ScriptManager getScriptManager() { + return scriptManager; + } + + public SymbolTable getSymbolTable() { + return symbolTable; + } + + public Stylesheet getStylesheet() { + Stylesheet merged = new Stylesheet(); + if (stylesheet != null) { + merged.add(stylesheet.getRules()); + } + merged.add(inlineStyles.toArray(new Rule[inlineStyles.size()])); + return merged; + } + + public FieldDescriptor[] getScriptFields() { + List<FieldDescriptor> scriptFields = symbolTable.getScriptFields(); + return scriptFields.toArray(new FieldDescriptor[scriptFields.size()]); + } + + public MethodDescriptor[] getScriptMethods() { + List<MethodDescriptor> scriptMethods = symbolTable.getScriptMethods(); + return scriptMethods.toArray(new MethodDescriptor[scriptMethods.size()]); + } + + public MethodDescriptor getScriptMethod(String methodName) { + for (MethodDescriptor m :symbolTable.getScriptMethods()) { + if (methodName.equals(m.getName())) { + return m; + } + } + return null; + } + + public boolean isFailed() { + return failed; + } + + /** + * Returns a <code>ClassLoader</code> which searches the user-specified class path in addition + * to the normal system class path. + * + * @return <code>ClassLoader</code> to use while resolving class references + */ + public ClassLoader getClassLoader() { + if (classLoader == null) { + if (options.getClassLoader() != null) { + classLoader = options.getClassLoader(); + } else { + String classPath = options.getClassPath(); + if (classPath == null) { + classPath = "."; + } + String[] paths = classPath.split(File.pathSeparator); + URL[] urls = new URL[paths.length]; + for (int i = 0; i < paths.length; i++) { + try { + urls[i] = new File(paths[i]).toURI().toURL(); + } + catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } + classLoader = new URLClassLoader(urls, getClass().getClassLoader()); + } + } + + return classLoader; + } + + public JAXXObjectDescriptor getJAXXObjectDescriptor() { + runInitializers(); + CompiledObject[] components = new ArrayList<CompiledObject>(objects.values()).toArray(new CompiledObject[objects.size()]); + assert initializers.isEmpty() : "there are pending initializers remaining"; + assert root != null : "root object has not been defined"; + assert Arrays.asList(components).contains(root) : "root object is not registered"; + ComponentDescriptor[] descriptors = new ComponentDescriptor[components.length]; + // as we print, sort the array so that component's parents are always before the components themselves + for (int i = 0; i < components.length; i++) { + CompiledObject parent = components[i].getParent(); + while (parent != null) { + boolean found = false; + for (int j = i + 1; j < components.length; j++) { // found parent after component, swap them + if (components[j] == parent) { + components[j] = components[i]; + components[i] = parent; + found = true; + break; + } + } + if (!found) { + break; + } + parent = components[i].getParent(); + } + int parentIndex = -1; + if (parent != null) { + for (int j = 0; j < i; j++) { + if (components[j] == parent) { + parentIndex = j; + break; + } + } + } + descriptors[i] = new ComponentDescriptor(components[i].getId(), components[i] == root ? outputClassName : components[i].getObjectClass().getName(), + components[i].getStyleClass(), parentIndex != -1 ? descriptors[parentIndex] : null); + } + + Stylesheet stylesheet = getStylesheet(); + if (stylesheet == null) { + stylesheet = new Stylesheet(); + } + + return new JAXXObjectDescriptor(descriptors, stylesheet); + } + + /*---------------------------------------------------------------------------------*/ + /*-- Setter methods ---------------------------------------------------------------*/ + /*---------------------------------------------------------------------------------*/ + + public void setFailed(boolean failed) { + this.failed = failed; + } + + /*---------------------------------------------------------------------------------*/ + /*-- Buffer ------------------------------------*/ + /*---------------------------------------------------------------------------------*/ + + public StringBuffer getInitializer() { + return initializer; + } + + public StringBuffer getLateInitializer() { + return lateInitializer; + } + + public StringBuffer getBodyCode() { + return bodyCode; + } + + public StringBuffer getInitDataBindings() { + return initDataBindings; + } + + public StringBuffer getApplyDataBinding() { + return applyDataBinding; + } + + public StringBuffer getRemoveDataBinding() { + return removeDataBinding; + } + + public StringBuffer getProcessDataBinding() { + return processDataBinding; + } + + public boolean isMainDeclared() { + return mainDeclared; + } + + public void setMainDeclared(boolean mainDeclared) { + this.mainDeclared = mainDeclared; + } + + public void appendInitializerCode(String code) { + getInitializer().append(code); + } + + public void appendBodyCode(String code) { + getBodyCode().append(code); + } + + public void appendInitDataBindings(String code) { + getInitDataBindings().append(code); + } + + public void appendProcessDataBinding(String code) { + getProcessDataBinding().append(code); + } + + public void appendApplyDataBinding(String code) { + getApplyDataBinding().append(code); + } + + public void appendRemoveDataBinding(String code) { + getRemoveDataBinding().append(code); + } + + public void appendLateInitializer(String code) { + getLateInitializer().append(code); + } + + public boolean haveProcessDataBinding() { + return getProcessDataBinding().length() > 0; + } + + public boolean haveApplyDataBinding() { + return getApplyDataBinding().length() > 0; + } + + public boolean haveRemoveDataBinding() { + return getRemoveDataBinding().length() > 0; + } + + public void addMethodToJavaFile(JavaMethod method) { + getJavaFile().addMethod(method); + } + + public boolean hasMethod(String methodName) { + JavaMethod[] methods = getJavaFile().getMethods(); + for (JavaMethod method : methods) { + if (methodName.equals(method.getName())) { + return true; + } + } + return false; + } + + /*---------------------------------------------------------------------------------*/ + /*-- Other methods ----------------------------------------------------------------*/ + /*---------------------------------------------------------------------------------*/ + + public void addImport(String text) { + if (text.endsWith("*")) { + importedPackages.add(text.substring(0, text.length() - 1)); + } else { + importedClasses.add(text); + } + + if (!text.equals("*")) { + getJavaFile().addImport(text); + } + } + + public void addDependencyClass(String className) { + if (!JAXXCompilerLaunchor.get().jaxxFileClassNames.contains(className)) { + URL jaxxURL = getClassLoader().getResource(className.replace('.', '/') + ".jaxx"); + URL classURL = getClassLoader().getResource(className.replace('.', '/') + ".class"); + if (jaxxURL != null && classURL != null) { + try { + File jaxxFile = URLtoFile(jaxxURL); + File classFile = URLtoFile(classURL); + if (classFile.lastModified() > jaxxFile.lastModified()) { + return; // class file is newer, no need to recompile + } + } + catch (Exception e) { + // do nothing + } + } + + if (jaxxURL != null && jaxxURL.toString().startsWith("file:")) { + File jaxxFile = URLtoFile(jaxxURL); + try { + jaxxFile = jaxxFile.getCanonicalFile(); + } + catch (IOException ex) { + // ignore ? + } + assert jaxxFile.getName().equalsIgnoreCase(className.substring(className.lastIndexOf(".") + 1) + ".jaxx") : + "expecting file name to match " + className + ", but found " + jaxxFile.getName(); + if (jaxxFile.getName().equals(className.substring(className.lastIndexOf(".") + 1) + ".jaxx")) { // check case match + if (JAXXCompilerLaunchor.get().currentPass != JAXXCompilerLaunchor.LifeCycle.compile_first_pass) { + throw new AssertionError("Internal error: adding dependency class " + className + " during second compilation pass"); + } + JAXXCompilerLaunchor.get().jaxxFileClassNames.add(className); + JAXXCompilerLaunchor.get().jaxxFiles.add(jaxxFile); + } + } + } + } + + /** + * Verifies that a snippet of Java code parses correctly. A warning is generated if the string has enclosing + * curly braces. + * + * @param javaCode the Java code snippet to test + * @return a "cooked" version of the string which has enclosing curly braces removed. + * @throws jaxx.CompilerException if the code cannot be parsed + */ + public String checkJavaCode(String javaCode) { + javaCode = scriptManager.trimScript(javaCode); + scriptManager.checkParse(javaCode); + return javaCode; + } + + /** + * Check that a reference exists in symbol table on second compil pass + * + * @param tag the current tag + * @param reference the required reference + * @param strict flag to report an error if reference was not found + * @param attribute (if not null reference the attribute where is defined the reference) + * @return <code>true</code> if reference was found, <code>false</code> otherwise and add an error in compiler + */ + public boolean checkReference(Element tag, String reference, boolean strict, String attribute) { + String component = getSymbolTable().getClassTagIds().get(reference); + if (component == null) { + if (strict) { + String msg; + if (attribute != null) { + msg = "tag '" + tag.getLocalName() + "' could not find the reference '" + reference + "' on attribute [" + attribute + "]"; + } else { + msg = "tag '" + tag.getLocalName() + "' could not find the reference '" + reference + "'"; + } + reportError(msg); + } + return false; + } + return true; + } + + protected int getNextLeftBrace(String string, int pos) { + leftBraceMatcher.reset(string); + return leftBraceMatcher.find(pos) ? Math.max(leftBraceMatcher.start(1), leftBraceMatcher.start(2)) : -1; + } + + protected int getNextRightBrace(String string, int pos) { + leftBraceMatcher.reset(string); + rightBraceMatcher.reset(string); + int openCount = 1; + int rightPos; + while (openCount > 0) { + pos++; + int leftPos = leftBraceMatcher.find(pos) ? Math.max(leftBraceMatcher.start(1), leftBraceMatcher.start(2)) : -1; + rightPos = rightBraceMatcher.find(pos) ? Math.max(rightBraceMatcher.start(1), rightBraceMatcher.start(2)) : -1; + assert leftPos == -1 || leftPos >= pos; + assert rightPos == -1 || rightPos >= pos; + if (leftPos != -1 && leftPos < rightPos) { + pos = leftPos; + openCount++; + } else if (rightPos != -1) { + pos = rightPos; + openCount--; + } else { + openCount = 0; + } + } + return pos; + } + + public String[] parseParameterList(String parameters) throws CompilerException { + List<String> result = new ArrayList<String>(); + StringBuffer current = new StringBuffer(); + int state = 0; // normal + for (int i = 0; i < parameters.length(); i++) { + char c = parameters.charAt(i); + switch (state) { + case 0: // normal + switch (c) { + case '"': + current.append(c); + state = 1; + break; // in quoted string + case '\\': + current.append(c); + state = 2; + break; // immediately after backslash + case ',': + if (current.length() > 0) { + result.add(current.toString()); + current.setLength(0); + break; + } else { + reportError("error parsing parameter list: " + parameters); + } + default: + current.append(c); + } + break; + case 1: // in quoted string + switch (c) { + case '"': + current.append(c); + state = 0; + break; // normal + case '\\': + current.append(c); + state = 3; + break; // immediate after backslash in quoted string + default: + current.append(c); + } + break; + case 2: // immediately after backslash + current.append(c); + state = 0; // normal + break; + case 3: // immediately after backslash in quoted string + current.append(c); + state = 1; // in quoted string + break; + } + } + if (current.length() > 0) { + result.add(current.toString()); + } + return result.toArray(new String[result.size()]); + } + + public String getAutoId(ClassDescriptor objectClass) { + if (options.getOptimize()) { + return "$" + Integer.toString(autogenID++, 36); + } else { + String name = objectClass.getName(); + name = name.substring(name.lastIndexOf(".") + 1); + return "$" + name + autogenID++; + } + } + + public String getUniqueId(Object object) { + String result = uniqueIds.get(object); + if (result == null) { + result = "$u" + uniqueIds.size(); + uniqueIds.put(object, result); + } + return result; + } + + public void setExtraInterfaces(String[] extraInterfaces) { + this.extraInterfaces = extraInterfaces; + } + + public String[] getExtraInterfaces() { + return extraInterfaces; + } + + public boolean isAbstractClass() { + return abstractClass; + } + + public void setAbstractClass(boolean abstractClass) { + this.abstractClass = abstractClass; + } + + public String getGenericType() { + return genericType; + } + + public void setGenericType(String genericType) { + this.genericType = genericType; + } + + public String getSuperGenericType() { + return superGenericType; + } + + public void setSuperGenericType(String superGenericType) { + this.superGenericType = superGenericType; + } + + public void addSimpleField(JavaField javaField) { + getJavaFile().addSimpleField(javaField); + } + + public JavaFile getJavaFile() { + if (javaFile == null) { + javaFile = new JavaFile(); + } + return javaFile; + } + + public void generateCode(Iterable<Generator> generatorIterator) throws IOException { + File dest; + if (getOptions().getTargetDirectory() != null) { + dest = new File(getOptions().getTargetDirectory(), getOutputClassName().replace('.', File.separatorChar) + ".java"); + } else { + dest = new File(getBaseDir(), getOutputClassName().substring(getOutputClassName().lastIndexOf(".") + 1) + ".java"); + } + if (dest.exists() && !dest.setLastModified(System.currentTimeMillis())) { + log.warn("could not touch file " + dest); + } + try { + PrintWriter out = new PrintWriter(new FileWriter(dest)); + int dotPos = getOutputClassName().lastIndexOf("."); + String packageName = dotPos != -1 ? getOutputClassName().substring(0, dotPos) : null; + String simpleClassName = getOutputClassName().substring(dotPos + 1); + CompiledObject compiledObject = getRootObject(); + for (Generator generator : generatorIterator) { + generator.finalizeCompiler(compiledObject, this, javaFile, packageName, simpleClassName); + } + + for (CompiledObject object : getObjects().values()) { + object.finalizeCompiler(); + } + + for (Generator generator : generatorIterator) { + generator.prepareJavaFile(compiledObject, this, javaFile, packageName, simpleClassName); + } + out.println(javaFile.toString(getLineSeparator())); + out.close(); + } catch (RuntimeException e) { + // file could not be generated, so delete it... + if (!dest.delete()) { + log.warn("could not delete file " + dest); + } + throw e; + } catch (ClassNotFoundException e) { + // file could not be generated, so delete it... + if (!dest.delete()) { + log.warn("could not delete file " + dest); + } + throw new CompilerException(e); + } + } + + /** line separator cached value */ + protected static String lineSeparator = System.getProperty("line.separator", "\n"); + + /** + * Returns the system line separator string. + * + * @return the string used to separate lines + */ + public static String getLineSeparator() { + return lineSeparator; + } + + // 1.5 adds getCanonicalName; unfortunately we can't depend on 1.5 features yet + public static String getCanonicalName(Class clazz) { + if (clazz.isArray()) { + String canonicalName = getCanonicalName(clazz.getComponentType()); + if (canonicalName != null) { + return canonicalName + "[]"; + } + return null; + } + return clazz.getName().replace('$', '.'); + } + + public static String getCanonicalName(ClassDescriptor clazz) { + if (clazz.isArray()) { + String canonicalName = getCanonicalName(clazz.getComponentType()); + if (canonicalName != null) { + return canonicalName + "[]"; + } + return null; + } + return clazz.getName().replace('$', '.'); + } + + public static String getCanonicalName(CompiledObject compiled) { + ClassDescriptor clazz = compiled.getObjectClass(); + if (clazz.isArray()) { + String canonicalName = getCanonicalName(clazz.getComponentType()); + if (canonicalName != null) { + if (compiled.getGenericTypesLength() > 0) { + canonicalName += compiled.getGenericTypes(); + } + return canonicalName + "[]"; + } + return null; + } + + String canonicalName = clazz.getName().replace('$', '.'); + if (compiled.getGenericTypesLength() > 0) { + canonicalName += compiled.getGenericTypes(); + } + return canonicalName; + } + + /** + * Escapes a string using standard Java escape sequences, generally in preparation to including it in a string literal + * in a compiled Java file. + * + * @param raw the raw string to be escape + * @return a string in which all 'dangerous' characters have been replaced by equivalent Java escape sequences + */ + public static String escapeJavaString(String raw) { + StringBuffer out = new StringBuffer(raw); + for (int i = 0; i < out.length(); i++) { + char c = out.charAt(i); + if (c == '\\' || c == '"') { + out.insert(i, '\\'); + i++; + } else if (c == '\n') { + out.replace(i, i + 1, "\\n"); + i++; + } else if (c == '\r') { + out.replace(i, i + 1, "\\r"); + i++; + } else if (c < 32 || c > 127) { + String value = Integer.toString((int) c, 16); + while (value.length() < 4) { + value = "0" + value; + } + out.replace(i, i + 1, "\\u" + value); + i += 5; + } + } + return out.toString(); + } + + public static File URLtoFile(URL url) { + return URLtoFile(url.toString()); + } + + public static File URLtoFile(String urlString) { + if (!urlString.startsWith("file:")) { + throw new IllegalArgumentException("url must start with 'file:'"); + } + urlString = urlString.substring("file:".length()); + if (urlString.startsWith("/") && System.getProperty("os.name").startsWith("Windows")) { + urlString = urlString.substring(1); + } + try { + return new File(URLDecoder.decode(urlString.replace('/', File.separatorChar), "utf-8")); + } + catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + public static SAXParser getSAXParser() { + try { + SAXParserFactory factory = SAXParserFactory.newInstance(); + factory.setNamespaceAware(true); + SAXParser parser; + parser = factory.newSAXParser(); + return parser; + } + catch (SAXException e) { + throw new RuntimeException(e); + } + catch (ParserConfigurationException e) { + throw new RuntimeException(e); + } + } + + public static Document parseDocument(InputStream in) throws IOException, SAXException { + try { + TransformerFactory factory = TransformerFactory.newInstance(); + Transformer transformer = factory.newTransformer(); + transformer.setErrorListener(new ErrorListener() { + public void warning(TransformerException ex) throws TransformerException { + throw ex; + } + + public void error(TransformerException ex) throws TransformerException { + throw ex; + } + + public void fatalError(TransformerException ex) throws TransformerException { + throw ex; + } + }); + + DOMResult result = new DOMResult(); + transformer.transform(new SAXSource(new XMLFilterImpl(getSAXParser().getXMLReader()) { + Locator locator; + + @Override + public void setDocumentLocator(Locator locator) { + this.locator = locator; + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { + AttributesImpl resultAtts = new AttributesImpl(atts); + resultAtts.addAttribute(JAXX_INTERNAL_NAMESPACE, "line", "internal:line", "CDATA", String.valueOf(locator.getLineNumber())); + getContentHandler().startElement(uri, localName, qName, resultAtts); + } + }, new InputSource(in)), result); + return (Document) result.getNode(); + } + catch (TransformerConfigurationException e) { + throw new RuntimeException(e); + } + catch (TransformerException e) { + Throwable ex = e; + while (ex.getCause() != null) { + ex = ex.getCause(); + } + if (ex instanceof IOException) { + throw (IOException) ex; + } + if (ex instanceof SAXException) { + throw (SAXException) ex; + } + if (ex instanceof RuntimeException) { + throw (RuntimeException) ex; + } + throw new RuntimeException(ex); + } + } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/compiler/JAXXCompilerLaunchor.java b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/JAXXCompilerLaunchor.java new file mode 100644 index 0000000..cacc54a --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/JAXXCompilerLaunchor.java @@ -0,0 +1,451 @@ +package jaxx.compiler; + +import jaxx.CompilerException; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.spi.Initializer; +import jaxx.tags.DefaultObjectHandler; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.ServiceLoader; + +/** @author chemit */ +public class JAXXCompilerLaunchor { + + /** log */ + protected static final Log log = LogFactory.getLog(JAXXCompilerLaunchor.class); + + protected enum LifeCycle { + + init,// state before compilation + compile_first_pass, // state when first pass of compilation + compile_second_pass, // state when second pass of compilation + stylesheet_pass, // state when applygin stylesheet phase after compilation + generate_pass, // state when generation phase + profile_pass // state when profile + } + /** shared instance of unique launchor at a givne time. */ + protected static JAXXCompilerLaunchor singleton; + + /** + * Create a new empty launchor and set it as current launchor accessible via method {@link #get()} + * + * @return the new instanciated launchor + */ + public static synchronized JAXXCompilerLaunchor newLaunchor() { + return newLaunchor((File[]) null, null, null); + } + + /** + * Create a new launchor and set it as current launchor accessible via method {@link #get()}. + * <p/> + * The launchor will be prepared to compile a set of files, expressed as paths relative to a base directory. + * The class names of the compiled files are derived from the relative path strings + * (e.g. "example/Foo.jaxx" compiles into a class named "example.Foo"). + * + * @param base the directory against which to resolve relative paths + * @param relativePaths a list of relative paths to .jaxx files being compiled + * @param options the compiler options to use + * @return the new instanciated launchor + */ + public static synchronized JAXXCompilerLaunchor newLaunchor(File base, String[] relativePaths, CompilerOptions options) { + File[] files = new File[relativePaths.length]; + String[] classNames = new String[relativePaths.length]; + for (int i = 0; i < files.length; i++) { + files[i] = new File(base, relativePaths[i]); + classNames[i] = relativePaths[i].substring(0, relativePaths[i].lastIndexOf(".")); + classNames[i] = classNames[i].replace(File.separatorChar, '.'); + classNames[i] = classNames[i].replace('/', '.'); + classNames[i] = classNames[i].replace('\\', '.'); + classNames[i] = classNames[i].replace(':', '.'); + } + return newLaunchor(files, classNames, options); + } + + /** + * Create a new launchor and set it as current launchor accessible via method {@link #get()}. + * <p/> + * The launchor will be prepared to compile a set of files, with the class names specified explicitly. + * The class compiled from files[i] will be named classNames[i]. + * + * @param files the .jaxx files to compile + * @param classNames the names of the classes being compiled + * @param options the compiler options to use + * @return the new instanciated launchor + */ + public static synchronized JAXXCompilerLaunchor newLaunchor(File[] files, String[] classNames, CompilerOptions options) { + if (singleton != null) { + singleton.reset(); + } + singleton = new JAXXCompilerLaunchor(files, classNames, options); + return singleton; + } + + /** + * @return the current launchor + * @throws NullPointerException if no launchor was registred via a <code>newLaunchor-like</code> method. + */ + public static JAXXCompilerLaunchor get() throws NullPointerException { + if (singleton == null) { + throw new NullPointerException("no launchor was registred via newLaunchor method"); + } + return singleton; + } + + /** @return <code> if there is a launchor registred, <code>false</code> otherwise. */ + public static boolean isRegistred() { + return singleton != null; + } + + /** + * Load the {@link jaxx.spi.Initializer} services found via the{@link ServiceLoader} mecanism. + * + * @param verbose <ocde>true</code> to print initializers + */ + public static void loadLibraries(boolean verbose) { + //BeanInfoUtil.reset(); + ClassLoader classloader = Thread.currentThread().getContextClassLoader(); + if (verbose) { + log.info("with cl " + classloader); + } + ServiceLoader<Initializer> loader = ServiceLoader.load(Initializer.class, classloader); + for (Initializer initializer : loader) { + if (verbose) { + log.info("load initializer " + initializer); + } + initializer.initialize(); + } + } + /** options of the launchor and underlines compilers */ + protected CompilerOptions options; + /** original list of files to compile */ + protected final File[] files; + /** original list of classes to compile */ + protected final String[] classNames; + /** Files to be treated while compilation. */ + protected List<File> jaxxFiles = new ArrayList<File>(); + /** Class names corresponding to the files in the jaxxFiles list. */ + protected List<String> jaxxFileClassNames = new ArrayList<String>(); + /** Maps the names of classes being compiled to the compiler instance handling the compilation. */ + protected Map<String, JAXXCompiler> compilers = new HashMap<String, JAXXCompiler>(); + /** Maps the names of classes being compiled to their symbol tables (created after the first compiler pass). */ + protected Map<File, SymbolTable> symbolTables = new HashMap<File, SymbolTable>(); + protected LifeCycle currentPass; + protected int errorCount; + protected int warningCount; + protected int compilerCount; + protected JAXXProfile profiler; + + protected JAXXCompilerLaunchor(File[] files, String[] classNames, CompilerOptions options) { + this.options = options == null ? new CompilerOptions() : options; + this.files = files; + this.classNames = classNames; + if (this.options.isVerbose()) { + log.info("files : " + Arrays.toString(files)); + } + if (this.options.isProfile()) { + profiler = new JAXXProfile(); + } + } + + public void init() { + // forces static initializer to run if it hasn't yet + } + + /** Resets all state in preparation for a new compilation session. */ + protected void reset() { + errorCount = warningCount = 0; + jaxxFiles.clear(); + jaxxFileClassNames.clear(); + symbolTables.clear(); + compilers.clear(); + if (profiler != null) { + profiler.clear(); + } + } + + public String getVersion() { + return "1.0.4"; + } + + /** + * Creates a dummy Compiler for use in unit testing. + * + * @return the compiler + */ + public static JAXXCompiler createDummyCompiler() { + return createDummyCompiler(JAXXCompiler.class.getClassLoader()); + } + + /** + * Creates a dummy Compiler for use in unit testing. + * + * @param classLoader class loader to use + * @return the compiler + */ + public static JAXXCompiler createDummyCompiler(ClassLoader classLoader) { + return new JAXXCompiler(classLoader, new DefaultObjectHandler(ClassDescriptorLoader.getClassDescriptor(Object.class))) { + }; + } + + /** + * @param className the name of the class to use + * @return the compiler instance which is processing the specified JAXX class. Each class is compiled by a + * different compiler instance. + */ + public JAXXCompiler getJAXXCompiler(String className) { + return compilers != null ? compilers.get(className) : null; + } + + /** + * @param className the name of the class to use + * @return the symbol table for the specified JAXX class. Must be called during the second compiler pass. + * Returns <code>null</code> if no such symbol table could be found. + */ + public SymbolTable getSymbolTable(String className) { + JAXXCompiler compiler = getJAXXCompiler(className); + if (compiler == null) { + return null; + } + return compiler.getSymbolTable(); + } + + /** + * Returns the system line separator string. + * + * @return the string used to separate lines + */ + public String getLineSeparator() { + return System.getProperty("line.separator", "\n"); + } + + /** + * Compiled a set of files. + * + * @return <code>true</code> if compilation succeeds, <code>false</code> otherwise + */ + public synchronized boolean compile() { + //reset(); // just to be safe... + compilerCount = 0; + jaxxFiles.addAll(Arrays.asList(files)); + jaxxFileClassNames.addAll(Arrays.asList(classNames)); + try { + boolean success = true; + + // pass 1 + if (!nextStep(LifeCycle.compile_first_pass, success)) { + return false; + } + boolean compiled; + do { + compiled = false; + assert jaxxFiles.size() == jaxxFileClassNames.size(); + java.util.Iterator<File> filesIterator = new ArrayList<File>(jaxxFiles).iterator(); // clone it so it can safely be modified while we're iterating + java.util.Iterator<String> classNamesIterator = new ArrayList<String>(jaxxFileClassNames).iterator(); + while (filesIterator.hasNext()) { + File file = filesIterator.next(); + String className = classNamesIterator.next(); + if (log.isDebugEnabled()) { + log.debug("compile first pass for " + className); + } + if (symbolTables.get(file) == null) { + compiled = true; + if (compilers.containsKey(className)) { + throw new CompilerException("Internal error: " + className + " is already being compiled, attempting to compile it again"); + } + + File destDir = options.getTargetDirectory(); + if (destDir != null) { + int dotPos = className.lastIndexOf("."); + if (dotPos != -1) { + destDir = new File(destDir, className.substring(0, dotPos).replace('.', File.separatorChar)); + } + if (!destDir.exists() && !destDir.mkdirs()) { + log.warn("could not create directory " + destDir); + continue; + } + } else { + //destDir = file.getParentFile(); + } + JAXXCompiler compiler = newCompiler(file.getParentFile(), file, className); + addProfileTime(compiler, currentPass.name() + "_start"); + compilers.put(className, compiler); + compiler.compileFirstPass(); + addProfileTime(compiler, currentPass.name() + "_end"); + assert !symbolTables.values().contains(compiler.getSymbolTable()) : "symbolTable is already registered"; + symbolTables.put(file, compiler.getSymbolTable()); + if (compiler.isFailed()) { + success = false; + } + } + } + + } while (compiled); + + // pass 2 + if (!nextStep(LifeCycle.compile_second_pass, success)) { + return false; + } + + assert jaxxFiles.size() == jaxxFileClassNames.size(); + List<File> jaxxFilesClone = new ArrayList<File>(jaxxFiles); + for (String className : jaxxFileClassNames) { + JAXXCompiler compiler = getCompiler(className, "Internal error: could not find compiler for " + className + " during second pass"); + addProfileTime(compiler, currentPass.name() + "_start"); + if (log.isDebugEnabled()) { + log.debug("runInitializers for " + className); + } + if (!compiler.isFailed()) { + compiler.runInitializers(); + } + if (log.isDebugEnabled()) { + log.debug("compile second pass for " + className); + } + compiler.compileSecondPass(); + addProfileTime(compiler, currentPass.name() + "_end"); + if (log.isDebugEnabled()) { + log.debug("done with result [" + !compiler.isFailed() + "] for " + className); + } + if (compiler.isFailed()) { + success = false; + } + } + if (!jaxxFilesClone.equals(jaxxFiles)) { + throw new AssertionError("Internal error: compilation set altered during pass 2 (was " + jaxxFilesClone + ", modified to " + jaxxFiles + ")"); + } + + // stylesheet application + if (!nextStep(LifeCycle.stylesheet_pass, success)) { + return false; + } + assert jaxxFiles.size() == jaxxFileClassNames.size(); + for (String className : jaxxFileClassNames) { + JAXXCompiler compiler = getCompiler(className, "Internal error: could not find compiler for " + className + " during stylesheet application"); + addProfileTime(compiler, currentPass.name() + "_start"); + compiler.applyStylesheets(); + addProfileTime(compiler, currentPass.name() + "_end"); + if (compiler.isFailed()) { + success = false; + } + } + + // code generation + if (!nextStep(LifeCycle.generate_pass, success)) { + return false; + } + assert jaxxFiles.size() == jaxxFileClassNames.size(); + List<Generator> generators = new ArrayList<Generator>(); + for (Generator generator : ServiceLoader.load(Generator.class)) { + generators.add(generator); + } + for (String className : jaxxFileClassNames) { + JAXXCompiler compiler = getCompiler(className, "Internal error: could not find compiler for " + className + " during code generation"); + addProfileTime(compiler, currentPass.name() + "_start"); + compiler.generateCode(generators); + addProfileTime(compiler, currentPass.name() + "_end"); + //compiler.generateCode(); + if (compiler.isFailed()) { + success = false; + } + } + + if (options.isProfile()) { + // profile pass (only if succes compile) + if (!nextStep(LifeCycle.profile_pass, success)) { + return false; + } + StringBuilder buffer = profiler.computeProfileReport(); + log.info(buffer.toString()); + } + + return report(success); + + //FIXME : deal better the exception treatment... + } catch (CompilerException e) { + System.err.println(e.getMessage()); + e.printStackTrace(); + return false; + } catch (Throwable e) { + e.printStackTrace(); + return false; + } finally { + compilerCount = compilers.size(); + //TC - 20081018 only reset when no error was detected + if (options.isResetAfterCompile() && errorCount == 0) { + reset(); + } + } + } + + public int getCompilerCount() { + return compilerCount; + } + + protected JAXXCompiler getCompiler(String className, String message) { + JAXXCompiler compiler = compilers.get(className); + if (compiler == null) { + throw new CompilerException(message); + } + return compiler; + } + + protected boolean nextStep(LifeCycle nextCycle, boolean success) { + if (!success) { + return report(false); + } + currentPass = nextCycle; + return true; + } + + protected boolean report(boolean success) { + if (warningCount == 1) { + System.err.println("1 warning"); + } else if (warningCount > 0) { + System.err.println(warningCount + " warnings"); + } + if (errorCount == 1) { + System.err.println("1 error"); + } else if (errorCount > 0) { + System.err.println(errorCount + " errors"); + } + return success; + } + + protected JAXXCompiler newCompiler(File parentFile, File file, String className) throws InvocationTargetException, IllegalAccessException, InstantiationException, NoSuchMethodException { + Constructor<? extends JAXXCompiler> cons = options.getCompilerClass().getConstructor(File.class, File.class, String.class, CompilerOptions.class); + return cons.newInstance(parentFile, file, className, options); + } + + public static void addProfileTime(JAXXCompiler compiler, String key) { + JAXXProfile p = JAXXCompilerLaunchor.get().profiler; + if (p != null) { + p.addTime(compiler, key); + } + } + + protected static void showUsage() { + System.out.println("Usage: jaxxc <options> <source files>"); + System.out.println(); + System.out.println("Source files must end in extension .jaxx"); + System.out.println("Use JAXX_OPTS environment variable to pass arguments to Java runtime"); + System.out.println(); + System.out.println("Supported options include:"); + System.out.println(" -classpath <paths> paths to search for user classes"); + System.out.println(" -cp <paths> same as -classpath"); + System.out.println(" -d <directory> target directory for generated class files"); + System.out.println(" -java or -j produce .java files, but do not compile them"); + System.out.println(" -keep or -k preserve generated .java files after compilation"); + System.out.println(" -optimize or -o optimize during compilation"); + System.out.println(" -version display version information"); + System.out.println(); + System.out.println("See http://www.jaxxframework.org/ for full documentation."); + } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/compiler/JAXXObjectGenerator.java b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/JAXXObjectGenerator.java new file mode 100644 index 0000000..5d3e8b0 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/JAXXObjectGenerator.java @@ -0,0 +1,598 @@ +package jaxx.compiler; + +import jaxx.Base64Coder; +import jaxx.CompilerException; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.reflect.FieldDescriptor; +import jaxx.reflect.MethodDescriptor; +import jaxx.runtime.JAXXContext; +import jaxx.runtime.JAXXObject; +import jaxx.runtime.JAXXObjectDescriptor; +import jaxx.types.TypeManager; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import static java.lang.reflect.Modifier.FINAL; +import static java.lang.reflect.Modifier.PROTECTED; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * This class is a refactoring of the {@link jaxx.compiler.JAXXCompiler}. + * <p/> + * We delegate now the generation of a {@link jaxx.runtime.JAXXObject} to this class, the + * {@link jaxx.compiler.JAXXCompiler} now only deals with the compilation of files. + * + * @author chemit + */ +public class JAXXObjectGenerator implements Generator { + + /** log */ + protected static final Log log = LogFactory.getLog(JAXXObjectGenerator.class); + protected static final JavaField ACTIVE_BINDINGS_FIELD = JavaField.newField(PROTECTED, + "java.util.List<Object>", "$activeBindings", "new ArrayList<Object>()"); + protected static final JavaField BINDING_SOURCES_FIELD = JavaField.newField(PROTECTED, + "java.util.Map<String,Object>", "$bindingSources", "new HashMap<String,Object>()"); + protected static final JavaField OBJECT_MAP_FIELD = JavaField.newField(PROTECTED, + "Map<String,Object>", "$objectMap", "new HashMap<String,Object>()"); + protected static final JavaField ALL_COMPONENTS_CREATED_FIELD = JavaField.newField(java.lang.reflect.Modifier.PRIVATE, + "boolean", "allComponentsCreated"); + protected static final JavaField CONTEXT_INITIALIZED = JavaField.newField(java.lang.reflect.Modifier.PRIVATE, + "boolean", "contextInitialized", "true"); + protected static final JavaField PREVIOUS_VALUES_FIELD = JavaField.newField(0, + "java.util.Map", "$previousValues", "new java.util.HashMap()"); + protected static final JavaField DELEGATE_CONTEXT_FIELD = JavaField.newField(PROTECTED, + "jaxx.runtime.JAXXContext", "delegateContext"); + protected static final JavaField PROPERTY_CHANGE_SUPPORT_FIELD = JavaField.newField(0, + "java.beans.PropertyChangeSupport", "$propertyChangeSupport"); + protected static final JavaMethod GET_CONTEXT_VALUE_METHOD = JavaMethod.newMethod(java.lang.reflect.Modifier.PUBLIC, "<T> T", "getContextValue", + "return delegateContext.getContextValue(clazz, null);", + new JavaArgument("Class<T>", "clazz")); + protected static final JavaMethod GET_CONTEXT_VALUE_NAMED_METHOD = JavaMethod.newMethod(java.lang.reflect.Modifier.PUBLIC, "<T> T", "getContextValue", + "return delegateContext.getContextValue(clazz, name);", + new JavaArgument("Class<T>", "clazz"), new JavaArgument("String", "name")); + protected static final JavaMethod SET_CONTEXT_VALUE_NAMED_METHOD = JavaMethod.newMethod(java.lang.reflect.Modifier.PUBLIC, "<T> void", "setContextValue", + "delegateContext.setContextValue(o, name);", + new JavaArgument("T", "o"), new JavaArgument("String", "name")); + protected static final JavaMethod SET_CONTEXT_VALUE_METHOD = JavaMethod.newMethod(java.lang.reflect.Modifier.PUBLIC, "<T> void", "setContextValue", + "delegateContext.setContextValue(o, null);", + new JavaArgument("T", "o")); + protected static final JavaMethod REMOVE_CONTEXT_VALUE_NAMED_METHOD = JavaMethod.newMethod(java.lang.reflect.Modifier.PUBLIC, "<T> void", "removeContextValue", + "delegateContext.removeContextValue(clazz, name);", + new JavaArgument("Class<T>", "clazz"), new JavaArgument("String", "name")); + protected static final JavaMethod REMOVE_CONTEXT_VALUE_METHOD = JavaMethod.newMethod(java.lang.reflect.Modifier.PUBLIC, "<T> void", "removeContextValue", + "delegateContext.removeContextValue(clazz, null);", + new JavaArgument("Class<T>", "clazz")); + protected static final JavaMethod GET_PARENT_CONTAINER_MORE_METHOD = JavaMethod.newMethod(java.lang.reflect.Modifier.PUBLIC, "<O extends Container> O", "getParentContainer", + "return delegateContext.getParentContainer(source, clazz);", + new JavaArgument("Object", "source"), new JavaArgument("Class<O>", "clazz")); + protected static final JavaMethod GET_PARENT_CONTAINER_METHOD = JavaMethod.newMethod(java.lang.reflect.Modifier.PUBLIC, "<O extends Container> O", "getParentContainer", + "return delegateContext.getParentContainer(clazz);", + new JavaArgument("Class<O>", "clazz")); + protected static final JavaMethod GET_OBJECT_BY_ID_METHOD = JavaMethod.newMethod(java.lang.reflect.Modifier.PUBLIC, "java.lang.Object", "getObjectById", + "return $objectMap.get(id);", + new JavaArgument("String", "id")); + protected static final JavaMethod GET_JAXX_OBJECT_DESCRIPTOR_METHOD = JavaMethod.newMethod(java.lang.reflect.Modifier.PUBLIC | java.lang.reflect.Modifier.STATIC, "jaxx.runtime.JAXXObjectDescriptor", "$getJAXXObjectDescriptor", + "return jaxx.runtime.Util.decodeCompressedJAXXObjectDescriptor($jaxxObjectDescriptor);"); + protected static final JavaMethod PROCESS_DATA_BINDING_METHOD = JavaMethod.newMethod(java.lang.reflect.Modifier.PUBLIC, "void", "processDataBinding", + "processDataBinding(dest, false);", + new JavaArgument("String", "dest")); + protected static final JavaMethod FIRE_PROPERTY_CHANGE_METHOD = JavaMethod.newMethod(java.lang.reflect.Modifier.PUBLIC, "void", "firePropertyChange", + "super.firePropertyChange(propertyName, oldValue, newValue);", + new JavaArgument("String", "propertyName"), new JavaArgument("Object", "oldValue"), new JavaArgument("Object", "newValue")); + protected static final JavaMethod FIRE_PROPERTY_CHANGE_NAMED_METHOD = JavaMethod.newMethod(java.lang.reflect.Modifier.PUBLIC, "void", "firePropertyChange", + "$getPropertyChangeSupport().firePropertyChange(propertyName, oldValue, newValue);", + new JavaArgument("String", "propertyName"), new JavaArgument("Object", "oldValue"), new JavaArgument("Object", "newValue")); + protected static final JavaMethod GET_PROPERTY_CHANGE_SUPPORT_METHOD = JavaMethod.newMethod(0, "java.beans.PropertyChangeSupport", "$getPropertyChangeSupport", + "if ($propertyChangeSupport == null)\n" + + " $propertyChangeSupport = new PropertyChangeSupport(this);\n" + + "return $propertyChangeSupport;"); + protected static final JavaMethod ADD_PROPERTY_CHANGE_SUPPORT_METHOD = JavaMethod.newMethod(java.lang.reflect.Modifier.PUBLIC, "void", "addPropertyChangeListener", + "$getPropertyChangeSupport().addPropertyChangeListener(listener);", + new JavaArgument("java.beans.PropertyChangeListener", "listener")); + protected static final JavaMethod ADD_PROPERTY_CHANGE_SUPPORT_NAMED_METHOD = JavaMethod.newMethod(java.lang.reflect.Modifier.PUBLIC, "void", "addPropertyChangeListener", + "$getPropertyChangeSupport().addPropertyChangeListener(property, listener);", + new JavaArgument("String", "property"), new JavaArgument("java.beans.PropertyChangeListener", "listener")); + protected static final JavaMethod REMOVE_PROPERTY_CHANGE_SUPPORT_METHOD = JavaMethod.newMethod(java.lang.reflect.Modifier.PUBLIC, "void", "removePropertyChangeListener", + "$getPropertyChangeSupport().removePropertyChangeListener(listener);", + new JavaArgument("java.beans.PropertyChangeListener", "listener")); + protected static final JavaMethod REMOVE_PROPERTY_CHANGE_SUPPORT_NAMED_METHOD = JavaMethod.newMethod(java.lang.reflect.Modifier.PUBLIC, "void", "removePropertyChangeListener", + "$getPropertyChangeSupport().removePropertyChangeListener(property, listener);", + new JavaArgument("String", "property"), new JavaArgument("java.beans.PropertyChangeListener", "listener")); + + @Override + public void finalizeCompiler(CompiledObject root, JAXXCompiler compiler, JavaFile javaFile, String packageName, String className) { + + String fullClassName = packageName != null ? packageName + "." + className : className; + if (root == null) { + throw new CompilerException("root tag must be a class tag"); + } + //Map<String, CompiledObject> objects = compiler.getObjects(); + ClassDescriptor superclass = root.getObjectClass(); + boolean superclassIsJAXXObject = ClassDescriptorLoader.getClassDescriptor(JAXXObject.class).isAssignableFrom(superclass); + javaFile.setModifiers(Modifier.PUBLIC); + javaFile.setClassName(fullClassName); + javaFile.setSuperClass(JAXXCompiler.getCanonicalName(superclass)); + javaFile.setSuperclassIsJAXXObject(superclassIsJAXXObject); + + javaFile.addInterfaces(compiler.getExtraInterfaces()); + javaFile.setAbstractClass(compiler.isAbstractClass()); + javaFile.setGenericType(compiler.getGenericType()); + javaFile.setSuperGenericType(compiler.getSuperGenericType()); + + for (CompiledObject object : compiler.getObjects().values()) { + CompiledObjectDecorator decorator = object.getDecorator(); + decorator.finalizeCompiler(compiler, root, object, javaFile, packageName, className, fullClassName); + + /*if (!object.isOverride() && !(object instanceof ScriptInitializer)) { + String id = object.getId(); + int access = id.startsWith("$") ? Modifier.PRIVATE : Modifier.PROTECTED; + if (object == root) { + javaFile.addField(new JavaField(access, fullClassName, id, "this")); + } else { + //TC -20081017 can have generic on compiled Object + javaFile.addField(JavaField.newField(access, JAXXCompiler.getCanonicalName(object), id), object.isJavaBean()); + } + } + + if (!compiler.inlineCreation(object) && object != root) { + javaFile.addMethod(JavaMethod.newMethod(Modifier.PROTECTED, "void", object.getCreationMethodName(), getCreationCode(compiler, object))); + }*/ + } + + // DataBinding + for (DataBinding dataBinding : compiler.getDataBindings()) { + if (dataBinding.compile(true)) { + compiler.getInitDataBindings().append("applyDataBinding(").append(TypeManager.getJavaCode(dataBinding.getId())).append(");").append(JAXXCompiler.getLineSeparator()); + } + } + + if (superclassIsJAXXObject) { + boolean hasBind = compiler.getApplyDataBinding().length() > 0; + if (hasBind) { + compiler.appendApplyDataBinding(" else {"); + compiler.appendApplyDataBinding(JAXXCompiler.getLineSeparator()); + compiler.appendApplyDataBinding(" "); + } + compiler.appendApplyDataBinding("super.applyDataBinding($binding);"); + compiler.appendApplyDataBinding(JAXXCompiler.getLineSeparator()); + + if (hasBind) { + compiler.appendApplyDataBinding(" return;"); + compiler.appendApplyDataBinding(JAXXCompiler.getLineSeparator()); + compiler.appendApplyDataBinding("}"); + } + + + hasBind = compiler.getRemoveDataBinding().length() > 0; + if (hasBind) { + compiler.appendRemoveDataBinding(" else {"); + compiler.appendRemoveDataBinding(JAXXCompiler.getLineSeparator()); + compiler.appendRemoveDataBinding(" "); + } + compiler.appendRemoveDataBinding("super.removeDataBinding($binding);"); + compiler.appendRemoveDataBinding(JAXXCompiler.getLineSeparator()); + + if (hasBind) { + compiler.appendRemoveDataBinding("}"); + } + } else { + javaFile.addInterface(JAXXCompiler.getCanonicalName(JAXXObject.class)); + } + } + + @Override + public void prepareJavaFile(CompiledObject root, JAXXCompiler compiler, JavaFile javaFile, String packageName, String className) throws ClassNotFoundException { + + String fullClassName = javaFile.getClassName(); + + String jaxxContextImplementorClass = compiler.getOptions().getJaxxContextImplementorClass(); + boolean superclassIsJAXXObject = javaFile.isSuperclassIsJAXXObject(); + if (!superclassIsJAXXObject) { + // add logger + if (compiler.getOptions().isAddLogger()) { + javaFile.addImport(Log.class); + javaFile.addImport(LogFactory.class); + javaFile.addField(JavaField.newField(Modifier.PUBLIC + Modifier.STATIC + FINAL, "Log", "log", "LogFactory.getLog(" + fullClassName + ".class)")); + } + + // JAXXObject + javaFile.addField(OBJECT_MAP_FIELD); + javaFile.addMethod(GET_OBJECT_BY_ID_METHOD); + javaFile.addField(BINDING_SOURCES_FIELD); + javaFile.addField(ACTIVE_BINDINGS_FIELD); + + // JAXXContext + javaFile.addField(JavaField.newField(PROTECTED | FINAL, JAXXContext.class.getName(), "delegateContext", "new " + jaxxContextImplementorClass + "(this);")); + javaFile.addMethod(SET_CONTEXT_VALUE_METHOD); + javaFile.addMethod(SET_CONTEXT_VALUE_NAMED_METHOD); + javaFile.addMethod(GET_CONTEXT_VALUE_METHOD); + javaFile.addMethod(GET_CONTEXT_VALUE_NAMED_METHOD); + javaFile.addMethod(REMOVE_CONTEXT_VALUE_METHOD); + javaFile.addMethod(REMOVE_CONTEXT_VALUE_NAMED_METHOD); + javaFile.addMethod(GET_PARENT_CONTAINER_METHOD); + javaFile.addMethod(GET_PARENT_CONTAINER_MORE_METHOD); + + // PropertyChangeSupport + addPropertyChangeSupport(root, javaFile); + + // DataBinding + javaFile.addMethod(PROCESS_DATA_BINDING_METHOD); + } + + javaFile.addField(ALL_COMPONENTS_CREATED_FIELD); + boolean overrideContextInitialized = false; + FieldDescriptor[] scriptFields = compiler.getScriptFields(); + for (FieldDescriptor f : scriptFields) { + if ("contextInitialized".equals(f.getName())) { + overrideContextInitialized = true; + break; + } + } + if (!overrideContextInitialized) { + javaFile.addField(CONTEXT_INITIALIZED); + } + javaFile.addField(createJAXXObjectDescriptorField(compiler, javaFile)); + + if (compiler.getStylesheet() != null) { + javaFile.addField(PREVIOUS_VALUES_FIELD); + } + /*for (CompiledObject object : compiler.getObjects().values()) { + List<CompiledObject.ChildRef> refList = object.getChilds(); + if (refList==null || refList.isEmpty()) { + continue; + } + for (ChildRef childRef : refList) { + childRef.addToAdditionCode(buffer); + } + }*/ + //TC 20090228 - only generate constructors if not done in scripts + boolean constructorDetected = false; + MethodDescriptor[] methods = compiler.getScriptMethods(); + for (MethodDescriptor m : methods) { + try { + m.getReturnType(); + if (className.equals(m.getName())) { + constructorDetected = true; + break; + } + } catch (Exception e) { + log.warn("could not find return type " + m); + } + } + if (!constructorDetected) { + javaFile.addMethod(createConstructor(compiler, className, superclassIsJAXXObject)); + javaFile.addMethod(createConstructorWithInitialContext(compiler, className, superclassIsJAXXObject)); + } + + javaFile.addMethod(createInitializer(compiler)); + javaFile.addMethod(GET_JAXX_OBJECT_DESCRIPTOR_METHOD); + + javaFile.addBodyCode(compiler.getBodyCode().toString()); + + javaFile.addMethod(createCompleteSetupMethod(compiler, javaFile, compiler.getInitDataBindings())); + + + javaFile.addMethod(JavaMethod.newMethod(Modifier.PUBLIC, "void", "applyDataBinding", + compiler.getApplyDataBinding().toString() + JAXXCompiler.getLineSeparator() + "processDataBinding($binding);", + new JavaArgument("String", "$binding"))); + + javaFile.addMethod(JavaMethod.newMethod(Modifier.PUBLIC, "void", "removeDataBinding", + compiler.getRemoveDataBinding().toString(), new JavaArgument("String", "$binding"))); + + javaFile.addMethod(createProcessDataBindingMethod(compiler, superclassIsJAXXObject)); + + addEventHandlers(compiler, javaFile); + + } + + + /*---------------------------------------------------------------------------------*/ + /*-- Create fields ----------------------------------------------------------------*/ + /*---------------------------------------------------------------------------------*/ + protected JavaField createJAXXObjectDescriptorField(JAXXCompiler compiler, JavaFile javaFile) { + try { + JAXXObjectDescriptor descriptor = compiler.getJAXXObjectDescriptor(); + String data = Base64Coder.serialize(descriptor, true); + /*ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(new GZIPOutputStream(buffer)); + out.writeObject(descriptor); + out.close(); + // the use of the weird deprecated constructor is deliberate -- we need to store the data as a String + // in the compiled class file, since byte array initialization is horribly inefficient compared to + // String initialization. So we store the bytes in the String, and we quite explicitly want a 1:1 + // mapping between bytes and chars, with the high byte of the char set to zero. We can then safely + // reconstitute the original byte[] at a later date. This is unquestionably an abuse of the String + // type, but if we could efficiently store a byte[] we wouldn't have to do this. + String data = new String(buffer.toByteArray(), 0);*/ + + int sizeLimit = 65000; // constant strings are limited to 64K, and I'm not brave enough to push right up to the limit + if (data.length() < sizeLimit) { + return JavaField.newField(Modifier.PRIVATE | Modifier.STATIC, "java.lang.String", "$jaxxObjectDescriptor", TypeManager.getJavaCode(data)); + } else { + StringBuffer initializer = new StringBuffer(); + for (int i = 0; i < data.length(); i += sizeLimit) { + String name = "$jaxxObjectDescriptor" + i; + javaFile.addField(new JavaField(Modifier.PRIVATE | Modifier.STATIC, "java.lang.String", name, + TypeManager.getJavaCode(data.substring(i, Math.min(i + sizeLimit, data.length()))))); + if (initializer.length() > 0) { + initializer.append(" + "); + } + initializer.append("String.valueOf(").append(name).append(")"); + } + return JavaField.newField(Modifier.PRIVATE | Modifier.STATIC, "java.lang.String", "$jaxxObjectDescriptor", initializer.toString()); + } + } catch (IOException e) { + throw new RuntimeException("Internal error: can't-happen error", e); + } + } + + /*---------------------------------------------------------------------------------*/ + /*-- Create methods ---------------------------------------------------------------*/ + /*---------------------------------------------------------------------------------*/ + protected void addPropertyChangeSupport(CompiledObject root, JavaFile javaFile) { + ClassDescriptor currentClass = root.getObjectClass(); + MethodDescriptor firePropertyChange = null; + while (firePropertyChange == null && currentClass != null) { + try { + firePropertyChange = currentClass.getDeclaredMethodDescriptor("firePropertyChange", ClassDescriptorLoader.getClassDescriptor(String.class), + ClassDescriptorLoader.getClassDescriptor(Object.class), + ClassDescriptorLoader.getClassDescriptor(Object.class)); + + } catch (NoSuchMethodException e) { + currentClass = currentClass.getSuperclass(); + } + } + + int modifiers = firePropertyChange != null ? firePropertyChange.getModifiers() : 0; + if (Modifier.isPublic(modifiers)) { + // we have all the support we need + } + if (Modifier.isProtected(modifiers)) { + // there is property change support but the firePropertyChange method is protected + javaFile.addMethod(FIRE_PROPERTY_CHANGE_METHOD); + } else { + // either no support at all or firePropertyChange isn't accessible + javaFile.addField(PROPERTY_CHANGE_SUPPORT_FIELD); + javaFile.addMethod(GET_PROPERTY_CHANGE_SUPPORT_METHOD); + javaFile.addMethod(ADD_PROPERTY_CHANGE_SUPPORT_METHOD); + javaFile.addMethod(ADD_PROPERTY_CHANGE_SUPPORT_NAMED_METHOD); + javaFile.addMethod(REMOVE_PROPERTY_CHANGE_SUPPORT_METHOD); + javaFile.addMethod(REMOVE_PROPERTY_CHANGE_SUPPORT_NAMED_METHOD); + javaFile.addMethod(FIRE_PROPERTY_CHANGE_NAMED_METHOD); + } + } + + protected void addEventHandlers(JAXXCompiler compiler, JavaFile javaFile) { + for (Map.Entry<String, Map<ClassDescriptor, List<EventHandler>>> e1 : compiler.getEventHandlers().entrySet()) { + // outer loop is iterating over different objects (well, technically, different Java expressions) + for (Map.Entry<ClassDescriptor, List<EventHandler>> e2 : e1.getValue().entrySet()) { + // iterate over different types of listeners for this particular object (MouseListener, ComponentListener, etc.) + for (EventHandler handler : e2.getValue()) { + // iterate over individual event handlers of a single type + String methodName = compiler.getEventHandlerMethodName(handler); + MethodDescriptor listenerMethod = handler.getListenerMethod(); + if (listenerMethod.getParameterTypes().length != 1) { + throw new CompilerException("Expected event handler " + listenerMethod.getName() + " of class " + handler.getListenerClass() + " to have exactly one argument"); + } + javaFile.addMethod(JavaMethod.newMethod(Modifier.PUBLIC, "void", methodName, handler.getJavaCode(), + new JavaArgument(JAXXCompiler.getCanonicalName(listenerMethod.getParameterTypes()[0]), "event"))); + } + } + } + } + + protected JavaMethod createConstructor(JAXXCompiler compiler, String className, boolean superclassIsJAXXObject) throws CompilerException { + StringBuffer code = new StringBuffer(); + String constructorParams = compiler.getRootObject().getConstructorParams(); + if (constructorParams != null) { + code.append(" super(").append(constructorParams).append(");").append(JAXXCompiler.getLineSeparator()); + } else { + if (superclassIsJAXXObject) { + code.append(" super();").append(JAXXCompiler.getLineSeparator()); + } + } + code.append("$initialize();"); + code.append(JAXXCompiler.getLineSeparator()); + return JavaMethod.newMethod(Modifier.PUBLIC, null, className, code.toString()); + } + + protected JavaMethod createConstructorWithInitialContext(JAXXCompiler compiler, String className, boolean superclassIsJAXXObject) throws CompilerException { + StringBuffer code = new StringBuffer(); + String constructorParams = compiler.getRootObject().getConstructorParams(); + if (constructorParams != null) { + code.append(" super(").append(constructorParams).append(");").append(JAXXCompiler.getLineSeparator()); + } else { + if (superclassIsJAXXObject) { + code.append(" super(parentContext);").append(JAXXCompiler.getLineSeparator()); + } + } + if (!superclassIsJAXXObject) { + code.append("if (parentContext instanceof jaxx.runtime.JAXXInitialContext) {"); + code.append(JAXXCompiler.getLineSeparator()); + code.append(" ((jaxx.runtime.JAXXInitialContext)parentContext).to(this);"); + code.append(JAXXCompiler.getLineSeparator()); + code.append("} else {"); + code.append(JAXXCompiler.getLineSeparator()); + code.append(" setContextValue(parentContext);"); + code.append(JAXXCompiler.getLineSeparator()); + code.append("}"); + code.append(JAXXCompiler.getLineSeparator()); + } + code.append("$initialize();"); + code.append(JAXXCompiler.getLineSeparator()); + return JavaMethod.newMethod(Modifier.PUBLIC, null, className, code.toString(), new JavaArgument("jaxx.runtime.JAXXContext", "parentContext")); + } + + public JavaMethod createInitializer(JAXXCompiler compiler) throws CompilerException { + StringBuffer code = new StringBuffer(); + CompiledObject root = compiler.getRootObject(); + code.append("if (allComponentsCreated || !contextInitialized) {"); + code.append(JAXXCompiler.getLineSeparator()); + code.append(" return;"); + code.append(JAXXCompiler.getLineSeparator()); + code.append("}"); + code.append(JAXXCompiler.getLineSeparator()); + code.append("$objectMap.put(").append(TypeManager.getJavaCode(root.getId())).append(", this);"); + code.append(JAXXCompiler.getLineSeparator()); + + Iterator<CompiledObject> i = compiler.getObjectCreationOrder(); + boolean lastWasMethodCall = false; + while (i.hasNext()) { + CompiledObject object = i.next(); + if (object == root) { + continue; + } + CompiledObjectDecorator decorator = object.getDecorator(); + lastWasMethodCall = decorator.createInitializer(compiler, root, object, code, lastWasMethodCall); + /*if (object != root && !object.isOverride()) { + if (compiler.inlineCreation(object)) { + if (lastWasMethodCall) { + lastWasMethodCall = false; + code.append(JAXXCompiler.getLineSeparator()); + } + code.append(getCreationCode(compiler, object)); + code.append(JAXXCompiler.getLineSeparator()); + } else { + code.append(object.getCreationMethodName()).append("();"); + code.append(JAXXCompiler.getLineSeparator()); + lastWasMethodCall = true; + } + }*/ + } + root.getDecorator().createInitializer(compiler, root, root, code, lastWasMethodCall); + /*String rootCode = root.getInitializationCode(compiler); + if (rootCode != null && rootCode.length() > 0) { + code.append(rootCode); + code.append(JAXXCompiler.getLineSeparator()); + }*/ + code.append(JAXXCompiler.getLineSeparator()); + if (compiler.getInitializer().length() > 0) { + code.append(compiler.getInitializer()); + code.append(JAXXCompiler.getLineSeparator()); + } + code.append("$completeSetup();"); + code.append(JAXXCompiler.getLineSeparator()); + return JavaMethod.newMethod(Modifier.PRIVATE, "void", "$initialize", code.toString()); + } + + protected JavaMethod createCompleteSetupMethod(JAXXCompiler compiler, JavaFile javaFile, StringBuffer initDataBindings) { + StringBuffer code = new StringBuffer(); + code.append("allComponentsCreated = true;"); + code.append(JAXXCompiler.getLineSeparator()); + for (CompiledObject object : compiler.getObjects().values()) { + CompiledObjectDecorator decorator = object.getDecorator(); + code.append(decorator.createCompleteSetupMethod(compiler, object, javaFile, initDataBindings)); + + /*//TC - 20081017 only generate the method if not empty ? + if (object.getId().startsWith("$")) { + code.append(object.getAdditionCode()).append(JAXXCompiler.getLineSeparator()); + } else { + String additionCode = object.getAdditionCode(); + if (additionCode.length() > 0) { + code.append(object.getAdditionMethodName()).append("();").append(JAXXCompiler.getLineSeparator()); + additionCode = "if (!allComponentsCreated) {" + JAXXCompiler.getLineSeparator() + " return;" + JAXXCompiler.getLineSeparator() + "}" + JAXXCompiler.getLineSeparator() + additionCode; + javaFile.addMethod(JavaMethod.newMethod(Modifier.PROTECTED, "void", object.getAdditionMethodName(), additionCode)); + } + }*/ + //code.append(getLineSeparator()); + } + + code.append(initDataBindings); + + if (compiler.getLateInitializer().length() > 0) { + code.append(compiler.getLateInitializer()); + code.append(JAXXCompiler.getLineSeparator()); + } + //TC-20090313 add an extra method after complete setup + MethodDescriptor method = compiler.getScriptMethod("$afterCompleteSetup"); + if (method != null) { + code.append("$afterCompleteSetup();").append(JAXXCompiler.getLineSeparator()); + } + return JavaMethod.newMethod(Modifier.PRIVATE, "void", "$completeSetup", code.toString()); + } + + protected JavaMethod createProcessDataBindingMethod(JAXXCompiler compiler, boolean superclassIsJAXXObject) { + StringBuffer code = new StringBuffer(); + //boolean superclassIsJAXXObject = ClassDescriptorLoader.getClassDescriptor(JAXXObject.class).isAssignableFrom(compiler.getRootObject().getObjectClass()); + // the force parameter forces the update to happen even if it is already in activeBindings. This + // is used on superclass invocations b/c by the time the call gets to the superclass, it is already + // marked active and would otherwise be skipped + if (compiler.getProcessDataBinding().length() > 0) { + code.append(" if (!$force && $activeBindings.contains($dest)) { "); + code.append(JAXXCompiler.getLineSeparator()); + code.append(" return;"); + code.append(JAXXCompiler.getLineSeparator()); + code.append("}"); + code.append(JAXXCompiler.getLineSeparator()); + code.append("$activeBindings.add($dest);"); + code.append(JAXXCompiler.getLineSeparator()); + code.append("try {"); + code.append(JAXXCompiler.getLineSeparator()); + if (compiler.getProcessDataBinding().length() > 0) { + code.append(compiler.getProcessDataBinding().toString()); + //code.append(JAXXCompiler.getLineSeparator()); + } + if (superclassIsJAXXObject) { + code.append(" else {"); + code.append(JAXXCompiler.getLineSeparator()); + code.append(" super.processDataBinding($dest, true);"); + code.append(JAXXCompiler.getLineSeparator()); + code.append(" }"); + code.append(JAXXCompiler.getLineSeparator()); + } + code.append("} finally {"); + code.append(JAXXCompiler.getLineSeparator()); + code.append(" $activeBindings.remove($dest);"); + code.append(JAXXCompiler.getLineSeparator()); + code.append("}"); + code.append(JAXXCompiler.getLineSeparator()); + } else if (superclassIsJAXXObject) { + code.append("super.processDataBinding($dest, true);"); + code.append(JAXXCompiler.getLineSeparator()); + } + return JavaMethod.newMethod(Modifier.PUBLIC, "void", "processDataBinding", code.toString(), + new JavaArgument("String", "$dest"), new JavaArgument("boolean", "$force")); + } + + /*---------------------------------------------------------------------------------*/ + /*-- Create methods code ----------------------------------------------------------*/ + /*---------------------------------------------------------------------------------*/ + + /* protected String getCreationCode(JAXXCompiler compiler, CompiledObject object) throws CompilerException { + if (object instanceof ScriptInitializer) { + return object.getInitializationCode(compiler); + } + CompiledObjectDecorator decorator = object.getDecorator(); + String result = decorator.getCreationCode(compiler, object); + return result;*/ + /*StringBuffer result = new StringBuffer(); + result.append(object.getId()); + result.append(" = "); + if (object.isJavaBean() && object.getJavaBeanInitCode() != null) { + result.append(object.getJavaBeanInitCode()).append(";"); + } else { + String constructorParams = object.getConstructorParams(); + if (constructorParams != null) { + //TC - 20081017 compiledObject can have generics + result.append(" new ").append(JAXXCompiler.getCanonicalName(object)).append("(").append(constructorParams).append(");"); + //result.append("(").append(getCanonicalName(object.getObjectClass())).append(") new ").append(getCanonicalName(object.getObjectClass())).append("(").append(constructorParams).append(");"); + } else { + //TC - 20081017 compiledObject can have generics + result.append("new ").append(JAXXCompiler.getCanonicalName(object)).append("();"); + } + } + result.append(JAXXCompiler.getLineSeparator()); + String initCode = object.getInitializationCode(compiler); + if (initCode != null && initCode.length() > 0) { + result.append(initCode); + } + result.append("$objectMap.put(").append(TypeManager.getJavaCode(object.getId())).append(", ").append(object.getId()).append(");"); + + return result.toString();*/ +// } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/compiler/JAXXProfile.java b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/JAXXProfile.java new file mode 100644 index 0000000..0ed1f68 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/JAXXProfile.java @@ -0,0 +1,240 @@ +package jaxx.compiler; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.SortedMap; +import jaxx.compiler.JAXXCompilerLaunchor.LifeCycle; +import org.nuiton.util.StringUtil; + +/** + * Pour profiler les temps d'execution pendant une compilation. + * + * @author tony + * @since 1.3 + */ +public class JAXXProfile { + + void clear() { + entries.clear(); + compilers.clear(); + } + + protected class CompilerEntry { + + JAXXCompiler compiler; + SortedMap<String, Long> times; + + public CompilerEntry(JAXXCompiler compiler) { + this.compiler = compiler; + times = new java.util.TreeMap<String, Long>(); + } + } + + public static class ProfileResult { + + long min, max, average, total; + Map<JAXXCompiler, Long> delta; + List<Long> times; + + ProfileResult(String label, Map<JAXXCompiler, Long> delta) { + this.delta = delta; + times = new java.util.ArrayList<Long>(delta.values()); + java.util.Collections.sort(times); + min = times.get(0); + max = times.get(times.size() - 1); + total = 0; + average = 0; + for (Long t : times) { + total += t; + } + average = total / times.size(); + } + + public long getTime(JAXXCompiler compiler) { + for (Entry<JAXXCompiler, Long> entry : delta.entrySet()) { + if (entry.getKey().equals(compiler)) { + return entry.getValue(); + } + } + throw new IllegalArgumentException("could not find time for compiler " + compiler); + } + + public void clear() { + times.clear(); + delta.clear(); + } + + public JAXXCompiler getCompiler(Long l) { + for (Entry<JAXXCompiler, Long> entry : delta.entrySet()) { + if (entry.getValue().equals(l)) { + return entry.getKey(); + } + } + throw new IllegalArgumentException("could not find compiler for time " + l); + } + } + SortedMap<Integer, CompilerEntry> entries; + List<JAXXCompiler> compilers; + + public JAXXProfile() { + compilers = new java.util.ArrayList<JAXXCompiler>(); + entries = new java.util.TreeMap<Integer, CompilerEntry>(); + } + + public void addTime(JAXXCompiler compiler, String key) { + CompilerEntry e = getEntry(compiler); + e.times.put(key, System.nanoTime()); + } + + public Map<JAXXCompiler, Long> getDelta(String label, String keyOne, String keyTwo) { + Map<JAXXCompiler, Long> result = new java.util.HashMap<JAXXCompiler, Long>(); + for (java.util.Map.Entry<Integer, CompilerEntry> e : entries.entrySet()) { + JAXXCompiler c = getCompiler(e.getKey()); + CompilerEntry entry = e.getValue(); + Long t0 = entry.times.get(keyOne); + Long t1 = entry.times.get(keyTwo); + if (t0 == null) { + throw new NullPointerException("could not find time for " + keyOne + " on compiler " + c.getOutputClassName()); + } + if (t1 == null) { + throw new NullPointerException("could not find time for " + keyTwo + " on compiler " + c.getOutputClassName()); + } + long delta = t1 - t0; + result.put(c, delta); + } + return result; + } + + public ProfileResult newProfileResult(LifeCycle step) { + ProfileResult result; + String name = step.name(); + Map<JAXXCompiler, Long> delta = getDelta(name, name + "_start", name + "_end"); + result = new ProfileResult(name, delta); + return result; + } + + public ProfileResult newProfileResult(ProfileResult... toCumul) { + ProfileResult result; + Map<JAXXCompiler, Long> delta = new java.util.HashMap<JAXXCompiler, Long>(); + for (JAXXCompiler c : compilers) { + long total = 0; + for (ProfileResult cumul : toCumul) { + long time = cumul.getTime(c); + total += time; + } + delta.put(c, total); + } + result = new ProfileResult("all", delta); + return result; + } + + public StringBuilder computeProfileReport() { + + StringBuilder buffer = new StringBuilder(); + + if (compilers.isEmpty()) { + return buffer.append("no jaxx file treated, no profile report"); + } + + // compute max size of the fqn of a compiled file + int maxLength = 0; + for (JAXXCompiler compiler : compilers) { + int l = compiler.getOutputClassName().length(); + if (l > maxLength) { + maxLength = l; + } + } + + ProfileResult cfp = newProfileResult(LifeCycle.compile_first_pass); + ProfileResult csp = newProfileResult(LifeCycle.compile_second_pass); + ProfileResult ssp = newProfileResult(LifeCycle.stylesheet_pass); + ProfileResult gp = newProfileResult(LifeCycle.generate_pass); + ProfileResult total = newProfileResult(cfp, csp, ssp, gp); + + String reportPattern = "\n|%1$-" + maxLength + "s|%2$15s|%3$15s|%4$15s|%5$15s|%6$15s|"; + + char[] tmpC = new char[maxLength]; + Arrays.fill(tmpC, '-'); + String line = String.format(reportPattern, + new String(tmpC), + "---------------", + "---------------", + "---------------", + "---------------", + "---------------"); + + buffer.append(line); + + buffer.append(String.format(reportPattern, + "(files / stats) \\ passes", + "compile round 1", "compile round 2", "stylesheet", "generation", "all passes")); + + buffer.append(line); + + // affiche les temps de tous les fichiers en temp total croissant + for (Long l : total.times) { + JAXXCompiler c = total.getCompiler(l); + printReportLine(buffer, reportPattern, c.getOutputClassName(), cfp.getTime(c), csp.getTime(c), ssp.getTime(c), gp.getTime(c), total.getTime(c)); + } + + buffer.append(line); + + if (compilers.size() > 1) { + printReportLine(buffer, reportPattern, "total (" + compilers.size() + " files)", cfp.total, csp.total, ssp.total, gp.total, total.total); + + buffer.append(line); + + printReportLine2(buffer, reportPattern, "min", cfp.min, csp.min, ssp.min, gp.min, total.min); + printReportLine2(buffer, reportPattern, "max", cfp.max, csp.max, ssp.max, gp.max, total.max); + printReportLine(buffer, reportPattern, "average", cfp.average, csp.average, ssp.average, gp.average, total.average); + buffer.append(line); + } + cfp.clear(); + csp.clear(); + ssp.clear(); + gp.clear(); + total.clear(); + + return buffer; + } + public static final String TIME_PATTERN = "%1$9s - %2$2d%%"; + + protected void printReportLine(StringBuilder buffer, String reportPattern, String label, long firstPassCounter, long secondPassCounter, long cssCounter, long generatorCounter, long totalCounter) { + float percentCFP = ((float) firstPassCounter / totalCounter) * 100; + float percentCSP = ((float) secondPassCounter / totalCounter) * 100; + float percentCSSP = ((float) cssCounter / totalCounter) * 100; + float percentGP = ((float) generatorCounter / totalCounter) * 100; + String strCFP = String.format(TIME_PATTERN, StringUtil.convertTime(firstPassCounter), (int) percentCFP); + String strCSP = String.format(TIME_PATTERN, StringUtil.convertTime(secondPassCounter), (int) percentCSP); + String strCSSP = String.format(TIME_PATTERN, StringUtil.convertTime(cssCounter), (int) percentCSSP); + String strGP = String.format(TIME_PATTERN, StringUtil.convertTime(generatorCounter), (int) percentGP); + + buffer.append(String.format(reportPattern, label, strCFP, strCSP, strCSSP, strGP, StringUtil.convertTime(totalCounter))); + } + + protected void printReportLine2(StringBuilder buffer, String reportPattern, String label, long firstPassCounter, long secondPassCounter, long cssCounter, long generatorCounter, long totalCounter) { + buffer.append(String.format(reportPattern, label, StringUtil.convertTime(firstPassCounter), StringUtil.convertTime(secondPassCounter), StringUtil.convertTime(cssCounter), StringUtil.convertTime(generatorCounter), StringUtil.convertTime(totalCounter))); + } + + protected CompilerEntry getEntry(JAXXCompiler compiler) { + int key = compiler.getOutputClassName().hashCode(); + CompilerEntry result = entries.get(key); + if (result == null) { + result = new CompilerEntry(compiler); + entries.put(key, result); + compilers.add(compiler); + } + return result; + } + + protected JAXXCompiler getCompiler(int hasCode) { + for (JAXXCompiler c : compilers) { + if (hasCode == c.getOutputClassName().hashCode()) { + return c; + } + } + return null; + } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/compiler/JavaArgument.java b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/JavaArgument.java new file mode 100644 index 0000000..638e872 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/JavaArgument.java @@ -0,0 +1,86 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.compiler; + +/** + * Represents an argument to a <code>JavaMethod</code>. + * + * @see JavaMethod + */ +public class JavaArgument { + private String name; + private String type; + private boolean isFinal; + + + /** + * Creates a new <code>JavaArgument</code> with the specified name and type. For example, the method <code>main()</code> + * might have a <code>JavaArgument</code> with a name of <code>"arg"</code> and a type of <code>"java.lang.String[]"</code>. + * + * @param type the argument's type, as it would appear in Java source code + * @param name the argument's name + */ + public JavaArgument(String type, String name) { + this(type, name, false); + } + + + /** + * Creates a new <code>JavaArgument</code> with the specified name, type, and finality. For example, the method <code>main()</code> + * might have a <code>JavaArgument</code> with a name of <code>"arg"</code> and a type of <code>"java.lang.String[]"</code>. The + * <code>isFinal</code> parameter allows the presence of the <code>final</code> keyword on the argument to be controlled. + * + * @param type the argument's type, as it would appear in Java source code + * @param name the argument's name + * @param isFinal <code>true</code> if the argument should be marked final + */ + public JavaArgument(String type, String name, boolean isFinal) { + this.type = type; + this.name = name; + this.isFinal = isFinal; + } + + + /** + * Returns the argument's name. + * + * @return the name of the argument + */ + public String getName() { + return name; + } + + + /** + * Returns the argument's type as it would be represented in Java source code. + * + * @return the argument's type + */ + public String getType() { + return type; + } + + + /** + * Returns <code>true</code> if the <code>final</code> keyword should appear before the argument. + * + * @return <code>true</code> if the argument is final + */ + public boolean isFinal() { + return isFinal; + } + + + /** + * Returns the Java source code for this argument. + * + * @return the Java source code for this argument + */ + @Override + public String toString() { + String result = type + ' ' + name; + return isFinal ? "final " + result : result; + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/compiler/JavaField.java b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/JavaField.java new file mode 100644 index 0000000..4dcd369 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/JavaField.java @@ -0,0 +1,187 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.compiler; + +import java.lang.reflect.Modifier; +import java.util.Comparator; + +/** + * Represents a field in a Java source file being generated for output. <code>JavaFields</code> are created + * and added to a {@link JavaFile}, which can then output Java source code. + */ +public class JavaField implements Comparable<JavaField> { + + private int modifiers; + private String type; + private String name; + private String initializer; + + + /** + * Constructs a new <code>JavaField</code>. The <code>modifiers</code> parameter is a bit mask of the + * constants from {@link java.lang.reflect.Modifier}, and the <code>type</code> of the field should be + * represented as it would appear in Java source code. + * + * @param modifiers the modifier keywords that should appear as part of the field's declaration + * @param type the type of the field as it would appear in Java source code + * @param name the field's name + */ + public JavaField(int modifiers, String type, String name) { + this(modifiers, type, name, null); + } + + + /** + * Constructs a new <code>JavaField</code>. The <code>modifiers</code> parameter is a bit mask of the + * constants from <code>java.lang.reflect.Modifier</code>, and the <code>type</code> of the field should be + * represented as it would appear in Java source code. The <code>initializer</code> is the initial + * value of the field as it would appear in Java source code, or <code>null</code> to leave it at the + * default value. + * + * @param modifiers the modifier keywords that should appear as part of the field's declaration + * @param type the type of the field as it would appear in Java source code + * @param name the field's name + * @param initializer the initial value of the field, as it would appear in Java source code + */ + public JavaField(int modifiers, String type, String name, String initializer) { + this.modifiers = modifiers; + this.type = type; + this.name = name; + this.initializer = initializer; + } + + + /** + * Returns a bit mask describing the modifier keywords which should appear as part of this field's + * declaration. See <code>java.lang.reflect.Modifier</code> for more information on decoding this + * field. + * + * @return the modifier bit mask + */ + public int getModifiers() { + return modifiers; + } + + + /** + * Returns the field's name. + * + * @return the field's name + */ + public String getName() { + return name; + } + + + /** + * Returns the field's type, as it would be represented in Java source code. + * + * @return the field's type + */ + public String getType() { + return type; + } + + + /** + * Returns the Java source code for this field. + * + * @param lineSeparator line separator + * @return the Java source code for this field + */ + public String toString(String lineSeparator) { + StringBuffer result = new StringBuffer(); + result.append(JavaFile.getModifiersText(modifiers)); + result.append(type).append(' ').append(name); + if (initializer != null) { + result.append(" = ").append(initializer); + } + result.append(';').append(lineSeparator); + return result.toString(); + } + + public int compareTo(JavaField o) { + return COMPARATOR.compare(this, o); + } + + public static final Comparator<JavaField> COMPARATOR = new Comparator<JavaField>() { + + public int compare(JavaField o1, JavaField o2) { + + int result; + if ((result = compareStatic(o1, o2)) != 0) { + return result; + } + + // data sources must be on the last after all other fields + if ((result = compareDataSource(o1, o2)) != 0) { + return result; + } + + // same static + if ((result = compareVisibility(o1, o2)) != 0) { + return result; + } + // same visibility, test name + return o1.name.compareTo(o2.name); + } + + public int compareStatic(JavaField o1, JavaField o2) { + // first comparator modifiers : static always before none static + if (Modifier.isStatic(o1.modifiers) && !Modifier.isStatic(o2.modifiers)) { + return -1; + } + if (!Modifier.isStatic(o1.modifiers) && Modifier.isStatic(o2.modifiers)) { + return 1; + } + return 0; + } + + public int compareDataSource(JavaField o1, JavaField o2) { + // first comparator modifiers : static always before none static + if (o1.name.startsWith("$DataSource") && !o2.name.startsWith("$DataSource")) { + return 1; + } + if (!o1.name.startsWith("$DataSource") && o2.name.startsWith("$DataSource")) { + return -1; + } + return 0; + } + + public int compareVisibility(JavaField o1, JavaField o2) { + // first comparator modifiers : static always before none static + if (!Modifier.isPublic(o1.modifiers) && Modifier.isPublic(o2.modifiers)) { + return 1; + } + + if (Modifier.isPublic(o1.modifiers) && !Modifier.isPublic(o2.modifiers)) { + return -1; + } + + if (Modifier.isProtected(o1.modifiers) && !Modifier.isProtected(o2.modifiers)) { + return -1; + } + if (!Modifier.isProtected(o1.modifiers) && Modifier.isProtected(o2.modifiers)) { + return 1; + } + + if (Modifier.isPrivate(o1.modifiers) && !Modifier.isPrivate(o2.modifiers)) { + return -1; + } + if (!Modifier.isPrivate(o1.modifiers) && Modifier.isPrivate(o2.modifiers)) { + return 1; + } + return 0; + } + }; + + public static JavaField newField(int modifiers, String returnType, String name) { + return newField(modifiers, returnType, name, null); + } + + public static JavaField newField(int modifiers, String returnType, String name, String initializer) { + return new JavaField(modifiers, returnType, name, initializer); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/compiler/JavaFile.java b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/JavaFile.java new file mode 100644 index 0000000..5dbaaf4 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/JavaFile.java @@ -0,0 +1,344 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.compiler; + +import jaxx.compiler.JavaMethod.MethodOrder; + +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EnumMap; +import java.util.List; +import java.util.Map.Entry; + +/** + * A Java source file being generated for output. Once the class is completely initialized, use the + * {@link #toString} method to generate source code for it. + */ +public class JavaFile { + + protected static final String GETTER_PATTERN = "return %1$s;"; + + protected static final String BOOLEAN_GETTER_PATTERN = "return %1$s !=null && %1$s;"; + + protected static final String SETTER_PATTERN = "%1$s oldValue = this.%2$s;\nthis.%2$s = newValue;\nfirePropertyChange(\"%2$s\", oldValue, newValue);"; + + private int modifiers; + private String className; + private List<String> imports = new ArrayList<String>(); + private List<JavaField> fields = new ArrayList<JavaField>(); + private List<JavaMethod> methods = new ArrayList<JavaMethod>(); + private List<JavaFile> innerClasses = new ArrayList<JavaFile>(); + private String superClass; + private List<String> interfaces; + private StringBuffer rawBodyCode = new StringBuffer(); + private boolean superclassIsJAXXObject; + private boolean abstractClass; + private String genericType; + private String superGenericType; + + + public JavaFile() { + } + + + public JavaFile(int modifiers, String className, String superClass) { + this(modifiers, className, superClass, null); + } + + + public JavaFile(int modifiers, String className, String superClass, List<String> interfaces) { + this.modifiers = modifiers; + this.className = className; + this.superClass = superClass; + this.interfaces = interfaces; + } + + + public void addImport(String importString) { + imports.add(importString); + } + + public void addImport(Class importString) { + imports.add(importString.getName()); + } + + + public String[] getImports() { + return imports.toArray(new String[imports.size()]); + } + + + public int getModifiers() { + return modifiers; + } + + + public void setModifiers(int modifiers) { + this.modifiers = modifiers; + } + + + public String getClassName() { + return className; + } + + + public void setClassName(String className) { + this.className = className; + } + + + public String getSuperClass() { + return superClass; + } + + + public void setSuperClass(String superClass) { + this.superClass = superClass; + } + + + public List<String> getInterfaces() { + if (interfaces == null) { + interfaces = new ArrayList<String>(); + } + return interfaces; + } + + + public void setInterfaces(List<String> interfaces) { + this.interfaces = interfaces; + } + + public void setGenericType(String genericType) { + this.genericType = genericType; + } + + public void addMethod(JavaMethod method) { + methods.add(method); + } + + + public JavaMethod[] getMethods() { + return methods.toArray(new JavaMethod[methods.size()]); + } + + public void addField(JavaField field) { + addField(field, false); + } + + public void addField(JavaField field, boolean javaBean) { + addSimpleField(field); + String id = field.getName(); + String capitalizedName = org.apache.commons.lang.StringUtils.capitalize(id); + // add getter file + String content = String.format(GETTER_PATTERN, id); + addMethod(new JavaMethod( + Modifier.isProtected(field.getModifiers()) ? Modifier.PUBLIC : Modifier.PROTECTED, + field.getType(), "get" + capitalizedName, null, null, content)); + + if (javaBean) { + // add full javabean support + if (Boolean.class.getName().equals(field.getType())) { + content = String.format(BOOLEAN_GETTER_PATTERN, id); + addMethod(new JavaMethod(Modifier.PUBLIC, field.getType(), "is" + capitalizedName, null, null, content)); + } + content = String.format(SETTER_PATTERN, field.getType(), id); + JavaArgument arg = new JavaArgument(field.getType(), "newValue"); + addMethod(new JavaMethod(Modifier.PUBLIC, "void", "set" + capitalizedName, new JavaArgument[]{arg}, null, content)); + } + } + + public void addSimpleField(JavaField field) { + fields.add(field); + } + + + public JavaField[] getFields() { + return fields.toArray(new JavaField[fields.size()]); + } + + + public static String addIndentation(String source, int indentation, String lineSeparator) { + return indent(source, indentation, false, lineSeparator); + } + + + public static String setIndentation(String source, int indentation, String lineSeparator) { + return indent(source, indentation, true, lineSeparator); + } + + + public static String indent(String source, int indentation, boolean trim, String lineSeparator) { + if (trim) { + source = source.trim(); + } + char[] spaces = new char[indentation]; + Arrays.fill(spaces, ' '); + StringBuffer result = new StringBuffer(); + String[] lines = source.split(System.getProperty("line.separator") + "|\n"); + for (int i = 0; i < lines.length; i++) { + if (i > 0) { + result.append(lineSeparator); + } + result.append(spaces); + result.append(trim ? lines[i].trim() : lines[i]); + } + return result.toString(); + } + + + public void addBodyCode(String bodyCode) { + rawBodyCode.append(bodyCode); + } + + + public String getClassBody(String lineSeparator) { + StringBuffer result = new StringBuffer(); + if (fields.size() > 0) { + java.util.Collections.sort(fields); // sort fields + + for (JavaField field : fields) { + result.append(addIndentation(field.toString(lineSeparator), 4, lineSeparator)); + result.append(lineSeparator); + } + + result.append(lineSeparator); + } + + if (rawBodyCode.length() > 0) { + result.append(addIndentation("/* begin raw body code */\n", 4, lineSeparator)); + String s = rawBodyCode.toString(); + if (!s.startsWith(lineSeparator)) { + result.append(lineSeparator); + } + result.append(addIndentation(s, 4, lineSeparator)); + result.append(lineSeparator); + result.append(addIndentation("/* end raw body code */", 4, lineSeparator)); + result.append(lineSeparator); + } + + for (JavaFile innerClass : innerClasses) { + result.append(addIndentation(innerClass.toString(), 4, lineSeparator)); + result.append(lineSeparator).append(lineSeparator); + } + + EnumMap<MethodOrder, List<JavaMethod>> map = JavaMethod.getSortedMethods(methods); + for (Entry<MethodOrder, List<JavaMethod>> entry : map.entrySet()) { + List<JavaMethod> list = entry.getValue(); + entry.getKey().generate(result, list, lineSeparator); + list.clear(); + } + map.clear(); + + return result.toString(); + } + + + public String getClassDefinition(String lineSeparator) { + StringBuffer result = new StringBuffer(); + result.append(getModifiersText(modifiers)); + if (abstractClass) { + result.append("abstract "); + } + result.append("class "); + result.append(className.substring(className.lastIndexOf(".") + 1)); + if (genericType != null) { + result.append('<').append(genericType).append('>'); + } + result.append(" extends "); + result.append(superClass); + if (superGenericType != null) { + result.append('<').append(superGenericType).append('>'); + } + if (interfaces != null && !interfaces.isEmpty()) { + result.append(" implements ").append(interfaces.get(0)); + for (int i = 1; i < interfaces.size(); i++) { + /*if (i > 0) { + result.append(", "); + }*/ + result.append(", ").append(interfaces.get(i)); + } + } + result.append(" {"); + result.append(lineSeparator); + result.append(getClassBody(lineSeparator)); + result.append("}"); + return result.toString(); + } + + + public static String getModifiersText(int modifiers) { + if (modifiers == 0) { + return ""; + } else { + return Modifier.toString(modifiers) + ' '; + } + } + + + /** + * Returns the Java source code for this class. + * + * @param lineSeparator line separator + * @return a complete Java file for this class + */ + public String toString(String lineSeparator) { + StringBuffer result = new StringBuffer(); + if (className.indexOf(".") != -1) { + result.append("package ").append(className.substring(0, className.lastIndexOf("."))).append(";"); + result.append(lineSeparator); + result.append(lineSeparator); + } + + if (imports.size() > 0) { + for (String anImport : imports) { + result.append("import "); + result.append(anImport); + result.append(';'); + result.append(lineSeparator); + } + result.append(lineSeparator); + } + + result.append(getClassDefinition(lineSeparator)); + return result.toString(); + } + + public void addInterface(String canonicalName) { + if (interfaces == null || !interfaces.contains(canonicalName)) { + getInterfaces().add(canonicalName); + } + } + + public void addInterfaces(String[] canonicalNames) { + if (canonicalNames == null) { + return; + } + for (String canonicalName : canonicalNames) { + if (interfaces == null || !interfaces.contains(canonicalName)) { + getInterfaces().add(canonicalName); + } + } + } + + public boolean isSuperclassIsJAXXObject() { + return superclassIsJAXXObject; + } + + public void setSuperclassIsJAXXObject(boolean superclassIsJAXXObject) { + this.superclassIsJAXXObject = superclassIsJAXXObject; + } + + public void setAbstractClass(boolean abstractClass) { + this.abstractClass = abstractClass; + } + + + public void setSuperGenericType(String superGenericType) { + this.superGenericType = superGenericType; + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/compiler/JavaMethod.java b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/JavaMethod.java new file mode 100644 index 0000000..e8a2e5e --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/JavaMethod.java @@ -0,0 +1,499 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.compiler; + +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.Iterator; +import java.util.List; + +/** + * Represents a method in a Java source file being generated for output. <code>JavaMethods</code> are created + * and added to a {@link JavaFile}, which can then output Java source code. In addition to normal methods, a + * <code>JavaMethod</code> can represent a constructor -- constructors should be named after their containing + * classes and have a return type of <code>null</code>. + */ +public class JavaMethod implements Comparable<JavaMethod> { + private int modifiers; + private String returnType; + private String name; + private JavaArgument[] arguments; + private String[] exceptions; + private StringBuffer bodyCode; + + + /** + * Constructs a new no-argument <code>JavaMethod</code> which throws no checked exceptions. The + * <code>modifiers</code> parameter is a bit mask of the constants from {@link java.lang.reflect.Modifier}, + * and the <code>returnType</code> of the method should be represented as it would appear in Java source + * code (<code>null</code> for a constructor). The method body is initially empty. + * + * @param modifiers the modifier keywords that should appear as part of the method's declaration + * @param returnType the return type of the method as it would appear in Java source code + * @param name the method's name + * @see #appendBodyCode + */ + //public JavaMethod(int modifiers, String returnType, String name) { + // this(modifiers, returnType, name, null); + //} + + + /** + * Constructs a new <code>JavaMethod</code> which throws no checked exceptions. The <code>modifiers</code> + * parameter is a bit mask of the constants from {@link java.lang.reflect.Modifier}, and the + * <code>returnType</code> of the method should be represented as it would appear in Java source code + * (<code>null</code> for a constructor). The method body is initially empty. + * + * @param modifiers the modifier keywords that should appear as part of the method's declaration + * @param returnType the return type of the method as it would appear in Java source code + * @param name the method's name + * @param arguments the method's arguments + * @see #appendBodyCode + */ + //public JavaMethod(int modifiers, String returnType, String name, JavaArgument[] arguments) { + // this(modifiers, returnType, name, arguments, null); + //} + + + /** + * Constructs a new <code>JavaMethod</code>. The <code>modifiers</code> parameter is a bit mask of the + * constants from {@link java.lang.reflect.Modifier}, and the <code>returnType</code> and <code>exceptions</code> + * of the method should be represented as they would appear in Java source code (<code>null</code> for a + * constructor). The method body is initially empty. + * + * @param modifiers the modifier keywords that should appear as part of the method's declaration + * @param returnType the return type of the method as it would appear in Java source code + * @param name the method's name + * @param arguments the method's arguments + * @param exceptions a list of exceptions the methods can throw, as they would be represented in Java source code + * @see #appendBodyCode + */ + //public JavaMethod(int modifiers, String returnType, String name, JavaArgument[] arguments, String[] exceptions) { + // this(modifiers, returnType, name, arguments, exceptions, null); + //} + + + /** + * Constructs a new <code>JavaMethod</code> containing the specified body code. The <code>modifiers</code> parameter + * is a bit mask of the constants from {@link java.lang.reflect.Modifier}, and the <code>returnType</code> and + * <code>exceptions</code> of the method should be represented as they would appear in Java source code (<code>null</code> + * for a constructor). The method body is initially empty. + * + * @param modifiers the modifier keywords that should appear as part of the method's declaration + * @param returnType the return type of the method as it would appear in Java source code + * @param name the method's name + * @param arguments the method's arguments + * @param exceptions a list of exceptions the methods can throw, as they would be represented in Java source code + * @param bodyCode Java source code which should appear in the method body + */ + public JavaMethod(int modifiers, String returnType, String name, JavaArgument[] arguments, String[] exceptions, String bodyCode) { + this.modifiers = modifiers; + this.returnType = returnType; + this.name = name; + this.arguments = arguments; + this.exceptions = exceptions; + this.bodyCode = new StringBuffer(bodyCode != null ? bodyCode : ""); + } + + + /** + * Returns a bit mask describing the modifier keywords which should appear as part of this method's + * declaration. See <code>java.lang.reflect.Modifier</code> for more information on decoding this + * field. + * + * @return the modifier bit mask + */ + public int getModifiers() { + return modifiers; + } + + + /** + * Returns the method's return type, as it would be represented in Java source code. + * + * @return the method's return type + */ + public String getReturnType() { + return returnType; + } + + + /** + * Returns the method's name. + * + * @return the method's name + */ + public String getName() { + return name; + } + + + /** + * Returns a list of the method's arguments. + * + * @return the method's arguments + */ + public JavaArgument[] getArguments() { + return arguments; + } + + + /** + * Returns a list of exceptions the method can throw. + * + * @return the method's exceptions + */ + public String[] getExceptions() { + return exceptions; + } + + + /** + * Returns the Java source code for the method's body. + * + * @return the method's body code + */ + public String getBodyCode() { + return bodyCode.toString(); + } + + + /** + * Appends additional code to the method's body. + * + * @param extraCode Java source code to append to the method's body + * @param lineSeparator line separator + */ + public void appendBodyCode(String extraCode, String lineSeparator) { + if (extraCode.length() == 0) { + return; + } + if (bodyCode.length() > 0 && !bodyCode.toString().endsWith(lineSeparator)) { + bodyCode.append(lineSeparator); + } + bodyCode.append(extraCode); + } + + + /** + * Returns the Java source code for this method. + * + * @param lineSeparator line separator + * @return the Java source code for this method + */ + public String toString(String lineSeparator) { + StringBuffer result = new StringBuffer(); + result.append(JavaFile.getModifiersText(modifiers)); + if (returnType != null) { + result.append(returnType); + result.append(' '); + } + result.append(name); + result.append('('); + if (arguments != null) { + for (int i = 0; i < arguments.length; i++) { + if (i > 0) { + result.append(", "); + } + result.append(arguments[i].toString()); + } + } + result.append(") {"); + result.append(lineSeparator); + if (bodyCode != null) { + String formattedBodyCode = JavaFile.addIndentation(bodyCode.toString().trim(), 4, lineSeparator); + if (formattedBodyCode.length() > 0) { + result.append(formattedBodyCode); + result.append(lineSeparator); + } + } + result.append("}"); + return result.toString(); + } + + public int compareTo(JavaMethod o) { + return COMPARATOR.compare(this, o); + } + + public static JavaMethod newMethod(int modifiers, String returnType, String name, String initializer, String[] exceptions, JavaArgument... arguments) { + return new JavaMethod(modifiers, returnType, name, arguments, exceptions, initializer); + } + + public static JavaMethod newMethod(int modifiers, String returnType, String name, String initializer, JavaArgument... arguments) { + return newMethod(modifiers, returnType, name, initializer, new String[0], arguments); + } + + public enum MethodOrder { + + statics(Modifier.STATIC, "/*---------------------------------------------------------------------------------*/\n" + + "/*-- Statics methods --------------------------------------------------------------*/\n" + + "/*---------------------------------------------------------------------------------*/") { + }, + + constructors(Modifier.PUBLIC, "/*---------------------------------------------------------------------------------*/\n" + + "/*-- Constructors -----------------------------------------------------------------*/\n" + + "/*---------------------------------------------------------------------------------*/") { + public boolean accept(JavaMethod method) { + return method.returnType == null; + } + }, + + JAXXObject(Modifier.PUBLIC, "/*---------------------------------------------------------------------------------*/\n" + + "/*-- JAXXObject implementation ----------------------------------------------------*/\n" + + "/*---------------------------------------------------------------------------------*/") { + private List<String> methods = Arrays.asList("applyDataBinding", "firePropertyChange", "getObjectById", "get$objectMap", "processDataBinding", "removeDataBinding"); + + public boolean accept(JavaMethod method) { + return methods.contains(method.name); + } + }, + + JAXXContext(Modifier.PUBLIC, "/*---------------------------------------------------------------------------------*/\n" + + "/*-- JAXXContext implementation ---------------------------------------------------*/\n" + + "/*---------------------------------------------------------------------------------*/") { + private List<String> methods = Arrays.asList("getContextValue", "getDelegateContext", "getParentContainer", "removeContextValue", "setContextValue"); + public boolean accept(JavaMethod method) { + return methods.contains(method.name); + } + }, + + JAXXValidation(Modifier.PUBLIC, "/*---------------------------------------------------------------------------------*/\n" + + "/*-- JAXXValidation implementation ------------------------------------------------*/\n" + + "/*---------------------------------------------------------------------------------*/") { + private List<String> methods = Arrays.asList("getValidator", "getValidatorIds"); + + public boolean accept(JavaMethod method) { + return methods.contains(method.name); + } + }, + + events(Modifier.PUBLIC, "/*---------------------------------------------------------------------------------*/\n" + + "/*-- Event methods ----------------------------------------------------------------*/\n" + + "/*---------------------------------------------------------------------------------*/") { + public boolean accept(JavaMethod method) { + return (method.name.startsWith("do") && method.name.indexOf("__") > -1); + } + }, + + publicGetters(Modifier.PUBLIC, "/*---------------------------------------------------------------------------------*/\n" + + "/*-- public acessor methods -------------------------------------------------------*/\n" + + "/*---------------------------------------------------------------------------------*/") { + public boolean accept(JavaMethod method) { + return (method.name.startsWith("get") || method.name.startsWith("is")); + } + }, + + publicSetters(Modifier.PUBLIC, "/*---------------------------------------------------------------------------------*/\n" + + "/*-- public mutator methods -------------------------------------------------------*/\n" + + "/*---------------------------------------------------------------------------------*/") { + public boolean accept(JavaMethod method) { + return (method.name.startsWith("set")); + } + }, + + otherPublic(Modifier.PUBLIC, "/*---------------------------------------------------------------------------------*/\n" + + "/*-- public mutator methods -------------------------------------------------------*/\n" + + "/*---------------------------------------------------------------------------------*/") { + @Override + public boolean accept(int mod) { + return super.accept(mod) && !Modifier.isStatic(mod); + } + }, + + protectedGetters(Modifier.PROTECTED, "/*---------------------------------------------------------------------------------*/\n" + + "/*-- protected acessors methods ---------------------------------------------------*/\n" + + "/*---------------------------------------------------------------------------------*/") { + public boolean accept(JavaMethod method) { + return (method.name.startsWith("get") || method.name.startsWith("is")); + } + }, + + createMethod(Modifier.PROTECTED | Modifier.PRIVATE, "/*---------------------------------------------------------------------------------*/\n" + + "/*-- ui creation methods ----------------------------------------------------------*/\n" + + "/*---------------------------------------------------------------------------------*/") { + public boolean accept(JavaMethod method) { + return method.name.startsWith("create") || method.name.startsWith("add") || + method.name.equals("$completeSetup") || + method.name.equals("$initialize"); + } + }, + + protecteds(Modifier.PROTECTED, "/*---------------------------------------------------------------------------------*/\n" + + "/*-- Other protected methods ------------------------------------------------------*/\n" + + "/*---------------------------------------------------------------------------------*/") { + }, + + packageLocal(0, "/*---------------------------------------------------------------------------------*/\n" + + "/*-- Package methods --------------------------------------------------------------*/\n" + + "/*---------------------------------------------------------------------------------*/") { + @Override + public boolean accept(int mod) { + return !Modifier.isStatic(mod) && !Modifier.isPublic(mod) && !Modifier.isProtected(mod); + }}, + + privates(Modifier.PRIVATE, "/*---------------------------------------------------------------------------------*/\n" + + "/*-- Private methods --------------------------------------------------------------*/\n" + + "/*---------------------------------------------------------------------------------*/") { + }; + + private final String header; + + private int modifier; + + MethodOrder(int modifier, String header) { + this.header = header; + this.modifier = modifier; + } + + public String getHeader() { + return header; + } + + public boolean accept(JavaMethod method) { + return true; + } + + public boolean accept(int mod) { + return (mod & modifier) != 0; + } + + public boolean accept(int mod, JavaMethod method) { + return accept(mod) && accept(method); + } + + public static MethodOrder valueOf(JavaMethod method, int scope) { + for (MethodOrder o : values()) { + if (o.accept(scope, method)) { + return o; + } + } + throw new IllegalArgumentException("could not find a " + MethodOrder.class + " for method " + method); + } + + public void generate(StringBuffer buffer, List<JavaMethod> methods, String lineSeparator) { + if (methods.isEmpty()) { + return; + } + buffer.append(JavaFile.addIndentation(header, 4, lineSeparator)); + buffer.append(lineSeparator).append(lineSeparator); + for (JavaMethod method : methods) { + buffer.append(JavaFile.addIndentation(method.toString(lineSeparator), 4, lineSeparator)); + buffer.append(lineSeparator).append(lineSeparator); + } + } + } + + public static EnumMap<MethodOrder, List<JavaMethod>> getSortedMethods(List<JavaMethod> methods) { + + EnumMap<MethodOrder, List<JavaMethod>> result = new EnumMap<MethodOrder, List<JavaMethod>>(MethodOrder.class); + for (MethodOrder methodOrder : MethodOrder.values()) { + result.put(methodOrder, new ArrayList<JavaMethod>()); + } + + EnumSet<MethodOrder> allConstants = EnumSet.allOf(MethodOrder.class); + List<JavaMethod> allMethods = new ArrayList<JavaMethod>(methods); + int[] scopes = new int[]{Modifier.STATIC, Modifier.PUBLIC, Modifier.PROTECTED, Modifier.PRIVATE}; + for (int scope : scopes) { + EnumSet<MethodOrder> constants = getMethodOrderScope(allConstants, scope); + + Iterator<JavaMethod> itMethods = allMethods.iterator(); + while (itMethods.hasNext()) { + JavaMethod method = itMethods.next(); + for (MethodOrder constant : constants) { + if (constant.accept(method.getModifiers(), method)) { + result.get(constant).add(method); + itMethods.remove(); + break; + } + } + } + constants.clear(); + } + + if (!allMethods.isEmpty()) { + throw new IllegalArgumentException("could not find a " + MethodOrder.class + " for method " + allMethods); + } + + for (MethodOrder methodOrder : MethodOrder.values()) { + // sort methods + java.util.Collections.sort(result.get(methodOrder)); + } + return result; + } + + public static EnumSet<MethodOrder> getMethodOrderScope(EnumSet<MethodOrder> allConstants, int scope) { + EnumSet<MethodOrder> constants = EnumSet.noneOf(MethodOrder.class); + for (MethodOrder order : allConstants) { + if (order.accept(scope)) { + constants.add(order); + } + } + return constants; + } + + public static final Comparator<JavaMethod> COMPARATOR = new Comparator<JavaMethod>() { + + public int compare(JavaMethod o1, JavaMethod o2) { + + /*int result; + if ((result = compareStatic(o1, o2)) != 0) { + return result; + } + if ((result = compareConstructor(o1, o2)) != 0) { + return result; + } + if ((result = compareVisibility(o1, o2)) != 0) { + return result; + }*/ + return o1.name.compareTo(o2.name); + } + + public int compareStatic(JavaMethod o1, JavaMethod o2) { + if (Modifier.isStatic(o1.modifiers) && !Modifier.isStatic(o2.modifiers)) { + return -1; + } + if (!Modifier.isStatic(o1.modifiers) && Modifier.isStatic(o2.modifiers)) { + return 1; + } + return 0; + } + + public int compareConstructor(JavaMethod o1, JavaMethod o2) { + if (o1.returnType == null && o2.returnType != null) { + return -1; + } + if (o1.returnType != null && o2.returnType == null) { + return 1; + } + return 0; + } + + public int compareVisibility(JavaMethod o1, JavaMethod o2) { + if (Modifier.isPublic(o1.modifiers) && !Modifier.isPublic(o2.modifiers)) { + return -1; + } + if (!Modifier.isPublic(o1.modifiers) && Modifier.isPublic(o2.modifiers)) { + return 1; + } + if (Modifier.isProtected(o1.modifiers) && !Modifier.isProtected(o2.modifiers)) { + return -1; + } + if (!Modifier.isProtected(o1.modifiers) && Modifier.isProtected(o2.modifiers)) { + return 1; + } + if (Modifier.isPrivate(o1.modifiers) && !Modifier.isPrivate(o2.modifiers)) { + return -1; + } + if (!Modifier.isPrivate(o1.modifiers) && Modifier.isPrivate(o2.modifiers)) { + return 1; + } + return 0; + } + }; +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/compiler/ScriptInitializer.java b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/ScriptInitializer.java new file mode 100644 index 0000000..e9d1caf --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/ScriptInitializer.java @@ -0,0 +1,20 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.compiler; + +import jaxx.reflect.ClassDescriptorLoader; + +/** + * A dummy CompiledObject which serves to initialize scripted field. This is handled by + * a CompiledObject rather than (say) simply inlining the initialization code in order to + * ensure that the field is initialized in document order. + */ +public class ScriptInitializer extends CompiledObject { + public ScriptInitializer(String initializer, JAXXCompiler compiler) { + super(compiler.getAutoId(ClassDescriptorLoader.getClassDescriptor(ScriptInitializer.class)), + ClassDescriptorLoader.getClassDescriptor(ScriptInitializer.class), compiler, false); + appendInitializationCode(initializer); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/compiler/ScriptManager.java b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/ScriptManager.java new file mode 100644 index 0000000..fd6a878 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/ScriptManager.java @@ -0,0 +1,336 @@ +package jaxx.compiler; + +import jaxx.CompilerException; +import jaxx.parser.JavaParser; +import jaxx.parser.JavaParserTreeConstants; +import jaxx.parser.SimpleNode; +import jaxx.reflect.FieldDescriptor; +import jaxx.reflect.MethodDescriptor; +import jaxx.tags.TagManager; + +import java.io.StringReader; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class ScriptManager { + private JAXXCompiler compiler; + + + ScriptManager(JAXXCompiler compiler) { + this.compiler = compiler; + } + + + /** + * Strips unnecessary curly braces from around the script, generating a warning if they are found. + * + * @param script script to trim + * @return the trimed script + */ + public String trimScript(String script) { + script = script.trim(); + if (script.startsWith("{") && script.endsWith("}")) { + compiler.reportWarning("curly braces are unnecessary for script '" + script + "'"); + script = script.substring(1, script.length() - 1); + } + return script; + } + + + public void checkParse(String script) throws CompilerException { + script = trimScript(script); + JavaParser p = new JavaParser(new StringReader(script)); + while (!p.Line()) { + // ??? + } + } + + + public String preprocessScript(String script) throws CompilerException { + script = trimScript(script); + StringBuffer result = new StringBuffer(); + JavaParser p = new JavaParser(new StringReader(script)); + //JavaParser p = new JavaParser(new StringReader(script + ";")); + while (!p.Line()) { + SimpleNode node = p.popNode(); + if (node != null) { + preprocessScriptNode(node, false); + result.append(node.getText()); + } + } + return result.toString(); + } + + + /** + * Scans through a compound symbol (foo.bar.baz) to identify and compile the JAXX class it refers to, if any. + * + * @param symbol symbol to scan + */ + private void scanCompoundSymbol(String symbol) { + String[] tokens = symbol.split("\\."); + StringBuffer currentSymbol = new StringBuffer(); + for (String token : tokens) { + if (currentSymbol.length() > 0) + currentSymbol.append('.'); + currentSymbol.append(token.trim()); + + String contextClass = TagManager.resolveClassName(currentSymbol.toString(), compiler); + if (contextClass != null) { + compiler.addDependencyClass(contextClass); + } + } + } + + + private void preprocessScriptNode(SimpleNode node, boolean staticContext) throws CompilerException { + // identify static methods and initializers -- we can't fire events statically + if (node.getId() == JavaParserTreeConstants.JJTMETHODDECLARATION) { + if (node.getParent().getChild(0).getText().indexOf("static") != -1) { + staticContext = true; + } + } else if (node.getId() == JavaParserTreeConstants.JJTINITIALIZER) + if (node.getText().trim().startsWith("static")) { + staticContext = true; + } + + int count = node.jjtGetNumChildren(); + for (int i = 0; i < count; i++) { + preprocessScriptNode(node.getChild(i), staticContext); + } + + int id = node.getId(); + if (id == JavaParserTreeConstants.JJTNAME || id == JavaParserTreeConstants.JJTCLASSORINTERFACETYPE) { + scanCompoundSymbol(node.getText()); + } + if (!staticContext) { + String lhs = null; + if (id == JavaParserTreeConstants.JJTASSIGNMENTEXPRESSION || (id == JavaParserTreeConstants.JJTPOSTFIXEXPRESSION && node.jjtGetNumChildren() == 2)) { + lhs = ((SimpleNode) node.jjtGetChild(0)).getText().trim(); + } + else + if (id == JavaParserTreeConstants.JJTPREINCREMENTEXPRESSION || id == JavaParserTreeConstants.JJTPREDECREMENTEXPRESSION) { + lhs = ((SimpleNode) node.jjtGetChild(0)).getText().trim(); + } + if (lhs != null) { + FieldDescriptor[] fields = compiler.getScriptFields(); + for (FieldDescriptor field : fields) { + if (field.getName().equals(lhs)) { + //lhs.substring(lhs.lastIndexOf(".") + 1); + node.firstToken.image = "jaxx.runtime.Util.assignment(" + node.firstToken.image; + String outputClassName = compiler.getOutputClassName(); + node.lastToken.image = node.lastToken.image + ", \"" + lhs + "\", " + outputClassName + ".this)"; + } + } + } + } + } + + + /** + * Examines a Line to determine its real type. As all tokens returned by the parser are Lines, and + * they are just a tiny wrapper around the real node, this method strips off the wrapper layers to identify + * the real type of a node. + * + * @param line line to scan + * @return the line type + */ + private int getLineType(SimpleNode line) { + if (line.jjtGetNumChildren() == 1) { + SimpleNode node = line.getChild(0); + if (node.getId() == JavaParserTreeConstants.JJTBLOCKSTATEMENT) { + if (node.jjtGetNumChildren() == 1) { + return node.getChild(0).getId(); + } + } else + if (node.getId() == JavaParserTreeConstants.JJTCLASSORINTERFACEBODYDECLARATION) { + int id = node.getChild(0).getId(); + if (id == JavaParserTreeConstants.JJTMODIFIERS) { + return node.getChild(1).getId(); + } + if (id == JavaParserTreeConstants.JJTINITIALIZER) { + return id; + } + } + return node.getId(); + } + return JavaParserTreeConstants.JJTLINE; // generic value implying that it's okay to put into the initializer block + } + + + private SimpleNode findExplicitConstructorInvocation(SimpleNode parent) { + if (parent.getId() == JavaParserTreeConstants.JJTEXPLICITCONSTRUCTORINVOCATION) { + return parent; + } + + int count = parent.jjtGetNumChildren(); + for (int i = 0; i < count; i++) { + SimpleNode result = findExplicitConstructorInvocation(parent.getChild(i)); + if (result != null) { + return result; + } + } + return null; + } + + + private void processConstructor(String modifiers, SimpleNode node) { + assert node.getId() == JavaParserTreeConstants.JJTCONSTRUCTORDECLARATION : "expected node to be ConstructorDeclaration, found " + JavaParserTreeConstants.jjtNodeName[node.getId()] + " instead"; + assert node.getChild(0).getId() == JavaParserTreeConstants.JJTFORMALPARAMETERS : "expected node 0 to be FormalParameters, found " + JavaParserTreeConstants.jjtNodeName[node.getChild(1).getId()] + " instead"; + String code = ""; + if (node.getChild(0).jjtGetNumChildren() == 0) { + compiler.reportError("The default no-argument constructor may not be redefined"); + } + else { + SimpleNode explicitConstructorInvocation = findExplicitConstructorInvocation(node); + if (explicitConstructorInvocation == null || explicitConstructorInvocation.getText().trim().startsWith("super(")) { + code = "$initialize();" + JAXXCompiler.getLineSeparator(); + if (explicitConstructorInvocation == null) { + node.getChild(1).firstToken.image = node.getChild(1).firstToken.image; + } + else { + explicitConstructorInvocation.lastToken.image += code; + } + } + } + + compiler.appendBodyCode(modifiers + " "+ node.getText().substring(0,node.getText().length()-1) + code + "}"); + //compiler.bodyCode.append(";\n"); + } + + + private void scanScriptNode(SimpleNode node) throws CompilerException { + int nodeType = getLineType(node); + if (nodeType == JavaParserTreeConstants.JJTIMPORTDECLARATION) { // have to handle imports early so the preprocessing takes them into account + String text = node.getChild(0).getText().trim(); + if (text.startsWith("import")) { + text = text.substring("import".length()).trim(); + } + if (text.endsWith(";")) { + text = text.substring(0, text.length() - 1); + } + compiler.addImport(text); + } + + preprocessScriptNode(node, false); + + if (nodeType == JavaParserTreeConstants.JJTIMPORTDECLARATION) { + // do nothing, already handled above + } else if (nodeType == JavaParserTreeConstants.JJTMETHODDECLARATION) { + String returnType = null; + String name = null; + List<String> parameterTypes = new ArrayList<String>(); + //List<String> parameterNames = new ArrayList<String>(); + SimpleNode methodDeclaration = node.getChild(0).getChild(1); + assert methodDeclaration.getId() == JavaParserTreeConstants.JJTMETHODDECLARATION; + for (int i = 0; i < methodDeclaration.jjtGetNumChildren(); i++) { + SimpleNode child = methodDeclaration.getChild(i); + int type = child.getId(); + if (type == JavaParserTreeConstants.JJTRESULTTYPE) { + String rawReturnType = child.getText().trim(); + returnType = TagManager.resolveClassName(rawReturnType, compiler); + // FIXME: this check fails for inner classes defined in this file + //if (returnType == null) + // throw new CompilerException("could not find class '" + rawReturnType + "'"); + } else + if (type == JavaParserTreeConstants.JJTMETHODDECLARATOR) { + name = child.firstToken.image.trim(); + SimpleNode formalParameters = child.getChild(0); + assert formalParameters.getId() == JavaParserTreeConstants.JJTFORMALPARAMETERS; + for (int j = 0; j < formalParameters.jjtGetNumChildren(); j++) + { + SimpleNode parameter = formalParameters.getChild(j); + String rawParameterType = parameter.getChild(1).getText().trim().replaceAll("\\.\\.\\.", "[]"); + String parameterType = TagManager.resolveClassName(rawParameterType, compiler); + // FIXME: this check fails for inner classes defined in this file + //if (parameterType == null) + // throw new CompilerException("could not find class '" + rawParameterType + "'"); + parameterTypes.add(parameterType); + //parameterNames.add(parameter.getChild(2).getText().trim()); + } + } + } + compiler.appendBodyCode(node.getText()); + //compiler.bodyCode.append(";\n"); + compiler.addScriptMethod(new MethodDescriptor(name, Modifier.PUBLIC, returnType, parameterTypes.toArray(new String[parameterTypes.size()]), compiler.getClassLoader())); + } else + if (nodeType == JavaParserTreeConstants.JJTCLASSORINTERFACEDECLARATION || + nodeType == JavaParserTreeConstants.JJTINITIALIZER) { + String str = node.getText().trim(); + if (str.endsWith(";")) { + str+=";"; + } + compiler.appendBodyCode(str); + //compiler.bodyCode.append(";\n"); + } else + if (nodeType == JavaParserTreeConstants.JJTCONSTRUCTORDECLARATION) { + processConstructor(node.getChild(0).getChild(0).getText(), node.getChild(0).getChild(1)); + } else + if (nodeType == JavaParserTreeConstants.JJTLOCALVARIABLEDECLARATION || nodeType == JavaParserTreeConstants.JJTFIELDDECLARATION) { + // the "local" variable declarations in this expression aren't actually local -- they are flagged local + // just because there isn't an enclosing class scope visible to the parser. "Real" local variable + // declarations won't show up here, because they will be buried inside of methods. + String text = node.getText().trim(); + if (!text.endsWith(";")) { + text+=";"; + } + String declaration = text; + int equals = text.indexOf("="); + if (equals != -1) { + declaration = declaration.substring(0, equals); + } + declaration = declaration.trim(); + String[] declarationTokens = declaration.split("\\s"); + boolean isFinal = Arrays.asList(declarationTokens).contains("final"); + boolean isStatic = Arrays.asList(declarationTokens).contains("static"); + String name = declarationTokens[declarationTokens.length - 1]; + if (name.endsWith(";")) { + name = name.substring(0, name.length() - 1).trim(); + } + String className = declarationTokens[declarationTokens.length - 2]; + String type = TagManager.resolveClassName(className, compiler); + compiler.addScriptField(new FieldDescriptor(name, Modifier.PUBLIC, type, compiler.getClassLoader())); // TODO: determine the actual modifiers + if (equals != -1 && !isFinal && !isStatic) { // declare the field in the class body, but wait to actually initialize it + //compiler.bodyCode.append(text.substring(0, equals).trim()); + compiler.appendBodyCode(text.substring(0, equals).trim() + ";"); + String initializer = text.substring(equals + 1).trim(); + if (type.endsWith("[]")) { + initializer = "new " + type + " " + initializer; + } + final String finalInitializer = name + " = " + initializer; + compiler.registerInitializer(new Runnable() { + public void run() { + compiler.registerCompiledObject(new ScriptInitializer(finalInitializer, compiler)); + } + }); + } else { + compiler.appendBodyCode(text); + } + compiler.appendBodyCode("\n"); + //compiler.bodyCode.append(";\n"); + } else { + String text = node.getText().trim(); + if (text.length() > 0) { + if (!text.endsWith(";")) { + text += ";"; + } + compiler.appendInitializerCode(text); + //compiler.initializer.append(";\n"); + } + } + } + + + public void registerScript(String script) throws CompilerException { + JavaParser p = new JavaParser(new StringReader(script)); + //JavaParser p = new JavaParser(new StringReader(script + ";")); + while (!p.Line()) { + SimpleNode node = p.popNode(); + if (node != null) { + scanScriptNode(node); + } + } + } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/compiler/SwingCompiler.java b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/SwingCompiler.java new file mode 100644 index 0000000..05e495c --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/SwingCompiler.java @@ -0,0 +1,73 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.compiler; + +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.tags.DefaultObjectHandler; + +import java.io.File; + +/** + * Swing JAXX compiler. + * <p/> + * todo finish javadoc + */ +public class SwingCompiler extends JAXXCompiler { + + /*---------------------------------------------------------------------------------*/ + /*-- Constructor methods ----------------------------------------------------------*/ + /*---------------------------------------------------------------------------------*/ + + public SwingCompiler(ClassLoader classLoader) { + super(classLoader, + new DefaultObjectHandler(ClassDescriptorLoader.getClassDescriptor(Object.class)), + "java.awt.*", + "java.awt.event.*", + "java.beans.*", + "java.io.*", + "java.lang.*", + "java.util.*", + "javax.swing.*", + "javax.swing.border.*", + "javax.swing.event.*", + "jaxx.runtime.swing.JAXXButtonGroup", + "jaxx.runtime.swing.HBox", + "jaxx.runtime.swing.VBox", + "jaxx.runtime.swing.Table", + "static org.nuiton.i18n.I18n._", + "static jaxx.runtime.Util.createImageIcon"); + + + } + + /** + * Creates a new SwingCompiler. + * + * @param baseDir classpath location + * @param options options to pass to javac + * @param src location of file to compile + * @param outputClassName the out file name + */ + public SwingCompiler(File baseDir, File src, String outputClassName, CompilerOptions options) { + super(baseDir, src, outputClassName, options, + new DefaultObjectHandler(ClassDescriptorLoader.getClassDescriptor(Object.class)), + "java.awt.*", + "java.awt.event.*", + "java.beans.*", + "java.io.*", + "java.lang.*", + "java.util.*", + "javax.swing.*", + "javax.swing.border.*", + "javax.swing.event.*", + "jaxx.runtime.swing.JAXXButtonGroup", + "jaxx.runtime.swing.HBox", + "jaxx.runtime.swing.VBox", + "jaxx.runtime.swing.Table", + "static org.nuiton.i18n.I18n._", + "static jaxx.runtime.Util.createImageIcon"); + } + +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/compiler/SwingGenerator.java b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/SwingGenerator.java new file mode 100644 index 0000000..a1235f1 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/SwingGenerator.java @@ -0,0 +1,26 @@ +package jaxx.compiler; + +import jaxx.reflect.ClassDescriptorLoader; + +import java.lang.reflect.Modifier; + +/** @author chemit */ +public class SwingGenerator implements Generator { + @Override + public void finalizeCompiler(CompiledObject root, JAXXCompiler compiler, JavaFile javaFile, String packageName, String className) { + + } + + @Override + public void prepareJavaFile(CompiledObject root, JAXXCompiler compiler, JavaFile javaFile, String packageName, String className) throws ClassNotFoundException { + + //TODO : move this to jaxx-compiler-swing generator + if (ClassDescriptorLoader.getClassDescriptor("jaxx.runtime.swing.Application").isAssignableFrom(root.getObjectClass()) && !compiler.isMainDeclared()) { + // TODO: check for existing main method first + javaFile.addMethod(JavaMethod.newMethod(Modifier.PUBLIC | Modifier.STATIC, "void", "main", + "SwingUtilities.invokeLater(new Runnable() { public void run() { new " + className + "().setVisible(true); } });", + new JavaArgument("String[]", "arg")) + ); + } + } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/compiler/SymbolTable.java b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/SymbolTable.java new file mode 100644 index 0000000..352322c --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/SymbolTable.java @@ -0,0 +1,56 @@ +package jaxx.compiler; + +import jaxx.reflect.FieldDescriptor; +import jaxx.reflect.MethodDescriptor; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** Symbol table constructed during the first pass of compilation. */ +public class SymbolTable { + + private String superclass; + + // maps ID strings to class names -- we can't map directly to CompiledObjects, because we + // can't create those until after the first pass + private Map<String, String> ids = new HashMap<String, String>(); + + private List<FieldDescriptor> scriptFields = new ArrayList<FieldDescriptor>(); + + private List<MethodDescriptor> scriptMethods = new ArrayList<MethodDescriptor>(); + + + /** @return the fully-qualified name of the superclass of the class described by this symbol table. */ + public String getSuperclassName() { + return superclass; + } + + + public void setSuperclassName(String superclass) { + this.superclass = superclass; + } + + + /** + * @return a map of IDs to class names. Each entry in the map corresponds to a class tag with an + * <code>id</code> attribute. The <code>id</code> is the key, and the fully-qualified class name + * of the tag is the value. + */ + public Map<String, String> getClassTagIds() { + return ids; + } + + + /** @return a list of <code>FieldDescriptors</code> for fields defined in <script> tags. */ + public List<FieldDescriptor> getScriptFields() { + return scriptFields; + } + + + /** @return a list of <code>MethodDescriptors</code> for methods defined in <script> tags. */ + public List<MethodDescriptor> getScriptMethods() { + return scriptMethods; + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/compiler/ValidatorGenerator.java b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/ValidatorGenerator.java new file mode 100644 index 0000000..e317805 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/compiler/ValidatorGenerator.java @@ -0,0 +1,89 @@ +package jaxx.compiler; + +import jaxx.compiler.CompiledObject.ChildRef; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.tags.validator.BeanValidatorHandler; +import jaxx.tags.validator.BeanValidatorHandler.CompiledBeanValidator; +import jaxx.types.TypeManager; + +import java.util.List; + +/** @author chemit */ +public class ValidatorGenerator implements Generator { + + protected static final JavaField VALIDATOR_IDS_FIELD = JavaField.newField(java.lang.reflect.Modifier.PROTECTED, + "java.util.List<String>", "validatorIds", "new ArrayList<String>()" + ); + + @Override + public void finalizeCompiler(CompiledObject root, JAXXCompiler compiler, JavaFile javaFile, String packageName, String className) { + + if (!BeanValidatorHandler.hasValidator(compiler)) { + return; + } + + for (CompiledObject object : compiler.getObjects().values()) { + List<ChildRef> childs = object.getChilds(); + if (childs == null || childs.isEmpty()) { + continue; + } + for (ChildRef child : childs) { + String javaCode = child.getChildJavaCode(); + // some validators are defined on this object + boolean found = BeanValidatorHandler.isComponentUsedByValidator(compiler, child.getChild().getId()); + if (found) { + // box the child component in a JxLayer + child.setChildJavaCode(jaxx.runtime.SwingUtil.class.getName()+".boxComponentWithJxLayer(" + javaCode + ")"); + } + } + } + // register validator + for (CompiledBeanValidator validator : BeanValidatorHandler.getValidators(compiler)) { + String id = TypeManager.getJavaCode(validator.getId()); + compiler.appendLateInitializer("validatorIds.add(" + id + ");"); + compiler.appendLateInitializer(JAXXCompiler.getLineSeparator()); + compiler.appendLateInitializer("getValidator(" + id + ").installUIs();"); + compiler.appendLateInitializer(JAXXCompiler.getLineSeparator()); + compiler.appendLateInitializer("getValidator(" + id + ").reloadBean();"); + //compiler.appendLateInitializer("getValidator(" + id + ").validate();"); + compiler.appendLateInitializer(JAXXCompiler.getLineSeparator()); + } + compiler.appendLateInitializer("validatorIds = java.util.Collections.unmodifiableList(validatorIds);"); + compiler.appendLateInitializer(JAXXCompiler.getLineSeparator()); + } + + @Override + public void prepareJavaFile(CompiledObject root, JAXXCompiler compiler, JavaFile javaFile, String packageName, String className) throws ClassNotFoundException { + if (!BeanValidatorHandler.hasValidator(compiler)) { + return; + } + Class<?> validatorClass = compiler.getOptions().getValidatorClass(); + String validatorFQN = validatorClass.getName(); + javaFile.addImport(validatorFQN); + + //TODO use the specific JAXXValidator interface (swing, gwt,...) + Class<?> validatorInterface = jaxx.runtime.JAXXValidator.class; + + if (javaFile.isSuperclassIsJAXXObject()) { + ClassDescriptor superClass = ClassDescriptorLoader.getClassDescriptor(javaFile.getSuperClass()); + boolean parentIsValidator = ClassDescriptorLoader.getClassDescriptor(validatorInterface).isAssignableFrom(superClass); + + if (parentIsValidator) { + // nothing to generate (use the parent directly) + return; + } + } + + // add JAXXValidator interface + javaFile.addInterface(JAXXCompiler.getCanonicalName(validatorInterface)); + + // implements JAXXValidator + javaFile.addField(VALIDATOR_IDS_FIELD); + javaFile.addMethod(JavaMethod.newMethod(java.lang.reflect.Modifier.PUBLIC, validatorFQN + "<?>", "getValidator", + "return (" + validatorFQN + ") (validatorIds.contains(validatorId) ? getObjectById(validatorId) : null);", + new JavaArgument("String", "validatorId") + )); + } + +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/css/CSS.jj b/trunk/jaxx-compiler/src/main/java/jaxx/css/CSS.jj new file mode 100644 index 0000000..fbd133f --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/css/CSS.jj @@ -0,0 +1,587 @@ +/*@bgen(jjtree) Generated By:JJTree: Do not edit this line. .\CSS.jj */ +/*@egen*//* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ + +// I would love to have used an existing CSS parser, but all of the ones I could +// find are licensed under the LGPL. As JAXX is BSD licensed and I'm not a big +// fan of the LGPL, unfortunately that won't work. +options { + STATIC = false; + JDK_VERSION = "1.4"; +} + +PARSER_BEGIN(CSSParser) +package jaxx.css; + +public class CSSParser/*@bgen(jjtree)*/implements CSSParserTreeConstants/*@egen*/ {/*@bgen(jjtree)*/ + protected JJTCSSParserState jjtree = new JJTCSSParserState(); + +/*@egen*/ + public SimpleNode popNode() { + if ( jjtree.nodeArity() > 0) // number of child nodes + return (SimpleNode)jjtree.popNode(); + else + return null; + } + + void jjtreeOpenNodeScope(Node n) { + ((SimpleNode) n).firstToken = getToken(1); + } + + void jjtreeCloseNodeScope(Node n) { + ((SimpleNode) n).lastToken = getToken(0); + } + + public static void main(String args[]) { + System.out.println("Reading from standard input..."); + CSSParser css = new CSSParser(System.in); + try { + SimpleNode n = css.Stylesheet(); + n.dump(""); + System.out.println("Thank you."); + } catch (Exception e) { + System.out.println("Oops."); + System.out.println(e.getMessage()); + e.printStackTrace(); + } + } +} + +PARSER_END(CSSParser) + + +<DEFAULT, IN_RULE> SKIP : +{ + " " +| "\t" +| "\n" +| "\r" +| <"//" (~["\n","\r"])* ("\n"|"\r"|"\r\n")> +| <"/*" (~["*"])* "*" (~["/"] (~["*"])* "*")* "/"> +} + +<*> TOKEN : /* LITERALS */ +{ + <DECIMAL_LITERAL: <INTEGER_LITERAL> ("." <INTEGER_LITERAL>)?> +| + <#INTEGER_LITERAL: (["0"-"9"])+> +} + +<DEFAULT, IN_RULE> TOKEN : /* IDENTIFIER */ +{ + <IDENTIFIER: <LETTER> (<LETTER>|<DIGIT>)*> +| + <#LETTER: ["_", "-", "a"-"z", "A"-"Z"]> +| + <#DIGIT: ["0"-"9"]> +} + +<IN_PSEUDOCLASS> TOKEN : /* PSEUDOCLASS_IDENTIFIER */ +{ + <PSEUDOCLASS_IDENTIFIER: <IDENTIFIER>> : DEFAULT +} + +<DEFAULT> TOKEN: /* COLON */ +{ + <PSEUDOCLASS_COLON: ":"> : IN_PSEUDOCLASS +} + +<IN_RULE> TOKEN: /* COLON_IN_RULE */ +{ + <COLON: ":"> +} + +<*> TOKEN: /* SEMICOLON */ +{ + <SEMICOLON: ";"> +} + +TOKEN : /* LEFT BRACE */ +{ + <LEFT_BRACE: "{"> : IN_RULE +} + +<IN_RULE> TOKEN : /* RIGHT BRACE */ +{ + <RIGHT_BRACE: "}"> : DEFAULT +} + +<IN_RULE> TOKEN : /* JAVA_CODE_RULE START */ +{ + <JAVA_CODE_START: <LEFT_BRACE>> : JAVA_CODE_RULE +} + +<JAVA_CODE_RULE> TOKEN : /* JAVA_CODE_RULE */ +{ + <JAVA_CODE: (~["}"])+ > +} + +<JAVA_CODE_RULE> TOKEN : /* JAVA_CODE_RULE END */ +{ + <JAVA_CODE_END: <RIGHT_BRACE>> : IN_RULE +} + + +<IN_PSEUDOCLASS> TOKEN : /* PROGRAMMATIC_PSEUDOCLASS */ +{ + <PROGRAMMATIC_PSEUDOCLASS: "{" (~["}"])+ "}"> : DEFAULT +} + +<IN_RULE> TOKEN : /* STRINGS */ +{ + <STRING: "\"" (~["\"", "\\", "\n", "\r"])* "\""> +} + +<IN_RULE> TOKEN : /* COLORS */ +{ + <HEXCOLOR: "#" <HEXDIGIT> <HEXDIGIT> <HEXDIGIT> (<HEXDIGIT> <HEXDIGIT> <HEXDIGIT>)?> +| + <#HEXDIGIT: ["0"-"9", "a"-"f", "A"-"F"]> +} + + +<IN_RULE> TOKEN : /* EMS */ +{ + <EMS: <DECIMAL_LITERAL> "em"> +} + + +<IN_RULE> TOKEN : /* EXS */ +{ + <EXS: <DECIMAL_LITERAL> "ex"> +} + + +<IN_RULE> TOKEN : /* LENGTH */ +{ + <LENGTH: <DECIMAL_LITERAL> ("pt" | "mm" | "cm" | "pc" | "in")> +} + + +SimpleNode Stylesheet() : {/*@bgen(jjtree) Stylesheet */ + SimpleNode jjtn000 = new SimpleNode(JJTSTYLESHEET); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) Stylesheet */ + try { +/*@egen*/ + (Rule())*/*@bgen(jjtree)*/ + { + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtreeCloseNodeScope(jjtn000); + } +/*@egen*/ + { return jjtn000; }/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + + +void Rule() : {/*@bgen(jjtree) Rule */ + SimpleNode jjtn000 = new SimpleNode(JJTRULE); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) Rule */ + try { +/*@egen*/ + Selectors() + <LEFT_BRACE> Declaration() (";" (Declaration())?)* <RIGHT_BRACE>/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + + +void Selectors() : {/*@bgen(jjtree) Selectors */ + SimpleNode jjtn000 = new SimpleNode(JJTSELECTORS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) Selectors */ + try { +/*@egen*/ + Selector() ("," Selector())*/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + + +void Selector() : {/*@bgen(jjtree) Selector */ + SimpleNode jjtn000 = new SimpleNode(JJTSELECTOR); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) Selector */ + try { +/*@egen*/ + JavaClass() (Id())? (Class())? (PseudoClass())? +| + Id() (Class())? (PseudoClass())? +| + Class() (PseudoClass())? +| + PseudoClass()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + + +void JavaClass() : {/*@bgen(jjtree) JavaClass */ + SimpleNode jjtn000 = new SimpleNode(JJTJAVACLASS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) JavaClass */ + try { +/*@egen*/ + <IDENTIFIER> | "*"/*@bgen(jjtree)*/ + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + + +void Id() : {/*@bgen(jjtree) Id */ + SimpleNode jjtn000 = new SimpleNode(JJTID); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) Id */ + try { +/*@egen*/ + "#" <IDENTIFIER>/*@bgen(jjtree)*/ + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + + +void Class() : {/*@bgen(jjtree) Class */ + SimpleNode jjtn000 = new SimpleNode(JJTCLASS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) Class */ + try { +/*@egen*/ + "." <IDENTIFIER>/*@bgen(jjtree)*/ + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + + +void PseudoClass() : {/*@bgen(jjtree) PseudoClass */ + SimpleNode jjtn000 = new SimpleNode(JJTPSEUDOCLASS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) PseudoClass */ + try { +/*@egen*/ + <PSEUDOCLASS_COLON> (<PSEUDOCLASS_IDENTIFIER> | <PROGRAMMATIC_PSEUDOCLASS>) (AnimationProperties())?/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + + +void AnimationProperties() : {/*@bgen(jjtree) AnimationProperties */ + SimpleNode jjtn000 = new SimpleNode(JJTANIMATIONPROPERTIES); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) AnimationProperties */ + try { +/*@egen*/ + "[" AnimationProperty() ("," AnimationProperty())* "]"/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + + +void AnimationProperty() : {/*@bgen(jjtree) AnimationProperty */ + SimpleNode jjtn000 = new SimpleNode(JJTANIMATIONPROPERTY); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) AnimationProperty */ + try { +/*@egen*/ + <IDENTIFIER> "=" <DECIMAL_LITERAL> (<IDENTIFIER>)?/*@bgen(jjtree)*/ + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + + +void Declaration() : {/*@bgen(jjtree) Declaration */ + SimpleNode jjtn000 = new SimpleNode(JJTDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) Declaration */ + try { +/*@egen*/ + Property() <COLON> Expression()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + + +void Property() : {/*@bgen(jjtree) Property */ + SimpleNode jjtn000 = new SimpleNode(JJTPROPERTY); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) Property */ + try { +/*@egen*/ + <IDENTIFIER>/*@bgen(jjtree)*/ + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + + +void Expression() : {/*@bgen(jjtree) Expression */ + SimpleNode jjtn000 = new SimpleNode(JJTEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) Expression */ + try { +/*@egen*/ + (<DECIMAL_LITERAL> | <STRING> | <IDENTIFIER> | <HEXCOLOR> | <EMS> | <EXS> | <LENGTH> | + JavaCode())/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + + +void JavaCode() : {/*@bgen(jjtree) JavaCode */ + SimpleNode jjtn000 = new SimpleNode(JJTJAVACODE); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) JavaCode */ + try { +/*@egen*/ + <JAVA_CODE_START> <JAVA_CODE> <JAVA_CODE_END>/*@bgen(jjtree)*/ + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + + +void Identifier() : {/*@bgen(jjtree) Identifier */ + SimpleNode jjtn000 = new SimpleNode(JJTIDENTIFIER); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) Identifier */ + try { +/*@egen*/ + <IDENTIFIER>/*@bgen(jjtree)*/ + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/css/CSS.jjt b/trunk/jaxx-compiler/src/main/java/jaxx/css/CSS.jjt new file mode 100644 index 0000000..80cc349 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/css/CSS.jjt @@ -0,0 +1,256 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ + +// I would love to have used an existing CSS parser, but all of the ones I could +// find are licensed under the LGPL. As JAXX is BSD licensed and I'm not a big +// fan of the LGPL, unfortunately that won't work. +options { + STATIC = false; + JDK_VERSION = "1.4"; + NODE_SCOPE_HOOK = true; +} + +PARSER_BEGIN(CSSParser) +package jaxx.css; + +public class CSSParser { + public SimpleNode popNode() { + if ( jjtree.nodeArity() > 0) // number of child nodes + return (SimpleNode)jjtree.popNode(); + else + return null; + } + + void jjtreeOpenNodeScope(Node n) { + ((SimpleNode) n).firstToken = getToken(1); + } + + void jjtreeCloseNodeScope(Node n) { + ((SimpleNode) n).lastToken = getToken(0); + } + + public static void main(String args[]) { + System.out.println("Reading from standard input..."); + CSSParser css = new CSSParser(System.in); + try { + SimpleNode n = css.Stylesheet(); + n.dump(""); + System.out.println("Thank you."); + } catch (Exception e) { + System.out.println("Oops."); + System.out.println(e.getMessage()); + e.printStackTrace(); + } + } +} + +PARSER_END(CSSParser) + + +<DEFAULT, IN_RULE> SKIP : +{ + " " +| "\t" +| "\n" +| "\r" +| <"//" (~["\n","\r"])* ("\n"|"\r"|"\r\n")> +| <"/*" (~["*"])* "*" (~["/"] (~["*"])* "*")* "/"> +} + +<*> TOKEN : /* LITERALS */ +{ + <DECIMAL_LITERAL: <INTEGER_LITERAL> ("." <INTEGER_LITERAL>)?> +| + <#INTEGER_LITERAL: (["0"-"9"])+> +} + +<DEFAULT, IN_RULE> TOKEN : /* IDENTIFIER */ +{ + <IDENTIFIER: <LETTER> (<LETTER>|<DIGIT>)*> +| + <#LETTER: ["_", "-", "a"-"z", "A"-"Z"]> +| + <#DIGIT: ["0"-"9"]> +} + +<IN_PSEUDOCLASS> TOKEN : /* PSEUDOCLASS_IDENTIFIER */ +{ + <PSEUDOCLASS_IDENTIFIER: <IDENTIFIER>> : DEFAULT +} + +<DEFAULT> TOKEN: /* COLON */ +{ + <PSEUDOCLASS_COLON: ":"> : IN_PSEUDOCLASS +} + +<IN_RULE> TOKEN: /* COLON_IN_RULE */ +{ + <COLON: ":"> +} + +<*> TOKEN: /* SEMICOLON */ +{ + <SEMICOLON: ";"> +} + +TOKEN : /* LEFT BRACE */ +{ + <LEFT_BRACE: "{"> : IN_RULE +} + +<IN_RULE> TOKEN : /* RIGHT BRACE */ +{ + <RIGHT_BRACE: "}"> : DEFAULT +} + +<IN_RULE> TOKEN : /* JAVA_CODE_RULE START */ +{ + <JAVA_CODE_START: <LEFT_BRACE>> : JAVA_CODE_RULE +} + +<JAVA_CODE_RULE> TOKEN : /* JAVA_CODE_RULE */ +{ + <JAVA_CODE: (~["}"])+ > +} + +<JAVA_CODE_RULE> TOKEN : /* JAVA_CODE_RULE END */ +{ + <JAVA_CODE_END: <RIGHT_BRACE>> : IN_RULE +} + + +<IN_PSEUDOCLASS> TOKEN : /* PROGRAMMATIC_PSEUDOCLASS */ +{ + <PROGRAMMATIC_PSEUDOCLASS: "{" (~["}"])+ "}"> : DEFAULT +} + +<IN_RULE> TOKEN : /* STRINGS */ +{ + <STRING: "\"" (~["\"", "\\", "\n", "\r"])* "\""> +} + +<IN_RULE> TOKEN : /* COLORS */ +{ + <HEXCOLOR: "#" <HEXDIGIT> <HEXDIGIT> <HEXDIGIT> (<HEXDIGIT> <HEXDIGIT> <HEXDIGIT>)?> +| + <#HEXDIGIT: ["0"-"9", "a"-"f", "A"-"F"]> +} + + +<IN_RULE> TOKEN : /* EMS */ +{ + <EMS: <DECIMAL_LITERAL> "em"> +} + + +<IN_RULE> TOKEN : /* EXS */ +{ + <EXS: <DECIMAL_LITERAL> "ex"> +} + + +<IN_RULE> TOKEN : /* LENGTH */ +{ + <LENGTH: <DECIMAL_LITERAL> ("pt" | "mm" | "cm" | "pc" | "in")> +} + + +SimpleNode Stylesheet() : {} +{ + (Rule())* + { return jjtThis; } +} + + +void Rule() : {} +{ + Selectors() + <LEFT_BRACE> Declaration() (";" (Declaration())?)* <RIGHT_BRACE> +} + + +void Selectors() : {} +{ + Selector() ("," Selector())* +} + + +void Selector() : {} +{ + JavaClass() (Id())? (Class())? (PseudoClass())? +| + Id() (Class())? (PseudoClass())? +| + Class() (PseudoClass())? +| + PseudoClass() +} + + +void JavaClass() : {} +{ + <IDENTIFIER> | "*" +} + + +void Id() : {} +{ + "#" <IDENTIFIER> +} + + +void Class() : {} +{ + "." <IDENTIFIER> +} + + +void PseudoClass() : {} +{ + <PSEUDOCLASS_COLON> (<PSEUDOCLASS_IDENTIFIER> | <PROGRAMMATIC_PSEUDOCLASS>) (AnimationProperties())? +} + + +void AnimationProperties() : {} +{ + "[" AnimationProperty() ("," AnimationProperty())* "]" +} + + +void AnimationProperty() : {} +{ + <IDENTIFIER> "=" <DECIMAL_LITERAL> (<IDENTIFIER>)? +} + + +void Declaration() : {} +{ + Property() <COLON> Expression() +} + + +void Property() : {} +{ + <IDENTIFIER> +} + + +void Expression() : {} +{ + (<DECIMAL_LITERAL> | <STRING> | <IDENTIFIER> | <HEXCOLOR> | <EMS> | <EXS> | <LENGTH> | + JavaCode()) +} + + +void JavaCode() : {} +{ + <JAVA_CODE_START> <JAVA_CODE> <JAVA_CODE_END> +} + + +void Identifier() : {} +{ + <IDENTIFIER> +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/css/CSSParser.java b/trunk/jaxx-compiler/src/main/java/jaxx/css/CSSParser.java new file mode 100644 index 0000000..ca71bfa --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/css/CSSParser.java @@ -0,0 +1,799 @@ +/* Generated By:JJTree&JavaCC: Do not edit this line. CSSParser.java */ +package jaxx.css; + +public class CSSParser/*@bgen(jjtree)*/ implements CSSParserTreeConstants, CSSParserConstants {/*@bgen(jjtree)*/ + protected JJTCSSParserState jjtree = new JJTCSSParserState(); + + public SimpleNode popNode() { + if (jjtree.nodeArity() > 0) // number of child nodes + return (SimpleNode) jjtree.popNode(); + else + return null; + } + + void jjtreeOpenNodeScope(Node n) { + ((SimpleNode) n).firstToken = getToken(1); + } + + void jjtreeCloseNodeScope(Node n) { + ((SimpleNode) n).lastToken = getToken(0); + } + + public static void main(String args[]) { + System.out.println("Reading from standard input..."); + CSSParser css = new CSSParser(System.in); + try { + SimpleNode n = css.Stylesheet(); + n.dump(""); + System.out.println("Thank you."); + } catch (Exception e) { + System.out.println("Oops."); + System.out.println(e.getMessage()); + e.printStackTrace(); + } + } + + final public SimpleNode Stylesheet() throws ParseException { + /*@bgen(jjtree) Stylesheet */ + SimpleNode jjtn000 = new SimpleNode(JJTSTYLESHEET); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + label_1: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case IDENTIFIER: + case PSEUDOCLASS_COLON: + case 29: + case 30: + case 31: + ; + break; + default: + jj_la1[0] = jj_gen; + break label_1; + } + Rule(); + } + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtreeCloseNodeScope(jjtn000); + { + if (true) return jjtn000; + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + throw new Error("Missing return statement in function"); + } + + final public void Rule() throws ParseException { + /*@bgen(jjtree) Rule */ + SimpleNode jjtn000 = new SimpleNode(JJTRULE); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + Selectors(); + jj_consume_token(LEFT_BRACE); + Declaration(); + label_2: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case SEMICOLON: + ; + break; + default: + jj_la1[1] = jj_gen; + break label_2; + } + jj_consume_token(SEMICOLON); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case IDENTIFIER: + Declaration(); + break; + default: + jj_la1[2] = jj_gen; + ; + } + } + jj_consume_token(RIGHT_BRACE); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void Selectors() throws ParseException { + /*@bgen(jjtree) Selectors */ + SimpleNode jjtn000 = new SimpleNode(JJTSELECTORS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + Selector(); + label_3: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case 28: + ; + break; + default: + jj_la1[3] = jj_gen; + break label_3; + } + jj_consume_token(28); + Selector(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void Selector() throws ParseException { + /*@bgen(jjtree) Selector */ + SimpleNode jjtn000 = new SimpleNode(JJTSELECTOR); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case IDENTIFIER: + case 29: + JavaClass(); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case 30: + Id(); + break; + default: + jj_la1[4] = jj_gen; + ; + } + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case 31: + Class(); + break; + default: + jj_la1[5] = jj_gen; + ; + } + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case PSEUDOCLASS_COLON: + PseudoClass(); + break; + default: + jj_la1[6] = jj_gen; + ; + } + break; + case 30: + Id(); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case 31: + Class(); + break; + default: + jj_la1[7] = jj_gen; + ; + } + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case PSEUDOCLASS_COLON: + PseudoClass(); + break; + default: + jj_la1[8] = jj_gen; + ; + } + break; + case 31: + Class(); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case PSEUDOCLASS_COLON: + PseudoClass(); + break; + default: + jj_la1[9] = jj_gen; + ; + } + break; + case PSEUDOCLASS_COLON: + PseudoClass(); + break; + default: + jj_la1[10] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void JavaClass() throws ParseException { + /*@bgen(jjtree) JavaClass */ + SimpleNode jjtn000 = new SimpleNode(JJTJAVACLASS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case IDENTIFIER: + jj_consume_token(IDENTIFIER); + break; + case 29: + jj_consume_token(29); + break; + default: + jj_la1[11] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void Id() throws ParseException { + /*@bgen(jjtree) Id */ + SimpleNode jjtn000 = new SimpleNode(JJTID); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(30); + jj_consume_token(IDENTIFIER); + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void Class() throws ParseException { + /*@bgen(jjtree) Class */ + SimpleNode jjtn000 = new SimpleNode(JJTCLASS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(31); + jj_consume_token(IDENTIFIER); + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void PseudoClass() throws ParseException { + /*@bgen(jjtree) PseudoClass */ + SimpleNode jjtn000 = new SimpleNode(JJTPSEUDOCLASS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(PSEUDOCLASS_COLON); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case PSEUDOCLASS_IDENTIFIER: + jj_consume_token(PSEUDOCLASS_IDENTIFIER); + break; + case PROGRAMMATIC_PSEUDOCLASS: + jj_consume_token(PROGRAMMATIC_PSEUDOCLASS); + break; + default: + jj_la1[12] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case 32: + AnimationProperties(); + break; + default: + jj_la1[13] = jj_gen; + ; + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void AnimationProperties() throws ParseException { + /*@bgen(jjtree) AnimationProperties */ + SimpleNode jjtn000 = new SimpleNode(JJTANIMATIONPROPERTIES); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(32); + AnimationProperty(); + label_4: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case 28: + ; + break; + default: + jj_la1[14] = jj_gen; + break label_4; + } + jj_consume_token(28); + AnimationProperty(); + } + jj_consume_token(33); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void AnimationProperty() throws ParseException { + /*@bgen(jjtree) AnimationProperty */ + SimpleNode jjtn000 = new SimpleNode(JJTANIMATIONPROPERTY); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(IDENTIFIER); + jj_consume_token(34); + jj_consume_token(DECIMAL_LITERAL); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case IDENTIFIER: + jj_consume_token(IDENTIFIER); + break; + default: + jj_la1[15] = jj_gen; + ; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void Declaration() throws ParseException { + /*@bgen(jjtree) Declaration */ + SimpleNode jjtn000 = new SimpleNode(JJTDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + Property(); + jj_consume_token(COLON); + Expression(); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void Property() throws ParseException { + /*@bgen(jjtree) Property */ + SimpleNode jjtn000 = new SimpleNode(JJTPROPERTY); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(IDENTIFIER); + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void Expression() throws ParseException { + /*@bgen(jjtree) Expression */ + SimpleNode jjtn000 = new SimpleNode(JJTEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case DECIMAL_LITERAL: + jj_consume_token(DECIMAL_LITERAL); + break; + case STRING: + jj_consume_token(STRING); + break; + case IDENTIFIER: + jj_consume_token(IDENTIFIER); + break; + case HEXCOLOR: + jj_consume_token(HEXCOLOR); + break; + case EMS: + jj_consume_token(EMS); + break; + case EXS: + jj_consume_token(EXS); + break; + case LENGTH: + jj_consume_token(LENGTH); + break; + case JAVA_CODE_START: + JavaCode(); + break; + default: + jj_la1[16] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void JavaCode() throws ParseException { + /*@bgen(jjtree) JavaCode */ + SimpleNode jjtn000 = new SimpleNode(JJTJAVACODE); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(JAVA_CODE_START); + jj_consume_token(JAVA_CODE); + jj_consume_token(JAVA_CODE_END); + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void Identifier() throws ParseException { + /*@bgen(jjtree) Identifier */ + SimpleNode jjtn000 = new SimpleNode(JJTIDENTIFIER); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(IDENTIFIER); + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + public CSSParserTokenManager token_source; + SimpleCharStream jj_input_stream; + public Token token, jj_nt; + private int jj_ntk; + private int jj_gen; + final private int[] jj_la1 = new int[17]; + static private int[] jj_la1_0; + static private int[] jj_la1_1; + + static { + jj_la1_0(); + jj_la1_1(); + } + + private static void jj_la1_0() { + jj_la1_0 = new int[]{0xe0002200, 0x8000, 0x200, 0x10000000, 0x40000000, 0x80000000, 0x2000, 0x80000000, 0x2000, 0x2000, 0xe0002200, 0x20000200, 0x201000, 0x0, 0x10000000, 0x200, 0xec40280,}; + } + + private static void jj_la1_1() { + jj_la1_1 = new int[]{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,}; + } + + public CSSParser(java.io.InputStream stream) { + this(stream, null); + } + + public CSSParser(java.io.InputStream stream, String encoding) { + try { + jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); + } catch (java.io.UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + token_source = new CSSParserTokenManager(jj_input_stream); + token = new Token(); + jj_ntk = -1; + jj_gen = 0; + for (int i = 0; i < 17; i++) jj_la1[i] = -1; + } + + public void ReInit(java.io.InputStream stream) { + ReInit(stream, null); + } + + public void ReInit(java.io.InputStream stream, String encoding) { + try { + jj_input_stream.ReInit(stream, encoding, 1, 1); + } catch (java.io.UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + token_source.ReInit(jj_input_stream); + token = new Token(); + jj_ntk = -1; + jjtree.reset(); + jj_gen = 0; + for (int i = 0; i < 17; i++) jj_la1[i] = -1; + } + + public CSSParser(java.io.Reader stream) { + jj_input_stream = new SimpleCharStream(stream, 1, 1); + token_source = new CSSParserTokenManager(jj_input_stream); + token = new Token(); + jj_ntk = -1; + jj_gen = 0; + for (int i = 0; i < 17; i++) jj_la1[i] = -1; + } + + public void ReInit(java.io.Reader stream) { + jj_input_stream.ReInit(stream, 1, 1); + token_source.ReInit(jj_input_stream); + token = new Token(); + jj_ntk = -1; + jjtree.reset(); + jj_gen = 0; + for (int i = 0; i < 17; i++) jj_la1[i] = -1; + } + + public CSSParser(CSSParserTokenManager tm) { + token_source = tm; + token = new Token(); + jj_ntk = -1; + jj_gen = 0; + for (int i = 0; i < 17; i++) jj_la1[i] = -1; + } + + public void ReInit(CSSParserTokenManager tm) { + token_source = tm; + token = new Token(); + jj_ntk = -1; + jjtree.reset(); + jj_gen = 0; + for (int i = 0; i < 17; i++) jj_la1[i] = -1; + } + + final private Token jj_consume_token(int kind) throws ParseException { + Token oldToken; + if ((oldToken = token).next != null) token = token.next; + else token = token.next = token_source.getNextToken(); + jj_ntk = -1; + if (token.kind == kind) { + jj_gen++; + return token; + } + token = oldToken; + jj_kind = kind; + throw generateParseException(); + } + + final public Token getNextToken() { + if (token.next != null) token = token.next; + else token = token.next = token_source.getNextToken(); + jj_ntk = -1; + jj_gen++; + return token; + } + + final public Token getToken(int index) { + Token t = token; + for (int i = 0; i < index; i++) { + if (t.next != null) t = t.next; + else t = t.next = token_source.getNextToken(); + } + return t; + } + + final private int jj_ntk() { + if ((jj_nt = token.next) == null) + return (jj_ntk = (token.next = token_source.getNextToken()).kind); + else + return (jj_ntk = jj_nt.kind); + } + + private java.util.Vector jj_expentries = new java.util.Vector(); + private int[] jj_expentry; + private int jj_kind = -1; + + public ParseException generateParseException() { + Token errortok = token.next; + int line = errortok.beginLine, column = errortok.beginColumn; + String mess = (errortok.kind == 0) ? tokenImage[0] : errortok.image; + return new ParseException("Parse error. Encountered: " + mess, line, column); + } + + final public void enable_tracing() { + } + + final public void disable_tracing() { + } + +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/css/CSSParserConstants.java b/trunk/jaxx-compiler/src/main/java/jaxx/css/CSSParserConstants.java new file mode 100644 index 0000000..bade092 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/css/CSSParserConstants.java @@ -0,0 +1,72 @@ +/* Generated By:JJTree&JavaCC: Do not edit this line. CSSParserConstants.java */ +package jaxx.css; + +public interface CSSParserConstants { + + int EOF = 0; + int DECIMAL_LITERAL = 7; + int INTEGER_LITERAL = 8; + int IDENTIFIER = 9; + int LETTER = 10; + int DIGIT = 11; + int PSEUDOCLASS_IDENTIFIER = 12; + int PSEUDOCLASS_COLON = 13; + int COLON = 14; + int SEMICOLON = 15; + int LEFT_BRACE = 16; + int RIGHT_BRACE = 17; + int JAVA_CODE_START = 18; + int JAVA_CODE = 19; + int JAVA_CODE_END = 20; + int PROGRAMMATIC_PSEUDOCLASS = 21; + int STRING = 22; + int HEXCOLOR = 23; + int HEXDIGIT = 24; + int EMS = 25; + int EXS = 26; + int LENGTH = 27; + + int DEFAULT = 0; + int IN_RULE = 1; + int JAVA_CODE_RULE = 2; + int IN_PSEUDOCLASS = 3; + + String[] tokenImage = { + "<EOF>", + "\" \"", + "\"\\t\"", + "\"\\n\"", + "\"\\r\"", + "<token of kind 5>", + "<token of kind 6>", + "<DECIMAL_LITERAL>", + "<INTEGER_LITERAL>", + "<IDENTIFIER>", + "<LETTER>", + "<DIGIT>", + "<PSEUDOCLASS_IDENTIFIER>", + "\":\"", + "\":\"", + "\";\"", + "\"{\"", + "\"}\"", + "<JAVA_CODE_START>", + "<JAVA_CODE>", + "<JAVA_CODE_END>", + "<PROGRAMMATIC_PSEUDOCLASS>", + "<STRING>", + "<HEXCOLOR>", + "<HEXDIGIT>", + "<EMS>", + "<EXS>", + "<LENGTH>", + "\",\"", + "\"*\"", + "\"#\"", + "\".\"", + "\"[\"", + "\"]\"", + "\"=\"", + }; + +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/css/CSSParserTokenManager.java b/trunk/jaxx-compiler/src/main/java/jaxx/css/CSSParserTokenManager.java new file mode 100644 index 0000000..3d4a0d7 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/css/CSSParserTokenManager.java @@ -0,0 +1,1152 @@ +/* Generated By:JJTree&JavaCC: Do not edit this line. CSSParserTokenManager.java */ +package jaxx.css; + +public class CSSParserTokenManager implements CSSParserConstants { + public java.io.PrintStream debugStream = System.out; + + public void setDebugStream(java.io.PrintStream ds) { + debugStream = ds; + } + + private int jjStopStringLiteralDfa_0(int pos, long active0) { + switch (pos) { + default: + return -1; + } + } + + private int jjStartNfa_0(int pos, long active0) { + return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1); + } + + private int jjStopAtPos(int pos, int kind) { + jjmatchedKind = kind; + jjmatchedPos = pos; + return pos + 1; + } + + private int jjStartNfaWithStates_0(int pos, int kind, int state) { + jjmatchedKind = kind; + jjmatchedPos = pos; + try { + curChar = input_stream.readChar(); + } + catch (java.io.IOException e) { + return pos + 1; + } + return jjMoveNfa_0(state, pos + 1); + } + + private int jjMoveStringLiteralDfa0_0() { + switch (curChar) { + case 35: + return jjStopAtPos(0, 30); + case 42: + return jjStopAtPos(0, 29); + case 44: + return jjStopAtPos(0, 28); + case 46: + return jjStopAtPos(0, 31); + case 58: + return jjStopAtPos(0, 13); + case 59: + return jjStopAtPos(0, 15); + case 61: + return jjStopAtPos(0, 34); + case 91: + return jjStopAtPos(0, 32); + case 93: + return jjStopAtPos(0, 33); + case 123: + return jjStopAtPos(0, 16); + default: + return jjMoveNfa_0(3, 0); + } + } + + private void jjCheckNAdd(int state) { + if (jjrounds[state] != jjround) { + jjstateSet[jjnewStateCnt++] = state; + jjrounds[state] = jjround; + } + } + + private void jjAddStates(int start, int end) { + do { + jjstateSet[jjnewStateCnt++] = jjnextStates[start]; + } while (start++ != end); + } + + private void jjCheckNAddTwoStates(int state1, int state2) { + jjCheckNAdd(state1); + jjCheckNAdd(state2); + } + + private void jjCheckNAddStates(int start, int end) { + do { + jjCheckNAdd(jjnextStates[start]); + } while (start++ != end); + } + + private void jjCheckNAddStates(int start) { + jjCheckNAdd(jjnextStates[start]); + jjCheckNAdd(jjnextStates[start + 1]); + } + + static final long[] jjbitVec0 = { + 0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL + }; + + private int jjMoveNfa_0(int startState, int curPos) { + int[] nextStates; + int startsAt = 0; + jjnewStateCnt = 17; + int i = 1; + jjstateSet[0] = startState; + int j, kind = 0x7fffffff; + for (; ;) { + if (++jjround == 0x7fffffff) + ReInitRounds(); + if (curChar < 64) { + long l = 1L << curChar; + MatchLoop: + do { + switch (jjstateSet[--i]) { + case 3: + if ((0x3ff000000000000L & l) != 0L) { + if (kind > 7) + kind = 7; + jjCheckNAddTwoStates(0, 1); + } else if (curChar == 47) + jjAddStates(0, 1); + else if (curChar == 45) { + if (kind > 9) + kind = 9; + jjCheckNAdd(4); + } + break; + case 0: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 7) + kind = 7; + jjCheckNAddTwoStates(0, 1); + break; + case 1: + if (curChar == 46) + jjCheckNAdd(2); + break; + case 2: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 7) + kind = 7; + jjCheckNAdd(2); + break; + case 4: + if ((0x3ff200000000000L & l) == 0L) + break; + if (kind > 9) + kind = 9; + jjCheckNAdd(4); + break; + case 5: + if (curChar == 47) + jjAddStates(0, 1); + break; + case 6: + if (curChar == 47) + jjCheckNAddStates(2, 4); + break; + case 7: + if ((0xffffffffffffdbffL & l) != 0L) + jjCheckNAddStates(2, 4); + break; + case 8: + if ((0x2400L & l) != 0L && kind > 5) + kind = 5; + break; + case 9: + if (curChar == 10 && kind > 5) + kind = 5; + break; + case 10: + if (curChar == 13) + jjstateSet[jjnewStateCnt++] = 9; + break; + case 11: + if (curChar == 42) + jjCheckNAddTwoStates(12, 13); + break; + case 12: + if ((0xfffffbffffffffffL & l) != 0L) + jjCheckNAddTwoStates(12, 13); + break; + case 13: + if (curChar == 42) + jjAddStates(5, 6); + break; + case 14: + if ((0xffff7fffffffffffL & l) != 0L) + jjCheckNAddTwoStates(15, 13); + break; + case 15: + if ((0xfffffbffffffffffL & l) != 0L) + jjCheckNAddTwoStates(15, 13); + break; + case 16: + if (curChar == 47 && kind > 6) + kind = 6; + break; + default: + break; + } + } while (i != startsAt); + } else if (curChar < 128) { + long l = 1L << (curChar & 077); + MatchLoop: + do { + switch (jjstateSet[--i]) { + case 3: + case 4: + if ((0x7fffffe87fffffeL & l) == 0L) + break; + if (kind > 9) + kind = 9; + jjCheckNAdd(4); + break; + case 7: + jjAddStates(2, 4); + break; + case 12: + jjCheckNAddTwoStates(12, 13); + break; + case 14: + case 15: + jjCheckNAddTwoStates(15, 13); + break; + default: + break; + } + } while (i != startsAt); + } else { + int i2 = (curChar & 0xff) >> 6; + long l2 = 1L << (curChar & 077); + MatchLoop: + do { + switch (jjstateSet[--i]) { + case 7: + if ((jjbitVec0[i2] & l2) != 0L) + jjAddStates(2, 4); + break; + case 12: + if ((jjbitVec0[i2] & l2) != 0L) + jjCheckNAddTwoStates(12, 13); + break; + case 14: + case 15: + if ((jjbitVec0[i2] & l2) != 0L) + jjCheckNAddTwoStates(15, 13); + break; + default: + break; + } + } while (i != startsAt); + } + if (kind != 0x7fffffff) { + jjmatchedKind = kind; + jjmatchedPos = curPos; + kind = 0x7fffffff; + } + ++curPos; + if ((i = jjnewStateCnt) == (startsAt = 17 - (jjnewStateCnt = startsAt))) + return curPos; + try { + curChar = input_stream.readChar(); + } + catch (java.io.IOException e) { + return curPos; + } + } + } + + private int jjStopStringLiteralDfa_3(int pos, long active0) { + switch (pos) { + default: + return -1; + } + } + + private int jjStartNfa_3(int pos, long active0) { + return jjMoveNfa_3(jjStopStringLiteralDfa_3(pos, active0), pos + 1); + } + + private int jjStartNfaWithStates_3(int pos, int kind, int state) { + jjmatchedKind = kind; + jjmatchedPos = pos; + try { + curChar = input_stream.readChar(); + } + catch (java.io.IOException e) { + return pos + 1; + } + return jjMoveNfa_3(state, pos + 1); + } + + private int jjMoveStringLiteralDfa0_3() { + switch (curChar) { + case 59: + return jjStopAtPos(0, 15); + default: + return jjMoveNfa_3(3, 0); + } + } + + private int jjMoveNfa_3(int startState, int curPos) { + int[] nextStates; + int startsAt = 0; + jjnewStateCnt = 8; + int i = 1; + jjstateSet[0] = startState; + int j, kind = 0x7fffffff; + for (; ;) { + if (++jjround == 0x7fffffff) + ReInitRounds(); + if (curChar < 64) { + long l = 1L << curChar; + MatchLoop: + do { + switch (jjstateSet[--i]) { + case 3: + if ((0x3ff000000000000L & l) != 0L) { + if (kind > 7) + kind = 7; + jjCheckNAddTwoStates(0, 1); + } else if (curChar == 45) { + if (kind > 12) + kind = 12; + jjCheckNAdd(4); + } + break; + case 0: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 7) + kind = 7; + jjCheckNAddTwoStates(0, 1); + break; + case 1: + if (curChar == 46) + jjCheckNAdd(2); + break; + case 2: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 7) + kind = 7; + jjCheckNAdd(2); + break; + case 4: + if ((0x3ff200000000000L & l) == 0L) + break; + if (kind > 12) + kind = 12; + jjCheckNAdd(4); + break; + case 6: + jjAddStates(7, 8); + break; + default: + break; + } + } while (i != startsAt); + } else if (curChar < 128) { + long l = 1L << (curChar & 077); + MatchLoop: + do { + switch (jjstateSet[--i]) { + case 3: + if ((0x7fffffe87fffffeL & l) != 0L) { + if (kind > 12) + kind = 12; + jjCheckNAdd(4); + } else if (curChar == 123) + jjCheckNAdd(6); + break; + case 4: + if ((0x7fffffe87fffffeL & l) == 0L) + break; + if (kind > 12) + kind = 12; + jjCheckNAdd(4); + break; + case 5: + if (curChar == 123) + jjCheckNAdd(6); + break; + case 6: + if ((0xdfffffffffffffffL & l) != 0L) + jjCheckNAddTwoStates(6, 7); + break; + case 7: + if (curChar == 125) + kind = 21; + break; + default: + break; + } + } while (i != startsAt); + } else { + int i2 = (curChar & 0xff) >> 6; + long l2 = 1L << (curChar & 077); + MatchLoop: + do { + switch (jjstateSet[--i]) { + case 6: + if ((jjbitVec0[i2] & l2) != 0L) + jjAddStates(7, 8); + break; + default: + break; + } + } while (i != startsAt); + } + if (kind != 0x7fffffff) { + jjmatchedKind = kind; + jjmatchedPos = curPos; + kind = 0x7fffffff; + } + ++curPos; + if ((i = jjnewStateCnt) == (startsAt = 8 - (jjnewStateCnt = startsAt))) + return curPos; + try { + curChar = input_stream.readChar(); + } + catch (java.io.IOException e) { + return curPos; + } + } + } + + private int jjStopStringLiteralDfa_1(int pos, long active0) { + switch (pos) { + default: + return -1; + } + } + + private int jjStartNfa_1(int pos, long active0) { + return jjMoveNfa_1(jjStopStringLiteralDfa_1(pos, active0), pos + 1); + } + + private int jjStartNfaWithStates_1(int pos, int kind, int state) { + jjmatchedKind = kind; + jjmatchedPos = pos; + try { + curChar = input_stream.readChar(); + } + catch (java.io.IOException e) { + return pos + 1; + } + return jjMoveNfa_1(state, pos + 1); + } + + private int jjMoveStringLiteralDfa0_1() { + switch (curChar) { + case 58: + return jjStopAtPos(0, 14); + case 59: + return jjStopAtPos(0, 15); + case 125: + return jjStopAtPos(0, 17); + default: + return jjMoveNfa_1(0, 0); + } + } + + private int jjMoveNfa_1(int startState, int curPos) { + int[] nextStates; + int startsAt = 0; + jjnewStateCnt = 50; + int i = 1; + jjstateSet[0] = startState; + int j, kind = 0x7fffffff; + for (; ;) { + if (++jjround == 0x7fffffff) + ReInitRounds(); + if (curChar < 64) { + long l = 1L << curChar; + MatchLoop: + do { + switch (jjstateSet[--i]) { + case 0: + if ((0x3ff000000000000L & l) != 0L) { + if (kind > 7) + kind = 7; + jjCheckNAddStates(9, 22); + } else if (curChar == 47) + jjAddStates(23, 24); + else if (curChar == 35) + jjstateSet[jjnewStateCnt++] = 7; + else if (curChar == 34) + jjCheckNAddTwoStates(4, 5); + else if (curChar == 45) { + if (kind > 9) + kind = 9; + jjCheckNAdd(1); + } + break; + case 1: + if ((0x3ff200000000000L & l) == 0L) + break; + if (kind > 9) + kind = 9; + jjCheckNAdd(1); + break; + case 3: + if (curChar == 34) + jjCheckNAddTwoStates(4, 5); + break; + case 4: + if ((0xfffffffbffffdbffL & l) != 0L) + jjCheckNAddTwoStates(4, 5); + break; + case 5: + if (curChar == 34 && kind > 22) + kind = 22; + break; + case 6: + if (curChar == 35) + jjstateSet[jjnewStateCnt++] = 7; + break; + case 7: + if ((0x3ff000000000000L & l) != 0L) + jjstateSet[jjnewStateCnt++] = 8; + break; + case 8: + if ((0x3ff000000000000L & l) != 0L) + jjstateSet[jjnewStateCnt++] = 9; + break; + case 9: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 23) + kind = 23; + jjstateSet[jjnewStateCnt++] = 10; + break; + case 10: + if ((0x3ff000000000000L & l) != 0L) + jjstateSet[jjnewStateCnt++] = 11; + break; + case 11: + if ((0x3ff000000000000L & l) != 0L) + jjstateSet[jjnewStateCnt++] = 12; + break; + case 12: + if ((0x3ff000000000000L & l) != 0L && kind > 23) + kind = 23; + break; + case 13: + if (curChar == 47) + jjAddStates(23, 24); + break; + case 14: + if (curChar == 47) + jjCheckNAddStates(25, 27); + break; + case 15: + if ((0xffffffffffffdbffL & l) != 0L) + jjCheckNAddStates(25, 27); + break; + case 16: + if ((0x2400L & l) != 0L && kind > 5) + kind = 5; + break; + case 17: + if (curChar == 10 && kind > 5) + kind = 5; + break; + case 18: + if (curChar == 13) + jjstateSet[jjnewStateCnt++] = 17; + break; + case 19: + if (curChar == 42) + jjCheckNAddTwoStates(20, 21); + break; + case 20: + if ((0xfffffbffffffffffL & l) != 0L) + jjCheckNAddTwoStates(20, 21); + break; + case 21: + if (curChar == 42) + jjAddStates(28, 29); + break; + case 22: + if ((0xffff7fffffffffffL & l) != 0L) + jjCheckNAddTwoStates(23, 21); + break; + case 23: + if ((0xfffffbffffffffffL & l) != 0L) + jjCheckNAddTwoStates(23, 21); + break; + case 24: + if (curChar == 47 && kind > 6) + kind = 6; + break; + case 25: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 7) + kind = 7; + jjCheckNAddStates(9, 22); + break; + case 26: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 7) + kind = 7; + jjCheckNAddTwoStates(26, 27); + break; + case 27: + if (curChar == 46) + jjCheckNAdd(28); + break; + case 28: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 7) + kind = 7; + jjCheckNAdd(28); + break; + case 29: + if ((0x3ff000000000000L & l) != 0L) + jjCheckNAddStates(30, 32); + break; + case 30: + if (curChar == 46) + jjCheckNAdd(31); + break; + case 31: + if ((0x3ff000000000000L & l) != 0L) + jjCheckNAddTwoStates(31, 33); + break; + case 34: + if ((0x3ff000000000000L & l) != 0L) + jjCheckNAddStates(33, 35); + break; + case 35: + if (curChar == 46) + jjCheckNAdd(36); + break; + case 36: + if ((0x3ff000000000000L & l) != 0L) + jjCheckNAddTwoStates(36, 38); + break; + case 39: + if ((0x3ff000000000000L & l) != 0L) + jjCheckNAddStates(36, 41); + break; + case 40: + if (curChar == 46) + jjCheckNAdd(41); + break; + case 41: + if ((0x3ff000000000000L & l) != 0L) + jjCheckNAddStates(42, 46); + break; + default: + break; + } + } while (i != startsAt); + } else if (curChar < 128) { + long l = 1L << (curChar & 077); + MatchLoop: + do { + switch (jjstateSet[--i]) { + case 0: + if ((0x7fffffe87fffffeL & l) != 0L) { + if (kind > 9) + kind = 9; + jjCheckNAdd(1); + } else if (curChar == 123) { + if (kind > 18) + kind = 18; + } + break; + case 1: + if ((0x7fffffe87fffffeL & l) == 0L) + break; + if (kind > 9) + kind = 9; + jjCheckNAdd(1); + break; + case 2: + if (curChar == 123 && kind > 18) + kind = 18; + break; + case 4: + if ((0xffffffffefffffffL & l) != 0L) + jjAddStates(47, 48); + break; + case 7: + if ((0x7e0000007eL & l) != 0L) + jjstateSet[jjnewStateCnt++] = 8; + break; + case 8: + if ((0x7e0000007eL & l) != 0L) + jjstateSet[jjnewStateCnt++] = 9; + break; + case 9: + if ((0x7e0000007eL & l) == 0L) + break; + if (kind > 23) + kind = 23; + jjstateSet[jjnewStateCnt++] = 10; + break; + case 10: + if ((0x7e0000007eL & l) != 0L) + jjstateSet[jjnewStateCnt++] = 11; + break; + case 11: + if ((0x7e0000007eL & l) != 0L) + jjstateSet[jjnewStateCnt++] = 12; + break; + case 12: + if ((0x7e0000007eL & l) != 0L && kind > 23) + kind = 23; + break; + case 15: + jjAddStates(25, 27); + break; + case 20: + jjCheckNAddTwoStates(20, 21); + break; + case 22: + case 23: + jjCheckNAddTwoStates(23, 21); + break; + case 32: + if (curChar == 109 && kind > 25) + kind = 25; + break; + case 33: + if (curChar == 101) + jjstateSet[jjnewStateCnt++] = 32; + break; + case 37: + if (curChar == 120 && kind > 26) + kind = 26; + break; + case 38: + if (curChar == 101) + jjstateSet[jjnewStateCnt++] = 37; + break; + case 42: + if (curChar == 109 && kind > 27) + kind = 27; + break; + case 43: + if (curChar == 109) + jjCheckNAdd(42); + break; + case 44: + if (curChar == 99) + jjCheckNAdd(42); + break; + case 45: + if (curChar == 110 && kind > 27) + kind = 27; + break; + case 46: + if (curChar == 105) + jjstateSet[jjnewStateCnt++] = 45; + break; + case 47: + if (curChar == 112) + jjAddStates(49, 50); + break; + case 48: + if (curChar == 116 && kind > 27) + kind = 27; + break; + case 49: + if (curChar == 99 && kind > 27) + kind = 27; + break; + default: + break; + } + } while (i != startsAt); + } else { + int i2 = (curChar & 0xff) >> 6; + long l2 = 1L << (curChar & 077); + MatchLoop: + do { + switch (jjstateSet[--i]) { + case 4: + if ((jjbitVec0[i2] & l2) != 0L) + jjAddStates(47, 48); + break; + case 15: + if ((jjbitVec0[i2] & l2) != 0L) + jjAddStates(25, 27); + break; + case 20: + if ((jjbitVec0[i2] & l2) != 0L) + jjCheckNAddTwoStates(20, 21); + break; + case 22: + case 23: + if ((jjbitVec0[i2] & l2) != 0L) + jjCheckNAddTwoStates(23, 21); + break; + default: + break; + } + } while (i != startsAt); + } + if (kind != 0x7fffffff) { + jjmatchedKind = kind; + jjmatchedPos = curPos; + kind = 0x7fffffff; + } + ++curPos; + if ((i = jjnewStateCnt) == (startsAt = 50 - (jjnewStateCnt = startsAt))) + return curPos; + try { + curChar = input_stream.readChar(); + } + catch (java.io.IOException e) { + return curPos; + } + } + } + + private int jjStopStringLiteralDfa_2(int pos, long active0) { + switch (pos) { + default: + return -1; + } + } + + private int jjStartNfa_2(int pos, long active0) { + return jjMoveNfa_2(jjStopStringLiteralDfa_2(pos, active0), pos + 1); + } + + private int jjStartNfaWithStates_2(int pos, int kind, int state) { + jjmatchedKind = kind; + jjmatchedPos = pos; + try { + curChar = input_stream.readChar(); + } + catch (java.io.IOException e) { + return pos + 1; + } + return jjMoveNfa_2(state, pos + 1); + } + + private int jjMoveStringLiteralDfa0_2() { + switch (curChar) { + case 59: + return jjStartNfaWithStates_2(0, 15, 3); + default: + return jjMoveNfa_2(4, 0); + } + } + + private int jjMoveNfa_2(int startState, int curPos) { + int[] nextStates; + int startsAt = 0; + jjnewStateCnt = 5; + int i = 1; + jjstateSet[0] = startState; + int j, kind = 0x7fffffff; + for (; ;) { + if (++jjround == 0x7fffffff) + ReInitRounds(); + if (curChar < 64) { + long l = 1L << curChar; + MatchLoop: + do { + switch (jjstateSet[--i]) { + case 4: + if (kind > 19) + kind = 19; + jjCheckNAdd(3); + if ((0x3ff000000000000L & l) != 0L) { + if (kind > 7) + kind = 7; + jjCheckNAddTwoStates(0, 1); + } + break; + case 0: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 7) + kind = 7; + jjCheckNAddTwoStates(0, 1); + break; + case 1: + if (curChar == 46) + jjCheckNAdd(2); + break; + case 2: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 7) + kind = 7; + jjCheckNAdd(2); + break; + case 3: + if (kind > 19) + kind = 19; + jjCheckNAdd(3); + break; + default: + break; + } + } while (i != startsAt); + } else if (curChar < 128) { + long l = 1L << (curChar & 077); + MatchLoop: + do { + switch (jjstateSet[--i]) { + case 4: + if ((0xdfffffffffffffffL & l) != 0L) { + if (kind > 19) + kind = 19; + jjCheckNAdd(3); + } else if (curChar == 125) { + if (kind > 20) + kind = 20; + } + break; + case 3: + if ((0xdfffffffffffffffL & l) == 0L) + break; + kind = 19; + jjCheckNAdd(3); + break; + default: + break; + } + } while (i != startsAt); + } else { + int i2 = (curChar & 0xff) >> 6; + long l2 = 1L << (curChar & 077); + MatchLoop: + do { + switch (jjstateSet[--i]) { + case 4: + case 3: + if ((jjbitVec0[i2] & l2) == 0L) + break; + if (kind > 19) + kind = 19; + jjCheckNAdd(3); + break; + default: + break; + } + } while (i != startsAt); + } + if (kind != 0x7fffffff) { + jjmatchedKind = kind; + jjmatchedPos = curPos; + kind = 0x7fffffff; + } + ++curPos; + if ((i = jjnewStateCnt) == (startsAt = 5 - (jjnewStateCnt = startsAt))) + return curPos; + try { + curChar = input_stream.readChar(); + } + catch (java.io.IOException e) { + return curPos; + } + } + } + + static final int[] jjnextStates = { + 6, 11, 7, 8, 10, 14, 16, 6, 7, 26, 27, 29, 30, 33, 34, 35, + 38, 39, 40, 43, 44, 46, 47, 14, 19, 15, 16, 18, 22, 24, 29, 30, + 33, 34, 35, 38, 39, 40, 43, 44, 46, 47, 41, 43, 44, 46, 47, 4, + 5, 48, 49, + }; + public static final String[] jjstrLiteralImages = { + "", null, null, null, null, null, null, null, null, null, null, null, null, + "\72", "\72", "\73", "\173", "\175", null, null, null, null, null, null, null, null, + null, null, "\54", "\52", "\43", "\56", "\133", "\135", "\75",}; + public static final String[] lexStateNames = { + "DEFAULT", + "IN_RULE", + "JAVA_CODE_RULE", + "IN_PSEUDOCLASS", + }; + public static final int[] jjnewLexState = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 3, -1, -1, 1, 0, 2, -1, 1, 0, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + }; + static final long[] jjtoToken = { + 0x7fefff281L, + }; + static final long[] jjtoSkip = { + 0x7eL, + }; + protected SimpleCharStream input_stream; + private final int[] jjrounds = new int[50]; + private final int[] jjstateSet = new int[100]; + protected char curChar; + + public CSSParserTokenManager(SimpleCharStream stream) { + if (SimpleCharStream.staticFlag) + throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer."); + input_stream = stream; + } + + public CSSParserTokenManager(SimpleCharStream stream, int lexState) { + this(stream); + SwitchTo(lexState); + } + + public void ReInit(SimpleCharStream stream) { + jjmatchedPos = jjnewStateCnt = 0; + curLexState = defaultLexState; + input_stream = stream; + ReInitRounds(); + } + + private void ReInitRounds() { + int i; + jjround = 0x80000001; + for (i = 50; i-- > 0;) + jjrounds[i] = 0x80000000; + } + + public void ReInit(SimpleCharStream stream, int lexState) { + ReInit(stream); + SwitchTo(lexState); + } + + public void SwitchTo(int lexState) { + if (lexState >= 4 || lexState < 0) + throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE); + else + curLexState = lexState; + } + + protected Token jjFillToken() { + Token t = Token.newToken(jjmatchedKind); + t.kind = jjmatchedKind; + String im = jjstrLiteralImages[jjmatchedKind]; + t.image = (im == null) ? input_stream.GetImage() : im; + t.beginLine = input_stream.getBeginLine(); + t.beginColumn = input_stream.getBeginColumn(); + t.endLine = input_stream.getEndLine(); + t.endColumn = input_stream.getEndColumn(); + return t; + } + + int curLexState = 0; + int defaultLexState = 0; + int jjnewStateCnt; + int jjround; + int jjmatchedPos; + int jjmatchedKind; + + public Token getNextToken() { + int kind; + Token specialToken = null; + Token matchedToken; + int curPos = 0; + + EOFLoop: + for (; ;) { + try { + curChar = input_stream.BeginToken(); + } + catch (java.io.IOException e) { + jjmatchedKind = 0; + matchedToken = jjFillToken(); + return matchedToken; + } + + switch (curLexState) { + case 0: + try { + input_stream.backup(0); + while (curChar <= 32 && (0x100002600L & (1L << curChar)) != 0L) + curChar = input_stream.BeginToken(); + } + catch (java.io.IOException e1) { + continue EOFLoop; + } + jjmatchedKind = 0x7fffffff; + jjmatchedPos = 0; + curPos = jjMoveStringLiteralDfa0_0(); + break; + case 1: + try { + input_stream.backup(0); + while (curChar <= 32 && (0x100002600L & (1L << curChar)) != 0L) + curChar = input_stream.BeginToken(); + } + catch (java.io.IOException e1) { + continue EOFLoop; + } + jjmatchedKind = 0x7fffffff; + jjmatchedPos = 0; + curPos = jjMoveStringLiteralDfa0_1(); + break; + case 2: + jjmatchedKind = 0x7fffffff; + jjmatchedPos = 0; + curPos = jjMoveStringLiteralDfa0_2(); + break; + case 3: + jjmatchedKind = 0x7fffffff; + jjmatchedPos = 0; + curPos = jjMoveStringLiteralDfa0_3(); + break; + } + if (jjmatchedKind != 0x7fffffff) { + if (jjmatchedPos + 1 < curPos) + input_stream.backup(curPos - jjmatchedPos - 1); + if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) { + matchedToken = jjFillToken(); + if (jjnewLexState[jjmatchedKind] != -1) + curLexState = jjnewLexState[jjmatchedKind]; + return matchedToken; + } else { + if (jjnewLexState[jjmatchedKind] != -1) + curLexState = jjnewLexState[jjmatchedKind]; + continue EOFLoop; + } + } + int error_line = input_stream.getEndLine(); + int error_column = input_stream.getEndColumn(); + String error_after = null; + boolean EOFSeen = false; + try { + input_stream.readChar(); + input_stream.backup(1); + } + catch (java.io.IOException e1) { + EOFSeen = true; + error_after = curPos <= 1 ? "" : input_stream.GetImage(); + if (curChar == '\n' || curChar == '\r') { + error_line++; + error_column = 0; + } else + error_column++; + } + if (!EOFSeen) { + input_stream.backup(1); + error_after = curPos <= 1 ? "" : input_stream.GetImage(); + } + throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR); + } + } + +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/css/CSSParserTreeConstants.java b/trunk/jaxx-compiler/src/main/java/jaxx/css/CSSParserTreeConstants.java new file mode 100644 index 0000000..c3a624e --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/css/CSSParserTreeConstants.java @@ -0,0 +1,40 @@ +/* Generated By:JJTree: Do not edit this line. .\CSSParserTreeConstants.java */ + +package jaxx.css; + +public interface CSSParserTreeConstants { + public int JJTSTYLESHEET = 0; + public int JJTRULE = 1; + public int JJTSELECTORS = 2; + public int JJTSELECTOR = 3; + public int JJTJAVACLASS = 4; + public int JJTID = 5; + public int JJTCLASS = 6; + public int JJTPSEUDOCLASS = 7; + public int JJTANIMATIONPROPERTIES = 8; + public int JJTANIMATIONPROPERTY = 9; + public int JJTDECLARATION = 10; + public int JJTPROPERTY = 11; + public int JJTEXPRESSION = 12; + public int JJTJAVACODE = 13; + public int JJTIDENTIFIER = 14; + + + public String[] jjtNodeName = { + "Stylesheet", + "Rule", + "Selectors", + "Selector", + "JavaClass", + "Id", + "Class", + "PseudoClass", + "AnimationProperties", + "AnimationProperty", + "Declaration", + "Property", + "Expression", + "JavaCode", + "Identifier", + }; +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/css/JJTCSSParserState.java b/trunk/jaxx-compiler/src/main/java/jaxx/css/JJTCSSParserState.java new file mode 100644 index 0000000..21545f5 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/css/JJTCSSParserState.java @@ -0,0 +1,123 @@ +/* Generated By:JJTree: Do not edit this line. .\JJTCSSParserState.java */ + +package jaxx.css; + +class JJTCSSParserState { + private java.util.Stack<Node> nodes; + private java.util.Stack<Integer> marks; + + private int sp; // number of nodes on stack + private int mk; // current mark + private boolean node_created; + + JJTCSSParserState() { + nodes = new java.util.Stack<Node>(); + marks = new java.util.Stack<Integer>(); + sp = 0; + mk = 0; + } + + /* Determines whether the current node was actually closed and + pushed. This should only be called in the final user action of a + node scope. */ + boolean nodeCreated() { + return node_created; + } + + /* Call this to reinitialize the node stack. It is called +automatically by the parser's ReInit() method. */ + void reset() { + nodes.removeAllElements(); + marks.removeAllElements(); + sp = 0; + mk = 0; + } + + /* Returns the root node of the AST. It only makes sense to call +this after a successful parse. */ + Node rootNode() { + return nodes.elementAt(0); + } + + /* Pushes a node on to the stack. */ + void pushNode(Node n) { + nodes.push(n); + ++sp; + } + + /* Returns the node on the top of the stack, and remove it from the + stack. */ + Node popNode() { + if (--sp < mk) { + mk = marks.pop(); + } + return nodes.pop(); + } + + /* Returns the node currently on the top of the stack. */ + Node peekNode() { + return nodes.peek(); + } + + /* Returns the number of children on the stack in the current node + scope. */ + int nodeArity() { + return sp - mk; + } + + + void clearNodeScope(Node n) { + while (sp > mk) { + popNode(); + } + mk = marks.pop(); + } + + + void openNodeScope(Node n) { + marks.push(mk); + mk = sp; + n.jjtOpen(); + } + + + /* A definite node is constructed from a specified number of +children. That number of nodes are popped from the stack and +made the children of the definite node. Then the definite node +is pushed on to the stack. */ + void closeNodeScope(Node n, int num) { + mk = marks.pop(); + while (num-- > 0) { + Node c = popNode(); + c.jjtSetParent(n); + n.jjtAddChild(c, num); + } + n.jjtClose(); + pushNode(n); + node_created = true; + } + + + /* A conditional node is constructed if its condition is true. All +the nodes that have been pushed since the node was opened are +made children of the the conditional node, which is then pushed +on to the stack. If the condition is false the node is not +constructed and they are left on the stack. */ + void closeNodeScope(Node n, boolean condition) { + if (condition) { + int a = nodeArity(); + mk = marks.pop(); + while (a-- > 0) { + Node c = popNode(); + c.jjtSetParent(n); + n.jjtAddChild(c, a); + } + n.jjtClose(); + pushNode(n); + node_created = true; + } else { + mk = marks.pop(); + node_created = false; + } + } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/css/Node.java b/trunk/jaxx-compiler/src/main/java/jaxx/css/Node.java new file mode 100644 index 0000000..e1d887a --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/css/Node.java @@ -0,0 +1,51 @@ +/* Generated By:JJTree: Do not edit this line. Node.java */ + +package jaxx.css; + +/* All AST nodes must implement this interface. It provides basic + machinery for constructing the parent and child relationships + between nodes. */ + +public interface Node { + + /** + * This method is called after the node has been made the current + * node. It indicates that child nodes can now be added to it. + */ + public void jjtOpen(); + + /** + * This method is called after all the child nodes have been + * added. + */ + public void jjtClose(); + + /** + * This pair of methods are used to inform the node of its + * parent. + * + * @param n node + */ + public void jjtSetParent(Node n); + + public Node jjtGetParent(); + + /** + * This method tells the node to add its argument to the node's + * list of children. + * + * @param n node + * @param i pos + */ + public void jjtAddChild(Node n, int i); + + /** + * @param i pos + * @return a child node. The children are numbered + * from zero, left to right. + */ + public Node jjtGetChild(int i); + + /** @return the number of children the node has. */ + public int jjtGetNumChildren(); +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/css/ParseException.java b/trunk/jaxx-compiler/src/main/java/jaxx/css/ParseException.java new file mode 100644 index 0000000..df4b451 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/css/ParseException.java @@ -0,0 +1,20 @@ +/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */ +package jaxx.css; + +public class ParseException extends jaxx.parser.ParseException { + private static final long serialVersionUID = 229575674880359031L; + + public ParseException() { + super(); + } + + + public ParseException(String message) { + super(message); + } + + + public ParseException(String message, int line, int column) { + super(message, line, column); + } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/css/SimpleCharStream.java b/trunk/jaxx-compiler/src/main/java/jaxx/css/SimpleCharStream.java new file mode 100644 index 0000000..dcbbe0d --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/css/SimpleCharStream.java @@ -0,0 +1,398 @@ +/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 4.0 */ +package jaxx.css; + +/** + * An implementation of interface CharStream, where the stream is assumed to + * contain only ASCII characters (without unicode processing). + */ + +public class SimpleCharStream { + public static final boolean staticFlag = false; + int bufsize; + int available; + int tokenBegin; + public int bufpos = -1; + protected int bufline[]; + protected int bufcolumn[]; + + protected int column = 0; + protected int line = 1; + + protected boolean prevCharIsCR = false; + protected boolean prevCharIsLF = false; + + protected java.io.Reader inputStream; + + protected char[] buffer; + protected int maxNextCharInd = 0; + protected int inBuf = 0; + protected int tabSize = 8; + + protected void setTabSize(int i) { + tabSize = i; + } + + protected int getTabSize(int i) { + return tabSize; + } + + + protected void ExpandBuff(boolean wrapAround) { + char[] newbuffer = new char[bufsize + 2048]; + int newbufline[] = new int[bufsize + 2048]; + int newbufcolumn[] = new int[bufsize + 2048]; + + try { + if (wrapAround) { + System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); + System.arraycopy(buffer, 0, newbuffer, + bufsize - tokenBegin, bufpos); + buffer = newbuffer; + + System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); + System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos); + bufline = newbufline; + + System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); + System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos); + bufcolumn = newbufcolumn; + + maxNextCharInd = (bufpos += (bufsize - tokenBegin)); + } else { + System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); + buffer = newbuffer; + + System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); + bufline = newbufline; + + System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); + bufcolumn = newbufcolumn; + + maxNextCharInd = (bufpos -= tokenBegin); + } + } + catch (Throwable t) { + throw new Error(t.getMessage()); + } + + + bufsize += 2048; + available = bufsize; + tokenBegin = 0; + } + + protected void FillBuff() throws java.io.IOException { + if (maxNextCharInd == available) { + if (available == bufsize) { + if (tokenBegin > 2048) { + bufpos = maxNextCharInd = 0; + available = tokenBegin; + } else if (tokenBegin < 0) + bufpos = maxNextCharInd = 0; + else + ExpandBuff(false); + } else if (available > tokenBegin) + available = bufsize; + else if ((tokenBegin - available) < 2048) + ExpandBuff(true); + else + available = tokenBegin; + } + + int i; + try { + if ((i = inputStream.read(buffer, maxNextCharInd, + available - maxNextCharInd)) == -1) { + inputStream.close(); + throw new java.io.IOException(); + } else + maxNextCharInd += i; + } + catch (java.io.IOException e) { + --bufpos; + backup(0); + if (tokenBegin == -1) + tokenBegin = bufpos; + throw e; + } + } + + public char BeginToken() throws java.io.IOException { + tokenBegin = -1; + char c = readChar(); + tokenBegin = bufpos; + + return c; + } + + protected void UpdateLineColumn(char c) { + column++; + + if (prevCharIsLF) { + prevCharIsLF = false; + line += (column = 1); + } else if (prevCharIsCR) { + prevCharIsCR = false; + if (c == '\n') { + prevCharIsLF = true; + } else + line += (column = 1); + } + + switch (c) { + case '\r': + prevCharIsCR = true; + break; + case '\n': + prevCharIsLF = true; + break; + case '\t': + column--; + column += (tabSize - (column % tabSize)); + break; + default: + break; + } + + bufline[bufpos] = line; + bufcolumn[bufpos] = column; + } + + public char readChar() throws java.io.IOException { + if (inBuf > 0) { + --inBuf; + + if (++bufpos == bufsize) + bufpos = 0; + + return buffer[bufpos]; + } + + if (++bufpos >= maxNextCharInd) + FillBuff(); + + char c = buffer[bufpos]; + + UpdateLineColumn(c); + return (c); + } + + /** + * @return ??? + * @see #getEndColumn + * @deprecated + */ + + public int getColumn() { + return bufcolumn[bufpos]; + } + + /** + * @return ??? + * @see #getEndLine + * @deprecated + */ + + public int getLine() { + return bufline[bufpos]; + } + + public int getEndColumn() { + return bufcolumn[bufpos]; + } + + public int getEndLine() { + return bufline[bufpos]; + } + + public int getBeginColumn() { + return bufcolumn[tokenBegin]; + } + + public int getBeginLine() { + return bufline[tokenBegin]; + } + + public void backup(int amount) { + + inBuf += amount; + if ((bufpos -= amount) < 0) + bufpos += bufsize; + } + + public SimpleCharStream(java.io.Reader dstream, int startline, + int startcolumn, int buffersize) { + inputStream = dstream; + line = startline; + column = startcolumn - 1; + + available = bufsize = buffersize; + buffer = new char[buffersize]; + bufline = new int[buffersize]; + bufcolumn = new int[buffersize]; + } + + public SimpleCharStream(java.io.Reader dstream, int startline, + int startcolumn) { + this(dstream, startline, startcolumn, 4096); + } + + public SimpleCharStream(java.io.Reader dstream) { + this(dstream, 1, 1, 4096); + } + + public void ReInit(java.io.Reader dstream, int startline, + int startcolumn, int buffersize) { + inputStream = dstream; + line = startline; + column = startcolumn - 1; + + if (buffer == null || buffersize != buffer.length) { + available = bufsize = buffersize; + buffer = new char[buffersize]; + bufline = new int[buffersize]; + bufcolumn = new int[buffersize]; + } + prevCharIsLF = prevCharIsCR = false; + tokenBegin = inBuf = maxNextCharInd = 0; + bufpos = -1; + } + + public void ReInit(java.io.Reader dstream, int startline, + int startcolumn) { + ReInit(dstream, startline, startcolumn, 4096); + } + + public void ReInit(java.io.Reader dstream) { + ReInit(dstream, 1, 1, 4096); + } + + public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline, + int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException { + this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); + } + + public SimpleCharStream(java.io.InputStream dstream, int startline, + int startcolumn, int buffersize) { + this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); + } + + public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline, + int startcolumn) throws java.io.UnsupportedEncodingException { + this(dstream, encoding, startline, startcolumn, 4096); + } + + public SimpleCharStream(java.io.InputStream dstream, int startline, + int startcolumn) { + this(dstream, startline, startcolumn, 4096); + } + + public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException { + this(dstream, encoding, 1, 1, 4096); + } + + public SimpleCharStream(java.io.InputStream dstream) { + this(dstream, 1, 1, 4096); + } + + public void ReInit(java.io.InputStream dstream, String encoding, int startline, + int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException { + ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); + } + + public void ReInit(java.io.InputStream dstream, int startline, + int startcolumn, int buffersize) { + ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); + } + + public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException { + ReInit(dstream, encoding, 1, 1, 4096); + } + + public void ReInit(java.io.InputStream dstream) { + ReInit(dstream, 1, 1, 4096); + } + + public void ReInit(java.io.InputStream dstream, String encoding, int startline, + int startcolumn) throws java.io.UnsupportedEncodingException { + ReInit(dstream, encoding, startline, startcolumn, 4096); + } + + public void ReInit(java.io.InputStream dstream, int startline, + int startcolumn) { + ReInit(dstream, startline, startcolumn, 4096); + } + + public String GetImage() { + if (bufpos >= tokenBegin) + return new String(buffer, tokenBegin, bufpos - tokenBegin + 1); + else + return new String(buffer, tokenBegin, bufsize - tokenBegin) + + new String(buffer, 0, bufpos + 1); + } + + public char[] GetSuffix(int len) { + char[] ret = new char[len]; + + if ((bufpos + 1) >= len) + System.arraycopy(buffer, bufpos - len + 1, ret, 0, len); + else { + System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0, + len - bufpos - 1); + System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1); + } + + return ret; + } + + public void Done() { + buffer = null; + bufline = null; + bufcolumn = null; + } + + /** + * Method to adjust line and column numbers for the start of a token. + * + * @param newLine ? + * @param newCol ? + */ + public void adjustBeginLineColumn(int newLine, int newCol) { + int start = tokenBegin; + int len; + + if (bufpos >= tokenBegin) { + len = bufpos - tokenBegin + inBuf + 1; + } else { + len = bufsize - tokenBegin + bufpos + 1 + inBuf; + } + + int i = 0, j = 0, k; + int nextColDiff, columnDiff = 0; + + while (i < len && + bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) { + bufline[j] = newLine; + nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j]; + bufcolumn[j] = newCol + columnDiff; + columnDiff = nextColDiff; + i++; + } + + if (i < len) { + bufline[j] = newLine++; + bufcolumn[j] = newCol + columnDiff; + + while (i++ < len) { + if (bufline[j = start % bufsize] != bufline[++start % bufsize]) + bufline[j] = newLine++; + else + bufline[j] = newLine; + } + } + + line = bufline[j]; + column = bufcolumn[j]; + } + +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/css/SimpleNode.java b/trunk/jaxx-compiler/src/main/java/jaxx/css/SimpleNode.java new file mode 100644 index 0000000..cad997a --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/css/SimpleNode.java @@ -0,0 +1,122 @@ +/* Generated By:JJTree: Do not edit this line. SimpleNode.java */ + +package jaxx.css; + +public class SimpleNode implements Node { + protected Node parent; + protected Node[] children; + protected int id; + protected CSSParser parser; + public Token firstToken; + public Token lastToken; + + + public SimpleNode(int i) { + id = i; + } + + public SimpleNode(CSSParser p, int i) { + this(i); + parser = p; + } + + + public int getId() { + return id; + } + + public void jjtOpen() { + } + + public void jjtClose() { + } + + public void jjtSetParent(Node n) { + parent = n; + } + + public Node jjtGetParent() { + return parent; + } + + public SimpleNode getParent() { + return (SimpleNode) parent; + } + + public void jjtAddChild(Node n, int i) { + if (children == null) { + children = new Node[i + 1]; + } else if (i >= children.length) { + Node c[] = new Node[i + 1]; + System.arraycopy(children, 0, c, 0, children.length); + children = c; + } + children[i] = n; + } + + public Node jjtGetChild(int i) { + return children[i]; + } + + public SimpleNode getChild(int i) { + return (SimpleNode) children[i]; + } + + public int jjtGetNumChildren() { + return (children == null) ? 0 : children.length; + } + + /* You can override these two methods in subclasses of SimpleNode to +customize the way the node appears when the tree is dumped. If +your output uses more than one line you should override +toString(String), otherwise overriding toString() is probably all +you need to do. */ + + @Override + public String toString() { + return getClass().getName() + "[" + getText() + "]"; + } + + public String toString(String prefix) { + return prefix + toString(); + } + + /* Override this method if you want to customize how the node dumps + out its children. */ + + public void dump(String prefix) { + System.out.println(toString(prefix)); + if (children != null) { + for (Node aChildren : children) { + SimpleNode n = (SimpleNode) aChildren; + if (n != null) { + n.dump(prefix + " "); + } + } + } + } + + private void appendSpecialTokens(StringBuffer s, Token st) { + if (st != null) { + appendSpecialTokens(s, st.specialToken); + s.append(st.image); + } + } + + + /** @return the text of the tokens comprising this node. */ + public String getText() { + StringBuffer text = new StringBuffer(); + Token t = firstToken; + while (t != null) { + appendSpecialTokens(text, t.specialToken); + text.append(t.image); + if (t == lastToken) + break; + t = t.next; + } + + return text.toString(); + } +} + diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/css/StylesheetHelper.java b/trunk/jaxx-compiler/src/main/java/jaxx/css/StylesheetHelper.java new file mode 100644 index 0000000..ea6dbd8 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/css/StylesheetHelper.java @@ -0,0 +1,563 @@ +package jaxx.css; + +import jaxx.CompilerException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.DataBinding; +import jaxx.compiler.DataSource; +import jaxx.compiler.JAXXCompiler; +import jaxx.parser.JavaParser; +import jaxx.parser.JavaParserTreeConstants; +import jaxx.parser.SimpleNode; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.reflect.MethodDescriptor; +import jaxx.tags.DefaultObjectHandler; +import jaxx.tags.TagManager; +import jaxx.types.TypeManager; + +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * A helper class to compute {@link Stylesheet}, {@link Rule} and {@link Selector} + * and extract all the compiler logic from this class. + * <p/> + * In that way we can make the compiler as a single module and a runtime as another module. + * + * @author chemit + */ +public class StylesheetHelper { + + public static void applyTo(CompiledObject object, JAXXCompiler compiler, Stylesheet stylesheet, Stylesheet overrides) throws CompilerException { + Map<String, String> overriddenProperties; + if (overrides != null) { + overriddenProperties = getApplicableProperties(overrides, object); + //overriddenProperties = overrides.getApplicableProperties(s,object); + } else { + overriddenProperties = null; + } + + Map<String, String> properties = getApplicableProperties(stylesheet, object); + if (properties != null) { + if (overriddenProperties != null) { + properties.keySet().removeAll(overriddenProperties.keySet()); + } + DefaultObjectHandler handler = TagManager.getTagHandler(object.getObjectClass()); + for (Map.Entry<String, String> e : properties.entrySet()) { + String value = e.getValue(); + if (value.equals(Rule.INLINE_ATTRIBUTE) || value.equals(Rule.DATA_BINDING)) { + continue; + } + handler.setAttribute(object, e.getKey(), e.getValue(), false, compiler); + } + } + + Rule[] pseudoClasses = getApplicablePseudoClasses(stylesheet, object); + if (pseudoClasses != null) { + Map<String, Map<String, String>> combinedPseudoClasses = new LinkedHashMap<String, Map<String, String>>(); + for (Rule pseudoClass1 : pseudoClasses) { + Selector[] selectors = pseudoClass1.getSelectors(); + for (Selector selector : selectors) { + if (appliesTo(selector, object) == Selector.PSEUDOCLASS_APPLIES) { + properties = pseudoClass1.getProperties(); + String pseudoClass = selector.getPseudoClass(); + // TODO: overrides by downstream pseudoclasses are not handled + Map<String, String> combinedProperties = combinedPseudoClasses.get(pseudoClass); + if (combinedProperties == null) { + combinedProperties = new HashMap<String, String>(); + combinedPseudoClasses.put(pseudoClass, combinedProperties); + } + combinedProperties.putAll(properties); + } + } + } + + int count = 0; + for (Map.Entry<String, Map<String, String>> e : combinedPseudoClasses.entrySet()) { + applyPseudoClass(e.getKey(), e.getValue(), object, compiler, count++); + } + } + } + + /** + * Replaces all references to the variable "object" with the actual object ID. + * + * @param code ? + * @param id ? + * @return ? + * @throws jaxx.CompilerException ? + */ + public static String replaceObjectReferences(String code, String id) throws CompilerException { + JavaParser p = new JavaParser(new StringReader(code + ";")); + p.Expression(); + jaxx.parser.SimpleNode node = p.popNode(); + scanNode(node, id); + return node.getText(); + } + + public static void scanNode(SimpleNode node, String id) { + if (node.getId() == JavaParserTreeConstants.JJTNAME) { + String name = node.getText(); + if (name.equals("object") || (name.indexOf(".") != -1 && name.substring(0, name.indexOf(".")).trim().equals("object"))) { + node.firstToken.image = id; + } + } else { + int count = node.jjtGetNumChildren(); + for (int i = 0; i < count; i++) { + scanNode(node.getChild(i), id); + } + } + } + + public static void compilePseudoClassAdd(String pseudoClass, CompiledObject object, String propertyCode, JAXXCompiler compiler) throws CompilerException { + + if (pseudoClass.startsWith("{")) { + pseudoClass = pseudoClass.substring(1, pseudoClass.length() - 1).trim(); + pseudoClass = replaceObjectReferences(pseudoClass, object.getJavaCode()); + String dest = object.getId() + ".style." + pseudoClass + ".add"; + String destCode = TypeManager.getJavaCode(dest); + if (compiler.haveProcessDataBinding()) { + compiler.appendProcessDataBinding("else "); + } + compiler.appendProcessDataBinding("if ($dest.equals(" + destCode + ")) { if (" + pseudoClass + ") { " + propertyCode + "} }"); + new DataSource(dest, pseudoClass, compiler).compile("new jaxx.runtime.DataBindingListener(" + compiler.getRootObject().getJavaCode() + ", " + destCode + ")"); + compiler.appendInitDataBindings("applyDataBinding(" + destCode + ");"); + return; + } + + MouseEventEnum constant = MouseEventEnum.valueOf(pseudoClass); + + String property = null; + switch (constant) { + case mousedown: + property = "mousePressed"; + break; + case mouseout: + property = "mouseExited"; + break; + case mouseover: + property = "mouseEntered"; + break; + case mouseup: + property = "mouseReleased"; + break; + } + + ClassDescriptor mouseListenerDescriptor = ClassDescriptorLoader.getClassDescriptor(MouseListener.class); + ClassDescriptor mouseEventDescriptor = ClassDescriptorLoader.getClassDescriptor(MouseEvent.class); + + try { + MethodDescriptor addMouseListener = object.getObjectClass().getMethodDescriptor("addMouseListener", mouseListenerDescriptor); + MethodDescriptor methodDescriptor = mouseListenerDescriptor.getMethodDescriptor(property, mouseEventDescriptor); + object.addEventHandler("style." + pseudoClass + ".add", addMouseListener, methodDescriptor, propertyCode, compiler); + + } catch (NoSuchMethodException e) { + compiler.reportError("mouseover pseudoclass cannot be applied to object " + object.getObjectClass().getName() + " (no addMouseListener method)"); + } + + /*if (pseudoClass.equals("mouseover")) { + try { + MethodDescriptor addMouseListener = object.getObjectClass().getMethodDescriptor("addMouseListener", + new ClassDescriptor[]{ClassDescriptorLoader.getClassDescriptor(MouseListener.class)}); + object.addEventHandler("style." + pseudoClass + ".add", addMouseListener, + ClassDescriptorLoader.getClassDescriptor(MouseListener.class).getMethodDescriptor("mouseEntered", + new ClassDescriptor[]{ClassDescriptorLoader.getClassDescriptor(MouseEvent.class)}), + propertyCode, compiler); + } + catch (NoSuchMethodException e) { + compiler.reportError("mouseover pseudoclass cannot be applied to object " + object.getObjectClass().getName() + " (no addMouseListener method)"); + } + } else if (pseudoClass.equals("mouseout")) { + try { + MethodDescriptor addMouseListener = object.getObjectClass().getMethodDescriptor("addMouseListener", + new ClassDescriptor[]{ClassDescriptorLoader.getClassDescriptor(MouseListener.class)}); + object.addEventHandler("style." + pseudoClass + ".add", addMouseListener, + ClassDescriptorLoader.getClassDescriptor(MouseListener.class).getMethodDescriptor("mouseExited", + new ClassDescriptor[]{ClassDescriptorLoader.getClassDescriptor(MouseEvent.class)}), + propertyCode, compiler); + compiler.appendInitDataBindings("{" + propertyCode + "}"); + } + catch (NoSuchMethodException e) { + compiler.reportError("mouseout pseudoclass cannot be applied to object " + object.getObjectClass().getName() + " (no addMouseListener method)"); + } + } else if (pseudoClass.equals("mousedown")) { + try { + MethodDescriptor addMouseListener = object.getObjectClass().getMethodDescriptor("addMouseListener", + new ClassDescriptor[]{ClassDescriptorLoader.getClassDescriptor(MouseListener.class)}); + object.addEventHandler("style." + pseudoClass + ".add", addMouseListener, + ClassDescriptorLoader.getClassDescriptor(MouseListener.class).getMethodDescriptor("mousePressed", + new ClassDescriptor[]{ClassDescriptorLoader.getClassDescriptor(MouseEvent.class)}), + propertyCode, compiler); + } + catch (NoSuchMethodException e) { + compiler.reportError("mousedown pseudoclass cannot be applied to object " + object.getObjectClass().getName() + " (no addMouseListener method)"); + } + } else if (pseudoClass.equals("mouseup")) { + try { + MethodDescriptor addMouseListener = object.getObjectClass().getMethodDescriptor("addMouseListener", + new ClassDescriptor[]{ClassDescriptorLoader.getClassDescriptor(MouseListener.class)}); + object.addEventHandler("style." + pseudoClass + ".add", addMouseListener, + ClassDescriptorLoader.getClassDescriptor(MouseListener.class).getMethodDescriptor("mouseReleased", + new ClassDescriptor[]{ClassDescriptorLoader.getClassDescriptor(MouseEvent.class)}), + propertyCode, compiler); + compiler.appendInitDataBindings("{" + propertyCode + "}"); + } + catch (NoSuchMethodException e) { + compiler.reportError("mouseup pseudoclass cannot be applied to object " + object.getObjectClass().getName() + " (no addMouseListener method)"); + } + } else if (pseudoClass.startsWith("{")) { + pseudoClass = pseudoClass.substring(1, pseudoClass.length() - 1).trim(); + pseudoClass = replaceObjectReferences(pseudoClass, object.getJavaCode()); + String dest = object.getId() + ".style." + pseudoClass + ".add"; + String destCode = TypeManager.getJavaCode(dest); + if (compiler.haveProcessDataBinding()) { + compiler.appendProcessDataBinding("else "); + } + compiler.appendProcessDataBinding("if ($dest.equals(" + destCode + ")) { if (" + pseudoClass + ") { "+ propertyCode + "} }"); + new DataSource(dest, pseudoClass, compiler).compile("new jaxx.runtime.DataBindingListener(" + compiler.getRootObject().getJavaCode() + ", " + destCode + ")"); + compiler.appendInitDataBindings("applyDataBinding("+ destCode + ");"); + } else + throw new IllegalArgumentException("unrecognized pseudoclass: " + pseudoClass);*/ + } + + public static void compilePseudoClassRemove(String pseudoClass, CompiledObject object, String propertyCode, JAXXCompiler compiler) throws CompilerException { + if (pseudoClass.startsWith("{")) { + pseudoClass = pseudoClass.substring(1, pseudoClass.length() - 1).trim(); + pseudoClass = replaceObjectReferences(pseudoClass, object.getJavaCode()); + String dest = object.getId() + ".style." + pseudoClass + ".remove"; + String destCode = TypeManager.getJavaCode(dest); + if (compiler.haveProcessDataBinding()) { + compiler.appendProcessDataBinding("else "); + } + compiler.appendProcessDataBinding("if ($dest.equals(" + destCode + ")) { if (" + invert(pseudoClass) + ") { " + propertyCode + "} }"); + new DataSource(dest, pseudoClass, compiler).compile("new jaxx.runtime.DataBindingListener(" + compiler.getRootObject().getJavaCode() + ", " + destCode + ")"); + compiler.appendInitDataBindings("applyDataBinding(" + destCode + ");"); + return; + } + + MouseEventEnum constant = MouseEventEnum.valueOf(pseudoClass); + + String property = null; + switch (constant) { + case mousedown: + property = "mousePressed"; + break; + case mouseout: + property = "mouseReleased"; + break; + case mouseover: + property = "mouseExited"; + break; + case mouseup: + property = "mousePressed"; + break; + } + + ClassDescriptor mouseListenerDescriptor = ClassDescriptorLoader.getClassDescriptor(MouseListener.class); + ClassDescriptor mouseEventDescriptor = ClassDescriptorLoader.getClassDescriptor(MouseEvent.class); + + try { + MethodDescriptor addMouseListener = object.getObjectClass().getMethodDescriptor("addMouseListener", mouseListenerDescriptor); + MethodDescriptor methodDescriptor = mouseListenerDescriptor.getMethodDescriptor(property, mouseEventDescriptor); + object.addEventHandler("style." + pseudoClass + ".remove", addMouseListener, methodDescriptor, propertyCode, compiler); + + } catch (NoSuchMethodException e) { + compiler.reportError("mouseover pseudoclass cannot be applied to object " + object.getObjectClass().getName() + " (no addMouseListener method)"); + } + + /*if (pseudoClass.equals("mouseover")) { + try { + MethodDescriptor addMouseListener = object.getObjectClass().getMethodDescriptor("addMouseListener", + new ClassDescriptor[]{ClassDescriptorLoader.getClassDescriptor(MouseListener.class)}); + object.addEventHandler("style." + pseudoClass + ".remove", addMouseListener, + ClassDescriptorLoader.getClassDescriptor(MouseListener.class).getMethodDescriptor("mouseExited", + new ClassDescriptor[]{ClassDescriptorLoader.getClassDescriptor(MouseEvent.class)}), + propertyCode, compiler); + } + catch (NoSuchMethodException e) { + compiler.reportError("mouseover pseudoclass cannot be applied to object " + object.getObjectClass().getName() + " (no addMouseListener method)"); + } + } else if (pseudoClass.equals("mouseout")) { + try { + MethodDescriptor addMouseListener = object.getObjectClass().getMethodDescriptor("addMouseListener", + new ClassDescriptor[]{ClassDescriptorLoader.getClassDescriptor(MouseListener.class)}); + object.addEventHandler("style." + pseudoClass + ".remove", addMouseListener, + ClassDescriptorLoader.getClassDescriptor(MouseListener.class).getMethodDescriptor("mouseEntered", + new ClassDescriptor[]{ClassDescriptorLoader.getClassDescriptor(MouseEvent.class)}), + propertyCode, compiler); + } + catch (NoSuchMethodException e) { + compiler.reportError("mouseout pseudoclass cannot be applied to object " + object.getObjectClass().getName() + " (no addMouseListener method)"); + } + } else if (pseudoClass.equals("mousedown")) { + try { + MethodDescriptor addMouseListener = object.getObjectClass().getMethodDescriptor("addMouseListener", + new ClassDescriptor[]{ClassDescriptorLoader.getClassDescriptor(MouseListener.class)}); + object.addEventHandler("style." + pseudoClass + ".remove", addMouseListener, + ClassDescriptorLoader.getClassDescriptor(MouseListener.class).getMethodDescriptor("mouseReleased", + new ClassDescriptor[]{ClassDescriptorLoader.getClassDescriptor(MouseEvent.class)}), + propertyCode, compiler); + } + catch (NoSuchMethodException e) { + compiler.reportError("mousedown pseudoclass cannot be applied to object " + object.getObjectClass().getName() + " (no addMouseListener method)"); + } + } else if (pseudoClass.equals("mouseup")) { + try { + MethodDescriptor addMouseListener = object.getObjectClass().getMethodDescriptor("addMouseListener", + new ClassDescriptor[]{ClassDescriptorLoader.getClassDescriptor(MouseListener.class)}); + object.addEventHandler("style." + pseudoClass + ".remove", addMouseListener, + ClassDescriptorLoader.getClassDescriptor(MouseListener.class).getMethodDescriptor("mousePressed", + new ClassDescriptor[]{ClassDescriptorLoader.getClassDescriptor(MouseEvent.class)}), + propertyCode, compiler); + } + catch (NoSuchMethodException e) { + compiler.reportError("mouseup pseudoclass cannot be applied to object " + object.getObjectClass().getName() + " (no addMouseListener method)"); + } + } else if (pseudoClass.startsWith("{")) { + pseudoClass = pseudoClass.substring(1, pseudoClass.length() - 1).trim(); + pseudoClass = replaceObjectReferences(pseudoClass, object.getJavaCode()); + String dest = object.getId() + ".style." + pseudoClass + ".remove"; + String destCode = TypeManager.getJavaCode(dest); + if (compiler.haveProcessDataBinding()) { + compiler.appendProcessDataBinding("else "); + } + compiler.appendProcessDataBinding("if ($dest.equals(" + destCode + ")) { if (" + invert(pseudoClass) + ") { " + propertyCode + "} }"); + new DataSource(dest, pseudoClass, compiler).compile("new jaxx.runtime.DataBindingListener(" + compiler.getRootObject().getJavaCode() + ", " + destCode + ")"); + compiler.appendInitDataBindings("applyDataBinding(" + destCode + ");"); + } else { + throw new IllegalArgumentException("unrecognized pseudoclass: " + pseudoClass); + }*/ + } + + public static String invert(String javaCode) { + javaCode = javaCode.trim(); + return javaCode.startsWith("!") ? javaCode.substring(1) : "!(" + javaCode + ")"; + } + + public static String unwrap(ClassDescriptor type, String valueCode) { + if (type == ClassDescriptorLoader.getClassDescriptor(boolean.class)) { + return "((java.lang.Boolean) " + valueCode + ").booleanValue()"; + } else if (type == ClassDescriptorLoader.getClassDescriptor(byte.class)) { + return "((java.lang.Byte) " + valueCode + ").byteValue()"; + } else if (type == ClassDescriptorLoader.getClassDescriptor(short.class)) { + return "((java.lang.Short) " + valueCode + ").shortValue()"; + } else if (type == ClassDescriptorLoader.getClassDescriptor(int.class)) { + return "((java.lang.Integer) " + valueCode + ").intValue()"; + } else if (type == ClassDescriptorLoader.getClassDescriptor(long.class)) { + return "((java.lang.Long) " + valueCode + ").longValue()"; + } else if (type == ClassDescriptorLoader.getClassDescriptor(float.class)) { + return "((java.lang.Float) " + valueCode + ").floatValue()"; + } else if (type == ClassDescriptorLoader.getClassDescriptor(double.class)) { + return "((java.lang.Double) " + valueCode + ").doubleValue()"; + } else if (type == ClassDescriptorLoader.getClassDescriptor(char.class)) { + return "((java.lang.Character) " + valueCode + ").charValue()"; + } else { + return valueCode; + } + } + + public static void applyPseudoClass(String pseudoClass, Map<String, String> properties, + CompiledObject object, JAXXCompiler compiler, int priority) throws CompilerException { + if (pseudoClass.indexOf("[") != -1) { + pseudoClass = pseudoClass.substring(0, pseudoClass.indexOf("[")); + } + final StringBuffer buffer = new StringBuffer(); + /*CompiledObject bufferObject = new CompiledObject(object.getId(), object.getJavaCode(), object.getObjectClass(), compiler, true) { + public void appendInitializationCode(String code) { + buffer.append(code); + } + public void registerDataBinding(String src, String property, String assignment, JAXXCompiler compiler) throws CompilerException { + buffer.append(assignment); + } + };*/ + + DefaultObjectHandler handler = TagManager.getTagHandler(object.getObjectClass()); + boolean valueDeclared = false; + for (Map.Entry<String, String> e : properties.entrySet()) { + String property = e.getKey(); + ClassDescriptor type = handler.getPropertyType(object, property, compiler); + String dataBinding = compiler.processDataBindings(e.getValue(), type); + String valueCode; + if (dataBinding != null) { + valueCode = "new jaxx.runtime.css.DataBinding(" + TypeManager.getJavaCode(object.getId() + "." + property + "." + priority) + ")"; + new DataBinding(dataBinding, object.getId() + "." + property + "." + priority, handler.getSetPropertyCode(object.getJavaCode(), + property, "(" + JAXXCompiler.getCanonicalName(type) + ") " + dataBinding, compiler), compiler).compile(false); + } else { + try { + Class typeClass = type != null ? ClassDescriptorLoader.getClass(type.getName(), type.getClassLoader()) : null; + valueCode = TypeManager.getJavaCode(TypeManager.convertFromString(e.getValue(), typeClass)); + } + catch (ClassNotFoundException ex) { + compiler.reportError("could not find class " + type.getName()); + return; + } + } + if (!valueDeclared) { + buffer.append("java.lang.Object "); + valueDeclared = true; + } + buffer.append("value = jaxx.runtime.css.Pseudoclasses.applyProperty(").append(compiler.getOutputClassName()).append(".this, ").append(object.getJavaCode()).append(", ").append(TypeManager.getJavaCode(property)).append(", ").append(valueCode).append(", jaxx.runtime.css.Pseudoclasses.wrap(").append(handler.getGetPropertyCode(object.getJavaCode(), property, compiler)).append("), ").append(priority).append(");").append(JAXXCompiler.getLineSeparator()); + buffer.append("if (!(value instanceof jaxx.runtime.css.DataBinding)) {").append(JAXXCompiler.getLineSeparator()); + String unwrappedValue = unwrap(type, "value"); + buffer.append(" ").append(handler.getSetPropertyCode(object.getJavaCode(), property, "(" + JAXXCompiler.getCanonicalName(type) + + ") " + unwrappedValue, compiler)).append(JAXXCompiler.getLineSeparator()); + buffer.append("}").append(JAXXCompiler.getLineSeparator()); + } + + if (pseudoClass.equals("focused")) { + pseudoClass = "{ object.hasFocus() }"; + } else if (pseudoClass.equals("unfocused")) { + pseudoClass = "{ !object.hasFocus() }"; + } else if (pseudoClass.equals("enabled")) { + pseudoClass = "{ object.isEnabled() }"; + } else if (pseudoClass.equals("disabled")) { + pseudoClass = "{ !object.isEnabled() }"; + } else if (pseudoClass.equals("selected")) { + pseudoClass = "{ object.isSelected() }"; + } else if (pseudoClass.equals("deselected")) { + pseudoClass = "{ !object.isSelected() }"; + } + + compilePseudoClassAdd(pseudoClass, object, buffer.toString(), compiler); + + buffer.setLength(0); + valueDeclared = false; + for (Map.Entry<String, String> e : properties.entrySet()) { + String property = e.getKey(); + ClassDescriptor type = handler.getPropertyType(object, property, compiler); + String dataBinding = compiler.processDataBindings(e.getValue(), type); + String valueCode; + if (dataBinding != null) { + valueCode = "new jaxx.runtime.css.DataBinding(" + TypeManager.getJavaCode(object.getId() + "." + property + "." + priority) + ")"; + new DataBinding(dataBinding, object.getId() + "." + property + "." + priority, handler.getSetPropertyCode(object.getJavaCode(), + property, "(" + JAXXCompiler.getCanonicalName(type) + ") " + dataBinding, compiler), compiler).compile(false); + } else { + try { + Class typeClass = type != null ? ClassDescriptorLoader.getClass(type.getName(), type.getClassLoader()) : null; + valueCode = TypeManager.getJavaCode(TypeManager.convertFromString(e.getValue(), typeClass)); + } + catch (ClassNotFoundException ex) { + compiler.reportError("could not find class " + type.getName()); + return; + } + } + if (!valueDeclared) { + buffer.append("java.lang.Object "); + valueDeclared = true; + } + buffer.append("value = jaxx.runtime.css.Pseudoclasses.removeProperty(").append(compiler.getOutputClassName()).append(".this, ").append(object.getJavaCode()).append(", ").append(TypeManager.getJavaCode(property)).append(", ").append(valueCode).append(", jaxx.runtime.css.Pseudoclasses.wrap(").append(handler.getGetPropertyCode(object.getJavaCode(), property, compiler)).append("), ").append(priority).append(");").append(JAXXCompiler.getLineSeparator()); + buffer.append("if (!(value instanceof jaxx.runtime.css.DataBinding)) {").append(JAXXCompiler.getLineSeparator()); + String unwrappedValue = unwrap(type, "value"); + buffer.append(" ").append(handler.getSetPropertyCode(object.getJavaCode(), property, "(" + JAXXCompiler.getCanonicalName(type) + + ") " + unwrappedValue, compiler)).append(JAXXCompiler.getLineSeparator()); + buffer.append("}").append(JAXXCompiler.getLineSeparator()); + } + compilePseudoClassRemove(pseudoClass, object, buffer.toString(), compiler); + } + + public static Map<String, String> getApplicableProperties(Stylesheet s, CompiledObject object) throws CompilerException { + DefaultObjectHandler handler = TagManager.getTagHandler(object.getObjectClass()); + Map<String, String> result = null; + for (Rule rule : s.getRules()) { + int apply = appliesTo(rule, object); + if (apply == Selector.ALWAYS_APPLIES || apply == Selector.ALWAYS_APPLIES_INHERIT_ONLY) { + if (result == null) { + result = new HashMap<String, String>(); + } + for (Map.Entry<String, String> entry : rule.getProperties().entrySet()) { + String property = entry.getKey(); + if (apply == Selector.ALWAYS_APPLIES || handler.isPropertyInherited(property)) { + result.put(property, entry.getValue()); + } + } + } + } + return result; + } + + public static Rule[] getApplicablePseudoClasses(Stylesheet s, CompiledObject object) throws CompilerException { + List<Rule> result = null; + for (Rule rule : s.getRules()) { + if (appliesTo(rule, object) == Selector.PSEUDOCLASS_APPLIES) { + if (result == null) { + result = new ArrayList<Rule>(); + } + result.add(rule); + } + } + return result != null ? result.toArray(new Rule[result.size()]) : null; + } + + public static Rule inlineAttribute(CompiledObject object, String propertyName, boolean dataBinding) { + Map<String, String> properties = new HashMap<String, String>(); + properties.put(propertyName, dataBinding ? Rule.DATA_BINDING : Rule.INLINE_ATTRIBUTE); + return new Rule(new Selector[]{new Selector(null, null, null, object.getId(), true)}, properties); + } + + public static int appliesTo(Rule rule, CompiledObject object) throws CompilerException { + int appliesTo = Selector.NEVER_APPLIES; + for (Selector selector : rule.getSelectors()) { + appliesTo = Math.max(appliesTo(selector, object), appliesTo); + if (appliesTo == Selector.ALWAYS_APPLIES || appliesTo == Selector.ALWAYS_APPLIES_INHERIT_ONLY) { + break; + } + } + return appliesTo; + } + + public static int appliesTo(Selector selector, CompiledObject object) { + boolean inheritOnly = false; + CompiledObject parent = object; + String javaClassName = selector.getJavaClassName(); + String styleClass = selector.getStyleClass(); + String pseudoClass = selector.getPseudoClass(); + String id = selector.getId(); + + while (parent != null) { + boolean classMatch = (javaClassName == null); + if (!classMatch) { + ClassDescriptor javaClass = parent.getObjectClass(); + do { + String name = javaClass.getName(); + if (name.equals(javaClassName) || name.substring(name.lastIndexOf(".") + 1).equals(javaClassName)) { + classMatch = true; + break; + } + javaClass = javaClass.getSuperclass(); + } + while (javaClass != null); + } + + boolean styleClassMatch = (styleClass == null || styleClass.equals(parent.getStyleClass())); + + String objectId = parent.getId(); + objectId = objectId.substring(objectId.lastIndexOf(".") + 1); + boolean idMatch = (id == null || (' ' + objectId + ' ').indexOf(' ' + id + ' ') > -1); + + if (classMatch && styleClassMatch && idMatch) { + if (pseudoClass != null) { + return inheritOnly ? Selector.PSEUDOCLASS_APPLIES_INHERIT_ONLY : Selector.PSEUDOCLASS_APPLIES; + } else { + return inheritOnly ? Selector.ALWAYS_APPLIES_INHERIT_ONLY : Selector.ALWAYS_APPLIES; + } + } + + parent = parent.getParent(); + inheritOnly = true; + } + return Selector.NEVER_APPLIES; + } + + public enum MouseEventEnum { + mouseover, + mouseout, + mousedown, + mouseup + } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/css/Token.java b/trunk/jaxx-compiler/src/main/java/jaxx/css/Token.java new file mode 100644 index 0000000..bf785d8 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/css/Token.java @@ -0,0 +1,76 @@ +/* Generated By:JavaCC: Do not edit this line. Token.java Version 3.0 */ +package jaxx.css; + +/** Describes the input token stream. */ + +public class Token { + + /** + * An integer that describes the kind of this token. This numbering + * system is determined by JavaCCParser, and a table of these numbers is + * stored in the file ...Constants.java. + */ + public int kind; + + /** + * beginLine and beginColumn describe the position of the first character + * of this token; endLine and endColumn describe the position of the + * last character of this token. + */ + public int beginLine, beginColumn, endLine, endColumn; + + /** The string image of the token. */ + public String image; + + /** + * A reference to the next regular (non-special) token from the input + * stream. If this is the last token from the input stream, or if the + * token manager has not read tokens beyond this one, this field is + * set to null. This is true only if this token is also a regular + * token. Otherwise, see below for a description of the contents of + * this field. + */ + public Token next; + + /** + * This field is used to access special tokens that occur prior to this + * token, but after the immediately preceding regular (non-special) token. + * If there are no such special tokens, this field is set to null. + * When there are more than one such special token, this field refers + * to the last of these special tokens, which in turn refers to the next + * previous special token through its specialToken field, and so on + * until the first special token (whose specialToken field is null). + * The next fields of special tokens refer to other special tokens that + * immediately follow it (without an intervening regular token). If there + * is no such token, this field is null. + */ + public Token specialToken; + + /** Returns the image. */ + public String toString() { + return image; + } + + /** + * Returns a new Token object, by default. However, if you want, you + * can create and return subclass objects based on the value of ofKind. + * Simply add the cases to the switch for all those special cases. + * For example, if you have a subclass of Token called IDToken that + * you want to create if ofKind is ID, simlpy add something like : + * <p/> + * case MyParserConstants.ID : return new IDToken(); + * <p/> + * to the following switch statement. Then you can cast matchedToken + * variable to the appropriate type and use it in your lexical actions. + * + * @param ofKind kind of token + * @return the new token + */ + public static Token newToken(int ofKind) { + switch (ofKind) { + default: + return new Token(); + } + } + +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/css/TokenMgrError.java b/trunk/jaxx-compiler/src/main/java/jaxx/css/TokenMgrError.java new file mode 100644 index 0000000..9c9b1bc --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/css/TokenMgrError.java @@ -0,0 +1,126 @@ +/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 3.0 */ +package jaxx.css; + +public class TokenMgrError extends Error { + /* + * Ordinals for various reasons why an Error of this type can be thrown. + */ + + /** Lexical error occured. */ + static final int LEXICAL_ERROR = 0; + + /** An attempt wass made to create a second instance of a static token manager. */ + static final int STATIC_LEXER_ERROR = 1; + + /** Tried to change to an invalid lexical state. */ + static final int INVALID_LEXICAL_STATE = 2; + + /** Detected (and bailed out of) an infinite loop in the token manager. */ + static final int LOOP_DETECTED = 3; + + /** + * Indicates the reason why the exception is thrown. It will have + * one of the above 4 values. + */ + int errorCode; + private static final long serialVersionUID = -4308847190164230336L; + + /** + * Replaces unprintable characters by their espaced (or unicode escaped) + * equivalents in the given string + * + * @param str text to espace + * @return the espaced text + */ + protected static String addEscapes(String str) { + StringBuffer retval = new StringBuffer(); + char ch; + for (int i = 0; i < str.length(); i++) { + switch (str.charAt(i)) { + case 0: + continue; + case '\b': + retval.append("\\b"); + continue; + case '\t': + retval.append("\\t"); + continue; + case '\n': + retval.append("\\n"); + continue; + case '\f': + retval.append("\\f"); + continue; + case '\r': + retval.append("\\r"); + continue; + case '\"': + retval.append("\\\""); + continue; + case '\'': + retval.append("\\\'"); + continue; + case '\\': + retval.append("\\\\"); + continue; + default: + if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { + String s = "0000" + Integer.toString(ch, 16); + retval.append("\\u").append(s.substring(s.length() - 4, s.length())); + } else { + retval.append(ch); + } + } + } + return retval.toString(); + } + + /** + * @param EOFSeen : indicates if EOF caused the lexicl error + * @param lexState : lexical state in which this error occured + * @param errorLine : line number when the error occured + * @param errorColumn : column number when the error occured + * @param errorAfter : prefix that was seen before this error occured + * @param curChar : the offending character + * Note: You can customize the lexical error message by modifying this method. + * @return a detailed message for the Error when it is thrown by the + * token manager to indicate a lexical error. + */ + protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) { + return ("Lexical error at line " + + errorLine + ", column " + + errorColumn + ". Encountered: " + + (EOFSeen ? "<EOF> " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int) curChar + "), ") + + "after : \"" + addEscapes(errorAfter) + "\""); + } + + /** + * You can also modify the body of this method to customize your error messages. + * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not + * of end-users concern, so you can return something like : + * <p/> + * "Internal Error : Please file a bug report .... " + * <p/> + * from this method for such cases in the release version of your parser. + */ + @Override + public String getMessage() { + return super.getMessage(); + } + + /* + * Constructors of various flavors follow. + */ + + public TokenMgrError() { + } + + public TokenMgrError(String message, int reason) { + super(message); + errorCode = reason; + } + + public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) { + this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason); + } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/introspection/JAXXBeanDescriptor.java b/trunk/jaxx-compiler/src/main/java/jaxx/introspection/JAXXBeanDescriptor.java new file mode 100644 index 0000000..8cc1bbe --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/introspection/JAXXBeanDescriptor.java @@ -0,0 +1,14 @@ +package jaxx.introspection; + +import jaxx.reflect.ClassDescriptor; + +/** + * Mirrors the class <code>java.beans.BeanDescriptor</code>. JAXX uses its own introspector rather than the built-in + * <code>java.beans.Introspector</code> so that it can introspect {@link jaxx.reflect.ClassDescriptor}, + * not just <code>java.lang.Class</code>. + */ +public class JAXXBeanDescriptor extends JAXXFeatureDescriptor { + public JAXXBeanDescriptor(ClassDescriptor beanClass) { + super(beanClass, beanClass.getName()); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/introspection/JAXXBeanInfo.java b/trunk/jaxx-compiler/src/main/java/jaxx/introspection/JAXXBeanInfo.java new file mode 100644 index 0000000..a355bb0 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/introspection/JAXXBeanInfo.java @@ -0,0 +1,36 @@ +package jaxx.introspection; + +/** + * Mirrors the class <code>java.beans.BeanInfo</code>. JAXX uses its own introspector rather than the built-in + * <code>java.beans.Introspector</code> so that it can introspect {@link jaxx.reflect.ClassDescriptor}, + * not just <code>java.lang.Class</code>. + */ +public class JAXXBeanInfo { + private JAXXBeanDescriptor beanDescriptor; + private JAXXPropertyDescriptor[] propertyDescriptors; + private JAXXEventSetDescriptor[] eventSetDescriptors; + + + public JAXXBeanInfo(JAXXBeanDescriptor beanDescriptor, + JAXXPropertyDescriptor[] propertyDescriptors, + JAXXEventSetDescriptor[] eventSetDescriptors) { + this.beanDescriptor = beanDescriptor; + this.propertyDescriptors = propertyDescriptors; + this.eventSetDescriptors = eventSetDescriptors; + } + + + public JAXXBeanDescriptor getJAXXBeanDescriptor() { + return beanDescriptor; + } + + + public JAXXPropertyDescriptor[] getJAXXPropertyDescriptors() { + return propertyDescriptors; + } + + + public JAXXEventSetDescriptor[] getJAXXEventSetDescriptors() { + return eventSetDescriptors; + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/introspection/JAXXEventSetDescriptor.java b/trunk/jaxx-compiler/src/main/java/jaxx/introspection/JAXXEventSetDescriptor.java new file mode 100644 index 0000000..92af3db --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/introspection/JAXXEventSetDescriptor.java @@ -0,0 +1,39 @@ +package jaxx.introspection; + +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.MethodDescriptor; + +/** + * Mirrors the class <code>java.beans.EventSetDescriptor</code>. JAXX uses its own introspector rather than the built-in + * <code>java.beans.Introspector</code> so that it can introspect {@link jaxx.reflect.ClassDescriptor}, + * not just <code>java.lang.Class</code>. + */ +public class JAXXEventSetDescriptor extends JAXXFeatureDescriptor { + private MethodDescriptor addListenerMethod; + private MethodDescriptor removeListenerMethod; + private MethodDescriptor[] listenerMethods; + + + public JAXXEventSetDescriptor(ClassDescriptor classDescriptor, String name, MethodDescriptor addListenerMethod, + MethodDescriptor removeListenerMethod, MethodDescriptor[] listenerMethods) { + super(classDescriptor, name); + this.addListenerMethod = addListenerMethod; + this.removeListenerMethod = removeListenerMethod; + this.listenerMethods = listenerMethods; + } + + + public MethodDescriptor getAddListenerMethod() { + return addListenerMethod; + } + + + public MethodDescriptor getRemoveListenerMethod() { + return removeListenerMethod; + } + + + public MethodDescriptor[] getListenerMethods() { + return listenerMethods; + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/introspection/JAXXFeatureDescriptor.java b/trunk/jaxx-compiler/src/main/java/jaxx/introspection/JAXXFeatureDescriptor.java new file mode 100644 index 0000000..49ba384 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/introspection/JAXXFeatureDescriptor.java @@ -0,0 +1,55 @@ +package jaxx.introspection; + +import jaxx.reflect.ClassDescriptor; + +import java.util.HashMap; +import java.util.Map; + +/** + * Mirrors the class <code>java.beans.FeatureDescriptor</code>. JAXX uses its own introspector rather than the built-in + * <code>java.beans.Introspector</code> so that it can introspect {@link jaxx.reflect.ClassDescriptor}, + * not just <code>java.lang.Class</code>. + */ +public class JAXXFeatureDescriptor { + private String name; + private Map<String, Object> values; + private ClassDescriptor classDescriptor; + + + JAXXFeatureDescriptor(ClassDescriptor classDescriptor, String name) { + if (name == null || classDescriptor == null) + throw new NullPointerException(); + this.name = name; + this.classDescriptor = classDescriptor; + } + + + public String getName() { + return name; + } + + + public ClassDescriptor getClassDescriptor() { + return classDescriptor; + } + + + public Object getValue(String key) { + return values != null ? values.get(key) : null; + } + + + public void setValue(String key, Object value) { + if (values == null) + values = new HashMap<String, Object>(); + values.put(key, value); + } + + + public static String capitalize(String name) { + if (name.length() == 0) + return name; + else + return Character.toUpperCase(name.charAt(0)) + name.substring(1); + } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/introspection/JAXXIntrospector.java b/trunk/jaxx-compiler/src/main/java/jaxx/introspection/JAXXIntrospector.java new file mode 100644 index 0000000..92d43f8 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/introspection/JAXXIntrospector.java @@ -0,0 +1,176 @@ +package jaxx.introspection; + +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.reflect.MethodDescriptor; + +import java.beans.BeanDescriptor; +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyChangeListener; +import java.beans.PropertyDescriptor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Enumeration; +import java.util.EventListener; +import java.util.HashMap; +import java.util.Map; + +/** + * Performs introspection on a <code>ClassDescriptor</code>. Ideally, I could just have copied Sun's Introspector + * and changed a few things, but the licensing terms are incompatible. This implementation is incomplete -- it only + * bothers to report info that JAXX actually checks. It also relaxes some of Introspector's rules a bit, but I + * don't believe it results in any meaningful incompatibilities. + * <p/> + * JAXX uses its own introspector rather than the built-in + * <code>java.beans.Introspector</code> so that it can introspect {@link jaxx.reflect.ClassDescriptor}, + * not just <code>java.lang.Class</code>. + */ +public class JAXXIntrospector { + private ClassDescriptor classDescriptor; + private Map<String, JAXXPropertyDescriptor> propertyDescriptors = new HashMap<String, JAXXPropertyDescriptor>(); + private Map<String, JAXXEventSetDescriptor> eventSetDescriptors = new HashMap<String, JAXXEventSetDescriptor>(); + + private JAXXIntrospector(ClassDescriptor classDescriptor) { + this.classDescriptor = classDescriptor; + } + + + /** + * Returns the <code>JAXXBeanInfo</code> for a given class. + * + * @param classDescriptor the class to introspect + * @return the <code>JAXXBeanInfo</code> for the bean class + * @throws IntrospectionException if an error occurs + */ + public static JAXXBeanInfo getJAXXBeanInfo(ClassDescriptor classDescriptor) throws IntrospectionException { + JAXXIntrospector introspector = new JAXXIntrospector(classDescriptor); + return introspector.createBeanInfo(); + } + + + private JAXXBeanInfo createBeanInfo() { + ClassDescriptor explicitInfoClass = classDescriptor; + BeanInfo explicitBeanInfo = null; + while (explicitInfoClass != null) { + explicitBeanInfo = getExplicitBeanInfo(explicitInfoClass); + if (explicitBeanInfo != null) + break; + explicitInfoClass = explicitInfoClass.getSuperclass(); + } + + if (explicitBeanInfo != null) { + PropertyDescriptor[] explicitProperties = explicitBeanInfo.getPropertyDescriptors(); + for (PropertyDescriptor explicitProperty : explicitProperties) { + Class type = explicitProperty.getPropertyType(); + Method readMethod = explicitProperty.getReadMethod(); + Method writeMethod = explicitProperty.getWriteMethod(); + try { + ClassDescriptor typeDescriptor = ClassDescriptorLoader.getClassDescriptor(type.getName(), type.getClassLoader()); + JAXXPropertyDescriptor propertyDescriptor = new JAXXPropertyDescriptor(classDescriptor, explicitProperty.getName(), + readMethod != null ? classDescriptor.getMethodDescriptor(readMethod.getName()) : null, + writeMethod != null ? classDescriptor.getMethodDescriptor(writeMethod.getName(), typeDescriptor) : null); + propertyDescriptor.setBound(explicitProperty.isBound()); + Enumeration<String> attributeNames = explicitProperty.attributeNames(); + while (attributeNames.hasMoreElements()) { + String name = attributeNames.nextElement(); + propertyDescriptor.setValue(name, explicitProperty.getValue(name)); + } + propertyDescriptors.put(propertyDescriptor.getName(), propertyDescriptor); + } + catch (ClassNotFoundException e) { + throw new RuntimeException("Internal error: Could not find ClassDescriptor corresponding to Java " + type, e); + } + catch (NoSuchMethodException e) { + throw new RuntimeException("Internal error: Could not find expected MethodDescriptor in " + classDescriptor, e); + } + } + } + + // if the class broadcasts PropertyChangeEvent, assume all properties are bound (java.beans.Introspector + // does the same) + boolean propertyChangeSource; + try { + classDescriptor.getMethodDescriptor("addPropertyChangeListener", ClassDescriptorLoader.getClassDescriptor(PropertyChangeListener.class)); + propertyChangeSource = true; + } + catch (NoSuchMethodException e) { + propertyChangeSource = false; + } + + MethodDescriptor[] methods = classDescriptor.getMethodDescriptors(); + for (MethodDescriptor method : methods) { + String name = method.getName(); + if (name.startsWith("get") && name.length() > 3 && Character.isUpperCase(name.charAt(3)) && method.getParameterTypes().length == 0) { + String propertyName = Introspector.decapitalize(name.substring(3)); + if (!propertyDescriptors.containsKey(propertyName)) + propertyDescriptors.put(propertyName, new JAXXPropertyDescriptor(classDescriptor, propertyName, method, null, propertyChangeSource)); + } else + if (name.startsWith("is") && name.length() > 2 && Character.isUpperCase(name.charAt(2)) && method.getParameterTypes().length == 0) { + String propertyName = Introspector.decapitalize(name.substring(2)); + if (!propertyDescriptors.containsKey(propertyName)) + propertyDescriptors.put(propertyName, new JAXXPropertyDescriptor(classDescriptor, propertyName, method, null, propertyChangeSource)); + } else + if (name.startsWith("set") && name.length() > 3 && Character.isUpperCase(name.charAt(3)) && method.getParameterTypes().length == 1) { + String propertyName = Introspector.decapitalize(name.substring(3)); + if (!propertyDescriptors.containsKey(propertyName)) + propertyDescriptors.put(propertyName, new JAXXPropertyDescriptor(classDescriptor, propertyName, null, method, propertyChangeSource)); + } else + if (name.startsWith("add") && name.length() > 3 && Character.isUpperCase(name.charAt(3))) { + ClassDescriptor[] parameters = method.getParameterTypes(); + if (parameters.length != 1 || !ClassDescriptorLoader.getClassDescriptor(EventListener.class).isAssignableFrom(parameters[0])) + continue; // not an event listener method + try { + String eventSetName = method.getName().substring(3); + MethodDescriptor remove = classDescriptor.getMethodDescriptor("remove" + eventSetName, parameters); + eventSetDescriptors.put(eventSetName, new JAXXEventSetDescriptor(classDescriptor, eventSetName, method, remove, parameters[0].getMethodDescriptors())); + } + catch (NoSuchMethodException e) { + // no matching remove method, not a valid event + } + } + } + + JAXXBeanDescriptor beanDescriptor = new JAXXBeanDescriptor(classDescriptor); + if (explicitBeanInfo != null) { + BeanDescriptor explicitBeanDescriptor = explicitBeanInfo.getBeanDescriptor(); + if (explicitBeanDescriptor != null) { + Enumeration/*<String>*/ attributeNames = explicitBeanDescriptor.attributeNames(); + while (attributeNames.hasMoreElements()) { + String name = (String) attributeNames.nextElement(); + beanDescriptor.setValue(name, explicitBeanDescriptor.getValue(name)); + } + } + } + + return new JAXXBeanInfo(beanDescriptor, + propertyDescriptors.values().toArray(new JAXXPropertyDescriptor[propertyDescriptors.size()]), + eventSetDescriptors.values().toArray(new JAXXEventSetDescriptor[eventSetDescriptors.size()])); + } + + + private static BeanInfo getExplicitBeanInfo(ClassDescriptor classDescriptor) { + try { + Class beanClass = Class.forName(classDescriptor.getName(), true, classDescriptor.getClassLoader()); // see if there is a class by that name in this package + Method findExplicitBeanInfo = Introspector.class.getDeclaredMethod("findExplicitBeanInfo", new Class[]{Class.class}); + findExplicitBeanInfo.setAccessible(true); + return (BeanInfo) findExplicitBeanInfo.invoke(null, beanClass); + } + catch (ClassNotFoundException e) { + return null; // happens for uncompiled classes + } + catch (NoClassDefFoundError e) { + return null; // wrong case, etc. + } + catch (NoSuchMethodException e) { + throw new RuntimeException("Error: could not find method 'findExplicitBeanInfo' in java.beans.Introspector. You are most likely running a version of Java against which JAXX has not been tested."); + } + catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/introspection/JAXXPropertyDescriptor.java b/trunk/jaxx-compiler/src/main/java/jaxx/introspection/JAXXPropertyDescriptor.java new file mode 100644 index 0000000..61b504c --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/introspection/JAXXPropertyDescriptor.java @@ -0,0 +1,96 @@ +package jaxx.introspection; + +import jaxx.CompilerException; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.MethodDescriptor; + +/** + * Mirrors the class <code>java.beans.PropertyDescriptor</code>. JAXX uses its own introspector rather than the built-in + * <code>java.beans.Introspector</code> so that it can introspect {@link jaxx.reflect.ClassDescriptor}, + * not just <code>java.lang.Class</code>. + */ +public class JAXXPropertyDescriptor extends JAXXFeatureDescriptor { + private ClassDescriptor propertyType; + private MethodDescriptor readMethod; + private MethodDescriptor writeMethod; + private boolean bound; + + public JAXXPropertyDescriptor(ClassDescriptor classDescriptor, String propertyName) { + this(classDescriptor, propertyName, null, null); + } + + + public JAXXPropertyDescriptor(ClassDescriptor classDescriptor, String propertyName, + MethodDescriptor readMethod, MethodDescriptor writeMethod) { + this(classDescriptor, propertyName, readMethod, writeMethod, false); + } + + + public JAXXPropertyDescriptor(ClassDescriptor classDescriptor, String propertyName, + MethodDescriptor readMethod, MethodDescriptor writeMethod, + boolean bound) { + super(classDescriptor, propertyName); + this.readMethod = readMethod; + this.writeMethod = writeMethod; + this.bound = bound; + } + + + public MethodDescriptor getReadMethodDescriptor() { + if (readMethod == null) { + try { + readMethod = getClassDescriptor().getMethodDescriptor("get" + capitalize(getName())); + } + catch (NoSuchMethodException e) { + try { + readMethod = getClassDescriptor().getMethodDescriptor("is" + capitalize(getName())); + } + catch (NoSuchMethodException e2) { + } + } + } + return readMethod; + } + + + public MethodDescriptor getWriteMethodDescriptor() { + if (writeMethod == null) { + try { + String methodName = "set" + capitalize(getName()); + MethodDescriptor read = getReadMethodDescriptor(); + if (read != null) { + writeMethod = getClassDescriptor().getMethodDescriptor(methodName, read.getReturnType()); + } else { + throw new CompilerException("Internal error: requesting 'set' method for property of unknown type: '" + getName() + "' (in " + getClassDescriptor() + ")"); + } + } + catch (NoSuchMethodException e) { + } + } + return writeMethod; + } + + + public ClassDescriptor getPropertyType() { + if (propertyType == null) { + MethodDescriptor read = getReadMethodDescriptor(); + if (read != null) + propertyType = read.getReturnType(); + else { + MethodDescriptor write = getWriteMethodDescriptor(); + propertyType = write.getParameterTypes()[0]; + } + } + return propertyType; + } + + + public boolean isBound() { + return bound; + } + + + public void setBound(boolean bound) { + this.bound = bound; + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/parser/JJTJavaParserState.java b/trunk/jaxx-compiler/src/main/java/jaxx/parser/JJTJavaParserState.java new file mode 100644 index 0000000..b726fbb --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/parser/JJTJavaParserState.java @@ -0,0 +1,123 @@ +/* Generated By:JJTree: Do not edit this line. .\JJTJavaParserState.java */ + +package jaxx.parser; + +class JJTJavaParserState { + private java.util.Stack<Node> nodes; + private java.util.Stack<Integer> marks; + + private int sp; // number of nodes on stack + private int mk; // current mark + private boolean node_created; + + JJTJavaParserState() { + nodes = new java.util.Stack<Node>(); + marks = new java.util.Stack<Integer>(); + sp = 0; + mk = 0; + } + + /* Determines whether the current node was actually closed and + pushed. This should only be called in the final user action of a + node scope. */ + boolean nodeCreated() { + return node_created; + } + + /* Call this to reinitialize the node stack. It is called +automatically by the parser's ReInit() method. */ + void reset() { + nodes.removeAllElements(); + marks.removeAllElements(); + sp = 0; + mk = 0; + } + + /* Returns the root node of the AST. It only makes sense to call +this after a successful parse. */ + Node rootNode() { + return nodes.elementAt(0); + } + + /* Pushes a node on to the stack. */ + void pushNode(Node n) { + nodes.push(n); + ++sp; + } + + /* Returns the node on the top of the stack, and remove it from the + stack. */ + Node popNode() { + if (--sp < mk) { + mk = marks.pop(); + } + return nodes.pop(); + } + + /* Returns the node currently on the top of the stack. */ + Node peekNode() { + return nodes.peek(); + } + + /* Returns the number of children on the stack in the current node + scope. */ + int nodeArity() { + return sp - mk; + } + + + void clearNodeScope(Node n) { + while (sp > mk) { + popNode(); + } + mk = marks.pop(); + } + + + void openNodeScope(Node n) { + marks.push(mk); + mk = sp; + n.jjtOpen(); + } + + + /* A definite node is constructed from a specified number of +children. That number of nodes are popped from the stack and +made the children of the definite node. Then the definite node +is pushed on to the stack. */ + void closeNodeScope(Node n, int num) { + mk = marks.pop(); + while (num-- > 0) { + Node c = popNode(); + c.jjtSetParent(n); + n.jjtAddChild(c, num); + } + n.jjtClose(); + pushNode(n); + node_created = true; + } + + + /* A conditional node is constructed if its condition is true. All +the nodes that have been pushed since the node was opened are +made children of the the conditional node, which is then pushed +on to the stack. If the condition is false the node is not +constructed and they are left on the stack. */ + void closeNodeScope(Node n, boolean condition) { + if (condition) { + int a = nodeArity(); + mk = marks.pop(); + while (a-- > 0) { + Node c = popNode(); + c.jjtSetParent(n); + n.jjtAddChild(c, a); + } + n.jjtClose(); + pushNode(n); + node_created = true; + } else { + mk = marks.pop(); + node_created = false; + } + } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/parser/Java1.5.jj b/trunk/jaxx-compiler/src/main/java/jaxx/parser/Java1.5.jj new file mode 100644 index 0000000..96d01d3 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/parser/Java1.5.jj @@ -0,0 +1,5125 @@ +/*@bgen(jjtree) Generated By:JJTree: Do not edit this line. ./Java1.5.jj */ +/*@egen*/ +/* + * Copyright \u00a9 2002 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * California 95054, U.S.A. All rights reserved. Sun Microsystems, Inc. has + * intellectual property rights relating to technology embodied in the product + * that is described in this document. In particular, and without limitation, + * these intellectual property rights may include one or more of the U.S. + * patents listed at http://www.sun.com/patents and one or more additional + * patents or pending patent applications in the U.S. and in other countries. + * U.S. Government Rights - Commercial software. Government users are subject + * to the Sun Microsystems, Inc. standard license agreement and applicable + * provisions of the FAR and its supplements. Use is subject to license terms. + * Sun, Sun Microsystems, the Sun logo and Java are trademarks or registered + * trademarks of Sun Microsystems, Inc. in the U.S. and other countries. This + * product is covered and controlled by U.S. Export Control laws and may be + * subject to the export or import laws in other countries. Nuclear, missile, + * chemical biological weapons or nuclear maritime end uses or end users, + * whether direct or indirect, are strictly prohibited. Export or reexport + * to countries subject to U.S. embargo or to entities identified on U.S. + * export exclusion lists, including, but not limited to, the denied persons + * and specially designated nationals lists is strictly prohibited. + */ + +// Slightly modified version of javacc's reference 1.5 grammar, tweaked for +// usage with JAXX. There are two main areas of changes: several new +// nonterminals were added to make identifying certain constructs easier, +// and the Line nonterminal was added to support JAXX's script tags. +// Several of the new changes are inefficient and require excess lookahead, +// but at this point I'd rather have inefficiency than risk breaking it during +// attempted optimizations. + +options { + JAVA_UNICODE_ESCAPE = true; + ERROR_REPORTING = false; + STATIC = false; + JDK_VERSION = "1.4"; +} + +PARSER_BEGIN(JavaParser) +package jaxx.parser; + +import java.io.*; + +/** + * Grammar to parse Java version 1.5 + * @author Sreenivasa Viswanadha - Simplified and enhanced for 1.5 + */ +public class JavaParser/*@bgen(jjtree)*/implements JavaParserTreeConstants/*@egen*/ +{/*@bgen(jjtree)*/ + protected JJTJavaParserState jjtree = new JJTJavaParserState(); + +/*@egen*/ + /** + * Class to hold modifiers. + */ + static public final class ModifierSet + { + /* Definitions of the bits in the modifiers field. */ + public static final int PUBLIC = 0x0001; + public static final int PROTECTED = 0x0002; + public static final int PRIVATE = 0x0004; + public static final int ABSTRACT = 0x0008; + public static final int STATIC = 0x0010; + public static final int FINAL = 0x0020; + public static final int SYNCHRONIZED = 0x0040; + public static final int NATIVE = 0x0080; + public static final int TRANSIENT = 0x0100; + public static final int VOLATILE = 0x0200; + public static final int STRICTFP = 0x1000; + + /** A set of accessors that indicate whether the specified modifier + is in the set. */ + + public boolean isPublic(int modifiers) + { + return (modifiers & PUBLIC) != 0; + } + + public boolean isProtected(int modifiers) + { + return (modifiers & PROTECTED) != 0; + } + + public boolean isPrivate(int modifiers) + { + return (modifiers & PRIVATE) != 0; + } + + public boolean isStatic(int modifiers) + { + return (modifiers & STATIC) != 0; + } + + public boolean isAbstract(int modifiers) + { + return (modifiers & ABSTRACT) != 0; + } + + public boolean isFinal(int modifiers) + { + return (modifiers & FINAL) != 0; + } + + public boolean isNative(int modifiers) + { + return (modifiers & NATIVE) != 0; + } + + public boolean isStrictfp(int modifiers) + { + return (modifiers & STRICTFP) != 0; + } + + public boolean isSynchronized(int modifiers) + { + return (modifiers & SYNCHRONIZED) != 0; + } + + public boolean isTransient(int modifiers) + { + return (modifiers & TRANSIENT) != 0; + } + + public boolean isVolatile(int modifiers) + { + return (modifiers & VOLATILE) != 0; + } + + /** + * Removes the given modifier. + */ + static int removeModifier(int modifiers, int mod) + { + return modifiers & ~mod; + } + } + + public JavaParser(String fileName) + { + this(System.in); + try { ReInit(new FileInputStream(new File(fileName))); } + catch(Exception e) { e.printStackTrace(); } + } + + void jjtreeOpenNodeScope(Node n) { + ((SimpleNode) n).firstToken = getToken(1); + } + + void jjtreeCloseNodeScope(Node n) { + ((SimpleNode) n).lastToken = getToken(0); + } + + public SimpleNode popNode() + { + if ( jjtree.nodeArity() > 0) // number of child nodes + return (SimpleNode)jjtree.popNode(); + else + return null; + } + public static void main(String args[]) { + JavaParser parser; + if (args.length == 0) { + System.out.println("Java Parser Version 1.1: Reading from standard input . . ."); + parser = new JavaParser(System.in); + } else if (args.length == 1) { + System.out.println("Java Parser Version 1.1: Reading from file " + args[0] + " . . ."); + try { + parser = new JavaParser(new java.io.FileInputStream(args[0])); + } catch (java.io.FileNotFoundException e) { + System.out.println("Java Parser Version 1.1: File " + args[0] + " not found."); + return; + } + } else { + System.out.println("Java Parser Version 1.1: Usage is one of:"); + System.out.println(" java JavaParser < inputfile"); + System.out.println("OR"); + System.out.println(" java JavaParser inputfile"); + return; + } + try { + parser.CompilationUnit(); + System.out.println("Java Parser Version 1.1: Java program parsed successfully."); + } catch (ParseException e) { + System.out.println(e.getMessage()); + System.out.println("Java Parser Version 1.1: Encountered errors during parse."); + } + } + +} + +PARSER_END(JavaParser) + +/* COMMENTS */ + +MORE : +{ + <"/**" ~["/"]> { input_stream.backup(1); } : IN_FORMAL_COMMENT +| + "/*" : IN_MULTI_LINE_COMMENT +} + +SPECIAL_TOKEN: +{ + <WHITE_SPACE: ([" ", "\n", "\r", "\t", "\f"])+> +} + +SPECIAL_TOKEN : +{ + <SINGLE_LINE_COMMENT: "//" (~["\n", "\r"])* ("\n" | "\r" | "\r\n")?> +} + +<IN_FORMAL_COMMENT> +SPECIAL_TOKEN : +{ + <FORMAL_COMMENT: "*/" > : DEFAULT +} + +<IN_MULTI_LINE_COMMENT> +SPECIAL_TOKEN : +{ + <MULTI_LINE_COMMENT: "*/" > : DEFAULT +} + +<IN_FORMAL_COMMENT,IN_MULTI_LINE_COMMENT> +MORE : +{ + < ~[] > +} + +/* RESERVED WORDS AND LITERALS */ + +TOKEN : +{ + < ABSTRACT: "abstract" > +| < ASSERT: "assert" > +| < BOOLEAN: "boolean" > +| < BREAK: "break" > +| < BYTE: "byte" > +| < CASE: "case" > +| < CATCH: "catch" > +| < CHAR: "char" > +| < CLASS: "class" > +| < CONST: "const" > +| < CONTINUE: "continue" > +| < _DEFAULT: "default" > +| < DO: "do" > +| < DOUBLE: "double" > +| < ELSE: "else" > +| < ENUM: "enum" > +| < EXTENDS: "extends" > +| < FALSE: "false" > +| < FINAL: "final" > +| < FINALLY: "finally" > +| < FLOAT: "float" > +| < FOR: "for" > +| < GOTO: "goto" > +| < IF: "if" > +| < IMPLEMENTS: "implements" > +| < IMPORT: "import" > +| < INSTANCEOF: "instanceof" > +| < INT: "int" > +| < INTERFACE: "interface" > +| < LONG: "long" > +| < NATIVE: "native" > +| < NEW: "new" > +| < NULL: "null" > +| < PACKAGE: "package"> +| < PRIVATE: "private" > +| < PROTECTED: "protected" > +| < PUBLIC: "public" > +| < RETURN: "return" > +| < SHORT: "short" > +| < STATIC: "static" > +| < STRICTFP: "strictfp" > +| < SUPER: "super" > +| < SWITCH: "switch" > +| < SYNCHRONIZED: "synchronized" > +| < THIS: "this" > +| < THROW: "throw" > +| < THROWS: "throws" > +| < TRANSIENT: "transient" > +| < TRUE: "true" > +| < TRY: "try" > +| < VOID: "void" > +| < VOLATILE: "volatile" > +| < WHILE: "while" > +} + +/* LITERALS */ + +TOKEN : +{ + < INTEGER_LITERAL: + <DECIMAL_LITERAL> (["l","L"])? + | <HEX_LITERAL> (["l","L"])? + | <OCTAL_LITERAL> (["l","L"])? + > +| + < #DECIMAL_LITERAL: ["1"-"9"] (["0"-"9"])* > +| + < #HEX_LITERAL: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ > +| + < #OCTAL_LITERAL: "0" (["0"-"7"])* > +| + < FLOATING_POINT_LITERAL: + <DECIMAL_FLOATING_POINT_LITERAL> + | <HEXADECIMAL_FLOATING_POINT_LITERAL> + > +| + < #DECIMAL_FLOATING_POINT_LITERAL: + (["0"-"9"])+ "." (["0"-"9"])* (<DECIMAL_EXPONENT>)? (["f","F","d","D"])? + | "." (["0"-"9"])+ (<DECIMAL_EXPONENT>)? (["f","F","d","D"])? + | (["0"-"9"])+ <DECIMAL_EXPONENT> (["f","F","d","D"])? + | (["0"-"9"])+ (<DECIMAL_EXPONENT>)? ["f","F","d","D"] + > +| + < #DECIMAL_EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ > +| + < #HEXADECIMAL_FLOATING_POINT_LITERAL: + "0" ["x", "X"] (["0"-"9","a"-"f","A"-"F"])+ (".")? <HEXADECIMAL_EXPONENT> (["f","F","d","D"])? + | "0" ["x", "X"] (["0"-"9","a"-"f","A"-"F"])* "." (["0"-"9","a"-"f","A"-"F"])+ <HEXADECIMAL_EXPONENT> (["f","F","d","D"])? + > +| + < #HEXADECIMAL_EXPONENT: ["p","P"] (["+","-"])? (["0"-"9"])+ > +| + < CHARACTER_LITERAL: + "'" + ( (~["'","\\","\n","\r"]) + | ("\\" + ( ["n","t","b","r","f","\\","'","\""] + | ["0"-"7"] ( ["0"-"7"] )? + | ["0"-"3"] ["0"-"7"] ["0"-"7"] + ) + ) + ) + "'" + > +| + < STRING_LITERAL: + "\"" + ( (~["\"","\\","\n","\r"]) + | ("\\" + ( ["n","t","b","r","f","\\","'","\""] + | ["0"-"7"] ( ["0"-"7"] )? + | ["0"-"3"] ["0"-"7"] ["0"-"7"] + ) + ) + )* + "\"" + > +} + +/* IDENTIFIERS */ + +TOKEN : +{ + < IDENTIFIER: <LETTER> (<PART_LETTER>)* > +| + < #LETTER: + [ // all chars for which Character.isIdentifierStart is true + "$", + "A"-"Z", + "_", + "a"-"z", + "\u00a2"-"\u00a5", + "\u00aa", + "\u00b5", + "\u00ba", + "\u00c0"-"\u00d6", + "\u00d8"-"\u00f6", + "\u00f8"-"\u021f", + "\u0222"-"\u0233", + "\u0250"-"\u02ad", + "\u02b0"-"\u02b8", + "\u02bb"-"\u02c1", + "\u02d0"-"\u02d1", + "\u02e0"-"\u02e4", + "\u02ee", + "\u037a", + "\u0386", + "\u0388"-"\u038a", + "\u038c", + "\u038e"-"\u03a1", + "\u03a3"-"\u03ce", + "\u03d0"-"\u03d7", + "\u03da"-"\u03f3", + "\u0400"-"\u0481", + "\u048c"-"\u04c4", + "\u04c7"-"\u04c8", + "\u04cb"-"\u04cc", + "\u04d0"-"\u04f5", + "\u04f8"-"\u04f9", + "\u0531"-"\u0556", + "\u0559", + "\u0561"-"\u0587", + "\u05d0"-"\u05ea", + "\u05f0"-"\u05f2", + "\u0621"-"\u063a", + "\u0640"-"\u064a", + "\u0671"-"\u06d3", + "\u06d5", + "\u06e5"-"\u06e6", + "\u06fa"-"\u06fc", + "\u0710", + "\u0712"-"\u072c", + "\u0780"-"\u07a5", + "\u0905"-"\u0939", + "\u093d", + "\u0950", + "\u0958"-"\u0961", + "\u0985"-"\u098c", + "\u098f"-"\u0990", + "\u0993"-"\u09a8", + "\u09aa"-"\u09b0", + "\u09b2", + "\u09b6"-"\u09b9", + "\u09dc"-"\u09dd", + "\u09df"-"\u09e1", + "\u09f0"-"\u09f3", + "\u0a05"-"\u0a0a", + "\u0a0f"-"\u0a10", + "\u0a13"-"\u0a28", + "\u0a2a"-"\u0a30", + "\u0a32"-"\u0a33", + "\u0a35"-"\u0a36", + "\u0a38"-"\u0a39", + "\u0a59"-"\u0a5c", + "\u0a5e", + "\u0a72"-"\u0a74", + "\u0a85"-"\u0a8b", + "\u0a8d", + "\u0a8f"-"\u0a91", + "\u0a93"-"\u0aa8", + "\u0aaa"-"\u0ab0", + "\u0ab2"-"\u0ab3", + "\u0ab5"-"\u0ab9", + "\u0abd", + "\u0ad0", + "\u0ae0", + "\u0b05"-"\u0b0c", + "\u0b0f"-"\u0b10", + "\u0b13"-"\u0b28", + "\u0b2a"-"\u0b30", + "\u0b32"-"\u0b33", + "\u0b36"-"\u0b39", + "\u0b3d", + "\u0b5c"-"\u0b5d", + "\u0b5f"-"\u0b61", + "\u0b85"-"\u0b8a", + "\u0b8e"-"\u0b90", + "\u0b92"-"\u0b95", + "\u0b99"-"\u0b9a", + "\u0b9c", + "\u0b9e"-"\u0b9f", + "\u0ba3"-"\u0ba4", + "\u0ba8"-"\u0baa", + "\u0bae"-"\u0bb5", + "\u0bb7"-"\u0bb9", + "\u0c05"-"\u0c0c", + "\u0c0e"-"\u0c10", + "\u0c12"-"\u0c28", + "\u0c2a"-"\u0c33", + "\u0c35"-"\u0c39", + "\u0c60"-"\u0c61", + "\u0c85"-"\u0c8c", + "\u0c8e"-"\u0c90", + "\u0c92"-"\u0ca8", + "\u0caa"-"\u0cb3", + "\u0cb5"-"\u0cb9", + "\u0cde", + "\u0ce0"-"\u0ce1", + "\u0d05"-"\u0d0c", + "\u0d0e"-"\u0d10", + "\u0d12"-"\u0d28", + "\u0d2a"-"\u0d39", + "\u0d60"-"\u0d61", + "\u0d85"-"\u0d96", + "\u0d9a"-"\u0db1", + "\u0db3"-"\u0dbb", + "\u0dbd", + "\u0dc0"-"\u0dc6", + "\u0e01"-"\u0e30", + "\u0e32"-"\u0e33", + "\u0e3f"-"\u0e46", + "\u0e81"-"\u0e82", + "\u0e84", + "\u0e87"-"\u0e88", + "\u0e8a", + "\u0e8d", + "\u0e94"-"\u0e97", + "\u0e99"-"\u0e9f", + "\u0ea1"-"\u0ea3", + "\u0ea5", + "\u0ea7", + "\u0eaa"-"\u0eab", + "\u0ead"-"\u0eb0", + "\u0eb2"-"\u0eb3", + "\u0ebd", + "\u0ec0"-"\u0ec4", + "\u0ec6", + "\u0edc"-"\u0edd", + "\u0f00", + "\u0f40"-"\u0f47", + "\u0f49"-"\u0f6a", + "\u0f88"-"\u0f8b", + "\u1000"-"\u1021", + "\u1023"-"\u1027", + "\u1029"-"\u102a", + "\u1050"-"\u1055", + "\u10a0"-"\u10c5", + "\u10d0"-"\u10f6", + "\u1100"-"\u1159", + "\u115f"-"\u11a2", + "\u11a8"-"\u11f9", + "\u1200"-"\u1206", + "\u1208"-"\u1246", + "\u1248", + "\u124a"-"\u124d", + "\u1250"-"\u1256", + "\u1258", + "\u125a"-"\u125d", + "\u1260"-"\u1286", + "\u1288", + "\u128a"-"\u128d", + "\u1290"-"\u12ae", + "\u12b0", + "\u12b2"-"\u12b5", + "\u12b8"-"\u12be", + "\u12c0", + "\u12c2"-"\u12c5", + "\u12c8"-"\u12ce", + "\u12d0"-"\u12d6", + "\u12d8"-"\u12ee", + "\u12f0"-"\u130e", + "\u1310", + "\u1312"-"\u1315", + "\u1318"-"\u131e", + "\u1320"-"\u1346", + "\u1348"-"\u135a", + "\u13a0"-"\u13f4", + "\u1401"-"\u166c", + "\u166f"-"\u1676", + "\u1681"-"\u169a", + "\u16a0"-"\u16ea", + "\u1780"-"\u17b3", + "\u17db", + "\u1820"-"\u1877", + "\u1880"-"\u18a8", + "\u1e00"-"\u1e9b", + "\u1ea0"-"\u1ef9", + "\u1f00"-"\u1f15", + "\u1f18"-"\u1f1d", + "\u1f20"-"\u1f45", + "\u1f48"-"\u1f4d", + "\u1f50"-"\u1f57", + "\u1f59", + "\u1f5b", + "\u1f5d", + "\u1f5f"-"\u1f7d", + "\u1f80"-"\u1fb4", + "\u1fb6"-"\u1fbc", + "\u1fbe", + "\u1fc2"-"\u1fc4", + "\u1fc6"-"\u1fcc", + "\u1fd0"-"\u1fd3", + "\u1fd6"-"\u1fdb", + "\u1fe0"-"\u1fec", + "\u1ff2"-"\u1ff4", + "\u1ff6"-"\u1ffc", + "\u203f"-"\u2040", + "\u207f", + "\u20a0"-"\u20af", + "\u2102", + "\u2107", + "\u210a"-"\u2113", + "\u2115", + "\u2119"-"\u211d", + "\u2124", + "\u2126", + "\u2128", + "\u212a"-"\u212d", + "\u212f"-"\u2131", + "\u2133"-"\u2139", + "\u2160"-"\u2183", + "\u3005"-"\u3007", + "\u3021"-"\u3029", + "\u3031"-"\u3035", + "\u3038"-"\u303a", + "\u3041"-"\u3094", + "\u309d"-"\u309e", + "\u30a1"-"\u30fe", + "\u3105"-"\u312c", + "\u3131"-"\u318e", + "\u31a0"-"\u31b7", + "\u3400"-"\u4db5", + "\u4e00"-"\u9fa5", + "\ua000"-"\ua48c", + "\uac00"-"\ud7a3", + "\uf900"-"\ufa2d", + "\ufb00"-"\ufb06", + "\ufb13"-"\ufb17", + "\ufb1d", + "\ufb1f"-"\ufb28", + "\ufb2a"-"\ufb36", + "\ufb38"-"\ufb3c", + "\ufb3e", + "\ufb40"-"\ufb41", + "\ufb43"-"\ufb44", + "\ufb46"-"\ufbb1", + "\ufbd3"-"\ufd3d", + "\ufd50"-"\ufd8f", + "\ufd92"-"\ufdc7", + "\ufdf0"-"\ufdfb", + "\ufe33"-"\ufe34", + "\ufe4d"-"\ufe4f", + "\ufe69", + "\ufe70"-"\ufe72", + "\ufe74", + "\ufe76"-"\ufefc", + "\uff04", + "\uff21"-"\uff3a", + "\uff3f", + "\uff41"-"\uff5a", + "\uff65"-"\uffbe", + "\uffc2"-"\uffc7", + "\uffca"-"\uffcf", + "\uffd2"-"\uffd7", + "\uffda"-"\uffdc", + "\uffe0"-"\uffe1", + "\uffe5"-"\uffe6" + ] + > +| + < #PART_LETTER: + [ // all chars for which Character.isIdentifierPart is true + "\u0000"-"\u0008", + "\u000e"-"\u001b", + "$", + "0"-"9", + "A"-"Z", + "_", + "a"-"z", + "\u007f"-"\u009f", + "\u00a2"-"\u00a5", + "\u00aa", + "\u00b5", + "\u00ba", + "\u00c0"-"\u00d6", + "\u00d8"-"\u00f6", + "\u00f8"-"\u021f", + "\u0222"-"\u0233", + "\u0250"-"\u02ad", + "\u02b0"-"\u02b8", + "\u02bb"-"\u02c1", + "\u02d0"-"\u02d1", + "\u02e0"-"\u02e4", + "\u02ee", + "\u0300"-"\u034e", + "\u0360"-"\u0362", + "\u037a", + "\u0386", + "\u0388"-"\u038a", + "\u038c", + "\u038e"-"\u03a1", + "\u03a3"-"\u03ce", + "\u03d0"-"\u03d7", + "\u03da"-"\u03f3", + "\u0400"-"\u0481", + "\u0483"-"\u0486", + "\u048c"-"\u04c4", + "\u04c7"-"\u04c8", + "\u04cb"-"\u04cc", + "\u04d0"-"\u04f5", + "\u04f8"-"\u04f9", + "\u0531"-"\u0556", + "\u0559", + "\u0561"-"\u0587", + "\u0591"-"\u05a1", + "\u05a3"-"\u05b9", + "\u05bb"-"\u05bd", + "\u05bf", + "\u05c1"-"\u05c2", + "\u05c4", + "\u05d0"-"\u05ea", + "\u05f0"-"\u05f2", + "\u0621"-"\u063a", + "\u0640"-"\u0655", + "\u0660"-"\u0669", + "\u0670"-"\u06d3", + "\u06d5"-"\u06dc", + "\u06df"-"\u06e8", + "\u06ea"-"\u06ed", + "\u06f0"-"\u06fc", + "\u070f"-"\u072c", + "\u0730"-"\u074a", + "\u0780"-"\u07b0", + "\u0901"-"\u0903", + "\u0905"-"\u0939", + "\u093c"-"\u094d", + "\u0950"-"\u0954", + "\u0958"-"\u0963", + "\u0966"-"\u096f", + "\u0981"-"\u0983", + "\u0985"-"\u098c", + "\u098f"-"\u0990", + "\u0993"-"\u09a8", + "\u09aa"-"\u09b0", + "\u09b2", + "\u09b6"-"\u09b9", + "\u09bc", + "\u09be"-"\u09c4", + "\u09c7"-"\u09c8", + "\u09cb"-"\u09cd", + "\u09d7", + "\u09dc"-"\u09dd", + "\u09df"-"\u09e3", + "\u09e6"-"\u09f3", + "\u0a02", + "\u0a05"-"\u0a0a", + "\u0a0f"-"\u0a10", + "\u0a13"-"\u0a28", + "\u0a2a"-"\u0a30", + "\u0a32"-"\u0a33", + "\u0a35"-"\u0a36", + "\u0a38"-"\u0a39", + "\u0a3c", + "\u0a3e"-"\u0a42", + "\u0a47"-"\u0a48", + "\u0a4b"-"\u0a4d", + "\u0a59"-"\u0a5c", + "\u0a5e", + "\u0a66"-"\u0a74", + "\u0a81"-"\u0a83", + "\u0a85"-"\u0a8b", + "\u0a8d", + "\u0a8f"-"\u0a91", + "\u0a93"-"\u0aa8", + "\u0aaa"-"\u0ab0", + "\u0ab2"-"\u0ab3", + "\u0ab5"-"\u0ab9", + "\u0abc"-"\u0ac5", + "\u0ac7"-"\u0ac9", + "\u0acb"-"\u0acd", + "\u0ad0", + "\u0ae0", + "\u0ae6"-"\u0aef", + "\u0b01"-"\u0b03", + "\u0b05"-"\u0b0c", + "\u0b0f"-"\u0b10", + "\u0b13"-"\u0b28", + "\u0b2a"-"\u0b30", + "\u0b32"-"\u0b33", + "\u0b36"-"\u0b39", + "\u0b3c"-"\u0b43", + "\u0b47"-"\u0b48", + "\u0b4b"-"\u0b4d", + "\u0b56"-"\u0b57", + "\u0b5c"-"\u0b5d", + "\u0b5f"-"\u0b61", + "\u0b66"-"\u0b6f", + "\u0b82"-"\u0b83", + "\u0b85"-"\u0b8a", + "\u0b8e"-"\u0b90", + "\u0b92"-"\u0b95", + "\u0b99"-"\u0b9a", + "\u0b9c", + "\u0b9e"-"\u0b9f", + "\u0ba3"-"\u0ba4", + "\u0ba8"-"\u0baa", + "\u0bae"-"\u0bb5", + "\u0bb7"-"\u0bb9", + "\u0bbe"-"\u0bc2", + "\u0bc6"-"\u0bc8", + "\u0bca"-"\u0bcd", + "\u0bd7", + "\u0be7"-"\u0bef", + "\u0c01"-"\u0c03", + "\u0c05"-"\u0c0c", + "\u0c0e"-"\u0c10", + "\u0c12"-"\u0c28", + "\u0c2a"-"\u0c33", + "\u0c35"-"\u0c39", + "\u0c3e"-"\u0c44", + "\u0c46"-"\u0c48", + "\u0c4a"-"\u0c4d", + "\u0c55"-"\u0c56", + "\u0c60"-"\u0c61", + "\u0c66"-"\u0c6f", + "\u0c82"-"\u0c83", + "\u0c85"-"\u0c8c", + "\u0c8e"-"\u0c90", + "\u0c92"-"\u0ca8", + "\u0caa"-"\u0cb3", + "\u0cb5"-"\u0cb9", + "\u0cbe"-"\u0cc4", + "\u0cc6"-"\u0cc8", + "\u0cca"-"\u0ccd", + "\u0cd5"-"\u0cd6", + "\u0cde", + "\u0ce0"-"\u0ce1", + "\u0ce6"-"\u0cef", + "\u0d02"-"\u0d03", + "\u0d05"-"\u0d0c", + "\u0d0e"-"\u0d10", + "\u0d12"-"\u0d28", + "\u0d2a"-"\u0d39", + "\u0d3e"-"\u0d43", + "\u0d46"-"\u0d48", + "\u0d4a"-"\u0d4d", + "\u0d57", + "\u0d60"-"\u0d61", + "\u0d66"-"\u0d6f", + "\u0d82"-"\u0d83", + "\u0d85"-"\u0d96", + "\u0d9a"-"\u0db1", + "\u0db3"-"\u0dbb", + "\u0dbd", + "\u0dc0"-"\u0dc6", + "\u0dca", + "\u0dcf"-"\u0dd4", + "\u0dd6", + "\u0dd8"-"\u0ddf", + "\u0df2"-"\u0df3", + "\u0e01"-"\u0e3a", + "\u0e3f"-"\u0e4e", + "\u0e50"-"\u0e59", + "\u0e81"-"\u0e82", + "\u0e84", + "\u0e87"-"\u0e88", + "\u0e8a", + "\u0e8d", + "\u0e94"-"\u0e97", + "\u0e99"-"\u0e9f", + "\u0ea1"-"\u0ea3", + "\u0ea5", + "\u0ea7", + "\u0eaa"-"\u0eab", + "\u0ead"-"\u0eb9", + "\u0ebb"-"\u0ebd", + "\u0ec0"-"\u0ec4", + "\u0ec6", + "\u0ec8"-"\u0ecd", + "\u0ed0"-"\u0ed9", + "\u0edc"-"\u0edd", + "\u0f00", + "\u0f18"-"\u0f19", + "\u0f20"-"\u0f29", + "\u0f35", + "\u0f37", + "\u0f39", + "\u0f3e"-"\u0f47", + "\u0f49"-"\u0f6a", + "\u0f71"-"\u0f84", + "\u0f86"-"\u0f8b", + "\u0f90"-"\u0f97", + "\u0f99"-"\u0fbc", + "\u0fc6", + "\u1000"-"\u1021", + "\u1023"-"\u1027", + "\u1029"-"\u102a", + "\u102c"-"\u1032", + "\u1036"-"\u1039", + "\u1040"-"\u1049", + "\u1050"-"\u1059", + "\u10a0"-"\u10c5", + "\u10d0"-"\u10f6", + "\u1100"-"\u1159", + "\u115f"-"\u11a2", + "\u11a8"-"\u11f9", + "\u1200"-"\u1206", + "\u1208"-"\u1246", + "\u1248", + "\u124a"-"\u124d", + "\u1250"-"\u1256", + "\u1258", + "\u125a"-"\u125d", + "\u1260"-"\u1286", + "\u1288", + "\u128a"-"\u128d", + "\u1290"-"\u12ae", + "\u12b0", + "\u12b2"-"\u12b5", + "\u12b8"-"\u12be", + "\u12c0", + "\u12c2"-"\u12c5", + "\u12c8"-"\u12ce", + "\u12d0"-"\u12d6", + "\u12d8"-"\u12ee", + "\u12f0"-"\u130e", + "\u1310", + "\u1312"-"\u1315", + "\u1318"-"\u131e", + "\u1320"-"\u1346", + "\u1348"-"\u135a", + "\u1369"-"\u1371", + "\u13a0"-"\u13f4", + "\u1401"-"\u166c", + "\u166f"-"\u1676", + "\u1681"-"\u169a", + "\u16a0"-"\u16ea", + "\u1780"-"\u17d3", + "\u17db", + "\u17e0"-"\u17e9", + "\u180b"-"\u180e", + "\u1810"-"\u1819", + "\u1820"-"\u1877", + "\u1880"-"\u18a9", + "\u1e00"-"\u1e9b", + "\u1ea0"-"\u1ef9", + "\u1f00"-"\u1f15", + "\u1f18"-"\u1f1d", + "\u1f20"-"\u1f45", + "\u1f48"-"\u1f4d", + "\u1f50"-"\u1f57", + "\u1f59", + "\u1f5b", + "\u1f5d", + "\u1f5f"-"\u1f7d", + "\u1f80"-"\u1fb4", + "\u1fb6"-"\u1fbc", + "\u1fbe", + "\u1fc2"-"\u1fc4", + "\u1fc6"-"\u1fcc", + "\u1fd0"-"\u1fd3", + "\u1fd6"-"\u1fdb", + "\u1fe0"-"\u1fec", + "\u1ff2"-"\u1ff4", + "\u1ff6"-"\u1ffc", + "\u200c"-"\u200f", + "\u202a"-"\u202e", + "\u203f"-"\u2040", + "\u206a"-"\u206f", + "\u207f", + "\u20a0"-"\u20af", + "\u20d0"-"\u20dc", + "\u20e1", + "\u2102", + "\u2107", + "\u210a"-"\u2113", + "\u2115", + "\u2119"-"\u211d", + "\u2124", + "\u2126", + "\u2128", + "\u212a"-"\u212d", + "\u212f"-"\u2131", + "\u2133"-"\u2139", + "\u2160"-"\u2183", + "\u3005"-"\u3007", + "\u3021"-"\u302f", + "\u3031"-"\u3035", + "\u3038"-"\u303a", + "\u3041"-"\u3094", + "\u3099"-"\u309a", + "\u309d"-"\u309e", + "\u30a1"-"\u30fe", + "\u3105"-"\u312c", + "\u3131"-"\u318e", + "\u31a0"-"\u31b7", + "\u3400"-"\u4db5", + "\u4e00"-"\u9fa5", + "\ua000"-"\ua48c", + "\uac00"-"\ud7a3", + "\uf900"-"\ufa2d", + "\ufb00"-"\ufb06", + "\ufb13"-"\ufb17", + "\ufb1d"-"\ufb28", + "\ufb2a"-"\ufb36", + "\ufb38"-"\ufb3c", + "\ufb3e", + "\ufb40"-"\ufb41", + "\ufb43"-"\ufb44", + "\ufb46"-"\ufbb1", + "\ufbd3"-"\ufd3d", + "\ufd50"-"\ufd8f", + "\ufd92"-"\ufdc7", + "\ufdf0"-"\ufdfb", + "\ufe20"-"\ufe23", + "\ufe33"-"\ufe34", + "\ufe4d"-"\ufe4f", + "\ufe69", + "\ufe70"-"\ufe72", + "\ufe74", + "\ufe76"-"\ufefc", + "\ufeff", + "\uff04", + "\uff10"-"\uff19", + "\uff21"-"\uff3a", + "\uff3f", + "\uff41"-"\uff5a", + "\uff65"-"\uffbe", + "\uffc2"-"\uffc7", + "\uffca"-"\uffcf", + "\uffd2"-"\uffd7", + "\uffda"-"\uffdc", + "\uffe0"-"\uffe1", + "\uffe5"-"\uffe6", + "\ufff9"-"\ufffb" + ] + > +} + +/* SEPARATORS */ + +TOKEN : +{ + < LPAREN: "(" > +| < RPAREN: ")" > +| < LBRACE: "{" > +| < RBRACE: "}" > +| < LBRACKET: "[" > +| < RBRACKET: "]" > +| < SEMICOLON: ";" > +| < COMMA: "," > +| < DOT: "." > +| < AT: "@" > +} + +/* OPERATORS */ + +TOKEN : +{ + < ASSIGN: "=" > +| < LT: "<" > +| < BANG: "!" > +| < TILDE: "~" > +| < HOOK: "?" > +| < COLON: ":" > +| < EQ: "==" > +| < LE: "<=" > +| < GE: ">=" > +| < NE: "!=" > +| < SC_OR: "||" > +| < SC_AND: "&&" > +| < INCR: "++" > +| < DECR: "--" > +| < PLUS: "+" > +| < MINUS: "-" > +| < STAR: "*" > +| < SLASH: "/" > +| < BIT_AND: "&" > +| < BIT_OR: "|" > +| < XOR: "^" > +| < REM: "%" > +| < LSHIFT: "<<" > +| < PLUSASSIGN: "+=" > +| < MINUSASSIGN: "-=" > +| < STARASSIGN: "*=" > +| < SLASHASSIGN: "/=" > +| < ANDASSIGN: "&=" > +| < ORASSIGN: "|=" > +| < XORASSIGN: "^=" > +| < REMASSIGN: "%=" > +| < LSHIFTASSIGN: "<<=" > +| < RSIGNEDSHIFTASSIGN: ">>=" > +| < RUNSIGNEDSHIFTASSIGN: ">>>=" > +| < ELLIPSIS: "..." > +} + +/* >'s need special attention due to generics syntax. */ +TOKEN : +{ + < RUNSIGNEDSHIFT: ">>>" > + { + matchedToken.kind = GT; + ((Token.GTToken)matchedToken).realKind = RUNSIGNEDSHIFT; + input_stream.backup(2); + matchedToken.image = ">"; + } +| < RSIGNEDSHIFT: ">>" > + { + matchedToken.kind = GT; + ((Token.GTToken)matchedToken).realKind = RSIGNEDSHIFT; + input_stream.backup(1); + matchedToken.image = ">"; + } +| < GT: ">" > +} + +boolean Line() : +{/*@bgen(jjtree) Line */ + SimpleNode jjtn000 = new SimpleNode(JJTLINE); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/ + int modifiers; +} +{/*@bgen(jjtree) Line */ + try { +/*@egen*/ + <EOF>/*@bgen(jjtree)*/ + { + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtreeCloseNodeScope(jjtn000); + } +/*@egen*/ { + return true; + } +| + LOOKAHEAD(BlockStatement()) + BlockStatement()/*@bgen(jjtree)*/ + { + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtreeCloseNodeScope(jjtn000); + } +/*@egen*/ { + return false; + } +| + LOOKAHEAD(Modifiers() [ TypeParameters() ] [ ResultType() ] <IDENTIFIER> FormalParameters() [ "throws" NameList() ] "{") + ClassOrInterfaceBodyDeclaration(false)/*@bgen(jjtree)*/ + { + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtreeCloseNodeScope(jjtn000); + } +/*@egen*/ { + return false; + } +| + LOOKAHEAD(ClassOrInterfaceBodyDeclaration(false)) + ClassOrInterfaceBodyDeclaration(false)/*@bgen(jjtree)*/ + { + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtreeCloseNodeScope(jjtn000); + } +/*@egen*/ { + return false; + } +| + LOOKAHEAD(Expression()) + Expression()/*@bgen(jjtree)*/ + { + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtreeCloseNodeScope(jjtn000); + } +/*@egen*/ { + return false; + } +| + ImportDeclaration()/*@bgen(jjtree)*/ + { + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtreeCloseNodeScope(jjtn000); + } +/*@egen*/ { + return false; + }/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +/***************************************** + * THE JAVA LANGUAGE GRAMMAR STARTS HERE * + *****************************************/ + +/* + * Program structuring syntax follows. + */ + +void CompilationUnit(): +{/*@bgen(jjtree) CompilationUnit */ + SimpleNode jjtn000 = new SimpleNode(JJTCOMPILATIONUNIT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) CompilationUnit */ + try { +/*@egen*/ + [ LOOKAHEAD( ( Annotation() )* "package" ) PackageDeclaration() ] + ( ImportDeclaration() )* + ( TypeDeclaration() )* + ( < "\u001a" > )? + ( <STUFF_TO_IGNORE: ~[]> )? + <EOF>/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void PackageDeclaration(): +{/*@bgen(jjtree) PackageDeclaration */ + SimpleNode jjtn000 = new SimpleNode(JJTPACKAGEDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) PackageDeclaration */ + try { +/*@egen*/ + Modifiers() "package" Name() ";"/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void ImportDeclaration(): +{/*@bgen(jjtree) ImportDeclaration */ + SimpleNode jjtn000 = new SimpleNode(JJTIMPORTDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) ImportDeclaration */ + try { +/*@egen*/ + "import" [ "static" ] Name() [ "." "*" ] ";"/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +/* + * Modifiers. We match all modifiers in a single rule to reduce the chances of + * syntax errors for simple modifier mistakes. It will also enable us to give + * better error messages. + */ + +int Modifiers(): +{/*@bgen(jjtree) Modifiers */ + SimpleNode jjtn000 = new SimpleNode(JJTMODIFIERS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/ + int modifiers = 0; +} +{/*@bgen(jjtree) Modifiers */ + try { +/*@egen*/ + ( + LOOKAHEAD(2) + ( + "public" { modifiers |= ModifierSet.PUBLIC; } + | + "static" { modifiers |= ModifierSet.STATIC; } + | + "protected" { modifiers |= ModifierSet.PROTECTED; } + | + "private" { modifiers |= ModifierSet.PRIVATE; } + | + "final" { modifiers |= ModifierSet.FINAL; } + | + "abstract" { modifiers |= ModifierSet.ABSTRACT; } + | + "synchronized" { modifiers |= ModifierSet.SYNCHRONIZED; } + | + "native" { modifiers |= ModifierSet.NATIVE; } + | + "transient" { modifiers |= ModifierSet.TRANSIENT; } + | + "volatile" { modifiers |= ModifierSet.VOLATILE; } + | + "strictfp" { modifiers |= ModifierSet.STRICTFP; } + | + Annotation() + ) + )*/*@bgen(jjtree)*/ + { + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtreeCloseNodeScope(jjtn000); + } +/*@egen*/ + + { + return modifiers; + }/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +/* + * Declaration syntax follows. + */ +void TypeDeclaration(): +{/*@bgen(jjtree) TypeDeclaration */ + SimpleNode jjtn000 = new SimpleNode(JJTTYPEDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/ + int modifiers; +} +{/*@bgen(jjtree) TypeDeclaration */ + try { +/*@egen*/ + ";" +| + modifiers = Modifiers() + ( + ClassOrInterfaceDeclaration(modifiers) + | + EnumDeclaration(modifiers) + | + AnnotationTypeDeclaration(modifiers) + )/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + + +void ClassOrInterfaceDeclaration(int modifiers): +{/*@bgen(jjtree) ClassOrInterfaceDeclaration */ + SimpleNode jjtn000 = new SimpleNode(JJTCLASSORINTERFACEDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/ + boolean isInterface = false; +} +{/*@bgen(jjtree) ClassOrInterfaceDeclaration */ + try { +/*@egen*/ + ( "class" | "interface" { isInterface = true; } ) + <IDENTIFIER> + [ TypeParameters() ] + [ ExtendsList(isInterface) ] + [ ImplementsList(isInterface) ] + ClassOrInterfaceBody(isInterface)/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void ExtendsList(boolean isInterface): +{/*@bgen(jjtree) ExtendsList */ + SimpleNode jjtn000 = new SimpleNode(JJTEXTENDSLIST); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/ + boolean extendsMoreThanOne = false; +} +{/*@bgen(jjtree) ExtendsList */ + try { +/*@egen*/ + "extends" ClassOrInterfaceType() + ( "," ClassOrInterfaceType() { extendsMoreThanOne = true; } )*/*@bgen(jjtree)*/ + { + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtreeCloseNodeScope(jjtn000); + } +/*@egen*/ + { + if (extendsMoreThanOne && !isInterface) + throw new ParseException("A class cannot extend more than one other class"); + }/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void ImplementsList(boolean isInterface): +{/*@bgen(jjtree) ImplementsList */ + SimpleNode jjtn000 = new SimpleNode(JJTIMPLEMENTSLIST); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) ImplementsList */ + try { +/*@egen*/ + "implements" ClassOrInterfaceType() + ( "," ClassOrInterfaceType() )*/*@bgen(jjtree)*/ + { + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtreeCloseNodeScope(jjtn000); + } +/*@egen*/ + { + if (isInterface) + throw new ParseException("An interface cannot implement other interfaces"); + }/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void EnumDeclaration(int modifiers): +{/*@bgen(jjtree) EnumDeclaration */ + SimpleNode jjtn000 = new SimpleNode(JJTENUMDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) EnumDeclaration */ + try { +/*@egen*/ + "enum" <IDENTIFIER> + [ ImplementsList(false) ] + EnumBody()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void EnumBody(): +{/*@bgen(jjtree) EnumBody */ + SimpleNode jjtn000 = new SimpleNode(JJTENUMBODY); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) EnumBody */ + try { +/*@egen*/ + "{" + [ EnumConstant() ( LOOKAHEAD(2) "," EnumConstant() )* ] + [ "," ] + [ ";" ( ClassOrInterfaceBodyDeclaration(false) )* ] + "}"/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void EnumConstant(): +{/*@bgen(jjtree) EnumConstant */ + SimpleNode jjtn000 = new SimpleNode(JJTENUMCONSTANT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) EnumConstant */ + try { +/*@egen*/ + Modifiers() <IDENTIFIER> [ Arguments() ] [ ClassOrInterfaceBody(false) ]/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void TypeParameters(): +{/*@bgen(jjtree) TypeParameters */ + SimpleNode jjtn000 = new SimpleNode(JJTTYPEPARAMETERS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) TypeParameters */ + try { +/*@egen*/ + "<" TypeParameter() ( "," TypeParameter() )* ">"/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void TypeParameter(): +{/*@bgen(jjtree) TypeParameter */ + SimpleNode jjtn000 = new SimpleNode(JJTTYPEPARAMETER); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) TypeParameter */ + try { +/*@egen*/ + <IDENTIFIER> [ TypeBound() ]/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void TypeBound(): +{/*@bgen(jjtree) TypeBound */ + SimpleNode jjtn000 = new SimpleNode(JJTTYPEBOUND); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) TypeBound */ + try { +/*@egen*/ + "extends" ClassOrInterfaceType() ( "&" ClassOrInterfaceType() )*/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void ClassOrInterfaceBody(boolean isInterface): +{/*@bgen(jjtree) ClassOrInterfaceBody */ + SimpleNode jjtn000 = new SimpleNode(JJTCLASSORINTERFACEBODY); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) ClassOrInterfaceBody */ + try { +/*@egen*/ + "{" ( ClassOrInterfaceBodyDeclaration(isInterface) )* "}"/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void ClassOrInterfaceBodyDeclaration(boolean isInterface): +{/*@bgen(jjtree) ClassOrInterfaceBodyDeclaration */ + SimpleNode jjtn000 = new SimpleNode(JJTCLASSORINTERFACEBODYDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/ + boolean isNestedInterface = false; + int modifiers; +} +{/*@bgen(jjtree) ClassOrInterfaceBodyDeclaration */ + try { +/*@egen*/ + LOOKAHEAD(2) + Initializer()/*@bgen(jjtree)*/ + { + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtreeCloseNodeScope(jjtn000); + } +/*@egen*/ + { + if (isInterface) + throw new ParseException("An interface cannot have initializers"); + } +| + modifiers = Modifiers() // Just get all the modifiers out of the way. If you want to do + // more checks, pass the modifiers down to the member + ( + ClassOrInterfaceDeclaration(modifiers) + | + EnumDeclaration(modifiers) + | + LOOKAHEAD( [ TypeParameters() ] <IDENTIFIER> "(" ) + ConstructorDeclaration() + | + LOOKAHEAD( Type() <IDENTIFIER> ( "[" "]" )* ( "," | "=" | ";" ) ) + FieldDeclaration(modifiers) + | + MethodDeclaration(modifiers) + ) +| + ";"/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void FieldDeclaration(int modifiers): +{/*@bgen(jjtree) FieldDeclaration */ + SimpleNode jjtn000 = new SimpleNode(JJTFIELDDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) FieldDeclaration */ + try { +/*@egen*/ + // Modifiers are already matched in the caller + Type() VariableDeclarator() ( "," VariableDeclarator() )* ";"/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void VariableDeclarator(): +{/*@bgen(jjtree) VariableDeclarator */ + SimpleNode jjtn000 = new SimpleNode(JJTVARIABLEDECLARATOR); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) VariableDeclarator */ + try { +/*@egen*/ + VariableDeclaratorId() [ "=" VariableInitializer() ]/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void VariableDeclaratorId(): +{/*@bgen(jjtree) VariableDeclaratorId */ + SimpleNode jjtn000 = new SimpleNode(JJTVARIABLEDECLARATORID); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) VariableDeclaratorId */ + try { +/*@egen*/ + <IDENTIFIER> ( "[" "]" )*/*@bgen(jjtree)*/ + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void VariableInitializer(): +{/*@bgen(jjtree) VariableInitializer */ + SimpleNode jjtn000 = new SimpleNode(JJTVARIABLEINITIALIZER); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) VariableInitializer */ + try { +/*@egen*/ + ArrayInitializer() +| + Expression()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void ArrayInitializer(): +{/*@bgen(jjtree) ArrayInitializer */ + SimpleNode jjtn000 = new SimpleNode(JJTARRAYINITIALIZER); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) ArrayInitializer */ + try { +/*@egen*/ + "{" [ VariableInitializer() ( LOOKAHEAD(2) "," VariableInitializer() )* ] [ "," ] "}"/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void MethodDeclaration(int modifiers): +{/*@bgen(jjtree) MethodDeclaration */ + SimpleNode jjtn000 = new SimpleNode(JJTMETHODDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) MethodDeclaration */ + try { +/*@egen*/ + // Modifiers already matched in the caller! + [ TypeParameters() ] + ResultType() + MethodDeclarator() [ "throws" NameList() ] + ( Block() | ";" )/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void MethodDeclarator(): +{/*@bgen(jjtree) MethodDeclarator */ + SimpleNode jjtn000 = new SimpleNode(JJTMETHODDECLARATOR); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) MethodDeclarator */ + try { +/*@egen*/ + <IDENTIFIER> FormalParameters() ( "[" "]" )*/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void FormalParameters(): +{/*@bgen(jjtree) FormalParameters */ + SimpleNode jjtn000 = new SimpleNode(JJTFORMALPARAMETERS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) FormalParameters */ + try { +/*@egen*/ + "(" [ FormalParameter() ( "," FormalParameter() )* ] ")"/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void FormalParameter(): +{/*@bgen(jjtree) FormalParameter */ + SimpleNode jjtn000 = new SimpleNode(JJTFORMALPARAMETER); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) FormalParameter */ + try { +/*@egen*/ + Modifiers() Type() [ "..." ] VariableDeclaratorId()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void ConstructorDeclaration(): +{/*@bgen(jjtree) ConstructorDeclaration */ + SimpleNode jjtn000 = new SimpleNode(JJTCONSTRUCTORDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) ConstructorDeclaration */ + try { +/*@egen*/ + [ TypeParameters() ] + // Modifiers matched in the caller + <IDENTIFIER> FormalParameters() [ "throws" NameList() ] + "{" + [ LOOKAHEAD(ExplicitConstructorInvocation()) + ExplicitConstructorInvocation() + ] + ( BlockStatement() )* + "}"/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void ExplicitConstructorInvocation(): +{/*@bgen(jjtree) ExplicitConstructorInvocation */ + SimpleNode jjtn000 = new SimpleNode(JJTEXPLICITCONSTRUCTORINVOCATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) ExplicitConstructorInvocation */ + try { +/*@egen*/ + ( <IDENTIFIER> "." )* [ LOOKAHEAD(2) "this" "." ] + [ TypeArguments() ] ("this"|"super") Arguments() ";"/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void Initializer(): +{/*@bgen(jjtree) Initializer */ + SimpleNode jjtn000 = new SimpleNode(JJTINITIALIZER); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) Initializer */ + try { +/*@egen*/ + [ "static" ] Block()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + + +/* + * Type, name and expression syntax follows. + */ + +void Type(): +{/*@bgen(jjtree) Type */ + SimpleNode jjtn000 = new SimpleNode(JJTTYPE); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) Type */ + try { +/*@egen*/ + LOOKAHEAD(2) ReferenceType() + | + PrimitiveType()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void ReferenceType(): +{/*@bgen(jjtree) ReferenceType */ + SimpleNode jjtn000 = new SimpleNode(JJTREFERENCETYPE); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) ReferenceType */ + try { +/*@egen*/ + PrimitiveType() ( LOOKAHEAD(2) "[" "]" )+ + | + ( ClassOrInterfaceType() ) ( LOOKAHEAD(2) "[" "]" )*/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void ClassOrInterfaceType(): +{/*@bgen(jjtree) ClassOrInterfaceType */ + SimpleNode jjtn000 = new SimpleNode(JJTCLASSORINTERFACETYPE); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) ClassOrInterfaceType */ + try { +/*@egen*/ + <IDENTIFIER> [ LOOKAHEAD(2) TypeArguments() ] + ( LOOKAHEAD(2) "." <IDENTIFIER> [ LOOKAHEAD(2) TypeArguments() ] )*/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void TypeArguments(): +{/*@bgen(jjtree) TypeArguments */ + SimpleNode jjtn000 = new SimpleNode(JJTTYPEARGUMENTS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) TypeArguments */ + try { +/*@egen*/ + "<" TypeArgument() ( "," TypeArgument() )* ">"/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void TypeArgument(): +{/*@bgen(jjtree) TypeArgument */ + SimpleNode jjtn000 = new SimpleNode(JJTTYPEARGUMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) TypeArgument */ + try { +/*@egen*/ + ReferenceType() + | + "?" [ WildcardBounds() ]/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void WildcardBounds(): +{/*@bgen(jjtree) WildcardBounds */ + SimpleNode jjtn000 = new SimpleNode(JJTWILDCARDBOUNDS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) WildcardBounds */ + try { +/*@egen*/ + "extends" ReferenceType() + | + "super" ReferenceType()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + + +void PrimitiveType(): +{/*@bgen(jjtree) PrimitiveType */ + SimpleNode jjtn000 = new SimpleNode(JJTPRIMITIVETYPE); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) PrimitiveType */ + try { +/*@egen*/ + "boolean" +| + "char" +| + "byte" +| + "short" +| + "int" +| + "long" +| + "float" +| + "double"/*@bgen(jjtree)*/ + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void ResultType(): +{/*@bgen(jjtree) ResultType */ + SimpleNode jjtn000 = new SimpleNode(JJTRESULTTYPE); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) ResultType */ + try { +/*@egen*/ + "void" +| + Type()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void Name(): +/* + * A lookahead of 2 is required below since "Name" can be followed + * by a ".*" when used in the context of an "ImportDeclaration". + */ +{/*@bgen(jjtree) Name */ + SimpleNode jjtn000 = new SimpleNode(JJTNAME); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) Name */ + try { +/*@egen*/ + <IDENTIFIER> + ( LOOKAHEAD(2) "." <IDENTIFIER> + )*/*@bgen(jjtree)*/ + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void NameList(): +{/*@bgen(jjtree) NameList */ + SimpleNode jjtn000 = new SimpleNode(JJTNAMELIST); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) NameList */ + try { +/*@egen*/ + Name() ( "," Name() )*/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + + +/* + * Expression syntax follows. + */ + +void Expression(): +/* + * This expansion has been written this way instead of: + * Assignment() | ConditionalExpression() + * for performance reasons. + * However, it is a weakening of the grammar for it allows the LHS of + * assignments to be any conditional expression whereas it can only be + * a primary expression. Consider adding a semantic predicate to work + * around this. + */ +{/*@bgen(jjtree) Expression */ + SimpleNode jjtn000 = new SimpleNode(JJTEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) Expression */ + try { +/*@egen*/ + ConditionalExpression() + [ + LOOKAHEAD(2) + AssignmentOperator() Expression() + ]/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void AssignmentOperator(): +{/*@bgen(jjtree) AssignmentOperator */ + SimpleNode jjtn000 = new SimpleNode(JJTASSIGNMENTOPERATOR); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) AssignmentOperator */ + try { +/*@egen*/ + "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | ">>>=" | "&=" | "^=" | "|="/*@bgen(jjtree)*/ + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void AssignmentExpression(): +{/*@bgen(jjtree) AssignmentExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTASSIGNMENTEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) AssignmentExpression */ + try { +/*@egen*/ + PrimaryExpression() AssignmentOperator() Expression()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void ConditionalExpression(): +{/*@bgen(jjtree) ConditionalExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTCONDITIONALEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) ConditionalExpression */ + try { +/*@egen*/ + ConditionalOrExpression() [ "?" Expression() ":" Expression() ]/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void ConditionalOrExpression(): +{/*@bgen(jjtree) ConditionalOrExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTCONDITIONALOREXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) ConditionalOrExpression */ + try { +/*@egen*/ + ConditionalAndExpression() ( "||" ConditionalAndExpression() )*/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void ConditionalAndExpression(): +{/*@bgen(jjtree) ConditionalAndExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTCONDITIONALANDEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) ConditionalAndExpression */ + try { +/*@egen*/ + InclusiveOrExpression() ( "&&" InclusiveOrExpression() )*/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void InclusiveOrExpression(): +{/*@bgen(jjtree) InclusiveOrExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTINCLUSIVEOREXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) InclusiveOrExpression */ + try { +/*@egen*/ + ExclusiveOrExpression() ( "|" ExclusiveOrExpression() )*/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void ExclusiveOrExpression(): +{/*@bgen(jjtree) ExclusiveOrExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTEXCLUSIVEOREXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) ExclusiveOrExpression */ + try { +/*@egen*/ + AndExpression() ( "^" AndExpression() )*/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void AndExpression(): +{/*@bgen(jjtree) AndExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTANDEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) AndExpression */ + try { +/*@egen*/ + EqualityExpression() ( "&" EqualityExpression() )*/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void EqualityExpression(): +{/*@bgen(jjtree) EqualityExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTEQUALITYEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) EqualityExpression */ + try { +/*@egen*/ + InstanceOfExpression() ( ( "==" | "!=" ) InstanceOfExpression() )*/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void InstanceOfExpression(): +{/*@bgen(jjtree) InstanceOfExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTINSTANCEOFEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) InstanceOfExpression */ + try { +/*@egen*/ + RelationalExpression() [ "instanceof" Type() ]/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void RelationalExpression(): +{/*@bgen(jjtree) RelationalExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTRELATIONALEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) RelationalExpression */ + try { +/*@egen*/ + ShiftExpression() ( ( "<" | ">" | "<=" | ">=" ) ShiftExpression() )*/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void ShiftExpression(): +{/*@bgen(jjtree) ShiftExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTSHIFTEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) ShiftExpression */ + try { +/*@egen*/ + AdditiveExpression() ( ( "<<" | RSIGNEDSHIFT() | RUNSIGNEDSHIFT() ) AdditiveExpression() )*/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void AdditiveExpression(): +{/*@bgen(jjtree) AdditiveExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTADDITIVEEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) AdditiveExpression */ + try { +/*@egen*/ + MultiplicativeExpression() ( ( "+" | "-" ) MultiplicativeExpression() )*/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void MultiplicativeExpression(): +{/*@bgen(jjtree) MultiplicativeExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTMULTIPLICATIVEEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) MultiplicativeExpression */ + try { +/*@egen*/ + UnaryExpression() ( ( "*" | "/" | "%" ) UnaryExpression() )*/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void UnaryExpression(): +{/*@bgen(jjtree) UnaryExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTUNARYEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) UnaryExpression */ + try { +/*@egen*/ + ( "+" | "-" ) UnaryExpression() +| + PreIncrementExpression() +| + PreDecrementExpression() +| + UnaryExpressionNotPlusMinus()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void PreIncrementExpression(): +{/*@bgen(jjtree) PreIncrementExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTPREINCREMENTEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) PreIncrementExpression */ + try { +/*@egen*/ + "++" PrimaryExpression()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void PreDecrementExpression(): +{/*@bgen(jjtree) PreDecrementExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTPREDECREMENTEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) PreDecrementExpression */ + try { +/*@egen*/ + "--" PrimaryExpression()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void UnaryExpressionNotPlusMinus(): +{/*@bgen(jjtree) UnaryExpressionNotPlusMinus */ + SimpleNode jjtn000 = new SimpleNode(JJTUNARYEXPRESSIONNOTPLUSMINUS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) UnaryExpressionNotPlusMinus */ + try { +/*@egen*/ + ( "~" | "!" ) UnaryExpression() +| + LOOKAHEAD( CastLookahead() ) + CastExpression() +| + PostfixExpression()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +// This production is to determine lookahead only. The LOOKAHEAD specifications +// below are not used, but they are there just to indicate that we know about +// this. +void CastLookahead(): +{/*@bgen(jjtree) CastLookahead */ + SimpleNode jjtn000 = new SimpleNode(JJTCASTLOOKAHEAD); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) CastLookahead */ + try { +/*@egen*/ + LOOKAHEAD(2) + "(" PrimitiveType() +| + LOOKAHEAD("(" Type() "[") + "(" Type() "[" "]" +| + "(" Type() ")" ( "~" | "!" | "(" | <IDENTIFIER> | "this" | "super" | "new" | Literal() )/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void PostfixExpression(): +{/*@bgen(jjtree) PostfixExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTPOSTFIXEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) PostfixExpression */ + try { +/*@egen*/ + PrimaryExpression() [ PostfixOperator() ]/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void PostfixOperator(): +{/*@bgen(jjtree) PostfixOperator */ + SimpleNode jjtn000 = new SimpleNode(JJTPOSTFIXOPERATOR); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) PostfixOperator */ + try { +/*@egen*/ + "++" | "--"/*@bgen(jjtree)*/ + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void CastExpression(): +{/*@bgen(jjtree) CastExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTCASTEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) CastExpression */ + try { +/*@egen*/ + LOOKAHEAD("(" PrimitiveType()) + "(" Type() ")" UnaryExpression() +| + "(" Type() ")" UnaryExpressionNotPlusMinus()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void PrimaryExpression(): +{/*@bgen(jjtree) PrimaryExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTPRIMARYEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) PrimaryExpression */ + try { +/*@egen*/ + PrimaryPrefix() ( LOOKAHEAD(2) PrimarySuffix() )*/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void MemberSelector(): +{/*@bgen(jjtree) MemberSelector */ + SimpleNode jjtn000 = new SimpleNode(JJTMEMBERSELECTOR); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) MemberSelector */ + try { +/*@egen*/ + "." TypeArguments() <IDENTIFIER>/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void PrimaryPrefix(): +{/*@bgen(jjtree) PrimaryPrefix */ + SimpleNode jjtn000 = new SimpleNode(JJTPRIMARYPREFIX); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) PrimaryPrefix */ + try { +/*@egen*/ + Literal() +| + LOOKAHEAD( ( <IDENTIFIER> "." )* "this" ) + ( <IDENTIFIER> "." )* + "this" +| + "super" "." <IDENTIFIER> +| + "(" Expression() ")" +| + AllocationExpression() +| + LOOKAHEAD( ResultType() "." "class" ) + ResultType() "." "class" +| + Name()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void PrimarySuffix(): +{/*@bgen(jjtree) PrimarySuffix */ + SimpleNode jjtn000 = new SimpleNode(JJTPRIMARYSUFFIX); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) PrimarySuffix */ + try { +/*@egen*/ + LOOKAHEAD("." "super" ".") + "." "super" +| + LOOKAHEAD("." "this") + "." "this" +| + LOOKAHEAD(2) + "." AllocationExpression() +| + LOOKAHEAD(3) + MemberSelector() +| + "[" Expression() "]" +| + "." <IDENTIFIER> +| + Arguments()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void Literal(): +{/*@bgen(jjtree) Literal */ + SimpleNode jjtn000 = new SimpleNode(JJTLITERAL); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) Literal */ + try { +/*@egen*/ + <INTEGER_LITERAL> +| + <FLOATING_POINT_LITERAL> +| + <CHARACTER_LITERAL> +| + <STRING_LITERAL> +| + BooleanLiteral() +| + NullLiteral()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void BooleanLiteral(): +{/*@bgen(jjtree) BooleanLiteral */ + SimpleNode jjtn000 = new SimpleNode(JJTBOOLEANLITERAL); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) BooleanLiteral */ + try { +/*@egen*/ + "true" +| + "false"/*@bgen(jjtree)*/ + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void NullLiteral(): +{/*@bgen(jjtree) NullLiteral */ + SimpleNode jjtn000 = new SimpleNode(JJTNULLLITERAL); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) NullLiteral */ + try { +/*@egen*/ + "null"/*@bgen(jjtree)*/ + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void Arguments(): +{/*@bgen(jjtree) Arguments */ + SimpleNode jjtn000 = new SimpleNode(JJTARGUMENTS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) Arguments */ + try { +/*@egen*/ + "(" [ ArgumentList() ] ")"/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void ArgumentList(): +{/*@bgen(jjtree) ArgumentList */ + SimpleNode jjtn000 = new SimpleNode(JJTARGUMENTLIST); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) ArgumentList */ + try { +/*@egen*/ + Expression() ( "," Expression() )*/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void AllocationExpression(): +{/*@bgen(jjtree) AllocationExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTALLOCATIONEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) AllocationExpression */ + try { +/*@egen*/ + LOOKAHEAD(2) + "new" PrimitiveType() ArrayDimsAndInits() +| + "new" ClassOrInterfaceType() [ TypeArguments() ] + ( + ArrayDimsAndInits() + | + Arguments() [ ClassOrInterfaceBody(false) ] + )/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +/* + * The third LOOKAHEAD specification below is to parse to PrimarySuffix + * if there is an expression between the "[...]". + */ +void ArrayDimsAndInits(): +{/*@bgen(jjtree) ArrayDimsAndInits */ + SimpleNode jjtn000 = new SimpleNode(JJTARRAYDIMSANDINITS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) ArrayDimsAndInits */ + try { +/*@egen*/ + LOOKAHEAD(2) + ( LOOKAHEAD(2) "[" Expression() "]" )+ ( LOOKAHEAD(2) "[" "]" )* +| + ( "[" "]" )+ ArrayInitializer()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + + +/* + * Statement syntax follows. + */ + +void Statement(): +{/*@bgen(jjtree) Statement */ + SimpleNode jjtn000 = new SimpleNode(JJTSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) Statement */ + try { +/*@egen*/ + LOOKAHEAD(2) + LabeledStatement() +| + AssertStatement() +| + Block() +| + EmptyStatement() +| + StatementExpression() ";" +| + SwitchStatement() +| + IfStatement() +| + WhileStatement() +| + DoStatement() +| + ForStatement() +| + BreakStatement() +| + ContinueStatement() +| + ReturnStatement() +| + ThrowStatement() +| + SynchronizedStatement() +| + TryStatement()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void AssertStatement(): +{/*@bgen(jjtree) AssertStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTASSERTSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) AssertStatement */ + try { +/*@egen*/ + "assert" Expression() [ ":" Expression() ] ";"/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void LabeledStatement(): +{/*@bgen(jjtree) LabeledStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTLABELEDSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) LabeledStatement */ + try { +/*@egen*/ + <IDENTIFIER> ":" Statement()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void Block(): +{/*@bgen(jjtree) Block */ + SimpleNode jjtn000 = new SimpleNode(JJTBLOCK); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) Block */ + try { +/*@egen*/ + "{" ( BlockStatement() )* "}"/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void BlockStatement(): +{/*@bgen(jjtree) BlockStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTBLOCKSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) BlockStatement */ + try { +/*@egen*/ + LOOKAHEAD( Modifiers() Type() <IDENTIFIER> ) + LocalVariableDeclaration() ";" +| + Statement() +| + ClassOrInterfaceDeclaration(0)/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void LocalVariableDeclaration(): +{/*@bgen(jjtree) LocalVariableDeclaration */ + SimpleNode jjtn000 = new SimpleNode(JJTLOCALVARIABLEDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) LocalVariableDeclaration */ + try { +/*@egen*/ + Modifiers() Type() VariableDeclarator() ( "," VariableDeclarator() )*/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void EmptyStatement(): +{/*@bgen(jjtree) EmptyStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTEMPTYSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) EmptyStatement */ + try { +/*@egen*/ + ";"/*@bgen(jjtree)*/ + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void StatementExpression(): +{/*@bgen(jjtree) StatementExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTSTATEMENTEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) StatementExpression */ + try { +/*@egen*/ + PreIncrementExpression() +| + PreDecrementExpression() +| + LOOKAHEAD(PrimaryExpression() AssignmentOperator()) + AssignmentExpression() +| + PostfixExpression()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void SwitchStatement(): +{/*@bgen(jjtree) SwitchStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTSWITCHSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) SwitchStatement */ + try { +/*@egen*/ + "switch" "(" Expression() ")" "{" + ( SwitchLabel() ( BlockStatement() )* )* + "}"/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void SwitchLabel(): +{/*@bgen(jjtree) SwitchLabel */ + SimpleNode jjtn000 = new SimpleNode(JJTSWITCHLABEL); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) SwitchLabel */ + try { +/*@egen*/ + "case" Expression() ":" +| + "default" ":"/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void IfStatement(): +/* + * The disambiguating algorithm of JavaCC automatically binds dangling + * else's to the innermost if statement. The LOOKAHEAD specification + * is to tell JavaCC that we know what we are doing. + */ +{/*@bgen(jjtree) IfStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTIFSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) IfStatement */ + try { +/*@egen*/ + "if" "(" Expression() ")" Statement() [ LOOKAHEAD(1) "else" Statement() ]/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void WhileStatement(): +{/*@bgen(jjtree) WhileStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTWHILESTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) WhileStatement */ + try { +/*@egen*/ + "while" "(" Expression() ")" Statement()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void DoStatement(): +{/*@bgen(jjtree) DoStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTDOSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) DoStatement */ + try { +/*@egen*/ + "do" Statement() "while" "(" Expression() ")" ";"/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void ForStatement(): +{/*@bgen(jjtree) ForStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTFORSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) ForStatement */ + try { +/*@egen*/ + "for" "(" + + ( + LOOKAHEAD(Modifiers() Type() <IDENTIFIER> ":") + Modifiers() Type() <IDENTIFIER> ":" Expression() + | + [ ForInit() ] ";" [ Expression() ] ";" [ ForUpdate() ] + ) + + ")" Statement()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void ForInit(): +{/*@bgen(jjtree) ForInit */ + SimpleNode jjtn000 = new SimpleNode(JJTFORINIT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) ForInit */ + try { +/*@egen*/ + LOOKAHEAD( Modifiers() Type() <IDENTIFIER> ) + LocalVariableDeclaration() +| + StatementExpressionList()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void StatementExpressionList(): +{/*@bgen(jjtree) StatementExpressionList */ + SimpleNode jjtn000 = new SimpleNode(JJTSTATEMENTEXPRESSIONLIST); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) StatementExpressionList */ + try { +/*@egen*/ + StatementExpression() ( "," StatementExpression() )*/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void ForUpdate(): +{/*@bgen(jjtree) ForUpdate */ + SimpleNode jjtn000 = new SimpleNode(JJTFORUPDATE); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) ForUpdate */ + try { +/*@egen*/ + StatementExpressionList()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void BreakStatement(): +{/*@bgen(jjtree) BreakStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTBREAKSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) BreakStatement */ + try { +/*@egen*/ + "break" [ <IDENTIFIER> ] ";"/*@bgen(jjtree)*/ + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void ContinueStatement(): +{/*@bgen(jjtree) ContinueStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTCONTINUESTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) ContinueStatement */ + try { +/*@egen*/ + "continue" [ <IDENTIFIER> ] ";"/*@bgen(jjtree)*/ + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void ReturnStatement(): +{/*@bgen(jjtree) ReturnStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTRETURNSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) ReturnStatement */ + try { +/*@egen*/ + "return" [ Expression() ] ";"/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void ThrowStatement(): +{/*@bgen(jjtree) ThrowStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTTHROWSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) ThrowStatement */ + try { +/*@egen*/ + "throw" Expression() ";"/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void SynchronizedStatement(): +{/*@bgen(jjtree) SynchronizedStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTSYNCHRONIZEDSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) SynchronizedStatement */ + try { +/*@egen*/ + "synchronized" "(" Expression() ")" Block()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void TryStatement(): +/* + * Semantic check required here to make sure that at least one + * finally/catch is present. + */ +{/*@bgen(jjtree) TryStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTTRYSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) TryStatement */ + try { +/*@egen*/ + "try" Block() + ( "catch" "(" FormalParameter() ")" Block() )* + [ "finally" Block() ]/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +/* We use productions to match >>>, >> and > so that we can keep the + * type declaration syntax with generics clean + */ + +void RUNSIGNEDSHIFT(): +{/*@bgen(jjtree) RUNSIGNEDSHIFT */ + SimpleNode jjtn000 = new SimpleNode(JJTRUNSIGNEDSHIFT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) RUNSIGNEDSHIFT */ + try { +/*@egen*/ + ( LOOKAHEAD({ getToken(1).kind == GT && + ((Token.GTToken)getToken(1)).realKind == RUNSIGNEDSHIFT} ) + ">" ">" ">" + )/*@bgen(jjtree)*/ + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void RSIGNEDSHIFT(): +{/*@bgen(jjtree) RSIGNEDSHIFT */ + SimpleNode jjtn000 = new SimpleNode(JJTRSIGNEDSHIFT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) RSIGNEDSHIFT */ + try { +/*@egen*/ + ( LOOKAHEAD({ getToken(1).kind == GT && + ((Token.GTToken)getToken(1)).realKind == RSIGNEDSHIFT} ) + ">" ">" + )/*@bgen(jjtree)*/ + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +/* Annotation syntax follows. */ + +void Annotation(): +{/*@bgen(jjtree) Annotation */ + SimpleNode jjtn000 = new SimpleNode(JJTANNOTATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) Annotation */ + try { +/*@egen*/ + LOOKAHEAD( "@" Name() "(" ( <IDENTIFIER> "=" | ")" )) + NormalAnnotation() + | + LOOKAHEAD( "@" Name() "(" ) + SingleMemberAnnotation() + | + MarkerAnnotation()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void NormalAnnotation(): +{/*@bgen(jjtree) NormalAnnotation */ + SimpleNode jjtn000 = new SimpleNode(JJTNORMALANNOTATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) NormalAnnotation */ + try { +/*@egen*/ + "@" Name() "(" [ MemberValuePairs() ] ")"/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void MarkerAnnotation(): +{/*@bgen(jjtree) MarkerAnnotation */ + SimpleNode jjtn000 = new SimpleNode(JJTMARKERANNOTATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) MarkerAnnotation */ + try { +/*@egen*/ + "@" Name()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void SingleMemberAnnotation(): +{/*@bgen(jjtree) SingleMemberAnnotation */ + SimpleNode jjtn000 = new SimpleNode(JJTSINGLEMEMBERANNOTATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) SingleMemberAnnotation */ + try { +/*@egen*/ + "@" Name() "(" MemberValue() ")"/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void MemberValuePairs(): +{/*@bgen(jjtree) MemberValuePairs */ + SimpleNode jjtn000 = new SimpleNode(JJTMEMBERVALUEPAIRS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) MemberValuePairs */ + try { +/*@egen*/ + MemberValuePair() ( "," MemberValuePair() )*/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void MemberValuePair(): +{/*@bgen(jjtree) MemberValuePair */ + SimpleNode jjtn000 = new SimpleNode(JJTMEMBERVALUEPAIR); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) MemberValuePair */ + try { +/*@egen*/ + <IDENTIFIER> "=" MemberValue()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void MemberValue(): +{/*@bgen(jjtree) MemberValue */ + SimpleNode jjtn000 = new SimpleNode(JJTMEMBERVALUE); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) MemberValue */ + try { +/*@egen*/ + Annotation() + | + MemberValueArrayInitializer() + | + ConditionalExpression()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void MemberValueArrayInitializer(): +{/*@bgen(jjtree) MemberValueArrayInitializer */ + SimpleNode jjtn000 = new SimpleNode(JJTMEMBERVALUEARRAYINITIALIZER); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) MemberValueArrayInitializer */ + try { +/*@egen*/ + "{" MemberValue() ( LOOKAHEAD(2) "," MemberValue() )* [ "," ] "}"/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + + +/* Annotation Types. */ + +void AnnotationTypeDeclaration(int modifiers): +{/*@bgen(jjtree) AnnotationTypeDeclaration */ + SimpleNode jjtn000 = new SimpleNode(JJTANNOTATIONTYPEDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) AnnotationTypeDeclaration */ + try { +/*@egen*/ + "@" "interface" <IDENTIFIER> AnnotationTypeBody()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void AnnotationTypeBody(): +{/*@bgen(jjtree) AnnotationTypeBody */ + SimpleNode jjtn000 = new SimpleNode(JJTANNOTATIONTYPEBODY); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) AnnotationTypeBody */ + try { +/*@egen*/ + "{" ( AnnotationTypeMemberDeclaration() )* "}"/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void AnnotationTypeMemberDeclaration(): +{/*@bgen(jjtree) AnnotationTypeMemberDeclaration */ + SimpleNode jjtn000 = new SimpleNode(JJTANNOTATIONTYPEMEMBERDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/ + int modifiers; +} +{/*@bgen(jjtree) AnnotationTypeMemberDeclaration */ + try { +/*@egen*/ + modifiers = Modifiers() + ( + LOOKAHEAD(Type() <IDENTIFIER> "(") + Type() <IDENTIFIER> "(" ")" [ DefaultValue() ] ";" + | + ClassOrInterfaceDeclaration(modifiers) + | + EnumDeclaration(modifiers) + | + AnnotationTypeDeclaration(modifiers) + | + FieldDeclaration(modifiers) + ) + | + ( ";" )/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} + +void DefaultValue(): +{/*@bgen(jjtree) DefaultValue */ + SimpleNode jjtn000 = new SimpleNode(JJTDEFAULTVALUE); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); +/*@egen*/} +{/*@bgen(jjtree) DefaultValue */ + try { +/*@egen*/ + "default" MemberValue()/*@bgen(jjtree)*/ + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + throw (RuntimeException)jjte000; + } + if (jjte000 instanceof ParseException) { + throw (ParseException)jjte000; + } + throw (Error)jjte000; + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } +/*@egen*/ +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/parser/Java1.5.jjt b/trunk/jaxx-compiler/src/main/java/jaxx/parser/Java1.5.jjt new file mode 100644 index 0000000..b47955f --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/parser/Java1.5.jjt @@ -0,0 +1,2150 @@ + +/* + * Copyright © 2002 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * California 95054, U.S.A. All rights reserved. Sun Microsystems, Inc. has + * intellectual property rights relating to technology embodied in the product + * that is described in this document. In particular, and without limitation, + * these intellectual property rights may include one or more of the U.S. + * patents listed at http://www.sun.com/patents and one or more additional + * patents or pending patent applications in the U.S. and in other countries. + * U.S. Government Rights - Commercial software. Government users are subject + * to the Sun Microsystems, Inc. standard license agreement and applicable + * provisions of the FAR and its supplements. Use is subject to license terms. + * Sun, Sun Microsystems, the Sun logo and Java are trademarks or registered + * trademarks of Sun Microsystems, Inc. in the U.S. and other countries. This + * product is covered and controlled by U.S. Export Control laws and may be + * subject to the export or import laws in other countries. Nuclear, missile, + * chemical biological weapons or nuclear maritime end uses or end users, + * whether direct or indirect, are strictly prohibited. Export or reexport + * to countries subject to U.S. embargo or to entities identified on U.S. + * export exclusion lists, including, but not limited to, the denied persons + * and specially designated nationals lists is strictly prohibited. + */ + +// Slightly modified version of javacc's reference 1.5 grammar, tweaked for +// usage with JAXX. There are two main areas of changes: several new +// nonterminals were added to make identifying certain constructs easier, +// and the Line nonterminal was added to support JAXX's script tags. +// Several of the new changes are inefficient and require excess lookahead, +// but at this point I'd rather have inefficiency than risk breaking it during +// attempted optimizations. + +options { + JAVA_UNICODE_ESCAPE = true; + ERROR_REPORTING = false; + STATIC = false; + JDK_VERSION = "1.4"; + NODE_SCOPE_HOOK=true; +} + +PARSER_BEGIN(JavaParser) +package jaxx.parser; + +import java.io.*; + +/** + * Grammar to parse Java version 1.5 + * @author Sreenivasa Viswanadha - Simplified and enhanced for 1.5 + */ +public class JavaParser +{ + /** + * Class to hold modifiers. + */ + static public final class ModifierSet + { + /* Definitions of the bits in the modifiers field. */ + public static final int PUBLIC = 0x0001; + public static final int PROTECTED = 0x0002; + public static final int PRIVATE = 0x0004; + public static final int ABSTRACT = 0x0008; + public static final int STATIC = 0x0010; + public static final int FINAL = 0x0020; + public static final int SYNCHRONIZED = 0x0040; + public static final int NATIVE = 0x0080; + public static final int TRANSIENT = 0x0100; + public static final int VOLATILE = 0x0200; + public static final int STRICTFP = 0x1000; + + /** A set of accessors that indicate whether the specified modifier + is in the set. */ + + public boolean isPublic(int modifiers) + { + return (modifiers & PUBLIC) != 0; + } + + public boolean isProtected(int modifiers) + { + return (modifiers & PROTECTED) != 0; + } + + public boolean isPrivate(int modifiers) + { + return (modifiers & PRIVATE) != 0; + } + + public boolean isStatic(int modifiers) + { + return (modifiers & STATIC) != 0; + } + + public boolean isAbstract(int modifiers) + { + return (modifiers & ABSTRACT) != 0; + } + + public boolean isFinal(int modifiers) + { + return (modifiers & FINAL) != 0; + } + + public boolean isNative(int modifiers) + { + return (modifiers & NATIVE) != 0; + } + + public boolean isStrictfp(int modifiers) + { + return (modifiers & STRICTFP) != 0; + } + + public boolean isSynchronized(int modifiers) + { + return (modifiers & SYNCHRONIZED) != 0; + } + + public boolean isTransient(int modifiers) + { + return (modifiers & TRANSIENT) != 0; + } + + public boolean isVolatile(int modifiers) + { + return (modifiers & VOLATILE) != 0; + } + + /** + * Removes the given modifier. + */ + static int removeModifier(int modifiers, int mod) + { + return modifiers & ~mod; + } + } + + public JavaParser(String fileName) + { + this(System.in); + try { ReInit(new FileInputStream(new File(fileName))); } + catch(Exception e) { e.printStackTrace(); } + } + + void jjtreeOpenNodeScope(Node n) { + ((SimpleNode) n).firstToken = getToken(1); + } + + void jjtreeCloseNodeScope(Node n) { + ((SimpleNode) n).lastToken = getToken(0); + } + + public SimpleNode popNode() + { + if ( jjtree.nodeArity() > 0) // number of child nodes + return (SimpleNode)jjtree.popNode(); + else + return null; + } + public static void main(String args[]) { + JavaParser parser; + if (args.length == 0) { + System.out.println("Java Parser Version 1.1: Reading from standard input . . ."); + parser = new JavaParser(System.in); + } else if (args.length == 1) { + System.out.println("Java Parser Version 1.1: Reading from file " + args[0] + " . . ."); + try { + parser = new JavaParser(new java.io.FileInputStream(args[0])); + } catch (java.io.FileNotFoundException e) { + System.out.println("Java Parser Version 1.1: File " + args[0] + " not found."); + return; + } + } else { + System.out.println("Java Parser Version 1.1: Usage is one of:"); + System.out.println(" java JavaParser < inputfile"); + System.out.println("OR"); + System.out.println(" java JavaParser inputfile"); + return; + } + try { + parser.CompilationUnit(); + System.out.println("Java Parser Version 1.1: Java program parsed successfully."); + } catch (ParseException e) { + System.out.println(e.getMessage()); + System.out.println("Java Parser Version 1.1: Encountered errors during parse."); + } + } + +} + +PARSER_END(JavaParser) + +/* COMMENTS */ + +MORE : +{ + <"/**" ~["/"]> { input_stream.backup(1); } : IN_FORMAL_COMMENT +| + "/*" : IN_MULTI_LINE_COMMENT +} + +SPECIAL_TOKEN: +{ + <WHITE_SPACE: ([" ", "\n", "\r", "\t", "\f"])+> +} + +SPECIAL_TOKEN : +{ + <SINGLE_LINE_COMMENT: "//" (~["\n", "\r"])* ("\n" | "\r" | "\r\n")?> +} + +<IN_FORMAL_COMMENT> +SPECIAL_TOKEN : +{ + <FORMAL_COMMENT: "*/" > : DEFAULT +} + +<IN_MULTI_LINE_COMMENT> +SPECIAL_TOKEN : +{ + <MULTI_LINE_COMMENT: "*/" > : DEFAULT +} + +<IN_FORMAL_COMMENT,IN_MULTI_LINE_COMMENT> +MORE : +{ + < ~[] > +} + +/* RESERVED WORDS AND LITERALS */ + +TOKEN : +{ + < ABSTRACT: "abstract" > +| < ASSERT: "assert" > +| < BOOLEAN: "boolean" > +| < BREAK: "break" > +| < BYTE: "byte" > +| < CASE: "case" > +| < CATCH: "catch" > +| < CHAR: "char" > +| < CLASS: "class" > +| < CONST: "const" > +| < CONTINUE: "continue" > +| < _DEFAULT: "default" > +| < DO: "do" > +| < DOUBLE: "double" > +| < ELSE: "else" > +| < ENUM: "enum" > +| < EXTENDS: "extends" > +| < FALSE: "false" > +| < FINAL: "final" > +| < FINALLY: "finally" > +| < FLOAT: "float" > +| < FOR: "for" > +| < GOTO: "goto" > +| < IF: "if" > +| < IMPLEMENTS: "implements" > +| < IMPORT: "import" > +| < INSTANCEOF: "instanceof" > +| < INT: "int" > +| < INTERFACE: "interface" > +| < LONG: "long" > +| < NATIVE: "native" > +| < NEW: "new" > +| < NULL: "null" > +| < PACKAGE: "package"> +| < PRIVATE: "private" > +| < PROTECTED: "protected" > +| < PUBLIC: "public" > +| < RETURN: "return" > +| < SHORT: "short" > +| < STATIC: "static" > +| < STRICTFP: "strictfp" > +| < SUPER: "super" > +| < SWITCH: "switch" > +| < SYNCHRONIZED: "synchronized" > +| < THIS: "this" > +| < THROW: "throw" > +| < THROWS: "throws" > +| < TRANSIENT: "transient" > +| < TRUE: "true" > +| < TRY: "try" > +| < VOID: "void" > +| < VOLATILE: "volatile" > +| < WHILE: "while" > +} + +/* LITERALS */ + +TOKEN : +{ + < INTEGER_LITERAL: + <DECIMAL_LITERAL> (["l","L"])? + | <HEX_LITERAL> (["l","L"])? + | <OCTAL_LITERAL> (["l","L"])? + > +| + < #DECIMAL_LITERAL: ["1"-"9"] (["0"-"9"])* > +| + < #HEX_LITERAL: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ > +| + < #OCTAL_LITERAL: "0" (["0"-"7"])* > +| + < FLOATING_POINT_LITERAL: + <DECIMAL_FLOATING_POINT_LITERAL> + | <HEXADECIMAL_FLOATING_POINT_LITERAL> + > +| + < #DECIMAL_FLOATING_POINT_LITERAL: + (["0"-"9"])+ "." (["0"-"9"])* (<DECIMAL_EXPONENT>)? (["f","F","d","D"])? + | "." (["0"-"9"])+ (<DECIMAL_EXPONENT>)? (["f","F","d","D"])? + | (["0"-"9"])+ <DECIMAL_EXPONENT> (["f","F","d","D"])? + | (["0"-"9"])+ (<DECIMAL_EXPONENT>)? ["f","F","d","D"] + > +| + < #DECIMAL_EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ > +| + < #HEXADECIMAL_FLOATING_POINT_LITERAL: + "0" ["x", "X"] (["0"-"9","a"-"f","A"-"F"])+ (".")? <HEXADECIMAL_EXPONENT> (["f","F","d","D"])? + | "0" ["x", "X"] (["0"-"9","a"-"f","A"-"F"])* "." (["0"-"9","a"-"f","A"-"F"])+ <HEXADECIMAL_EXPONENT> (["f","F","d","D"])? + > +| + < #HEXADECIMAL_EXPONENT: ["p","P"] (["+","-"])? (["0"-"9"])+ > +| + < CHARACTER_LITERAL: + "'" + ( (~["'","\\","\n","\r"]) + | ("\\" + ( ["n","t","b","r","f","\\","'","\""] + | ["0"-"7"] ( ["0"-"7"] )? + | ["0"-"3"] ["0"-"7"] ["0"-"7"] + ) + ) + ) + "'" + > +| + < STRING_LITERAL: + "\"" + ( (~["\"","\\","\n","\r"]) + | ("\\" + ( ["n","t","b","r","f","\\","'","\""] + | ["0"-"7"] ( ["0"-"7"] )? + | ["0"-"3"] ["0"-"7"] ["0"-"7"] + ) + ) + )* + "\"" + > +} + +/* IDENTIFIERS */ + +TOKEN : +{ + < IDENTIFIER: <LETTER> (<PART_LETTER>)* > +| + < #LETTER: + [ // all chars for which Character.isIdentifierStart is true + "$", + "A"-"Z", + "_", + "a"-"z", + "\u00a2"-"\u00a5", + "\u00aa", + "\u00b5", + "\u00ba", + "\u00c0"-"\u00d6", + "\u00d8"-"\u00f6", + "\u00f8"-"\u021f", + "\u0222"-"\u0233", + "\u0250"-"\u02ad", + "\u02b0"-"\u02b8", + "\u02bb"-"\u02c1", + "\u02d0"-"\u02d1", + "\u02e0"-"\u02e4", + "\u02ee", + "\u037a", + "\u0386", + "\u0388"-"\u038a", + "\u038c", + "\u038e"-"\u03a1", + "\u03a3"-"\u03ce", + "\u03d0"-"\u03d7", + "\u03da"-"\u03f3", + "\u0400"-"\u0481", + "\u048c"-"\u04c4", + "\u04c7"-"\u04c8", + "\u04cb"-"\u04cc", + "\u04d0"-"\u04f5", + "\u04f8"-"\u04f9", + "\u0531"-"\u0556", + "\u0559", + "\u0561"-"\u0587", + "\u05d0"-"\u05ea", + "\u05f0"-"\u05f2", + "\u0621"-"\u063a", + "\u0640"-"\u064a", + "\u0671"-"\u06d3", + "\u06d5", + "\u06e5"-"\u06e6", + "\u06fa"-"\u06fc", + "\u0710", + "\u0712"-"\u072c", + "\u0780"-"\u07a5", + "\u0905"-"\u0939", + "\u093d", + "\u0950", + "\u0958"-"\u0961", + "\u0985"-"\u098c", + "\u098f"-"\u0990", + "\u0993"-"\u09a8", + "\u09aa"-"\u09b0", + "\u09b2", + "\u09b6"-"\u09b9", + "\u09dc"-"\u09dd", + "\u09df"-"\u09e1", + "\u09f0"-"\u09f3", + "\u0a05"-"\u0a0a", + "\u0a0f"-"\u0a10", + "\u0a13"-"\u0a28", + "\u0a2a"-"\u0a30", + "\u0a32"-"\u0a33", + "\u0a35"-"\u0a36", + "\u0a38"-"\u0a39", + "\u0a59"-"\u0a5c", + "\u0a5e", + "\u0a72"-"\u0a74", + "\u0a85"-"\u0a8b", + "\u0a8d", + "\u0a8f"-"\u0a91", + "\u0a93"-"\u0aa8", + "\u0aaa"-"\u0ab0", + "\u0ab2"-"\u0ab3", + "\u0ab5"-"\u0ab9", + "\u0abd", + "\u0ad0", + "\u0ae0", + "\u0b05"-"\u0b0c", + "\u0b0f"-"\u0b10", + "\u0b13"-"\u0b28", + "\u0b2a"-"\u0b30", + "\u0b32"-"\u0b33", + "\u0b36"-"\u0b39", + "\u0b3d", + "\u0b5c"-"\u0b5d", + "\u0b5f"-"\u0b61", + "\u0b85"-"\u0b8a", + "\u0b8e"-"\u0b90", + "\u0b92"-"\u0b95", + "\u0b99"-"\u0b9a", + "\u0b9c", + "\u0b9e"-"\u0b9f", + "\u0ba3"-"\u0ba4", + "\u0ba8"-"\u0baa", + "\u0bae"-"\u0bb5", + "\u0bb7"-"\u0bb9", + "\u0c05"-"\u0c0c", + "\u0c0e"-"\u0c10", + "\u0c12"-"\u0c28", + "\u0c2a"-"\u0c33", + "\u0c35"-"\u0c39", + "\u0c60"-"\u0c61", + "\u0c85"-"\u0c8c", + "\u0c8e"-"\u0c90", + "\u0c92"-"\u0ca8", + "\u0caa"-"\u0cb3", + "\u0cb5"-"\u0cb9", + "\u0cde", + "\u0ce0"-"\u0ce1", + "\u0d05"-"\u0d0c", + "\u0d0e"-"\u0d10", + "\u0d12"-"\u0d28", + "\u0d2a"-"\u0d39", + "\u0d60"-"\u0d61", + "\u0d85"-"\u0d96", + "\u0d9a"-"\u0db1", + "\u0db3"-"\u0dbb", + "\u0dbd", + "\u0dc0"-"\u0dc6", + "\u0e01"-"\u0e30", + "\u0e32"-"\u0e33", + "\u0e3f"-"\u0e46", + "\u0e81"-"\u0e82", + "\u0e84", + "\u0e87"-"\u0e88", + "\u0e8a", + "\u0e8d", + "\u0e94"-"\u0e97", + "\u0e99"-"\u0e9f", + "\u0ea1"-"\u0ea3", + "\u0ea5", + "\u0ea7", + "\u0eaa"-"\u0eab", + "\u0ead"-"\u0eb0", + "\u0eb2"-"\u0eb3", + "\u0ebd", + "\u0ec0"-"\u0ec4", + "\u0ec6", + "\u0edc"-"\u0edd", + "\u0f00", + "\u0f40"-"\u0f47", + "\u0f49"-"\u0f6a", + "\u0f88"-"\u0f8b", + "\u1000"-"\u1021", + "\u1023"-"\u1027", + "\u1029"-"\u102a", + "\u1050"-"\u1055", + "\u10a0"-"\u10c5", + "\u10d0"-"\u10f6", + "\u1100"-"\u1159", + "\u115f"-"\u11a2", + "\u11a8"-"\u11f9", + "\u1200"-"\u1206", + "\u1208"-"\u1246", + "\u1248", + "\u124a"-"\u124d", + "\u1250"-"\u1256", + "\u1258", + "\u125a"-"\u125d", + "\u1260"-"\u1286", + "\u1288", + "\u128a"-"\u128d", + "\u1290"-"\u12ae", + "\u12b0", + "\u12b2"-"\u12b5", + "\u12b8"-"\u12be", + "\u12c0", + "\u12c2"-"\u12c5", + "\u12c8"-"\u12ce", + "\u12d0"-"\u12d6", + "\u12d8"-"\u12ee", + "\u12f0"-"\u130e", + "\u1310", + "\u1312"-"\u1315", + "\u1318"-"\u131e", + "\u1320"-"\u1346", + "\u1348"-"\u135a", + "\u13a0"-"\u13f4", + "\u1401"-"\u166c", + "\u166f"-"\u1676", + "\u1681"-"\u169a", + "\u16a0"-"\u16ea", + "\u1780"-"\u17b3", + "\u17db", + "\u1820"-"\u1877", + "\u1880"-"\u18a8", + "\u1e00"-"\u1e9b", + "\u1ea0"-"\u1ef9", + "\u1f00"-"\u1f15", + "\u1f18"-"\u1f1d", + "\u1f20"-"\u1f45", + "\u1f48"-"\u1f4d", + "\u1f50"-"\u1f57", + "\u1f59", + "\u1f5b", + "\u1f5d", + "\u1f5f"-"\u1f7d", + "\u1f80"-"\u1fb4", + "\u1fb6"-"\u1fbc", + "\u1fbe", + "\u1fc2"-"\u1fc4", + "\u1fc6"-"\u1fcc", + "\u1fd0"-"\u1fd3", + "\u1fd6"-"\u1fdb", + "\u1fe0"-"\u1fec", + "\u1ff2"-"\u1ff4", + "\u1ff6"-"\u1ffc", + "\u203f"-"\u2040", + "\u207f", + "\u20a0"-"\u20af", + "\u2102", + "\u2107", + "\u210a"-"\u2113", + "\u2115", + "\u2119"-"\u211d", + "\u2124", + "\u2126", + "\u2128", + "\u212a"-"\u212d", + "\u212f"-"\u2131", + "\u2133"-"\u2139", + "\u2160"-"\u2183", + "\u3005"-"\u3007", + "\u3021"-"\u3029", + "\u3031"-"\u3035", + "\u3038"-"\u303a", + "\u3041"-"\u3094", + "\u309d"-"\u309e", + "\u30a1"-"\u30fe", + "\u3105"-"\u312c", + "\u3131"-"\u318e", + "\u31a0"-"\u31b7", + "\u3400"-"\u4db5", + "\u4e00"-"\u9fa5", + "\ua000"-"\ua48c", + "\uac00"-"\ud7a3", + "\uf900"-"\ufa2d", + "\ufb00"-"\ufb06", + "\ufb13"-"\ufb17", + "\ufb1d", + "\ufb1f"-"\ufb28", + "\ufb2a"-"\ufb36", + "\ufb38"-"\ufb3c", + "\ufb3e", + "\ufb40"-"\ufb41", + "\ufb43"-"\ufb44", + "\ufb46"-"\ufbb1", + "\ufbd3"-"\ufd3d", + "\ufd50"-"\ufd8f", + "\ufd92"-"\ufdc7", + "\ufdf0"-"\ufdfb", + "\ufe33"-"\ufe34", + "\ufe4d"-"\ufe4f", + "\ufe69", + "\ufe70"-"\ufe72", + "\ufe74", + "\ufe76"-"\ufefc", + "\uff04", + "\uff21"-"\uff3a", + "\uff3f", + "\uff41"-"\uff5a", + "\uff65"-"\uffbe", + "\uffc2"-"\uffc7", + "\uffca"-"\uffcf", + "\uffd2"-"\uffd7", + "\uffda"-"\uffdc", + "\uffe0"-"\uffe1", + "\uffe5"-"\uffe6" + ] + > +| + < #PART_LETTER: + [ // all chars for which Character.isIdentifierPart is true + "\u0000"-"\u0008", + "\u000e"-"\u001b", + "$", + "0"-"9", + "A"-"Z", + "_", + "a"-"z", + "\u007f"-"\u009f", + "\u00a2"-"\u00a5", + "\u00aa", + "\u00b5", + "\u00ba", + "\u00c0"-"\u00d6", + "\u00d8"-"\u00f6", + "\u00f8"-"\u021f", + "\u0222"-"\u0233", + "\u0250"-"\u02ad", + "\u02b0"-"\u02b8", + "\u02bb"-"\u02c1", + "\u02d0"-"\u02d1", + "\u02e0"-"\u02e4", + "\u02ee", + "\u0300"-"\u034e", + "\u0360"-"\u0362", + "\u037a", + "\u0386", + "\u0388"-"\u038a", + "\u038c", + "\u038e"-"\u03a1", + "\u03a3"-"\u03ce", + "\u03d0"-"\u03d7", + "\u03da"-"\u03f3", + "\u0400"-"\u0481", + "\u0483"-"\u0486", + "\u048c"-"\u04c4", + "\u04c7"-"\u04c8", + "\u04cb"-"\u04cc", + "\u04d0"-"\u04f5", + "\u04f8"-"\u04f9", + "\u0531"-"\u0556", + "\u0559", + "\u0561"-"\u0587", + "\u0591"-"\u05a1", + "\u05a3"-"\u05b9", + "\u05bb"-"\u05bd", + "\u05bf", + "\u05c1"-"\u05c2", + "\u05c4", + "\u05d0"-"\u05ea", + "\u05f0"-"\u05f2", + "\u0621"-"\u063a", + "\u0640"-"\u0655", + "\u0660"-"\u0669", + "\u0670"-"\u06d3", + "\u06d5"-"\u06dc", + "\u06df"-"\u06e8", + "\u06ea"-"\u06ed", + "\u06f0"-"\u06fc", + "\u070f"-"\u072c", + "\u0730"-"\u074a", + "\u0780"-"\u07b0", + "\u0901"-"\u0903", + "\u0905"-"\u0939", + "\u093c"-"\u094d", + "\u0950"-"\u0954", + "\u0958"-"\u0963", + "\u0966"-"\u096f", + "\u0981"-"\u0983", + "\u0985"-"\u098c", + "\u098f"-"\u0990", + "\u0993"-"\u09a8", + "\u09aa"-"\u09b0", + "\u09b2", + "\u09b6"-"\u09b9", + "\u09bc", + "\u09be"-"\u09c4", + "\u09c7"-"\u09c8", + "\u09cb"-"\u09cd", + "\u09d7", + "\u09dc"-"\u09dd", + "\u09df"-"\u09e3", + "\u09e6"-"\u09f3", + "\u0a02", + "\u0a05"-"\u0a0a", + "\u0a0f"-"\u0a10", + "\u0a13"-"\u0a28", + "\u0a2a"-"\u0a30", + "\u0a32"-"\u0a33", + "\u0a35"-"\u0a36", + "\u0a38"-"\u0a39", + "\u0a3c", + "\u0a3e"-"\u0a42", + "\u0a47"-"\u0a48", + "\u0a4b"-"\u0a4d", + "\u0a59"-"\u0a5c", + "\u0a5e", + "\u0a66"-"\u0a74", + "\u0a81"-"\u0a83", + "\u0a85"-"\u0a8b", + "\u0a8d", + "\u0a8f"-"\u0a91", + "\u0a93"-"\u0aa8", + "\u0aaa"-"\u0ab0", + "\u0ab2"-"\u0ab3", + "\u0ab5"-"\u0ab9", + "\u0abc"-"\u0ac5", + "\u0ac7"-"\u0ac9", + "\u0acb"-"\u0acd", + "\u0ad0", + "\u0ae0", + "\u0ae6"-"\u0aef", + "\u0b01"-"\u0b03", + "\u0b05"-"\u0b0c", + "\u0b0f"-"\u0b10", + "\u0b13"-"\u0b28", + "\u0b2a"-"\u0b30", + "\u0b32"-"\u0b33", + "\u0b36"-"\u0b39", + "\u0b3c"-"\u0b43", + "\u0b47"-"\u0b48", + "\u0b4b"-"\u0b4d", + "\u0b56"-"\u0b57", + "\u0b5c"-"\u0b5d", + "\u0b5f"-"\u0b61", + "\u0b66"-"\u0b6f", + "\u0b82"-"\u0b83", + "\u0b85"-"\u0b8a", + "\u0b8e"-"\u0b90", + "\u0b92"-"\u0b95", + "\u0b99"-"\u0b9a", + "\u0b9c", + "\u0b9e"-"\u0b9f", + "\u0ba3"-"\u0ba4", + "\u0ba8"-"\u0baa", + "\u0bae"-"\u0bb5", + "\u0bb7"-"\u0bb9", + "\u0bbe"-"\u0bc2", + "\u0bc6"-"\u0bc8", + "\u0bca"-"\u0bcd", + "\u0bd7", + "\u0be7"-"\u0bef", + "\u0c01"-"\u0c03", + "\u0c05"-"\u0c0c", + "\u0c0e"-"\u0c10", + "\u0c12"-"\u0c28", + "\u0c2a"-"\u0c33", + "\u0c35"-"\u0c39", + "\u0c3e"-"\u0c44", + "\u0c46"-"\u0c48", + "\u0c4a"-"\u0c4d", + "\u0c55"-"\u0c56", + "\u0c60"-"\u0c61", + "\u0c66"-"\u0c6f", + "\u0c82"-"\u0c83", + "\u0c85"-"\u0c8c", + "\u0c8e"-"\u0c90", + "\u0c92"-"\u0ca8", + "\u0caa"-"\u0cb3", + "\u0cb5"-"\u0cb9", + "\u0cbe"-"\u0cc4", + "\u0cc6"-"\u0cc8", + "\u0cca"-"\u0ccd", + "\u0cd5"-"\u0cd6", + "\u0cde", + "\u0ce0"-"\u0ce1", + "\u0ce6"-"\u0cef", + "\u0d02"-"\u0d03", + "\u0d05"-"\u0d0c", + "\u0d0e"-"\u0d10", + "\u0d12"-"\u0d28", + "\u0d2a"-"\u0d39", + "\u0d3e"-"\u0d43", + "\u0d46"-"\u0d48", + "\u0d4a"-"\u0d4d", + "\u0d57", + "\u0d60"-"\u0d61", + "\u0d66"-"\u0d6f", + "\u0d82"-"\u0d83", + "\u0d85"-"\u0d96", + "\u0d9a"-"\u0db1", + "\u0db3"-"\u0dbb", + "\u0dbd", + "\u0dc0"-"\u0dc6", + "\u0dca", + "\u0dcf"-"\u0dd4", + "\u0dd6", + "\u0dd8"-"\u0ddf", + "\u0df2"-"\u0df3", + "\u0e01"-"\u0e3a", + "\u0e3f"-"\u0e4e", + "\u0e50"-"\u0e59", + "\u0e81"-"\u0e82", + "\u0e84", + "\u0e87"-"\u0e88", + "\u0e8a", + "\u0e8d", + "\u0e94"-"\u0e97", + "\u0e99"-"\u0e9f", + "\u0ea1"-"\u0ea3", + "\u0ea5", + "\u0ea7", + "\u0eaa"-"\u0eab", + "\u0ead"-"\u0eb9", + "\u0ebb"-"\u0ebd", + "\u0ec0"-"\u0ec4", + "\u0ec6", + "\u0ec8"-"\u0ecd", + "\u0ed0"-"\u0ed9", + "\u0edc"-"\u0edd", + "\u0f00", + "\u0f18"-"\u0f19", + "\u0f20"-"\u0f29", + "\u0f35", + "\u0f37", + "\u0f39", + "\u0f3e"-"\u0f47", + "\u0f49"-"\u0f6a", + "\u0f71"-"\u0f84", + "\u0f86"-"\u0f8b", + "\u0f90"-"\u0f97", + "\u0f99"-"\u0fbc", + "\u0fc6", + "\u1000"-"\u1021", + "\u1023"-"\u1027", + "\u1029"-"\u102a", + "\u102c"-"\u1032", + "\u1036"-"\u1039", + "\u1040"-"\u1049", + "\u1050"-"\u1059", + "\u10a0"-"\u10c5", + "\u10d0"-"\u10f6", + "\u1100"-"\u1159", + "\u115f"-"\u11a2", + "\u11a8"-"\u11f9", + "\u1200"-"\u1206", + "\u1208"-"\u1246", + "\u1248", + "\u124a"-"\u124d", + "\u1250"-"\u1256", + "\u1258", + "\u125a"-"\u125d", + "\u1260"-"\u1286", + "\u1288", + "\u128a"-"\u128d", + "\u1290"-"\u12ae", + "\u12b0", + "\u12b2"-"\u12b5", + "\u12b8"-"\u12be", + "\u12c0", + "\u12c2"-"\u12c5", + "\u12c8"-"\u12ce", + "\u12d0"-"\u12d6", + "\u12d8"-"\u12ee", + "\u12f0"-"\u130e", + "\u1310", + "\u1312"-"\u1315", + "\u1318"-"\u131e", + "\u1320"-"\u1346", + "\u1348"-"\u135a", + "\u1369"-"\u1371", + "\u13a0"-"\u13f4", + "\u1401"-"\u166c", + "\u166f"-"\u1676", + "\u1681"-"\u169a", + "\u16a0"-"\u16ea", + "\u1780"-"\u17d3", + "\u17db", + "\u17e0"-"\u17e9", + "\u180b"-"\u180e", + "\u1810"-"\u1819", + "\u1820"-"\u1877", + "\u1880"-"\u18a9", + "\u1e00"-"\u1e9b", + "\u1ea0"-"\u1ef9", + "\u1f00"-"\u1f15", + "\u1f18"-"\u1f1d", + "\u1f20"-"\u1f45", + "\u1f48"-"\u1f4d", + "\u1f50"-"\u1f57", + "\u1f59", + "\u1f5b", + "\u1f5d", + "\u1f5f"-"\u1f7d", + "\u1f80"-"\u1fb4", + "\u1fb6"-"\u1fbc", + "\u1fbe", + "\u1fc2"-"\u1fc4", + "\u1fc6"-"\u1fcc", + "\u1fd0"-"\u1fd3", + "\u1fd6"-"\u1fdb", + "\u1fe0"-"\u1fec", + "\u1ff2"-"\u1ff4", + "\u1ff6"-"\u1ffc", + "\u200c"-"\u200f", + "\u202a"-"\u202e", + "\u203f"-"\u2040", + "\u206a"-"\u206f", + "\u207f", + "\u20a0"-"\u20af", + "\u20d0"-"\u20dc", + "\u20e1", + "\u2102", + "\u2107", + "\u210a"-"\u2113", + "\u2115", + "\u2119"-"\u211d", + "\u2124", + "\u2126", + "\u2128", + "\u212a"-"\u212d", + "\u212f"-"\u2131", + "\u2133"-"\u2139", + "\u2160"-"\u2183", + "\u3005"-"\u3007", + "\u3021"-"\u302f", + "\u3031"-"\u3035", + "\u3038"-"\u303a", + "\u3041"-"\u3094", + "\u3099"-"\u309a", + "\u309d"-"\u309e", + "\u30a1"-"\u30fe", + "\u3105"-"\u312c", + "\u3131"-"\u318e", + "\u31a0"-"\u31b7", + "\u3400"-"\u4db5", + "\u4e00"-"\u9fa5", + "\ua000"-"\ua48c", + "\uac00"-"\ud7a3", + "\uf900"-"\ufa2d", + "\ufb00"-"\ufb06", + "\ufb13"-"\ufb17", + "\ufb1d"-"\ufb28", + "\ufb2a"-"\ufb36", + "\ufb38"-"\ufb3c", + "\ufb3e", + "\ufb40"-"\ufb41", + "\ufb43"-"\ufb44", + "\ufb46"-"\ufbb1", + "\ufbd3"-"\ufd3d", + "\ufd50"-"\ufd8f", + "\ufd92"-"\ufdc7", + "\ufdf0"-"\ufdfb", + "\ufe20"-"\ufe23", + "\ufe33"-"\ufe34", + "\ufe4d"-"\ufe4f", + "\ufe69", + "\ufe70"-"\ufe72", + "\ufe74", + "\ufe76"-"\ufefc", + "\ufeff", + "\uff04", + "\uff10"-"\uff19", + "\uff21"-"\uff3a", + "\uff3f", + "\uff41"-"\uff5a", + "\uff65"-"\uffbe", + "\uffc2"-"\uffc7", + "\uffca"-"\uffcf", + "\uffd2"-"\uffd7", + "\uffda"-"\uffdc", + "\uffe0"-"\uffe1", + "\uffe5"-"\uffe6", + "\ufff9"-"\ufffb" + ] + > +} + +/* SEPARATORS */ + +TOKEN : +{ + < LPAREN: "(" > +| < RPAREN: ")" > +| < LBRACE: "{" > +| < RBRACE: "}" > +| < LBRACKET: "[" > +| < RBRACKET: "]" > +| < SEMICOLON: ";" > +| < COMMA: "," > +| < DOT: "." > +| < AT: "@" > +} + +/* OPERATORS */ + +TOKEN : +{ + < ASSIGN: "=" > +| < LT: "<" > +| < BANG: "!" > +| < TILDE: "~" > +| < HOOK: "?" > +| < COLON: ":" > +| < EQ: "==" > +| < LE: "<=" > +| < GE: ">=" > +| < NE: "!=" > +| < SC_OR: "||" > +| < SC_AND: "&&" > +| < INCR: "++" > +| < DECR: "--" > +| < PLUS: "+" > +| < MINUS: "-" > +| < STAR: "*" > +| < SLASH: "/" > +| < BIT_AND: "&" > +| < BIT_OR: "|" > +| < XOR: "^" > +| < REM: "%" > +| < LSHIFT: "<<" > +| < PLUSASSIGN: "+=" > +| < MINUSASSIGN: "-=" > +| < STARASSIGN: "*=" > +| < SLASHASSIGN: "/=" > +| < ANDASSIGN: "&=" > +| < ORASSIGN: "|=" > +| < XORASSIGN: "^=" > +| < REMASSIGN: "%=" > +| < LSHIFTASSIGN: "<<=" > +| < RSIGNEDSHIFTASSIGN: ">>=" > +| < RUNSIGNEDSHIFTASSIGN: ">>>=" > +| < ELLIPSIS: "..." > +} + +/* >'s need special attention due to generics syntax. */ +TOKEN : +{ + < RUNSIGNEDSHIFT: ">>>" > + { + matchedToken.kind = GT; + ((Token.GTToken)matchedToken).realKind = RUNSIGNEDSHIFT; + input_stream.backup(2); + matchedToken.image = ">"; + } +| < RSIGNEDSHIFT: ">>" > + { + matchedToken.kind = GT; + ((Token.GTToken)matchedToken).realKind = RSIGNEDSHIFT; + input_stream.backup(1); + matchedToken.image = ">"; + } +| < GT: ">" > +} + +boolean Line() : +{ + int modifiers; +} +{ + <EOF> { + return true; + } +| + LOOKAHEAD(BlockStatement()) + BlockStatement() { + return false; + } +| + LOOKAHEAD(Modifiers() [ TypeParameters() ] [ ResultType() ] <IDENTIFIER> FormalParameters() [ "throws" NameList() ] "{") + ClassOrInterfaceBodyDeclaration(false) { + return false; + } +| + LOOKAHEAD(ClassOrInterfaceBodyDeclaration(false)) + ClassOrInterfaceBodyDeclaration(false) { + return false; + } +| + LOOKAHEAD(Expression()) + Expression() { + return false; + } +| + ImportDeclaration() { + return false; + } +} + +/***************************************** + * THE JAVA LANGUAGE GRAMMAR STARTS HERE * + *****************************************/ + +/* + * Program structuring syntax follows. + */ + +void CompilationUnit(): +{} +{ + [ LOOKAHEAD( ( Annotation() )* "package" ) PackageDeclaration() ] + ( ImportDeclaration() )* + ( TypeDeclaration() )* + ( < "\u001a" > )? + ( <STUFF_TO_IGNORE: ~[]> )? + <EOF> +} + +void PackageDeclaration(): +{} +{ + Modifiers() "package" Name() ";" +} + +void ImportDeclaration(): +{} +{ + "import" [ "static" ] Name() [ "." "*" ] ";" +} + +/* + * Modifiers. We match all modifiers in a single rule to reduce the chances of + * syntax errors for simple modifier mistakes. It will also enable us to give + * better error messages. + */ + +int Modifiers(): +{ + int modifiers = 0; +} +{ + ( + LOOKAHEAD(2) + ( + "public" { modifiers |= ModifierSet.PUBLIC; } + | + "static" { modifiers |= ModifierSet.STATIC; } + | + "protected" { modifiers |= ModifierSet.PROTECTED; } + | + "private" { modifiers |= ModifierSet.PRIVATE; } + | + "final" { modifiers |= ModifierSet.FINAL; } + | + "abstract" { modifiers |= ModifierSet.ABSTRACT; } + | + "synchronized" { modifiers |= ModifierSet.SYNCHRONIZED; } + | + "native" { modifiers |= ModifierSet.NATIVE; } + | + "transient" { modifiers |= ModifierSet.TRANSIENT; } + | + "volatile" { modifiers |= ModifierSet.VOLATILE; } + | + "strictfp" { modifiers |= ModifierSet.STRICTFP; } + | + Annotation() + ) + )* + + { + return modifiers; + } +} + +/* + * Declaration syntax follows. + */ +void TypeDeclaration(): +{ + int modifiers; +} +{ + ";" +| + modifiers = Modifiers() + ( + ClassOrInterfaceDeclaration(modifiers) + | + EnumDeclaration(modifiers) + | + AnnotationTypeDeclaration(modifiers) + ) +} + + +void ClassOrInterfaceDeclaration(int modifiers): +{ + boolean isInterface = false; +} +{ + ( "class" | "interface" { isInterface = true; } ) + <IDENTIFIER> + [ TypeParameters() ] + [ ExtendsList(isInterface) ] + [ ImplementsList(isInterface) ] + ClassOrInterfaceBody(isInterface) +} + +void ExtendsList(boolean isInterface): +{ + boolean extendsMoreThanOne = false; +} +{ + "extends" ClassOrInterfaceType() + ( "," ClassOrInterfaceType() { extendsMoreThanOne = true; } )* + { + if (extendsMoreThanOne && !isInterface) + throw new ParseException("A class cannot extend more than one other class"); + } +} + +void ImplementsList(boolean isInterface): +{} +{ + "implements" ClassOrInterfaceType() + ( "," ClassOrInterfaceType() )* + { + if (isInterface) + throw new ParseException("An interface cannot implement other interfaces"); + } +} + +void EnumDeclaration(int modifiers): +{} +{ + "enum" <IDENTIFIER> + [ ImplementsList(false) ] + EnumBody() +} + +void EnumBody(): +{} +{ + "{" + [ EnumConstant() ( LOOKAHEAD(2) "," EnumConstant() )* ] + [ "," ] + [ ";" ( ClassOrInterfaceBodyDeclaration(false) )* ] + "}" +} + +void EnumConstant(): +{} +{ + Modifiers() <IDENTIFIER> [ Arguments() ] [ ClassOrInterfaceBody(false) ] +} + +void TypeParameters(): +{} +{ + "<" TypeParameter() ( "," TypeParameter() )* ">" +} + +void TypeParameter(): +{} +{ + <IDENTIFIER> [ TypeBound() ] +} + +void TypeBound(): +{} +{ + "extends" ClassOrInterfaceType() ( "&" ClassOrInterfaceType() )* +} + +void ClassOrInterfaceBody(boolean isInterface): +{} +{ + "{" ( ClassOrInterfaceBodyDeclaration(isInterface) )* "}" +} + +void ClassOrInterfaceBodyDeclaration(boolean isInterface): +{ + boolean isNestedInterface = false; + int modifiers; +} +{ + LOOKAHEAD(2) + Initializer() + { + if (isInterface) + throw new ParseException("An interface cannot have initializers"); + } +| + modifiers = Modifiers() // Just get all the modifiers out of the way. If you want to do + // more checks, pass the modifiers down to the member + ( + ClassOrInterfaceDeclaration(modifiers) + | + EnumDeclaration(modifiers) + | + LOOKAHEAD( [ TypeParameters() ] <IDENTIFIER> "(" ) + ConstructorDeclaration() + | + LOOKAHEAD( Type() <IDENTIFIER> ( "[" "]" )* ( "," | "=" | ";" ) ) + FieldDeclaration(modifiers) + | + MethodDeclaration(modifiers) + ) +| + ";" +} + +void FieldDeclaration(int modifiers): +{} +{ + // Modifiers are already matched in the caller + Type() VariableDeclarator() ( "," VariableDeclarator() )* ";" +} + +void VariableDeclarator(): +{} +{ + VariableDeclaratorId() [ "=" VariableInitializer() ] +} + +void VariableDeclaratorId(): +{} +{ + <IDENTIFIER> ( "[" "]" )* +} + +void VariableInitializer(): +{} +{ + ArrayInitializer() +| + Expression() +} + +void ArrayInitializer(): +{} +{ + "{" [ VariableInitializer() ( LOOKAHEAD(2) "," VariableInitializer() )* ] [ "," ] "}" +} + +void MethodDeclaration(int modifiers): +{} +{ + // Modifiers already matched in the caller! + [ TypeParameters() ] + ResultType() + MethodDeclarator() [ "throws" NameList() ] + ( Block() | ";" ) +} + +void MethodDeclarator(): +{} +{ + <IDENTIFIER> FormalParameters() ( "[" "]" )* +} + +void FormalParameters(): +{} +{ + "(" [ FormalParameter() ( "," FormalParameter() )* ] ")" +} + +void FormalParameter(): +{} +{ + Modifiers() Type() [ "..." ] VariableDeclaratorId() +} + +void ConstructorDeclaration(): +{} +{ + [ TypeParameters() ] + // Modifiers matched in the caller + <IDENTIFIER> FormalParameters() [ "throws" NameList() ] + "{" + [ LOOKAHEAD(ExplicitConstructorInvocation()) + ExplicitConstructorInvocation() + ] + ( BlockStatement() )* + "}" +} + +void ExplicitConstructorInvocation(): +{} +{ + ( <IDENTIFIER> "." )* [ LOOKAHEAD(2) "this" "." ] + [ TypeArguments() ] ("this"|"super") Arguments() ";" +} + +void Initializer(): +{} +{ + [ "static" ] Block() +} + + +/* + * Type, name and expression syntax follows. + */ + +void Type(): +{} +{ + LOOKAHEAD(2) ReferenceType() + | + PrimitiveType() +} + +void ReferenceType(): +{} +{ + PrimitiveType() ( LOOKAHEAD(2) "[" "]" )+ + | + ( ClassOrInterfaceType() ) ( LOOKAHEAD(2) "[" "]" )* +} + +void ClassOrInterfaceType(): +{} +{ + <IDENTIFIER> [ LOOKAHEAD(2) TypeArguments() ] + ( LOOKAHEAD(2) "." <IDENTIFIER> [ LOOKAHEAD(2) TypeArguments() ] )* +} + +void TypeArguments(): +{} +{ + "<" TypeArgument() ( "," TypeArgument() )* ">" +} + +void TypeArgument(): +{} +{ + ReferenceType() + | + "?" [ WildcardBounds() ] +} + +void WildcardBounds(): +{} +{ + "extends" ReferenceType() + | + "super" ReferenceType() +} + + +void PrimitiveType(): +{} +{ + "boolean" +| + "char" +| + "byte" +| + "short" +| + "int" +| + "long" +| + "float" +| + "double" +} + +void ResultType(): +{} +{ + "void" +| + Type() +} + +void Name(): +/* + * A lookahead of 2 is required below since "Name" can be followed + * by a ".*" when used in the context of an "ImportDeclaration". + */ +{} +{ + <IDENTIFIER> + ( LOOKAHEAD(2) "." <IDENTIFIER> + )* +} + +void NameList(): +{} +{ + Name() ( "," Name() )* +} + + +/* + * Expression syntax follows. + */ + +void Expression(): +/* + * This expansion has been written this way instead of: + * Assignment() | ConditionalExpression() + * for performance reasons. + * However, it is a weakening of the grammar for it allows the LHS of + * assignments to be any conditional expression whereas it can only be + * a primary expression. Consider adding a semantic predicate to work + * around this. + */ +{} +{ + ConditionalExpression() + [ + LOOKAHEAD(2) + AssignmentOperator() Expression() + ] +} + +void AssignmentOperator(): +{} +{ + "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | ">>>=" | "&=" | "^=" | "|=" +} + +void AssignmentExpression(): +{} +{ + PrimaryExpression() AssignmentOperator() Expression() +} + +void ConditionalExpression(): +{} +{ + ConditionalOrExpression() [ "?" Expression() ":" Expression() ] +} + +void ConditionalOrExpression(): +{} +{ + ConditionalAndExpression() ( "||" ConditionalAndExpression() )* +} + +void ConditionalAndExpression(): +{} +{ + InclusiveOrExpression() ( "&&" InclusiveOrExpression() )* +} + +void InclusiveOrExpression(): +{} +{ + ExclusiveOrExpression() ( "|" ExclusiveOrExpression() )* +} + +void ExclusiveOrExpression(): +{} +{ + AndExpression() ( "^" AndExpression() )* +} + +void AndExpression(): +{} +{ + EqualityExpression() ( "&" EqualityExpression() )* +} + +void EqualityExpression(): +{} +{ + InstanceOfExpression() ( ( "==" | "!=" ) InstanceOfExpression() )* +} + +void InstanceOfExpression(): +{} +{ + RelationalExpression() [ "instanceof" Type() ] +} + +void RelationalExpression(): +{} +{ + ShiftExpression() ( ( "<" | ">" | "<=" | ">=" ) ShiftExpression() )* +} + +void ShiftExpression(): +{} +{ + AdditiveExpression() ( ( "<<" | RSIGNEDSHIFT() | RUNSIGNEDSHIFT() ) AdditiveExpression() )* +} + +void AdditiveExpression(): +{} +{ + MultiplicativeExpression() ( ( "+" | "-" ) MultiplicativeExpression() )* +} + +void MultiplicativeExpression(): +{} +{ + UnaryExpression() ( ( "*" | "/" | "%" ) UnaryExpression() )* +} + +void UnaryExpression(): +{} +{ + ( "+" | "-" ) UnaryExpression() +| + PreIncrementExpression() +| + PreDecrementExpression() +| + UnaryExpressionNotPlusMinus() +} + +void PreIncrementExpression(): +{} +{ + "++" PrimaryExpression() +} + +void PreDecrementExpression(): +{} +{ + "--" PrimaryExpression() +} + +void UnaryExpressionNotPlusMinus(): +{} +{ + ( "~" | "!" ) UnaryExpression() +| + LOOKAHEAD( CastLookahead() ) + CastExpression() +| + PostfixExpression() +} + +// This production is to determine lookahead only. The LOOKAHEAD specifications +// below are not used, but they are there just to indicate that we know about +// this. +void CastLookahead(): +{} +{ + LOOKAHEAD(2) + "(" PrimitiveType() +| + LOOKAHEAD("(" Type() "[") + "(" Type() "[" "]" +| + "(" Type() ")" ( "~" | "!" | "(" | <IDENTIFIER> | "this" | "super" | "new" | Literal() ) +} + +void PostfixExpression(): +{} +{ + PrimaryExpression() [ PostfixOperator() ] +} + +void PostfixOperator(): +{} +{ + "++" | "--" +} + +void CastExpression(): +{} +{ + LOOKAHEAD("(" PrimitiveType()) + "(" Type() ")" UnaryExpression() +| + "(" Type() ")" UnaryExpressionNotPlusMinus() +} + +void PrimaryExpression(): +{} +{ + PrimaryPrefix() ( LOOKAHEAD(2) PrimarySuffix() )* +} + +void MemberSelector(): +{} +{ + "." TypeArguments() <IDENTIFIER> +} + +void PrimaryPrefix(): +{} +{ + Literal() +| + LOOKAHEAD( ( <IDENTIFIER> "." )* "this" ) + ( <IDENTIFIER> "." )* + "this" +| + "super" "." <IDENTIFIER> +| + "(" Expression() ")" +| + AllocationExpression() +| + LOOKAHEAD( ResultType() "." "class" ) + ResultType() "." "class" +| + Name() +} + +void PrimarySuffix(): +{} +{ + LOOKAHEAD("." "super" ".") + "." "super" +| + LOOKAHEAD("." "this") + "." "this" +| + LOOKAHEAD(2) + "." AllocationExpression() +| + LOOKAHEAD(3) + MemberSelector() +| + "[" Expression() "]" +| + "." <IDENTIFIER> +| + Arguments() +} + +void Literal(): +{} +{ + <INTEGER_LITERAL> +| + <FLOATING_POINT_LITERAL> +| + <CHARACTER_LITERAL> +| + <STRING_LITERAL> +| + BooleanLiteral() +| + NullLiteral() +} + +void BooleanLiteral(): +{} +{ + "true" +| + "false" +} + +void NullLiteral(): +{} +{ + "null" +} + +void Arguments(): +{} +{ + "(" [ ArgumentList() ] ")" +} + +void ArgumentList(): +{} +{ + Expression() ( "," Expression() )* +} + +void AllocationExpression(): +{} +{ + LOOKAHEAD(2) + "new" PrimitiveType() ArrayDimsAndInits() +| + "new" ClassOrInterfaceType() [ TypeArguments() ] + ( + ArrayDimsAndInits() + | + Arguments() [ ClassOrInterfaceBody(false) ] + ) +} + +/* + * The third LOOKAHEAD specification below is to parse to PrimarySuffix + * if there is an expression between the "[...]". + */ +void ArrayDimsAndInits(): +{} +{ + LOOKAHEAD(2) + ( LOOKAHEAD(2) "[" Expression() "]" )+ ( LOOKAHEAD(2) "[" "]" )* +| + ( "[" "]" )+ ArrayInitializer() +} + + +/* + * Statement syntax follows. + */ + +void Statement(): +{} +{ + LOOKAHEAD(2) + LabeledStatement() +| + AssertStatement() +| + Block() +| + EmptyStatement() +| + StatementExpression() ";" +| + SwitchStatement() +| + IfStatement() +| + WhileStatement() +| + DoStatement() +| + ForStatement() +| + BreakStatement() +| + ContinueStatement() +| + ReturnStatement() +| + ThrowStatement() +| + SynchronizedStatement() +| + TryStatement() +} + +void AssertStatement(): +{} +{ + "assert" Expression() [ ":" Expression() ] ";" +} + +void LabeledStatement(): +{} +{ + <IDENTIFIER> ":" Statement() +} + +void Block(): +{} +{ + "{" ( BlockStatement() )* "}" +} + +void BlockStatement(): +{} +{ + LOOKAHEAD( Modifiers() Type() <IDENTIFIER> ) + LocalVariableDeclaration() ";" +| + Statement() +| + ClassOrInterfaceDeclaration(0) +} + +void LocalVariableDeclaration(): +{} +{ + Modifiers() Type() VariableDeclarator() ( "," VariableDeclarator() )* +} + +void EmptyStatement(): +{} +{ + ";" +} + +void StatementExpression(): +{} +{ + PreIncrementExpression() +| + PreDecrementExpression() +| + LOOKAHEAD(PrimaryExpression() AssignmentOperator()) + AssignmentExpression() +| + PostfixExpression() +} + +void SwitchStatement(): +{} +{ + "switch" "(" Expression() ")" "{" + ( SwitchLabel() ( BlockStatement() )* )* + "}" +} + +void SwitchLabel(): +{} +{ + "case" Expression() ":" +| + "default" ":" +} + +void IfStatement(): +/* + * The disambiguating algorithm of JavaCC automatically binds dangling + * else's to the innermost if statement. The LOOKAHEAD specification + * is to tell JavaCC that we know what we are doing. + */ +{} +{ + "if" "(" Expression() ")" Statement() [ LOOKAHEAD(1) "else" Statement() ] +} + +void WhileStatement(): +{} +{ + "while" "(" Expression() ")" Statement() +} + +void DoStatement(): +{} +{ + "do" Statement() "while" "(" Expression() ")" ";" +} + +void ForStatement(): +{} +{ + "for" "(" + + ( + LOOKAHEAD(Modifiers() Type() <IDENTIFIER> ":") + Modifiers() Type() <IDENTIFIER> ":" Expression() + | + [ ForInit() ] ";" [ Expression() ] ";" [ ForUpdate() ] + ) + + ")" Statement() +} + +void ForInit(): +{} +{ + LOOKAHEAD( Modifiers() Type() <IDENTIFIER> ) + LocalVariableDeclaration() +| + StatementExpressionList() +} + +void StatementExpressionList(): +{} +{ + StatementExpression() ( "," StatementExpression() )* +} + +void ForUpdate(): +{} +{ + StatementExpressionList() +} + +void BreakStatement(): +{} +{ + "break" [ <IDENTIFIER> ] ";" +} + +void ContinueStatement(): +{} +{ + "continue" [ <IDENTIFIER> ] ";" +} + +void ReturnStatement(): +{} +{ + "return" [ Expression() ] ";" +} + +void ThrowStatement(): +{} +{ + "throw" Expression() ";" +} + +void SynchronizedStatement(): +{} +{ + "synchronized" "(" Expression() ")" Block() +} + +void TryStatement(): +/* + * Semantic check required here to make sure that at least one + * finally/catch is present. + */ +{} +{ + "try" Block() + ( "catch" "(" FormalParameter() ")" Block() )* + [ "finally" Block() ] +} + +/* We use productions to match >>>, >> and > so that we can keep the + * type declaration syntax with generics clean + */ + +void RUNSIGNEDSHIFT(): +{} +{ + ( LOOKAHEAD({ getToken(1).kind == GT && + ((Token.GTToken)getToken(1)).realKind == RUNSIGNEDSHIFT} ) + ">" ">" ">" + ) +} + +void RSIGNEDSHIFT(): +{} +{ + ( LOOKAHEAD({ getToken(1).kind == GT && + ((Token.GTToken)getToken(1)).realKind == RSIGNEDSHIFT} ) + ">" ">" + ) +} + +/* Annotation syntax follows. */ + +void Annotation(): +{} +{ + LOOKAHEAD( "@" Name() "(" ( <IDENTIFIER> "=" | ")" )) + NormalAnnotation() + | + LOOKAHEAD( "@" Name() "(" ) + SingleMemberAnnotation() + | + MarkerAnnotation() +} + +void NormalAnnotation(): +{} +{ + "@" Name() "(" [ MemberValuePairs() ] ")" +} + +void MarkerAnnotation(): +{} +{ + "@" Name() +} + +void SingleMemberAnnotation(): +{} +{ + "@" Name() "(" MemberValue() ")" +} + +void MemberValuePairs(): +{} +{ + MemberValuePair() ( "," MemberValuePair() )* +} + +void MemberValuePair(): +{} +{ + <IDENTIFIER> "=" MemberValue() +} + +void MemberValue(): +{} +{ + Annotation() + | + MemberValueArrayInitializer() + | + ConditionalExpression() +} + +void MemberValueArrayInitializer(): +{} +{ + "{" MemberValue() ( LOOKAHEAD(2) "," MemberValue() )* [ "," ] "}" +} + + +/* Annotation Types. */ + +void AnnotationTypeDeclaration(int modifiers): +{} +{ + "@" "interface" <IDENTIFIER> AnnotationTypeBody() +} + +void AnnotationTypeBody(): +{} +{ + "{" ( AnnotationTypeMemberDeclaration() )* "}" +} + +void AnnotationTypeMemberDeclaration(): +{ + int modifiers; +} +{ + modifiers = Modifiers() + ( + LOOKAHEAD(Type() <IDENTIFIER> "(") + Type() <IDENTIFIER> "(" ")" [ DefaultValue() ] ";" + | + ClassOrInterfaceDeclaration(modifiers) + | + EnumDeclaration(modifiers) + | + AnnotationTypeDeclaration(modifiers) + | + FieldDeclaration(modifiers) + ) + | + ( ";" ) +} + +void DefaultValue(): +{} +{ + "default" MemberValue() +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/parser/JavaCharStream.java b/trunk/jaxx-compiler/src/main/java/jaxx/parser/JavaCharStream.java new file mode 100644 index 0000000..f60fb69 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/parser/JavaCharStream.java @@ -0,0 +1,530 @@ +/* Generated By:JavaCC: Do not edit this line. JavaCharStream.java Version 4.0 */ +package jaxx.parser; + +/** + * An implementation of interface CharStream, where the stream is assumed to + * contain only ASCII characters (with java-like unicode escape processing). + */ + +public class JavaCharStream { + public static final boolean staticFlag = false; + + static int hexval(char c) throws java.io.IOException { + switch (c) { + case '0': + return 0; + case '1': + return 1; + case '2': + return 2; + case '3': + return 3; + case '4': + return 4; + case '5': + return 5; + case '6': + return 6; + case '7': + return 7; + case '8': + return 8; + case '9': + return 9; + + case 'a': + case 'A': + return 10; + case 'b': + case 'B': + return 11; + case 'c': + case 'C': + return 12; + case 'd': + case 'D': + return 13; + case 'e': + case 'E': + return 14; + case 'f': + case 'F': + return 15; + } + + throw new java.io.IOException(); // Should never come here + } + + public int bufpos = -1; + int bufsize; + int available; + int tokenBegin; + protected int bufline[]; + protected int bufcolumn[]; + + protected int column = 0; + protected int line = 1; + + protected boolean prevCharIsCR = false; + protected boolean prevCharIsLF = false; + + protected java.io.Reader inputStream; + + protected char[] nextCharBuf; + protected char[] buffer; + protected int maxNextCharInd = 0; + protected int nextCharInd = -1; + protected int inBuf = 0; + protected int tabSize = 8; + + protected void setTabSize(int i) { + tabSize = i; + } + + protected int getTabSize(int i) { + return tabSize; + } + + protected void ExpandBuff(boolean wrapAround) { + char[] newbuffer = new char[bufsize + 2048]; + int newbufline[] = new int[bufsize + 2048]; + int newbufcolumn[] = new int[bufsize + 2048]; + + try { + if (wrapAround) { + System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); + System.arraycopy(buffer, 0, newbuffer, + bufsize - tokenBegin, bufpos); + buffer = newbuffer; + + System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); + System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos); + bufline = newbufline; + + System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); + System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos); + bufcolumn = newbufcolumn; + + bufpos += (bufsize - tokenBegin); + } else { + System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); + buffer = newbuffer; + + System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); + bufline = newbufline; + + System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); + bufcolumn = newbufcolumn; + + bufpos -= tokenBegin; + } + } + catch (Throwable t) { + throw new Error(t.getMessage()); + } + + available = (bufsize += 2048); + tokenBegin = 0; + } + + protected void FillBuff() throws java.io.IOException { + int i; + if (maxNextCharInd == 4096) + maxNextCharInd = nextCharInd = 0; + + try { + if ((i = inputStream.read(nextCharBuf, maxNextCharInd, + 4096 - maxNextCharInd)) == -1) { + inputStream.close(); + throw new java.io.IOException(); + } else { + maxNextCharInd += i; + } + } + catch (java.io.IOException e) { + if (bufpos != 0) { + --bufpos; + backup(0); + } else { + bufline[bufpos] = line; + bufcolumn[bufpos] = column; + } + throw e; + } + } + + protected char ReadByte() throws java.io.IOException { + if (++nextCharInd >= maxNextCharInd) + FillBuff(); + + return nextCharBuf[nextCharInd]; + } + + public char BeginToken() throws java.io.IOException { + if (inBuf > 0) { + --inBuf; + + if (++bufpos == bufsize) { + bufpos = 0; + } + + tokenBegin = bufpos; + return buffer[bufpos]; + } + + tokenBegin = 0; + bufpos = -1; + + return readChar(); + } + + protected void AdjustBuffSize() { + if (available == bufsize) { + if (tokenBegin > 2048) { + bufpos = 0; + available = tokenBegin; + } else + ExpandBuff(false); + } else if (available > tokenBegin) + available = bufsize; + else if ((tokenBegin - available) < 2048) + ExpandBuff(true); + else + available = tokenBegin; + } + + protected void UpdateLineColumn(char c) { + column++; + + if (prevCharIsLF) { + prevCharIsLF = false; + line += (column = 1); + } else if (prevCharIsCR) { + prevCharIsCR = false; + if (c == '\n') { + prevCharIsLF = true; + } else + line += (column = 1); + } + + switch (c) { + case '\r': + prevCharIsCR = true; + break; + case '\n': + prevCharIsLF = true; + break; + case '\t': + column--; + column += (tabSize - (column % tabSize)); + break; + default: + break; + } + + bufline[bufpos] = line; + bufcolumn[bufpos] = column; + } + + public char readChar() throws java.io.IOException { + if (inBuf > 0) { + --inBuf; + + if (++bufpos == bufsize) + bufpos = 0; + + return buffer[bufpos]; + } + + char c; + + if (++bufpos == available) + AdjustBuffSize(); + + if ((buffer[bufpos] = c = ReadByte()) == '\\') { + UpdateLineColumn(c); + + int backSlashCnt = 1; + + for (; ;) // Read all the backslashes + { + if (++bufpos == available) + AdjustBuffSize(); + + try { + if ((buffer[bufpos] = c = ReadByte()) != '\\') { + UpdateLineColumn(c); + // found a non-backslash char. + if ((c == 'u') && ((backSlashCnt & 1) == 1)) { + if (--bufpos < 0) + bufpos = bufsize - 1; + + break; + } + + backup(backSlashCnt); + return '\\'; + } + } + catch (java.io.IOException e) { + if (backSlashCnt > 1) + backup(backSlashCnt); + + return '\\'; + } + + UpdateLineColumn(c); + backSlashCnt++; + } + + // Here, we have seen an odd number of backslash's followed by a 'u' + try { + while ((c = ReadByte()) == 'u') + ++column; + + buffer[bufpos] = c = (char) (hexval(c) << 12 | + hexval(ReadByte()) << 8 | + hexval(ReadByte()) << 4 | + hexval(ReadByte())); + + column += 4; + } + catch (java.io.IOException e) { + throw new Error("Invalid escape character at line " + line + + " column " + column + "."); + } + + if (backSlashCnt == 1) + return c; + else { + backup(backSlashCnt - 1); + return '\\'; + } + } else { + UpdateLineColumn(c); + return (c); + } + } + + /** + * @return column index + * @see #getEndColumn + * @deprecated + */ + + public int getColumn() { + return bufcolumn[bufpos]; + } + + /** + * @return line type ??? + * @see #getEndLine + * @deprecated + */ + + public int getLine() { + return bufline[bufpos]; + } + + public int getEndColumn() { + return bufcolumn[bufpos]; + } + + public int getEndLine() { + return bufline[bufpos]; + } + + public int getBeginColumn() { + return bufcolumn[tokenBegin]; + } + + public int getBeginLine() { + return bufline[tokenBegin]; + } + + public void backup(int amount) { + + inBuf += amount; + if ((bufpos -= amount) < 0) + bufpos += bufsize; + } + + public JavaCharStream(java.io.Reader dstream, + int startline, int startcolumn, int buffersize) { + inputStream = dstream; + line = startline; + column = startcolumn - 1; + + available = bufsize = buffersize; + buffer = new char[buffersize]; + bufline = new int[buffersize]; + bufcolumn = new int[buffersize]; + nextCharBuf = new char[4096]; + } + + public JavaCharStream(java.io.Reader dstream, + int startline, int startcolumn) { + this(dstream, startline, startcolumn, 4096); + } + + public JavaCharStream(java.io.Reader dstream) { + this(dstream, 1, 1, 4096); + } + + public void ReInit(java.io.Reader dstream, + int startline, int startcolumn, int buffersize) { + inputStream = dstream; + line = startline; + column = startcolumn - 1; + + if (buffer == null || buffersize != buffer.length) { + available = bufsize = buffersize; + buffer = new char[buffersize]; + bufline = new int[buffersize]; + bufcolumn = new int[buffersize]; + nextCharBuf = new char[4096]; + } + prevCharIsLF = prevCharIsCR = false; + tokenBegin = inBuf = maxNextCharInd = 0; + nextCharInd = bufpos = -1; + } + + public void ReInit(java.io.Reader dstream, + int startline, int startcolumn) { + ReInit(dstream, startline, startcolumn, 4096); + } + + public void ReInit(java.io.Reader dstream) { + ReInit(dstream, 1, 1, 4096); + } + + public JavaCharStream(java.io.InputStream dstream, String encoding, int startline, + int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException { + this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); + } + + public JavaCharStream(java.io.InputStream dstream, int startline, + int startcolumn, int buffersize) { + this(new java.io.InputStreamReader(dstream), startline, startcolumn, 4096); + } + + public JavaCharStream(java.io.InputStream dstream, String encoding, int startline, + int startcolumn) throws java.io.UnsupportedEncodingException { + this(dstream, encoding, startline, startcolumn, 4096); + } + + public JavaCharStream(java.io.InputStream dstream, int startline, + int startcolumn) { + this(dstream, startline, startcolumn, 4096); + } + + public JavaCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException { + this(dstream, encoding, 1, 1, 4096); + } + + public JavaCharStream(java.io.InputStream dstream) { + this(dstream, 1, 1, 4096); + } + + public void ReInit(java.io.InputStream dstream, String encoding, int startline, + int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException { + ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); + } + + public void ReInit(java.io.InputStream dstream, int startline, + int startcolumn, int buffersize) { + ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); + } + + public void ReInit(java.io.InputStream dstream, String encoding, int startline, + int startcolumn) throws java.io.UnsupportedEncodingException { + ReInit(dstream, encoding, startline, startcolumn, 4096); + } + + public void ReInit(java.io.InputStream dstream, int startline, + int startcolumn) { + ReInit(dstream, startline, startcolumn, 4096); + } + + public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException { + ReInit(dstream, encoding, 1, 1, 4096); + } + + public void ReInit(java.io.InputStream dstream) { + ReInit(dstream, 1, 1, 4096); + } + + public String GetImage() { + if (bufpos >= tokenBegin) + return new String(buffer, tokenBegin, bufpos - tokenBegin + 1); + else + return new String(buffer, tokenBegin, bufsize - tokenBegin) + + new String(buffer, 0, bufpos + 1); + } + + public char[] GetSuffix(int len) { + char[] ret = new char[len]; + + if ((bufpos + 1) >= len) + System.arraycopy(buffer, bufpos - len + 1, ret, 0, len); + else { + System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0, + len - bufpos - 1); + System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1); + } + + return ret; + } + + public void Done() { + nextCharBuf = null; + buffer = null; + bufline = null; + bufcolumn = null; + } + + /** + * Method to adjust line and column numbers for the start of a token. + * + * @param newLine line number ? + * @param newCol column number ? + */ + public void adjustBeginLineColumn(int newLine, int newCol) { + int start = tokenBegin; + int len; + + if (bufpos >= tokenBegin) { + len = bufpos - tokenBegin + inBuf + 1; + } else { + len = bufsize - tokenBegin + bufpos + 1 + inBuf; + } + + int i = 0, j = 0, k; + int nextColDiff, columnDiff = 0; + + while (i < len && + bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) { + bufline[j] = newLine; + nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j]; + bufcolumn[j] = newCol + columnDiff; + columnDiff = nextColDiff; + i++; + } + + if (i < len) { + bufline[j] = newLine++; + bufcolumn[j] = newCol + columnDiff; + + while (i++ < len) { + if (bufline[j = start % bufsize] != bufline[++start % bufsize]) + bufline[j] = newLine++; + else + bufline[j] = newLine; + } + } + + line = bufline[j]; + column = bufcolumn[j]; + } + +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/parser/JavaParser.java b/trunk/jaxx-compiler/src/main/java/jaxx/parser/JavaParser.java new file mode 100644 index 0000000..21f786c --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/parser/JavaParser.java @@ -0,0 +1,10048 @@ +/* Generated By:JJTree&JavaCC: Do not edit this line. JavaParser.java */ +package jaxx.parser; + +import java.io.File; +import java.io.FileInputStream; + +/** + * Grammar to parse Java version 1.5 + * + * @author Sreenivasa Viswanadha - Simplified and enhanced for 1.5 + */ +public class JavaParser/*@bgen(jjtree)*/ implements JavaParserTreeConstants, JavaParserConstants {/*@bgen(jjtree)*/ + protected JJTJavaParserState jjtree = new JJTJavaParserState(); + + /** Class to hold modifiers. */ + static public final class ModifierSet { + /* Definitions of the bits in the modifiers field. */ + public static final int PUBLIC = 0x0001; + public static final int PROTECTED = 0x0002; + public static final int PRIVATE = 0x0004; + public static final int ABSTRACT = 0x0008; + public static final int STATIC = 0x0010; + public static final int FINAL = 0x0020; + public static final int SYNCHRONIZED = 0x0040; + public static final int NATIVE = 0x0080; + public static final int TRANSIENT = 0x0100; + public static final int VOLATILE = 0x0200; + public static final int STRICTFP = 0x1000; + + /** + * A set of accessors that indicate whether the specified modifier + * is in the set. + */ + + public boolean isPublic(int modifiers) { + return (modifiers & PUBLIC) != 0; + } + + public boolean isProtected(int modifiers) { + return (modifiers & PROTECTED) != 0; + } + + public boolean isPrivate(int modifiers) { + return (modifiers & PRIVATE) != 0; + } + + public boolean isStatic(int modifiers) { + return (modifiers & STATIC) != 0; + } + + public boolean isAbstract(int modifiers) { + return (modifiers & ABSTRACT) != 0; + } + + public boolean isFinal(int modifiers) { + return (modifiers & FINAL) != 0; + } + + public boolean isNative(int modifiers) { + return (modifiers & NATIVE) != 0; + } + + public boolean isStrictfp(int modifiers) { + return (modifiers & STRICTFP) != 0; + } + + public boolean isSynchronized(int modifiers) { + return (modifiers & SYNCHRONIZED) != 0; + } + + public boolean isTransient(int modifiers) { + return (modifiers & TRANSIENT) != 0; + } + + public boolean isVolatile(int modifiers) { + return (modifiers & VOLATILE) != 0; + } + + /** Removes the given modifier. */ + static int removeModifier(int modifiers, int mod) { + return modifiers & ~mod; + } + } + + public JavaParser(String fileName) { + this(System.in); + try { + ReInit(new FileInputStream(new File(fileName))); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + void jjtreeOpenNodeScope(Node n) { + ((SimpleNode) n).firstToken = getToken(1); + } + + void jjtreeCloseNodeScope(Node n) { + ((SimpleNode) n).lastToken = getToken(0); + } + + public SimpleNode popNode() { + if (jjtree.nodeArity() > 0) // number of child nodes + return (SimpleNode) jjtree.popNode(); + else + return null; + } + + public static void main(String args[]) { + JavaParser parser; + if (args.length == 0) { + System.out.println("Java Parser Version 1.1: Reading from standard input . . ."); + parser = new JavaParser(System.in); + } else if (args.length == 1) { + System.out.println("Java Parser Version 1.1: Reading from file " + args[0] + " . . ."); + try { + parser = new JavaParser(new java.io.FileInputStream(args[0])); + } catch (java.io.FileNotFoundException e) { + System.out.println("Java Parser Version 1.1: File " + args[0] + " not found."); + return; + } + } else { + System.out.println("Java Parser Version 1.1: Usage is one of:"); + System.out.println(" java JavaParser < inputfile"); + System.out.println("OR"); + System.out.println(" java JavaParser inputfile"); + return; + } + try { + parser.CompilationUnit(); + System.out.println("Java Parser Version 1.1: Java program parsed successfully."); + } catch (ParseException e) { + System.out.println(e.getMessage()); + System.out.println("Java Parser Version 1.1: Encountered errors during parse."); + } + } + + final public boolean Line() throws ParseException { + /*@bgen(jjtree) Line */ + SimpleNode jjtn000 = new SimpleNode(JJTLINE); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + int modifiers; + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case 0: + jj_consume_token(0); + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtreeCloseNodeScope(jjtn000); + { + if (true) return true; + } + break; + default: + if (jj_2_1(2147483647)) { + BlockStatement(); + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtreeCloseNodeScope(jjtn000); + { + if (true) return false; + } + } else if (jj_2_2(2147483647)) { + ClassOrInterfaceBodyDeclaration(false); + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtreeCloseNodeScope(jjtn000); + { + if (true) return false; + } + } else if (jj_2_3(2147483647)) { + ClassOrInterfaceBodyDeclaration(false); + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtreeCloseNodeScope(jjtn000); + { + if (true) return false; + } + } else if (jj_2_4(2147483647)) { + Expression(); + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtreeCloseNodeScope(jjtn000); + { + if (true) return false; + } + } else { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case IMPORT: + ImportDeclaration(); + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtreeCloseNodeScope(jjtn000); + { + if (true) return false; + } + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + throw new Error("Missing return statement in function"); + } + + /** + * ************************************** + * THE JAVA LANGUAGE GRAMMAR STARTS HERE * + * *************************************** + */ + +/* + * Program structuring syntax follows. + */ + final public void CompilationUnit() throws ParseException { + /*@bgen(jjtree) CompilationUnit */ + SimpleNode jjtn000 = new SimpleNode(JJTCOMPILATIONUNIT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + if (jj_2_5(2147483647)) { + PackageDeclaration(); + } else { + ; + } + label_1: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case IMPORT: + ; + break; + default: + break label_1; + } + ImportDeclaration(); + } + label_2: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case ABSTRACT: + case CLASS: + case ENUM: + case FINAL: + case INTERFACE: + case NATIVE: + case PRIVATE: + case PROTECTED: + case PUBLIC: + case STATIC: + case STRICTFP: + case SYNCHRONIZED: + case TRANSIENT: + case VOLATILE: + case SEMICOLON: + case AT: + ; + break; + default: + break label_2; + } + TypeDeclaration(); + } + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case 123: + jj_consume_token(123); + break; + default: + ; + } + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case STUFF_TO_IGNORE: + jj_consume_token(STUFF_TO_IGNORE); + break; + default: + ; + } + jj_consume_token(0); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void PackageDeclaration() throws ParseException { + /*@bgen(jjtree) PackageDeclaration */ + SimpleNode jjtn000 = new SimpleNode(JJTPACKAGEDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + Modifiers(); + jj_consume_token(PACKAGE); + Name(); + jj_consume_token(SEMICOLON); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void ImportDeclaration() throws ParseException { + /*@bgen(jjtree) ImportDeclaration */ + SimpleNode jjtn000 = new SimpleNode(JJTIMPORTDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(IMPORT); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case STATIC: + jj_consume_token(STATIC); + break; + default: + ; + } + Name(); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case DOT: + jj_consume_token(DOT); + jj_consume_token(STAR); + break; + default: + ; + } + jj_consume_token(SEMICOLON); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + /* + * Modifiers. We match all modifiers in a single rule to reduce the chances of + * syntax errors for simple modifier mistakes. It will also enable us to give + * better error messages. + */ + final public int Modifiers() throws ParseException { + /*@bgen(jjtree) Modifiers */ + SimpleNode jjtn000 = new SimpleNode(JJTMODIFIERS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + int modifiers = 0; + try { + label_3: + while (true) { + if (jj_2_6(2)) { + ; + } else { + break label_3; + } + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case PUBLIC: + jj_consume_token(PUBLIC); + modifiers |= ModifierSet.PUBLIC; + break; + case STATIC: + jj_consume_token(STATIC); + modifiers |= ModifierSet.STATIC; + break; + case PROTECTED: + jj_consume_token(PROTECTED); + modifiers |= ModifierSet.PROTECTED; + break; + case PRIVATE: + jj_consume_token(PRIVATE); + modifiers |= ModifierSet.PRIVATE; + break; + case FINAL: + jj_consume_token(FINAL); + modifiers |= ModifierSet.FINAL; + break; + case ABSTRACT: + jj_consume_token(ABSTRACT); + modifiers |= ModifierSet.ABSTRACT; + break; + case SYNCHRONIZED: + jj_consume_token(SYNCHRONIZED); + modifiers |= ModifierSet.SYNCHRONIZED; + break; + case NATIVE: + jj_consume_token(NATIVE); + modifiers |= ModifierSet.NATIVE; + break; + case TRANSIENT: + jj_consume_token(TRANSIENT); + modifiers |= ModifierSet.TRANSIENT; + break; + case VOLATILE: + jj_consume_token(VOLATILE); + modifiers |= ModifierSet.VOLATILE; + break; + case STRICTFP: + jj_consume_token(STRICTFP); + modifiers |= ModifierSet.STRICTFP; + break; + case AT: + Annotation(); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtreeCloseNodeScope(jjtn000); + { + if (true) return modifiers; + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + throw new Error("Missing return statement in function"); + } + + /* + * Declaration syntax follows. + */ + final public void TypeDeclaration() throws ParseException { + /*@bgen(jjtree) TypeDeclaration */ + SimpleNode jjtn000 = new SimpleNode(JJTTYPEDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + int modifiers; + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case SEMICOLON: + jj_consume_token(SEMICOLON); + break; + case ABSTRACT: + case CLASS: + case ENUM: + case FINAL: + case INTERFACE: + case NATIVE: + case PRIVATE: + case PROTECTED: + case PUBLIC: + case STATIC: + case STRICTFP: + case SYNCHRONIZED: + case TRANSIENT: + case VOLATILE: + case AT: + modifiers = Modifiers(); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case CLASS: + case INTERFACE: + ClassOrInterfaceDeclaration(modifiers); + break; + case ENUM: + EnumDeclaration(modifiers); + break; + case AT: + AnnotationTypeDeclaration(modifiers); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void ClassOrInterfaceDeclaration(int modifiers) throws ParseException { + /*@bgen(jjtree) ClassOrInterfaceDeclaration */ + SimpleNode jjtn000 = new SimpleNode(JJTCLASSORINTERFACEDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + boolean isInterface = false; + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case CLASS: + jj_consume_token(CLASS); + break; + case INTERFACE: + jj_consume_token(INTERFACE); + isInterface = true; + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + jj_consume_token(IDENTIFIER); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case LT: + TypeParameters(); + break; + default: + ; + } + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case EXTENDS: + ExtendsList(isInterface); + break; + default: + ; + } + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case IMPLEMENTS: + ImplementsList(isInterface); + break; + default: + ; + } + ClassOrInterfaceBody(isInterface); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void ExtendsList(boolean isInterface) throws ParseException { + /*@bgen(jjtree) ExtendsList */ + SimpleNode jjtn000 = new SimpleNode(JJTEXTENDSLIST); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + boolean extendsMoreThanOne = false; + try { + jj_consume_token(EXTENDS); + ClassOrInterfaceType(); + label_4: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case COMMA: + ; + break; + default: + break label_4; + } + jj_consume_token(COMMA); + ClassOrInterfaceType(); + extendsMoreThanOne = true; + } + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtreeCloseNodeScope(jjtn000); + if (extendsMoreThanOne && !isInterface) { + if (true) + throw new ParseException("A class cannot extend more than one other class"); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void ImplementsList(boolean isInterface) throws ParseException { + /*@bgen(jjtree) ImplementsList */ + SimpleNode jjtn000 = new SimpleNode(JJTIMPLEMENTSLIST); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(IMPLEMENTS); + ClassOrInterfaceType(); + label_5: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case COMMA: + ; + break; + default: + break label_5; + } + jj_consume_token(COMMA); + ClassOrInterfaceType(); + } + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtreeCloseNodeScope(jjtn000); + if (isInterface) { + if (true) + throw new ParseException("An interface cannot implement other interfaces"); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void EnumDeclaration(int modifiers) throws ParseException { + /*@bgen(jjtree) EnumDeclaration */ + SimpleNode jjtn000 = new SimpleNode(JJTENUMDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(ENUM); + jj_consume_token(IDENTIFIER); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case IMPLEMENTS: + ImplementsList(false); + break; + default: + ; + } + EnumBody(); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void EnumBody() throws ParseException { + /*@bgen(jjtree) EnumBody */ + SimpleNode jjtn000 = new SimpleNode(JJTENUMBODY); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(LBRACE); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case ABSTRACT: + case FINAL: + case NATIVE: + case PRIVATE: + case PROTECTED: + case PUBLIC: + case STATIC: + case STRICTFP: + case SYNCHRONIZED: + case TRANSIENT: + case VOLATILE: + case IDENTIFIER: + case AT: + EnumConstant(); + label_6: + while (true) { + if (jj_2_7(2)) { + ; + } else { + break label_6; + } + jj_consume_token(COMMA); + EnumConstant(); + } + break; + default: + ; + } + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case COMMA: + jj_consume_token(COMMA); + break; + default: + ; + } + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case SEMICOLON: + jj_consume_token(SEMICOLON); + label_7: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case ABSTRACT: + case BOOLEAN: + case BYTE: + case CHAR: + case CLASS: + case DOUBLE: + case ENUM: + case FINAL: + case FLOAT: + case INT: + case INTERFACE: + case LONG: + case NATIVE: + case PRIVATE: + case PROTECTED: + case PUBLIC: + case SHORT: + case STATIC: + case STRICTFP: + case SYNCHRONIZED: + case TRANSIENT: + case VOID: + case VOLATILE: + case IDENTIFIER: + case LBRACE: + case SEMICOLON: + case AT: + case LT: + ; + break; + default: + break label_7; + } + ClassOrInterfaceBodyDeclaration(false); + } + break; + default: + ; + } + jj_consume_token(RBRACE); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void EnumConstant() throws ParseException { + /*@bgen(jjtree) EnumConstant */ + SimpleNode jjtn000 = new SimpleNode(JJTENUMCONSTANT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + Modifiers(); + jj_consume_token(IDENTIFIER); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case LPAREN: + Arguments(); + break; + default: + ; + } + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case LBRACE: + ClassOrInterfaceBody(false); + break; + default: + ; + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void TypeParameters() throws ParseException { + /*@bgen(jjtree) TypeParameters */ + SimpleNode jjtn000 = new SimpleNode(JJTTYPEPARAMETERS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(LT); + TypeParameter(); + label_8: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case COMMA: + ; + break; + default: + break label_8; + } + jj_consume_token(COMMA); + TypeParameter(); + } + jj_consume_token(GT); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void TypeParameter() throws ParseException { + /*@bgen(jjtree) TypeParameter */ + SimpleNode jjtn000 = new SimpleNode(JJTTYPEPARAMETER); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(IDENTIFIER); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case EXTENDS: + TypeBound(); + break; + default: + ; + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void TypeBound() throws ParseException { + /*@bgen(jjtree) TypeBound */ + SimpleNode jjtn000 = new SimpleNode(JJTTYPEBOUND); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(EXTENDS); + ClassOrInterfaceType(); + label_9: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case BIT_AND: + ; + break; + default: + break label_9; + } + jj_consume_token(BIT_AND); + ClassOrInterfaceType(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void ClassOrInterfaceBody(boolean isInterface) throws ParseException { + /*@bgen(jjtree) ClassOrInterfaceBody */ + SimpleNode jjtn000 = new SimpleNode(JJTCLASSORINTERFACEBODY); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(LBRACE); + label_10: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case ABSTRACT: + case BOOLEAN: + case BYTE: + case CHAR: + case CLASS: + case DOUBLE: + case ENUM: + case FINAL: + case FLOAT: + case INT: + case INTERFACE: + case LONG: + case NATIVE: + case PRIVATE: + case PROTECTED: + case PUBLIC: + case SHORT: + case STATIC: + case STRICTFP: + case SYNCHRONIZED: + case TRANSIENT: + case VOID: + case VOLATILE: + case IDENTIFIER: + case LBRACE: + case SEMICOLON: + case AT: + case LT: + ; + break; + default: + break label_10; + } + ClassOrInterfaceBodyDeclaration(isInterface); + } + jj_consume_token(RBRACE); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void ClassOrInterfaceBodyDeclaration(boolean isInterface) throws ParseException { + /*@bgen(jjtree) ClassOrInterfaceBodyDeclaration */ + SimpleNode jjtn000 = new SimpleNode(JJTCLASSORINTERFACEBODYDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + boolean isNestedInterface = false; + int modifiers; + try { + if (jj_2_10(2)) { + Initializer(); + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtreeCloseNodeScope(jjtn000); + if (isInterface) { + if (true) + throw new ParseException("An interface cannot have initializers"); + } + } else { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case ABSTRACT: + case BOOLEAN: + case BYTE: + case CHAR: + case CLASS: + case DOUBLE: + case ENUM: + case FINAL: + case FLOAT: + case INT: + case INTERFACE: + case LONG: + case NATIVE: + case PRIVATE: + case PROTECTED: + case PUBLIC: + case SHORT: + case STATIC: + case STRICTFP: + case SYNCHRONIZED: + case TRANSIENT: + case VOID: + case VOLATILE: + case IDENTIFIER: + case AT: + case LT: + modifiers = Modifiers(); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case CLASS: + case INTERFACE: + ClassOrInterfaceDeclaration(modifiers); + break; + case ENUM: + EnumDeclaration(modifiers); + break; + default: + if (jj_2_8(2147483647)) { + ConstructorDeclaration(); + } else if (jj_2_9(2147483647)) { + FieldDeclaration(modifiers); + } else { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FLOAT: + case INT: + case LONG: + case SHORT: + case VOID: + case IDENTIFIER: + case LT: + MethodDeclaration(modifiers); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } + } + break; + case SEMICOLON: + jj_consume_token(SEMICOLON); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void FieldDeclaration(int modifiers) throws ParseException { + /*@bgen(jjtree) FieldDeclaration */ + SimpleNode jjtn000 = new SimpleNode(JJTFIELDDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + Type(); + VariableDeclarator(); + label_11: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case COMMA: + ; + break; + default: + break label_11; + } + jj_consume_token(COMMA); + VariableDeclarator(); + } + jj_consume_token(SEMICOLON); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void VariableDeclarator() throws ParseException { + /*@bgen(jjtree) VariableDeclarator */ + SimpleNode jjtn000 = new SimpleNode(JJTVARIABLEDECLARATOR); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + VariableDeclaratorId(); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case ASSIGN: + jj_consume_token(ASSIGN); + VariableInitializer(); + break; + default: + ; + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void VariableDeclaratorId() throws ParseException { + /*@bgen(jjtree) VariableDeclaratorId */ + SimpleNode jjtn000 = new SimpleNode(JJTVARIABLEDECLARATORID); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(IDENTIFIER); + label_12: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case LBRACKET: + ; + break; + default: + break label_12; + } + jj_consume_token(LBRACKET); + jj_consume_token(RBRACKET); + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void VariableInitializer() throws ParseException { + /*@bgen(jjtree) VariableInitializer */ + SimpleNode jjtn000 = new SimpleNode(JJTVARIABLEINITIALIZER); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case LBRACE: + ArrayInitializer(); + break; + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FALSE: + case FLOAT: + case INT: + case LONG: + case NEW: + case NULL: + case SHORT: + case SUPER: + case THIS: + case TRUE: + case VOID: + case INTEGER_LITERAL: + case FLOATING_POINT_LITERAL: + case CHARACTER_LITERAL: + case STRING_LITERAL: + case IDENTIFIER: + case LPAREN: + case BANG: + case TILDE: + case INCR: + case DECR: + case PLUS: + case MINUS: + Expression(); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void ArrayInitializer() throws ParseException { + /*@bgen(jjtree) ArrayInitializer */ + SimpleNode jjtn000 = new SimpleNode(JJTARRAYINITIALIZER); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(LBRACE); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FALSE: + case FLOAT: + case INT: + case LONG: + case NEW: + case NULL: + case SHORT: + case SUPER: + case THIS: + case TRUE: + case VOID: + case INTEGER_LITERAL: + case FLOATING_POINT_LITERAL: + case CHARACTER_LITERAL: + case STRING_LITERAL: + case IDENTIFIER: + case LPAREN: + case LBRACE: + case BANG: + case TILDE: + case INCR: + case DECR: + case PLUS: + case MINUS: + VariableInitializer(); + label_13: + while (true) { + if (jj_2_11(2)) { + ; + } else { + break label_13; + } + jj_consume_token(COMMA); + VariableInitializer(); + } + break; + default: + ; + } + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case COMMA: + jj_consume_token(COMMA); + break; + default: + ; + } + jj_consume_token(RBRACE); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void MethodDeclaration(int modifiers) throws ParseException { + /*@bgen(jjtree) MethodDeclaration */ + SimpleNode jjtn000 = new SimpleNode(JJTMETHODDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case LT: + TypeParameters(); + break; + default: + ; + } + ResultType(); + MethodDeclarator(); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case THROWS: + jj_consume_token(THROWS); + NameList(); + break; + default: + ; + } + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case LBRACE: + Block(); + break; + case SEMICOLON: + jj_consume_token(SEMICOLON); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void MethodDeclarator() throws ParseException { + /*@bgen(jjtree) MethodDeclarator */ + SimpleNode jjtn000 = new SimpleNode(JJTMETHODDECLARATOR); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(IDENTIFIER); + FormalParameters(); + label_14: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case LBRACKET: + ; + break; + default: + break label_14; + } + jj_consume_token(LBRACKET); + jj_consume_token(RBRACKET); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void FormalParameters() throws ParseException { + /*@bgen(jjtree) FormalParameters */ + SimpleNode jjtn000 = new SimpleNode(JJTFORMALPARAMETERS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(LPAREN); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case ABSTRACT: + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FINAL: + case FLOAT: + case INT: + case LONG: + case NATIVE: + case PRIVATE: + case PROTECTED: + case PUBLIC: + case SHORT: + case STATIC: + case STRICTFP: + case SYNCHRONIZED: + case TRANSIENT: + case VOLATILE: + case IDENTIFIER: + case AT: + FormalParameter(); + label_15: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case COMMA: + ; + break; + default: + break label_15; + } + jj_consume_token(COMMA); + FormalParameter(); + } + break; + default: + ; + } + jj_consume_token(RPAREN); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void FormalParameter() throws ParseException { + /*@bgen(jjtree) FormalParameter */ + SimpleNode jjtn000 = new SimpleNode(JJTFORMALPARAMETER); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + Modifiers(); + Type(); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case ELLIPSIS: + jj_consume_token(ELLIPSIS); + break; + default: + ; + } + VariableDeclaratorId(); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void ConstructorDeclaration() throws ParseException { + /*@bgen(jjtree) ConstructorDeclaration */ + SimpleNode jjtn000 = new SimpleNode(JJTCONSTRUCTORDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case LT: + TypeParameters(); + break; + default: + ; + } + jj_consume_token(IDENTIFIER); + FormalParameters(); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case THROWS: + jj_consume_token(THROWS); + NameList(); + break; + default: + ; + } + jj_consume_token(LBRACE); + if (jj_2_12(2147483647)) { + ExplicitConstructorInvocation(); + } else { + ; + } + label_16: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case ABSTRACT: + case ASSERT: + case BOOLEAN: + case BREAK: + case BYTE: + case CHAR: + case CLASS: + case CONTINUE: + case DO: + case DOUBLE: + case FALSE: + case FINAL: + case FLOAT: + case FOR: + case IF: + case INT: + case INTERFACE: + case LONG: + case NATIVE: + case NEW: + case NULL: + case PRIVATE: + case PROTECTED: + case PUBLIC: + case RETURN: + case SHORT: + case STATIC: + case STRICTFP: + case SUPER: + case SWITCH: + case SYNCHRONIZED: + case THIS: + case THROW: + case TRANSIENT: + case TRUE: + case TRY: + case VOID: + case VOLATILE: + case WHILE: + case INTEGER_LITERAL: + case FLOATING_POINT_LITERAL: + case CHARACTER_LITERAL: + case STRING_LITERAL: + case IDENTIFIER: + case LPAREN: + case LBRACE: + case SEMICOLON: + case AT: + case INCR: + case DECR: + ; + break; + default: + break label_16; + } + BlockStatement(); + } + jj_consume_token(RBRACE); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void ExplicitConstructorInvocation() throws ParseException { + /*@bgen(jjtree) ExplicitConstructorInvocation */ + SimpleNode jjtn000 = new SimpleNode(JJTEXPLICITCONSTRUCTORINVOCATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + label_17: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case IDENTIFIER: + ; + break; + default: + break label_17; + } + jj_consume_token(IDENTIFIER); + jj_consume_token(DOT); + } + if (jj_2_13(2)) { + jj_consume_token(THIS); + jj_consume_token(DOT); + } else { + ; + } + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case LT: + TypeArguments(); + break; + default: + ; + } + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case THIS: + jj_consume_token(THIS); + break; + case SUPER: + jj_consume_token(SUPER); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + Arguments(); + jj_consume_token(SEMICOLON); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void Initializer() throws ParseException { + /*@bgen(jjtree) Initializer */ + SimpleNode jjtn000 = new SimpleNode(JJTINITIALIZER); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case STATIC: + jj_consume_token(STATIC); + break; + default: + ; + } + Block(); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + /* + * Type, name and expression syntax follows. + */ + final public void Type() throws ParseException { + /*@bgen(jjtree) Type */ + SimpleNode jjtn000 = new SimpleNode(JJTTYPE); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + if (jj_2_14(2)) { + ReferenceType(); + } else { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FLOAT: + case INT: + case LONG: + case SHORT: + PrimitiveType(); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void ReferenceType() throws ParseException { + /*@bgen(jjtree) ReferenceType */ + SimpleNode jjtn000 = new SimpleNode(JJTREFERENCETYPE); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FLOAT: + case INT: + case LONG: + case SHORT: + PrimitiveType(); + label_18: + while (true) { + jj_consume_token(LBRACKET); + jj_consume_token(RBRACKET); + if (jj_2_15(2)) { + ; + } else { + break label_18; + } + } + break; + case IDENTIFIER: + ClassOrInterfaceType(); + label_19: + while (true) { + if (jj_2_16(2)) { + ; + } else { + break label_19; + } + jj_consume_token(LBRACKET); + jj_consume_token(RBRACKET); + } + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void ClassOrInterfaceType() throws ParseException { + /*@bgen(jjtree) ClassOrInterfaceType */ + SimpleNode jjtn000 = new SimpleNode(JJTCLASSORINTERFACETYPE); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(IDENTIFIER); + if (jj_2_17(2)) { + TypeArguments(); + } else { + ; + } + label_20: + while (true) { + if (jj_2_18(2)) { + ; + } else { + break label_20; + } + jj_consume_token(DOT); + jj_consume_token(IDENTIFIER); + if (jj_2_19(2)) { + TypeArguments(); + } else { + ; + } + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void TypeArguments() throws ParseException { + /*@bgen(jjtree) TypeArguments */ + SimpleNode jjtn000 = new SimpleNode(JJTTYPEARGUMENTS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(LT); + TypeArgument(); + label_21: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case COMMA: + ; + break; + default: + break label_21; + } + jj_consume_token(COMMA); + TypeArgument(); + } + jj_consume_token(GT); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void TypeArgument() throws ParseException { + /*@bgen(jjtree) TypeArgument */ + SimpleNode jjtn000 = new SimpleNode(JJTTYPEARGUMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FLOAT: + case INT: + case LONG: + case SHORT: + case IDENTIFIER: + ReferenceType(); + break; + case HOOK: + jj_consume_token(HOOK); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case EXTENDS: + case SUPER: + WildcardBounds(); + break; + default: + ; + } + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void WildcardBounds() throws ParseException { + /*@bgen(jjtree) WildcardBounds */ + SimpleNode jjtn000 = new SimpleNode(JJTWILDCARDBOUNDS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case EXTENDS: + jj_consume_token(EXTENDS); + ReferenceType(); + break; + case SUPER: + jj_consume_token(SUPER); + ReferenceType(); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void PrimitiveType() throws ParseException { + /*@bgen(jjtree) PrimitiveType */ + SimpleNode jjtn000 = new SimpleNode(JJTPRIMITIVETYPE); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case BOOLEAN: + jj_consume_token(BOOLEAN); + break; + case CHAR: + jj_consume_token(CHAR); + break; + case BYTE: + jj_consume_token(BYTE); + break; + case SHORT: + jj_consume_token(SHORT); + break; + case INT: + jj_consume_token(INT); + break; + case LONG: + jj_consume_token(LONG); + break; + case FLOAT: + jj_consume_token(FLOAT); + break; + case DOUBLE: + jj_consume_token(DOUBLE); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void ResultType() throws ParseException { + /*@bgen(jjtree) ResultType */ + SimpleNode jjtn000 = new SimpleNode(JJTRESULTTYPE); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case VOID: + jj_consume_token(VOID); + break; + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FLOAT: + case INT: + case LONG: + case SHORT: + case IDENTIFIER: + Type(); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void Name() throws ParseException { + /*@bgen(jjtree) Name */ + SimpleNode jjtn000 = new SimpleNode(JJTNAME); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(IDENTIFIER); + label_22: + while (true) { + if (jj_2_20(2)) { + ; + } else { + break label_22; + } + jj_consume_token(DOT); + jj_consume_token(IDENTIFIER); + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void NameList() throws ParseException { + /*@bgen(jjtree) NameList */ + SimpleNode jjtn000 = new SimpleNode(JJTNAMELIST); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + Name(); + label_23: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case COMMA: + ; + break; + default: + break label_23; + } + jj_consume_token(COMMA); + Name(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + /* + * Expression syntax follows. + */ + final public void Expression() throws ParseException { + /*@bgen(jjtree) Expression */ + SimpleNode jjtn000 = new SimpleNode(JJTEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + ConditionalExpression(); + if (jj_2_21(2)) { + AssignmentOperator(); + Expression(); + } else { + ; + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void AssignmentOperator() throws ParseException { + /*@bgen(jjtree) AssignmentOperator */ + SimpleNode jjtn000 = new SimpleNode(JJTASSIGNMENTOPERATOR); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case ASSIGN: + jj_consume_token(ASSIGN); + break; + case STARASSIGN: + jj_consume_token(STARASSIGN); + break; + case SLASHASSIGN: + jj_consume_token(SLASHASSIGN); + break; + case REMASSIGN: + jj_consume_token(REMASSIGN); + break; + case PLUSASSIGN: + jj_consume_token(PLUSASSIGN); + break; + case MINUSASSIGN: + jj_consume_token(MINUSASSIGN); + break; + case LSHIFTASSIGN: + jj_consume_token(LSHIFTASSIGN); + break; + case RSIGNEDSHIFTASSIGN: + jj_consume_token(RSIGNEDSHIFTASSIGN); + break; + case RUNSIGNEDSHIFTASSIGN: + jj_consume_token(RUNSIGNEDSHIFTASSIGN); + break; + case ANDASSIGN: + jj_consume_token(ANDASSIGN); + break; + case XORASSIGN: + jj_consume_token(XORASSIGN); + break; + case ORASSIGN: + jj_consume_token(ORASSIGN); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void AssignmentExpression() throws ParseException { + /*@bgen(jjtree) AssignmentExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTASSIGNMENTEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + PrimaryExpression(); + AssignmentOperator(); + Expression(); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void ConditionalExpression() throws ParseException { + /*@bgen(jjtree) ConditionalExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTCONDITIONALEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + ConditionalOrExpression(); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case HOOK: + jj_consume_token(HOOK); + Expression(); + jj_consume_token(COLON); + Expression(); + break; + default: + ; + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void ConditionalOrExpression() throws ParseException { + /*@bgen(jjtree) ConditionalOrExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTCONDITIONALOREXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + ConditionalAndExpression(); + label_24: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case SC_OR: + ; + break; + default: + break label_24; + } + jj_consume_token(SC_OR); + ConditionalAndExpression(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void ConditionalAndExpression() throws ParseException { + /*@bgen(jjtree) ConditionalAndExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTCONDITIONALANDEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + InclusiveOrExpression(); + label_25: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case SC_AND: + ; + break; + default: + break label_25; + } + jj_consume_token(SC_AND); + InclusiveOrExpression(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void InclusiveOrExpression() throws ParseException { + /*@bgen(jjtree) InclusiveOrExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTINCLUSIVEOREXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + ExclusiveOrExpression(); + label_26: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case BIT_OR: + ; + break; + default: + break label_26; + } + jj_consume_token(BIT_OR); + ExclusiveOrExpression(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void ExclusiveOrExpression() throws ParseException { + /*@bgen(jjtree) ExclusiveOrExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTEXCLUSIVEOREXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + AndExpression(); + label_27: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case XOR: + ; + break; + default: + break label_27; + } + jj_consume_token(XOR); + AndExpression(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void AndExpression() throws ParseException { + /*@bgen(jjtree) AndExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTANDEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + EqualityExpression(); + label_28: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case BIT_AND: + ; + break; + default: + break label_28; + } + jj_consume_token(BIT_AND); + EqualityExpression(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void EqualityExpression() throws ParseException { + /*@bgen(jjtree) EqualityExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTEQUALITYEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + InstanceOfExpression(); + label_29: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case EQ: + case NE: + ; + break; + default: + break label_29; + } + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case EQ: + jj_consume_token(EQ); + break; + case NE: + jj_consume_token(NE); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + InstanceOfExpression(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void InstanceOfExpression() throws ParseException { + /*@bgen(jjtree) InstanceOfExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTINSTANCEOFEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + RelationalExpression(); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case INSTANCEOF: + jj_consume_token(INSTANCEOF); + Type(); + break; + default: + ; + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void RelationalExpression() throws ParseException { + /*@bgen(jjtree) RelationalExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTRELATIONALEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + ShiftExpression(); + label_30: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case LT: + case LE: + case GE: + case GT: + ; + break; + default: + break label_30; + } + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case LT: + jj_consume_token(LT); + break; + case GT: + jj_consume_token(GT); + break; + case LE: + jj_consume_token(LE); + break; + case GE: + jj_consume_token(GE); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + ShiftExpression(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void ShiftExpression() throws ParseException { + /*@bgen(jjtree) ShiftExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTSHIFTEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + AdditiveExpression(); + label_31: + while (true) { + if (jj_2_22(1)) { + ; + } else { + break label_31; + } + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case LSHIFT: + jj_consume_token(LSHIFT); + break; + default: + if (jj_2_23(1)) { + RSIGNEDSHIFT(); + } else if (jj_2_24(1)) { + RUNSIGNEDSHIFT(); + } else { + jj_consume_token(-1); + throw new ParseException(); + } + } + AdditiveExpression(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void AdditiveExpression() throws ParseException { + /*@bgen(jjtree) AdditiveExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTADDITIVEEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + MultiplicativeExpression(); + label_32: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case PLUS: + case MINUS: + ; + break; + default: + break label_32; + } + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case PLUS: + jj_consume_token(PLUS); + break; + case MINUS: + jj_consume_token(MINUS); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + MultiplicativeExpression(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void MultiplicativeExpression() throws ParseException { + /*@bgen(jjtree) MultiplicativeExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTMULTIPLICATIVEEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + UnaryExpression(); + label_33: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case STAR: + case SLASH: + case REM: + ; + break; + default: + break label_33; + } + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case STAR: + jj_consume_token(STAR); + break; + case SLASH: + jj_consume_token(SLASH); + break; + case REM: + jj_consume_token(REM); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + UnaryExpression(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void UnaryExpression() throws ParseException { + /*@bgen(jjtree) UnaryExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTUNARYEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case PLUS: + case MINUS: + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case PLUS: + jj_consume_token(PLUS); + break; + case MINUS: + jj_consume_token(MINUS); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + UnaryExpression(); + break; + case INCR: + PreIncrementExpression(); + break; + case DECR: + PreDecrementExpression(); + break; + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FALSE: + case FLOAT: + case INT: + case LONG: + case NEW: + case NULL: + case SHORT: + case SUPER: + case THIS: + case TRUE: + case VOID: + case INTEGER_LITERAL: + case FLOATING_POINT_LITERAL: + case CHARACTER_LITERAL: + case STRING_LITERAL: + case IDENTIFIER: + case LPAREN: + case BANG: + case TILDE: + UnaryExpressionNotPlusMinus(); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void PreIncrementExpression() throws ParseException { + /*@bgen(jjtree) PreIncrementExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTPREINCREMENTEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(INCR); + PrimaryExpression(); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void PreDecrementExpression() throws ParseException { + /*@bgen(jjtree) PreDecrementExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTPREDECREMENTEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(DECR); + PrimaryExpression(); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void UnaryExpressionNotPlusMinus() throws ParseException { + /*@bgen(jjtree) UnaryExpressionNotPlusMinus */ + SimpleNode jjtn000 = new SimpleNode(JJTUNARYEXPRESSIONNOTPLUSMINUS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case BANG: + case TILDE: + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case TILDE: + jj_consume_token(TILDE); + break; + case BANG: + jj_consume_token(BANG); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + UnaryExpression(); + break; + default: + if (jj_2_25(2147483647)) { + CastExpression(); + } else { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FALSE: + case FLOAT: + case INT: + case LONG: + case NEW: + case NULL: + case SHORT: + case SUPER: + case THIS: + case TRUE: + case VOID: + case INTEGER_LITERAL: + case FLOATING_POINT_LITERAL: + case CHARACTER_LITERAL: + case STRING_LITERAL: + case IDENTIFIER: + case LPAREN: + PostfixExpression(); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + +// This production is to determine lookahead only. The LOOKAHEAD specifications +// below are not used, but they are there just to indicate that we know about + + // this. + final public void CastLookahead() throws ParseException { + /*@bgen(jjtree) CastLookahead */ + SimpleNode jjtn000 = new SimpleNode(JJTCASTLOOKAHEAD); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + if (jj_2_26(2)) { + jj_consume_token(LPAREN); + PrimitiveType(); + } else if (jj_2_27(2147483647)) { + jj_consume_token(LPAREN); + Type(); + jj_consume_token(LBRACKET); + jj_consume_token(RBRACKET); + } else { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case LPAREN: + jj_consume_token(LPAREN); + Type(); + jj_consume_token(RPAREN); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case TILDE: + jj_consume_token(TILDE); + break; + case BANG: + jj_consume_token(BANG); + break; + case LPAREN: + jj_consume_token(LPAREN); + break; + case IDENTIFIER: + jj_consume_token(IDENTIFIER); + break; + case THIS: + jj_consume_token(THIS); + break; + case SUPER: + jj_consume_token(SUPER); + break; + case NEW: + jj_consume_token(NEW); + break; + case FALSE: + case NULL: + case TRUE: + case INTEGER_LITERAL: + case FLOATING_POINT_LITERAL: + case CHARACTER_LITERAL: + case STRING_LITERAL: + Literal(); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void PostfixExpression() throws ParseException { + /*@bgen(jjtree) PostfixExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTPOSTFIXEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + PrimaryExpression(); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case INCR: + case DECR: + PostfixOperator(); + break; + default: + ; + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void PostfixOperator() throws ParseException { + /*@bgen(jjtree) PostfixOperator */ + SimpleNode jjtn000 = new SimpleNode(JJTPOSTFIXOPERATOR); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case INCR: + jj_consume_token(INCR); + break; + case DECR: + jj_consume_token(DECR); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void CastExpression() throws ParseException { + /*@bgen(jjtree) CastExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTCASTEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + if (jj_2_28(2147483647)) { + jj_consume_token(LPAREN); + Type(); + jj_consume_token(RPAREN); + UnaryExpression(); + } else { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case LPAREN: + jj_consume_token(LPAREN); + Type(); + jj_consume_token(RPAREN); + UnaryExpressionNotPlusMinus(); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void PrimaryExpression() throws ParseException { + /*@bgen(jjtree) PrimaryExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTPRIMARYEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + PrimaryPrefix(); + label_34: + while (true) { + if (jj_2_29(2)) { + ; + } else { + break label_34; + } + PrimarySuffix(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void MemberSelector() throws ParseException { + /*@bgen(jjtree) MemberSelector */ + SimpleNode jjtn000 = new SimpleNode(JJTMEMBERSELECTOR); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(DOT); + TypeArguments(); + jj_consume_token(IDENTIFIER); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void PrimaryPrefix() throws ParseException { + /*@bgen(jjtree) PrimaryPrefix */ + SimpleNode jjtn000 = new SimpleNode(JJTPRIMARYPREFIX); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case FALSE: + case NULL: + case TRUE: + case INTEGER_LITERAL: + case FLOATING_POINT_LITERAL: + case CHARACTER_LITERAL: + case STRING_LITERAL: + Literal(); + break; + default: + if (jj_2_30(2147483647)) { + label_35: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case IDENTIFIER: + ; + break; + default: + break label_35; + } + jj_consume_token(IDENTIFIER); + jj_consume_token(DOT); + } + jj_consume_token(THIS); + } else { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case SUPER: + jj_consume_token(SUPER); + jj_consume_token(DOT); + jj_consume_token(IDENTIFIER); + break; + case LPAREN: + jj_consume_token(LPAREN); + Expression(); + jj_consume_token(RPAREN); + break; + case NEW: + AllocationExpression(); + break; + default: + if (jj_2_31(2147483647)) { + ResultType(); + jj_consume_token(DOT); + jj_consume_token(CLASS); + } else { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case IDENTIFIER: + Name(); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } + } + } + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void PrimarySuffix() throws ParseException { + /*@bgen(jjtree) PrimarySuffix */ + SimpleNode jjtn000 = new SimpleNode(JJTPRIMARYSUFFIX); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + if (jj_2_32(2147483647)) { + jj_consume_token(DOT); + jj_consume_token(SUPER); + } else if (jj_2_33(2147483647)) { + jj_consume_token(DOT); + jj_consume_token(THIS); + } else if (jj_2_34(2)) { + jj_consume_token(DOT); + AllocationExpression(); + } else if (jj_2_35(3)) { + MemberSelector(); + } else { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case LBRACKET: + jj_consume_token(LBRACKET); + Expression(); + jj_consume_token(RBRACKET); + break; + case DOT: + jj_consume_token(DOT); + jj_consume_token(IDENTIFIER); + break; + case LPAREN: + Arguments(); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void Literal() throws ParseException { + /*@bgen(jjtree) Literal */ + SimpleNode jjtn000 = new SimpleNode(JJTLITERAL); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case INTEGER_LITERAL: + jj_consume_token(INTEGER_LITERAL); + break; + case FLOATING_POINT_LITERAL: + jj_consume_token(FLOATING_POINT_LITERAL); + break; + case CHARACTER_LITERAL: + jj_consume_token(CHARACTER_LITERAL); + break; + case STRING_LITERAL: + jj_consume_token(STRING_LITERAL); + break; + case FALSE: + case TRUE: + BooleanLiteral(); + break; + case NULL: + NullLiteral(); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void BooleanLiteral() throws ParseException { + /*@bgen(jjtree) BooleanLiteral */ + SimpleNode jjtn000 = new SimpleNode(JJTBOOLEANLITERAL); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case TRUE: + jj_consume_token(TRUE); + break; + case FALSE: + jj_consume_token(FALSE); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void NullLiteral() throws ParseException { + /*@bgen(jjtree) NullLiteral */ + SimpleNode jjtn000 = new SimpleNode(JJTNULLLITERAL); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(NULL); + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void Arguments() throws ParseException { + /*@bgen(jjtree) Arguments */ + SimpleNode jjtn000 = new SimpleNode(JJTARGUMENTS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(LPAREN); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FALSE: + case FLOAT: + case INT: + case LONG: + case NEW: + case NULL: + case SHORT: + case SUPER: + case THIS: + case TRUE: + case VOID: + case INTEGER_LITERAL: + case FLOATING_POINT_LITERAL: + case CHARACTER_LITERAL: + case STRING_LITERAL: + case IDENTIFIER: + case LPAREN: + case BANG: + case TILDE: + case INCR: + case DECR: + case PLUS: + case MINUS: + ArgumentList(); + break; + default: + ; + } + jj_consume_token(RPAREN); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void ArgumentList() throws ParseException { + /*@bgen(jjtree) ArgumentList */ + SimpleNode jjtn000 = new SimpleNode(JJTARGUMENTLIST); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + Expression(); + label_36: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case COMMA: + ; + break; + default: + break label_36; + } + jj_consume_token(COMMA); + Expression(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void AllocationExpression() throws ParseException { + /*@bgen(jjtree) AllocationExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTALLOCATIONEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + if (jj_2_36(2)) { + jj_consume_token(NEW); + PrimitiveType(); + ArrayDimsAndInits(); + } else { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case NEW: + jj_consume_token(NEW); + ClassOrInterfaceType(); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case LT: + TypeArguments(); + break; + default: + ; + } + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case LBRACKET: + ArrayDimsAndInits(); + break; + case LPAREN: + Arguments(); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case LBRACE: + ClassOrInterfaceBody(false); + break; + default: + ; + } + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + /* + * The third LOOKAHEAD specification below is to parse to PrimarySuffix + * if there is an expression between the "[...]". + */ + final public void ArrayDimsAndInits() throws ParseException { + /*@bgen(jjtree) ArrayDimsAndInits */ + SimpleNode jjtn000 = new SimpleNode(JJTARRAYDIMSANDINITS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + if (jj_2_39(2)) { + label_37: + while (true) { + jj_consume_token(LBRACKET); + Expression(); + jj_consume_token(RBRACKET); + if (jj_2_37(2)) { + ; + } else { + break label_37; + } + } + label_38: + while (true) { + if (jj_2_38(2)) { + ; + } else { + break label_38; + } + jj_consume_token(LBRACKET); + jj_consume_token(RBRACKET); + } + } else { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case LBRACKET: + label_39: + while (true) { + jj_consume_token(LBRACKET); + jj_consume_token(RBRACKET); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case LBRACKET: + ; + break; + default: + break label_39; + } + } + ArrayInitializer(); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + /* + * Statement syntax follows. + */ + final public void Statement() throws ParseException { + /*@bgen(jjtree) Statement */ + SimpleNode jjtn000 = new SimpleNode(JJTSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + if (jj_2_40(2)) { + LabeledStatement(); + } else { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case ASSERT: + AssertStatement(); + break; + case LBRACE: + Block(); + break; + case SEMICOLON: + EmptyStatement(); + break; + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FALSE: + case FLOAT: + case INT: + case LONG: + case NEW: + case NULL: + case SHORT: + case SUPER: + case THIS: + case TRUE: + case VOID: + case INTEGER_LITERAL: + case FLOATING_POINT_LITERAL: + case CHARACTER_LITERAL: + case STRING_LITERAL: + case IDENTIFIER: + case LPAREN: + case INCR: + case DECR: + StatementExpression(); + jj_consume_token(SEMICOLON); + break; + case SWITCH: + SwitchStatement(); + break; + case IF: + IfStatement(); + break; + case WHILE: + WhileStatement(); + break; + case DO: + DoStatement(); + break; + case FOR: + ForStatement(); + break; + case BREAK: + BreakStatement(); + break; + case CONTINUE: + ContinueStatement(); + break; + case RETURN: + ReturnStatement(); + break; + case THROW: + ThrowStatement(); + break; + case SYNCHRONIZED: + SynchronizedStatement(); + break; + case TRY: + TryStatement(); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void AssertStatement() throws ParseException { + /*@bgen(jjtree) AssertStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTASSERTSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(ASSERT); + Expression(); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case COLON: + jj_consume_token(COLON); + Expression(); + break; + default: + ; + } + jj_consume_token(SEMICOLON); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void LabeledStatement() throws ParseException { + /*@bgen(jjtree) LabeledStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTLABELEDSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(IDENTIFIER); + jj_consume_token(COLON); + Statement(); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void Block() throws ParseException { + /*@bgen(jjtree) Block */ + SimpleNode jjtn000 = new SimpleNode(JJTBLOCK); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(LBRACE); + label_40: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case ABSTRACT: + case ASSERT: + case BOOLEAN: + case BREAK: + case BYTE: + case CHAR: + case CLASS: + case CONTINUE: + case DO: + case DOUBLE: + case FALSE: + case FINAL: + case FLOAT: + case FOR: + case IF: + case INT: + case INTERFACE: + case LONG: + case NATIVE: + case NEW: + case NULL: + case PRIVATE: + case PROTECTED: + case PUBLIC: + case RETURN: + case SHORT: + case STATIC: + case STRICTFP: + case SUPER: + case SWITCH: + case SYNCHRONIZED: + case THIS: + case THROW: + case TRANSIENT: + case TRUE: + case TRY: + case VOID: + case VOLATILE: + case WHILE: + case INTEGER_LITERAL: + case FLOATING_POINT_LITERAL: + case CHARACTER_LITERAL: + case STRING_LITERAL: + case IDENTIFIER: + case LPAREN: + case LBRACE: + case SEMICOLON: + case AT: + case INCR: + case DECR: + ; + break; + default: + break label_40; + } + BlockStatement(); + } + jj_consume_token(RBRACE); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void BlockStatement() throws ParseException { + /*@bgen(jjtree) BlockStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTBLOCKSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + if (jj_2_41(2147483647)) { + LocalVariableDeclaration(); + jj_consume_token(SEMICOLON); + } else { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case ASSERT: + case BOOLEAN: + case BREAK: + case BYTE: + case CHAR: + case CONTINUE: + case DO: + case DOUBLE: + case FALSE: + case FLOAT: + case FOR: + case IF: + case INT: + case LONG: + case NEW: + case NULL: + case RETURN: + case SHORT: + case SUPER: + case SWITCH: + case SYNCHRONIZED: + case THIS: + case THROW: + case TRUE: + case TRY: + case VOID: + case WHILE: + case INTEGER_LITERAL: + case FLOATING_POINT_LITERAL: + case CHARACTER_LITERAL: + case STRING_LITERAL: + case IDENTIFIER: + case LPAREN: + case LBRACE: + case SEMICOLON: + case INCR: + case DECR: + Statement(); + break; + case CLASS: + case INTERFACE: + ClassOrInterfaceDeclaration(0); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void LocalVariableDeclaration() throws ParseException { + /*@bgen(jjtree) LocalVariableDeclaration */ + SimpleNode jjtn000 = new SimpleNode(JJTLOCALVARIABLEDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + Modifiers(); + Type(); + VariableDeclarator(); + label_41: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case COMMA: + ; + break; + default: + break label_41; + } + jj_consume_token(COMMA); + VariableDeclarator(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void EmptyStatement() throws ParseException { + /*@bgen(jjtree) EmptyStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTEMPTYSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(SEMICOLON); + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void StatementExpression() throws ParseException { + /*@bgen(jjtree) StatementExpression */ + SimpleNode jjtn000 = new SimpleNode(JJTSTATEMENTEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case INCR: + PreIncrementExpression(); + break; + case DECR: + PreDecrementExpression(); + break; + default: + if (jj_2_42(2147483647)) { + AssignmentExpression(); + } else { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FALSE: + case FLOAT: + case INT: + case LONG: + case NEW: + case NULL: + case SHORT: + case SUPER: + case THIS: + case TRUE: + case VOID: + case INTEGER_LITERAL: + case FLOATING_POINT_LITERAL: + case CHARACTER_LITERAL: + case STRING_LITERAL: + case IDENTIFIER: + case LPAREN: + PostfixExpression(); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void SwitchStatement() throws ParseException { + /*@bgen(jjtree) SwitchStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTSWITCHSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(SWITCH); + jj_consume_token(LPAREN); + Expression(); + jj_consume_token(RPAREN); + jj_consume_token(LBRACE); + label_42: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case CASE: + case _DEFAULT: + ; + break; + default: + break label_42; + } + SwitchLabel(); + label_43: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case ABSTRACT: + case ASSERT: + case BOOLEAN: + case BREAK: + case BYTE: + case CHAR: + case CLASS: + case CONTINUE: + case DO: + case DOUBLE: + case FALSE: + case FINAL: + case FLOAT: + case FOR: + case IF: + case INT: + case INTERFACE: + case LONG: + case NATIVE: + case NEW: + case NULL: + case PRIVATE: + case PROTECTED: + case PUBLIC: + case RETURN: + case SHORT: + case STATIC: + case STRICTFP: + case SUPER: + case SWITCH: + case SYNCHRONIZED: + case THIS: + case THROW: + case TRANSIENT: + case TRUE: + case TRY: + case VOID: + case VOLATILE: + case WHILE: + case INTEGER_LITERAL: + case FLOATING_POINT_LITERAL: + case CHARACTER_LITERAL: + case STRING_LITERAL: + case IDENTIFIER: + case LPAREN: + case LBRACE: + case SEMICOLON: + case AT: + case INCR: + case DECR: + ; + break; + default: + break label_43; + } + BlockStatement(); + } + } + jj_consume_token(RBRACE); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void SwitchLabel() throws ParseException { + /*@bgen(jjtree) SwitchLabel */ + SimpleNode jjtn000 = new SimpleNode(JJTSWITCHLABEL); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case CASE: + jj_consume_token(CASE); + Expression(); + jj_consume_token(COLON); + break; + case _DEFAULT: + jj_consume_token(_DEFAULT); + jj_consume_token(COLON); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void IfStatement() throws ParseException { + /*@bgen(jjtree) IfStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTIFSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(IF); + jj_consume_token(LPAREN); + Expression(); + jj_consume_token(RPAREN); + Statement(); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case ELSE: + jj_consume_token(ELSE); + Statement(); + break; + default: + ; + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void WhileStatement() throws ParseException { + /*@bgen(jjtree) WhileStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTWHILESTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(WHILE); + jj_consume_token(LPAREN); + Expression(); + jj_consume_token(RPAREN); + Statement(); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void DoStatement() throws ParseException { + /*@bgen(jjtree) DoStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTDOSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(DO); + Statement(); + jj_consume_token(WHILE); + jj_consume_token(LPAREN); + Expression(); + jj_consume_token(RPAREN); + jj_consume_token(SEMICOLON); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void ForStatement() throws ParseException { + /*@bgen(jjtree) ForStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTFORSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(FOR); + jj_consume_token(LPAREN); + if (jj_2_43(2147483647)) { + Modifiers(); + Type(); + jj_consume_token(IDENTIFIER); + jj_consume_token(COLON); + Expression(); + } else { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case ABSTRACT: + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FALSE: + case FINAL: + case FLOAT: + case INT: + case LONG: + case NATIVE: + case NEW: + case NULL: + case PRIVATE: + case PROTECTED: + case PUBLIC: + case SHORT: + case STATIC: + case STRICTFP: + case SUPER: + case SYNCHRONIZED: + case THIS: + case TRANSIENT: + case TRUE: + case VOID: + case VOLATILE: + case INTEGER_LITERAL: + case FLOATING_POINT_LITERAL: + case CHARACTER_LITERAL: + case STRING_LITERAL: + case IDENTIFIER: + case LPAREN: + case SEMICOLON: + case AT: + case INCR: + case DECR: + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case ABSTRACT: + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FALSE: + case FINAL: + case FLOAT: + case INT: + case LONG: + case NATIVE: + case NEW: + case NULL: + case PRIVATE: + case PROTECTED: + case PUBLIC: + case SHORT: + case STATIC: + case STRICTFP: + case SUPER: + case SYNCHRONIZED: + case THIS: + case TRANSIENT: + case TRUE: + case VOID: + case VOLATILE: + case INTEGER_LITERAL: + case FLOATING_POINT_LITERAL: + case CHARACTER_LITERAL: + case STRING_LITERAL: + case IDENTIFIER: + case LPAREN: + case AT: + case INCR: + case DECR: + ForInit(); + break; + default: + ; + } + jj_consume_token(SEMICOLON); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FALSE: + case FLOAT: + case INT: + case LONG: + case NEW: + case NULL: + case SHORT: + case SUPER: + case THIS: + case TRUE: + case VOID: + case INTEGER_LITERAL: + case FLOATING_POINT_LITERAL: + case CHARACTER_LITERAL: + case STRING_LITERAL: + case IDENTIFIER: + case LPAREN: + case BANG: + case TILDE: + case INCR: + case DECR: + case PLUS: + case MINUS: + Expression(); + break; + default: + ; + } + jj_consume_token(SEMICOLON); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FALSE: + case FLOAT: + case INT: + case LONG: + case NEW: + case NULL: + case SHORT: + case SUPER: + case THIS: + case TRUE: + case VOID: + case INTEGER_LITERAL: + case FLOATING_POINT_LITERAL: + case CHARACTER_LITERAL: + case STRING_LITERAL: + case IDENTIFIER: + case LPAREN: + case INCR: + case DECR: + ForUpdate(); + break; + default: + ; + } + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } + jj_consume_token(RPAREN); + Statement(); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void ForInit() throws ParseException { + /*@bgen(jjtree) ForInit */ + SimpleNode jjtn000 = new SimpleNode(JJTFORINIT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + if (jj_2_44(2147483647)) { + LocalVariableDeclaration(); + } else { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FALSE: + case FLOAT: + case INT: + case LONG: + case NEW: + case NULL: + case SHORT: + case SUPER: + case THIS: + case TRUE: + case VOID: + case INTEGER_LITERAL: + case FLOATING_POINT_LITERAL: + case CHARACTER_LITERAL: + case STRING_LITERAL: + case IDENTIFIER: + case LPAREN: + case INCR: + case DECR: + StatementExpressionList(); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void StatementExpressionList() throws ParseException { + /*@bgen(jjtree) StatementExpressionList */ + SimpleNode jjtn000 = new SimpleNode(JJTSTATEMENTEXPRESSIONLIST); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + StatementExpression(); + label_44: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case COMMA: + ; + break; + default: + break label_44; + } + jj_consume_token(COMMA); + StatementExpression(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void ForUpdate() throws ParseException { + /*@bgen(jjtree) ForUpdate */ + SimpleNode jjtn000 = new SimpleNode(JJTFORUPDATE); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + StatementExpressionList(); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void BreakStatement() throws ParseException { + /*@bgen(jjtree) BreakStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTBREAKSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(BREAK); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case IDENTIFIER: + jj_consume_token(IDENTIFIER); + break; + default: + ; + } + jj_consume_token(SEMICOLON); + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void ContinueStatement() throws ParseException { + /*@bgen(jjtree) ContinueStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTCONTINUESTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(CONTINUE); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case IDENTIFIER: + jj_consume_token(IDENTIFIER); + break; + default: + ; + } + jj_consume_token(SEMICOLON); + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void ReturnStatement() throws ParseException { + /*@bgen(jjtree) ReturnStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTRETURNSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(RETURN); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FALSE: + case FLOAT: + case INT: + case LONG: + case NEW: + case NULL: + case SHORT: + case SUPER: + case THIS: + case TRUE: + case VOID: + case INTEGER_LITERAL: + case FLOATING_POINT_LITERAL: + case CHARACTER_LITERAL: + case STRING_LITERAL: + case IDENTIFIER: + case LPAREN: + case BANG: + case TILDE: + case INCR: + case DECR: + case PLUS: + case MINUS: + Expression(); + break; + default: + ; + } + jj_consume_token(SEMICOLON); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void ThrowStatement() throws ParseException { + /*@bgen(jjtree) ThrowStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTTHROWSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(THROW); + Expression(); + jj_consume_token(SEMICOLON); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void SynchronizedStatement() throws ParseException { + /*@bgen(jjtree) SynchronizedStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTSYNCHRONIZEDSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(SYNCHRONIZED); + jj_consume_token(LPAREN); + Expression(); + jj_consume_token(RPAREN); + Block(); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void TryStatement() throws ParseException { + /*@bgen(jjtree) TryStatement */ + SimpleNode jjtn000 = new SimpleNode(JJTTRYSTATEMENT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(TRY); + Block(); + label_45: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case CATCH: + ; + break; + default: + break label_45; + } + jj_consume_token(CATCH); + jj_consume_token(LPAREN); + FormalParameter(); + jj_consume_token(RPAREN); + Block(); + } + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case FINALLY: + jj_consume_token(FINALLY); + Block(); + break; + default: + ; + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + /* We use productions to match >>>, >> and > so that we can keep the + * type declaration syntax with generics clean + */ + final public void RUNSIGNEDSHIFT() throws ParseException { + /*@bgen(jjtree) RUNSIGNEDSHIFT */ + SimpleNode jjtn000 = new SimpleNode(JJTRUNSIGNEDSHIFT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + if (getToken(1).kind == GT && + ((Token.GTToken) getToken(1)).realKind == RUNSIGNEDSHIFT) { + + } else { + jj_consume_token(-1); + throw new ParseException(); + } + jj_consume_token(GT); + jj_consume_token(GT); + jj_consume_token(GT); + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void RSIGNEDSHIFT() throws ParseException { + /*@bgen(jjtree) RSIGNEDSHIFT */ + SimpleNode jjtn000 = new SimpleNode(JJTRSIGNEDSHIFT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + if (getToken(1).kind == GT && + ((Token.GTToken) getToken(1)).realKind == RSIGNEDSHIFT) { + + } else { + jj_consume_token(-1); + throw new ParseException(); + } + jj_consume_token(GT); + jj_consume_token(GT); + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + /* Annotation syntax follows. */ + final public void Annotation() throws ParseException { + /*@bgen(jjtree) Annotation */ + SimpleNode jjtn000 = new SimpleNode(JJTANNOTATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + if (jj_2_45(2147483647)) { + NormalAnnotation(); + } else if (jj_2_46(2147483647)) { + SingleMemberAnnotation(); + } else { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case AT: + MarkerAnnotation(); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void NormalAnnotation() throws ParseException { + /*@bgen(jjtree) NormalAnnotation */ + SimpleNode jjtn000 = new SimpleNode(JJTNORMALANNOTATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(AT); + Name(); + jj_consume_token(LPAREN); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case IDENTIFIER: + MemberValuePairs(); + break; + default: + ; + } + jj_consume_token(RPAREN); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void MarkerAnnotation() throws ParseException { + /*@bgen(jjtree) MarkerAnnotation */ + SimpleNode jjtn000 = new SimpleNode(JJTMARKERANNOTATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(AT); + Name(); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void SingleMemberAnnotation() throws ParseException { + /*@bgen(jjtree) SingleMemberAnnotation */ + SimpleNode jjtn000 = new SimpleNode(JJTSINGLEMEMBERANNOTATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(AT); + Name(); + jj_consume_token(LPAREN); + MemberValue(); + jj_consume_token(RPAREN); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void MemberValuePairs() throws ParseException { + /*@bgen(jjtree) MemberValuePairs */ + SimpleNode jjtn000 = new SimpleNode(JJTMEMBERVALUEPAIRS); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + MemberValuePair(); + label_46: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case COMMA: + ; + break; + default: + break label_46; + } + jj_consume_token(COMMA); + MemberValuePair(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void MemberValuePair() throws ParseException { + /*@bgen(jjtree) MemberValuePair */ + SimpleNode jjtn000 = new SimpleNode(JJTMEMBERVALUEPAIR); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(IDENTIFIER); + jj_consume_token(ASSIGN); + MemberValue(); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void MemberValue() throws ParseException { + /*@bgen(jjtree) MemberValue */ + SimpleNode jjtn000 = new SimpleNode(JJTMEMBERVALUE); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case AT: + Annotation(); + break; + case LBRACE: + MemberValueArrayInitializer(); + break; + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FALSE: + case FLOAT: + case INT: + case LONG: + case NEW: + case NULL: + case SHORT: + case SUPER: + case THIS: + case TRUE: + case VOID: + case INTEGER_LITERAL: + case FLOATING_POINT_LITERAL: + case CHARACTER_LITERAL: + case STRING_LITERAL: + case IDENTIFIER: + case LPAREN: + case BANG: + case TILDE: + case INCR: + case DECR: + case PLUS: + case MINUS: + ConditionalExpression(); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void MemberValueArrayInitializer() throws ParseException { + /*@bgen(jjtree) MemberValueArrayInitializer */ + SimpleNode jjtn000 = new SimpleNode(JJTMEMBERVALUEARRAYINITIALIZER); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(LBRACE); + MemberValue(); + label_47: + while (true) { + if (jj_2_47(2)) { + ; + } else { + break label_47; + } + jj_consume_token(COMMA); + MemberValue(); + } + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case COMMA: + jj_consume_token(COMMA); + break; + default: + ; + } + jj_consume_token(RBRACE); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + /* Annotation Types. */ + final public void AnnotationTypeDeclaration(int modifiers) throws ParseException { + /*@bgen(jjtree) AnnotationTypeDeclaration */ + SimpleNode jjtn000 = new SimpleNode(JJTANNOTATIONTYPEDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(AT); + jj_consume_token(INTERFACE); + jj_consume_token(IDENTIFIER); + AnnotationTypeBody(); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void AnnotationTypeBody() throws ParseException { + /*@bgen(jjtree) AnnotationTypeBody */ + SimpleNode jjtn000 = new SimpleNode(JJTANNOTATIONTYPEBODY); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(LBRACE); + label_48: + while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case ABSTRACT: + case BOOLEAN: + case BYTE: + case CHAR: + case CLASS: + case DOUBLE: + case ENUM: + case FINAL: + case FLOAT: + case INT: + case INTERFACE: + case LONG: + case NATIVE: + case PRIVATE: + case PROTECTED: + case PUBLIC: + case SHORT: + case STATIC: + case STRICTFP: + case SYNCHRONIZED: + case TRANSIENT: + case VOLATILE: + case IDENTIFIER: + case SEMICOLON: + case AT: + ; + break; + default: + break label_48; + } + AnnotationTypeMemberDeclaration(); + } + jj_consume_token(RBRACE); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void AnnotationTypeMemberDeclaration() throws ParseException { + /*@bgen(jjtree) AnnotationTypeMemberDeclaration */ + SimpleNode jjtn000 = new SimpleNode(JJTANNOTATIONTYPEMEMBERDECLARATION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + int modifiers; + try { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case ABSTRACT: + case BOOLEAN: + case BYTE: + case CHAR: + case CLASS: + case DOUBLE: + case ENUM: + case FINAL: + case FLOAT: + case INT: + case INTERFACE: + case LONG: + case NATIVE: + case PRIVATE: + case PROTECTED: + case PUBLIC: + case SHORT: + case STATIC: + case STRICTFP: + case SYNCHRONIZED: + case TRANSIENT: + case VOLATILE: + case IDENTIFIER: + case AT: + modifiers = Modifiers(); + if (jj_2_48(2147483647)) { + Type(); + jj_consume_token(IDENTIFIER); + jj_consume_token(LPAREN); + jj_consume_token(RPAREN); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case _DEFAULT: + DefaultValue(); + break; + default: + ; + } + jj_consume_token(SEMICOLON); + } else { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case CLASS: + case INTERFACE: + ClassOrInterfaceDeclaration(modifiers); + break; + case ENUM: + EnumDeclaration(modifiers); + break; + case AT: + AnnotationTypeDeclaration(modifiers); + break; + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FLOAT: + case INT: + case LONG: + case SHORT: + case IDENTIFIER: + FieldDeclaration(modifiers); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } + break; + case SEMICOLON: + jj_consume_token(SEMICOLON); + break; + default: + jj_consume_token(-1); + throw new ParseException(); + } + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final public void DefaultValue() throws ParseException { + /*@bgen(jjtree) DefaultValue */ + SimpleNode jjtn000 = new SimpleNode(JJTDEFAULTVALUE); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + jjtreeOpenNodeScope(jjtn000); + try { + jj_consume_token(_DEFAULT); + MemberValue(); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + { + if (true) throw (RuntimeException) jjte000; + } + } + if (jjte000 instanceof ParseException) { + { + if (true) throw (ParseException) jjte000; + } + } + { + if (true) throw (Error) jjte000; + } + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + jjtreeCloseNodeScope(jjtn000); + } + } + } + + final private boolean jj_2_1(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_1(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_2(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_2(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_3(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_3(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_4(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_4(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_5(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_5(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_6(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_6(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_7(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_7(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_8(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_8(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_9(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_9(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_10(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_10(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_11(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_11(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_12(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_12(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_13(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_13(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_14(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_14(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_15(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_15(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_16(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_16(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_17(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_17(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_18(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_18(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_19(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_19(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_20(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_20(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_21(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_21(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_22(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_22(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_23(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_23(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_24(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_24(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_25(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_25(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_26(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_26(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_27(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_27(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_28(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_28(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_29(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_29(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_30(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_30(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_31(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_31(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_32(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_32(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_33(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_33(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_34(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_34(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_35(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_35(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_36(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_36(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_37(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_37(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_38(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_38(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_39(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_39(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_40(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_40(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_41(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_41(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_42(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_42(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_43(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_43(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_44(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_44(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_45(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_45(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_46(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_46(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_47(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_47(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_2_48(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_48(); + } + catch (LookaheadSuccess ls) { + return true; + } + } + + final private boolean jj_3R_56() { + if (jj_3R_101()) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3_21()) jj_scanpos = xsp; + return false; + } + + final private boolean jj_3R_135() { + if (jj_scan_token(COMMA)) return true; + if (jj_3R_91()) return true; + return false; + } + + final private boolean jj_3R_99() { + if (jj_3R_91()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_135()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3_20() { + if (jj_scan_token(DOT)) return true; + if (jj_scan_token(IDENTIFIER)) return true; + return false; + } + + final private boolean jj_3R_91() { + if (jj_scan_token(IDENTIFIER)) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3_20()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_122() { + if (jj_3R_72()) return true; + return false; + } + + final private boolean jj_3R_86() { + Token xsp; + xsp = jj_scanpos; + if (jj_scan_token(58)) { + jj_scanpos = xsp; + if (jj_3R_122()) return true; + } + return false; + } + + final private boolean jj_3_19() { + if (jj_3R_78()) return true; + return false; + } + + final private boolean jj_3R_83() { + Token xsp; + xsp = jj_scanpos; + if (jj_scan_token(10)) { + jj_scanpos = xsp; + if (jj_scan_token(15)) { + jj_scanpos = xsp; + if (jj_scan_token(12)) { + jj_scanpos = xsp; + if (jj_scan_token(46)) { + jj_scanpos = xsp; + if (jj_scan_token(35)) { + jj_scanpos = xsp; + if (jj_scan_token(37)) { + jj_scanpos = xsp; + if (jj_scan_token(28)) { + jj_scanpos = xsp; + if (jj_scan_token(21)) return true; + } + } + } + } + } + } + } + return false; + } + + final private boolean jj_3R_194() { + if (jj_scan_token(COMMA)) return true; + if (jj_3R_112()) return true; + return false; + } + + final private boolean jj_3R_290() { + if (jj_scan_token(SUPER)) return true; + if (jj_3R_77()) return true; + return false; + } + + final private boolean jj_3_16() { + if (jj_scan_token(LBRACKET)) return true; + if (jj_scan_token(RBRACKET)) return true; + return false; + } + + final private boolean jj_3R_289() { + if (jj_scan_token(EXTENDS)) return true; + if (jj_3R_77()) return true; + return false; + } + + final private boolean jj_3R_277() { + Token xsp; + xsp = jj_scanpos; + if (jj_3R_289()) { + jj_scanpos = xsp; + if (jj_3R_290()) return true; + } + return false; + } + + final private boolean jj_3R_256() { + if (jj_3R_277()) return true; + return false; + } + + final private boolean jj_3R_151() { + if (jj_scan_token(HOOK)) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3R_256()) jj_scanpos = xsp; + return false; + } + + final private boolean jj_3_17() { + if (jj_3R_78()) return true; + return false; + } + + final private boolean jj_3R_112() { + Token xsp; + xsp = jj_scanpos; + if (jj_3R_150()) { + jj_scanpos = xsp; + if (jj_3R_151()) return true; + } + return false; + } + + final private boolean jj_3R_150() { + if (jj_3R_77()) return true; + return false; + } + + final private boolean jj_3_15() { + if (jj_scan_token(LBRACKET)) return true; + if (jj_scan_token(RBRACKET)) return true; + return false; + } + + final private boolean jj_3R_78() { + if (jj_scan_token(LT)) return true; + if (jj_3R_112()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_194()) { + jj_scanpos = xsp; + break; + } + } + if (jj_scan_token(GT)) return true; + return false; + } + + final private boolean jj_3_18() { + if (jj_scan_token(DOT)) return true; + if (jj_scan_token(IDENTIFIER)) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3_19()) jj_scanpos = xsp; + return false; + } + + final private boolean jj_3R_149() { + if (jj_scan_token(IDENTIFIER)) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3_17()) jj_scanpos = xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3_18()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_111() { + if (jj_3R_149()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3_16()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_110() { + if (jj_3R_83()) return true; + Token xsp; + if (jj_3_15()) return true; + while (true) { + xsp = jj_scanpos; + if (jj_3_15()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_77() { + Token xsp; + xsp = jj_scanpos; + if (jj_3R_110()) { + jj_scanpos = xsp; + if (jj_3R_111()) return true; + } + return false; + } + + final private boolean jj_3_13() { + if (jj_scan_token(THIS)) return true; + if (jj_scan_token(DOT)) return true; + return false; + } + + final private boolean jj_3R_221() { + if (jj_scan_token(THROWS)) return true; + if (jj_3R_99()) return true; + return false; + } + + final private boolean jj_3R_103() { + if (jj_3R_83()) return true; + return false; + } + + final private boolean jj_3R_72() { + Token xsp; + xsp = jj_scanpos; + if (jj_3_14()) { + jj_scanpos = xsp; + if (jj_3R_103()) return true; + } + return false; + } + + final private boolean jj_3_14() { + if (jj_3R_77()) return true; + return false; + } + + final private boolean jj_3R_74() { + Token xsp; + xsp = jj_scanpos; + if (jj_scan_token(47)) jj_scanpos = xsp; + if (jj_3R_104()) return true; + return false; + } + + final private boolean jj_3_12() { + if (jj_3R_76()) return true; + return false; + } + + final private boolean jj_3R_108() { + if (jj_3R_78()) return true; + return false; + } + + final private boolean jj_3R_107() { + if (jj_scan_token(IDENTIFIER)) return true; + if (jj_scan_token(DOT)) return true; + return false; + } + + final private boolean jj_3R_252() { + if (jj_scan_token(LBRACKET)) return true; + if (jj_scan_token(RBRACKET)) return true; + return false; + } + + final private boolean jj_3R_76() { + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_107()) { + jj_scanpos = xsp; + break; + } + } + xsp = jj_scanpos; + if (jj_3_13()) jj_scanpos = xsp; + xsp = jj_scanpos; + if (jj_3R_108()) jj_scanpos = xsp; + xsp = jj_scanpos; + if (jj_scan_token(52)) { + jj_scanpos = xsp; + if (jj_scan_token(49)) return true; + } + if (jj_3R_109()) return true; + if (jj_scan_token(SEMICOLON)) return true; + return false; + } + + final private boolean jj_3R_134() { + if (jj_scan_token(COMMA)) return true; + if (jj_3R_133()) return true; + return false; + } + + final private boolean jj_3R_223() { + if (jj_3R_49()) return true; + return false; + } + + final private boolean jj_3R_222() { + if (jj_3R_76()) return true; + return false; + } + + final private boolean jj_3R_220() { + if (jj_3R_97()) return true; + return false; + } + + final private boolean jj_3R_186() { + Token xsp; + xsp = jj_scanpos; + if (jj_3R_220()) jj_scanpos = xsp; + if (jj_scan_token(IDENTIFIER)) return true; + if (jj_3R_53()) return true; + xsp = jj_scanpos; + if (jj_3R_221()) jj_scanpos = xsp; + if (jj_scan_token(LBRACE)) return true; + xsp = jj_scanpos; + if (jj_3R_222()) jj_scanpos = xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_223()) { + jj_scanpos = xsp; + break; + } + } + if (jj_scan_token(RBRACE)) return true; + return false; + } + + final private boolean jj_3_11() { + if (jj_scan_token(COMMA)) return true; + if (jj_3R_75()) return true; + return false; + } + + final private boolean jj_3R_227() { + if (jj_scan_token(THROWS)) return true; + if (jj_3R_99()) return true; + return false; + } + + final private boolean jj_3R_98() { + if (jj_3R_133()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_134()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_133() { + if (jj_3R_50()) return true; + if (jj_3R_72()) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_scan_token(119)) jj_scanpos = xsp; + if (jj_3R_184()) return true; + return false; + } + + final private boolean jj_3R_53() { + if (jj_scan_token(LPAREN)) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3R_98()) jj_scanpos = xsp; + if (jj_scan_token(RPAREN)) return true; + return false; + } + + final private boolean jj_3_48() { + if (jj_3R_72()) return true; + if (jj_scan_token(IDENTIFIER)) return true; + if (jj_scan_token(LPAREN)) return true; + return false; + } + + final private boolean jj_3R_226() { + if (jj_scan_token(IDENTIFIER)) return true; + if (jj_3R_53()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_252()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_228() { + if (jj_3R_104()) return true; + return false; + } + + final private boolean jj_3R_225() { + if (jj_3R_97()) return true; + return false; + } + + final private boolean jj_3R_292() { + if (jj_3R_75()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3_11()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_188() { + Token xsp; + xsp = jj_scanpos; + if (jj_3R_225()) jj_scanpos = xsp; + if (jj_3R_86()) return true; + if (jj_3R_226()) return true; + xsp = jj_scanpos; + if (jj_3R_227()) jj_scanpos = xsp; + xsp = jj_scanpos; + if (jj_3R_228()) { + jj_scanpos = xsp; + if (jj_scan_token(81)) return true; + } + return false; + } + + final private boolean jj_3R_198() { + if (jj_scan_token(ASSIGN)) return true; + if (jj_3R_75()) return true; + return false; + } + + final private boolean jj_3R_224() { + if (jj_scan_token(COMMA)) return true; + if (jj_3R_161()) return true; + return false; + } + + final private boolean jj_3_47() { + if (jj_scan_token(COMMA)) return true; + if (jj_3R_93()) return true; + return false; + } + + final private boolean jj_3R_217() { + if (jj_scan_token(LBRACKET)) return true; + if (jj_scan_token(RBRACKET)) return true; + return false; + } + + final private boolean jj_3R_147() { + if (jj_scan_token(LBRACE)) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3R_292()) jj_scanpos = xsp; + xsp = jj_scanpos; + if (jj_scan_token(82)) jj_scanpos = xsp; + if (jj_scan_token(RBRACE)) return true; + return false; + } + + final private boolean jj_3R_73() { + if (jj_scan_token(LBRACKET)) return true; + if (jj_scan_token(RBRACKET)) return true; + return false; + } + + final private boolean jj_3R_106() { + if (jj_3R_56()) return true; + return false; + } + + final private boolean jj_3R_105() { + if (jj_3R_147()) return true; + return false; + } + + final private boolean jj_3R_75() { + Token xsp; + xsp = jj_scanpos; + if (jj_3R_105()) { + jj_scanpos = xsp; + if (jj_3R_106()) return true; + } + return false; + } + + final private boolean jj_3R_184() { + if (jj_scan_token(IDENTIFIER)) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_217()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_160() { + if (jj_scan_token(LBRACE)) return true; + if (jj_3R_93()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3_47()) { + jj_scanpos = xsp; + break; + } + } + xsp = jj_scanpos; + if (jj_scan_token(82)) jj_scanpos = xsp; + if (jj_scan_token(RBRACE)) return true; + return false; + } + + final private boolean jj_3R_276() { + if (jj_scan_token(COMMA)) return true; + if (jj_3R_275()) return true; + return false; + } + + final private boolean jj_3R_161() { + if (jj_3R_184()) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3R_198()) jj_scanpos = xsp; + return false; + } + + final private boolean jj_3R_127() { + if (jj_3R_101()) return true; + return false; + } + + final private boolean jj_3_9() { + if (jj_3R_72()) return true; + if (jj_scan_token(IDENTIFIER)) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_73()) { + jj_scanpos = xsp; + break; + } + } + xsp = jj_scanpos; + if (jj_scan_token(82)) { + jj_scanpos = xsp; + if (jj_scan_token(85)) { + jj_scanpos = xsp; + if (jj_scan_token(81)) return true; + } + } + return false; + } + + final private boolean jj_3R_126() { + if (jj_3R_160()) return true; + return false; + } + + final private boolean jj_3R_71() { + if (jj_3R_97()) return true; + return false; + } + + final private boolean jj_3R_93() { + Token xsp; + xsp = jj_scanpos; + if (jj_3R_125()) { + jj_scanpos = xsp; + if (jj_3R_126()) { + jj_scanpos = xsp; + if (jj_3R_127()) return true; + } + } + return false; + } + + final private boolean jj_3R_125() { + if (jj_3R_102()) return true; + return false; + } + + final private boolean jj_3_8() { + Token xsp; + xsp = jj_scanpos; + if (jj_3R_71()) jj_scanpos = xsp; + if (jj_scan_token(IDENTIFIER)) return true; + if (jj_scan_token(LPAREN)) return true; + return false; + } + + final private boolean jj_3R_187() { + if (jj_3R_72()) return true; + if (jj_3R_161()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_224()) { + jj_scanpos = xsp; + break; + } + } + if (jj_scan_token(SEMICOLON)) return true; + return false; + } + + final private boolean jj_3R_275() { + if (jj_scan_token(IDENTIFIER)) return true; + if (jj_scan_token(ASSIGN)) return true; + if (jj_3R_93()) return true; + return false; + } + + final private boolean jj_3R_140() { + if (jj_3R_188()) return true; + return false; + } + + final private boolean jj_3R_139() { + if (jj_3R_187()) return true; + return false; + } + + final private boolean jj_3R_249() { + if (jj_scan_token(BIT_AND)) return true; + if (jj_3R_149()) return true; + return false; + } + + final private boolean jj_3R_138() { + if (jj_3R_186()) return true; + return false; + } + + final private boolean jj_3R_255() { + if (jj_3R_275()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_276()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_231() { + if (jj_3R_255()) return true; + return false; + } + + final private boolean jj_3R_137() { + if (jj_3R_185()) return true; + return false; + } + + final private boolean jj_3R_92() { + if (jj_scan_token(IDENTIFIER)) return true; + if (jj_scan_token(ASSIGN)) return true; + return false; + } + + final private boolean jj_3R_136() { + if (jj_3R_130()) return true; + return false; + } + + final private boolean jj_3R_192() { + if (jj_scan_token(AT)) return true; + if (jj_3R_91()) return true; + if (jj_scan_token(LPAREN)) return true; + if (jj_3R_93()) return true; + if (jj_scan_token(RPAREN)) return true; + return false; + } + + final private boolean jj_3R_286() { + if (jj_3R_182()) return true; + return false; + } + + final private boolean jj_3R_100() { + if (jj_3R_50()) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3R_136()) { + jj_scanpos = xsp; + if (jj_3R_137()) { + jj_scanpos = xsp; + if (jj_3R_138()) { + jj_scanpos = xsp; + if (jj_3R_139()) { + jj_scanpos = xsp; + if (jj_3R_140()) return true; + } + } + } + } + return false; + } + + final private boolean jj_3R_193() { + if (jj_scan_token(AT)) return true; + if (jj_3R_91()) return true; + return false; + } + + final private boolean jj_3_46() { + if (jj_scan_token(AT)) return true; + if (jj_3R_91()) return true; + if (jj_scan_token(LPAREN)) return true; + return false; + } + + final private boolean jj_3_10() { + if (jj_3R_74()) return true; + return false; + } + + final private boolean jj_3R_55() { + Token xsp; + xsp = jj_scanpos; + if (jj_3_10()) { + jj_scanpos = xsp; + if (jj_3R_100()) { + jj_scanpos = xsp; + if (jj_scan_token(81)) return true; + } + } + return false; + } + + final private boolean jj_3R_191() { + if (jj_scan_token(AT)) return true; + if (jj_3R_91()) return true; + if (jj_scan_token(LPAREN)) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3R_231()) jj_scanpos = xsp; + if (jj_scan_token(RPAREN)) return true; + return false; + } + + final private boolean jj_3_45() { + if (jj_scan_token(AT)) return true; + if (jj_3R_91()) return true; + if (jj_scan_token(LPAREN)) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3R_92()) { + jj_scanpos = xsp; + if (jj_scan_token(76)) return true; + } + return false; + } + + final private boolean jj_3R_215() { + if (jj_3R_55()) return true; + return false; + } + + final private boolean jj_3R_132() { + if (jj_scan_token(COMMA)) return true; + if (jj_3R_131()) return true; + return false; + } + + final private boolean jj_3R_183() { + if (jj_3R_216()) return true; + return false; + } + + final private boolean jj_3R_285() { + if (jj_3R_109()) return true; + return false; + } + + final private boolean jj_3R_145() { + if (jj_3R_193()) return true; + return false; + } + + final private boolean jj_3R_182() { + if (jj_scan_token(LBRACE)) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_215()) { + jj_scanpos = xsp; + break; + } + } + if (jj_scan_token(RBRACE)) return true; + return false; + } + + final private boolean jj_3R_144() { + if (jj_3R_192()) return true; + return false; + } + + final private boolean jj_3R_113() { + return false; + } + + final private boolean jj_3R_102() { + Token xsp; + xsp = jj_scanpos; + if (jj_3R_143()) { + jj_scanpos = xsp; + if (jj_3R_144()) { + jj_scanpos = xsp; + if (jj_3R_145()) return true; + } + } + return false; + } + + final private boolean jj_3R_143() { + if (jj_3R_191()) return true; + return false; + } + + final private boolean jj_3R_216() { + if (jj_scan_token(EXTENDS)) return true; + if (jj_3R_149()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_249()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_131() { + if (jj_scan_token(IDENTIFIER)) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3R_183()) jj_scanpos = xsp; + return false; + } + + final private boolean jj_3R_114() { + return false; + } + + final private boolean jj_3_7() { + if (jj_scan_token(COMMA)) return true; + if (jj_3R_70()) return true; + return false; + } + + final private boolean jj_3R_80() { + Token xsp; + xsp = jj_scanpos; + lookingAhead = true; + jj_semLA = getToken(1).kind == GT && + ((Token.GTToken) getToken(1)).realKind == RSIGNEDSHIFT; + lookingAhead = false; + if (!jj_semLA || jj_3R_113()) return true; + if (jj_scan_token(GT)) return true; + if (jj_scan_token(GT)) return true; + return false; + } + + final private boolean jj_3R_97() { + if (jj_scan_token(LT)) return true; + if (jj_3R_131()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_132()) { + jj_scanpos = xsp; + break; + } + } + if (jj_scan_token(GT)) return true; + return false; + } + + final private boolean jj_3R_272() { + if (jj_3R_55()) return true; + return false; + } + + final private boolean jj_3R_70() { + if (jj_3R_50()) return true; + if (jj_scan_token(IDENTIFIER)) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3R_285()) jj_scanpos = xsp; + xsp = jj_scanpos; + if (jj_3R_286()) jj_scanpos = xsp; + return false; + } + + final private boolean jj_3R_81() { + Token xsp; + xsp = jj_scanpos; + lookingAhead = true; + jj_semLA = getToken(1).kind == GT && + ((Token.GTToken) getToken(1)).realKind == RUNSIGNEDSHIFT; + lookingAhead = false; + if (!jj_semLA || jj_3R_114()) return true; + if (jj_scan_token(GT)) return true; + if (jj_scan_token(GT)) return true; + if (jj_scan_token(GT)) return true; + return false; + } + + final private boolean jj_3R_251() { + if (jj_scan_token(SEMICOLON)) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_272()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_250() { + if (jj_3R_70()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3_7()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_246() { + if (jj_scan_token(FINALLY)) return true; + if (jj_3R_104()) return true; + return false; + } + + final private boolean jj_3R_219() { + if (jj_scan_token(LBRACE)) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3R_250()) jj_scanpos = xsp; + xsp = jj_scanpos; + if (jj_scan_token(82)) jj_scanpos = xsp; + xsp = jj_scanpos; + if (jj_3R_251()) jj_scanpos = xsp; + if (jj_scan_token(RBRACE)) return true; + return false; + } + + final private boolean jj_3R_245() { + if (jj_scan_token(CATCH)) return true; + if (jj_scan_token(LPAREN)) return true; + if (jj_3R_133()) return true; + if (jj_scan_token(RPAREN)) return true; + if (jj_3R_104()) return true; + return false; + } + + final private boolean jj_3R_212() { + if (jj_scan_token(TRY)) return true; + if (jj_3R_104()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_245()) { + jj_scanpos = xsp; + break; + } + } + xsp = jj_scanpos; + if (jj_3R_246()) jj_scanpos = xsp; + return false; + } + + final private boolean jj_3R_218() { + if (jj_3R_214()) return true; + return false; + } + + final private boolean jj_3R_185() { + if (jj_scan_token(ENUM)) return true; + if (jj_scan_token(IDENTIFIER)) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3R_218()) jj_scanpos = xsp; + if (jj_3R_219()) return true; + return false; + } + + final private boolean jj_3R_211() { + if (jj_scan_token(SYNCHRONIZED)) return true; + if (jj_scan_token(LPAREN)) return true; + if (jj_3R_56()) return true; + if (jj_scan_token(RPAREN)) return true; + if (jj_3R_104()) return true; + return false; + } + + final private boolean jj_3R_244() { + if (jj_3R_56()) return true; + return false; + } + + final private boolean jj_3R_248() { + if (jj_scan_token(COMMA)) return true; + if (jj_3R_149()) return true; + return false; + } + + final private boolean jj_3R_214() { + if (jj_scan_token(IMPLEMENTS)) return true; + if (jj_3R_149()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_248()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_210() { + if (jj_scan_token(THROW)) return true; + if (jj_3R_56()) return true; + if (jj_scan_token(SEMICOLON)) return true; + return false; + } + + final private boolean jj_3R_271() { + if (jj_3R_284()) return true; + return false; + } + + final private boolean jj_3R_299() { + if (jj_scan_token(COMMA)) return true; + if (jj_3R_201()) return true; + return false; + } + + final private boolean jj_3R_209() { + if (jj_scan_token(RETURN)) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3R_244()) jj_scanpos = xsp; + if (jj_scan_token(SEMICOLON)) return true; + return false; + } + + final private boolean jj_3R_247() { + if (jj_scan_token(COMMA)) return true; + if (jj_3R_149()) return true; + return false; + } + + final private boolean jj_3R_213() { + if (jj_scan_token(EXTENDS)) return true; + if (jj_3R_149()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_247()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_208() { + if (jj_scan_token(CONTINUE)) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_scan_token(72)) jj_scanpos = xsp; + if (jj_scan_token(SEMICOLON)) return true; + return false; + } + + final private boolean jj_3R_178() { + if (jj_scan_token(INTERFACE)) return true; + return false; + } + + final private boolean jj_3R_207() { + if (jj_scan_token(BREAK)) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_scan_token(72)) jj_scanpos = xsp; + if (jj_scan_token(SEMICOLON)) return true; + return false; + } + + final private boolean jj_3R_181() { + if (jj_3R_214()) return true; + return false; + } + + final private boolean jj_3R_180() { + if (jj_3R_213()) return true; + return false; + } + + final private boolean jj_3R_179() { + if (jj_3R_97()) return true; + return false; + } + + final private boolean jj_3R_284() { + if (jj_3R_296()) return true; + return false; + } + + final private boolean jj_3R_270() { + if (jj_3R_56()) return true; + return false; + } + + final private boolean jj_3R_130() { + Token xsp; + xsp = jj_scanpos; + if (jj_scan_token(16)) { + jj_scanpos = xsp; + if (jj_3R_178()) return true; + } + if (jj_scan_token(IDENTIFIER)) return true; + xsp = jj_scanpos; + if (jj_3R_179()) jj_scanpos = xsp; + xsp = jj_scanpos; + if (jj_3R_180()) jj_scanpos = xsp; + xsp = jj_scanpos; + if (jj_3R_181()) jj_scanpos = xsp; + if (jj_3R_182()) return true; + return false; + } + + final private boolean jj_3_44() { + if (jj_3R_50()) return true; + if (jj_3R_72()) return true; + if (jj_scan_token(IDENTIFIER)) return true; + return false; + } + + final private boolean jj_3R_296() { + if (jj_3R_201()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_299()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_241() { + if (jj_scan_token(ELSE)) return true; + if (jj_3R_129()) return true; + return false; + } + + final private boolean jj_3R_295() { + if (jj_3R_296()) return true; + return false; + } + + final private boolean jj_3_43() { + if (jj_3R_50()) return true; + if (jj_3R_72()) return true; + if (jj_scan_token(IDENTIFIER)) return true; + if (jj_scan_token(COLON)) return true; + return false; + } + + final private boolean jj_3R_294() { + if (jj_3R_128()) return true; + return false; + } + + final private boolean jj_3R_283() { + Token xsp; + xsp = jj_scanpos; + if (jj_3R_294()) { + jj_scanpos = xsp; + if (jj_3R_295()) return true; + } + return false; + } + + final private boolean jj_3R_269() { + if (jj_3R_283()) return true; + return false; + } + + final private boolean jj_3R_243() { + Token xsp; + xsp = jj_scanpos; + if (jj_3R_269()) jj_scanpos = xsp; + if (jj_scan_token(SEMICOLON)) return true; + xsp = jj_scanpos; + if (jj_3R_270()) jj_scanpos = xsp; + if (jj_scan_token(SEMICOLON)) return true; + xsp = jj_scanpos; + if (jj_3R_271()) jj_scanpos = xsp; + return false; + } + + final private boolean jj_3R_242() { + if (jj_3R_50()) return true; + if (jj_3R_72()) return true; + if (jj_scan_token(IDENTIFIER)) return true; + if (jj_scan_token(COLON)) return true; + if (jj_3R_56()) return true; + return false; + } + + final private boolean jj_3R_54() { + if (jj_scan_token(THROWS)) return true; + if (jj_3R_99()) return true; + return false; + } + + final private boolean jj_3R_206() { + if (jj_scan_token(FOR)) return true; + if (jj_scan_token(LPAREN)) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3R_242()) { + jj_scanpos = xsp; + if (jj_3R_243()) return true; + } + if (jj_scan_token(RPAREN)) return true; + if (jj_3R_129()) return true; + return false; + } + + final private boolean jj_3R_69() { + if (jj_3R_102()) return true; + return false; + } + + final private boolean jj_3R_205() { + if (jj_scan_token(DO)) return true; + if (jj_3R_129()) return true; + if (jj_scan_token(WHILE)) return true; + if (jj_scan_token(LPAREN)) return true; + if (jj_3R_56()) return true; + if (jj_scan_token(RPAREN)) return true; + if (jj_scan_token(SEMICOLON)) return true; + return false; + } + + final private boolean jj_3R_68() { + if (jj_scan_token(STRICTFP)) return true; + return false; + } + + final private boolean jj_3R_67() { + if (jj_scan_token(VOLATILE)) return true; + return false; + } + + final private boolean jj_3R_66() { + if (jj_scan_token(TRANSIENT)) return true; + return false; + } + + final private boolean jj_3R_204() { + if (jj_scan_token(WHILE)) return true; + if (jj_scan_token(LPAREN)) return true; + if (jj_3R_56()) return true; + if (jj_scan_token(RPAREN)) return true; + if (jj_3R_129()) return true; + return false; + } + + final private boolean jj_3R_65() { + if (jj_scan_token(NATIVE)) return true; + return false; + } + + final private boolean jj_3R_64() { + if (jj_scan_token(SYNCHRONIZED)) return true; + return false; + } + + final private boolean jj_3R_63() { + if (jj_scan_token(ABSTRACT)) return true; + return false; + } + + final private boolean jj_3R_268() { + if (jj_3R_49()) return true; + return false; + } + + final private boolean jj_3R_203() { + if (jj_scan_token(IF)) return true; + if (jj_scan_token(LPAREN)) return true; + if (jj_3R_56()) return true; + if (jj_scan_token(RPAREN)) return true; + if (jj_3R_129()) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3R_241()) jj_scanpos = xsp; + return false; + } + + final private boolean jj_3R_62() { + if (jj_scan_token(FINAL)) return true; + return false; + } + + final private boolean jj_3R_61() { + if (jj_scan_token(PRIVATE)) return true; + return false; + } + + final private boolean jj_3R_162() { + if (jj_scan_token(COMMA)) return true; + if (jj_3R_161()) return true; + return false; + } + + final private boolean jj_3R_60() { + if (jj_scan_token(PROTECTED)) return true; + return false; + } + + final private boolean jj_3R_59() { + if (jj_scan_token(STATIC)) return true; + return false; + } + + final private boolean jj_3R_58() { + if (jj_scan_token(PUBLIC)) return true; + return false; + } + + final private boolean jj_3R_282() { + if (jj_scan_token(_DEFAULT)) return true; + if (jj_scan_token(COLON)) return true; + return false; + } + + final private boolean jj_3_6() { + Token xsp; + xsp = jj_scanpos; + if (jj_3R_58()) { + jj_scanpos = xsp; + if (jj_3R_59()) { + jj_scanpos = xsp; + if (jj_3R_60()) { + jj_scanpos = xsp; + if (jj_3R_61()) { + jj_scanpos = xsp; + if (jj_3R_62()) { + jj_scanpos = xsp; + if (jj_3R_63()) { + jj_scanpos = xsp; + if (jj_3R_64()) { + jj_scanpos = xsp; + if (jj_3R_65()) { + jj_scanpos = xsp; + if (jj_3R_66()) { + jj_scanpos = xsp; + if (jj_3R_67()) { + jj_scanpos = xsp; + if (jj_3R_68()) { + jj_scanpos = xsp; + if (jj_3R_69()) return true; + } + } + } + } + } + } + } + } + } + } + } + return false; + } + + final private boolean jj_3R_281() { + if (jj_scan_token(CASE)) return true; + if (jj_3R_56()) return true; + if (jj_scan_token(COLON)) return true; + return false; + } + + final private boolean jj_3R_267() { + Token xsp; + xsp = jj_scanpos; + if (jj_3R_281()) { + jj_scanpos = xsp; + if (jj_3R_282()) return true; + } + return false; + } + + final private boolean jj_3R_50() { + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3_6()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_240() { + if (jj_3R_267()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_268()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3_42() { + if (jj_3R_90()) return true; + if (jj_3R_79()) return true; + return false; + } + + final private boolean jj_3R_202() { + if (jj_scan_token(SWITCH)) return true; + if (jj_scan_token(LPAREN)) return true; + if (jj_3R_56()) return true; + if (jj_scan_token(RPAREN)) return true; + if (jj_scan_token(LBRACE)) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_240()) { + jj_scanpos = xsp; + break; + } + } + if (jj_scan_token(RBRACE)) return true; + return false; + } + + final private boolean jj_3R_239() { + if (jj_3R_266()) return true; + return false; + } + + final private boolean jj_3R_57() { + if (jj_3R_102()) return true; + return false; + } + + final private boolean jj_3R_52() { + if (jj_3R_86()) return true; + return false; + } + + final private boolean jj_3R_238() { + if (jj_3R_265()) return true; + return false; + } + + final private boolean jj_3_5() { + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_57()) { + jj_scanpos = xsp; + break; + } + } + if (jj_scan_token(PACKAGE)) return true; + return false; + } + + final private boolean jj_3R_237() { + if (jj_3R_264()) return true; + return false; + } + + final private boolean jj_3R_201() { + Token xsp; + xsp = jj_scanpos; + if (jj_3R_236()) { + jj_scanpos = xsp; + if (jj_3R_237()) { + jj_scanpos = xsp; + if (jj_3R_238()) { + jj_scanpos = xsp; + if (jj_3R_239()) return true; + } + } + } + return false; + } + + final private boolean jj_3R_236() { + if (jj_3R_263()) return true; + return false; + } + + final private boolean jj_3R_200() { + if (jj_scan_token(SEMICOLON)) return true; + return false; + } + + final private boolean jj_3_41() { + if (jj_3R_50()) return true; + if (jj_3R_72()) return true; + if (jj_scan_token(IDENTIFIER)) return true; + return false; + } + + final private boolean jj_3R_128() { + if (jj_3R_50()) return true; + if (jj_3R_72()) return true; + if (jj_3R_161()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_162()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_51() { + if (jj_3R_97()) return true; + return false; + } + + final private boolean jj_3R_235() { + if (jj_scan_token(COLON)) return true; + if (jj_3R_56()) return true; + return false; + } + + final private boolean jj_3R_96() { + if (jj_3R_130()) return true; + return false; + } + + final private boolean jj_3R_95() { + if (jj_3R_129()) return true; + return false; + } + + final private boolean jj_3_4() { + if (jj_3R_56()) return true; + return false; + } + + final private boolean jj_3R_94() { + if (jj_3R_128()) return true; + if (jj_scan_token(SEMICOLON)) return true; + return false; + } + + final private boolean jj_3R_49() { + Token xsp; + xsp = jj_scanpos; + if (jj_3R_94()) { + jj_scanpos = xsp; + if (jj_3R_95()) { + jj_scanpos = xsp; + if (jj_3R_96()) return true; + } + } + return false; + } + + final private boolean jj_3R_146() { + if (jj_3R_49()) return true; + return false; + } + + final private boolean jj_3_3() { + if (jj_3R_55()) return true; + return false; + } + + final private boolean jj_3R_104() { + if (jj_scan_token(LBRACE)) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_146()) { + jj_scanpos = xsp; + break; + } + } + if (jj_scan_token(RBRACE)) return true; + return false; + } + + final private boolean jj_3_2() { + if (jj_3R_50()) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3R_51()) jj_scanpos = xsp; + xsp = jj_scanpos; + if (jj_3R_52()) jj_scanpos = xsp; + if (jj_scan_token(IDENTIFIER)) return true; + if (jj_3R_53()) return true; + xsp = jj_scanpos; + if (jj_3R_54()) jj_scanpos = xsp; + if (jj_scan_token(LBRACE)) return true; + return false; + } + + final private boolean jj_3R_89() { + if (jj_scan_token(IDENTIFIER)) return true; + if (jj_scan_token(COLON)) return true; + if (jj_3R_129()) return true; + return false; + } + + final private boolean jj_3_1() { + if (jj_3R_49()) return true; + return false; + } + + final private boolean jj_3R_199() { + if (jj_scan_token(ASSERT)) return true; + if (jj_3R_56()) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3R_235()) jj_scanpos = xsp; + if (jj_scan_token(SEMICOLON)) return true; + return false; + } + + final private boolean jj_3R_177() { + if (jj_3R_212()) return true; + return false; + } + + final private boolean jj_3R_176() { + if (jj_3R_211()) return true; + return false; + } + + final private boolean jj_3_38() { + if (jj_scan_token(LBRACKET)) return true; + if (jj_scan_token(RBRACKET)) return true; + return false; + } + + final private boolean jj_3R_175() { + if (jj_3R_210()) return true; + return false; + } + + final private boolean jj_3R_174() { + if (jj_3R_209()) return true; + return false; + } + + final private boolean jj_3R_173() { + if (jj_3R_208()) return true; + return false; + } + + final private boolean jj_3R_172() { + if (jj_3R_207()) return true; + return false; + } + + final private boolean jj_3R_171() { + if (jj_3R_206()) return true; + return false; + } + + final private boolean jj_3R_170() { + if (jj_3R_205()) return true; + return false; + } + + final private boolean jj_3R_169() { + if (jj_3R_204()) return true; + return false; + } + + final private boolean jj_3R_168() { + if (jj_3R_203()) return true; + return false; + } + + final private boolean jj_3R_167() { + if (jj_3R_202()) return true; + return false; + } + + final private boolean jj_3R_166() { + if (jj_3R_201()) return true; + if (jj_scan_token(SEMICOLON)) return true; + return false; + } + + final private boolean jj_3R_165() { + if (jj_3R_200()) return true; + return false; + } + + final private boolean jj_3R_164() { + if (jj_3R_104()) return true; + return false; + } + + final private boolean jj_3R_163() { + if (jj_3R_199()) return true; + return false; + } + + final private boolean jj_3R_260() { + if (jj_3R_78()) return true; + return false; + } + + final private boolean jj_3_40() { + if (jj_3R_89()) return true; + return false; + } + + final private boolean jj_3R_129() { + Token xsp; + xsp = jj_scanpos; + if (jj_3_40()) { + jj_scanpos = xsp; + if (jj_3R_163()) { + jj_scanpos = xsp; + if (jj_3R_164()) { + jj_scanpos = xsp; + if (jj_3R_165()) { + jj_scanpos = xsp; + if (jj_3R_166()) { + jj_scanpos = xsp; + if (jj_3R_167()) { + jj_scanpos = xsp; + if (jj_3R_168()) { + jj_scanpos = xsp; + if (jj_3R_169()) { + jj_scanpos = xsp; + if (jj_3R_170()) { + jj_scanpos = xsp; + if (jj_3R_171()) { + jj_scanpos = xsp; + if (jj_3R_172()) { + jj_scanpos = xsp; + if (jj_3R_173()) { + jj_scanpos = xsp; + if (jj_3R_174()) { + jj_scanpos = xsp; + if (jj_3R_175()) { + jj_scanpos = xsp; + if (jj_3R_176()) { + jj_scanpos = xsp; + if (jj_3R_177()) + return true; + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + return false; + } + + final private boolean jj_3R_279() { + if (jj_3R_182()) return true; + return false; + } + + final private boolean jj_3R_291() { + if (jj_scan_token(LBRACKET)) return true; + if (jj_scan_token(RBRACKET)) return true; + return false; + } + + final private boolean jj_3R_278() { + Token xsp; + if (jj_3R_291()) return true; + while (true) { + xsp = jj_scanpos; + if (jj_3R_291()) { + jj_scanpos = xsp; + break; + } + } + if (jj_3R_147()) return true; + return false; + } + + final private boolean jj_3_37() { + if (jj_scan_token(LBRACKET)) return true; + if (jj_3R_56()) return true; + if (jj_scan_token(RBRACKET)) return true; + return false; + } + + final private boolean jj_3_39() { + Token xsp; + if (jj_3_37()) return true; + while (true) { + xsp = jj_scanpos; + if (jj_3_37()) { + jj_scanpos = xsp; + break; + } + } + while (true) { + xsp = jj_scanpos; + if (jj_3_38()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_259() { + Token xsp; + xsp = jj_scanpos; + if (jj_3_39()) { + jj_scanpos = xsp; + if (jj_3R_278()) return true; + } + return false; + } + + final private boolean jj_3R_262() { + if (jj_3R_109()) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3R_279()) jj_scanpos = xsp; + return false; + } + + final private boolean jj_3R_232() { + if (jj_scan_token(COMMA)) return true; + if (jj_3R_56()) return true; + return false; + } + + final private boolean jj_3R_261() { + if (jj_3R_259()) return true; + return false; + } + + final private boolean jj_3R_123() { + if (jj_scan_token(NEW)) return true; + if (jj_3R_149()) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3R_260()) jj_scanpos = xsp; + xsp = jj_scanpos; + if (jj_3R_261()) { + jj_scanpos = xsp; + if (jj_3R_262()) return true; + } + return false; + } + + final private boolean jj_3R_87() { + Token xsp; + xsp = jj_scanpos; + if (jj_3_36()) { + jj_scanpos = xsp; + if (jj_3R_123()) return true; + } + return false; + } + + final private boolean jj_3_36() { + if (jj_scan_token(NEW)) return true; + if (jj_3R_83()) return true; + if (jj_3R_259()) return true; + return false; + } + + final private boolean jj_3R_148() { + if (jj_3R_195()) return true; + return false; + } + + final private boolean jj_3R_195() { + if (jj_3R_56()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_232()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_109() { + if (jj_scan_token(LPAREN)) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3R_148()) jj_scanpos = xsp; + if (jj_scan_token(RPAREN)) return true; + return false; + } + + final private boolean jj_3R_258() { + if (jj_scan_token(NULL)) return true; + return false; + } + + final private boolean jj_3R_257() { + Token xsp; + xsp = jj_scanpos; + if (jj_scan_token(56)) { + jj_scanpos = xsp; + if (jj_scan_token(25)) return true; + } + return false; + } + + final private boolean jj_3R_234() { + if (jj_3R_258()) return true; + return false; + } + + final private boolean jj_3R_233() { + if (jj_3R_257()) return true; + return false; + } + + final private boolean jj_3R_196() { + Token xsp; + xsp = jj_scanpos; + if (jj_scan_token(61)) { + jj_scanpos = xsp; + if (jj_scan_token(65)) { + jj_scanpos = xsp; + if (jj_scan_token(70)) { + jj_scanpos = xsp; + if (jj_scan_token(71)) { + jj_scanpos = xsp; + if (jj_3R_233()) { + jj_scanpos = xsp; + if (jj_3R_234()) return true; + } + } + } + } + } + return false; + } + + final private boolean jj_3R_152() { + if (jj_3R_196()) return true; + return false; + } + + final private boolean jj_3R_121() { + if (jj_3R_109()) return true; + return false; + } + + final private boolean jj_3R_120() { + if (jj_scan_token(DOT)) return true; + if (jj_scan_token(IDENTIFIER)) return true; + return false; + } + + final private boolean jj_3_33() { + if (jj_scan_token(DOT)) return true; + if (jj_scan_token(THIS)) return true; + return false; + } + + final private boolean jj_3R_119() { + if (jj_scan_token(LBRACKET)) return true; + if (jj_3R_56()) return true; + if (jj_scan_token(RBRACKET)) return true; + return false; + } + + final private boolean jj_3_32() { + if (jj_scan_token(DOT)) return true; + if (jj_scan_token(SUPER)) return true; + if (jj_scan_token(DOT)) return true; + return false; + } + + final private boolean jj_3_35() { + if (jj_3R_88()) return true; + return false; + } + + final private boolean jj_3_34() { + if (jj_scan_token(DOT)) return true; + if (jj_3R_87()) return true; + return false; + } + + final private boolean jj_3R_118() { + if (jj_scan_token(DOT)) return true; + if (jj_scan_token(THIS)) return true; + return false; + } + + final private boolean jj_3_31() { + if (jj_3R_86()) return true; + if (jj_scan_token(DOT)) return true; + if (jj_scan_token(CLASS)) return true; + return false; + } + + final private boolean jj_3R_117() { + if (jj_scan_token(DOT)) return true; + if (jj_scan_token(SUPER)) return true; + return false; + } + + final private boolean jj_3R_84() { + Token xsp; + xsp = jj_scanpos; + if (jj_3R_117()) { + jj_scanpos = xsp; + if (jj_3R_118()) { + jj_scanpos = xsp; + if (jj_3_34()) { + jj_scanpos = xsp; + if (jj_3_35()) { + jj_scanpos = xsp; + if (jj_3R_119()) { + jj_scanpos = xsp; + if (jj_3R_120()) { + jj_scanpos = xsp; + if (jj_3R_121()) return true; + } + } + } + } + } + } + return false; + } + + final private boolean jj_3R_85() { + if (jj_scan_token(IDENTIFIER)) return true; + if (jj_scan_token(DOT)) return true; + return false; + } + + final private boolean jj_3R_159() { + if (jj_3R_91()) return true; + return false; + } + + final private boolean jj_3_30() { + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_85()) { + jj_scanpos = xsp; + break; + } + } + if (jj_scan_token(THIS)) return true; + return false; + } + + final private boolean jj_3R_158() { + if (jj_3R_86()) return true; + if (jj_scan_token(DOT)) return true; + if (jj_scan_token(CLASS)) return true; + return false; + } + + final private boolean jj_3R_157() { + if (jj_3R_87()) return true; + return false; + } + + final private boolean jj_3R_156() { + if (jj_scan_token(LPAREN)) return true; + if (jj_3R_56()) return true; + if (jj_scan_token(RPAREN)) return true; + return false; + } + + final private boolean jj_3_29() { + if (jj_3R_84()) return true; + return false; + } + + final private boolean jj_3R_155() { + if (jj_scan_token(SUPER)) return true; + if (jj_scan_token(DOT)) return true; + if (jj_scan_token(IDENTIFIER)) return true; + return false; + } + + final private boolean jj_3R_197() { + if (jj_scan_token(IDENTIFIER)) return true; + if (jj_scan_token(DOT)) return true; + return false; + } + + final private boolean jj_3R_154() { + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_197()) { + jj_scanpos = xsp; + break; + } + } + if (jj_scan_token(THIS)) return true; + return false; + } + + final private boolean jj_3R_124() { + Token xsp; + xsp = jj_scanpos; + if (jj_3R_153()) { + jj_scanpos = xsp; + if (jj_3R_154()) { + jj_scanpos = xsp; + if (jj_3R_155()) { + jj_scanpos = xsp; + if (jj_3R_156()) { + jj_scanpos = xsp; + if (jj_3R_157()) { + jj_scanpos = xsp; + if (jj_3R_158()) { + jj_scanpos = xsp; + if (jj_3R_159()) return true; + } + } + } + } + } + } + return false; + } + + final private boolean jj_3R_153() { + if (jj_3R_196()) return true; + return false; + } + + final private boolean jj_3R_88() { + if (jj_scan_token(DOT)) return true; + if (jj_3R_78()) return true; + if (jj_scan_token(IDENTIFIER)) return true; + return false; + } + + final private boolean jj_3R_280() { + if (jj_3R_293()) return true; + return false; + } + + final private boolean jj_3_28() { + if (jj_scan_token(LPAREN)) return true; + if (jj_3R_83()) return true; + return false; + } + + final private boolean jj_3R_90() { + if (jj_3R_124()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3_29()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_319() { + if (jj_scan_token(LPAREN)) return true; + if (jj_3R_72()) return true; + if (jj_scan_token(RPAREN)) return true; + if (jj_3R_313()) return true; + return false; + } + + final private boolean jj_3R_318() { + if (jj_scan_token(LPAREN)) return true; + if (jj_3R_72()) return true; + if (jj_scan_token(RPAREN)) return true; + if (jj_3R_307()) return true; + return false; + } + + final private boolean jj_3R_317() { + Token xsp; + xsp = jj_scanpos; + if (jj_3R_318()) { + jj_scanpos = xsp; + if (jj_3R_319()) return true; + } + return false; + } + + final private boolean jj_3R_293() { + Token xsp; + xsp = jj_scanpos; + if (jj_scan_token(97)) { + jj_scanpos = xsp; + if (jj_scan_token(98)) return true; + } + return false; + } + + final private boolean jj_3_27() { + if (jj_scan_token(LPAREN)) return true; + if (jj_3R_72()) return true; + if (jj_scan_token(LBRACKET)) return true; + return false; + } + + final private boolean jj_3R_266() { + if (jj_3R_90()) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3R_280()) jj_scanpos = xsp; + return false; + } + + final private boolean jj_3R_116() { + if (jj_scan_token(LPAREN)) return true; + if (jj_3R_72()) return true; + if (jj_scan_token(RPAREN)) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_scan_token(88)) { + jj_scanpos = xsp; + if (jj_scan_token(87)) { + jj_scanpos = xsp; + if (jj_scan_token(75)) { + jj_scanpos = xsp; + if (jj_scan_token(72)) { + jj_scanpos = xsp; + if (jj_scan_token(52)) { + jj_scanpos = xsp; + if (jj_scan_token(49)) { + jj_scanpos = xsp; + if (jj_scan_token(39)) { + jj_scanpos = xsp; + if (jj_3R_152()) return true; + } + } + } + } + } + } + } + return false; + } + + final private boolean jj_3R_115() { + if (jj_scan_token(LPAREN)) return true; + if (jj_3R_72()) return true; + if (jj_scan_token(LBRACKET)) return true; + if (jj_scan_token(RBRACKET)) return true; + return false; + } + + final private boolean jj_3R_82() { + Token xsp; + xsp = jj_scanpos; + if (jj_3_26()) { + jj_scanpos = xsp; + if (jj_3R_115()) { + jj_scanpos = xsp; + if (jj_3R_116()) return true; + } + } + return false; + } + + final private boolean jj_3_26() { + if (jj_scan_token(LPAREN)) return true; + if (jj_3R_83()) return true; + return false; + } + + final private boolean jj_3_25() { + if (jj_3R_82()) return true; + return false; + } + + final private boolean jj_3_24() { + if (jj_3R_81()) return true; + return false; + } + + final private boolean jj_3R_316() { + if (jj_3R_266()) return true; + return false; + } + + final private boolean jj_3R_315() { + if (jj_3R_317()) return true; + return false; + } + + final private boolean jj_3R_314() { + Token xsp; + xsp = jj_scanpos; + if (jj_scan_token(88)) { + jj_scanpos = xsp; + if (jj_scan_token(87)) return true; + } + if (jj_3R_307()) return true; + return false; + } + + final private boolean jj_3R_313() { + Token xsp; + xsp = jj_scanpos; + if (jj_3R_314()) { + jj_scanpos = xsp; + if (jj_3R_315()) { + jj_scanpos = xsp; + if (jj_3R_316()) return true; + } + } + return false; + } + + final private boolean jj_3R_264() { + if (jj_scan_token(DECR)) return true; + if (jj_3R_90()) return true; + return false; + } + + final private boolean jj_3R_306() { + Token xsp; + xsp = jj_scanpos; + if (jj_scan_token(99)) { + jj_scanpos = xsp; + if (jj_scan_token(100)) return true; + } + if (jj_3R_305()) return true; + return false; + } + + final private boolean jj_3R_308() { + Token xsp; + xsp = jj_scanpos; + if (jj_scan_token(101)) { + jj_scanpos = xsp; + if (jj_scan_token(102)) { + jj_scanpos = xsp; + if (jj_scan_token(106)) return true; + } + } + if (jj_3R_307()) return true; + return false; + } + + final private boolean jj_3_23() { + if (jj_3R_80()) return true; + return false; + } + + final private boolean jj_3R_263() { + if (jj_scan_token(INCR)) return true; + if (jj_3R_90()) return true; + return false; + } + + final private boolean jj_3R_312() { + if (jj_3R_313()) return true; + return false; + } + + final private boolean jj_3_22() { + Token xsp; + xsp = jj_scanpos; + if (jj_scan_token(107)) { + jj_scanpos = xsp; + if (jj_3_23()) { + jj_scanpos = xsp; + if (jj_3_24()) return true; + } + } + if (jj_3R_304()) return true; + return false; + } + + final private boolean jj_3R_311() { + if (jj_3R_264()) return true; + return false; + } + + final private boolean jj_3R_310() { + if (jj_3R_263()) return true; + return false; + } + + final private boolean jj_3R_309() { + Token xsp; + xsp = jj_scanpos; + if (jj_scan_token(99)) { + jj_scanpos = xsp; + if (jj_scan_token(100)) return true; + } + if (jj_3R_307()) return true; + return false; + } + + final private boolean jj_3R_307() { + Token xsp; + xsp = jj_scanpos; + if (jj_3R_309()) { + jj_scanpos = xsp; + if (jj_3R_310()) { + jj_scanpos = xsp; + if (jj_3R_311()) { + jj_scanpos = xsp; + if (jj_3R_312()) return true; + } + } + } + return false; + } + + final private boolean jj_3R_303() { + Token xsp; + xsp = jj_scanpos; + if (jj_scan_token(86)) { + jj_scanpos = xsp; + if (jj_scan_token(122)) { + jj_scanpos = xsp; + if (jj_scan_token(92)) { + jj_scanpos = xsp; + if (jj_scan_token(93)) return true; + } + } + } + if (jj_3R_302()) return true; + return false; + } + + final private boolean jj_3R_301() { + if (jj_scan_token(INSTANCEOF)) return true; + if (jj_3R_72()) return true; + return false; + } + + final private boolean jj_3R_305() { + if (jj_3R_307()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_308()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_298() { + Token xsp; + xsp = jj_scanpos; + if (jj_scan_token(91)) { + jj_scanpos = xsp; + if (jj_scan_token(94)) return true; + } + if (jj_3R_297()) return true; + return false; + } + + final private boolean jj_3R_304() { + if (jj_3R_305()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_306()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_302() { + if (jj_3R_304()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3_22()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_288() { + if (jj_scan_token(BIT_AND)) return true; + if (jj_3R_287()) return true; + return false; + } + + final private boolean jj_3R_300() { + if (jj_3R_302()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_303()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_254() { + if (jj_scan_token(BIT_OR)) return true; + if (jj_3R_253()) return true; + return false; + } + + final private boolean jj_3R_297() { + if (jj_3R_300()) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3R_301()) jj_scanpos = xsp; + return false; + } + + final private boolean jj_3R_274() { + if (jj_scan_token(XOR)) return true; + if (jj_3R_273()) return true; + return false; + } + + final private boolean jj_3R_230() { + if (jj_scan_token(SC_AND)) return true; + if (jj_3R_229()) return true; + return false; + } + + final private boolean jj_3R_287() { + if (jj_3R_297()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_298()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_190() { + if (jj_scan_token(SC_OR)) return true; + if (jj_3R_189()) return true; + return false; + } + + final private boolean jj_3R_273() { + if (jj_3R_287()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_288()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_142() { + if (jj_scan_token(HOOK)) return true; + if (jj_3R_56()) return true; + if (jj_scan_token(COLON)) return true; + if (jj_3R_56()) return true; + return false; + } + + final private boolean jj_3R_253() { + if (jj_3R_273()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_274()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_229() { + if (jj_3R_253()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_254()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_189() { + if (jj_3R_229()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_230()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_141() { + if (jj_3R_189()) return true; + Token xsp; + while (true) { + xsp = jj_scanpos; + if (jj_3R_190()) { + jj_scanpos = xsp; + break; + } + } + return false; + } + + final private boolean jj_3R_101() { + if (jj_3R_141()) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_3R_142()) jj_scanpos = xsp; + return false; + } + + final private boolean jj_3R_265() { + if (jj_3R_90()) return true; + if (jj_3R_79()) return true; + if (jj_3R_56()) return true; + return false; + } + + final private boolean jj_3R_79() { + Token xsp; + xsp = jj_scanpos; + if (jj_scan_token(85)) { + jj_scanpos = xsp; + if (jj_scan_token(110)) { + jj_scanpos = xsp; + if (jj_scan_token(111)) { + jj_scanpos = xsp; + if (jj_scan_token(115)) { + jj_scanpos = xsp; + if (jj_scan_token(108)) { + jj_scanpos = xsp; + if (jj_scan_token(109)) { + jj_scanpos = xsp; + if (jj_scan_token(116)) { + jj_scanpos = xsp; + if (jj_scan_token(117)) { + jj_scanpos = xsp; + if (jj_scan_token(118)) { + jj_scanpos = xsp; + if (jj_scan_token(112)) { + jj_scanpos = xsp; + if (jj_scan_token(114)) { + jj_scanpos = xsp; + if (jj_scan_token(113)) + return true; + } + } + } + } + } + } + } + } + } + } + } + return false; + } + + final private boolean jj_3_21() { + if (jj_3R_79()) return true; + if (jj_3R_56()) return true; + return false; + } + + public JavaParserTokenManager token_source; + JavaCharStream jj_input_stream; + public Token token, jj_nt; + private int jj_ntk; + private Token jj_scanpos, jj_lastpos; + private int jj_la; + public boolean lookingAhead = false; + private boolean jj_semLA; + + public JavaParser(java.io.InputStream stream) { + this(stream, null); + } + + public JavaParser(java.io.InputStream stream, String encoding) { + try { + jj_input_stream = new JavaCharStream(stream, encoding, 1, 1); + } catch (java.io.UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + token_source = new JavaParserTokenManager(jj_input_stream); + token = new Token(); + jj_ntk = -1; + } + + public void ReInit(java.io.InputStream stream) { + ReInit(stream, null); + } + + public void ReInit(java.io.InputStream stream, String encoding) { + try { + jj_input_stream.ReInit(stream, encoding, 1, 1); + } catch (java.io.UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + token_source.ReInit(jj_input_stream); + token = new Token(); + jj_ntk = -1; + jjtree.reset(); + } + + public JavaParser(java.io.Reader stream) { + jj_input_stream = new JavaCharStream(stream, 1, 1); + token_source = new JavaParserTokenManager(jj_input_stream); + token = new Token(); + jj_ntk = -1; + } + + public void ReInit(java.io.Reader stream) { + jj_input_stream.ReInit(stream, 1, 1); + token_source.ReInit(jj_input_stream); + token = new Token(); + jj_ntk = -1; + jjtree.reset(); + } + + public JavaParser(JavaParserTokenManager tm) { + token_source = tm; + token = new Token(); + jj_ntk = -1; + } + + public void ReInit(JavaParserTokenManager tm) { + token_source = tm; + token = new Token(); + jj_ntk = -1; + jjtree.reset(); + } + + final private Token jj_consume_token(int kind) throws ParseException { + Token oldToken; + if ((oldToken = token).next != null) token = token.next; + else token = token.next = token_source.getNextToken(); + jj_ntk = -1; + if (token.kind == kind) { + return token; + } + token = oldToken; + throw generateParseException(); + } + + static private final class LookaheadSuccess extends java.lang.Error { + } + + final private LookaheadSuccess jj_ls = new LookaheadSuccess(); + + final private boolean jj_scan_token(int kind) { + if (jj_scanpos == jj_lastpos) { + jj_la--; + if (jj_scanpos.next == null) { + jj_lastpos = jj_scanpos = jj_scanpos.next = token_source.getNextToken(); + } else { + jj_lastpos = jj_scanpos = jj_scanpos.next; + } + } else { + jj_scanpos = jj_scanpos.next; + } + if (jj_scanpos.kind != kind) return true; + if (jj_la == 0 && jj_scanpos == jj_lastpos) throw jj_ls; + return false; + } + + final public Token getNextToken() { + if (token.next != null) token = token.next; + else token = token.next = token_source.getNextToken(); + jj_ntk = -1; + return token; + } + + final public Token getToken(int index) { + Token t = lookingAhead ? jj_scanpos : token; + for (int i = 0; i < index; i++) { + if (t.next != null) t = t.next; + else t = t.next = token_source.getNextToken(); + } + return t; + } + + final private int jj_ntk() { + if ((jj_nt = token.next) == null) + return (jj_ntk = (token.next = token_source.getNextToken()).kind); + else + return (jj_ntk = jj_nt.kind); + } + + public ParseException generateParseException() { + Token errortok = token.next; + int line = errortok.beginLine, column = errortok.beginColumn; + String mess = (errortok.kind == 0) ? tokenImage[0] : errortok.image; + return new ParseException("Unable to parse Java code near token: " + mess, line, column); + } + + final public void enable_tracing() { + } + + final public void disable_tracing() { + } + +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/parser/JavaParserConstants.java b/trunk/jaxx-compiler/src/main/java/jaxx/parser/JavaParserConstants.java new file mode 100644 index 0000000..c0c1075 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/parser/JavaParserConstants.java @@ -0,0 +1,260 @@ +/* Generated By:JJTree&JavaCC: Do not edit this line. JavaParserConstants.java */ +package jaxx.parser; + +public interface JavaParserConstants { + + int EOF = 0; + int WHITE_SPACE = 3; + int SINGLE_LINE_COMMENT = 4; + int FORMAL_COMMENT = 5; + int MULTI_LINE_COMMENT = 6; + int ABSTRACT = 8; + int ASSERT = 9; + int BOOLEAN = 10; + int BREAK = 11; + int BYTE = 12; + int CASE = 13; + int CATCH = 14; + int CHAR = 15; + int CLASS = 16; + int CONST = 17; + int CONTINUE = 18; + int _DEFAULT = 19; + int DO = 20; + int DOUBLE = 21; + int ELSE = 22; + int ENUM = 23; + int EXTENDS = 24; + int FALSE = 25; + int FINAL = 26; + int FINALLY = 27; + int FLOAT = 28; + int FOR = 29; + int GOTO = 30; + int IF = 31; + int IMPLEMENTS = 32; + int IMPORT = 33; + int INSTANCEOF = 34; + int INT = 35; + int INTERFACE = 36; + int LONG = 37; + int NATIVE = 38; + int NEW = 39; + int NULL = 40; + int PACKAGE = 41; + int PRIVATE = 42; + int PROTECTED = 43; + int PUBLIC = 44; + int RETURN = 45; + int SHORT = 46; + int STATIC = 47; + int STRICTFP = 48; + int SUPER = 49; + int SWITCH = 50; + int SYNCHRONIZED = 51; + int THIS = 52; + int THROW = 53; + int THROWS = 54; + int TRANSIENT = 55; + int TRUE = 56; + int TRY = 57; + int VOID = 58; + int VOLATILE = 59; + int WHILE = 60; + int INTEGER_LITERAL = 61; + int DECIMAL_LITERAL = 62; + int HEX_LITERAL = 63; + int OCTAL_LITERAL = 64; + int FLOATING_POINT_LITERAL = 65; + int DECIMAL_FLOATING_POINT_LITERAL = 66; + int DECIMAL_EXPONENT = 67; + int HEXADECIMAL_FLOATING_POINT_LITERAL = 68; + int HEXADECIMAL_EXPONENT = 69; + int CHARACTER_LITERAL = 70; + int STRING_LITERAL = 71; + int IDENTIFIER = 72; + int LETTER = 73; + int PART_LETTER = 74; + int LPAREN = 75; + int RPAREN = 76; + int LBRACE = 77; + int RBRACE = 78; + int LBRACKET = 79; + int RBRACKET = 80; + int SEMICOLON = 81; + int COMMA = 82; + int DOT = 83; + int AT = 84; + int ASSIGN = 85; + int LT = 86; + int BANG = 87; + int TILDE = 88; + int HOOK = 89; + int COLON = 90; + int EQ = 91; + int LE = 92; + int GE = 93; + int NE = 94; + int SC_OR = 95; + int SC_AND = 96; + int INCR = 97; + int DECR = 98; + int PLUS = 99; + int MINUS = 100; + int STAR = 101; + int SLASH = 102; + int BIT_AND = 103; + int BIT_OR = 104; + int XOR = 105; + int REM = 106; + int LSHIFT = 107; + int PLUSASSIGN = 108; + int MINUSASSIGN = 109; + int STARASSIGN = 110; + int SLASHASSIGN = 111; + int ANDASSIGN = 112; + int ORASSIGN = 113; + int XORASSIGN = 114; + int REMASSIGN = 115; + int LSHIFTASSIGN = 116; + int RSIGNEDSHIFTASSIGN = 117; + int RUNSIGNEDSHIFTASSIGN = 118; + int ELLIPSIS = 119; + int RUNSIGNEDSHIFT = 120; + int RSIGNEDSHIFT = 121; + int GT = 122; + int STUFF_TO_IGNORE = 124; + + int DEFAULT = 0; + int IN_FORMAL_COMMENT = 1; + int IN_MULTI_LINE_COMMENT = 2; + + String[] tokenImage = { + "<EOF>", + "<token of kind 1>", + "\"/*\"", + "<WHITE_SPACE>", + "<SINGLE_LINE_COMMENT>", + "\"*/\"", + "\"*/\"", + "<token of kind 7>", + "\"abstract\"", + "\"assert\"", + "\"boolean\"", + "\"break\"", + "\"byte\"", + "\"case\"", + "\"catch\"", + "\"char\"", + "\"class\"", + "\"const\"", + "\"continue\"", + "\"default\"", + "\"do\"", + "\"double\"", + "\"else\"", + "\"enum\"", + "\"extends\"", + "\"false\"", + "\"final\"", + "\"finally\"", + "\"float\"", + "\"for\"", + "\"goto\"", + "\"if\"", + "\"implements\"", + "\"import\"", + "\"instanceof\"", + "\"int\"", + "\"interface\"", + "\"long\"", + "\"native\"", + "\"new\"", + "\"null\"", + "\"package\"", + "\"private\"", + "\"protected\"", + "\"public\"", + "\"return\"", + "\"short\"", + "\"static\"", + "\"strictfp\"", + "\"super\"", + "\"switch\"", + "\"synchronized\"", + "\"this\"", + "\"throw\"", + "\"throws\"", + "\"transient\"", + "\"true\"", + "\"try\"", + "\"void\"", + "\"volatile\"", + "\"while\"", + "<INTEGER_LITERAL>", + "<DECIMAL_LITERAL>", + "<HEX_LITERAL>", + "<OCTAL_LITERAL>", + "<FLOATING_POINT_LITERAL>", + "<DECIMAL_FLOATING_POINT_LITERAL>", + "<DECIMAL_EXPONENT>", + "<HEXADECIMAL_FLOATING_POINT_LITERAL>", + "<HEXADECIMAL_EXPONENT>", + "<CHARACTER_LITERAL>", + "<STRING_LITERAL>", + "<IDENTIFIER>", + "<LETTER>", + "<PART_LETTER>", + "\"(\"", + "\")\"", + "\"{\"", + "\"}\"", + "\"[\"", + "\"]\"", + "\";\"", + "\",\"", + "\".\"", + "\"@\"", + "\"=\"", + "\"<\"", + "\"!\"", + "\"~\"", + "\"?\"", + "\":\"", + "\"==\"", + "\"<=\"", + "\">=\"", + "\"!=\"", + "\"||\"", + "\"&&\"", + "\"++\"", + "\"--\"", + "\"+\"", + "\"-\"", + "\"*\"", + "\"/\"", + "\"&\"", + "\"|\"", + "\"^\"", + "\"%\"", + "\"<<\"", + "\"+=\"", + "\"-=\"", + "\"*=\"", + "\"/=\"", + "\"&=\"", + "\"|=\"", + "\"^=\"", + "\"%=\"", + "\"<<=\"", + "\">>=\"", + "\">>>=\"", + "\"...\"", + "\">>>\"", + "\">>\"", + "\">\"", + "\"\\u001a\"", + "<STUFF_TO_IGNORE>", + }; + +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/parser/JavaParserTokenManager.java b/trunk/jaxx-compiler/src/main/java/jaxx/parser/JavaParserTokenManager.java new file mode 100644 index 0000000..73e4d1a --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/parser/JavaParserTokenManager.java @@ -0,0 +1,2072 @@ +/* Generated By:JJTree&JavaCC: Do not edit this line. JavaParserTokenManager.java */ +package jaxx.parser; + +public class JavaParserTokenManager implements JavaParserConstants { + public java.io.PrintStream debugStream = System.out; + + public void setDebugStream(java.io.PrintStream ds) { + debugStream = ds; + } + + private int jjStopStringLiteralDfa_0(int pos, long active0, long active1) { + switch (pos) { + case 0: + if ((active0 & 0x4L) != 0L || (active1 & 0x804000000000L) != 0L) + return 48; + if ((active1 & 0x80000000080000L) != 0L) + return 5; + if ((active0 & 0x1fffffffffffff00L) != 0L) { + jjmatchedKind = 72; + return 29; + } + return -1; + case 1: + if ((active0 & 0x4L) != 0L) + return 46; + if ((active0 & 0x1fffffff7fcfff00L) != 0L) { + if (jjmatchedPos != 1) { + jjmatchedKind = 72; + jjmatchedPos = 1; + } + return 29; + } + if ((active0 & 0x80300000L) != 0L) + return 29; + return -1; + case 2: + if ((active0 & 0x1dffff675fefff00L) != 0L) { + if (jjmatchedPos != 2) { + jjmatchedKind = 72; + jjmatchedPos = 2; + } + return 29; + } + if ((active0 & 0x200009820000000L) != 0L) + return 29; + return -1; + case 3: + if ((active0 & 0x18effe571f2f4f00L) != 0L) { + jjmatchedKind = 72; + jjmatchedPos = 3; + return 29; + } + if ((active0 & 0x510012040c0b000L) != 0L) + return 29; + return -1; + case 4: + if ((active0 & 0x88dbe57012c0700L) != 0L) { + if (jjmatchedPos != 4) { + jjmatchedKind = 72; + jjmatchedPos = 4; + } + return 29; + } + if ((active0 & 0x106240001e034800L) != 0L) + return 29; + return -1; + case 5: + if ((active0 & 0x8890e15090c0500L) != 0L) { + jjmatchedKind = 72; + jjmatchedPos = 5; + return 29; + } + if ((active0 & 0x44b04200200200L) != 0L) + return 29; + return -1; + case 6: + if ((active0 & 0x889081500040100L) != 0L) { + jjmatchedKind = 72; + jjmatchedPos = 6; + return 29; + } + if ((active0 & 0x60009080400L) != 0L) + return 29; + return -1; + case 7: + if ((active0 & 0x801000000040100L) != 0L) + return 29; + if ((active0 & 0x88081500000000L) != 0L) { + jjmatchedKind = 72; + jjmatchedPos = 7; + return 29; + } + return -1; + case 8: + if ((active0 & 0x8000500000000L) != 0L) { + jjmatchedKind = 72; + jjmatchedPos = 8; + return 29; + } + if ((active0 & 0x80081000000000L) != 0L) + return 29; + return -1; + case 9: + if ((active0 & 0x8000000000000L) != 0L) { + jjmatchedKind = 72; + jjmatchedPos = 9; + return 29; + } + if ((active0 & 0x500000000L) != 0L) + return 29; + return -1; + case 10: + if ((active0 & 0x8000000000000L) != 0L) { + jjmatchedKind = 72; + jjmatchedPos = 10; + return 29; + } + return -1; + default: + return -1; + } + } + + private int jjStartNfa_0(int pos, long active0, long active1) { + return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0, active1), pos + 1); + } + + private int jjStopAtPos(int pos, int kind) { + jjmatchedKind = kind; + jjmatchedPos = pos; + return pos + 1; + } + + private int jjStartNfaWithStates_0(int pos, int kind, int state) { + jjmatchedKind = kind; + jjmatchedPos = pos; + try { + curChar = input_stream.readChar(); + } + catch (java.io.IOException e) { + return pos + 1; + } + return jjMoveNfa_0(state, pos + 1); + } + + private int jjMoveStringLiteralDfa0_0() { + switch (curChar) { + case 26: + return jjStopAtPos(0, 123); + case 33: + jjmatchedKind = 87; + return jjMoveStringLiteralDfa1_0(0x0L, 0x40000000L); + case 37: + jjmatchedKind = 106; + return jjMoveStringLiteralDfa1_0(0x0L, 0x8000000000000L); + case 38: + jjmatchedKind = 103; + return jjMoveStringLiteralDfa1_0(0x0L, 0x1000100000000L); + case 40: + return jjStopAtPos(0, 75); + case 41: + return jjStopAtPos(0, 76); + case 42: + jjmatchedKind = 101; + return jjMoveStringLiteralDfa1_0(0x0L, 0x400000000000L); + case 43: + jjmatchedKind = 99; + return jjMoveStringLiteralDfa1_0(0x0L, 0x100200000000L); + case 44: + return jjStopAtPos(0, 82); + case 45: + jjmatchedKind = 100; + return jjMoveStringLiteralDfa1_0(0x0L, 0x200400000000L); + case 46: + jjmatchedKind = 83; + return jjMoveStringLiteralDfa1_0(0x0L, 0x80000000000000L); + case 47: + jjmatchedKind = 102; + return jjMoveStringLiteralDfa1_0(0x4L, 0x800000000000L); + case 58: + return jjStopAtPos(0, 90); + case 59: + return jjStopAtPos(0, 81); + case 60: + jjmatchedKind = 86; + return jjMoveStringLiteralDfa1_0(0x0L, 0x10080010000000L); + case 61: + jjmatchedKind = 85; + return jjMoveStringLiteralDfa1_0(0x0L, 0x8000000L); + case 62: + jjmatchedKind = 122; + return jjMoveStringLiteralDfa1_0(0x0L, 0x360000020000000L); + case 63: + return jjStopAtPos(0, 89); + case 64: + return jjStopAtPos(0, 84); + case 91: + return jjStopAtPos(0, 79); + case 93: + return jjStopAtPos(0, 80); + case 94: + jjmatchedKind = 105; + return jjMoveStringLiteralDfa1_0(0x0L, 0x4000000000000L); + case 97: + return jjMoveStringLiteralDfa1_0(0x300L, 0x0L); + case 98: + return jjMoveStringLiteralDfa1_0(0x1c00L, 0x0L); + case 99: + return jjMoveStringLiteralDfa1_0(0x7e000L, 0x0L); + case 100: + return jjMoveStringLiteralDfa1_0(0x380000L, 0x0L); + case 101: + return jjMoveStringLiteralDfa1_0(0x1c00000L, 0x0L); + case 102: + return jjMoveStringLiteralDfa1_0(0x3e000000L, 0x0L); + case 103: + return jjMoveStringLiteralDfa1_0(0x40000000L, 0x0L); + case 105: + return jjMoveStringLiteralDfa1_0(0x1f80000000L, 0x0L); + case 108: + return jjMoveStringLiteralDfa1_0(0x2000000000L, 0x0L); + case 110: + return jjMoveStringLiteralDfa1_0(0x1c000000000L, 0x0L); + case 112: + return jjMoveStringLiteralDfa1_0(0x1e0000000000L, 0x0L); + case 114: + return jjMoveStringLiteralDfa1_0(0x200000000000L, 0x0L); + case 115: + return jjMoveStringLiteralDfa1_0(0xfc00000000000L, 0x0L); + case 116: + return jjMoveStringLiteralDfa1_0(0x3f0000000000000L, 0x0L); + case 118: + return jjMoveStringLiteralDfa1_0(0xc00000000000000L, 0x0L); + case 119: + return jjMoveStringLiteralDfa1_0(0x1000000000000000L, 0x0L); + case 123: + return jjStopAtPos(0, 77); + case 124: + jjmatchedKind = 104; + return jjMoveStringLiteralDfa1_0(0x0L, 0x2000080000000L); + case 125: + return jjStopAtPos(0, 78); + case 126: + return jjStopAtPos(0, 88); + default: + return jjMoveNfa_0(1, 0); + } + } + + private int jjMoveStringLiteralDfa1_0(long active0, long active1) { + try { + curChar = input_stream.readChar(); + } + catch (java.io.IOException e) { + jjStopStringLiteralDfa_0(0, active0, active1); + return 1; + } + switch (curChar) { + case 38: + if ((active1 & 0x100000000L) != 0L) + return jjStopAtPos(1, 96); + break; + case 42: + if ((active0 & 0x4L) != 0L) + return jjStartNfaWithStates_0(1, 2, 46); + break; + case 43: + if ((active1 & 0x200000000L) != 0L) + return jjStopAtPos(1, 97); + break; + case 45: + if ((active1 & 0x400000000L) != 0L) + return jjStopAtPos(1, 98); + break; + case 46: + return jjMoveStringLiteralDfa2_0(active0, 0L, active1, 0x80000000000000L); + case 60: + if ((active1 & 0x80000000000L) != 0L) { + jjmatchedKind = 107; + jjmatchedPos = 1; + } + return jjMoveStringLiteralDfa2_0(active0, 0L, active1, 0x10000000000000L); + case 61: + if ((active1 & 0x8000000L) != 0L) + return jjStopAtPos(1, 91); + else if ((active1 & 0x10000000L) != 0L) + return jjStopAtPos(1, 92); + else if ((active1 & 0x20000000L) != 0L) + return jjStopAtPos(1, 93); + else if ((active1 & 0x40000000L) != 0L) + return jjStopAtPos(1, 94); + else if ((active1 & 0x100000000000L) != 0L) + return jjStopAtPos(1, 108); + else if ((active1 & 0x200000000000L) != 0L) + return jjStopAtPos(1, 109); + else if ((active1 & 0x400000000000L) != 0L) + return jjStopAtPos(1, 110); + else if ((active1 & 0x800000000000L) != 0L) + return jjStopAtPos(1, 111); + else if ((active1 & 0x1000000000000L) != 0L) + return jjStopAtPos(1, 112); + else if ((active1 & 0x2000000000000L) != 0L) + return jjStopAtPos(1, 113); + else if ((active1 & 0x4000000000000L) != 0L) + return jjStopAtPos(1, 114); + else if ((active1 & 0x8000000000000L) != 0L) + return jjStopAtPos(1, 115); + break; + case 62: + if ((active1 & 0x200000000000000L) != 0L) { + jjmatchedKind = 121; + jjmatchedPos = 1; + } + return jjMoveStringLiteralDfa2_0(active0, 0L, active1, 0x160000000000000L); + case 97: + return jjMoveStringLiteralDfa2_0(active0, 0x24002006000L, active1, 0L); + case 98: + return jjMoveStringLiteralDfa2_0(active0, 0x100L, active1, 0L); + case 101: + return jjMoveStringLiteralDfa2_0(active0, 0x208000080000L, active1, 0L); + case 102: + if ((active0 & 0x80000000L) != 0L) + return jjStartNfaWithStates_0(1, 31, 29); + break; + case 104: + return jjMoveStringLiteralDfa2_0(active0, 0x1070400000008000L, active1, 0L); + case 105: + return jjMoveStringLiteralDfa2_0(active0, 0xc000000L, active1, 0L); + case 108: + return jjMoveStringLiteralDfa2_0(active0, 0x10410000L, active1, 0L); + case 109: + return jjMoveStringLiteralDfa2_0(active0, 0x300000000L, active1, 0L); + case 110: + return jjMoveStringLiteralDfa2_0(active0, 0x1c00800000L, active1, 0L); + case 111: + if ((active0 & 0x100000L) != 0L) { + jjmatchedKind = 20; + jjmatchedPos = 1; + } + return jjMoveStringLiteralDfa2_0(active0, 0xc00002060260400L, active1, 0L); + case 114: + return jjMoveStringLiteralDfa2_0(active0, 0x3800c0000000800L, active1, 0L); + case 115: + return jjMoveStringLiteralDfa2_0(active0, 0x200L, active1, 0L); + case 116: + return jjMoveStringLiteralDfa2_0(active0, 0x1800000000000L, active1, 0L); + case 117: + return jjMoveStringLiteralDfa2_0(active0, 0x2110000000000L, active1, 0L); + case 119: + return jjMoveStringLiteralDfa2_0(active0, 0x4000000000000L, active1, 0L); + case 120: + return jjMoveStringLiteralDfa2_0(active0, 0x1000000L, active1, 0L); + case 121: + return jjMoveStringLiteralDfa2_0(active0, 0x8000000001000L, active1, 0L); + case 124: + if ((active1 & 0x80000000L) != 0L) + return jjStopAtPos(1, 95); + break; + default: + break; + } + return jjStartNfa_0(0, active0, active1); + } + + private int jjMoveStringLiteralDfa2_0(long old0, long active0, long old1, long active1) { + if (((active0 &= old0) | (active1 &= old1)) == 0L) + return jjStartNfa_0(0, old0, old1); + try { + curChar = input_stream.readChar(); + } + catch (java.io.IOException e) { + jjStopStringLiteralDfa_0(1, active0, active1); + return 2; + } + switch (curChar) { + case 46: + if ((active1 & 0x80000000000000L) != 0L) + return jjStopAtPos(2, 119); + break; + case 61: + if ((active1 & 0x10000000000000L) != 0L) + return jjStopAtPos(2, 116); + else if ((active1 & 0x20000000000000L) != 0L) + return jjStopAtPos(2, 117); + break; + case 62: + if ((active1 & 0x100000000000000L) != 0L) { + jjmatchedKind = 120; + jjmatchedPos = 2; + } + return jjMoveStringLiteralDfa3_0(active0, 0L, active1, 0x40000000000000L); + case 97: + return jjMoveStringLiteralDfa3_0(active0, 0x80800000018000L, active1, 0L); + case 98: + return jjMoveStringLiteralDfa3_0(active0, 0x100000000000L, active1, 0L); + case 99: + return jjMoveStringLiteralDfa3_0(active0, 0x20000000000L, active1, 0L); + case 101: + return jjMoveStringLiteralDfa3_0(active0, 0x800L, active1, 0L); + case 102: + return jjMoveStringLiteralDfa3_0(active0, 0x80000L, active1, 0L); + case 105: + return jjMoveStringLiteralDfa3_0(active0, 0x1414040000000000L, active1, 0L); + case 108: + return jjMoveStringLiteralDfa3_0(active0, 0x800010002000000L, active1, 0L); + case 110: + return jjMoveStringLiteralDfa3_0(active0, 0x800200c060000L, active1, 0L); + case 111: + return jjMoveStringLiteralDfa3_0(active0, 0x480010000400L, active1, 0L); + case 112: + return jjMoveStringLiteralDfa3_0(active0, 0x2000300000000L, active1, 0L); + case 114: + if ((active0 & 0x20000000L) != 0L) + return jjStartNfaWithStates_0(2, 29, 29); + return jjMoveStringLiteralDfa3_0(active0, 0x61000000000000L, active1, 0L); + case 115: + return jjMoveStringLiteralDfa3_0(active0, 0x400402300L, active1, 0L); + case 116: + if ((active0 & 0x800000000L) != 0L) { + jjmatchedKind = 35; + jjmatchedPos = 2; + } + return jjMoveStringLiteralDfa3_0(active0, 0x205041005000L, active1, 0L); + case 117: + return jjMoveStringLiteralDfa3_0(active0, 0x100000000a00000L, active1, 0L); + case 119: + if ((active0 & 0x8000000000L) != 0L) + return jjStartNfaWithStates_0(2, 39, 29); + break; + case 121: + if ((active0 & 0x200000000000000L) != 0L) + return jjStartNfaWithStates_0(2, 57, 29); + break; + default: + break; + } + return jjStartNfa_0(1, active0, active1); + } + + private int jjMoveStringLiteralDfa3_0(long old0, long active0, long old1, long active1) { + if (((active0 &= old0) | (active1 &= old1)) == 0L) + return jjStartNfa_0(1, old0, old1); + try { + curChar = input_stream.readChar(); + } + catch (java.io.IOException e) { + jjStopStringLiteralDfa_0(2, active0, active1); + return 3; + } + switch (curChar) { + case 61: + if ((active1 & 0x40000000000000L) != 0L) + return jjStopAtPos(3, 118); + break; + case 97: + return jjMoveStringLiteralDfa4_0(active0, 0x80000001c080800L, active1, 0L); + case 98: + return jjMoveStringLiteralDfa4_0(active0, 0x200000L, active1, 0L); + case 99: + return jjMoveStringLiteralDfa4_0(active0, 0x8000000004000L, active1, 0L); + case 100: + if ((active0 & 0x400000000000000L) != 0L) + return jjStartNfaWithStates_0(3, 58, 29); + break; + case 101: + if ((active0 & 0x1000L) != 0L) + return jjStartNfaWithStates_0(3, 12, 29); + else if ((active0 & 0x2000L) != 0L) + return jjStartNfaWithStates_0(3, 13, 29); + else if ((active0 & 0x400000L) != 0L) + return jjStartNfaWithStates_0(3, 22, 29); + else if ((active0 & 0x100000000000000L) != 0L) + return jjStartNfaWithStates_0(3, 56, 29); + return jjMoveStringLiteralDfa4_0(active0, 0x2001001000200L, active1, 0L); + case 103: + if ((active0 & 0x2000000000L) != 0L) + return jjStartNfaWithStates_0(3, 37, 29); + break; + case 105: + return jjMoveStringLiteralDfa4_0(active0, 0x1004000000000L, active1, 0L); + case 107: + return jjMoveStringLiteralDfa4_0(active0, 0x20000000000L, active1, 0L); + case 108: + if ((active0 & 0x10000000000L) != 0L) + return jjStartNfaWithStates_0(3, 40, 29); + return jjMoveStringLiteralDfa4_0(active0, 0x1000100100000400L, active1, 0L); + case 109: + if ((active0 & 0x800000L) != 0L) + return jjStartNfaWithStates_0(3, 23, 29); + break; + case 110: + return jjMoveStringLiteralDfa4_0(active0, 0x80000000000000L, active1, 0L); + case 111: + if ((active0 & 0x40000000L) != 0L) + return jjStartNfaWithStates_0(3, 30, 29); + return jjMoveStringLiteralDfa4_0(active0, 0x60000200000000L, active1, 0L); + case 114: + if ((active0 & 0x8000L) != 0L) + return jjStartNfaWithStates_0(3, 15, 29); + return jjMoveStringLiteralDfa4_0(active0, 0x400000000000L, active1, 0L); + case 115: + if ((active0 & 0x10000000000000L) != 0L) + return jjStartNfaWithStates_0(3, 52, 29); + return jjMoveStringLiteralDfa4_0(active0, 0x2030000L, active1, 0L); + case 116: + return jjMoveStringLiteralDfa4_0(active0, 0x4880400040100L, active1, 0L); + case 117: + return jjMoveStringLiteralDfa4_0(active0, 0x200000000000L, active1, 0L); + case 118: + return jjMoveStringLiteralDfa4_0(active0, 0x40000000000L, active1, 0L); + default: + break; + } + return jjStartNfa_0(2, active0, active1); + } + + private int jjMoveStringLiteralDfa4_0(long old0, long active0, long old1, long active1) { + if (((active0 &= old0) | (active1 &= old1)) == 0L) + return jjStartNfa_0(2, old0, old1); + try { + curChar = input_stream.readChar(); + } + catch (java.io.IOException e) { + jjStopStringLiteralDfa_0(3, active0, 0L); + return 4; + } + switch (curChar) { + case 97: + return jjMoveStringLiteralDfa5_0(active0, 0x60400000000L); + case 99: + return jjMoveStringLiteralDfa5_0(active0, 0x5000000000000L); + case 101: + if ((active0 & 0x2000000L) != 0L) + return jjStartNfaWithStates_0(4, 25, 29); + else if ((active0 & 0x1000000000000000L) != 0L) + return jjStartNfaWithStates_0(4, 60, 29); + return jjMoveStringLiteralDfa5_0(active0, 0x80100000400L); + case 104: + if ((active0 & 0x4000L) != 0L) + return jjStartNfaWithStates_0(4, 14, 29); + return jjMoveStringLiteralDfa5_0(active0, 0x8000000000000L); + case 105: + return jjMoveStringLiteralDfa5_0(active0, 0x900000040000L); + case 107: + if ((active0 & 0x800L) != 0L) + return jjStartNfaWithStates_0(4, 11, 29); + break; + case 108: + if ((active0 & 0x4000000L) != 0L) { + jjmatchedKind = 26; + jjmatchedPos = 4; + } + return jjMoveStringLiteralDfa5_0(active0, 0x8200000L); + case 110: + return jjMoveStringLiteralDfa5_0(active0, 0x1000000L); + case 114: + if ((active0 & 0x2000000000000L) != 0L) + return jjStartNfaWithStates_0(4, 49, 29); + return jjMoveStringLiteralDfa5_0(active0, 0x201200000300L); + case 115: + if ((active0 & 0x10000L) != 0L) + return jjStartNfaWithStates_0(4, 16, 29); + return jjMoveStringLiteralDfa5_0(active0, 0x80000000000000L); + case 116: + if ((active0 & 0x20000L) != 0L) + return jjStartNfaWithStates_0(4, 17, 29); + else if ((active0 & 0x10000000L) != 0L) + return jjStartNfaWithStates_0(4, 28, 29); + else if ((active0 & 0x400000000000L) != 0L) + return jjStartNfaWithStates_0(4, 46, 29); + return jjMoveStringLiteralDfa5_0(active0, 0x800000000000000L); + case 117: + return jjMoveStringLiteralDfa5_0(active0, 0x80000L); + case 118: + return jjMoveStringLiteralDfa5_0(active0, 0x4000000000L); + case 119: + if ((active0 & 0x20000000000000L) != 0L) { + jjmatchedKind = 53; + jjmatchedPos = 4; + } + return jjMoveStringLiteralDfa5_0(active0, 0x40000000000000L); + default: + break; + } + return jjStartNfa_0(3, active0, 0L); + } + + private int jjMoveStringLiteralDfa5_0(long old0, long active0) { + if (((active0 &= old0)) == 0L) + return jjStartNfa_0(3, old0, 0L); + try { + curChar = input_stream.readChar(); + } + catch (java.io.IOException e) { + jjStopStringLiteralDfa_0(4, active0, 0L); + return 5; + } + switch (curChar) { + case 97: + return jjMoveStringLiteralDfa6_0(active0, 0x500L); + case 99: + if ((active0 & 0x100000000000L) != 0L) + return jjStartNfaWithStates_0(5, 44, 29); + else if ((active0 & 0x800000000000L) != 0L) + return jjStartNfaWithStates_0(5, 47, 29); + return jjMoveStringLiteralDfa6_0(active0, 0x80000000000L); + case 100: + return jjMoveStringLiteralDfa6_0(active0, 0x1000000L); + case 101: + if ((active0 & 0x200000L) != 0L) + return jjStartNfaWithStates_0(5, 21, 29); + else if ((active0 & 0x4000000000L) != 0L) + return jjStartNfaWithStates_0(5, 38, 29); + break; + case 102: + return jjMoveStringLiteralDfa6_0(active0, 0x1000000000L); + case 103: + return jjMoveStringLiteralDfa6_0(active0, 0x20000000000L); + case 104: + if ((active0 & 0x4000000000000L) != 0L) + return jjStartNfaWithStates_0(5, 50, 29); + break; + case 105: + return jjMoveStringLiteralDfa6_0(active0, 0x880000000000000L); + case 108: + return jjMoveStringLiteralDfa6_0(active0, 0x8080000L); + case 109: + return jjMoveStringLiteralDfa6_0(active0, 0x100000000L); + case 110: + if ((active0 & 0x200000000000L) != 0L) + return jjStartNfaWithStates_0(5, 45, 29); + return jjMoveStringLiteralDfa6_0(active0, 0x400040000L); + case 114: + return jjMoveStringLiteralDfa6_0(active0, 0x8000000000000L); + case 115: + if ((active0 & 0x40000000000000L) != 0L) + return jjStartNfaWithStates_0(5, 54, 29); + break; + case 116: + if ((active0 & 0x200L) != 0L) + return jjStartNfaWithStates_0(5, 9, 29); + else if ((active0 & 0x200000000L) != 0L) + return jjStartNfaWithStates_0(5, 33, 29); + return jjMoveStringLiteralDfa6_0(active0, 0x1040000000000L); + default: + break; + } + return jjStartNfa_0(4, active0, 0L); + } + + private int jjMoveStringLiteralDfa6_0(long old0, long active0) { + if (((active0 &= old0)) == 0L) + return jjStartNfa_0(4, old0, 0L); + try { + curChar = input_stream.readChar(); + } + catch (java.io.IOException e) { + jjStopStringLiteralDfa_0(5, active0, 0L); + return 6; + } + switch (curChar) { + case 97: + return jjMoveStringLiteralDfa7_0(active0, 0x1000000000L); + case 99: + return jjMoveStringLiteralDfa7_0(active0, 0x400000100L); + case 101: + if ((active0 & 0x20000000000L) != 0L) + return jjStartNfaWithStates_0(6, 41, 29); + else if ((active0 & 0x40000000000L) != 0L) + return jjStartNfaWithStates_0(6, 42, 29); + return jjMoveStringLiteralDfa7_0(active0, 0x80000100000000L); + case 102: + return jjMoveStringLiteralDfa7_0(active0, 0x1000000000000L); + case 108: + return jjMoveStringLiteralDfa7_0(active0, 0x800000000000000L); + case 110: + if ((active0 & 0x400L) != 0L) + return jjStartNfaWithStates_0(6, 10, 29); + break; + case 111: + return jjMoveStringLiteralDfa7_0(active0, 0x8000000000000L); + case 115: + if ((active0 & 0x1000000L) != 0L) + return jjStartNfaWithStates_0(6, 24, 29); + break; + case 116: + if ((active0 & 0x80000L) != 0L) + return jjStartNfaWithStates_0(6, 19, 29); + return jjMoveStringLiteralDfa7_0(active0, 0x80000000000L); + case 117: + return jjMoveStringLiteralDfa7_0(active0, 0x40000L); + case 121: + if ((active0 & 0x8000000L) != 0L) + return jjStartNfaWithStates_0(6, 27, 29); + break; + default: + break; + } + return jjStartNfa_0(5, active0, 0L); + } + + private int jjMoveStringLiteralDfa7_0(long old0, long active0) { + if (((active0 &= old0)) == 0L) + return jjStartNfa_0(5, old0, 0L); + try { + curChar = input_stream.readChar(); + } + catch (java.io.IOException e) { + jjStopStringLiteralDfa_0(6, active0, 0L); + return 7; + } + switch (curChar) { + case 99: + return jjMoveStringLiteralDfa8_0(active0, 0x1000000000L); + case 101: + if ((active0 & 0x40000L) != 0L) + return jjStartNfaWithStates_0(7, 18, 29); + else if ((active0 & 0x800000000000000L) != 0L) + return jjStartNfaWithStates_0(7, 59, 29); + return jjMoveStringLiteralDfa8_0(active0, 0x80400000000L); + case 110: + return jjMoveStringLiteralDfa8_0(active0, 0x88000100000000L); + case 112: + if ((active0 & 0x1000000000000L) != 0L) + return jjStartNfaWithStates_0(7, 48, 29); + break; + case 116: + if ((active0 & 0x100L) != 0L) + return jjStartNfaWithStates_0(7, 8, 29); + break; + default: + break; + } + return jjStartNfa_0(6, active0, 0L); + } + + private int jjMoveStringLiteralDfa8_0(long old0, long active0) { + if (((active0 &= old0)) == 0L) + return jjStartNfa_0(6, old0, 0L); + try { + curChar = input_stream.readChar(); + } + catch (java.io.IOException e) { + jjStopStringLiteralDfa_0(7, active0, 0L); + return 8; + } + switch (curChar) { + case 100: + if ((active0 & 0x80000000000L) != 0L) + return jjStartNfaWithStates_0(8, 43, 29); + break; + case 101: + if ((active0 & 0x1000000000L) != 0L) + return jjStartNfaWithStates_0(8, 36, 29); + break; + case 105: + return jjMoveStringLiteralDfa9_0(active0, 0x8000000000000L); + case 111: + return jjMoveStringLiteralDfa9_0(active0, 0x400000000L); + case 116: + if ((active0 & 0x80000000000000L) != 0L) + return jjStartNfaWithStates_0(8, 55, 29); + return jjMoveStringLiteralDfa9_0(active0, 0x100000000L); + default: + break; + } + return jjStartNfa_0(7, active0, 0L); + } + + private int jjMoveStringLiteralDfa9_0(long old0, long active0) { + if (((active0 &= old0)) == 0L) + return jjStartNfa_0(7, old0, 0L); + try { + curChar = input_stream.readChar(); + } + catch (java.io.IOException e) { + jjStopStringLiteralDfa_0(8, active0, 0L); + return 9; + } + switch (curChar) { + case 102: + if ((active0 & 0x400000000L) != 0L) + return jjStartNfaWithStates_0(9, 34, 29); + break; + case 115: + if ((active0 & 0x100000000L) != 0L) + return jjStartNfaWithStates_0(9, 32, 29); + break; + case 122: + return jjMoveStringLiteralDfa10_0(active0, 0x8000000000000L); + default: + break; + } + return jjStartNfa_0(8, active0, 0L); + } + + private int jjMoveStringLiteralDfa10_0(long old0, long active0) { + if (((active0 &= old0)) == 0L) + return jjStartNfa_0(8, old0, 0L); + try { + curChar = input_stream.readChar(); + } + catch (java.io.IOException e) { + jjStopStringLiteralDfa_0(9, active0, 0L); + return 10; + } + switch (curChar) { + case 101: + return jjMoveStringLiteralDfa11_0(active0, 0x8000000000000L); + default: + break; + } + return jjStartNfa_0(9, active0, 0L); + } + + private int jjMoveStringLiteralDfa11_0(long old0, long active0) { + if (((active0 &= old0)) == 0L) + return jjStartNfa_0(9, old0, 0L); + try { + curChar = input_stream.readChar(); + } + catch (java.io.IOException e) { + jjStopStringLiteralDfa_0(10, active0, 0L); + return 11; + } + switch (curChar) { + case 100: + if ((active0 & 0x8000000000000L) != 0L) + return jjStartNfaWithStates_0(11, 51, 29); + break; + default: + break; + } + return jjStartNfa_0(10, active0, 0L); + } + + private void jjCheckNAdd(int state) { + if (jjrounds[state] != jjround) { + jjstateSet[jjnewStateCnt++] = state; + jjrounds[state] = jjround; + } + } + + private void jjAddStates(int start, int end) { + do { + jjstateSet[jjnewStateCnt++] = jjnextStates[start]; + } while (start++ != end); + } + + private void jjCheckNAddTwoStates(int state1, int state2) { + jjCheckNAdd(state1); + jjCheckNAdd(state2); + } + + private void jjCheckNAddStates(int start, int end) { + do { + jjCheckNAdd(jjnextStates[start]); + } while (start++ != end); + } + + private void jjCheckNAddStates(int start) { + jjCheckNAdd(jjnextStates[start]); + jjCheckNAdd(jjnextStates[start + 1]); + } + + static final long[] jjbitVec0 = { + 0xfffffffffffffffeL, 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL + }; + static final long[] jjbitVec2 = { + 0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL + }; + static final long[] jjbitVec3 = { + 0xfff0000000200002L, 0xffffffffffffdfffL, 0xfffff00f7fffffffL, 0x12000000007fffffL + }; + static final long[] jjbitVec4 = { + 0x0L, 0x0L, 0x420043c00000000L, 0xff7fffffff7fffffL + }; + static final long[] jjbitVec5 = { + 0xffffcffffffffL, 0xffffffffffff0000L, 0xf9ff3fffffffffffL, 0x401f00030003L + }; + static final long[] jjbitVec6 = { + 0x0L, 0x400000000000000L, 0xfffffffbffffd740L, 0xffffffcff7fffL + }; + static final long[] jjbitVec7 = { + 0xffffffffffffffffL, 0xffffffffffffffffL, 0xfffffffffffff003L, 0x33fffffffff199fL + }; + static final long[] jjbitVec8 = { + 0xfffe000000000000L, 0xfffffffe027fffffL, 0xffL, 0x707ffffff0000L + }; + static final long[] jjbitVec9 = { + 0x7fffffe00000000L, 0xfffe0000000007ffL, 0xffffffffffffffffL, 0x1c000060002fffffL + }; + static final long[] jjbitVec10 = { + 0x1ffffffd0000L, 0x0L, 0x3fffffffffL, 0x0L + }; + static final long[] jjbitVec11 = { + 0x23ffffffffffffe0L, 0x3ff010000L, 0x3c5fdfffff99fe0L, 0xf0003b0000000L + }; + static final long[] jjbitVec12 = { + 0x36dfdfffff987e0L, 0x1c00005e000000L, 0x23edfdfffffbafe0L, 0x100010000L + }; + static final long[] jjbitVec13 = { + 0x23cdfdfffff99fe0L, 0x3b0000000L, 0x3bfc718d63dc7e0L, 0x0L + }; + static final long[] jjbitVec14 = { + 0x3effdfffffddfe0L, 0x300000000L, 0x3effdfffffddfe0L, 0x340000000L + }; + static final long[] jjbitVec15 = { + 0x3fffdfffffddfe0L, 0x300000000L, 0x2ffbfffffc7fffe0L, 0x7fL + }; + static final long[] jjbitVec16 = { + 0x800dfffffffffffeL, 0x7fL, 0x200decaefef02596L, 0x3000005fL + }; + static final long[] jjbitVec17 = { + 0x1L, 0x7fffffffeffL, 0xf00L, 0x0L + }; + static final long[] jjbitVec18 = { + 0x6fbffffffffL, 0x3f0000L, 0xffffffff00000000L, 0x7fffffffff003fL + }; + static final long[] jjbitVec19 = { + 0xffffffffffffffffL, 0xffffffff83ffffffL, 0xffffff07ffffffffL, 0x3ffffffffffffffL + }; + static final long[] jjbitVec20 = { + 0xffffffffffffff7fL, 0xffffffff3d7f3d7fL, 0x7f3d7fffffff3d7fL, 0xffff7fffff7f7f3dL + }; + static final long[] jjbitVec21 = { + 0xffffffff7f3d7fffL, 0x7ffff7fL, 0xffffffff00000000L, 0x1fffffffffffffL + }; + static final long[] jjbitVec22 = { + 0xffffffffffffffffL, 0x7f9fffffffffffL, 0xffffffff07fffffeL, 0x7ffffffffffL + }; + static final long[] jjbitVec23 = { + 0x0L, 0x0L, 0xfffffffffffffL, 0x8000000L + }; + static final long[] jjbitVec24 = { + 0xffffffff00000000L, 0xffffffffffffffL, 0x1ffffffffffL, 0x0L + }; + static final long[] jjbitVec25 = { + 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffff0fffffffL, 0x3ffffffffffffffL + }; + static final long[] jjbitVec26 = { + 0xffffffff3f3fffffL, 0x3fffffffaaff3f3fL, 0x5fdfffffffffffffL, 0x1fdc1fff0fcf1fdcL + }; + static final long[] jjbitVec27 = { + 0x8000000000000000L, 0x8000000000000001L, 0xffff00000000L, 0x0L + }; + static final long[] jjbitVec28 = { + 0x3fbbd503e2ffc84L, 0xffffffff00000000L, 0xfL, 0x0L + }; + static final long[] jjbitVec29 = { + 0x73e03fe000000e0L, 0xfffffffffffffffeL, 0xfffffffe601fffffL, 0x7fffffffffffffffL + }; + static final long[] jjbitVec30 = { + 0xfffe1fffffffffe0L, 0xffffffffffffffffL, 0xffffff00007fffL, 0x0L + }; + static final long[] jjbitVec31 = { + 0xffffffffffffffffL, 0xffffffffffffffffL, 0x3fffffffffffffL, 0x0L + }; + static final long[] jjbitVec32 = { + 0xffffffffffffffffL, 0xffffffffffffffffL, 0x3fffffffffL, 0x0L + }; + static final long[] jjbitVec33 = { + 0xffffffffffffffffL, 0xffffffffffffffffL, 0x1fffL, 0x0L + }; + static final long[] jjbitVec34 = { + 0xffffffffffffffffL, 0xffffffffffffffffL, 0xfffffffffL, 0x0L + }; + static final long[] jjbitVec35 = { + 0x3fffffffffffL, 0x0L, 0x0L, 0x0L + }; + static final long[] jjbitVec36 = { + 0x5f7ffdffa0f8007fL, 0xffffffffffffffdbL, 0x3ffffffffffffL, 0xfffffffffff80000L + }; + static final long[] jjbitVec37 = { + 0x3fffffffffffffffL, 0xffffffffffff0000L, 0xfffffffffffcffffL, 0xfff0000000000ffL + }; + static final long[] jjbitVec38 = { + 0x18000000000000L, 0xffd702000000e000L, 0xffffffffffffffffL, 0x1fffffffffffffffL + }; + static final long[] jjbitVec39 = { + 0x87fffffe00000010L, 0xffffffe007fffffeL, 0x7fffffffffffffffL, 0x631cfcfcfcL + }; + static final long[] jjbitVec40 = { + 0x0L, 0x0L, 0x420043cffffffffL, 0xff7fffffff7fffffL + }; + static final long[] jjbitVec41 = { + 0xffffffffffffffffL, 0x400000700007fffL, 0xfffffffbffffd740L, 0xffffffcff7fffL + }; + static final long[] jjbitVec42 = { + 0xffffffffffffffffL, 0xffffffffffffffffL, 0xfffffffffffff07bL, 0x33fffffffff199fL + }; + static final long[] jjbitVec43 = { + 0xfffe000000000000L, 0xfffffffe027fffffL, 0xbbfffffbfffe00ffL, 0x707ffffff0016L + }; + static final long[] jjbitVec44 = { + 0x7fffffe00000000L, 0xffff03ff003fffffL, 0xffffffffffffffffL, 0x1fff3dff9fefffffL + }; + static final long[] jjbitVec45 = { + 0xffff1fffffff8000L, 0x7ffL, 0x1ffffffffffffL, 0x0L + }; + static final long[] jjbitVec46 = { + 0xf3ffffffffffffeeL, 0xffcfff1f3fffL, 0xd3c5fdfffff99feeL, 0xfffcfb080399fL + }; + static final long[] jjbitVec47 = { + 0xd36dfdfffff987e4L, 0x1fffc05e003987L, 0xf3edfdfffffbafeeL, 0xffc100013bbfL + }; + static final long[] jjbitVec48 = { + 0xf3cdfdfffff99feeL, 0xffc3b0c0398fL, 0xc3bfc718d63dc7ecL, 0xff8000803dc7L + }; + static final long[] jjbitVec49 = { + 0xc3effdfffffddfeeL, 0xffc300603ddfL, 0xc3effdfffffddfecL, 0xffc340603ddfL + }; + static final long[] jjbitVec50 = { + 0xc3fffdfffffddfecL, 0xffc300803dcfL, 0x2ffbfffffc7fffecL, 0xc0000ff5f847fL + }; + static final long[] jjbitVec51 = { + 0x87fffffffffffffeL, 0x3ff7fffL, 0x3bffecaefef02596L, 0x33ff3f5fL + }; + static final long[] jjbitVec52 = { + 0xc2a003ff03000001L, 0xfffe07fffffffeffL, 0x1ffffffffeff0fdfL, 0x40L + }; + static final long[] jjbitVec53 = { + 0x3c7f6fbffffffffL, 0x3ff03ffL, 0xffffffff00000000L, 0x7fffffffff003fL + }; + static final long[] jjbitVec54 = { + 0xffffffff7f3d7fffL, 0x3fe0007ffff7fL, 0xffffffff00000000L, 0x1fffffffffffffL + }; + static final long[] jjbitVec55 = { + 0x0L, 0x0L, 0xffffffffffffffffL, 0x3ff080fffffL + }; + static final long[] jjbitVec56 = { + 0xffffffff03ff7800L, 0xffffffffffffffL, 0x3ffffffffffL, 0x0L + }; + static final long[] jjbitVec57 = { + 0x80007c000000f000L, 0x8000fc0000000001L, 0xffff00000000L, 0x21fff0000L + }; + static final long[] jjbitVec58 = { + 0x73efffe000000e0L, 0xfffffffffffffffeL, 0xfffffffe661fffffL, 0x7fffffffffffffffL + }; + static final long[] jjbitVec59 = { + 0x5f7ffdffe0f8007fL, 0xffffffffffffffdbL, 0x3ffffffffffffL, 0xfffffffffff80000L + }; + static final long[] jjbitVec60 = { + 0x18000f00000000L, 0xffd702000000e000L, 0xffffffffffffffffL, 0x9fffffffffffffffL + }; + static final long[] jjbitVec61 = { + 0x87fffffe03ff0010L, 0xffffffe007fffffeL, 0x7fffffffffffffffL, 0xe0000631cfcfcfcL + }; + + private int jjMoveNfa_0(int startState, int curPos) { + int[] nextStates; + int startsAt = 0; + jjnewStateCnt = 71; + int i = 1; + jjstateSet[0] = startState; + int j, kind = 0x7fffffff; + for (; ;) { + if (++jjround == 0x7fffffff) + ReInitRounds(); + if (curChar < 64) { + long l = 1L << curChar; + MatchLoop: + do { + switch (jjstateSet[--i]) { + case 1: + if ((0x3ff000000000000L & l) != 0L) + jjCheckNAddStates(0, 6); + else if ((0x100003600L & l) != 0L) { + if (kind > 3) + kind = 3; + jjCheckNAdd(0); + } else if (curChar == 47) + jjAddStates(7, 8); + else if (curChar == 36) { + if (kind > 72) + kind = 72; + jjCheckNAdd(29); + } else if (curChar == 34) + jjCheckNAddStates(9, 11); + else if (curChar == 39) + jjAddStates(12, 13); + else if (curChar == 46) + jjCheckNAdd(5); + if ((0x3fe000000000000L & l) != 0L) { + if (kind > 61) + kind = 61; + jjCheckNAddTwoStates(2, 3); + } else if (curChar == 48) { + if (kind > 61) + kind = 61; + jjCheckNAddStates(14, 18); + } + break; + case 48: + if (curChar == 47) { + if (kind > 4) + kind = 4; + jjCheckNAddStates(19, 21); + } else if (curChar == 42) + jjstateSet[jjnewStateCnt++] = 46; + break; + case 0: + if ((0x100003600L & l) == 0L) + break; + if (kind > 3) + kind = 3; + jjCheckNAdd(0); + break; + case 2: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 61) + kind = 61; + jjCheckNAddTwoStates(2, 3); + break; + case 4: + if (curChar == 46) + jjCheckNAdd(5); + break; + case 5: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 65) + kind = 65; + jjCheckNAddStates(22, 24); + break; + case 7: + if ((0x280000000000L & l) != 0L) + jjCheckNAdd(8); + break; + case 8: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 65) + kind = 65; + jjCheckNAddTwoStates(8, 9); + break; + case 10: + if (curChar == 39) + jjAddStates(12, 13); + break; + case 11: + if ((0xffffff7fffffdbffL & l) != 0L) + jjCheckNAdd(12); + break; + case 12: + if (curChar == 39 && kind > 70) + kind = 70; + break; + case 14: + if ((0x8400000000L & l) != 0L) + jjCheckNAdd(12); + break; + case 15: + if ((0xff000000000000L & l) != 0L) + jjCheckNAddTwoStates(16, 12); + break; + case 16: + if ((0xff000000000000L & l) != 0L) + jjCheckNAdd(12); + break; + case 17: + if ((0xf000000000000L & l) != 0L) + jjstateSet[jjnewStateCnt++] = 18; + break; + case 18: + if ((0xff000000000000L & l) != 0L) + jjCheckNAdd(16); + break; + case 19: + if (curChar == 34) + jjCheckNAddStates(9, 11); + break; + case 20: + if ((0xfffffffbffffdbffL & l) != 0L) + jjCheckNAddStates(9, 11); + break; + case 22: + if ((0x8400000000L & l) != 0L) + jjCheckNAddStates(9, 11); + break; + case 23: + if (curChar == 34 && kind > 71) + kind = 71; + break; + case 24: + if ((0xff000000000000L & l) != 0L) + jjCheckNAddStates(25, 28); + break; + case 25: + if ((0xff000000000000L & l) != 0L) + jjCheckNAddStates(9, 11); + break; + case 26: + if ((0xf000000000000L & l) != 0L) + jjstateSet[jjnewStateCnt++] = 27; + break; + case 27: + if ((0xff000000000000L & l) != 0L) + jjCheckNAdd(25); + break; + case 28: + if (curChar != 36) + break; + if (kind > 72) + kind = 72; + jjCheckNAdd(29); + break; + case 29: + if ((0x3ff00100fffc1ffL & l) == 0L) + break; + if (kind > 72) + kind = 72; + jjCheckNAdd(29); + break; + case 30: + if ((0x3ff000000000000L & l) != 0L) + jjCheckNAddStates(0, 6); + break; + case 31: + if ((0x3ff000000000000L & l) != 0L) + jjCheckNAddStates(29, 31); + break; + case 33: + if ((0x280000000000L & l) != 0L) + jjCheckNAdd(34); + break; + case 34: + if ((0x3ff000000000000L & l) != 0L) + jjCheckNAddTwoStates(34, 9); + break; + case 35: + if ((0x3ff000000000000L & l) != 0L) + jjCheckNAddTwoStates(35, 36); + break; + case 37: + if ((0x280000000000L & l) != 0L) + jjCheckNAdd(38); + break; + case 38: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 65) + kind = 65; + jjCheckNAddTwoStates(38, 9); + break; + case 39: + if ((0x3ff000000000000L & l) != 0L) + jjCheckNAddTwoStates(39, 40); + break; + case 40: + if (curChar != 46) + break; + if (kind > 65) + kind = 65; + jjCheckNAddStates(32, 34); + break; + case 41: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 65) + kind = 65; + jjCheckNAddStates(32, 34); + break; + case 43: + if ((0x280000000000L & l) != 0L) + jjCheckNAdd(44); + break; + case 44: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 65) + kind = 65; + jjCheckNAddTwoStates(44, 9); + break; + case 45: + if (curChar == 47) + jjAddStates(7, 8); + break; + case 46: + if (curChar == 42) + jjstateSet[jjnewStateCnt++] = 47; + break; + case 47: + if ((0xffff7fffffffffffL & l) != 0L && kind > 1) + kind = 1; + break; + case 49: + if (curChar != 47) + break; + if (kind > 4) + kind = 4; + jjCheckNAddStates(19, 21); + break; + case 50: + if ((0xffffffffffffdbffL & l) == 0L) + break; + if (kind > 4) + kind = 4; + jjCheckNAddStates(19, 21); + break; + case 51: + if ((0x2400L & l) != 0L && kind > 4) + kind = 4; + break; + case 52: + if (curChar == 10 && kind > 4) + kind = 4; + break; + case 53: + if (curChar == 13) + jjstateSet[jjnewStateCnt++] = 52; + break; + case 54: + if (curChar != 48) + break; + if (kind > 61) + kind = 61; + jjCheckNAddStates(14, 18); + break; + case 56: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 61) + kind = 61; + jjCheckNAddTwoStates(56, 3); + break; + case 57: + if ((0xff000000000000L & l) == 0L) + break; + if (kind > 61) + kind = 61; + jjCheckNAddTwoStates(57, 3); + break; + case 59: + if ((0x3ff000000000000L & l) != 0L) + jjAddStates(35, 36); + break; + case 60: + if (curChar == 46) + jjCheckNAdd(61); + break; + case 61: + if ((0x3ff000000000000L & l) != 0L) + jjCheckNAddTwoStates(61, 62); + break; + case 63: + if ((0x280000000000L & l) != 0L) + jjCheckNAdd(64); + break; + case 64: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 65) + kind = 65; + jjCheckNAddTwoStates(64, 9); + break; + case 66: + if ((0x3ff000000000000L & l) != 0L) + jjCheckNAddStates(37, 39); + break; + case 67: + if (curChar == 46) + jjCheckNAdd(68); + break; + case 69: + if ((0x280000000000L & l) != 0L) + jjCheckNAdd(70); + break; + case 70: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 65) + kind = 65; + jjCheckNAddTwoStates(70, 9); + break; + default: + break; + } + } while (i != startsAt); + } else if (curChar < 128) { + long l = 1L << (curChar & 077); + MatchLoop: + do { + switch (jjstateSet[--i]) { + case 1: + if ((0x7fffffe87fffffeL & l) == 0L) + break; + if (kind > 72) + kind = 72; + jjCheckNAdd(29); + break; + case 3: + if ((0x100000001000L & l) != 0L && kind > 61) + kind = 61; + break; + case 6: + if ((0x2000000020L & l) != 0L) + jjAddStates(40, 41); + break; + case 9: + if ((0x5000000050L & l) != 0L && kind > 65) + kind = 65; + break; + case 11: + if ((0xffffffffefffffffL & l) != 0L) + jjCheckNAdd(12); + break; + case 13: + if (curChar == 92) + jjAddStates(42, 44); + break; + case 14: + if ((0x14404410000000L & l) != 0L) + jjCheckNAdd(12); + break; + case 20: + if ((0xffffffffefffffffL & l) != 0L) + jjCheckNAddStates(9, 11); + break; + case 21: + if (curChar == 92) + jjAddStates(45, 47); + break; + case 22: + if ((0x14404410000000L & l) != 0L) + jjCheckNAddStates(9, 11); + break; + case 29: + if ((0x87fffffe87fffffeL & l) == 0L) + break; + if (kind > 72) + kind = 72; + jjCheckNAdd(29); + break; + case 32: + if ((0x2000000020L & l) != 0L) + jjAddStates(48, 49); + break; + case 36: + if ((0x2000000020L & l) != 0L) + jjAddStates(50, 51); + break; + case 42: + if ((0x2000000020L & l) != 0L) + jjAddStates(52, 53); + break; + case 47: + if (kind > 1) + kind = 1; + break; + case 50: + if (kind > 4) + kind = 4; + jjAddStates(19, 21); + break; + case 55: + if ((0x100000001000000L & l) != 0L) + jjCheckNAdd(56); + break; + case 56: + if ((0x7e0000007eL & l) == 0L) + break; + if (kind > 61) + kind = 61; + jjCheckNAddTwoStates(56, 3); + break; + case 58: + if ((0x100000001000000L & l) != 0L) + jjCheckNAddTwoStates(59, 60); + break; + case 59: + if ((0x7e0000007eL & l) != 0L) + jjCheckNAddTwoStates(59, 60); + break; + case 61: + if ((0x7e0000007eL & l) != 0L) + jjAddStates(54, 55); + break; + case 62: + if ((0x1000000010000L & l) != 0L) + jjAddStates(56, 57); + break; + case 65: + if ((0x100000001000000L & l) != 0L) + jjCheckNAdd(66); + break; + case 66: + if ((0x7e0000007eL & l) != 0L) + jjCheckNAddStates(37, 39); + break; + case 68: + if ((0x1000000010000L & l) != 0L) + jjAddStates(58, 59); + break; + default: + break; + } + } while (i != startsAt); + } else { + int hiByte = (int) (curChar >> 8); + int i1 = hiByte >> 6; + long l1 = 1L << (hiByte & 077); + int i2 = (curChar & 0xff) >> 6; + long l2 = 1L << (curChar & 077); + MatchLoop: + do { + switch (jjstateSet[--i]) { + case 1: + if (!jjCanMove_1(hiByte, i1, i2, l1, l2)) + break; + if (kind > 72) + kind = 72; + jjCheckNAdd(29); + break; + case 11: + if (jjCanMove_0(hiByte, i1, i2, l1, l2)) + jjstateSet[jjnewStateCnt++] = 12; + break; + case 20: + if (jjCanMove_0(hiByte, i1, i2, l1, l2)) + jjAddStates(9, 11); + break; + case 29: + if (!jjCanMove_2(hiByte, i1, i2, l1, l2)) + break; + if (kind > 72) + kind = 72; + jjCheckNAdd(29); + break; + case 47: + if (jjCanMove_0(hiByte, i1, i2, l1, l2) && kind > 1) + kind = 1; + break; + case 50: + if (!jjCanMove_0(hiByte, i1, i2, l1, l2)) + break; + if (kind > 4) + kind = 4; + jjAddStates(19, 21); + break; + default: + break; + } + } while (i != startsAt); + } + if (kind != 0x7fffffff) { + jjmatchedKind = kind; + jjmatchedPos = curPos; + kind = 0x7fffffff; + } + ++curPos; + if ((i = jjnewStateCnt) == (startsAt = 71 - (jjnewStateCnt = startsAt))) + return curPos; + try { + curChar = input_stream.readChar(); + } + catch (java.io.IOException e) { + return curPos; + } + } + } + + private int jjMoveStringLiteralDfa0_2() { + switch (curChar) { + case 42: + return jjMoveStringLiteralDfa1_2(0x40L); + default: + return 1; + } + } + + private int jjMoveStringLiteralDfa1_2(long active0) { + try { + curChar = input_stream.readChar(); + } + catch (java.io.IOException e) { + return 1; + } + switch (curChar) { + case 47: + if ((active0 & 0x40L) != 0L) + return jjStopAtPos(1, 6); + break; + default: + return 2; + } + return 2; + } + + private int jjMoveStringLiteralDfa0_1() { + switch (curChar) { + case 42: + return jjMoveStringLiteralDfa1_1(0x20L); + default: + return 1; + } + } + + private int jjMoveStringLiteralDfa1_1(long active0) { + try { + curChar = input_stream.readChar(); + } + catch (java.io.IOException e) { + return 1; + } + switch (curChar) { + case 47: + if ((active0 & 0x20L) != 0L) + return jjStopAtPos(1, 5); + break; + default: + return 2; + } + return 2; + } + + static final int[] jjnextStates = { + 31, 32, 9, 35, 36, 39, 40, 48, 49, 20, 21, 23, 11, 13, 55, 57, + 3, 58, 65, 50, 51, 53, 5, 6, 9, 20, 21, 25, 23, 31, 32, 9, + 41, 42, 9, 59, 60, 66, 67, 68, 7, 8, 14, 15, 17, 22, 24, 26, + 33, 34, 37, 38, 43, 44, 61, 62, 63, 64, 69, 70, + }; + + private static boolean jjCanMove_0(int hiByte, int i1, int i2, long l1, long l2) { + switch (hiByte) { + case 0: + return ((jjbitVec2[i2] & l2) != 0L); + default: + if ((jjbitVec0[i1] & l1) != 0L) + return true; + return false; + } + } + + private static boolean jjCanMove_1(int hiByte, int i1, int i2, long l1, long l2) { + switch (hiByte) { + case 0: + return ((jjbitVec4[i2] & l2) != 0L); + case 2: + return ((jjbitVec5[i2] & l2) != 0L); + case 3: + return ((jjbitVec6[i2] & l2) != 0L); + case 4: + return ((jjbitVec7[i2] & l2) != 0L); + case 5: + return ((jjbitVec8[i2] & l2) != 0L); + case 6: + return ((jjbitVec9[i2] & l2) != 0L); + case 7: + return ((jjbitVec10[i2] & l2) != 0L); + case 9: + return ((jjbitVec11[i2] & l2) != 0L); + case 10: + return ((jjbitVec12[i2] & l2) != 0L); + case 11: + return ((jjbitVec13[i2] & l2) != 0L); + case 12: + return ((jjbitVec14[i2] & l2) != 0L); + case 13: + return ((jjbitVec15[i2] & l2) != 0L); + case 14: + return ((jjbitVec16[i2] & l2) != 0L); + case 15: + return ((jjbitVec17[i2] & l2) != 0L); + case 16: + return ((jjbitVec18[i2] & l2) != 0L); + case 17: + return ((jjbitVec19[i2] & l2) != 0L); + case 18: + return ((jjbitVec20[i2] & l2) != 0L); + case 19: + return ((jjbitVec21[i2] & l2) != 0L); + case 20: + return ((jjbitVec0[i2] & l2) != 0L); + case 22: + return ((jjbitVec22[i2] & l2) != 0L); + case 23: + return ((jjbitVec23[i2] & l2) != 0L); + case 24: + return ((jjbitVec24[i2] & l2) != 0L); + case 30: + return ((jjbitVec25[i2] & l2) != 0L); + case 31: + return ((jjbitVec26[i2] & l2) != 0L); + case 32: + return ((jjbitVec27[i2] & l2) != 0L); + case 33: + return ((jjbitVec28[i2] & l2) != 0L); + case 48: + return ((jjbitVec29[i2] & l2) != 0L); + case 49: + return ((jjbitVec30[i2] & l2) != 0L); + case 77: + return ((jjbitVec31[i2] & l2) != 0L); + case 159: + return ((jjbitVec32[i2] & l2) != 0L); + case 164: + return ((jjbitVec33[i2] & l2) != 0L); + case 215: + return ((jjbitVec34[i2] & l2) != 0L); + case 250: + return ((jjbitVec35[i2] & l2) != 0L); + case 251: + return ((jjbitVec36[i2] & l2) != 0L); + case 253: + return ((jjbitVec37[i2] & l2) != 0L); + case 254: + return ((jjbitVec38[i2] & l2) != 0L); + case 255: + return ((jjbitVec39[i2] & l2) != 0L); + default: + if ((jjbitVec3[i1] & l1) != 0L) + return true; + return false; + } + } + + private static boolean jjCanMove_2(int hiByte, int i1, int i2, long l1, long l2) { + switch (hiByte) { + case 0: + return ((jjbitVec40[i2] & l2) != 0L); + case 2: + return ((jjbitVec5[i2] & l2) != 0L); + case 3: + return ((jjbitVec41[i2] & l2) != 0L); + case 4: + return ((jjbitVec42[i2] & l2) != 0L); + case 5: + return ((jjbitVec43[i2] & l2) != 0L); + case 6: + return ((jjbitVec44[i2] & l2) != 0L); + case 7: + return ((jjbitVec45[i2] & l2) != 0L); + case 9: + return ((jjbitVec46[i2] & l2) != 0L); + case 10: + return ((jjbitVec47[i2] & l2) != 0L); + case 11: + return ((jjbitVec48[i2] & l2) != 0L); + case 12: + return ((jjbitVec49[i2] & l2) != 0L); + case 13: + return ((jjbitVec50[i2] & l2) != 0L); + case 14: + return ((jjbitVec51[i2] & l2) != 0L); + case 15: + return ((jjbitVec52[i2] & l2) != 0L); + case 16: + return ((jjbitVec53[i2] & l2) != 0L); + case 17: + return ((jjbitVec19[i2] & l2) != 0L); + case 18: + return ((jjbitVec20[i2] & l2) != 0L); + case 19: + return ((jjbitVec54[i2] & l2) != 0L); + case 20: + return ((jjbitVec0[i2] & l2) != 0L); + case 22: + return ((jjbitVec22[i2] & l2) != 0L); + case 23: + return ((jjbitVec55[i2] & l2) != 0L); + case 24: + return ((jjbitVec56[i2] & l2) != 0L); + case 30: + return ((jjbitVec25[i2] & l2) != 0L); + case 31: + return ((jjbitVec26[i2] & l2) != 0L); + case 32: + return ((jjbitVec57[i2] & l2) != 0L); + case 33: + return ((jjbitVec28[i2] & l2) != 0L); + case 48: + return ((jjbitVec58[i2] & l2) != 0L); + case 49: + return ((jjbitVec30[i2] & l2) != 0L); + case 77: + return ((jjbitVec31[i2] & l2) != 0L); + case 159: + return ((jjbitVec32[i2] & l2) != 0L); + case 164: + return ((jjbitVec33[i2] & l2) != 0L); + case 215: + return ((jjbitVec34[i2] & l2) != 0L); + case 250: + return ((jjbitVec35[i2] & l2) != 0L); + case 251: + return ((jjbitVec59[i2] & l2) != 0L); + case 253: + return ((jjbitVec37[i2] & l2) != 0L); + case 254: + return ((jjbitVec60[i2] & l2) != 0L); + case 255: + return ((jjbitVec61[i2] & l2) != 0L); + default: + if ((jjbitVec3[i1] & l1) != 0L) + return true; + return false; + } + } + + public static final String[] jjstrLiteralImages = { + "", null, null, null, null, null, null, null, + "\141\142\163\164\162\141\143\164", "\141\163\163\145\162\164", "\142\157\157\154\145\141\156", + "\142\162\145\141\153", "\142\171\164\145", "\143\141\163\145", "\143\141\164\143\150", + "\143\150\141\162", "\143\154\141\163\163", "\143\157\156\163\164", + "\143\157\156\164\151\156\165\145", "\144\145\146\141\165\154\164", "\144\157", "\144\157\165\142\154\145", + "\145\154\163\145", "\145\156\165\155", "\145\170\164\145\156\144\163", "\146\141\154\163\145", + "\146\151\156\141\154", "\146\151\156\141\154\154\171", "\146\154\157\141\164", "\146\157\162", + "\147\157\164\157", "\151\146", "\151\155\160\154\145\155\145\156\164\163", + "\151\155\160\157\162\164", "\151\156\163\164\141\156\143\145\157\146", "\151\156\164", + "\151\156\164\145\162\146\141\143\145", "\154\157\156\147", "\156\141\164\151\166\145", "\156\145\167", + "\156\165\154\154", "\160\141\143\153\141\147\145", "\160\162\151\166\141\164\145", + "\160\162\157\164\145\143\164\145\144", "\160\165\142\154\151\143", "\162\145\164\165\162\156", + "\163\150\157\162\164", "\163\164\141\164\151\143", "\163\164\162\151\143\164\146\160", + "\163\165\160\145\162", "\163\167\151\164\143\150", + "\163\171\156\143\150\162\157\156\151\172\145\144", "\164\150\151\163", "\164\150\162\157\167", "\164\150\162\157\167\163", + "\164\162\141\156\163\151\145\156\164", "\164\162\165\145", "\164\162\171", "\166\157\151\144", + "\166\157\154\141\164\151\154\145", "\167\150\151\154\145", null, null, null, null, null, null, null, null, null, + null, null, null, null, null, "\50", "\51", "\173", "\175", "\133", "\135", "\73", + "\54", "\56", "\100", "\75", "\74", "\41", "\176", "\77", "\72", "\75\75", "\74\75", + "\76\75", "\41\75", "\174\174", "\46\46", "\53\53", "\55\55", "\53", "\55", "\52", + "\57", "\46", "\174", "\136", "\45", "\74\74", "\53\75", "\55\75", "\52\75", + "\57\75", "\46\75", "\174\75", "\136\75", "\45\75", "\74\74\75", "\76\76\75", + "\76\76\76\75", "\56\56\56", "\76\76\76", "\76\76", "\76", "\32", null,}; + public static final String[] lexStateNames = { + "DEFAULT", + "IN_FORMAL_COMMENT", + "IN_MULTI_LINE_COMMENT", + }; + public static final int[] jjnewLexState = { + -1, 1, 2, -1, -1, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + }; + static final long[] jjtoToken = { + 0x3fffffffffffff01L, 0x1ffffffffffff9c2L, + }; + static final long[] jjtoSkip = { + 0x78L, 0x0L, + }; + static final long[] jjtoSpecial = { + 0x78L, 0x0L, + }; + static final long[] jjtoMore = { + 0x86L, 0x0L, + }; + protected JavaCharStream input_stream; + private final int[] jjrounds = new int[71]; + private final int[] jjstateSet = new int[142]; + StringBuffer image; + int jjimageLen; + int lengthOfMatch; + protected char curChar; + + public JavaParserTokenManager(JavaCharStream stream) { + if (JavaCharStream.staticFlag) + throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer."); + input_stream = stream; + } + + public JavaParserTokenManager(JavaCharStream stream, int lexState) { + this(stream); + SwitchTo(lexState); + } + + public void ReInit(JavaCharStream stream) { + jjmatchedPos = jjnewStateCnt = 0; + curLexState = defaultLexState; + input_stream = stream; + ReInitRounds(); + } + + private void ReInitRounds() { + int i; + jjround = 0x80000001; + for (i = 71; i-- > 0;) + jjrounds[i] = 0x80000000; + } + + public void ReInit(JavaCharStream stream, int lexState) { + ReInit(stream); + SwitchTo(lexState); + } + + public void SwitchTo(int lexState) { + if (lexState >= 3 || lexState < 0) + throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE); + else + curLexState = lexState; + } + + protected Token jjFillToken() { + Token t = Token.newToken(jjmatchedKind); + t.kind = jjmatchedKind; + String im = jjstrLiteralImages[jjmatchedKind]; + t.image = (im == null) ? input_stream.GetImage() : im; + t.beginLine = input_stream.getBeginLine(); + t.beginColumn = input_stream.getBeginColumn(); + t.endLine = input_stream.getEndLine(); + t.endColumn = input_stream.getEndColumn(); + return t; + } + + int curLexState = 0; + int defaultLexState = 0; + int jjnewStateCnt; + int jjround; + int jjmatchedPos; + int jjmatchedKind; + + public Token getNextToken() { + int kind; + Token specialToken = null; + Token matchedToken; + int curPos = 0; + + EOFLoop: + for (; ;) { + try { + curChar = input_stream.BeginToken(); + } + catch (java.io.IOException e) { + jjmatchedKind = 0; + matchedToken = jjFillToken(); + matchedToken.specialToken = specialToken; + return matchedToken; + } + image = null; + jjimageLen = 0; + + for (; ;) { + switch (curLexState) { + case 0: + jjmatchedKind = 0x7fffffff; + jjmatchedPos = 0; + curPos = jjMoveStringLiteralDfa0_0(); + if (jjmatchedPos == 0 && jjmatchedKind > 124) { + jjmatchedKind = 124; + } + break; + case 1: + jjmatchedKind = 0x7fffffff; + jjmatchedPos = 0; + curPos = jjMoveStringLiteralDfa0_1(); + if (jjmatchedPos == 0 && jjmatchedKind > 7) { + jjmatchedKind = 7; + } + break; + case 2: + jjmatchedKind = 0x7fffffff; + jjmatchedPos = 0; + curPos = jjMoveStringLiteralDfa0_2(); + if (jjmatchedPos == 0 && jjmatchedKind > 7) { + jjmatchedKind = 7; + } + break; + } + if (jjmatchedKind != 0x7fffffff) { + if (jjmatchedPos + 1 < curPos) + input_stream.backup(curPos - jjmatchedPos - 1); + if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) { + matchedToken = jjFillToken(); + matchedToken.specialToken = specialToken; + TokenLexicalActions(matchedToken); + if (jjnewLexState[jjmatchedKind] != -1) + curLexState = jjnewLexState[jjmatchedKind]; + return matchedToken; + } else + if ((jjtoSkip[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) { + if ((jjtoSpecial[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) { + matchedToken = jjFillToken(); + if (specialToken == null) + specialToken = matchedToken; + else { + matchedToken.specialToken = specialToken; + specialToken = (specialToken.next = matchedToken); + } + SkipLexicalActions(matchedToken); + } else + SkipLexicalActions(null); + if (jjnewLexState[jjmatchedKind] != -1) + curLexState = jjnewLexState[jjmatchedKind]; + continue EOFLoop; + } + MoreLexicalActions(); + if (jjnewLexState[jjmatchedKind] != -1) + curLexState = jjnewLexState[jjmatchedKind]; + curPos = 0; + jjmatchedKind = 0x7fffffff; + try { + curChar = input_stream.readChar(); + continue; + } + catch (java.io.IOException e1) { + } + } + int error_line = input_stream.getEndLine(); + int error_column = input_stream.getEndColumn(); + String error_after = null; + boolean EOFSeen = false; + try { + input_stream.readChar(); + input_stream.backup(1); + } + catch (java.io.IOException e1) { + EOFSeen = true; + error_after = curPos <= 1 ? "" : input_stream.GetImage(); + if (curChar == '\n' || curChar == '\r') { + error_line++; + error_column = 0; + } else + error_column++; + } + if (!EOFSeen) { + input_stream.backup(1); + error_after = curPos <= 1 ? "" : input_stream.GetImage(); + } + throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR); + } + } + } + + void SkipLexicalActions(Token matchedToken) { + switch (jjmatchedKind) { + default: + break; + } + } + + void MoreLexicalActions() { + jjimageLen += (lengthOfMatch = jjmatchedPos + 1); + switch (jjmatchedKind) { + case 1: + if (image == null) + image = new StringBuffer(); + image.append(input_stream.GetSuffix(jjimageLen)); + jjimageLen = 0; + input_stream.backup(1); + break; + default: + break; + } + } + + void TokenLexicalActions(Token matchedToken) { + switch (jjmatchedKind) { + case 120: + if (image == null) + image = new StringBuffer(); + image.append(jjstrLiteralImages[120]); + matchedToken.kind = GT; + ((Token.GTToken) matchedToken).realKind = RUNSIGNEDSHIFT; + input_stream.backup(2); + matchedToken.image = ">"; + break; + case 121: + if (image == null) + image = new StringBuffer(); + image.append(jjstrLiteralImages[121]); + matchedToken.kind = GT; + ((Token.GTToken) matchedToken).realKind = RSIGNEDSHIFT; + input_stream.backup(1); + matchedToken.image = ">"; + break; + default: + break; + } + } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/parser/JavaParserTreeConstants.java b/trunk/jaxx-compiler/src/main/java/jaxx/parser/JavaParserTreeConstants.java new file mode 100644 index 0000000..52aaead --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/parser/JavaParserTreeConstants.java @@ -0,0 +1,230 @@ +/* Generated By:JJTree: Do not edit this line. ./JavaParserTreeConstants.java */ + +package jaxx.parser; + +public interface JavaParserTreeConstants { + public int JJTLINE = 0; + public int JJTCOMPILATIONUNIT = 1; + public int JJTPACKAGEDECLARATION = 2; + public int JJTIMPORTDECLARATION = 3; + public int JJTMODIFIERS = 4; + public int JJTTYPEDECLARATION = 5; + public int JJTCLASSORINTERFACEDECLARATION = 6; + public int JJTEXTENDSLIST = 7; + public int JJTIMPLEMENTSLIST = 8; + public int JJTENUMDECLARATION = 9; + public int JJTENUMBODY = 10; + public int JJTENUMCONSTANT = 11; + public int JJTTYPEPARAMETERS = 12; + public int JJTTYPEPARAMETER = 13; + public int JJTTYPEBOUND = 14; + public int JJTCLASSORINTERFACEBODY = 15; + public int JJTCLASSORINTERFACEBODYDECLARATION = 16; + public int JJTFIELDDECLARATION = 17; + public int JJTVARIABLEDECLARATOR = 18; + public int JJTVARIABLEDECLARATORID = 19; + public int JJTVARIABLEINITIALIZER = 20; + public int JJTARRAYINITIALIZER = 21; + public int JJTMETHODDECLARATION = 22; + public int JJTMETHODDECLARATOR = 23; + public int JJTFORMALPARAMETERS = 24; + public int JJTFORMALPARAMETER = 25; + public int JJTCONSTRUCTORDECLARATION = 26; + public int JJTEXPLICITCONSTRUCTORINVOCATION = 27; + public int JJTINITIALIZER = 28; + public int JJTTYPE = 29; + public int JJTREFERENCETYPE = 30; + public int JJTCLASSORINTERFACETYPE = 31; + public int JJTTYPEARGUMENTS = 32; + public int JJTTYPEARGUMENT = 33; + public int JJTWILDCARDBOUNDS = 34; + public int JJTPRIMITIVETYPE = 35; + public int JJTRESULTTYPE = 36; + public int JJTNAME = 37; + public int JJTNAMELIST = 38; + public int JJTEXPRESSION = 39; + public int JJTASSIGNMENTOPERATOR = 40; + public int JJTASSIGNMENTEXPRESSION = 41; + public int JJTCONDITIONALEXPRESSION = 42; + public int JJTCONDITIONALOREXPRESSION = 43; + public int JJTCONDITIONALANDEXPRESSION = 44; + public int JJTINCLUSIVEOREXPRESSION = 45; + public int JJTEXCLUSIVEOREXPRESSION = 46; + public int JJTANDEXPRESSION = 47; + public int JJTEQUALITYEXPRESSION = 48; + public int JJTINSTANCEOFEXPRESSION = 49; + public int JJTRELATIONALEXPRESSION = 50; + public int JJTSHIFTEXPRESSION = 51; + public int JJTADDITIVEEXPRESSION = 52; + public int JJTMULTIPLICATIVEEXPRESSION = 53; + public int JJTUNARYEXPRESSION = 54; + public int JJTPREINCREMENTEXPRESSION = 55; + public int JJTPREDECREMENTEXPRESSION = 56; + public int JJTUNARYEXPRESSIONNOTPLUSMINUS = 57; + public int JJTCASTLOOKAHEAD = 58; + public int JJTPOSTFIXEXPRESSION = 59; + public int JJTPOSTFIXOPERATOR = 60; + public int JJTCASTEXPRESSION = 61; + public int JJTPRIMARYEXPRESSION = 62; + public int JJTMEMBERSELECTOR = 63; + public int JJTPRIMARYPREFIX = 64; + public int JJTPRIMARYSUFFIX = 65; + public int JJTLITERAL = 66; + public int JJTBOOLEANLITERAL = 67; + public int JJTNULLLITERAL = 68; + public int JJTARGUMENTS = 69; + public int JJTARGUMENTLIST = 70; + public int JJTALLOCATIONEXPRESSION = 71; + public int JJTARRAYDIMSANDINITS = 72; + public int JJTSTATEMENT = 73; + public int JJTASSERTSTATEMENT = 74; + public int JJTLABELEDSTATEMENT = 75; + public int JJTBLOCK = 76; + public int JJTBLOCKSTATEMENT = 77; + public int JJTLOCALVARIABLEDECLARATION = 78; + public int JJTEMPTYSTATEMENT = 79; + public int JJTSTATEMENTEXPRESSION = 80; + public int JJTSWITCHSTATEMENT = 81; + public int JJTSWITCHLABEL = 82; + public int JJTIFSTATEMENT = 83; + public int JJTWHILESTATEMENT = 84; + public int JJTDOSTATEMENT = 85; + public int JJTFORSTATEMENT = 86; + public int JJTFORINIT = 87; + public int JJTSTATEMENTEXPRESSIONLIST = 88; + public int JJTFORUPDATE = 89; + public int JJTBREAKSTATEMENT = 90; + public int JJTCONTINUESTATEMENT = 91; + public int JJTRETURNSTATEMENT = 92; + public int JJTTHROWSTATEMENT = 93; + public int JJTSYNCHRONIZEDSTATEMENT = 94; + public int JJTTRYSTATEMENT = 95; + public int JJTRUNSIGNEDSHIFT = 96; + public int JJTRSIGNEDSHIFT = 97; + public int JJTANNOTATION = 98; + public int JJTNORMALANNOTATION = 99; + public int JJTMARKERANNOTATION = 100; + public int JJTSINGLEMEMBERANNOTATION = 101; + public int JJTMEMBERVALUEPAIRS = 102; + public int JJTMEMBERVALUEPAIR = 103; + public int JJTMEMBERVALUE = 104; + public int JJTMEMBERVALUEARRAYINITIALIZER = 105; + public int JJTANNOTATIONTYPEDECLARATION = 106; + public int JJTANNOTATIONTYPEBODY = 107; + public int JJTANNOTATIONTYPEMEMBERDECLARATION = 108; + public int JJTDEFAULTVALUE = 109; + + + public String[] jjtNodeName = { + "Line", + "CompilationUnit", + "PackageDeclaration", + "ImportDeclaration", + "Modifiers", + "TypeDeclaration", + "ClassOrInterfaceDeclaration", + "ExtendsList", + "ImplementsList", + "EnumDeclaration", + "EnumBody", + "EnumConstant", + "TypeParameters", + "TypeParameter", + "TypeBound", + "ClassOrInterfaceBody", + "ClassOrInterfaceBodyDeclaration", + "FieldDeclaration", + "VariableDeclarator", + "VariableDeclaratorId", + "VariableInitializer", + "ArrayInitializer", + "MethodDeclaration", + "MethodDeclarator", + "FormalParameters", + "FormalParameter", + "ConstructorDeclaration", + "ExplicitConstructorInvocation", + "Initializer", + "Type", + "ReferenceType", + "ClassOrInterfaceType", + "TypeArguments", + "TypeArgument", + "WildcardBounds", + "PrimitiveType", + "ResultType", + "Name", + "NameList", + "Expression", + "AssignmentOperator", + "AssignmentExpression", + "ConditionalExpression", + "ConditionalOrExpression", + "ConditionalAndExpression", + "InclusiveOrExpression", + "ExclusiveOrExpression", + "AndExpression", + "EqualityExpression", + "InstanceOfExpression", + "RelationalExpression", + "ShiftExpression", + "AdditiveExpression", + "MultiplicativeExpression", + "UnaryExpression", + "PreIncrementExpression", + "PreDecrementExpression", + "UnaryExpressionNotPlusMinus", + "CastLookahead", + "PostfixExpression", + "PostfixOperator", + "CastExpression", + "PrimaryExpression", + "MemberSelector", + "PrimaryPrefix", + "PrimarySuffix", + "Literal", + "BooleanLiteral", + "NullLiteral", + "Arguments", + "ArgumentList", + "AllocationExpression", + "ArrayDimsAndInits", + "Statement", + "AssertStatement", + "LabeledStatement", + "Block", + "BlockStatement", + "LocalVariableDeclaration", + "EmptyStatement", + "StatementExpression", + "SwitchStatement", + "SwitchLabel", + "IfStatement", + "WhileStatement", + "DoStatement", + "ForStatement", + "ForInit", + "StatementExpressionList", + "ForUpdate", + "BreakStatement", + "ContinueStatement", + "ReturnStatement", + "ThrowStatement", + "SynchronizedStatement", + "TryStatement", + "RUNSIGNEDSHIFT", + "RSIGNEDSHIFT", + "Annotation", + "NormalAnnotation", + "MarkerAnnotation", + "SingleMemberAnnotation", + "MemberValuePairs", + "MemberValuePair", + "MemberValue", + "MemberValueArrayInitializer", + "AnnotationTypeDeclaration", + "AnnotationTypeBody", + "AnnotationTypeMemberDeclaration", + "DefaultValue", + }; +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/parser/Node.java b/trunk/jaxx-compiler/src/main/java/jaxx/parser/Node.java new file mode 100644 index 0000000..0d26aa0 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/parser/Node.java @@ -0,0 +1,51 @@ +/* Generated By:JJTree: Do not edit this line. Node.java */ + +package jaxx.parser; + +/* All AST nodes must implement this interface. It provides basic + machinery for constructing the parent and child relationships + between nodes. */ + +public interface Node { + + /** + * This method is called after the node has been made the current + * node. It indicates that child nodes can now be added to it. + */ + public void jjtOpen(); + + /** + * This method is called after all the child nodes have been + * added. + */ + public void jjtClose(); + + /** + * This pair of methods are used to inform the node of its + * parent. + * + * @param n node + */ + public void jjtSetParent(Node n); + + public Node jjtGetParent(); + + /** + * This method tells the node to add its argument to the node's + * list of children. + * + * @param n node + * @param i index ? + */ + public void jjtAddChild(Node n, int i); + + /** + * @param i index of child + * @return a child node. The children are numbered + * from zero, left to right. + */ + public Node jjtGetChild(int i); + + /** @return the number of children the node has. */ + public int jjtGetNumChildren(); +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/parser/ParseException.java b/trunk/jaxx-compiler/src/main/java/jaxx/parser/ParseException.java new file mode 100644 index 0000000..c74226b --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/parser/ParseException.java @@ -0,0 +1,214 @@ +/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */ +package jaxx.parser; + +/** + * This exception is thrown when parse errors are encountered. + * You can explicitly create objects of this exception type by + * calling the method generateParseException in the generated + * parser. + * <p/> + * You can modify this class to customize your error reporting + * mechanisms so long as you retain the public fields. + */ +public class ParseException extends jaxx.CompilerException { + int line; + int column; + private static final long serialVersionUID = 6179854408401024700L; + + /** + * This constructor is used by the method "generateParseException" + * in the generated parser. Calling this constructor generates + * a new object of this type with the fields "currentToken", + * "expectedTokenSequences", and "tokenImage" set. The boolean + * flag "specialConstructor" is also set to true to indicate that + * this constructor was used to create this object. + * This constructor calls its super class with the empty string + * to force the "toString" method of parent class "Throwable" to + * print the error message in the form: + * ParseException: <result of getMessage> + * + * @param currentTokenVal ? + * @param expectedTokenSequencesVal ? + * @param tokenImageVal ? + */ + public ParseException(Token currentTokenVal, + int[][] expectedTokenSequencesVal, + String[] tokenImageVal + ) { + super(""); + specialConstructor = true; + currentToken = currentTokenVal; + expectedTokenSequences = expectedTokenSequencesVal; + tokenImage = tokenImageVal; + } + + /** + * The following constructors are for use by you for whatever + * purpose you can think of. Constructing the exception in this + * manner makes the exception behave in the normal way - i.e., as + * documented in the class "Throwable". The fields "errorToken", + * "expectedTokenSequences", and "tokenImage" do not contain + * relevant information. The JavaCC generated code does not use + * these constructors. + */ + + public ParseException() { + super(); + specialConstructor = false; + } + + public ParseException(String message) { + super(message); + specialConstructor = false; + } + + public ParseException(String message, int line, int column) { + super(message); + specialConstructor = false; + this.line = line; + this.column = column; + } + + + /** + * This variable determines which constructor was used to create + * this object and thereby affects the semantics of the + * "getMessage" method (see below). + */ + protected boolean specialConstructor; + + /** + * This is the last token that has been consumed successfully. If + * this object has been created due to a parse error, the token + * followng this token will (therefore) be the first error token. + */ + public Token currentToken; + + /** + * Each entry in this array is an array of integers. Each array + * of integers represents a sequence of tokens (by their ordinal + * values) that is expected at this point of the parse. + */ + public int[][] expectedTokenSequences; + + /** + * This is a reference to the "tokenImage" array of the generated + * parser within which the parse error occurred. This array is + * defined in the generated ...Constants interface. + */ + public String[] tokenImage; + + /** + * This method has the standard behavior when this object has been + * created using the standard constructors. Otherwise, it uses + * "currentToken" and "expectedTokenSequences" to generate a parse + * error message and returns it. If this object has been created + * due to a parse error, and you do not catch it (it gets thrown + * from the parser), then this method is called during the printing + * of the final stack trace, and hence the correct error message + * gets displayed. + */ + public String getMessage() { + if (!specialConstructor) { + return super.getMessage(); + } + StringBuffer expected = new StringBuffer(); + int maxSize = 0; + for (int[] expectedTokenSequence : expectedTokenSequences) { + if (maxSize < expectedTokenSequence.length) { + maxSize = expectedTokenSequence.length; + } + for (int anExpectedTokenSequence : expectedTokenSequence) { + expected.append(tokenImage[anExpectedTokenSequence]).append(" "); + } + if (expectedTokenSequence[expectedTokenSequence.length - 1] != 0) { + expected.append("..."); + } + expected.append(eol).append(" "); + } + String retval = "Encountered \""; + Token tok = currentToken.next; + for (int i = 0; i < maxSize; i++) { + if (i != 0) retval += " "; + if (tok.kind == 0) { + retval += tokenImage[0]; + break; + } + retval += add_escapes(tok.image); + tok = tok.next; + } + retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn; + retval += "." + eol; + if (expectedTokenSequences.length == 1) { + retval += "Was expecting:" + eol + " "; + } else { + retval += "Was expecting one of:" + eol + " "; + } + retval += expected.toString(); + return retval; + } + + + public int getLine() { + return line; + } + + public int getColumn() { + return column; + } + + /** The end of line string for this machine. */ + protected String eol = System.getProperty("line.separator", "\n"); + + /** + * Used to convert raw characters to their escaped version + * when these raw version cannot be used as part of an ASCII + * string literal. + * + * @param str text to treate + * @return the escaped version of text + */ + protected String add_escapes(String str) { + StringBuffer retval = new StringBuffer(); + char ch; + for (int i = 0; i < str.length(); i++) { + switch (str.charAt(i)) { + case 0: + continue; + case '\b': + retval.append("\\b"); + continue; + case '\t': + retval.append("\\t"); + continue; + case '\n': + retval.append("\\n"); + continue; + case '\f': + retval.append("\\f"); + continue; + case '\r': + retval.append("\\r"); + continue; + case '\"': + retval.append("\\\""); + continue; + case '\'': + retval.append("\\\'"); + continue; + case '\\': + retval.append("\\\\"); + continue; + default: + if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { + String s = "0000" + Integer.toString(ch, 16); + retval.append("\\u").append(s.substring(s.length() - 4, s.length())); + } else { + retval.append(ch); + } + } + } + return retval.toString(); + } + +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/parser/SimpleNode.java b/trunk/jaxx-compiler/src/main/java/jaxx/parser/SimpleNode.java new file mode 100644 index 0000000..07b14f4 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/parser/SimpleNode.java @@ -0,0 +1,135 @@ +/* Generated By:JJTree: Do not edit this line. SimpleNode.java */ + +package jaxx.parser; + +import jaxx.reflect.ClassDescriptor; + +public class SimpleNode implements Node { + protected Node parent; + protected Node[] children; + protected int id; + protected JavaParser parser; + public Token firstToken; + public Token lastToken; + private ClassDescriptor javaType; + + + public SimpleNode(int i) { + id = i; + } + + public SimpleNode(JavaParser p, int i) { + this(i); + parser = p; + } + + + public int getId() { + return id; + } + + public void jjtOpen() { + } + + public void jjtClose() { + } + + public void jjtSetParent(Node n) { + parent = n; + } + + public Node jjtGetParent() { + return parent; + } + + public SimpleNode getParent() { + return (SimpleNode) parent; + } + + + public ClassDescriptor getJavaType() { + return javaType; + } + + + public void setJavaType(ClassDescriptor javaType) { + this.javaType = javaType; + } + + public void jjtAddChild(Node n, int i) { + if (children == null) { + children = new Node[i + 1]; + } else if (i >= children.length) { + Node c[] = new Node[i + 1]; + System.arraycopy(children, 0, c, 0, children.length); + children = c; + } + children[i] = n; + } + + public Node jjtGetChild(int i) { + return children[i]; + } + + public SimpleNode getChild(int i) { + return (SimpleNode) children[i]; + } + + public int jjtGetNumChildren() { + return (children == null) ? 0 : children.length; + } + + /* You can override these two methods in subclasses of SimpleNode to +customize the way the node appears when the tree is dumped. If +your output uses more than one line you should override +toString(String), otherwise overriding toString() is probably all +you need to do. */ + + @Override + public String toString() { + return getClass().getName() + "[" + getText() + "]"; + } + + public String toString(String prefix) { + return prefix + toString(); + } + + /* Override this method if you want to customize how the node dumps + out its children. */ + + public void dump(String prefix) { + System.out.println(toString(prefix)); + if (children != null) { + for (Node aChildren : children) { + SimpleNode n = (SimpleNode) aChildren; + if (n != null) { + n.dump(prefix + " "); + } + } + } + } + + private void appendSpecialTokens(StringBuffer s, Token st) { + if (st != null) { + appendSpecialTokens(s, st.specialToken); + s.append(st.image); + } + } + + + /** @return the text of the tokens comprising this node. */ + public String getText() { + StringBuffer text = new StringBuffer(); + Token t = firstToken; + while (t != null) { + appendSpecialTokens(text, t.specialToken); + text.append(t.image); + if (t == lastToken) + break; + t = t.next; + } + + return text.toString(); + } +} + diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/parser/Token.java b/trunk/jaxx-compiler/src/main/java/jaxx/parser/Token.java new file mode 100644 index 0000000..03c11a0 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/parser/Token.java @@ -0,0 +1,79 @@ +/* Generated By:JavaCC: Do not edit this line. Token.java Version 3.0 */ +package jaxx.parser; + +/** Describes the input token stream. */ + +public class Token { + /** + * An integer that describes the kind of this token. This numbering + * system is determined by JavaCCParser, and a table of these numbers is + * stored in the file ...Constants.java. + */ + public int kind; + + /** + * beginLine and beginColumn describe the position of the first character + * of this token; endLine and endColumn describe the position of the + * last character of this token. + */ + public int beginLine, beginColumn, endLine, endColumn; + + /** The string image of the token. */ + public String image; + + /** + * A reference to the next regular (non-special) token from the input + * stream. If this is the last token from the input stream, or if the + * token manager has not read tokens beyond this one, this field is + * set to null. This is true only if this token is also a regular + * token. Otherwise, see below for a description of the contents of + * this field. + */ + public Token next; + + /** + * This field is used to access special tokens that occur prior to this + * token, but after the immediately preceding regular (non-special) token. + * If there are no such special tokens, this field is set to null. + * When there are more than one such special token, this field refers + * to the last of these special tokens, which in turn refers to the next + * previous special token through its specialToken field, and so on + * until the first special token (whose specialToken field is null). + * The next fields of special tokens refer to other special tokens that + * immediately follow it (without an intervening regular token). If there + * is no such token, this field is null. + */ + public Token specialToken; + + /** Returns the image. */ + public String toString() { + return image; + } + + /** + * Returns a new Token object, by default. However, if you want, you + * can create and return subclass objects based on the value of ofKind. + * Simply add the cases to the switch for all those special cases. + * For example, if you have a subclass of Token called IDToken that + * you want to create if ofKind is ID, simlpy add something like : + * <p/> + * case MyParserConstants.ID : return new IDToken(); + * <p/> + * to the following switch statement. Then you can cast matchedToken + * variable to the appropriate type and use it in your lexical actions. + */ + public static final Token newToken(int ofKind) { + switch (ofKind) { + default: + return new Token(); + case JavaParserConstants.RUNSIGNEDSHIFT: + case JavaParserConstants.RSIGNEDSHIFT: + case JavaParserConstants.GT: + return new GTToken(); + } + } + + public static class GTToken extends Token { + int realKind = JavaParserConstants.GT; + } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/parser/TokenMgrError.java b/trunk/jaxx-compiler/src/main/java/jaxx/parser/TokenMgrError.java new file mode 100644 index 0000000..654ccd7 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/parser/TokenMgrError.java @@ -0,0 +1,126 @@ +/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 3.0 */ +package jaxx.parser; + +public class TokenMgrError extends Error { + /* + * Ordinals for various reasons why an Error of this type can be thrown. + */ + + /** Lexical error occured. */ + static final int LEXICAL_ERROR = 0; + + /** An attempt wass made to create a second instance of a static token manager. */ + static final int STATIC_LEXER_ERROR = 1; + + /** Tried to change to an invalid lexical state. */ + static final int INVALID_LEXICAL_STATE = 2; + + /** Detected (and bailed out of) an infinite loop in the token manager. */ + static final int LOOP_DETECTED = 3; + + /** + * Indicates the reason why the exception is thrown. It will have + * one of the above 4 values. + */ + int errorCode; + private static final long serialVersionUID = -9131500865453532454L; + + /** + * Replaces unprintable characters by their espaced (or unicode escaped) + * equivalents in the given string + * + * @param str text to treate + * @return the treated text + */ + protected static String addEscapes(String str) { + StringBuffer retval = new StringBuffer(); + char ch; + for (int i = 0; i < str.length(); i++) { + switch (str.charAt(i)) { + case 0: + continue; + case '\b': + retval.append("\\b"); + continue; + case '\t': + retval.append("\\t"); + continue; + case '\n': + retval.append("\\n"); + continue; + case '\f': + retval.append("\\f"); + continue; + case '\r': + retval.append("\\r"); + continue; + case '\"': + retval.append("\\\""); + continue; + case '\'': + retval.append("\\\'"); + continue; + case '\\': + retval.append("\\\\"); + continue; + default: + if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { + String s = "0000" + Integer.toString(ch, 16); + retval.append("\\u").append(s.substring(s.length() - 4, s.length())); + } else { + retval.append(ch); + } + } + } + return retval.toString(); + } + + /** + * @param EOFSeen : indicates if EOF caused the lexicl error + * @param lexState : lexical state in which this error occured + * @param errorLine : line number when the error occured + * @param errorColumn : column number when the error occured + * @param errorAfter : prefix that was seen before this error occured + * @param curChar : the offending character + * Note: You can customize the lexical error message by modifying this method. + * @return a detailed message for the Error when it is thrown by the + * token manager to indicate a lexical error. + */ + protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) { + return ("Lexical error at line " + + errorLine + ", column " + + errorColumn + ". Encountered: " + + (EOFSeen ? "<EOF> " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int) curChar + "), ") + + "after : \"" + addEscapes(errorAfter) + "\""); + } + + /** + * You can also modify the body of this method to customize your error messages. + * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not + * of end-users concern, so you can return something like : + * <p/> + * "Internal Error : Please file a bug report .... " + * <p/> + * from this method for such cases in the release version of your parser. + */ + @Override + public String getMessage() { + return super.getMessage(); + } + + /* + * Constructors of various flavors follow. + */ + + public TokenMgrError() { + } + + public TokenMgrError(String message, int reason) { + super(message); + errorCode = reason; + } + + public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) { + this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason); + } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/reflect/ClassDescriptor.java b/trunk/jaxx-compiler/src/main/java/jaxx/reflect/ClassDescriptor.java new file mode 100644 index 0000000..4665f5c --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/reflect/ClassDescriptor.java @@ -0,0 +1,166 @@ +package jaxx.reflect; + +import jaxx.runtime.JAXXObjectDescriptor; + +import java.util.Arrays; + +/** + * Mirrors the class <code>java.lang.Class</code>. JAXX uses <code>ClassDescriptor</code> instead of <code>Class</code> + * almost everywhere so that it can handle circular dependencies (there can't be a <code>Class</code> object for an uncompiled + * JAXX or Java source file, and a compiler must be allow references to symbols in uncompiled source files in order to handle + * circular dependencies). + */ +public abstract class ClassDescriptor { + private String name; + private String packageName; + private String superclass; + private String[] interfaces; + private boolean isInterface; + private boolean isArray; + private String componentType; + private JAXXObjectDescriptor jaxxObjectDescriptor; + private ClassLoader classLoader; + private MethodDescriptor[] methodDescriptors; + private FieldDescriptor[] fieldDescriptors; + + + ClassDescriptor(String name, String packageName, String superclass, String[] interfaces, boolean isInterface, + boolean isArray, String componentType, JAXXObjectDescriptor jaxxObjectDescriptor, + ClassLoader classLoader, MethodDescriptor[] methodDescriptors, FieldDescriptor[] fieldDescriptors) { + this.name = name; + this.packageName = packageName; + this.superclass = superclass; + this.interfaces = interfaces; + this.isInterface = isInterface; + this.isArray = isArray; + this.componentType = componentType; + this.jaxxObjectDescriptor = jaxxObjectDescriptor; + this.classLoader = classLoader; + this.methodDescriptors = methodDescriptors; + this.fieldDescriptors = fieldDescriptors; + } + + + public String getName() { + return name; + } + + + public String getPackageName() { + return packageName; + } + + + public ClassDescriptor getSuperclass() { + try { + return superclass != null ? ClassDescriptorLoader.getClassDescriptor(superclass, getClassLoader()) : null; + } + catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + + public ClassDescriptor[] getInterfaces() { + try { + ClassDescriptor[] result = new ClassDescriptor[interfaces.length]; + for (int i = 0; i < result.length; i++) { + result[i] = ClassDescriptorLoader.getClassDescriptor(interfaces[i], getClassLoader()); + } + return result; + } + catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + + public boolean isInterface() { + return isInterface; + } + + + public boolean isArray() { + return isArray; + } + + + public ClassDescriptor getComponentType() { + try { + return componentType != null ? ClassDescriptorLoader.getClassDescriptor(componentType, getClassLoader()) : null; + } + catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + + public ClassLoader getClassLoader() { + return classLoader; + } + + + public MethodDescriptor[] getMethodDescriptors() { + return methodDescriptors; + } + + + public MethodDescriptor getMethodDescriptor(String name, ClassDescriptor... parameterTypes) throws NoSuchMethodException { + for (MethodDescriptor methodDescriptor : methodDescriptors) { + if (methodDescriptor.getName().equals(name) + && methodDescriptor.getParameterTypes().length == parameterTypes.length + && Arrays.equals(methodDescriptor.getParameterTypes(), parameterTypes)) { + return methodDescriptor; + } + } + throw new NoSuchMethodException("Could not find method " + name + "(" + Arrays.asList(parameterTypes) + ") in " + getName()); + } + + + public abstract MethodDescriptor getDeclaredMethodDescriptor(String name, ClassDescriptor... parameterTypes) throws NoSuchMethodException; + + + public FieldDescriptor[] getFieldDescriptors() { + return fieldDescriptors; + } + + + public FieldDescriptor getFieldDescriptor(String name) throws NoSuchFieldException { + for (FieldDescriptor fieldDescriptor : fieldDescriptors) { + if (fieldDescriptor.getName().equals(name)) { + return fieldDescriptor; + } + } + throw new NoSuchFieldException("Could not find field " + name + " in " + getName()); + } + + + public abstract FieldDescriptor getDeclaredFieldDescriptor(String name) throws NoSuchFieldException; + + + public JAXXObjectDescriptor getJAXXObjectDescriptor() { + return jaxxObjectDescriptor; + } + + + public boolean isAssignableFrom(ClassDescriptor descriptor) { + while (descriptor != null) { + if (descriptor == this) { + return true; + } + ClassDescriptor[] interfaces = descriptor.getInterfaces(); + for (ClassDescriptor anInterface : interfaces) { + if (anInterface == this) { + return true; + } + } + descriptor = descriptor.getSuperclass(); + } + return false; + } + + @Override + public String toString() { + return "ClassDescriptor[" + getName() + "]"; + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/reflect/ClassDescriptorLoader.java b/trunk/jaxx-compiler/src/main/java/jaxx/reflect/ClassDescriptorLoader.java new file mode 100644 index 0000000..845fdee --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/reflect/ClassDescriptorLoader.java @@ -0,0 +1,431 @@ +package jaxx.reflect; + +import jaxx.CompilerException; +import jaxx.compiler.JAXXCompiler; +import jaxx.compiler.JAXXCompilerLaunchor; +import jaxx.compiler.SymbolTable; +import jaxx.runtime.JAXXObject; +import jaxx.runtime.JAXXObjectDescriptor; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.net.URL; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Mirrors the class <code>java.lang.ClassLoader</code>. JAXX uses <code>ClassDescriptor</code> instead of <code>Class</code> + * almost everywhere so that it can handle circular dependencies (there can't be a <code>Class</code> object for an uncompiled + * JAXX or Java source file, and a compiler must be allow references to symbols in uncompiled source files in order to handle + * circular dependencies). + */ +public class ClassDescriptorLoader { + + private static Map<String, ClassDescriptor> descriptors = new HashMap<String, ClassDescriptor>(); + + private ClassDescriptorLoader() { + } + + + public static synchronized ClassDescriptor getClassDescriptor(String className) throws ClassNotFoundException { + return getClassDescriptor(className, Thread.currentThread().getContextClassLoader()); + //return getClassDescriptor(className, ClassDescriptorLoader.class.getClassLoader()); + } + + public static synchronized ClassDescriptor getClassDescriptor(String className, ClassLoader classLoader) throws ClassNotFoundException { + ClassDescriptor result = descriptors.get(className); + if (result == null) { + if (JAXXCompilerLaunchor.isRegistred() && JAXXCompilerLaunchor.get().getSymbolTable(className) != null) { + result = createClassDescriptorFromSymbolTable(className, classLoader); + } else { + if (classLoader == null) { + classLoader = ClassDescriptorLoader.class.getClassLoader(); + } + + String relativePath = className.replaceAll("\\.", "/"); + String relativePathPattern = ".*";// + className + ".*"; // used to ensure that the located resource has the right character cases + + // find the most recently updated source for the class -- Java source, JAXX source, or compiled class file + long javaLastModified = -1; + URL javaFile = classLoader.getResource(relativePath + ".java"); + if (javaFile != null && javaFile.toString().startsWith("file:") && javaFile.toString().matches(relativePathPattern)) { + javaLastModified = JAXXCompiler.URLtoFile(javaFile).lastModified(); + } + + long classLastModified = -1; + URL classFile = classLoader.getResource(relativePath + ".class"); + if (classFile != null && classFile.toString().startsWith("file:") && classFile.toString().matches(relativePathPattern)) { + classLastModified = JAXXCompiler.URLtoFile(classFile).lastModified(); + } + + long jaxxLastModified = -1; + URL jaxxFile = classLoader.getResource(relativePath + ".jaxx"); + if (jaxxFile != null && jaxxFile.toString().startsWith("file:") && jaxxFile.toString().matches(relativePathPattern)) { + File jaxxFilePath = JAXXCompiler.URLtoFile(jaxxFile); + jaxxLastModified = jaxxFilePath.lastModified(); + String simplePath = jaxxFilePath.getPath(); + simplePath = simplePath.substring(0, simplePath.length() - ".jaxx".length()); + File cssFilePath = new File(simplePath + ".css"); + if (cssFilePath.exists()) { + jaxxLastModified = Math.max(jaxxLastModified, cssFilePath.lastModified()); + } + File scriptFilePath = new File(simplePath + ".script"); + if (scriptFilePath.exists()) { + jaxxLastModified = Math.max(jaxxLastModified, scriptFilePath.lastModified()); + } + } + + if (jaxxLastModified != -1 && JAXXCompilerLaunchor.isRegistred() && JAXXCompilerLaunchor.get().getSymbolTable(className) == null) { + jaxxLastModified = -1; // file has been modified, but wasn't included in this + } + // compilation set so we don't have a symbol table + + if (javaLastModified != -1 || classLastModified != -1 || jaxxLastModified != -1) { + if (jaxxLastModified > classLastModified && jaxxLastModified > javaLastModified) { + result = createClassDescriptorFromSymbolTable(className, classLoader); + } else if (javaLastModified > classLastModified && javaLastModified > jaxxLastModified) { + result = createClassDescriptorFromJavaSource(javaFile, classLoader); + } + } + // else work off of the class file. This also handles the case where the class is available, but wasn't in a location where + // we could check its last modified date (in a JAR, over the network, etc.) + if (result == null) { + Class<?> javaClass = getClass(className, classLoader); + result = createClassDescriptorFromClass(javaClass); + } + } + descriptors.put(className, result); + } + return result; + } + + + public static ClassDescriptor getClassDescriptor(Class<?> javaClass) { + try { + return getClassDescriptor(javaClass.getName(), javaClass.getClassLoader()); + } + catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + public static Class<?> getPrimitiveBoxedClass(String className) throws ClassNotFoundException { + if (className.equals("boolean")) { + return Boolean.class; + } + if (className.equals("byte")) { + return Byte.class; + } + if (className.equals("short")) { + return Short.class; + } + if (className.equals("int")) { + return Integer.class; + } + if (className.equals("long")) { + return Long.class; + } + if (className.equals("float")) { + return Float.class; + } + if (className.equals("double")) { + return Double.class; + } + if (className.equals("char")) { + return Character.class; + } + if (className.equals("void")) { + return Void.class; + } + return null; + } + + public static Class<?> getPrimitiveClass(String className) throws ClassNotFoundException { + if (className.equals("boolean")) { + return boolean.class; + } + if (className.equals("byte")) { + return byte.class; + } + if (className.equals("short")) { + return short.class; + } + if (className.equals("int")) { + return int.class; + } + if (className.equals("long")) { + return long.class; + } + if (className.equals("float")) { + return float.class; + } + if (className.equals("double")) { + return double.class; + } + if (className.equals("char")) { + return char.class; + } + if (className.equals("void")) { + return void.class; + } + // detect arrays + int arrayCount = 0; + while (className.endsWith("[]")) { + arrayCount++; + className = className.substring(0, className.length() - 2); + } + Class<?> klass=null; + if (arrayCount > 0) { + klass = getPrimitiveClass(className); + if (klass==null) { + // none primitive array + return null; + } + // must take the boxed class, other it does not works + // to make a Class.forName("[Lchar;"); but works + // with Class.forName("[LCharacter;"); ... + klass =getPrimitiveBoxedClass(className); + className=klass.getName(); + + className = "L" + className + ";"; + while (arrayCount > 0) { + className = "[" + className; + arrayCount--; + } + //System.out.println("primitive array class "+className); + return Class.forName(className); + } + return null; + } + + public static Class<?> getClass(String className, ClassLoader classLoader) throws ClassNotFoundException { + Class<?> klass = getPrimitiveClass(className); + if (klass!=null) { + return klass; + } + // try an array of none primitive classes + int arrayCount = 0; + while (className.endsWith("[]")) { + arrayCount++; + className = className.substring(0, className.length() - 2); + } + if (arrayCount > 0) { + className = "L" + className + ";"; + while (arrayCount > 0) { + className = "[" + className; + arrayCount--; + } + } + try { + return classLoader != null ? Class.forName(className, true, classLoader) : Class.forName(className); + } catch (ClassNotFoundException e) { + // perharps we are in a inner class ? + int dotIndex = className.lastIndexOf("."); + if (dotIndex > -1) { + String parentFQN = className.substring(0, dotIndex); + String simpleName = className.substring(dotIndex + 1); + try { + Class<?> parentClass = classLoader != null ? Class.forName(parentFQN, true, classLoader) : Class.forName(parentFQN); + for (Class<?> innerClass : parentClass.getClasses()) { + if (simpleName.equals(innerClass.getSimpleName())) { + return innerClass; + } + } + } catch (ClassNotFoundException e1) { + // no super class,so let the first exception throw... + } + } + throw e; + } + catch (NoClassDefFoundError e) { + + throw new ClassNotFoundException(e.toString()); + } + } + + private static MethodDescriptor createMethodDescriptor(Method javaMethod, ClassLoader classLoader) { + String methodName = javaMethod.getName(); + int modifiers = javaMethod.getModifiers(); + String returnType = javaMethod.getReturnType().getName(); + Class<?>[] javaParameters = javaMethod.getParameterTypes(); + String[] parameters = new String[javaParameters.length]; + for (int i = 0; i < parameters.length; i++) { + parameters[i] = javaParameters[i].getName(); + } + return new MethodDescriptor(methodName, modifiers, returnType, parameters, classLoader); + } + + + private static FieldDescriptor createFieldDescriptor(Field javaField, ClassLoader classLoader) { + String fieldName = javaField.getName(); + int modifiers = javaField.getModifiers(); + String type = javaField.getType().getName(); + return new FieldDescriptor(fieldName, modifiers, type, classLoader); + } + + private static JAXXObjectDescriptor getJAXXObjectDescriptor(Class<?> jaxxClass) { + if (!JAXXObject.class.isAssignableFrom(jaxxClass) || jaxxClass == JAXXObject.class) { + return null; + } + try { + Method getJAXXObjectDescriptor = jaxxClass.getMethod("$getJAXXObjectDescriptor", new Class<?>[0]); + return (JAXXObjectDescriptor) getJAXXObjectDescriptor.invoke(null); + } + catch (NoSuchMethodException e) { + throw new CompilerException("Expected JAXXObject " + jaxxClass.getName() + " to have a static method named $getJAXXObjectDescriptor"); + } + catch (IllegalAccessException e) { + throw new CompilerException("Expected JAXXObject " + jaxxClass.getName() + "'s $getJAXXObjectDescriptor method to be public"); + } + catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + private static ClassDescriptor createClassDescriptorFromJavaSource(URL javaSource, ClassLoader classLoader) throws ClassNotFoundException { + try { + InputStream in = javaSource.openStream(); + Reader reader = new InputStreamReader(in, "utf-8"); + ClassDescriptor result = JavaFileParser.parseJavaFile(javaSource.toString(), reader, classLoader); + reader.close(); + return result; + } + catch (IOException e) { + throw new ClassNotFoundException(e.toString()); + } + } + + private static ClassDescriptor createClassDescriptorFromSymbolTable(String className, ClassLoader classLoader) throws ClassNotFoundException { + final JAXXCompiler compiler = JAXXCompilerLaunchor.get().getJAXXCompiler(className); + final SymbolTable symbolTable = JAXXCompilerLaunchor.get().getSymbolTable(className); + if (symbolTable == null) { + throw new CompilerException("Internal error: no symbol table was generated for class '" + className + "'"); + } + ClassDescriptor superclass = getClassDescriptor(symbolTable.getSuperclassName(), classLoader); + List<MethodDescriptor> publicMethods = symbolTable.getScriptMethods(); + List<FieldDescriptor> publicFields = symbolTable.getScriptFields(); + //List<MethodDescriptor> declaredMethods = new ArrayList<MethodDescriptor>(publicMethods); + //List<FieldDescriptor> declaredFields = new ArrayList<FieldDescriptor>(publicFields); + Iterator<MethodDescriptor> methods = publicMethods.iterator(); + while (methods.hasNext()) { + MethodDescriptor method = methods.next(); + if (!Modifier.isPublic(method.getModifiers())) { + methods.remove(); + } + } + Iterator<FieldDescriptor> fields = publicFields.iterator(); + while (fields.hasNext()) { + FieldDescriptor field = fields.next(); + if (!Modifier.isPublic(field.getModifiers())) { + fields.remove(); + } + } + publicMethods.addAll(Arrays.asList(superclass.getMethodDescriptors())); + publicFields.addAll(Arrays.asList(superclass.getFieldDescriptors())); + int dotPos = className.lastIndexOf("."); + String packageName = dotPos != -1 ? className.substring(0, dotPos) : null; + Set<String> interfaces = new HashSet<String>(); + ClassDescriptor[] superclassInterfaces = superclass.getInterfaces(); + for (ClassDescriptor superclassInterface : superclassInterfaces) { + interfaces.add(superclassInterface.getName()); + } + interfaces.add(JAXXObject.class.getName()); + return new ClassDescriptor(className, packageName, symbolTable.getSuperclassName(), + interfaces.toArray(new String[interfaces.size()]), false, false, null, null, classLoader, + publicMethods.toArray(new MethodDescriptor[publicMethods.size()]), + publicFields.toArray(new FieldDescriptor[publicFields.size()])) { + @Override + public FieldDescriptor getDeclaredFieldDescriptor(String name) throws NoSuchFieldException { + String type = symbolTable.getClassTagIds().get(name); + if (type != null) { + return new FieldDescriptor(name, Modifier.PROTECTED, type, compiler.getClassLoader()); + } + throw new NoSuchFieldException(name); + } + + @Override + public MethodDescriptor getDeclaredMethodDescriptor(String name, ClassDescriptor... parameterTypes) throws NoSuchMethodException { + throw new NoSuchMethodException(name); + } + + @Override + public JAXXObjectDescriptor getJAXXObjectDescriptor() { + return compiler.getJAXXObjectDescriptor(); + } + }; + } + + + private static ClassDescriptor createClassDescriptorFromClass(final Class<?> javaClass) { + String name = javaClass.getName(); + Package p = javaClass.getPackage(); + String packageName = p != null ? p.getName() : null; + Class<?> superclass = javaClass.getSuperclass(); + String superclassName = superclass != null ? superclass.getName() : null; + Class<?>[] interfaces = javaClass.getInterfaces(); + String[] interfaceNames = new String[interfaces.length]; + for (int i = 0; i < interfaces.length; i++) { + interfaceNames[i] = interfaces[i].getName(); + } + boolean isInterface = javaClass.isInterface(); + boolean isArray = javaClass.isArray(); + String componentTypeName = isArray ? javaClass.getComponentType().getName() : null; + JAXXObjectDescriptor jaxxObjectDescriptor = getJAXXObjectDescriptor(javaClass); + ClassLoader classLoader = javaClass.getClassLoader(); + Method[] javaMethods = javaClass.getMethods(); + MethodDescriptor[] methods = new MethodDescriptor[javaMethods.length]; + for (int i = 0; i < methods.length; i++) { + methods[i] = createMethodDescriptor(javaMethods[i], javaClass.getClassLoader()); + } + Field[] javaFields = javaClass.getFields(); + FieldDescriptor[] fields = new FieldDescriptor[javaFields.length]; + for (int i = 0; i < fields.length; i++) { + fields[i] = createFieldDescriptor(javaFields[i], javaClass.getClassLoader()); + } + return new ClassDescriptor(name, packageName, superclassName, interfaceNames, isInterface, isArray, componentTypeName, jaxxObjectDescriptor, classLoader, methods, fields) { + @Override + public FieldDescriptor getDeclaredFieldDescriptor(String name) throws NoSuchFieldException { + return createFieldDescriptor(javaClass.getDeclaredField(name), javaClass.getClassLoader()); + } + + @Override + public MethodDescriptor getDeclaredMethodDescriptor(String name, ClassDescriptor... parameterTypes) throws NoSuchMethodException { + try { + Class[] parameterTypeClasses = new Class[parameterTypes.length]; + for (int i = 0; i < parameterTypes.length; i++) { + parameterTypeClasses[i] = Class.forName(parameterTypes[i].getName()); + } + return createMethodDescriptor(javaClass.getDeclaredMethod(name, parameterTypeClasses), javaClass.getClassLoader()); + } + catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + }; + } + + public static void checkSupportClass(Class<?> handlerClass, ClassDescriptor beanClass, Class<?>... tagClasses) { + for (Class<?> tagClass : tagClasses) { + if (getClassDescriptor(tagClass).isAssignableFrom(beanClass)) { + return; + } + } + throw new IllegalArgumentException(handlerClass.getName() + " does not support the class " + beanClass.getName()); + } + + public static void reset() { + descriptors.clear(); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/reflect/FieldDescriptor.java b/trunk/jaxx-compiler/src/main/java/jaxx/reflect/FieldDescriptor.java new file mode 100644 index 0000000..9b207fb --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/reflect/FieldDescriptor.java @@ -0,0 +1,27 @@ +package jaxx.reflect; + +/** + * Mirrors the class <code>java.lang.ref.Field</code>. JAXX uses <code>ClassDescriptor</code> instead of <code>Class</code> + * almost everywhere so that it can handle circular dependencies (there can't be a <code>Class</code> object for an uncompiled + * JAXX or Java source file, and a compiler must be allow references to symbols in uncompiled source files in order to handle + * circular dependencies). + */ +public class FieldDescriptor extends MemberDescriptor { + private String type; + + + public FieldDescriptor(String name, int modifiers, String type, ClassLoader classLoader) { + super(name, modifiers, classLoader); + this.type = type; + } + + + public ClassDescriptor getType() { + try { + return ClassDescriptorLoader.getClassDescriptor(type, getClassLoader()); + } + catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/reflect/JavaFileParser.java b/trunk/jaxx-compiler/src/main/java/jaxx/reflect/JavaFileParser.java new file mode 100644 index 0000000..edad5a7 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/reflect/JavaFileParser.java @@ -0,0 +1,230 @@ +package jaxx.reflect; + +import jaxx.CompilerException; +import jaxx.compiler.JAXXCompiler; +import jaxx.compiler.JAXXCompilerLaunchor; +import jaxx.parser.JavaParser; +import jaxx.parser.JavaParserTreeConstants; +import jaxx.parser.ParseException; +import jaxx.parser.SimpleNode; +import jaxx.tags.TagManager; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.Reader; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +// TODO: need to unify this implementation with the parsing in ScriptManager +public class JavaFileParser { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private final Log log = LogFactory.getLog(JavaFileParser.class); + + + private JAXXCompiler compiler; + private String className; + private String packageName = null; + private String superclass = "java.lang.Object"; + private List<MethodDescriptor> methods = new ArrayList<MethodDescriptor>(); + private List<FieldDescriptor> fields = new ArrayList<FieldDescriptor>(); + + + private JavaFileParser(ClassLoader classLoader) { + compiler = JAXXCompilerLaunchor.createDummyCompiler(classLoader); + } + + public static ClassDescriptor parseJavaFile(String displayName, Reader src, ClassLoader classLoader) throws ClassNotFoundException { + // has some limitations -- it reports all members as public, leaves getDeclaredMethod and getDeclaredField + // undefined, and doesn't report interfaces. It's safe to leave those the way they are for now, because + // JAXX doesn't look at any of those for non-JAXX classes. + JavaFileParser parser = new JavaFileParser(classLoader); + if (log.isDebugEnabled()) { + log.debug("starting parsing : " + displayName); + } + try { + parser.doParse(displayName, src); + } catch (Exception e) { + log.error(e.getMessage()); + throw new RuntimeException(e); + } + + List<MethodDescriptor> publicMethods = parser.methods; + List<FieldDescriptor> publicFields = parser.fields; + //List/*<MethodDescriptor>*/ declaredMethods = new ArrayList/*<MethodDescriptor>*/(publicMethods); + //List/*<FieldDescriptor>*/ declaredFields = new ArrayList/*<FieldDescriptor>*/(publicFields); + Iterator<MethodDescriptor> methods = publicMethods.iterator(); + while (methods.hasNext()) { + MethodDescriptor method = methods.next(); + if (!Modifier.isPublic(method.getModifiers())) { + methods.remove(); + } + } + Iterator<FieldDescriptor> fields = publicFields.iterator(); + while (fields.hasNext()) { + FieldDescriptor field = fields.next(); + if (!Modifier.isPublic(field.getModifiers())) { + fields.remove(); + } + } + ClassDescriptor superclassDescriptor = ClassDescriptorLoader.getClassDescriptor(parser.superclass, classLoader); + publicMethods.addAll(Arrays.asList(superclassDescriptor.getMethodDescriptors())); + publicFields.addAll(Arrays.asList(superclassDescriptor.getFieldDescriptors())); + //Set<String> interfaces = new HashSet<String>(); + //ClassDescriptor[] superclassInterfaces = superclassDescriptor.getInterfaces(); + //for (ClassDescriptor superclassInterface : superclassInterfaces) { + //interfaces.add(superclassInterface.getName()); + //} + return new ClassDescriptor(parser.className, parser.packageName, parser.superclass, new String[0], false, false, null, null, classLoader, + publicMethods.toArray(new MethodDescriptor[publicMethods.size()]), + publicFields.toArray(new FieldDescriptor[publicFields.size()])) { + @Override + public FieldDescriptor getDeclaredFieldDescriptor(String name) throws NoSuchFieldException { + throw new NoSuchFieldException(name); + } + + @Override + public MethodDescriptor getDeclaredMethodDescriptor(String name, ClassDescriptor... parameterTypes) throws NoSuchMethodException { + throw new NoSuchMethodException(name); + } + }; + } + + + private void doParse(String displayName, Reader src) { + try { + JavaParser p = new JavaParser(src); + p.CompilationUnit(); + SimpleNode node = p.popNode(); + if (node != null) { + scanCompilationUnit(node); + return; + } + throw new CompilerException("Internal error: null node parsing Java file from " + src); + } + catch (ParseException e) { + throw new CompilerException("Error parsing Java source code " + displayName + ": " + e.getMessage()); + } + } + + + private void scanCompilationUnit(SimpleNode node) { + for (int i = 0; i < node.jjtGetNumChildren(); i++) { + SimpleNode child = node.getChild(i); + int nodeType = child.getId(); + if (nodeType == JavaParserTreeConstants.JJTPACKAGEDECLARATION) { + packageName = child.getChild(1).getText().trim(); + compiler.addImport(packageName + ".*"); + } else + if (nodeType == JavaParserTreeConstants.JJTIMPORTDECLARATION) { + String text = child.getText().trim(); + if (text.startsWith("import")) { + text = text.substring("import".length()).trim(); + } + if (text.endsWith(";")) { + text = text.substring(0, text.length() - 1); + } + compiler.addImport(text); + } else if (nodeType == JavaParserTreeConstants.JJTTYPEDECLARATION) { + scanCompilationUnit(child); + } else + if (nodeType == JavaParserTreeConstants.JJTCLASSORINTERFACEDECLARATION) { + scanClass(child); + } + } + } + + + // scans the main ClassOrInterfaceDeclaration + private void scanClass(SimpleNode node) { + boolean isInterface = node.firstToken.image.equals("interface"); + className = node.firstToken.next.image; + if (packageName != null) { + className = packageName + "." + className; + } + for (int i = 0; i < node.jjtGetNumChildren(); i++) { + SimpleNode child = node.getChild(i); + int nodeType = child.getId(); + if (nodeType == JavaParserTreeConstants.JJTEXTENDSLIST) { + if (!isInterface) { + assert child.jjtGetNumChildren() == 1 : "expected ExtendsList to have exactly one child for a non-interface class"; + String rawName = child.getChild(0).getText().trim(); + superclass = TagManager.resolveClassName(rawName, compiler); + if (superclass == null) { + throw new CompilerException("Could not find class: " + rawName); + } + } + } else + if (nodeType == JavaParserTreeConstants.JJTCLASSORINTERFACEBODY) { + scanClassNode(child); + } + } + } + + + // scans class body nodes + private void scanClassNode(SimpleNode node) { + int nodeType = node.getId(); + if (nodeType == JavaParserTreeConstants.JJTMETHODDECLARATION) { + String returnType = null; + String name = null; + List<String> parameterTypes = new ArrayList<String>(); + //List<String> parameterNames = new ArrayList<String>(); + for (int i = 0; i < node.jjtGetNumChildren(); i++) { + SimpleNode child = node.getChild(i); + int type = child.getId(); + if (type == JavaParserTreeConstants.JJTRESULTTYPE) + returnType = TagManager.resolveClassName(child.getText().trim(), compiler); + else if (type == JavaParserTreeConstants.JJTMETHODDECLARATOR) { + name = child.firstToken.image.trim(); + SimpleNode formalParameters = child.getChild(0); + assert formalParameters.getId() == JavaParserTreeConstants.JJTFORMALPARAMETERS; + for (int j = 0; j < formalParameters.jjtGetNumChildren(); j++) + { + SimpleNode parameter = formalParameters.getChild(j); + String rawParameterType = parameter.getChild(1).getText().trim().replaceAll("\\.\\.\\.", "[]"); + String parameterType = TagManager.resolveClassName(rawParameterType, compiler); + if (parameterType == null && JAXXCompiler.STRICT_CHECKS) { + throw new CompilerException("could not find class '" + rawParameterType + "'"); + } + parameterTypes.add(parameterType); + //parameterNames.add(parameter.getChild(2).getText().trim()); + } + } + } + methods.add(new MethodDescriptor(name, Modifier.PUBLIC, returnType, parameterTypes.toArray(new String[parameterTypes.size()]), compiler.getClassLoader())); // TODO: determine the actual modifiers + } else + if (nodeType == JavaParserTreeConstants.JJTCLASSORINTERFACEDECLARATION) { + // TODO: handle inner classes + } else + if (nodeType == JavaParserTreeConstants.JJTCONSTRUCTORDECLARATION) { + // TODO: handle constructors + } else if (nodeType == JavaParserTreeConstants.JJTFIELDDECLARATION) { + String text = node.getText(); + String declaration = text; + int equals = text.indexOf("="); + if (equals != -1) { + declaration = declaration.substring(0, equals); + } + declaration = declaration.trim(); + String[] declarationTokens = declaration.split("\\s"); + //boolean isFinal = Arrays.asList(declarationTokens).contains("final"); + //boolean isStatic = Arrays.asList(declarationTokens).contains("static"); + String name = declarationTokens[declarationTokens.length - 1]; + if (name.endsWith(";")) { + name = name.substring(0, name.length() - 1).trim(); + } + String className = declarationTokens[declarationTokens.length - 2]; + String type = TagManager.resolveClassName(className, compiler); + fields.add(new FieldDescriptor(name, Modifier.PUBLIC, type, compiler.getClassLoader())); // TODO: determine the actual modifiers + } else { + for (int i = 0; i < node.jjtGetNumChildren(); i++) { + SimpleNode child = node.getChild(i); + scanClassNode(child); + } + } + } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/reflect/MemberDescriptor.java b/trunk/jaxx-compiler/src/main/java/jaxx/reflect/MemberDescriptor.java new file mode 100644 index 0000000..0ced5d7 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/reflect/MemberDescriptor.java @@ -0,0 +1,40 @@ +package jaxx.reflect; + +/** + * Mirrors the class <code>java.lang.ref.Member</code>. JAXX uses <code>ClassDescriptor</code> instead of <code>Class</code> + * almost everywhere so that it can handle circular dependencies (there can't be a <code>Class</code> object for an uncompiled + * JAXX or Java source file, and a compiler must be allow references to symbols in uncompiled source files in order to handle + * circular dependencies). + */ +public abstract class MemberDescriptor { + private String name; + private int modifiers; + private ClassLoader classLoader; + + + MemberDescriptor(String name, int modifiers, ClassLoader classLoader) { + this.name = name; + this.modifiers = modifiers; + this.classLoader = classLoader; + } + + + public String getName() { + return name; + } + + + public int getModifiers() { + return modifiers; + } + + + protected ClassLoader getClassLoader() { + return classLoader; + } + + @Override + public String toString() { + return getClass().getName() + "[" + getName() + "]"; + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/reflect/MethodDescriptor.java b/trunk/jaxx-compiler/src/main/java/jaxx/reflect/MethodDescriptor.java new file mode 100644 index 0000000..2b0a9c2 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/reflect/MethodDescriptor.java @@ -0,0 +1,54 @@ +package jaxx.reflect; + +import jaxx.compiler.JAXXCompiler; + +/** + * Mirrors the class <code>java.lang.ref.Method</code>. JAXX uses <code>ClassDescriptor</code> instead of <code>Class</code> + * almost everywhere so that it can handle circular dependencies (there can't be a <code>Class</code> object for an uncompiled + * JAXX or Java source file, and a compiler must be allow references to symbols in uncompiled source files in order to handle + * circular dependencies). + */ +public class MethodDescriptor extends MemberDescriptor { + private String returnType; + private String[] parameterTypes; + + + public MethodDescriptor(String name, int modifiers, String returnType, String[] parameterTypes, ClassLoader classLoader) { + super(name, modifiers, classLoader); + this.returnType = returnType; + this.parameterTypes = parameterTypes; + if (JAXXCompiler.STRICT_CHECKS && java.util.Arrays.asList(parameterTypes).contains(null)) { + throw new NullPointerException(name); + } + } + + + public ClassDescriptor getReturnType() { + try { + //TC 20090228 : fix bug when no return type defined (constructor method) + if (returnType == null) { + return null; + } + return ClassDescriptorLoader.getClassDescriptor(returnType); + } + catch (ClassNotFoundException e) { + throw new RuntimeException("could not find return type " + returnType, e); + } + } + + + public ClassDescriptor[] getParameterTypes() { + ClassDescriptor[] result = new ClassDescriptor[parameterTypes.length]; + try { + for (int i = 0; i < result.length; i++) { + if (parameterTypes[i] != null) { + result[i] = ClassDescriptorLoader.getClassDescriptor(parameterTypes[i], getClassLoader()); + } + } + return result; + } + catch (ClassNotFoundException e) { + throw new RuntimeException("could not find the parameter types " + java.util.Arrays.toString(parameterTypes), e); + } + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/spi/Initializer.java b/trunk/jaxx-compiler/src/main/java/jaxx/spi/Initializer.java new file mode 100644 index 0000000..af4f2b4 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/spi/Initializer.java @@ -0,0 +1,15 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.spi; + +/** + * Performs SPI initialization, typically to register new tags, beans and converter. + * <p/> + * <b>Note:</b> To load such Initializer, we use the {@link java.util.ServiceLoader} mecanism. + */ +public interface Initializer { + /** Performs SPI initialization, typically to register new tags, beans and converter */ + void initialize(); +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/DefaultComponentHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/DefaultComponentHandler.java new file mode 100644 index 0000000..4b68988 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/DefaultComponentHandler.java @@ -0,0 +1,322 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags; + +import jaxx.CompilerException; +import jaxx.UnsupportedAttributeException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.I18nHelper; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.w3c.dom.Element; + +import java.awt.Component; +import java.awt.Container; +import java.awt.event.ComponentListener; +import java.awt.event.ContainerListener; +import java.awt.event.FocusListener; +import java.beans.IntrospectionException; +import java.io.IOException; +import java.lang.reflect.Field; +import org.w3c.dom.Attr; +import org.w3c.dom.NamedNodeMap; + +public class DefaultComponentHandler extends DefaultObjectHandler { + + /** log */ + protected static final Log log = LogFactory.getLog(DefaultComponentHandler.class); + private String containerDelegate; + + public DefaultComponentHandler(ClassDescriptor beanClass) { + super(beanClass); + ClassDescriptorLoader.checkSupportClass(getClass(), beanClass, Component.class); + } + + @Override + protected void init() throws IntrospectionException { + if (jaxxBeanInfo == null) { + super.init(); + + containerDelegate = (String) getJAXXBeanInfo().getJAXXBeanDescriptor().getValue("containerDelegate"); + if (containerDelegate == null && ClassDescriptorLoader.getClassDescriptor(Container.class).isAssignableFrom(getBeanClass().getSuperclass())) { + containerDelegate = ((DefaultComponentHandler) TagManager.getTagHandler(getBeanClass().getSuperclass())).getContainerDelegate(); + } + } + } + + @Override + protected void configureProxyEventInfo() { + super.configureProxyEventInfo(); + addProxyEventInfo("hasFocus", FocusListener.class); + addProxyEventInfo("isVisible", ComponentListener.class); + addProxyEventInfo("getBounds", ComponentListener.class); + addProxyEventInfo("getLocation", ComponentListener.class); + addProxyEventInfo("getLocationOnScreen", ComponentListener.class); + addProxyEventInfo("getSize", ComponentListener.class); + addProxyEventInfo("getX", ComponentListener.class); + addProxyEventInfo("getY", ComponentListener.class); + addProxyEventInfo("getWidth", ComponentListener.class); + addProxyEventInfo("getHeight", ComponentListener.class); + if (ClassDescriptorLoader.getClassDescriptor(Container.class).isAssignableFrom(getBeanClass())) { + addProxyEventInfo("getComponentCount", ContainerListener.class); + } + } + + @Override + protected void setDefaults(CompiledObject object, Element tag, JAXXCompiler compiler) throws CompilerException { + super.setDefaults(object, tag, compiler); + setAttribute(object, "name", object.getId(), false, compiler); + openComponent(object, tag, compiler); + } + + @Override + public void compileFirstPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + super.compileFirstPass(tag, compiler); + } + + @Override + public void compileSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + super.compileSecondPass(tag, compiler); + closeComponent(compiler.getOpenComponent(), tag, compiler); + } + + protected void openComponent(CompiledObject object, Element tag, JAXXCompiler compiler) throws CompilerException { + String constraints = tag.getAttribute("constraints"); + if (constraints != null && constraints.length() > 0) { + compiler.openComponent(object, constraints); + } else { + compiler.openComponent(object); + } + } + + protected void closeComponent(CompiledObject object, Element tag, JAXXCompiler compiler) throws CompilerException { + compiler.closeComponent(object); + } + + @Override + public boolean isPropertyInherited(String property) throws UnsupportedAttributeException { + return property.equals("font") || property.startsWith("font-") || property.equals("foreground") || property.equals("enabled"); + } + + @Override + public ClassDescriptor getPropertyType(CompiledObject object, String propertyName, JAXXCompiler compiler) throws CompilerException { + if (propertyName.equals("x") || propertyName.equals("y") || propertyName.equals("width") || propertyName.equals("height") || + "font-size".equals(propertyName)) { + return ClassDescriptorLoader.getClassDescriptor(Integer.class); + } + if (propertyName.equals("font-face") || propertyName.equals("font-style") || propertyName.equals("font-weight")) { + return ClassDescriptorLoader.getClassDescriptor(String.class); + } + return super.getPropertyType(object, propertyName, compiler); + } + + @Override + public String getGetPropertyCode(String id, String name, JAXXCompiler compiler) throws CompilerException { + if (name.equals("font-face")) { + return id + ".getFont().getFontName()"; + } + if (name.equals("font-size")) { + return id + ".getFont().getSize()"; + } + if (name.equals("font-weight")) { + return "(" + id + ".getFont().getStyle() & Font.BOLD) != 0 ? \"bold\" : \"normal\""; + } + if (name.equals("font-style")) { + return "(" + id + ".getFont().getStyle() & Font.ITALIC) != 0 ? \"italic\" : \"normal\""; + } + return super.getGetPropertyCode(id, name, compiler); + } + + @Override + public String getSetPropertyCode(String id, String name, String valueCode, JAXXCompiler compiler) throws CompilerException { + if (name.equals("x")) { + return id + ".setLocation(" + valueCode + ", " + id + ".getY());"; + } + if (name.equals("y")) { + return id + ".setLocation(" + id + ".getX(), " + valueCode + ");"; + } + if (name.equals("width")) { // need to optimize case when both width and height are being assigned + return "jaxx.runtime.Util.setComponentWidth(" + id + "," + valueCode + ");\n"; + } + if (name.equals("height")) { + return "jaxx.runtime.Util.setComponentHeight(" + id + "," + valueCode + ");\n"; + } + if (name.equals("font-face")) { + return "if (" + id + ".getFont() != null) " + id + ".setFont(new Font(" + valueCode + ", " + id + ".getFont().getStyle(), " + id + ".getFont().getSize()));"; + } + if (name.equals("font-size")) { + return "if (" + id + ".getFont() != null) " + id + ".setFont(" + id + ".getFont().deriveFont((float) " + valueCode + "));"; + } + if (name.equals("font-weight")) { + if (valueCode.equals("\"bold\"")) { + return "if (" + id + ".getFont() != null) " + id + ".setFont(" + id + ".getFont().deriveFont(" + id + ".getFont().getStyle() | Font.BOLD));"; + } + if (valueCode.equals("\"normal\"")) { + return "if (" + id + ".getFont() != null) " + id + ".setFont(" + id + ".getFont().deriveFont(" + id + ".getFont().getStyle() & ~Font.BOLD));"; + } + if (!valueCode.startsWith("\"")) { + return "if (" + id + ".getFont() != null) { if ((" + valueCode + ").equals(\"bold\")) " + + id + ".setFont(" + id + ".getFont().deriveFont(" + id + ".getFont().getStyle() | Font.BOLD)); else " + + id + ".setFont(" + id + ".getFont().deriveFont(" + id + ".getFont().getStyle() & ~Font.BOLD)); }"; + } + compiler.reportError("font-weight must be either \"normal\" or \"bold\", found " + valueCode); + return ""; + } + if (name.equals("font-style")) { + if (valueCode.equals("\"italic\"")) { + return "if (" + id + ".getFont() != null) " + id + ".setFont(" + id + ".getFont().deriveFont(" + id + ".getFont().getStyle() | Font.ITALIC));"; + } + if (valueCode.equals("\"normal\"")) { + return "if (" + id + ".getFont() != null) " + id + ".setFont(" + id + ".getFont().deriveFont(" + id + ".getFont().getStyle() & ~Font.ITALIC));"; + } + if (!valueCode.startsWith("\"")) { + return "if (" + id + ".getFont() != null) { if ((" + valueCode + ").equals(\"italic\")) " + + id + ".setFont(" + id + ".getFont().deriveFont(" + id + ".getFont().getStyle() | Font.ITALIC)); else " + + id + ".setFont(" + id + ".getFont().deriveFont(" + id + ".getFont().getStyle() & ~Font.ITALIC)); }"; + } + compiler.reportError("font-style must be either \"normal\" or \"italic\", found " + valueCode); + return ""; + } + if (ClassDescriptorLoader.getClassDescriptor(Container.class).isAssignableFrom(getBeanClass()) && name.equals("layout")) { // handle containerDelegate (e.g. contentPane on JFrame) + String containerDelegate = (String) getJAXXBeanInfo().getJAXXBeanDescriptor().getValue("containerDelegate"); + if (containerDelegate != null) { + return id + '.' + containerDelegate + "().setLayout(" + valueCode + ");"; + } + } + // ajout du support i18n + if (I18nHelper.isI18nableAttribute(name, compiler)) { + valueCode = I18nHelper.addI18nInvocation(id, name, valueCode, compiler); + } + + return super.getSetPropertyCode(id, name, valueCode, compiler); + } + + @Override + public void setAttribute(CompiledObject object, String propertyName, String stringValue, boolean inline, JAXXCompiler compiler) { + + if (propertyName.startsWith("_")) { + // client property + if (stringValue.startsWith("{")) { + stringValue = stringValue.substring(1, stringValue.length() - 1); + } + object.addClientProperty(propertyName.substring(1), stringValue); + //TC-20090327 rather not generating code here + //object.appendAdditionCode(object.getJavaCode() + ".putClientProperty(\"" + propertyName.substring(1) + "\", " + stringValue + ");"); + return; + } + if ("icon".equals(propertyName)) { + if (!(stringValue.startsWith("{") || stringValue.endsWith("}"))) { + // this is a customized icon, add the icon creation code + if (compiler.getOptions().isUseUIManagerForIcon()) { + stringValue = "{" + jaxx.runtime.Util.class.getName() + ".getUIManagerIcon(\"" + stringValue + "\")}"; + } else { + stringValue = "{" + jaxx.runtime.Util.class.getName() + ".createImageIcon(\"" + stringValue + "\")}"; + } + } + } else if ("actionIcon".equals(propertyName)) { + // customized actionIcon property + if (stringValue.startsWith("{") && stringValue.endsWith("}")) { + // there is a script to define the action icon, this is forbidden + compiler.reportError("the actionIcon does not support script, remove braces..., fix the file " + compiler.getOutputClassName()); + return; + } + propertyName = "icon"; + if (compiler.getOptions().isUseUIManagerForIcon()) { + stringValue = "{" + jaxx.runtime.Util.class.getName() + ".getUIManagerActionIcon(\"" + stringValue + "\")}"; + } else { + stringValue = "{" + jaxx.runtime.Util.class.getName() + ".createActionIcon(\"" + stringValue + "\")}"; + } + } + super.setAttribute(object, propertyName, stringValue, inline, compiler); + } + + @Override + protected void scanAttributesForDependencies(Element tag, JAXXCompiler compiler) { + super.scanAttributesForDependencies(tag, compiler); + // check for clientProperty attributes + //FIXME make this works,... it seems jaxx compiler does not come here ? + //FIXME see the the firstPassHandler in JAXXCompiler ? + NamedNodeMap children = tag.getAttributes(); + for (int i = 0, max = children.getLength(); i < max; i++) { + Attr attr = (Attr) children.item(i); + String name = attr.getName(); + if (!name.startsWith("_")) { + continue; + } + String value = attr.getValue(); + if (value.startsWith("{")) { + compiler.reportWarning(tag, "an clientProperty attribute " + name.substring(1) + " does not required curly value but was : " + value, 0); + } + } + + } + + /** + * Maps string values onto integers, so that int-valued enumeration properties can be specified by strings. For + * example, when passed a key of 'alignment', this method should normally map the values 'left', 'center', and + * 'right' onto SwingConstants.LEFT, SwingConstants.CENTER, and SwingConstants.RIGHT respectively. + * <p/> + * You do not normally need to call this method yourself; it is invoked by {@link #convertFromString} when an + * int-valued property has a value which is not a valid number. By default, this method looks at the + * <code>enumerationValues</code> value of the <code>JAXXPropertyDescriptor</code>. + * + * @param key the name of the int-typed property + * @param value the non-numeric value that was specified for the property + * @throws IllegalArgumentException if the property is an enumeration, but the value is not valid + * @throws NumberFormatException if the property is not an enumeration + */ + @Override + protected int constantValue(String key, String value) { + if ((key.equals("mnemonic") || key.equals("displayedMnemonic"))) { + if (value.length() == 1) { + return value.charAt(0); + } + try { + Field vk = java.awt.event.KeyEvent.class.getField(value); + return (Integer) vk.get(null); + } catch (NoSuchFieldException e) { + throw new IllegalArgumentException("mnemonics must be either a single character or the name of a field in KeyEvent (found: '" + value + "')"); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + return super.constantValue(key, value); + } + + /** + * Returns <code>true</code> if this component can contain other components. For children to be + * allowed, the component must be a subclass of <code>Container</code> and its <code>JAXXBeanInfo</code> + * must not have the value <code>false</code> for its <code>isContainer</code> value. + * + * @return <code>true</code> if children are allowed + */ + public boolean isContainer() { + boolean container = ClassDescriptorLoader.getClassDescriptor(Container.class).isAssignableFrom(getBeanClass()); + if (container) { + try { + init(); + if (Boolean.FALSE.equals(getJAXXBeanInfo().getJAXXBeanDescriptor().getValue("isContainer"))) { + container = false; + } + } catch (IntrospectionException e) { + throw new RuntimeException(e); + } + } + return container; + } + + public String getContainerDelegate() { + try { + init(); + return containerDelegate; + } catch (IntrospectionException e) { + throw new RuntimeException(e); + } + + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/DefaultObjectHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/DefaultObjectHandler.java new file mode 100644 index 0000000..584b771 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/DefaultObjectHandler.java @@ -0,0 +1,1184 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags; + +import jaxx.CompilerException; +import jaxx.UnsupportedAttributeException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.compiler.JavaArgument; +import jaxx.compiler.JavaMethod; +import jaxx.css.Stylesheet; +import jaxx.css.StylesheetHelper; +import jaxx.introspection.JAXXBeanInfo; +import jaxx.introspection.JAXXEventSetDescriptor; +import jaxx.introspection.JAXXIntrospector; +import jaxx.introspection.JAXXPropertyDescriptor; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.reflect.FieldDescriptor; +import jaxx.reflect.MethodDescriptor; +import jaxx.runtime.ComponentDescriptor; +import jaxx.runtime.JAXXObject; +import jaxx.runtime.JAXXObjectDescriptor; +import jaxx.types.TypeManager; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; + +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyChangeListener; +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; +import jaxx.compiler.CompiledObjectDecorator; + +/** + * Default handler for class tags. Class tags are tags which represent instances of Java classes, + * such as <code><JButton label='Close'/></code>. <code>DefaultObjectHandler</code> + * provides support for attributes and events which adhere to JavaBeans naming conventions as + * well as basic JAXX features like the <code>id</code> attribute and data binding by means of + * curly braces. + * <p/> + * Throughout this class, the word "member" refers to the name of a field or method (e.g. + * <code>"getDocument"</code>) and the word "property" refers to the JavaBeans-style simple + * name of a property (e.g. <code>"document"</code>). + */ +public class DefaultObjectHandler implements TagHandler { + /** The class that this handler provides support for. */ + private ClassDescriptor beanClass; + + /** The JAXXBeanInfo for the beanClass. */ + protected JAXXBeanInfo jaxxBeanInfo; + + /** Maps property names to their respective JAXXPropertyDescriptors. */ + private Map<String, JAXXPropertyDescriptor> properties; + + /** Maps event names to their respective JAXXEventSetDescriptors. */ + private Map<String, JAXXEventSetDescriptor> events; + + /** Maps property names to their respective ProxyEventInfos. */ + private Map<String, ProxyEventInfo> eventInfos; + + /** Maps XML tags to the CompiledObjects created from them. */ + protected static Map<Element, CompiledObject> objectMap = new WeakHashMap<Element, CompiledObject>(); + + /** + * Encapsulates information about a "proxy event handler", which is an event handler that + * fires PropertyChangeEvents when it is triggered. ProxyEventInfos simplify the data binding + * system by allowing all dependencies to fire the same kind of event even if they would + * normally throw something else, like <code>DocumentEvent</code>. + */ + private class ProxyEventInfo { + /** The name of the method or field being proxied, e.g. "getText". */ + String memberName; + + /** The "actual" event listener for the property in question, e.g. DocumentListener. */ + ClassDescriptor listenerClass; + + /** + * In cases where a different object (such as a model) is more directly responsible for + * managing the property, this is the name of the property where that object can be + * found, e.g. "document" (which is turned into a call to "getDocument()"). This property + * is also treated as a dependency of the data binding expression, and any updates to it + * (assuming it is bound) will cause the listener to be removed from the old value and + * attached to the new value, and the data binding to be processed. + */ + String modelName; + + /** The name of the method used to add the "native" event listener, e.g. "addDocumentListener". */ + String addMethod; + + /** The name of the method used to remove the "native" event listener, e.g. "removeDocumentListener". */ + String removeMethod; + } + + + /** + * Creates a new <code>DefaultObjectHandler</code> which provides support for the specified class. The + * class is not actually introspected until the {@link #compileFirstPass} method is invoked. + * + * @param beanClass the class which this handler supports + */ + public DefaultObjectHandler(ClassDescriptor beanClass) { + this.beanClass = beanClass; + } + + + /** + * Performs introspection on the beanClass and stores the results. + * + * @throws java.beans.IntrospectionException + * TODO + */ + protected void init() throws IntrospectionException { + if (jaxxBeanInfo == null) { + // perform introspection & cache the results + jaxxBeanInfo = getJAXXBeanInfo(beanClass); + + JAXXPropertyDescriptor[] propertiesArray = jaxxBeanInfo.getJAXXPropertyDescriptors(); + properties = new HashMap<String, JAXXPropertyDescriptor>(); + for (int i = propertiesArray.length - 1; i >= 0; i--) { + properties.put(propertiesArray[i].getName(), propertiesArray[i]); + } + + JAXXEventSetDescriptor[] eventsArray = jaxxBeanInfo.getJAXXEventSetDescriptors(); + events = new HashMap<String, JAXXEventSetDescriptor>(); + for (int i = eventsArray.length - 1; i >= 0; i--) { + MethodDescriptor[] methods = eventsArray[i].getListenerMethods(); + for (MethodDescriptor method : methods) { + events.put(method.getName(), eventsArray[i]); + } + } + + configureProxyEventInfo(); + } + } + + + /** + * Returns + * + * @return the class which this <code>DefaultObjectHandler</code> supports. + */ + public ClassDescriptor getBeanClass() { + return beanClass; + } + + + /** + * @return the <code>JAXXBeanInfo</code> for the class which this <code>DefaultObjectHandler</code> + * supports. + */ + public JAXXBeanInfo getJAXXBeanInfo() { + try { + init(); + } catch (IntrospectionException e) { + throw new RuntimeException(e); + } + return jaxxBeanInfo; + } + + + /** + * Returns the <code>JAXXBeanInfo</code> for the specified class. + * + * @param beanClass the bean class for which to retrieve <code>JAXXBeanInfo</code> + * @return the class' <code>JAXXBeanInfo</code> + * @throws java.beans.IntrospectionException + * ? + */ + public static JAXXBeanInfo getJAXXBeanInfo(ClassDescriptor beanClass) throws IntrospectionException { + return JAXXIntrospector.getJAXXBeanInfo(beanClass); + } + + + /** + * Returns the type of the named property. This is the return type of the property's <code>get</code> method; + * for instance <code>JLabel</code>'s <code>text</code> property is a <code>String</code>. + * + * @param object the object being compiled + * @param propertyName the simple JavaBeans-style name of the property + * @param compiler the current <code>JAXXCompiler</code> + * @return the property's type + * @throws CompilerException if the type cannot be determined + */ + public ClassDescriptor getPropertyType(CompiledObject object, String propertyName, JAXXCompiler compiler) { + try { + init(); + } catch (IntrospectionException e) { + throw new RuntimeException(e); + } + + JAXXPropertyDescriptor property = properties.get(propertyName); + if (property != null) { + return property.getPropertyType(); + } + throw new UnsupportedAttributeException("property '" + propertyName + "' not found in " + object); + } + + + /** + * @param name ? + * @return <code>true</code> if the named member is <i>bound</i> (fires <code>PropertyChangeEvent</code> + * when modified). Members are either fields (represented by the simple name of the field) or <code>get/is</code> + * methods (represented by the simple name of the method, <b>not</b> the simplified JavaBeans-style name). + * Methods which are not actually bound in their native class, but for which proxy events have been + * configured (such as <code>JTextField.getText</code>, return <code>true</code>. + * @throws jaxx.UnsupportedAttributeException + * ? + */ + public boolean isMemberBound(String name) throws UnsupportedAttributeException { + try { + init(); + } catch (IntrospectionException e) { + throw new RuntimeException(e); + } + + if (eventInfos != null && eventInfos.containsKey(name)) { + return true; + } + + if (name.equals("getClass")) { + return false; + } + + String propertyName = null; + if (name.startsWith("get")) { + propertyName = Introspector.decapitalize(name.substring("get".length())); + } else if (name.startsWith("is")) { + propertyName = Introspector.decapitalize(name.substring("is".length())); + } + JAXXPropertyDescriptor property = propertyName != null ? properties.get(propertyName) : null; + if (property != null) { + return property.isBound(); + } + try { + FieldDescriptor field = getBeanClass().getFieldDescriptor(name); + return Modifier.isFinal(field.getModifiers()); // final fields might as well be considered bound -- they can't be modified anyway + } catch (NoSuchFieldException e) { + throw new UnsupportedAttributeException("cannot find property '" + name + "' of " + getBeanClass()); + } + } + + + private static ClassDescriptor getEventClass(ClassDescriptor listenerClass) { + return listenerClass.getMethodDescriptors()[0].getParameterTypes()[0]; + } + + + /** + * @param memberName name of the member + * @return an array of members on which the given property depends. For + * example, the JTextField.getText() member depends upon the getModel() + * member. Returns <code>null</code> if there are no dependencies. + */ + public String[] getMemberDependencies(String memberName) { + ProxyEventInfo eventInfo = eventInfos != null ? eventInfos.get(memberName) : null; + return eventInfo == null ? null : new String[]{eventInfo.modelName}; + } + + + /** + * Returns a snippet of Java code which will cause a <code>PropertyChangeListener</code> to be notified + * when the member's value changes. The <code>PropertyChangeListener</code> is provided in the form + * of a Java code snippet that evaluates to a listener object. + * <p/> + * For ordinary bound JavaBeans properties, the Java code returned is a simple call to + * <code>addPropertyChangeListener</code>. Fields and methods which do not actually fire + * <code>PropertyChangeEvents</code> when they change necessitate more complex code. + * + * @param objectCode Java code which evaluates to the object to which to add the listener + * *@param dataBinding the name of the data binding this listener is a part of + * @param dataBinding databinding + * @param memberName the name of the field or method to listen to + * @param propertyChangeListenerCode Java code which evaluates to a <code>PropertyChangeListener</code> + * @param compiler the current <code>JAXXCompiler</code> + * @return Java code snippet which causes the listener to be added to the object + */ + public String getAddMemberListenerCode(String objectCode, String dataBinding, String memberName, String propertyChangeListenerCode, JAXXCompiler compiler) { + if ("getClass".equals(memberName)) { + return null; + } + + ProxyEventInfo eventInfo = eventInfos != null ? eventInfos.get(memberName) : null; + if (eventInfo != null) { // a "proxied" event is one that doesn't fire PropertyChangeEvent, so we need to convert its native event type into PropertyChangeEvents + StringBuffer result = new StringBuffer(); + String methodName = "$pr" + compiler.getUniqueId(propertyChangeListenerCode); + boolean methodExists = compiler.hasMethod(methodName); + ClassDescriptor eventClass = getEventClass(eventInfo.listenerClass); + if (!methodExists) { + compiler.addMethodToJavaFile(new JavaMethod(Modifier.PUBLIC, "void", methodName, + new JavaArgument[]{new JavaArgument(JAXXCompiler.getCanonicalName(eventClass), "event")}, null, + propertyChangeListenerCode + ".propertyChange(null);")); + } + String code = objectCode + (eventInfo.modelName != null ? ".get" + org.apache.commons.lang.StringUtils.capitalize(eventInfo.modelName) + "()" : ""); + result.append("$bindingSources.put(\"").append(code).append("\", ").append(code).append(");").append(JAXXCompiler.getLineSeparator()); + result.append(code).append('.').append(eventInfo.addMethod).append("((").append(JAXXCompiler.getCanonicalName(eventInfo.listenerClass)).append(") jaxx.runtime.Util.getEventListener(").append(JAXXCompiler.getCanonicalName(eventInfo.listenerClass)).append(".class, ").append(compiler.getRootObject().getJavaCode()).append(", ").append(TypeManager.getJavaCode(methodName)).append("));\n"); + if (eventInfo.modelName != null) { + result.append(getAddMemberListenerCode(objectCode, dataBinding, "get" + org.apache.commons.lang.StringUtils.capitalize(eventInfo.modelName), + "jaxx.runtime.Util.getDataBindingUpdateListener(this , \"" + dataBinding + "\")", + compiler)); + } + return result.toString(); + } else { + String propertyName = null; + if (memberName.startsWith("get")) { + propertyName = Introspector.decapitalize(memberName.substring("get".length())); + } else if (memberName.startsWith("is")) { + propertyName = Introspector.decapitalize(memberName.substring("is".length())); + } else { + try { + getBeanClass().getFieldDescriptor(memberName); + propertyName = memberName; + } catch (NoSuchFieldException e) { + // ignore ? + } + } + if (propertyName != null) { + try { + // check for property-specific addPropertyChangeListener method + getBeanClass().getMethodDescriptor("addPropertyChangeListener", ClassDescriptorLoader.getClassDescriptor(String.class), + ClassDescriptorLoader.getClassDescriptor(PropertyChangeListener.class)); + return objectCode + ".addPropertyChangeListener(\"" + propertyName + "\", " + propertyChangeListenerCode + ");\n"; + } catch (NoSuchMethodException e) { + // no property-specific method, use general one + return objectCode + ".addPropertyChangeListener(" + propertyChangeListenerCode + ");\n"; + } + } + return null; + } + } + + + public String getRemoveMemberListenerCode(String objectCode, String dataBinding, String memberName, String propertyChangeListenerCode, JAXXCompiler compiler) { + if ("getClass".equals(memberName)) { + return null; + } + + ProxyEventInfo eventInfo = eventInfos != null ? eventInfos.get(memberName) : null; + if (eventInfo != null) { // a "proxied" event is one that doesn't fire PropertyChangeEvent, so we need to convert its native event type into PropertyChangeEvents + StringBuffer result = new StringBuffer(); + String methodName = "$pr" + compiler.getUniqueId(propertyChangeListenerCode); + boolean methodExists = compiler.hasMethod(methodName); + if (!methodExists) { + ClassDescriptor eventClass = getEventClass(eventInfo.listenerClass); + compiler.addMethodToJavaFile(new JavaMethod(Modifier.PUBLIC, "void", methodName, + new JavaArgument[]{new JavaArgument(JAXXCompiler.getCanonicalName(eventClass), "event")}, null, + propertyChangeListenerCode + ".propertyChange(null);")); + } + try { + String modelMemberName = eventInfo.modelName != null ? "get" + org.apache.commons.lang.StringUtils.capitalize(eventInfo.modelName) : null; + String modelClassName = modelMemberName != null ? getBeanClass().getMethodDescriptor(modelMemberName).getReturnType().getName() : JAXXCompiler.getCanonicalName(getBeanClass()); + String code = objectCode + (eventInfo.modelName != null ? "." + modelMemberName + "()" : ""); + result.append("((").append(modelClassName).append(") $bindingSources.remove(\"").append(code).append("\")).").append(eventInfo.removeMethod).append("((").append(JAXXCompiler.getCanonicalName(eventInfo.listenerClass)).append(") jaxx.runtime.Util.getEventListener(").append(JAXXCompiler.getCanonicalName(eventInfo.listenerClass)).append(".class, ").append(compiler.getRootObject().getJavaCode()).append(", ").append(TypeManager.getJavaCode(methodName)).append("));\n"); + if (eventInfo.modelName != null) { + result.append(getRemoveMemberListenerCode(objectCode, dataBinding, "get" + org.apache.commons.lang.StringUtils.capitalize(eventInfo.modelName), + "jaxx.runtime.Util.getDataBindingUpdateListener(this, \"" + dataBinding + "\")", + compiler)); + } + return result.toString(); + } + catch (NoSuchMethodException e) { + throw new CompilerException("Internal error: " + e); + } + } else { + String propertyName = null; + if (memberName.startsWith("get")) { + propertyName = Introspector.decapitalize(memberName.substring("get".length())); + } else if (memberName.startsWith("is")) { + propertyName = Introspector.decapitalize(memberName.substring("is".length())); + } else { + try { + getBeanClass().getFieldDescriptor(memberName); + propertyName = memberName; + } catch (NoSuchFieldException e) { + // ignore ? + } + } + if (propertyName != null) { + try { + // check for property-specific removePropertyChangeListener method + getBeanClass().getMethodDescriptor("removePropertyChangeListener", ClassDescriptorLoader.getClassDescriptor(String.class), + ClassDescriptorLoader.getClassDescriptor(PropertyChangeListener.class)); + return objectCode + ".removePropertyChangeListener(\"" + propertyName + "\", " + propertyChangeListenerCode + ");\n"; + } catch (NoSuchMethodException e) { + // no property-specific method, use general one + return objectCode + ".removePropertyChangeListener(" + propertyChangeListenerCode + ");\n"; + } + } + return null; + } + } + + + /** + * Configures the event handling for members which do not fire <code>PropertyChangeEvent</code> when + * modified. The default implementation does nothing. Subclasses should override this method to call + * <code>addProxyEventInfo</code> for each member which requires special handling. + */ + protected void configureProxyEventInfo() { + } + + + /** + * Configures a proxy event handler which fires <code>PropertyChangeEvents</code> when a non-bound + * member is updated. This is necessary for all fields (which cannot be bound) and for methods that are + * not bound property <code>get</code> methods. The proxy event handler will attach the specified kind + * of listener to the class and fire a <code>PropertyChangeEvent</code> whenever the listener receives + * any kind of event. + * <p/> + * Even though this method can theoretically be applied to fields (in addition to methods), it would be an + * unusual situation in which that would actually work -- as fields cannot fire events when modified, it would + * be difficult to have a listener that was always notified when a field value changed. + * + * @param memberName the name of the field or method being proxied + * @param listenerClass the type of listener which receives events when the field or method is updated + */ + public void addProxyEventInfo(String memberName, Class listenerClass) { + addProxyEventInfo(memberName, listenerClass, null); + } + + + /** + * Configures a proxy event handler which fires <code>PropertyChangeEvents</code> when a non-bound + * member is updated. This is necessary for all fields (which cannot be bound) and for methods that are + * not bound property <code>get</code> methods. This variant attaches a listener to a property of the + * object (such as <code>model</code>) and not the object itself, which is useful when there is a model + * that is the "real" container of the information. The proxy event handler will attach the specified kind + * of listener to the property's value (retrieved using the property's <code>get</code> method) and fire + * a <code>PropertyChangeEvent</code> whenever the listener receives any kind of event. + * <p/> + * If the property is itself bound (typically the case with models), any updates to the property's value will + * cause the listener to be removed from the old property value and reattached to the new property value, + * as well as cause a <code>PropertyChangeEvent</code> to be fired. + * <p/> + * Even though this method can theoretically be applied to fields (in addition to methods), it would be an + * unusual situation in which that would actually work -- as fields cannot fire events when modified, it would + * be difficult to have a listener that was always notified when a field value changed. + * + * @param memberName the name of the field or method being proxied + * @param listenerClass the type of listener which receives events when the field or method is updated + * @param modelName the JavaBeans-style name of the model property + */ + public void addProxyEventInfo(String memberName, Class listenerClass, String modelName) { + String listenerName = listenerClass.getName(); + listenerName = listenerName.substring(listenerName.lastIndexOf(".") + 1); + addProxyEventInfo(memberName, listenerClass, modelName, "add" + listenerName, "remove" + listenerName); + } + + + // TODO: remove this temporary method, complete switchover to ClassDescriptors + public void addProxyEventInfo(String memberName, Class listenerClass, + String modelName, String addMethod, String removeMethod) { + try { + addProxyEventInfo(memberName, ClassDescriptorLoader.getClassDescriptor(listenerClass.getName()), modelName, addMethod, removeMethod); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + + /** + * Configures a proxy event handler which fires <code>PropertyChangeEvents</code> when a non-bound + * member is updated. This is necessary for all fields (which cannot be bound) and for methods that are + * not bound property <code>get</code> methods. This variant attaches a listener to a property of the + * object (such as <code>model</code>) and not the object itself, which is useful when there is a model + * that is the "real" container of the information. The proxy event handler will attach the specified kind + * of listener to the property's value (retrieved using the property's <code>get</code> method) and fire + * a <code>PropertyChangeEvent</code> whenever the listener receives any kind of event. + * <p/> + * If the property is itself bound (typically the case with models), any updates to the property's value will + * cause the listener to be removed from the old property value and reattached to the new property value, + * as well as cause a <code>PropertyChangeEvent</code> to be fired. + * <p/> + * This variant of <code>addProxyEventInfo</code> allows the names of the methods that add and remove + * the event listener to be specified, in cases where the names are not simply <code>add<listenerClassName></code> + * and <code>remove<listenerClassName></code>. + * <p/> + * Even though this method can theoretically be applied to fields (in addition to methods), it would be an + * unusual situation in which that would actually work -- as fields cannot fire events when modified, it would + * be difficult to have a listener that was always notified when a field value changed. + * + * @param memberName the name of the field or method being proxied + * @param listenerClass the type of listener which receives events when the field or method is updated + * @param modelName the JavaBeans-style name of the model property + * @param addMethod add method name + * @param removeMethod remove method name + */ + public void addProxyEventInfo(String memberName, ClassDescriptor listenerClass, + String modelName, String addMethod, String removeMethod) { + ProxyEventInfo info = new ProxyEventInfo(); + info.memberName = memberName; + info.listenerClass = listenerClass; + info.modelName = modelName; + info.addMethod = addMethod; + info.removeMethod = removeMethod; + if (eventInfos == null) { + eventInfos = new HashMap<String, ProxyEventInfo>(); + } + eventInfos.put(memberName, info); + } + + + @Override + public void compileFirstPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + scanAttributesForDependencies(tag, compiler); + compileChildrenFirstPass(tag, compiler); + } + + + @Override + public void compileSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + try { + init(); + } catch (IntrospectionException e) { + throw new CompilerException(e); + } + CompiledObject object = objectMap.get(tag); + if (object == null) { + throw new IllegalStateException("unable to find CompiledObject associated with tag <" + tag.getTagName() + ">; should have been registered before second pass"); + } + compiler.checkOverride(object); + String constructorParams = tag.getAttribute("constructorParams"); + if (constructorParams != null && constructorParams.length() > 0) { + object.setConstructorParams(compiler.getScriptManager().trimScript(constructorParams)); + } + + setDefaults(object, tag, compiler); + setAttributes(object, tag, compiler); + if (object.getGenericTypesLength() > 0 && !(object == compiler.getRootObject() || object.isJavaBean())) { + // can ony be apply to root object or javaBean object + compiler.reportWarning("'genericType' attribute can only be found on root, or a javaBean object tag but was found on tag " + tag); + object.setGenericTypes(null); + return; + } + compileChildrenSecondPass(tag, compiler); + } + + + public void registerCompiledObject(Element tag, JAXXCompiler compiler) { + String id = tag.getAttribute("id"); + if (id == null || id.length() == 0) { + id = compiler.getAutoId(getBeanClass()); + } + CompiledObject object = createCompiledObject(id, compiler); + objectMap.put(tag, object); + String styleClass = tag.getAttribute("styleClass").trim(); + if (styleClass.length() > 0) { + object.setStyleClass(styleClass); + } + compiler.registerCompiledObject(object); + } + + + /** + * Creates the <code>CompiledObject</code> which will represent the object created by this <code>TagHandler</code>. + * + * @param id the <code>CompiledObject's</code> ID. + * @param compiler compiler to use + * @return the <code>CompiledObject</code> to use + */ + protected CompiledObject createCompiledObject(String id, JAXXCompiler compiler) { + return new CompiledObject(id, getBeanClass(), compiler); + } + + + /** + * Initializes the default settings of the object, prior to setting its attribute values. The default + * implementation does nothing. + * + * @param object the object to initialize + * @param tag the tag being compiled + * @param compiler the current <code>JAXXCompiler</code> + */ + protected void setDefaults(CompiledObject object, Element tag, JAXXCompiler compiler) { + } + + + /** + * @param property property name to test + * @return <code>true</code> if the specified property should be inherited by child components when specified + * via CSS. + * @throws jaxx.UnsupportedAttributeException + * ? + */ + public boolean isPropertyInherited(String property) throws UnsupportedAttributeException { + return false; + } + + + /** + * @param name name of event + * @return <code>true</code> if the specified name has the form of an event handler attribute + * (e.g. "onActionPerformed"). + */ + public boolean isEventHandlerName(String name) { + return name.length() > 2 && name.startsWith("on") && Character.isUpperCase(name.charAt(2)); + } + + + /** + * Scans all attributes for any dependency classes and adds them to the current compilation + * set. Called by <code>compileFirstPass()</code> (it is an error to add dependencies after + * pass 1 is complete). + * + * @param tag tag to scan + * @param compiler compiler to use + */ + protected void scanAttributesForDependencies(Element tag, JAXXCompiler compiler) { + List<Attr> attributes = new ArrayList<Attr>(); + NamedNodeMap children = tag.getAttributes(); + for (int i = 0; i < children.getLength(); i++) { + attributes.add((Attr) children.item(i)); + } + Collections.sort(attributes, getAttributeComparator()); + + for (Attr attribute : attributes) { + String name = attribute.getName(); + String value = attribute.getValue(); + if (name.equals("javaBean")) { + //compiler.preprocessScript(value); + continue; + } + if (name.equals("constraints") || isEventHandlerName(name)) { + compiler.preprocessScript(value); // adds dependencies as a side effect + } else if (name.equals("constructorParams")) { + for (String param : value.split("\\s*,\\s*")) { + compiler.preprocessScript(param); + } + } else if (value.startsWith("{") && value.endsWith("}")) { + compiler.preprocessScript(value.substring(1, value.length() - 1)); + } + } + } + + + /** + * Processes the attributes of an XML tag. Four kinds of attributes are supported: simple property values (of any + * datatype supported by {@link #convertFromString}), data binding expressions (attributes containing curly-brace + * pairs), event listeners (attributes starting with 'on', such as 'onActionPerformed'), and JAXX-defined properties + * such as 'id'. + * + * @param object the object to be modified + * @param tag the tag from which to pull attributes + * @param compiler the current <code>JAXXCompiler</code> + */ + public void setAttributes(CompiledObject object, Element tag, JAXXCompiler compiler) { + List<Attr> attributes = new ArrayList<Attr>(); + NamedNodeMap children = tag.getAttributes(); + for (int i = 0; i < children.getLength(); i++) { + attributes.add((Attr) children.item(i)); + } + Collections.sort(attributes, getAttributeComparator()); + + for (Attr attribute : attributes) { + String name = attribute.getName(); + String value = attribute.getValue().trim(); + if (name.equals("id") || name.equals("constraints") || name.equals("constructorParams") || name.equals("styleClass") || + name.startsWith("xmlns") || JAXXCompiler.JAXX_INTERNAL_NAMESPACE.equals(attribute.getNamespaceURI())) { + // ignore, already handled + continue; + } + if (name.equals("javaBean")) { + object.setJavaBean(true); + if (!value.isEmpty()) { + object.setJavaBeanInitCode(value); + } + continue; + } + if (name.equals("implements")) { + if (object != compiler.getRootObject()) { + // can ony be apply to root object + compiler.reportError("'implements' attribute can only be found on root tag but was found on tag " + tag); + return; + } + String[] interfaces = value.split(","); + compiler.setExtraInterfaces(interfaces); + continue; + } + + if (name.equals("abstract")) { + if (object != compiler.getRootObject()) { + // can ony be apply to root object + compiler.reportError("'abstract' attribute can only be found on root tag but was found on tag " + tag); + return; + } + compiler.setAbstractClass(true); + continue; + } + + if (name.equals("genericType")) { + //TC-20090313 check after all atributes been processed + if (object == compiler.getRootObject() ) { + compiler.setGenericType(value); + } else { + object.setGenericTypes(value.split(",")); + } + continue; + } + + if (name.equals("superGenericType")) { + if (object != compiler.getRootObject()) { + // can ony be apply to root object + compiler.reportError("'superGenericType' attribute can only be found on root tag but was found on tag " + tag); + return; + } + compiler.setSuperGenericType(value); + continue; + } + + if (name.equals("decorator")) { + if (!value.isEmpty()) { + CompiledObjectDecorator decorator = CompiledObjectDecorator.getDecorator(value); + object.setDecorator(decorator); + } + continue; + } + + if (isEventHandlerName(name)) { + // event handler + if (!value.endsWith(";")) { + value += ";"; + } + addEventHandler(object, Introspector.decapitalize(name.substring(2)), value, compiler); + continue; + } + // simple property + setAttribute(object, name, value, true, compiler); + } + } + + + /** + * Returns a <code>Comparator</code> which defines the ordering in which the tag's attributes should be processed. The + * default implementation sorts the attributes according to the order defined by the {@link #getAttributeOrdering} method. + * + * @return a <code>Comparator</code> defining the order of attribute processing + */ + protected Comparator<Attr> getAttributeComparator() { + return new Comparator<Attr>() { + @Override + public int compare(Attr a, Attr b) { + int aOrder = getAttributeOrdering(a); + int bOrder = getAttributeOrdering(b); + + return aOrder - bOrder; + } + }; + } + + + /** + * Returns the priority with which a particular attribute should be processed. Lower numbers should be processed before + * higher numbers. This value is used by the {@link #getAttributeComparator} method to define the sort ordering. + * + * @param attr the attribute to treate + * @return the attribute's priority + */ + protected int getAttributeOrdering(Attr attr) { + if (attr.getName().equals("displayedMnemonicIndex") || attr.getName().equals("displayedMnemonic") || attr.getName().equals("mnemonic")) { + return 1; + } + return 0; + } + + + public String getApplyPropertyOrDataBindingCode(CompiledObject object, String propertyName, String stringValue, JAXXCompiler compiler) { + ClassDescriptor type = getPropertyType(object, propertyName, compiler); + String binding = compiler.processDataBindings(stringValue, type); + if (binding != null) { + return ""; + } + try { + Class typeClass = type != null ? ClassDescriptorLoader.getClass(type.getName(), type.getClassLoader()) : null; + Object value = convertFromString(propertyName, stringValue, typeClass); + return getSetPropertyCode(object.getJavaCode(), propertyName, TypeManager.getJavaCode(value), compiler); + } catch (NumberFormatException e) { + compiler.reportError("could not convert literal string '" + stringValue + "' to type " + type.getName()); + } catch (IllegalArgumentException e) { + compiler.reportError("could not convert literal string '" + stringValue + "' to type " + type.getName()); + } catch (ClassNotFoundException e) { + compiler.reportError("could not find class " + type.getName()); + } + return ""; + } + + + /** + * Set a single property on an object. The value may be either a simple value or contain data binding expressions. + * Simple values are first converted to the property's type using {@link #convertFromString}. + * + * @param object the object on which to set the property + * @param propertyName the name of the property to set + * @param stringValue the raw string value of the property from the XML + * @param inline <code>true</code> if the value was directly specified as an inline class tag attribute, <code>false</code> otherwise (a default value, specified in CSS, etc.) + * @param compiler the current <code>JAXXCompiler</code> + */ + public void setAttribute(CompiledObject object, String propertyName, String stringValue, boolean inline, JAXXCompiler compiler) { + try { + if (ClassDescriptorLoader.getClassDescriptor(JAXXObject.class).isAssignableFrom(object.getObjectClass())) { + // check for data binding & remove if found + JAXXObjectDescriptor jaxxObjectDescriptor = object.getObjectClass().getJAXXObjectDescriptor(); + ComponentDescriptor root = jaxxObjectDescriptor.getComponentDescriptors()[0]; + object.appendInitializationCode(object.getJavaCode() + ".removeDataBinding(" + TypeManager.getJavaCode(root.getId() + "." + propertyName) + ");" + JAXXCompiler.getLineSeparator()); + } + object.addProperty(propertyName, stringValue); + ClassDescriptor type = getPropertyType(object, propertyName, compiler); + String binding = compiler.processDataBindings(stringValue, type); + if (binding != null) { + if (inline) { + compiler.addInlineStyle(object, propertyName, true); + } + ClassDescriptor propertyType = getPropertyType(object, propertyName, compiler); + if (propertyType != null && + propertyType != ClassDescriptorLoader.getClassDescriptor(Boolean.class) && + propertyType != ClassDescriptorLoader.getClassDescriptor(Byte.class) && + propertyType != ClassDescriptorLoader.getClassDescriptor(Short.class) && + propertyType != ClassDescriptorLoader.getClassDescriptor(Integer.class) && + propertyType != ClassDescriptorLoader.getClassDescriptor(Float.class) && + propertyType != ClassDescriptorLoader.getClassDescriptor(Double.class) && + propertyType != ClassDescriptorLoader.getClassDescriptor(Character.class)) { + //binding = "((" + propertyType.getName() + ") " + binding + ")"; + } + if (propertyName.equals("layout")) { // handle containerDelegate (e.g. contentPane on JFrame) + // have to set layout early, before children are added + object.appendInitializationCode(getSetPropertyCode(object.getJavaCode(), propertyName, binding, compiler)); + } + object.registerDataBinding(binding, propertyName, getSetPropertyCode(object.getJavaCode(), propertyName, binding, compiler), compiler); + } else { // no bindings, convert from string + if (inline) { + compiler.addInlineStyle(object, propertyName, false); + } + try { + Class typeClass = type != null ? ClassDescriptorLoader.getClass(type.getName(), type.getClassLoader()) : null; + Object value = convertFromString(propertyName, stringValue, typeClass); + setProperty(object, propertyName, value, compiler); + } catch (NumberFormatException e) { + compiler.reportError("could not convert literal string '" + stringValue + "' to type " + type.getName()); + } catch (IllegalArgumentException e) { + compiler.reportError("could not convert literal string '" + stringValue + "' to type " + type.getName()); + } catch (ClassNotFoundException e) { + compiler.reportError("could not find class " + type.getName()); + } + } + } catch (UnsupportedAttributeException e) { + compiler.reportError("class " + object.getObjectClass().getName() + " does not support attribute '" + propertyName + "'"); + } + } + + + public void applyStylesheets(CompiledObject object, JAXXCompiler compiler) { + applyStylesheets(object, compiler, null); + } + + + private void applyStylesheets(final CompiledObject object, JAXXCompiler compiler, Stylesheet overrides) { + applyStylesheets(object, compiler, overrides, true); + } + + + private void applyStylesheets(final CompiledObject object, JAXXCompiler compiler, Stylesheet overrides, boolean recurse) { + try { + Stylesheet stylesheet = compiler.getStylesheet(); + ClassDescriptor objectClass = object.getObjectClass(); + if (recurse && ClassDescriptorLoader.getClassDescriptor(JAXXObject.class).isAssignableFrom(objectClass)) { + JAXXObjectDescriptor jaxxObjectDescriptor = objectClass.getJAXXObjectDescriptor(); + ComponentDescriptor[] descriptors = jaxxObjectDescriptor.getComponentDescriptors(); + for (ComponentDescriptor descriptor : descriptors) { + ClassDescriptor classDescriptor = ClassDescriptorLoader.getClassDescriptor(descriptor.getJavaClassName()); + boolean isRoot = classDescriptor != objectClass; + String id = isRoot ? object.getId() + ' ' + descriptor.getId() : "( " + object.getId() + " ) " + descriptor.getId(); + CompiledObject child = new CompiledObject(id, + "((" + JAXXCompiler.getCanonicalName(classDescriptor) + ") " + + object.getJavaCode() + ".getObjectById(" + TypeManager.getJavaCode(descriptor.getId()) + "))", + classDescriptor, + compiler, + true); + ComponentDescriptor parentDescriptor = descriptor.getParent(); + CompiledObject currentObject = child; + while (parentDescriptor != null) { + CompiledObject parent = new CompiledObject("internal", ClassDescriptorLoader.getClassDescriptor(parentDescriptor.getJavaClassName()), compiler); + currentObject.setParent(parent); + currentObject = parent; + parentDescriptor = parentDescriptor.getParent(); + } + currentObject.setParent(object); + String styleClass = object.getStyleClass(); + if (styleClass == null) { + styleClass = descriptor.getStyleClass(); + } + child.setStyleClass(styleClass); + Stylesheet mergedStylesheet = overrides; + Stylesheet childOverrides = jaxxObjectDescriptor.getStylesheet(); + if (childOverrides != null) { + if (mergedStylesheet == null) { + mergedStylesheet = childOverrides; + } else { + mergedStylesheet.add(childOverrides.getRules()); + } + } + TagManager.getTagHandler(objectClass).applyStylesheets(child, compiler, mergedStylesheet, isRoot); + object.appendInitializationCode(child.getInitializationCode(compiler)); + } + } else if (stylesheet != null) { + StylesheetHelper.applyTo(object, compiler, stylesheet, overrides); + } + } + catch (ClassNotFoundException e) { + throw new CompilerException(e); + } catch (IllegalArgumentException e) { + compiler.reportError(e.getMessage()); + } + } + + + /** + * Adds the necessary Java code to a <code>CompiledObject</code> to add an event listener at runtime. + * + * @param object the <code>CompiledObject</code> to which the event listener should be added + * @param name the name of the event listener, such as <code>"actionPerformed"</code> + * @param value the Java code snippet to execute when the event is fired + * @param compiler the current <code>JAXXCompiler</code> + */ + public void addEventHandler(CompiledObject object, String name, String value, JAXXCompiler compiler) { + JAXXEventSetDescriptor JAXXEventSetDescriptor = events.get(name); + if (JAXXEventSetDescriptor != null) { + MethodDescriptor[] listenerMethods = JAXXEventSetDescriptor.getListenerMethods(); + MethodDescriptor listenerMethod = null; + for (MethodDescriptor listenerMethod1 : listenerMethods) { + if (listenerMethod1.getName().equals(name)) { + listenerMethod = listenerMethod1; + break; + } + } + if (listenerMethod == null) { + throw new RuntimeException("expected to find method '" + name + "' in JAXXEventSetDescriptor.getListenerMethods()"); + } + try { + value = compiler.preprocessScript(value); + object.addEventHandler(name, JAXXEventSetDescriptor.getAddListenerMethod(), listenerMethod, value, compiler); + } catch (CompilerException e) { + compiler.reportError("While parsing event handler for '" + name + "': " + e.getMessage()); + } + } else { + compiler.reportError("could not find event '" + name + "' for object " + object); + } + } + + + /** + * Returns a snippet of Java code which will retrieve an object property at runtime. Typically the code is + * just a call to the property's <code>get</code> method, but it can be arbitrarily complex. + * + * @param javaCode Java code for the object whose property is being retrieved + * @param name the name of the property to retrieve + * @param compiler the current <code>JAXXCompiler</code> + * @return the snippet + * @throws CompilerException if a compilation error occurs + */ + public String getGetPropertyCode(String javaCode, String name, JAXXCompiler compiler) { + try { + init(); + } catch (IntrospectionException e) { + throw new RuntimeException(e); + } + + JAXXPropertyDescriptor property = properties.get(name); + if (property != null) { + if (property.getReadMethodDescriptor() != null) { + return javaCode + '.' + property.getReadMethodDescriptor().getName() + "()"; + } + throw new UnsupportedAttributeException("property '" + name + "' of " + getBeanClass().getName() + " has no read method"); + } + throw new UnsupportedAttributeException("property '" + name + "' could not be found in class " + getBeanClass().getName()); + } + + + /** + * Returns a snippet of Java code which will set an object property at runtime. Typically the code is + * just a call to the property's <code>set</code> method, but it can be arbitrarily complex. + * + * @param javaCode Java code for the object whose property is being set + * @param name the name of the property to set + * @param valueCode Java expression representing the value to set the property to + * @param compiler the current <code>JAXXCompiler</code> + * @return the snippet + * @throws CompilerException if a compilation error occurs + */ + public String getSetPropertyCode(String javaCode, String name, String valueCode, JAXXCompiler compiler) { + JAXXPropertyDescriptor property = properties.get(name); + if (property != null) { + if (property.getWriteMethodDescriptor() != null) { + return javaCode + '.' + property.getWriteMethodDescriptor().getName() + '(' + valueCode + ");"; + } + throw new UnsupportedAttributeException("property '" + name + "' of " + getBeanClass().getName() + " is read-only"); + } + throw new UnsupportedAttributeException("property '" + name + "' could not be found in class " + getBeanClass().getName()); + } + + + /** + * Appends Java code to a <code>CompiledObject</code> in order to implement a property assignment. + * <code>setProperty</code> is invoked in response to most XML attributes (those which are not more + * complicated cases, like data bindings or event handlers). + * <p/> + * By the time it reaches this method, the <code>value</code> has already been converted from its XML + * string representation to the appropriate destination type for the property (i.e. if + * <code>JLabel.foreground</code> is being set, <code>value</code> will be a <code>Color</code>). + * + * @param object the object being modified + * @param name the name of the property to set + * @param value the value to set the property to + * @param compiler the current <code>JAXXCompiler</code> + * @throws CompilerException if a compilation error occurs + */ + public void setProperty(CompiledObject object, String name, Object value, JAXXCompiler compiler) { + object.appendInitializationCode(getSetPropertyCode(object.getJavaCodeForProperty(name), name, TypeManager.getJavaCode(value), compiler)); + } + + + /** + * Maps string values onto integers, so that int-valued enumeration properties can be specified by strings. For + * example, when passed a key of 'alignment', this method should normally map the values 'left', 'center', and + * 'right' onto SwingConstants.LEFT, SwingConstants.CENTER, and SwingConstants.RIGHT respectively. + * <p/> + * You do not normally need to call this method yourself; it is invoked by {@link #convertFromString} when an + * int-valued property has a value which is not a valid number. By default, this method looks at the + * <code>enumerationValues</code> value of the <code>JAXXPropertyDescriptor</code>. + * + * @param key the name of the int-typed property + * @param value the non-numeric value that was specified for the property + * @return the constant integer value + * @throws IllegalArgumentException if the property is an enumeration, but the value is not valid + * @throws NumberFormatException if the property is not an enumeration + */ + protected int constantValue(String key, String value) { + JAXXBeanInfo JAXXBeanInfo = getJAXXBeanInfo(); + JAXXPropertyDescriptor[] props = JAXXBeanInfo.getJAXXPropertyDescriptors(); + String lowercaseValue = value.toLowerCase(); + for (JAXXPropertyDescriptor property : props) { + if (property.getName().equals(key)) { + Object[] values = (Object[]) property.getValue("enumerationValues"); + if (values != null) { + for (int j = 0; j < values.length - 2; j += 3) { + if (((String) values[j]).toLowerCase().equals(lowercaseValue)) { + return (Integer) values[j + 1]; + } + } + + StringBuffer message = new StringBuffer("value of '" + key + "' must be one of: ["); + for (int j = 0; j < values.length - 2; j += 3) { + if (j != 0) { + message.append(", "); + } + message.append(((String) values[j]).toLowerCase()); + } + message.append("] (found '").append(value).append("')"); + throw new IllegalArgumentException(message.toString()); + } + } + } + throw new NumberFormatException(value); + } + + + /** + * As {@link TypeManager#convertFromString(String, Class)}, except that it additionally supports constant names + * for <code>int</code>-valued types. + * + * @param key the name of the property whose value is being converted + * @param value the raw string value of the property as it appears in the XML + * @param type the datatype to convert the string into + * @return the converted object + * @see #constantValue + */ + protected Object convertFromString(String key, String value, Class type) { + if (type == null || type == Object.class) { + return value; + } + + try { + return TypeManager.convertFromString(value, type); + } catch (NumberFormatException e) { + if (type == int.class || type == Integer.class) { + return constantValue(key, value); + } + throw e; + } + } + + + /** + * Compiles the child tags of the current tag. The default implementation invokes {@link #compileChildTagFirstPass} + * for each child tag. + * + * @param tag the tag whose children to compile + * @param compiler the current <code>JAXXCompiler</code> + * @throws CompilerException if a compilation error occurs + * @throws IOException if an I/O error occurs + */ + protected void compileChildrenFirstPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + NodeList children = tag.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node node = children.item(i); + int nodeType = node.getNodeType(); + if (nodeType == Node.ELEMENT_NODE) { + Element child = (Element) node; + compileChildTagFirstPass(child, compiler); + } + } + } + + + /** + * Compiles the child tags of the current tag. The default implementation invokes {@link #compileChildTagFirstPass} + * for each child tag. + * + * @param tag the tag whose children to compile + * @param compiler the current <code>JAXXCompiler</code> + * @throws CompilerException if a compilation error occurs + * @throws IOException if an I/O error occurs + */ + protected void compileChildrenSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + NodeList children = tag.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node node = children.item(i); + int nodeType = node.getNodeType(); + if (nodeType == Node.ELEMENT_NODE) { + Element child = (Element) node; + compileChildTagSecondPass(child, compiler); + } else if (nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE) { + String text = ((Text) node).getData().trim(); + if (text.length() > 0) { + compiler.reportError("tag '" + tag.getLocalName() + "' may not contain text ('" + ((Text) node).getData().trim() + "')"); + } + } + } + } + + + /** + * Compiles a child of the current tag. The default implementation calls {@link JAXXCompiler#compileFirstPass + * JAXXCompiler.compileFirstPass}. + * + * @param tag the child tag to compile + * @param compiler the current <code>JAXXCompiler</code> + * @throws CompilerException if a compilation error occurs + * @throws IOException if an I/O error occurs + */ + protected void compileChildTagFirstPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + compiler.compileFirstPass(tag); + } + + + /** + * Compiles a child of the current tag. The default implementation calls {@link JAXXCompiler#compileFirstPass + * JAXXCompiler.compileSecondPass}. + * + * @param tag the child tag to compile + * @param compiler the current <code>JAXXCompiler</code> + * @throws CompilerException if a compilation error occurs + * @throws IOException if an I/O error occurs + */ + protected void compileChildTagSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + compiler.compileSecondPass(tag); + } + + @Override + public String toString() { + return getClass().getName() + "[" + getBeanClass().getName() + "]"; + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/ScriptHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/ScriptHandler.java new file mode 100644 index 0000000..94fabe1 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/ScriptHandler.java @@ -0,0 +1,81 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags; + +import jaxx.CompilerException; +import jaxx.UnsupportedAttributeException; +import jaxx.compiler.JAXXCompiler; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.StringWriter; + +/** + * Handles the <code><script></code> tag. + * + * @author Ethan Nicholas + */ +public class ScriptHandler implements TagHandler { + public void compileFirstPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + File scriptFile = null; + NamedNodeMap attributes = tag.getAttributes(); + for (int i = 0; i < attributes.getLength(); i++) { + Attr attribute = (Attr) attributes.item(i); + String name = attribute.getName(); + String attrValue = attribute.getValue(); + if (name.equals("source")) { + scriptFile = new File(compiler.getBaseDir(), attrValue.replace('/', File.separatorChar)); + StringWriter scriptBuffer = new StringWriter(); + try { + FileReader in = new FileReader(scriptFile); + char[] readBuffer = new char[2048]; + int c; + while ((c = in.read(readBuffer)) > 0) { + scriptBuffer.write(readBuffer, 0, c); + } + } + catch (FileNotFoundException e) { + compiler.reportError("script file not found: " + scriptFile); + } + compiler.registerScript(scriptBuffer.toString(), scriptFile); + } else + if (!name.startsWith("xmlns") && !JAXXCompiler.JAXX_INTERNAL_NAMESPACE.equals(attribute.getNamespaceURI())) + throw new UnsupportedAttributeException(name); + } + + StringBuffer script = new StringBuffer(); + NodeList children = tag.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + switch (child.getNodeType()) { + case Node.ELEMENT_NODE: + compiler.reportError("<script> tag may not contain child elements: " + tag); + case Node.TEXT_NODE: // fall through + case Node.CDATA_SECTION_NODE: + script.append(((Text) child).getData()); + } + } + + String scriptString = script.toString().trim(); + if (scriptString.length() > 0) { + if (scriptFile != null) { + compiler.reportError("<script> tag has both a source attribute and an inline script"); + } + compiler.registerScript(script.toString()); + } + } + + + public void compileSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/StyleHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/StyleHandler.java new file mode 100644 index 0000000..9ad929c --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/StyleHandler.java @@ -0,0 +1,180 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags; + +import jaxx.CompilerException; +import jaxx.UnsupportedAttributeException; +import jaxx.compiler.JAXXCompiler; +import jaxx.css.CSSParser; +import jaxx.css.CSSParserConstants; +import jaxx.css.CSSParserTreeConstants; +import jaxx.css.Rule; +import jaxx.css.Selector; +import jaxx.css.SimpleNode; +import jaxx.css.Stylesheet; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Handles the <code><style></code> tag. + * + * @author Ethan Nicholas + */ +public class StyleHandler implements TagHandler { + public void compileFirstPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + boolean source = false; + NamedNodeMap attributes = tag.getAttributes(); + for (int i = 0; i < attributes.getLength(); i++) { + Attr attribute = (Attr) attributes.item(i); + String name = attribute.getName(); + String attrValue = attribute.getValue(); + if (name.equals("source")) { + source = true; + File styleFile = new File(compiler.getBaseDir(), attrValue.replace('/', File.separatorChar)); + StringWriter styleBuffer = new StringWriter(); + try { + FileReader in = new FileReader(styleFile); + char[] readBuffer = new char[2048]; + int c; + while ((c = in.read(readBuffer)) > 0) + styleBuffer.write(readBuffer, 0, c); + } + catch (FileNotFoundException e) { + compiler.reportError("stylesheet file not found: " + styleFile); + } + compiler.getSourceFiles().push(styleFile); + compiler.registerStylesheet(processStylesheet(styleBuffer.toString())); + compiler.getSourceFiles().pop(); + } else + if (!name.startsWith("xmlns") && !JAXXCompiler.JAXX_INTERNAL_NAMESPACE.equals(attribute.getNamespaceURI())) + throw new UnsupportedAttributeException(name); + } + + StringBuffer style = new StringBuffer(); + NodeList children = tag.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + switch (child.getNodeType()) { + case Node.ELEMENT_NODE: + compiler.reportError("<style> tag may not contain child elements: " + tag); + case Node.TEXT_NODE: // fall through + case Node.CDATA_SECTION_NODE: + style.append(((Text) child).getData()); + } + } + + String styleString = style.toString().trim(); + if (styleString.length() > 0) { + if (source) + compiler.reportError("<style> tag has both a source attribute and an inline stylesheet"); + compiler.registerStylesheet(processStylesheet(style.toString())); + } + } + + + public void compileSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + } + + + protected Selector processSelector(SimpleNode selector) { + if (selector.getId() != CSSParserTreeConstants.JJTSELECTOR) + throw new IllegalArgumentException("argument node is not a Selector"); + String javaClassName = null; + String styleClass = null; + String pseudoClass = null; + String id = null; + + for (int i = 0; i < selector.jjtGetNumChildren(); i++) { + SimpleNode child = selector.getChild(i); + switch (child.getId()) { + case CSSParserTreeConstants.JJTJAVACLASS: + if (!child.getText().trim().equals("*")) + javaClassName = child.getText(); + break; + case CSSParserTreeConstants.JJTCLASS: + styleClass = child.getText().substring(1); + break; + case CSSParserTreeConstants.JJTPSEUDOCLASS: + pseudoClass = child.getText().substring(1); + break; + case CSSParserTreeConstants.JJTID: + id = child.getText().substring(1); + break; + + default: + throw new IllegalStateException("unexpected child of Selector node, type=" + child.getId()); + } + } + + return new Selector(javaClassName, styleClass, pseudoClass, id); + } + + + protected Rule processRule(SimpleNode ruleNode) { + if (ruleNode.getId() != CSSParserTreeConstants.JJTRULE) { + throw new IllegalArgumentException("argument node is not a Rule"); + } + SimpleNode selectorsNode = ruleNode.getChild(0); + assert selectorsNode.getId() == CSSParserTreeConstants.JJTSELECTORS : "expected node to be of type Selectors"; + + List<Selector> selectors = new ArrayList<Selector>(); + for (int i = 0; i < selectorsNode.jjtGetNumChildren(); i++) { + SimpleNode selectorNode = selectorsNode.getChild(i); + selectors.add(processSelector(selectorNode)); + } + + Map<String, String> properties = new HashMap<String, String>(); + for (int i = 1; i < ruleNode.jjtGetNumChildren(); i++) { + SimpleNode declarationNode = ruleNode.getChild(i); + if (declarationNode.getId() == CSSParserTreeConstants.JJTDECLARATION) { + String key = declarationNode.getChild(0).getText(); + SimpleNode valueNode = declarationNode.getChild(1); + String value = valueNode.getText(); + if (valueNode.firstToken.kind == CSSParserConstants.STRING) { + value = value.substring(1, value.length() - 1); + } + properties.put(key, value); + } + } + Rule rule; + rule = new Rule(selectors.toArray(new Selector[selectors.size()]), properties); + return rule; + } + + + protected Stylesheet processStylesheet(String stylesheetText) throws CompilerException { + CSSParser p = new CSSParser(new StringReader(stylesheetText)); + SimpleNode node; + try { + node = p.Stylesheet(); + } catch (Error e) { + throw new CompilerException(e); + } + List<Rule> rules = new ArrayList<Rule>(); + for (int i = 0; i < node.jjtGetNumChildren(); i++) { + SimpleNode ruleNode = node.getChild(i); + Rule rule = processRule(ruleNode); + rules.add(rule); + } + Stylesheet stylesheet; + stylesheet = new Stylesheet(rules.toArray(new Rule[rules.size()])); + return stylesheet; + } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/TagHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/TagHandler.java new file mode 100644 index 0000000..93c5bd4 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/TagHandler.java @@ -0,0 +1,46 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags; + +import jaxx.CompilerException; +import jaxx.compiler.JAXXCompiler; +import org.w3c.dom.Element; + +import java.io.IOException; + +/** + * Implementations of <code>TagHandler</code> produce Java source code from XML tags. + * <code>TagHandlers</code> are mapped to particular XML tags (such as <JFrame>) in {@link JAXXCompiler}. + * There is only one <code>TagHandler</code> for any given XML tag, and therefore implementations must be + * stateless. + * + * @author Ethan Nicholas + */ +public interface TagHandler { + /** + * Performs the first pass of compilation on an XML tag from a JAXX source file. + * <code>TagHandler</code> implementations affect the generated <code>.java</code> + * file by calling methods in the <code>JAXXCompiler</code>. + * + * @param tag the XML tag to compile + * @param compiler the active JAXXCompiler + * @throws CompilerException if a compilation error occurs + * @throws IOException if an I/O error occurs + */ + void compileFirstPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException; + + + /** + * Performs the second pass of compilation on an XML tag from a JAXX source file. + * <code>TagHandler</code> implementations affect the generated <code>.java</code> + * file by calling methods in the <code>JAXXCompiler</code>. + * + * @param tag the XML tag to compile + * @param compiler the active JAXXCompiler + * @throws CompilerException if a compilation error occurs + * @throws IOException if an I/O error occurs + */ + void compileSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException; +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/TagManager.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/TagManager.java new file mode 100644 index 0000000..8c2090b --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/TagManager.java @@ -0,0 +1,479 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags; + +import jaxx.ClassMap; +import jaxx.CompilerException; +import jaxx.compiler.*; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** Manages TagHandlers, including automatically compiling .jaxx files corresponding to class tags. */ +public class TagManager { + /** log */ + protected static final Log log = LogFactory.getLog(TagManager.class); + + /** + * Namespace for JAXX's non-class tags, such as <script;>. The namespace normally does not + * need to be specified but can be used to resolve ambiguities. + */ + public static final String JAXX_NAMESPACE = "http://www.jaxxframework.org/"; + + /** Maps simple tag names to their default namespaces (package names). */ + private static Map<String, String> defaultNamespaces = new HashMap<String, String>(); + + /** Maps qualified tag names to the TagHandlers responsible for processing them. */ + private static Map<QName, TagHandler> registeredTags = new HashMap<QName, TagHandler>(); + + /** Keeps track of whether or not named classes exist. */ + private static Map<String, Boolean> classExistenceCache = new HashMap<String, Boolean>(); + + /** + * Maps bean classes to their TagHandler classes. The mapping is to TagHandler classes, rather than to + * TagHandler instances, because subclasses of the bean class should be handled by the same TagHandler + * (assuming no more specific mappings exist), which requires creating a new instance of the TagHandler. + */ + private static ClassMap<Class<? extends TagHandler>> registeredBeans = new ClassMap<Class<? extends TagHandler>>(); + + // still targeting 1.4, so I can't use javax.xml.namespace.QName + private static class QName { + private String namespaceURI; + private String localPart; + + public QName(String namespaceURI, String localPart) { + if (localPart == null) + throw new NullPointerException(); + this.namespaceURI = namespaceURI; + this.localPart = localPart; + } + + + public String getNamespaceURI() { + return namespaceURI; + } + + + public String getLocalPart() { + return localPart; + } + + @Override + public boolean equals(Object o) { + if (o == null || !(o instanceof QName)) + return false; + QName qname = (QName) o; + return qname.getNamespaceURI().equals(getNamespaceURI()) && qname.getLocalPart().equals(getLocalPart()); + } + + @Override + public int hashCode() { + return (namespaceURI != null ? namespaceURI.hashCode() : 0) ^ getLocalPart().hashCode(); + } + } + + + private TagManager() { /* not instantiable */ } + + + public static void reset(boolean verbose) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException { + registeredBeans.clear(); + registeredTags.clear(); + defaultNamespaces.clear(); + CompiledObjectDecorator.reset(); + JAXXCompilerLaunchor.loadLibraries(verbose); + } + + + /** + * Maps a class tag to a specific <code>TagHandler</code>. When a tag representing the bean class is + * encountered (either the class' simple name, if it is unambiguous, or its fully-qualified name), the specified + * <code>TagHandler</code> will be invoked to compile it. + * + * @param beanClass the class to associate with a <code>TagHandler</code> + * @param handler the <code>TagHandler</code> class, which must descend from <code>DefaultObjectHandler</code> + * @throws IllegalArgumentException if the handler class does not descend from <code>DefaultObjectHandler</code> + */ + public static <T extends TagHandler> void registerBean(ClassDescriptor beanClass, Class<T> handler) { + if (!DefaultObjectHandler.class.isAssignableFrom(handler)) { + throw new IllegalArgumentException("handler class must be a subclass of DefaultObjectHandler"); + } + registeredBeans.put(beanClass, handler); + if (log.isDebugEnabled()) { + log.debug(beanClass + " : " + handler); + } + String name = beanClass.getName(); + int dotPos = name.lastIndexOf("."); + String namespace = name.substring(0, dotPos + 1) + "*"; + name = name.substring(dotPos + 1); + registerDefaultNamespace(name, namespace); + } + + + /** + * Sets the default namespace for a tag. When the tag is encountered with no namespace specified, + * the specified namespace will be assumed. Mapping the same tag to two or more default namespaces + * removes the mapping and marks the entry as being ambiguous (by putting a <code>null</code> + * value into the map); this causes an error to be thrown if the tag is used without a namespace being + * specified. + * <p/> + * Java package names on tags are automatically converted into namespaces (e.g. <javax.swing.JButton/> + * and <JButton xmlns="javax.swing.*"/> are equivalent), so tags with package names are considered + * to have namespaces specified. + * + * @param tag tag name + * @param namespace namespace + */ + public static void registerDefaultNamespace(String tag, String namespace) { + if (defaultNamespaces.containsKey(tag) && !defaultNamespaces.get(tag).equals(namespace)) { + defaultNamespaces.put(tag, null); // tag name is now ambiguous + } else { + defaultNamespaces.put(tag, namespace); + } + } + + + /** + * Registers a <code>TagHandler</code> for a tag. When a tag with the given name and namespace + * is encountered, the <code>TagHandler's compileFirstPass</code> and <code>compileSecondPass</code> + * methods will be invoked to handle it. + * <p/> + * It is not an error to register an already-registered tag and namespace combination. The new mapping + * will replace the old mapping. + * + * @param namespace the tag's namespace + * @param tag the simple name of the tag + * @param handler the <code>TagHandler</code> which should process the tag + */ + public static <T extends TagHandler> void registerTag(String namespace, String tag, T handler) { + if (namespace == null) { + namespace = "*"; + } + //System.out.println("registerTag "+namespace+" : "+tag+" : "+handler); + if (log.isDebugEnabled()) { + log.debug(tag + " : " + handler); + } + registeredTags.put(new QName(namespace, tag), handler); + registerDefaultNamespace(tag, namespace); + } + + + /** + * Returns the <code>TagHandler</code> that should be used to process the specified tag. + * If the tag represents the class name of an uncompiled <code>.jaxx</code> file, the + * <code>.jaxx</code> is first compiled. + * + * @param namespace the tag's namespace (may be <code>null</code>) + * @param tag the tag's simple name + * @param compiler the current <code>JAXXCompiler</code> + * @return the <code>TagHandler</code> for the tag + * @throws jaxx.CompilerException ? + */ + public static TagHandler getTagHandler(String namespace, String tag, JAXXCompiler compiler) throws CompilerException { + return getTagHandler(namespace, tag, false, compiler); + } + + + private static String getNamespace(ClassDescriptor beanClass) { + String packageName = beanClass.getPackageName(); + return packageName != null ? packageName + ".*" : "*"; + + } + + + private static String getSimpleName(ClassDescriptor beanClass) { + String packageName = beanClass.getPackageName(); + if (packageName != null) { + assert beanClass.getName().startsWith(packageName); + return beanClass.getName().substring(packageName.length() + 1); + } + return beanClass.getName(); + } + + + /** + * @param beanClass the tag class + * @return the <code>TagHandler</code> that should be used to process the specified class. + * Only <code>TagHandlers</code> previously registered with <code>registerBean</code> + * are considered. + * @throws jaxx.CompilerException ? + */ + public static DefaultObjectHandler getTagHandler(ClassDescriptor beanClass) throws CompilerException { + try { + if (beanClass == null) { + throw new NullPointerException(); + } + String namespace = getNamespace(beanClass); + String tag = getSimpleName(beanClass); + DefaultObjectHandler handler = (DefaultObjectHandler) registeredTags.get(new QName(namespace, tag)); + if (handler == null) { + Class<? extends TagHandler> handlerClass = registeredBeans.get(beanClass); + if (handlerClass == null) { + throw new CompilerException("unable to find handler for " + beanClass); + } + Constructor<? extends TagHandler> constructor = handlerClass.getConstructor(ClassDescriptor.class); + handler = (DefaultObjectHandler) constructor.newInstance(beanClass); + registerTag(namespace, tag, handler); + } + return handler; + } + catch (InstantiationException e) { + throw new RuntimeException(e); + } + catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + + private static boolean classExists(String className, JAXXCompiler compiler) { + if (classExistenceCache.containsKey(className)) { + return classExistenceCache.get(className); + } + + boolean found = false; + try { + Class.forName(className, true, compiler.getClassLoader()); + found = true; + } + catch (ClassNotFoundException e) { + // ignore ? + } + catch (NoClassDefFoundError e) { // we get this instead of ClassNotFoundException on case-insensitive file systems when + // looking up a class with the wrong case + } + + if (!found) { // couldn't find .class, check for .java + URL javaURL = compiler.getClassLoader().getResource(className.replace('.', '/') + ".java"); + found = javaURL != null; + } + + if (!found) { // couldn't find .java, check for .jaxx + URL jaxxURL = compiler.getClassLoader().getResource(className.replace('.', '/') + ".jaxx"); + found = jaxxURL != null; + } + + classExistenceCache.put(className, found); + + return found; + } + + + private static String determinePackage(String simpleClassName, String defaultPackage, JAXXCompiler compiler) { + String namespace = null; + Set<String> classes = compiler.getImportedClasses(); + for (String className : classes) { // search class imports (e.g. import java.util.Date;) + if (className.equals(simpleClassName) || className.endsWith("." + simpleClassName)) { + namespace = className.substring(0, className.lastIndexOf(".") + 1) + "*"; + } + } + if (namespace == null) { // search package imports (e.g. import java.util.*;) + Set<String> searchList = compiler.getImportedPackages(); + if (defaultPackage != null) { + if (!defaultPackage.endsWith("*")) { + throw new IllegalArgumentException("defaultPackage must end in '*', found '" + defaultPackage + "'"); + } + if (classExists(defaultPackage.substring(0, defaultPackage.length() - 1) + simpleClassName, compiler)) { + return defaultPackage; + } + } + for (String currentPackage : searchList) { + String className = currentPackage + simpleClassName; + if (classExists(className, compiler)) { + if (namespace != null) { // we've already found the same name in another package + compiler.reportError("symbol '" + simpleClassName + "' is ambiguous, found matching classes " + namespace.substring(0, namespace.length() - 1) + simpleClassName + " and " + currentPackage + simpleClassName + ". Use fully-qualified name to disambiguate."); + return null; + } + namespace = currentPackage + "*"; + } + } + } + + return namespace; + } + + + /** + * Returns the <code>TagHandler</code> that should be used to process the specified tag. + * <p/> + * The <code>namespacePrefix</code> parameter is used only for error checking, as it is an + * error to specify conflicting package names using both a fully-qualified tag name and a + * namespace prefix, but it is not an error to specify conflicting package names using a + * fully-qualified tag name and a <i>default</i> namespace (i.e. <awt:javax.swing.JButton xmlns:awt='java.awt.*'/> + * is an error, whereas <javax.swing.JButton xmlns='java.awt.*'/> is not). + * + * @param namespace the tag's namespace (may be <code>null</code>) + * @param tag the tag's simple name (which can include fully-qualified Java class names) + * @param namespacePrefix <code>true</code> if the namespace was specified by means of a namespace prefix (as opposed to a default namespace) + * @param compiler the current <code>JAXXCompiler</code> + * @return the <code>TagHandler</code> for the tag + * @throws jaxx.CompilerException ? + */ + public static TagHandler getTagHandler(String namespace, String tag, boolean namespacePrefix, JAXXCompiler compiler) throws CompilerException { + if (tag == null) { + throw new NullPointerException(); + } + if (namespace == null && defaultNamespaces.containsKey(tag)) { + namespace = defaultNamespaces.get(tag); + if (namespace == null) { // defaultNamespaces map contains a null value, which is put there to indicate ambiguity + compiler.reportError("tag '" + tag + "' is ambiguous; specify fully-qualified name (package and class) to disambiguate"); + return null; + } + } + + TagHandler handler = registeredTags.get(new QName(namespace, tag)); + if (handler == null) { + if (namespace == null || namespace.endsWith("*")) { + String className; + if (namespace != null) { + className = resolveClassName(namespace.substring(0, namespace.length() - 1) + tag, compiler); + if (className == null) { + className = resolveClassName(tag, compiler); + if (namespacePrefix && !className.startsWith(namespace.substring(0, namespace.length() - 1))) { + className = null; // namespace was specified, but we found it in a different package - ignore + } + } + } else { + className = resolveClassName(tag, compiler); + } + if (className != null) { + int dotPos = className.lastIndexOf("."); + namespace = className.substring(0, dotPos + 1) + "*"; + tag = className.substring(dotPos + 1); + handler = registeredTags.get(new QName(namespace, tag)); + if (handler == null) { + try { + handler = getTagHandler(ClassDescriptorLoader.getClassDescriptor(className, compiler.getClassLoader())); + } + catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + } + } + } + return handler; + } + + + /** + * Resolves a simple class name (like <code>Object</code> or <code>String</code>) to its fully-qualified name. Inner + * classes should be represented as they would appear in Java source code (e.g. JPopupMenu.Separator). Fully-qualified names, + * such as <code>java.lang.Object</code> are legal and will be returned unmodified (and in fact it is generally impossible to + * even know whether a given reference is fully qualified until it has been resolved). Returns <code>null</code> if no matching + * class could be found. + * + * @param name name to resolve + * @param compiler compile to use + * @return the resolved fqn class name + */ + public static String resolveClassName(String name, JAXXCompiler compiler) { + if (name.endsWith("[]")) + return resolveClassName(name.substring(0, name.length() - 2), compiler) + "[]"; + if (name.indexOf("<") != -1) + name = name.substring(0, name.indexOf("<")); // strip off generic types + + name = name.intern(); + if (name.equals("boolean") || name.equals("byte") || name.equals("short") || name.equals("int") || + name.equals("long") || name.equals("float") || name.equals("double") || name.equals("char")) + return name; + + String result = null; + String originalName = name; + String defaultNamespace = null; + if (defaultNamespaces.containsKey(name)) { + defaultNamespace = defaultNamespaces.get(name); + if (defaultNamespace == null) { // defaultNamespaces map contains a null value, which is put there to indicate ambiguity + compiler.reportError("class '" + name + "' is ambiguous; specify fully-qualified name (package and class) to disambiguate"); + return null; + } + } + if (defaultNamespace != null && defaultNamespace.endsWith("*")) { + result = defaultNamespace.substring(0, defaultNamespace.length() - 1) + name; + } + + if (result == null) { + // Inner class names (like JPopupMenu.Separator) present a special challenge. The name before the dot might be + // a package name, or it might be a class name. If it's a class name, it might be fully qualified, or it might + // not. And it's also not actually the correct name of the class, as far as the JVM is concerned -- the correct + // name uses a dollar sign instead of a dot (javax.swing.JPopupMenu$Separator). And there could be more than + // one inner class -- it's possible to have com.mycompany.Outer$Inner$Innerer$Innerest. + // + // The basic strategy is to start by treating the part before the last dot as a package name, as that is by far + // the most likely case. If we don't find the class there, change the last dot to a dollar sign and try again. + // Suppose we have the tag <com.mycompany.Outer.Inner.Innerer.Innerest/>, matching the class above. Resolution + // proceeds like this: + // com.mycompany.Outer.Inner.Innerer.* : Innerest + // com.mycompany.Outer.Inner.* : Innerer$Innerest + // com.mycompany.Outer.* : Inner$Innerer$Innerest + // com.mycompany.* : Outer$Inner$Innerer$Innerest + // And at this point we have a match with the class Outer$Inner$Innerer$Innerest in package com.mycompany. + int dotPos = originalName.lastIndexOf('.'); + for (; ;) { + String namespace = dotPos != -1 ? originalName.substring(0, dotPos) + ".*" : "*"; + name = originalName.substring(dotPos + 1).replace('.', '$'); + String packageName = determinePackage(name, namespace, compiler); + if (packageName != null) { + assert packageName.endsWith("*"); + if (packageName.equals(namespace) || namespace.equals("*")) { + // check for an alias (like javax.swing.JComboBox actually being jaxx.runtime.swing.JAXXComboBox) + TagHandler handler = registeredTags.get(new QName(namespace, name)); + if (handler != null) { // determine alias by looking at handler + ClassDescriptor alias = ((DefaultObjectHandler) handler).getBeanClass(); + // make sure the same handler is used for both the aliased and non-aliased names, in order to avoid "no CompiledObject has been registered" error + // the line below doesn't bother to handle the case where the aliased class name doesn't have a package, since it's a pretty safe assumption that + // that will never happen + assert alias.getPackageName() != null && alias.getPackageName().length() > 0 : "aliasing with no package name has not been implemented"; + registeredTags.put(new QName(alias.getPackageName() + ".*", alias.getName().substring(alias.getPackageName().length() + 1)), handler); + result = alias.getName(); + break; + } else { // no alias + result = packageName.substring(0, packageName.length() - 1) + name; + break; + } + } + // else we found a class by the same name, but in the wrong package + } + + if (dotPos <= 0) + break; + dotPos = originalName.lastIndexOf('.', dotPos - 1); + } + } + + if (result != null && !result.equals(originalName)) + result = resolveClassName(result, compiler); // check for aliases against the new name as well + + return result; + } + + + public static ClassDescriptor resolveClass(String className, JAXXCompiler compiler) { + try { + className = resolveClassName(className, compiler); + if (className == null) + return null; + return ClassDescriptorLoader.getClassDescriptor(className, compiler.getClassLoader()); + } + catch (ClassNotFoundException e) { + return null; + } + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/ApplicationHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/ApplicationHandler.java new file mode 100644 index 0000000..f35c5dc --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/ApplicationHandler.java @@ -0,0 +1,41 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.CompilerException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.runtime.swing.Application; +import jaxx.types.TypeManager; +import org.w3c.dom.Element; + +import javax.swing.WindowConstants; + +public class ApplicationHandler extends JWindowHandler { + + public ApplicationHandler(ClassDescriptor beanClass) { + super(beanClass); + ClassDescriptorLoader.checkSupportClass(getClass(), beanClass, Application.class); + } + + + @Override + public void setAttribute(CompiledObject object, String propertyName, String stringValue, boolean inline, JAXXCompiler compiler) throws CompilerException { + if (propertyName.equals("lookAndFeel") && stringValue != null && !stringValue.trim().startsWith("{")) { + compiler.appendBodyCode("{ " + object.getJavaCode() + ".setLookAndFeel(" + TypeManager.getJavaCode(stringValue) + "); }" + JAXXCompiler.getLineSeparator()); + } else { + super.setAttribute(object, propertyName, stringValue, inline, compiler); + } + } + + + @Override + protected void setDefaults(CompiledObject object, Element tag, JAXXCompiler compiler) throws CompilerException { + super.setDefaults(object, tag, compiler); + setAttribute(object, "defaultCloseOperation", String.valueOf(WindowConstants.EXIT_ON_CLOSE), false, compiler); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/CellHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/CellHandler.java new file mode 100644 index 0000000..ffa6aa0 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/CellHandler.java @@ -0,0 +1,154 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.CompilerException; +import jaxx.UnsupportedAttributeException; +import jaxx.compiler.JAXXCompiler; +import jaxx.tags.TagHandler; +import jaxx.types.TypeManager; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; + +import java.awt.GridBagConstraints; +import java.awt.Insets; +import java.io.IOException; + +public class CellHandler implements TagHandler { + public void compileFirstPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + compileChildrenFirstPass(tag, compiler); + } + + + public void compileSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + Node parent = tag.getParentNode(); + if (parent.getNodeType() != Node.ELEMENT_NODE || !parent.getLocalName().equals("row")) { + compiler.reportError("cell tag may only appear within row tag"); + return; + } + + TableHandler.CompiledTable table = (TableHandler.CompiledTable) compiler.getOpenComponent(); + table.newCell(); + GridBagConstraints c = table.getCellConstraints(); + setAttributes(c, tag); + compileChildrenSecondPass(tag, compiler); + } + + + public static void setAttribute(GridBagConstraints c, String name, String value) throws CompilerException { + value = value.trim(); + if (name.equals("insets")) { + c.insets = (Insets) TypeManager.convertFromString(value, Insets.class); + } else if (name.equals("weightx")) { + c.weightx = Double.parseDouble(value); + } else if (name.equals("weighty")) { + c.weighty = Double.parseDouble(value); + } else if (name.equals("columns")) { + c.gridwidth = Integer.parseInt(value); + } else if (name.equals("rows")) { + c.gridheight = Integer.parseInt(value); + } else if (name.equals("fill")) { + if (value.equals("none")) { + c.fill = GridBagConstraints.NONE; + } else if (value.equals("horizontal")) { + c.fill = GridBagConstraints.HORIZONTAL; + } else if (value.equals("vertical")) { + c.fill = GridBagConstraints.VERTICAL; + } else if (value.equals("both")) { + c.fill = GridBagConstraints.BOTH; + } else { + throw new IllegalArgumentException("invalid value for fill attribute: '" + value + "'"); + } + } else if (name.equals("anchor")) { + //todo use a converter + if (value.equals("north")) { + c.anchor = GridBagConstraints.NORTH; + } else if (value.equals("northeast")) { + c.anchor = GridBagConstraints.NORTHEAST; + } else if (value.equals("east")) { + c.anchor = GridBagConstraints.EAST; + } else if (value.equals("southeast")) { + c.anchor = GridBagConstraints.SOUTHEAST; + } else if (value.equals("south")) { + c.anchor = GridBagConstraints.SOUTH; + } else if (value.equals("southwest")) { + c.anchor = GridBagConstraints.SOUTHWEST; + } else if (value.equals("west")) { + c.anchor = GridBagConstraints.WEST; + } else if (value.equals("northwest")) { + c.anchor = GridBagConstraints.NORTHWEST; + } else if (value.equals("center")) { + c.anchor = GridBagConstraints.CENTER; + } else { + throw new IllegalArgumentException("invalid value for anchor attribute: '" + value + "'"); + } + } else { + throw new UnsupportedAttributeException(name); + } + } + + + public static void setAttributes(GridBagConstraints c, Element tag) throws CompilerException { + NamedNodeMap children = tag.getAttributes(); + for (int i = 0; i < children.getLength(); i++) { + Attr attribute = (Attr) children.item(i); + String name = attribute.getName(); + String value = attribute.getValue(); + if (!name.startsWith("xmlns") && !JAXXCompiler.JAXX_INTERNAL_NAMESPACE.equals(attribute.getNamespaceURI())) { + setAttribute(c, name, value); + } + } + } + + + protected void compileChildrenFirstPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + NodeList children = tag.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node node = children.item(i); + int nodeType = node.getNodeType(); + if (nodeType == Node.ELEMENT_NODE) { + Element child = (Element) node; + compileChildTagFirstPass(child, compiler); + } else if (nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE) { + String text = ((Text) node).getData().trim(); + if (text.length() > 0) { + compiler.reportError("tag '" + tag.getLocalName() + "' may not contain text ('" + ((Text) node).getData().trim() + "')"); + } + } + } + } + + + protected void compileChildrenSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + NodeList children = tag.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node node = children.item(i); + int nodeType = node.getNodeType(); + if (nodeType == Node.ELEMENT_NODE) { + Element child = (Element) node; + compileChildTagSecondPass(child, compiler); + } else if (nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE) { + String text = ((Text) node).getData().trim(); + if (text.length() > 0) { + compiler.reportError("tag '" + tag.getLocalName() + "' may not contain text ('" + ((Text) node).getData().trim() + "')"); + } + } + } + } + + + protected void compileChildTagFirstPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + compiler.compileFirstPass(tag); + } + + + protected void compileChildTagSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + compiler.compileSecondPass(tag); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/CompiledItemContainer.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/CompiledItemContainer.java new file mode 100644 index 0000000..88da6b8 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/CompiledItemContainer.java @@ -0,0 +1,53 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.CompilerException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.runtime.swing.Item; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** Compiled representation of a class that contains Items arranged in a list or tree structure (JComboBox, JList, JTree). */ +class CompiledItemContainer extends CompiledObject { + private List<Item> items = new ArrayList<Item>(); + private Stack<Item> openNodes = new Stack<Item>(); + + public CompiledItemContainer(String id, ClassDescriptor objectClass, JAXXCompiler compiler) throws CompilerException { + super(id, objectClass, compiler); + } + + + public void openItem(Item item) { + if (openNodes.isEmpty()) { + items.add(item); + } else { + Item openNode = openNodes.peek(); + openNode.addChild(item); + } + openNodes.add(item); + } + + + public void closeItem(Item item) { + if (openNodes.pop() != item) { + throw new IllegalArgumentException(item + " was not at the top of the item stack"); + } + } + + + public List<Item> getItems() { + return items; + } + + + public void setItems(List<Item> items) { + this.items = items; + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/EnumEditorHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/EnumEditorHandler.java new file mode 100644 index 0000000..fda7b29 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/EnumEditorHandler.java @@ -0,0 +1,56 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.CompilerException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.tags.DefaultComponentHandler; + +import java.awt.event.ItemListener; +import jaxx.runtime.swing.editor.EnumEditor; + +public class EnumEditorHandler extends DefaultComponentHandler { + + public EnumEditorHandler(ClassDescriptor beanClass) { + super(beanClass); + ClassDescriptorLoader.checkSupportClass(getClass(), beanClass, EnumEditor.class); + } + + @Override + protected void configureProxyEventInfo() { + super.configureProxyEventInfo(); + addProxyEventInfo("getSelectedIndex", ItemListener.class); + addProxyEventInfo("getSelectedItem", ItemListener.class); + } + + @Override + protected CompiledObject createCompiledObject(String id, JAXXCompiler compiler) throws CompilerException { + return new CompiledItemContainer(id, getBeanClass(), compiler); + } +// @Override +// public void compileChildrenSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { +// super.compileChildrenSecondPass(tag, compiler); +// CompiledItemContainer list = (CompiledItemContainer) compiler.getOpenComponent(); +// List<Item> items = list.getItems(); +// if (items != null && !items.isEmpty()) { +// String listName = list.getId() + "$items"; +// list.appendAdditionCode("java.util.List<jaxx.runtime.swing.Item> " + listName + " = new java.util.ArrayList<jaxx.runtime.swing.Item>();"); +// for (Item item : items) { +// String id = item.getId(); +// CompiledObject compiledItem = new CompiledObject(id, ClassDescriptorLoader.getClassDescriptor(Item.class), compiler); +// compiledItem.setConstructorParams(TypeManager.getJavaCode(id) + ", " + TypeManager.getJavaCode(item.getLabel()) + ", " + TypeManager.getJavaCode(item.getValue()) + ", " + item.isSelected()); +// compiler.registerCompiledObject(compiledItem); +// list.appendAdditionCode(listName + ".add(" + id + ");"); +// } +// list.appendAdditionCode(list.getId() + ".setItems(" + listName + ");"); +// } +// } +} + + + diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/ItemHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/ItemHandler.java new file mode 100644 index 0000000..9de9b60 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/ItemHandler.java @@ -0,0 +1,144 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.CompilerException; +import jaxx.UnsupportedAttributeException; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.runtime.swing.Item; +import jaxx.tags.TagHandler; +import jaxx.types.TypeManager; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; + +import java.io.IOException; +import java.util.List; + +public class ItemHandler implements TagHandler { + private String DATA_BINDING = "<data binding has not been processed yet>"; + + public void compileFirstPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + compileChildrenFirstPass(tag, compiler); + } + + public void compileSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + String id = tag.getAttribute("id"); + if (id == null || id.length() == 0) + id = compiler.getAutoId(ClassDescriptorLoader.getClassDescriptor(Item.class)); + String label = null; + String value = null; + boolean selected = false; + NamedNodeMap children = tag.getAttributes(); + + for (int i = 0; i < children.getLength(); i++) { + Attr attribute = (Attr) children.item(i); + String name = attribute.getName(); + String attrValue = attribute.getValue(); + if (name.equals("id")) { + // already handled + continue; + } + if (name.equals(Item.LABEL_PROPERTY)) { + String labelBinding = compiler.processDataBindings(attrValue, ClassDescriptorLoader.getClassDescriptor(String.class)); + if (labelBinding != null) + compiler.registerDataBinding(labelBinding, id + ".label", id + ".setLabel(" + labelBinding + ");"); + else + label = attrValue; + continue; + } + if (name.equals(Item.VALUE_PROPERTY)) { + String valueBinding = compiler.processDataBindings(attrValue, ClassDescriptorLoader.getClassDescriptor(Object.class)); + if (valueBinding != null) { + value = DATA_BINDING; + compiler.registerDataBinding(valueBinding, id + ".value", id + ".setValue(" + valueBinding + ");"); + } else + value = attrValue; + continue; + } + if (name.equals(Item.SELECTED_PROPERTY)) { + String selectedBinding = compiler.processDataBindings(attrValue, ClassDescriptorLoader.getClassDescriptor(Boolean.class)); + if (selectedBinding != null) + compiler.registerDataBinding(selectedBinding, id + ".selected", id + ".setSelected(" + selectedBinding + ");"); + else + selected = (Boolean) TypeManager.convertFromString(attrValue, Boolean.class); + continue; + } + + if (!name.startsWith("xmlns") && !JAXXCompiler.JAXX_INTERNAL_NAMESPACE.equals(attribute.getNamespaceURI())) { + throw new UnsupportedAttributeException(name); + } + } + + Item item = new Item(id, label, value, selected); + CompiledItemContainer list = (CompiledItemContainer) compiler.getOpenComponent(); + if (value == null) + compiler.reportError("<item> tag is missing required 'value' attribute"); + else { + if (!value.equals(DATA_BINDING)) { + List<Item> items = list.getItems(); + for (Item item1 : items) { + if (item1.getValue().equals(value)) { + compiler.reportError("This container already has an <item> tag with the value '" + value + "'"); + break; + } + } + } + list.openItem(item); + compileChildrenSecondPass(tag, compiler); + list.closeItem(item); + } + } + + + protected void compileChildrenFirstPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + NodeList children = tag.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node node = children.item(i); + int nodeType = node.getNodeType(); + if (nodeType == Node.ELEMENT_NODE) { + Element child = (Element) node; + compileChildTagFirstPass(child, compiler); + } else + if (nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE) { + String text = ((Text) node).getData().trim(); + if (text.length() > 0) + compiler.reportError("tag '" + tag.getLocalName() + "' may not contain text ('" + ((Text) node).getData().trim() + "')"); + } + } + } + + + protected void compileChildrenSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + NodeList children = tag.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node node = children.item(i); + int nodeType = node.getNodeType(); + if (nodeType == Node.ELEMENT_NODE) { + Element child = (Element) node; + compileChildTagSecondPass(child, compiler); + } else + if (nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE) { + String text = ((Text) node).getData().trim(); + if (text.length() > 0) + compiler.reportError("tag '" + tag.getLocalName() + "' may not contain text ('" + ((Text) node).getData().trim() + "')"); + } + } + } + + + protected void compileChildTagFirstPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + compiler.compileFirstPass(tag); + } + + + protected void compileChildTagSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + compiler.compileSecondPass(tag); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JAXXTabHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JAXXTabHandler.java new file mode 100644 index 0000000..acf8f93 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JAXXTabHandler.java @@ -0,0 +1,28 @@ +/* +* \#\#% Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 Code Lutin, +* Tony Chemit, Gabriel Landais +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* \#\#% */ +package jaxx.tags.swing; + +import jaxx.reflect.ClassDescriptor; + +/** @author chemit */ +public class JAXXTabHandler extends TableHandler { + public JAXXTabHandler(ClassDescriptor beanClass) { + super(beanClass); + } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JCheckBoxHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JCheckBoxHandler.java new file mode 100644 index 0000000..be9be7d --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JCheckBoxHandler.java @@ -0,0 +1,25 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.tags.DefaultComponentHandler; + +import javax.swing.AbstractButton; +import javax.swing.event.ChangeListener; + +public class JCheckBoxHandler extends DefaultComponentHandler { + public JCheckBoxHandler(ClassDescriptor beanClass) { + super(beanClass); + ClassDescriptorLoader.checkSupportClass(getClass(), beanClass, AbstractButton.class); + } + + @Override + protected void configureProxyEventInfo() { + super.configureProxyEventInfo(); + addProxyEventInfo("isSelected", ChangeListener.class, "model"); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JComboBoxHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JComboBoxHandler.java new file mode 100644 index 0000000..56a1d8d --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JComboBoxHandler.java @@ -0,0 +1,62 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.CompilerException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.runtime.swing.Item; +import jaxx.runtime.swing.JAXXComboBox; +import jaxx.tags.DefaultComponentHandler; +import jaxx.types.TypeManager; +import org.w3c.dom.Element; + +import java.awt.event.ItemListener; +import java.io.IOException; +import java.util.List; + +public class JComboBoxHandler extends DefaultComponentHandler { + + public JComboBoxHandler(ClassDescriptor beanClass) { + super(beanClass); + ClassDescriptorLoader.checkSupportClass(getClass(), beanClass, JAXXComboBox.class); + } + + @Override + protected void configureProxyEventInfo() { + super.configureProxyEventInfo(); + addProxyEventInfo("getSelectedIndex", ItemListener.class); + addProxyEventInfo("getSelectedItem", ItemListener.class); + } + + @Override + protected CompiledObject createCompiledObject(String id, JAXXCompiler compiler) throws CompilerException { + return new CompiledItemContainer(id, getBeanClass(), compiler); + } + + @Override + public void compileChildrenSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + super.compileChildrenSecondPass(tag, compiler); + CompiledItemContainer list = (CompiledItemContainer) compiler.getOpenComponent(); + List<Item> items = list.getItems(); + if (items != null && !items.isEmpty()) { + String listName = list.getId() + "$items"; + list.appendAdditionCode("java.util.List<jaxx.runtime.swing.Item> " + listName + " = new java.util.ArrayList<jaxx.runtime.swing.Item>();"); + for (Item item : items) { + String id = item.getId(); + CompiledObject compiledItem = new CompiledObject(id, ClassDescriptorLoader.getClassDescriptor(Item.class), compiler); + compiledItem.setConstructorParams(TypeManager.getJavaCode(id) + ", " + TypeManager.getJavaCode(item.getLabel()) + ", " + TypeManager.getJavaCode(item.getValue()) + ", " + item.isSelected()); + compiler.registerCompiledObject(compiledItem); + list.appendAdditionCode(listName + ".add(" + id + ");"); + } + list.appendAdditionCode(list.getId() + ".setItems(" + listName + ");"); + } + } +} + + + diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JInternalFrameHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JInternalFrameHandler.java new file mode 100644 index 0000000..e59259a --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JInternalFrameHandler.java @@ -0,0 +1,54 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.CompilerException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.tags.DefaultComponentHandler; +import org.w3c.dom.Element; + +import javax.swing.JInternalFrame; +import javax.swing.JMenuBar; +import javax.swing.WindowConstants; + +public class JInternalFrameHandler extends DefaultComponentHandler { + + public JInternalFrameHandler(ClassDescriptor beanClass) { + super(beanClass); + ClassDescriptorLoader.checkSupportClass(getClass(), beanClass, JInternalFrame.class); + } + + @Override + public CompiledObject createCompiledObject(String id, JAXXCompiler compiler) throws CompilerException { + return new CompiledObject(id, getBeanClass(), compiler) { + @Override + public void addChild(CompiledObject child, String constraints, JAXXCompiler compiler) throws CompilerException { + if (ClassDescriptorLoader.getClassDescriptor(JMenuBar.class).isAssignableFrom(child.getObjectClass())) { + appendAdditionCode(getId() + ".setJMenuBar(" + child.getId() + ");"); + } else { + super.addChild(child, constraints, compiler); + } + } + }; + } + + @Override + protected void setDefaults(CompiledObject object, Element tag, JAXXCompiler compiler) throws CompilerException { + super.setDefaults(object, tag, compiler); + setAttribute(object, "visible", "true", false, compiler); + setAttribute(object, "closable", "true", false, compiler); + setAttribute(object, "defaultCloseOperation", String.valueOf(WindowConstants.DISPOSE_ON_CLOSE), false, compiler); + } + + + @Override + public void setAttributes(CompiledObject object, Element tag, JAXXCompiler compiler) throws CompilerException { + super.setAttributes(object, tag, compiler); + compiler.appendInitializerCode(object.getId() + ".pack();\n"); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JListHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JListHandler.java new file mode 100644 index 0000000..40d436b --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JListHandler.java @@ -0,0 +1,64 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.CompilerException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.runtime.swing.Item; +import jaxx.runtime.swing.JAXXList; +import jaxx.tags.DefaultComponentHandler; +import jaxx.types.TypeManager; +import org.w3c.dom.Element; + +import javax.swing.event.ListSelectionListener; +import java.io.IOException; +import java.util.List; + +public class JListHandler extends DefaultComponentHandler { + public JListHandler(ClassDescriptor beanClass) { + super(beanClass); + ClassDescriptorLoader.checkSupportClass(getClass(), beanClass, JAXXList.class); + } + + @Override + protected void configureProxyEventInfo() { + super.configureProxyEventInfo(); + addProxyEventInfo("getSelectedIndex", ListSelectionListener.class, "selectionModel"); + addProxyEventInfo("getSelectedIndices", ListSelectionListener.class, "selectionModel"); + addProxyEventInfo("getSelectedValue", ListSelectionListener.class, "selectionModel"); + addProxyEventInfo("getSelectedValues", ListSelectionListener.class, "selectionModel"); + } + + @Override + public CompiledObject createCompiledObject(String id, JAXXCompiler compiler) throws CompilerException { + return new CompiledItemContainer(id, getBeanClass(), compiler); + } + + @Override + public void compileChildrenSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + super.compileChildrenSecondPass(tag, compiler); + CompiledItemContainer list = (CompiledItemContainer) compiler.getOpenComponent(); + List<Item> items = list.getItems(); + if (items != null && !items.isEmpty()) { + String listName = list.getId() + "$items"; + //TODO Add the correct generic type + list.appendAdditionCode("java.util.List<jaxx.runtime.swing.Item> " + listName + " = new java.util.ArrayList<jaxx.runtime.swing.Item>();"); + for (Item item : items) { + String id = item.getId(); + CompiledObject compiledItem = new CompiledObject(id, ClassDescriptorLoader.getClassDescriptor(Item.class), compiler); + compiledItem.setConstructorParams(TypeManager.getJavaCode(id) + ", " + TypeManager.getJavaCode(item.getLabel()) + ", " + TypeManager.getJavaCode(item.getValue()) + ", " + item.isSelected()); + compiler.registerCompiledObject(compiledItem); + list.appendAdditionCode(listName + ".add(" + id + ");"); + } + list.appendAdditionCode(list.getId() + ".setItems(" + listName + ");"); + } + } +} + + + diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JMenuHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JMenuHandler.java new file mode 100644 index 0000000..1bb103f --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JMenuHandler.java @@ -0,0 +1,26 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.tags.DefaultComponentHandler; + +import javax.swing.JMenu; +import javax.swing.event.MenuListener; + +public class JMenuHandler extends DefaultComponentHandler { + + public JMenuHandler(ClassDescriptor beanClass) { + super(beanClass); + ClassDescriptorLoader.checkSupportClass(getClass(), beanClass, JMenu.class); + } + + @Override + protected void configureProxyEventInfo() { + super.configureProxyEventInfo(); + addProxyEventInfo("isSelected", MenuListener.class); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JPasswordFieldHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JPasswordFieldHandler.java new file mode 100644 index 0000000..c15dadd --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JPasswordFieldHandler.java @@ -0,0 +1,25 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; + +import javax.swing.JPasswordField; +import javax.swing.event.DocumentListener; + +public class JPasswordFieldHandler extends JTextComponentHandler { + + public JPasswordFieldHandler(ClassDescriptor beanClass) { + super(beanClass); + ClassDescriptorLoader.checkSupportClass(getClass(), beanClass, JPasswordField.class); + } + + @Override + protected void configureProxyEventInfo() { + super.configureProxyEventInfo(); + addProxyEventInfo("getPassword", DocumentListener.class, "document"); + } +} diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JPopupMenuHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JPopupMenuHandler.java new file mode 100644 index 0000000..47bc082 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JPopupMenuHandler.java @@ -0,0 +1,31 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.tags.DefaultComponentHandler; +import org.w3c.dom.Element; + +import javax.swing.JPopupMenu; + +public class JPopupMenuHandler extends DefaultComponentHandler { + public JPopupMenuHandler(ClassDescriptor beanClass) { + super(beanClass); + ClassDescriptorLoader.checkSupportClass(getClass(), beanClass, JPopupMenu.class); + } + + @Override + public boolean isContainer() { + return true; + } + + @Override + protected void openComponent(CompiledObject object, Element tag, JAXXCompiler compiler) { + compiler.openInvisibleComponent(object); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JProgressBarHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JProgressBarHandler.java new file mode 100644 index 0000000..5e087c8 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JProgressBarHandler.java @@ -0,0 +1,26 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.tags.DefaultComponentHandler; + +import javax.swing.JProgressBar; +import javax.swing.event.ChangeListener; + +public class JProgressBarHandler extends DefaultComponentHandler { + + public JProgressBarHandler(ClassDescriptor beanClass) { + super(beanClass); + ClassDescriptorLoader.checkSupportClass(getClass(), beanClass, JProgressBar.class); + } + + @Override + protected void configureProxyEventInfo() { + super.configureProxyEventInfo(); + addProxyEventInfo("getValue", ChangeListener.class, "change"); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JRadioButtonHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JRadioButtonHandler.java new file mode 100644 index 0000000..b5a0b8b --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JRadioButtonHandler.java @@ -0,0 +1,81 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.CompilerException; +import jaxx.UnsupportedAttributeException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.runtime.swing.JAXXButtonGroup; +import jaxx.tags.DefaultComponentHandler; +import jaxx.types.TypeManager; + +import javax.swing.AbstractButton; +import javax.swing.event.ChangeListener; + +public class JRadioButtonHandler extends DefaultComponentHandler { + private static final String VALUE_PROPERTY = JAXXButtonGroup.VALUE_CLIENT_PROPERTY.substring(1); + private static final String BUTTON_GROUP_PROPERTY = JAXXButtonGroup.BUTTON8GROUP_CLIENT_PROPERTY.substring(1); + + public JRadioButtonHandler(ClassDescriptor beanClass) { + super(beanClass); + ClassDescriptorLoader.checkSupportClass(getClass(), beanClass, AbstractButton.class); + } + + @Override + protected void configureProxyEventInfo() { + super.configureProxyEventInfo(); + addProxyEventInfo("isSelected", ChangeListener.class, "model"); + } + + @Override + public ClassDescriptor getPropertyType(CompiledObject object, String name, JAXXCompiler compiler) throws CompilerException { + if (name.equals(BUTTON_GROUP_PROPERTY)) { + return null; // accepts either a String or a ButtonGroup + } else if (name.equals(VALUE_PROPERTY)) { + return ClassDescriptorLoader.getClassDescriptor(Object.class); + } else { + return super.getPropertyType(object, name, compiler); + } + } + + @Override + public boolean isMemberBound(String name) throws UnsupportedAttributeException { + return !(name.equals(BUTTON_GROUP_PROPERTY) || name.equals(VALUE_PROPERTY)) && super.isMemberBound(name); + } + + // handle buttonGroup assignment in addition block rather than initialization block + @Override + public void setProperty(CompiledObject object, String name, Object value, JAXXCompiler compiler) { + if (name.equals(BUTTON_GROUP_PROPERTY)) { + object.appendAdditionCode(getSetPropertyCode(object.getJavaCode(), name, TypeManager.getJavaCode(value), compiler)); + } else { + super.setProperty(object, name, value, compiler); + } + } + + @Override + public String getSetPropertyCode(String id, String name, String valueCode, JAXXCompiler compiler) throws CompilerException { + if (name.equals(BUTTON_GROUP_PROPERTY)) { + if (valueCode.startsWith("\"") && valueCode.endsWith("\"")) { + valueCode = valueCode.substring(1, valueCode.length() - 1); + CompiledObject buttonGroup = compiler.getCompiledObject(valueCode); + if (buttonGroup == null) { + buttonGroup = new CompiledObject(valueCode, ClassDescriptorLoader.getClassDescriptor(JAXXButtonGroup.class), compiler); + compiler.registerCompiledObject(buttonGroup); + } + } + return "{ javax.swing.ButtonGroup $buttonGroup = " + valueCode + "; " + id + ".putClientProperty(\"$buttonGroup\", $buttonGroup); $buttonGroup.add(" + id + "); }\n"; + } else if (name.equals(VALUE_PROPERTY)) { + return "{ " + id + ".putClientProperty(\"" + JAXXButtonGroup.VALUE_CLIENT_PROPERTY + "\", " + valueCode + "); Object $buttonGroup = " + id + ".getClientProperty(\"" + JAXXButtonGroup.BUTTON8GROUP_CLIENT_PROPERTY + "\");" + + " if ($buttonGroup instanceof jaxx.runtime.swing.JAXXButtonGroup) { ((jaxx.runtime.swing.JAXXButtonGroup) $buttonGroup).updateSelectedValue(); } }\n"; + } else { + return super.getSetPropertyCode(id, name, valueCode, compiler); + } + } + +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JScrollPaneHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JScrollPaneHandler.java new file mode 100644 index 0000000..aa6d15e --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JScrollPaneHandler.java @@ -0,0 +1,41 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.CompilerException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.tags.DefaultComponentHandler; + +import javax.swing.JScrollPane; + +public class JScrollPaneHandler extends DefaultComponentHandler { + + public JScrollPaneHandler(ClassDescriptor beanClass) { + super(beanClass); + ClassDescriptorLoader.checkSupportClass(getClass(), beanClass, JScrollPane.class); + } + + @Override + public CompiledObject createCompiledObject(String id, JAXXCompiler compiler) throws CompilerException { + return new CompiledObject(id, getBeanClass(), compiler) { + boolean hasChild; + + @Override + public void addChild(CompiledObject child, String constraints, JAXXCompiler compiler) throws CompilerException { + if (constraints != null) { + compiler.reportError("JScrollPane does not accept constraints"); + } + if (hasChild) { + compiler.reportError("JScrollPane may only have one child"); + } + super.addChild(child, constraints, compiler); + hasChild = true; + } + }; + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JSliderHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JSliderHandler.java new file mode 100644 index 0000000..195bf5c --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JSliderHandler.java @@ -0,0 +1,45 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.CompilerException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.tags.DefaultComponentHandler; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; + +import javax.swing.JSlider; +import javax.swing.event.ChangeListener; + +public class JSliderHandler extends DefaultComponentHandler { + public JSliderHandler(ClassDescriptor beanClass) { + super(beanClass); + if (!ClassDescriptorLoader.getClassDescriptor(JSlider.class).isAssignableFrom(beanClass)) + throw new IllegalArgumentException(getClass().getName() + " does not support the class " + beanClass.getName()); + } + + + protected int getAttributeOrdering(Attr attr) { + if (attr.getName().equals("value")) + return 1; + else + return super.getAttributeOrdering(attr); + } + + + protected void setDefaults(CompiledObject object, Element tag, JAXXCompiler compiler) throws CompilerException { + super.setDefaults(object, tag, compiler); + setAttribute(object, "value", "0", false, compiler); + } + + + protected void configureProxyEventInfo() { + super.configureProxyEventInfo(); + addProxyEventInfo("getValue", ChangeListener.class, "model"); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JSpinnerHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JSpinnerHandler.java new file mode 100644 index 0000000..c839b0e --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JSpinnerHandler.java @@ -0,0 +1,92 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.CompilerException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.tags.DefaultComponentHandler; +import org.w3c.dom.Element; + +import javax.swing.JSpinner; +import javax.swing.event.ChangeListener; + +public class JSpinnerHandler extends DefaultComponentHandler { + public static String MINIMUM_PROPERTY = "minimum"; + public static String MAXIMUM_PROPERTY = "maximum"; + public static String VALUE_PROPERTY = "value"; + + public JSpinnerHandler(ClassDescriptor beanClass) { + super(beanClass); + ClassDescriptorLoader.checkSupportClass(getClass(), beanClass, JSpinner.class); + } + + public static class CompiledSpinner extends CompiledObject { + Integer minimum = null; + Integer maximum = null; + Integer value = null; + + public CompiledSpinner(String id, ClassDescriptor objectClass, JAXXCompiler compiler) throws CompilerException { + super(id, objectClass, compiler); + } + } + + @Override + public CompiledObject createCompiledObject(String id, JAXXCompiler compiler) throws CompilerException { + return new CompiledSpinner(id, getBeanClass(), compiler); + } + + @Override + protected void configureProxyEventInfo() { + super.configureProxyEventInfo(); + addProxyEventInfo("getValue", ChangeListener.class, "model"); + } + + @Override + public ClassDescriptor getPropertyType(CompiledObject object, String propertyName, JAXXCompiler compiler) throws CompilerException { + if (propertyName.equals(MINIMUM_PROPERTY) || propertyName.equals(MAXIMUM_PROPERTY) || + propertyName.equals(VALUE_PROPERTY)) { + return ClassDescriptorLoader.getClassDescriptor(Integer.class); + } + return super.getPropertyType(object, propertyName, compiler); + } + + @Override + public void setProperty(CompiledObject object, String name, Object value, JAXXCompiler compiler) throws CompilerException { + if (name.equals(MINIMUM_PROPERTY)) { + ((CompiledSpinner) object).minimum = (Integer) value; + } else if (name.equals(MAXIMUM_PROPERTY)) { + ((CompiledSpinner) object).maximum = (Integer) value; + } else if (name.equals(VALUE_PROPERTY)) { + ((CompiledSpinner) object).value = (Integer) value; + } else { + super.setProperty(object, name, value, compiler); + } + } + + @Override + protected void closeComponent(CompiledObject object, Element tag, JAXXCompiler compiler) throws CompilerException { + CompiledSpinner spinner = (CompiledSpinner) object; + if (spinner.minimum != null || spinner.maximum != null || spinner.value != null) { + if (spinner.getConstructorParams() != null) { + compiler.reportError("constructorParams and minimum/maximum may not both be specified for the same JSpinner"); + } + if (spinner.minimum == null) { + spinner.minimum = Math.min(0, spinner.maximum != null ? spinner.maximum.intValue() : 0); + } + if (spinner.maximum == null) { + spinner.maximum = Math.max(100, spinner.minimum.intValue()); + } + if (spinner.value == null) { + spinner.value = spinner.minimum; + } + spinner.setConstructorParams("new SpinnerNumberModel(" + spinner.value + ", " + spinner.minimum + ", " + spinner.maximum + ", 1)"); + } + + super.closeComponent(object, tag, compiler); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JSplitPaneHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JSplitPaneHandler.java new file mode 100644 index 0000000..b9ef79b --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JSplitPaneHandler.java @@ -0,0 +1,69 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.CompilerException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.tags.DefaultComponentHandler; +import org.w3c.dom.Element; + +import javax.swing.JSplitPane; +import java.awt.Component; + +public class JSplitPaneHandler extends DefaultComponentHandler { + public JSplitPaneHandler(ClassDescriptor beanClass) { + super(beanClass); + ClassDescriptorLoader.checkSupportClass(getClass(), beanClass, JSplitPane.class); + } + + protected Component createRawComponent(Element tag) { + return new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); + } + + /** + * Add support for <code>orientation="vertical"</code> and <code>orientation="horizontal"</code>. The + * values required by the JAXXBeanInfo are the unwieldy <code>vertical_split</code> and <code>horizontal_split</code> + * (which are also recognized). + */ + @Override + protected int constantValue(String key, String value) { + if (key.equals("orientation")) { + value = value.trim().toLowerCase(); + if (value.equals("horizontal") || value.equals("horizontal_split")) { + return JSplitPane.HORIZONTAL_SPLIT; + } + if (value.equals("vertical") || value.equals("vertical_split")) { + return JSplitPane.VERTICAL_SPLIT; + } + throw new IllegalArgumentException("orientation must be 'horizontal' or 'vertical', found '" + value + "'"); + } + return super.constantValue(key, value); + } + + @Override + public CompiledObject createCompiledObject(String id, JAXXCompiler compiler) throws CompilerException { + return new CompiledObject(id, getBeanClass(), compiler) { + private int count; + + @Override + public void addChild(CompiledObject child, String constraints, JAXXCompiler compiler) throws CompilerException { + if (constraints != null) { + compiler.reportError("JSplitPane does not accept constraints"); + } + if (count == 0) { + super.addChild(child, "JSplitPane.LEFT", compiler); + } else if (count == 1) { + super.addChild(child, "JSplitPane.RIGHT", compiler); + } else { + compiler.reportError("JSplitPane is limited to two children"); + } + count++; + } + }; + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JTabbedPaneHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JTabbedPaneHandler.java new file mode 100644 index 0000000..7ca446e --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JTabbedPaneHandler.java @@ -0,0 +1,135 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.CompilerException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.I18nHelper; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.runtime.swing.TabInfo; +import jaxx.tags.DefaultComponentHandler; +import jaxx.types.TypeManager; + +import javax.swing.Icon; +import javax.swing.JTabbedPane; +import javax.swing.event.ChangeListener; +import java.awt.Color; +import java.awt.event.ContainerListener; + +public class JTabbedPaneHandler extends DefaultComponentHandler { + public JTabbedPaneHandler(ClassDescriptor beanClass) { + super(beanClass); + ClassDescriptorLoader.checkSupportClass(getClass(), beanClass, JTabbedPane.class); + } + + public static class CompiledTabbedPane extends CompiledObject { + private static final TabInfo USED = new TabInfo("ALREADY USED"); + + int tabCount; + TabInfo tabInfo; + + public CompiledTabbedPane(String id, ClassDescriptor objectClass, JAXXCompiler compiler) throws CompilerException { + super(id, objectClass, compiler); + } + + @Override + public void addChild(CompiledObject child, String constraints, JAXXCompiler compiler) throws CompilerException { + if (constraints != null) { + compiler.reportError("JTabbedPane tabs may not have constraints"); + } + + super.addChild(child, constraints, compiler); + + if (tabInfo == null) { + compiler.reportError("JTabbedPaneHandler may only have 'tab' tags as children (found " + child.getObjectClass() + ")"); + return; + } else if (tabInfo == USED) { + compiler.reportError("<tab> tags may only have one child component"); + return; + } + + int tabIndex = ++tabCount - 1; + appendAdditionCode(tabInfo.getId() + ".addPropertyChangeListener(new jaxx.runtime.swing.TabInfoPropertyChangeListener(" + getId() + ", " + tabIndex + "));"); + + String title = tabInfo.getTitle(); + if (title != null) { + if (I18nHelper.isI18nAttribute("title")) { + if (!title.startsWith("_(\"")) { + // we did not have the invocation code, add it + title = I18nHelper.addI18nInvocation(getId(), "title", TypeManager.getJavaCode(title), compiler); + } + } else { + title = TypeManager.getJavaCode(title); + } + appendAdditionCode(getId() + ".setTitleAt(" + tabIndex + ", " + title + ");"); + } + + String toolTipText = tabInfo.getToolTipText(); + if (toolTipText != null) { + if (I18nHelper.isI18nAttribute("toolTipText")) { + if (!toolTipText.startsWith("_(\"")) { + // we did not have the invocation code, add it + toolTipText = I18nHelper.addI18nInvocation(getId(), "toolTipText", TypeManager.getJavaCode(toolTipText), compiler); + } + } else { + toolTipText = TypeManager.getJavaCode(toolTipText); + } + appendAdditionCode(getId() + ".setToolTipTextAt(" + tabIndex + ", " + toolTipText + ");"); + } + + boolean enabled = tabInfo.isEnabled(); + if (!enabled) { + appendAdditionCode(getId() + ".setEnabledAt(" + tabIndex + ", false);"); + } + + Color foreground = tabInfo.getForeground(); + if (foreground != null) { + appendAdditionCode(getId() + ".setForegroundAt(" + tabIndex + ", " + TypeManager.getJavaCode(foreground) + ");"); + } + + Color background = tabInfo.getBackground(); + if (background != null) { + appendAdditionCode(getId() + ".setBackgroundAt(" + tabIndex + ", " + TypeManager.getJavaCode(background) + ");"); + } + + int mnemonic = tabInfo.getMnemonic(); + if (mnemonic != -1) { + appendAdditionCode(getId() + ".setMnemonicAt(" + tabIndex + ", " + mnemonic + ");"); + } + + int displayedMnemonicIndex = tabInfo.getDisplayedMnemonicIndex(); + if (displayedMnemonicIndex != -1) { + appendAdditionCode(getId() + ".setDisplayedMnemonicIndexAt(" + tabIndex + ", " + displayedMnemonicIndex + ");"); + } + + Icon icon = tabInfo.getIcon(); + if (icon != null) { + appendAdditionCode(getId() + ".setIconAt(" + tabIndex + ", " + icon + ");"); + } + + Icon disabledIcon = tabInfo.getDisabledIcon(); + if (disabledIcon != null) { + appendAdditionCode(getId() + ".setDisabledIconAt(" + tabIndex + ", " + disabledIcon + ");"); + } + + tabInfo = USED; + } + } + + @Override + public CompiledObject createCompiledObject(String id, JAXXCompiler compiler) throws CompilerException { + return new CompiledTabbedPane(id, getBeanClass(), compiler); + } + + @Override + protected void configureProxyEventInfo() { + super.configureProxyEventInfo(); + addProxyEventInfo("getSelectedIndex", ChangeListener.class); + addProxyEventInfo("getSelectedComponent", ChangeListener.class); + addProxyEventInfo("getTabCount", ContainerListener.class); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JTextComponentHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JTextComponentHandler.java new file mode 100644 index 0000000..1c91b2e --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JTextComponentHandler.java @@ -0,0 +1,70 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.CompilerException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.tags.DefaultComponentHandler; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; + +import javax.swing.JTextArea; +import javax.swing.event.DocumentListener; +import javax.swing.text.JTextComponent; +import jaxx.runtime.SwingUtil; + +public class JTextComponentHandler extends DefaultComponentHandler { + private static final int DEFAULT_COLUMNS = 15; + + public JTextComponentHandler(ClassDescriptor beanClass) { + super(beanClass); + ClassDescriptorLoader.checkSupportClass(getClass(), beanClass, JTextComponent.class); + } + + @Override + protected void setDefaults(CompiledObject object, Element tag, JAXXCompiler compiler) throws CompilerException { + super.setDefaults(object, tag, compiler); + try { + object.getObjectClass().getMethodDescriptor("setColumns", ClassDescriptorLoader.getClassDescriptor(int.class)); + setAttribute(object, "columns", String.valueOf(DEFAULT_COLUMNS), false, compiler); + } + catch (NoSuchMethodException e) { + // ignore ? + } + + if (ClassDescriptorLoader.getClassDescriptor(JTextArea.class).isAssignableFrom(object.getObjectClass())) { + setAttribute(object, "lineWrap", "true", false, compiler); + setAttribute(object, "wrapStyleWord", "true", false, compiler); + } + } + + @Override + public String getSetPropertyCode(String id, String name, String valueCode, JAXXCompiler compiler) throws CompilerException { + if (name.equals("text")) { + return SwingUtil.class.getName()+".setText(" + id + ", " + valueCode + ");\n"; + //return "jaxx.runtime.swing.Utils.setText(" + id + ", " + valueCode + ");\n"; + } + return super.getSetPropertyCode(id, name, valueCode, compiler); + } + + @Override + protected int getAttributeOrdering(Attr attr) { + // delay text in case other attributes affect how it's processed, as is the case + // with JEditorPane's contentType + if (attr.getName().equals("text")) { + return 1; + } + return super.getAttributeOrdering(attr); + } + + @Override + protected void configureProxyEventInfo() { + super.configureProxyEventInfo(); + addProxyEventInfo("getText", DocumentListener.class, "document"); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JToolBarHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JToolBarHandler.java new file mode 100644 index 0000000..8135bc2 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JToolBarHandler.java @@ -0,0 +1,38 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.tags.DefaultComponentHandler; + +import javax.swing.JToolBar; + +public class JToolBarHandler extends DefaultComponentHandler { + public JToolBarHandler(ClassDescriptor beanClass) { + super(beanClass); + ClassDescriptorLoader.checkSupportClass(getClass(), beanClass, JToolBar.class); + } + + /** + * Add support for <code>orientation="vertical"</code> and <code>orientation="horizontal"</code>. These values should + * have been supported without any special effort on my part, but JToolBar's BeanInfo doesn't contain the enum attribute + * for the orientation property. + */ + @Override + protected int constantValue(String key, String value) { + if (key.equals("orientation")) { + value = value.trim().toLowerCase(); + if (value.equals("horizontal")) { + return JToolBar.HORIZONTAL; + } + if (value.equals("vertical")) { + return JToolBar.VERTICAL; + } + throw new IllegalArgumentException("orientation must be 'horizontal' or 'vertical', found '" + value + "'"); + } + return super.constantValue(key, value); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JTreeHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JTreeHandler.java new file mode 100644 index 0000000..0181aa2 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JTreeHandler.java @@ -0,0 +1,69 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.CompilerException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.runtime.swing.Item; +import jaxx.runtime.swing.JAXXTree; +import jaxx.tags.DefaultComponentHandler; +import jaxx.types.TypeManager; +import org.w3c.dom.Element; + +import javax.swing.event.TreeSelectionListener; +import java.io.IOException; +import java.util.List; + +public class JTreeHandler extends DefaultComponentHandler { + public JTreeHandler(ClassDescriptor beanClass) { + super(beanClass); + ClassDescriptorLoader.checkSupportClass(getClass(), beanClass, JAXXTree.class); + } + + @Override + protected void configureProxyEventInfo() { + super.configureProxyEventInfo(); + addProxyEventInfo("getSelectionCount", TreeSelectionListener.class, "selectionModel"); + addProxyEventInfo("getSelectionPath", TreeSelectionListener.class, "selectionModel"); + addProxyEventInfo("getSelectionPaths", TreeSelectionListener.class, "selectionModel"); + addProxyEventInfo("getSelectionRows", TreeSelectionListener.class, "selectionModel"); + addProxyEventInfo("getSelectionValue", TreeSelectionListener.class, "selectionModel"); + } + + @Override + public CompiledObject createCompiledObject(String id, JAXXCompiler compiler) throws CompilerException { + return new CompiledItemContainer(id, getBeanClass(), compiler); + } + + private void createItems(CompiledObject tree, List<Item> items, String addMethod, JAXXCompiler compiler) throws CompilerException { + for (Item item : items) { + String id = item.getId(); + CompiledObject compiledItem = new CompiledObject(id, ClassDescriptorLoader.getClassDescriptor(Item.class), compiler); + compiledItem.setConstructorParams(TypeManager.getJavaCode(id) + ", " + TypeManager.getJavaCode(item.getLabel()) + ", " + TypeManager.getJavaCode(item.getValue()) + ", " + item.isSelected()); + compiler.registerCompiledObject(compiledItem); + tree.appendAdditionCode(addMethod + "(" + id + ");"); + createItems(tree, item.getChildren(), id + ".addChild", compiler); + } + } + + @Override + public void compileChildrenSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + super.compileChildrenSecondPass(tag, compiler); + CompiledItemContainer tree = (CompiledItemContainer) compiler.getOpenComponent(); + List<Item> items = tree.getItems(); + if (items != null && !items.isEmpty()) { + String listName = tree.getId() + "$items"; + tree.appendAdditionCode("java.util.List<jaxx.runtime.swing.Item> " + listName + " = new java.util.ArrayList<jaxx.runtime.swing.Item>();"); + createItems(tree, items, listName + ".add", compiler); + tree.appendAdditionCode(tree.getId() + ".setItems(" + listName + ");"); + } + } +} + + + diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JWindowHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JWindowHandler.java new file mode 100644 index 0000000..b5ae451 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/JWindowHandler.java @@ -0,0 +1,61 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.CompilerException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.tags.DefaultComponentHandler; +import org.w3c.dom.Element; + +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JMenuBar; +import javax.swing.JWindow; +import java.io.IOException; +import java.util.Map; + +public class JWindowHandler extends DefaultComponentHandler { + + public JWindowHandler(ClassDescriptor beanClass) { + super(beanClass); + ClassDescriptorLoader.checkSupportClass(getClass(), beanClass, JWindow.class, JFrame.class, JDialog.class); + } + + @Override + public CompiledObject createCompiledObject(String id, JAXXCompiler compiler) throws CompilerException { + return new CompiledObject(id, getBeanClass(), compiler) { + @Override + public void addChild(CompiledObject child, String constraints, JAXXCompiler compiler) throws CompilerException { + if (ClassDescriptorLoader.getClassDescriptor(JMenuBar.class).isAssignableFrom(child.getObjectClass())) { + appendAdditionCode(getId() + ".setJMenuBar(" + child.getId() + ");"); + } else { + super.addChild(child, constraints, compiler); + } + } + }; + } + + @Override + protected void openComponent(CompiledObject object, Element tag, JAXXCompiler compiler) throws CompilerException { + if (compiler.getOpenComponent() != null) { + compiler.openInvisibleComponent(object); + } else { + super.openComponent(object, tag, compiler); + } + } + + @Override + public void compileSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + super.compileSecondPass(tag, compiler); + CompiledObject object = objectMap.get(tag); + Map properties = object.getProperties(); + if (!properties.containsKey("width") && !properties.containsKey("height")) { + compiler.appendLateInitializer(object.getId() + ".pack();\n"); + } + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/LocaleEditorHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/LocaleEditorHandler.java new file mode 100644 index 0000000..256db56 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/LocaleEditorHandler.java @@ -0,0 +1,56 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.CompilerException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.tags.DefaultComponentHandler; + +import java.awt.event.ItemListener; +import jaxx.runtime.swing.editor.LocaleEditor; + +public class LocaleEditorHandler extends DefaultComponentHandler { + + public LocaleEditorHandler(ClassDescriptor beanClass) { + super(beanClass); + ClassDescriptorLoader.checkSupportClass(getClass(), beanClass, LocaleEditor.class); + } + + @Override + protected void configureProxyEventInfo() { + super.configureProxyEventInfo(); + addProxyEventInfo("getSelectedIndex", ItemListener.class); + addProxyEventInfo("getSelectedItem", ItemListener.class); + } + + @Override + protected CompiledObject createCompiledObject(String id, JAXXCompiler compiler) throws CompilerException { + return new CompiledItemContainer(id, getBeanClass(), compiler); + } +// @Override +// public void compileChildrenSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { +// super.compileChildrenSecondPass(tag, compiler); +// CompiledItemContainer list = (CompiledItemContainer) compiler.getOpenComponent(); +// List<Item> items = list.getItems(); +// if (items != null && !items.isEmpty()) { +// String listName = list.getId() + "$items"; +// list.appendAdditionCode("java.util.List<jaxx.runtime.swing.Item> " + listName + " = new java.util.ArrayList<jaxx.runtime.swing.Item>();"); +// for (Item item : items) { +// String id = item.getId(); +// CompiledObject compiledItem = new CompiledObject(id, ClassDescriptorLoader.getClassDescriptor(Item.class), compiler); +// compiledItem.setConstructorParams(TypeManager.getJavaCode(id) + ", " + TypeManager.getJavaCode(item.getLabel()) + ", " + TypeManager.getJavaCode(item.getValue()) + ", " + item.isSelected()); +// compiler.registerCompiledObject(compiledItem); +// list.appendAdditionCode(listName + ".add(" + id + ");"); +// } +// list.appendAdditionCode(list.getId() + ".setItems(" + listName + ");"); +// } +// } +} + + + diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/RowHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/RowHandler.java new file mode 100644 index 0000000..61e1db8 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/RowHandler.java @@ -0,0 +1,85 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.CompilerException; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.runtime.swing.Table; +import jaxx.tags.TagHandler; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; + +import java.awt.GridBagConstraints; +import java.io.IOException; + +public class RowHandler implements TagHandler { + public void compileFirstPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + compileChildrenFirstPass(tag, compiler); + } + + public void compileSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + if (!ClassDescriptorLoader.getClassDescriptor(Table.class).isAssignableFrom(compiler.getOpenComponent().getObjectClass())) { + compiler.reportError("row tag may only appear within Table tag"); + return; + } + + TableHandler.CompiledTable table = (TableHandler.CompiledTable) compiler.getOpenComponent(); + table.newRow(); + GridBagConstraints c = table.getRowConstraints(); + CellHandler.setAttributes(c, tag); + compileChildrenSecondPass(tag, compiler); + } + + public void compileChildrenFirstPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + NodeList children = tag.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node node = children.item(i); + int nodeType = node.getNodeType(); + if (nodeType == Node.ELEMENT_NODE) { + Element child = (Element) node; + if (!child.getLocalName().equals("cell")) { + compiler.reportError("tag '" + tag.getLocalName() + "' may only contain cell tags as children"); + } + compileChildTagFirstPass(child, compiler); + } else if (nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE) { + String text = ((Text) node).getData().trim(); + if (text.length() > 0) { + compiler.reportError("tag '" + tag.getLocalName() + "' may not contain text ('" + ((Text) node).getData().trim() + "')"); + } + } + } + } + + public void compileChildrenSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + NodeList children = tag.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node node = children.item(i); + int nodeType = node.getNodeType(); + if (nodeType == Node.ELEMENT_NODE) { + Element child = (Element) node; + if (!child.getLocalName().equals("cell")) { + compiler.reportError("tag '" + tag.getLocalName() + "' may only contain cell tags as children"); + } + compileChildTagSecondPass(child, compiler); + } else if (nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE) { + String text = ((Text) node).getData().trim(); + if (text.length() > 0) { + compiler.reportError("tag '" + tag.getLocalName() + "' may not contain text ('" + ((Text) node).getData().trim() + "')"); + } + } + } + } + + protected void compileChildTagFirstPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + compiler.compileFirstPass(tag); + } + + protected void compileChildTagSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + compiler.compileSecondPass(tag); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/TabHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/TabHandler.java new file mode 100644 index 0000000..913c9cc --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/TabHandler.java @@ -0,0 +1,175 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.CompilerException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.I18nHelper; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.runtime.swing.TabInfo; +import jaxx.tags.TagHandler; +import jaxx.types.TypeManager; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; + +import javax.swing.Icon; +import javax.swing.JTabbedPane; +import java.awt.Color; +import java.io.IOException; + +public class TabHandler implements TagHandler { + + public void compileFirstPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + compileChildrenFirstPass(tag, compiler); + } + + + public void compileSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + if (!ClassDescriptorLoader.getClassDescriptor(JTabbedPane.class).isAssignableFrom(compiler.getOpenComponent().getObjectClass())) { + compiler.reportError("tab tag may only appear within JTabbedPane tag"); + return; + } + + JTabbedPaneHandler.CompiledTabbedPane tabs = (JTabbedPaneHandler.CompiledTabbedPane) compiler.getOpenComponent(); + + String id = tag.getAttribute("id"); + if (id == null || id.length() == 0) { + id = compiler.getAutoId(ClassDescriptorLoader.getClassDescriptor(TabInfo.class)); + } + TabInfo tabInfo = new TabInfo(id); + CompiledObject compiledTabInfo = new CompiledObject(id, ClassDescriptorLoader.getClassDescriptor(TabInfo.class), compiler); + compiler.registerCompiledObject(compiledTabInfo); + //id = tabInfo.getId(); + tabs.tabInfo = tabInfo; + setAttributes(compiledTabInfo, tabs, tag, compiler); + compileChildrenSecondPass(tag, compiler); + tabs.tabInfo = null; + } + + + public static void setAttribute(CompiledObject compiledTabInfo, JTabbedPaneHandler.CompiledTabbedPane tabs, String name, String value, JAXXCompiler compiler) throws CompilerException { + value = value.trim(); + TabInfo tabInfo = tabs.tabInfo; + String id = tabInfo.getId(); + String binding = compiler.processDataBindings(value, ClassDescriptorLoader.getClassDescriptor(Object.class)); + if (binding != null) { + compiler.registerDataBinding(binding, id + "." + name, id + ".set" + org.apache.commons.lang.StringUtils.capitalize(name) + "(" + binding + ");"); + return; + } + + String valueCode = TypeManager.getJavaCode(value); + + // add i18n support + if (I18nHelper.isI18nableAttribute(name, compiler)) { + value = valueCode = I18nHelper.addI18nInvocation(id, name, valueCode, compiler); + } + + if (name.equals("title")) { + tabInfo.setTitle(value); + compiledTabInfo.appendInitializationCode(id + ".setTitle(" + valueCode + ");"); + //compiledTabInfo.appendInitializationCode(id + ".setTitle(" + TypeManager.getJavaCode(value) + ");"); + } else if (name.equals("toolTipText")) { + tabInfo.setToolTipText(value); + compiledTabInfo.appendInitializationCode(id + ".setToolTipText(" + valueCode + ");"); + //compiledTabInfo.appendInitializationCode(id + ".setToolTipText(" + TypeManager.getJavaCode(value) + ");"); + } else if (name.equals("icon")) { + Icon icon = (Icon) TypeManager.convertFromString(value, Icon.class); + tabInfo.setIcon(icon); + compiledTabInfo.appendInitializationCode(id + ".setIcon(" + TypeManager.getJavaCode(icon) + ");"); + } else if (name.equals("enabled")) { + boolean enabled = (Boolean) TypeManager.convertFromString(value, Boolean.class); + tabInfo.setEnabled(enabled); + compiledTabInfo.appendInitializationCode(id + ".setEnabled(" + enabled + ");"); + } else if (name.equals("disabledIcon")) { + Icon disabledIcon = (Icon) TypeManager.convertFromString(value, Icon.class); + tabInfo.setDisabledIcon(disabledIcon); + compiledTabInfo.appendInitializationCode(id + ".setDisabledIcon(" + TypeManager.getJavaCode(disabledIcon) + ");"); + } else if (name.equals("mnemonic")) { + int mnemonic = (Character) TypeManager.convertFromString(value, char.class); + tabInfo.setMnemonic(mnemonic); + compiledTabInfo.appendInitializationCode(id + ".setMnemonic(" + mnemonic + ");"); + } else if (name.equals("displayedMnemonicIndex")) { + int displayedMnemonicIndex = (Integer) TypeManager.convertFromString(value, int.class); + tabInfo.setDisplayedMnemonicIndex(displayedMnemonicIndex); + compiledTabInfo.appendInitializationCode(id + ".setDisplayedMnemonicIndex(" + displayedMnemonicIndex + ");"); + } else if (name.equals("foreground")) { + Color foreground = (Color) TypeManager.convertFromString(value, Color.class); + tabInfo.setForeground(foreground); + compiledTabInfo.appendInitializationCode(id + ".setForeground(" + TypeManager.getJavaCode(foreground) + ");"); + } else if (name.equals("background")) { + Color background = (Color) TypeManager.convertFromString(value, Color.class); + tabInfo.setBackground(background); + compiledTabInfo.appendInitializationCode(id + ".setBackground(" + TypeManager.getJavaCode(background) + ");"); + } else if (name.equals("id")) { + // ignore, already handled + } else { + compiler.reportError("The <tab> tag does not support the attribute '" + name + "'"); + } + } + + + public void setAttributes(CompiledObject compiledTabInfo, JTabbedPaneHandler.CompiledTabbedPane tabs, Element tag, JAXXCompiler compiler) throws CompilerException { + NamedNodeMap children = tag.getAttributes(); + for (int i = 0; i < children.getLength(); i++) { + Attr attribute = (Attr) children.item(i); + String name = attribute.getName(); + String value = attribute.getValue(); + if (!name.startsWith("xmlns") && !JAXXCompiler.JAXX_INTERNAL_NAMESPACE.equals(attribute.getNamespaceURI())) { + setAttribute(compiledTabInfo, tabs, name, value, compiler); + } + } + } + + + protected void compileChildrenFirstPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + NodeList children = tag.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node node = children.item(i); + int nodeType = node.getNodeType(); + if (nodeType == Node.ELEMENT_NODE) { + Element child = (Element) node; + compileChildTagFirstPass(child, compiler); + } else if (nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE) { + String text = ((Text) node).getData().trim(); + if (text.length() > 0) { + compiler.reportError("tag '" + tag.getLocalName() + "' may not contain text ('" + ((Text) node).getData().trim() + "')"); + } + } + } + } + + + protected void compileChildTagFirstPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + compiler.compileFirstPass(tag); + } + + + protected void compileChildrenSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + NodeList children = tag.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node node = children.item(i); + int nodeType = node.getNodeType(); + if (nodeType == Node.ELEMENT_NODE) { + Element child = (Element) node; + compileChildTagSecondPass(child, compiler); + } else if (nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE) { + String text = ((Text) node).getData().trim(); + if (text.length() > 0) { + compiler.reportError("tag '" + tag.getLocalName() + "' may not contain text ('" + ((Text) node).getData().trim() + "')"); + } + } + } + } + + + protected void compileChildTagSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + compiler.compileSecondPass(tag); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/TableHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/TableHandler.java new file mode 100644 index 0000000..d97c12a --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/swing/TableHandler.java @@ -0,0 +1,124 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.swing; + +import jaxx.CompilerException; +import jaxx.UnsupportedAttributeException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.runtime.swing.Table; +import jaxx.tags.DefaultComponentHandler; +import jaxx.types.TypeManager; + +import java.awt.GridBagConstraints; +import java.awt.Insets; +import java.util.ArrayList; +import java.util.List; + +public class TableHandler extends DefaultComponentHandler { + public static final Insets DEFAULT_INSETS = new Insets(3, 3, 3, 3); + + public TableHandler(ClassDescriptor beanClass) { + super(beanClass); + ClassDescriptorLoader.checkSupportClass(getClass(), beanClass, Table.class); + } + + @Override + public void setAttribute(CompiledObject object, String propertyName, String stringValue, boolean inline, JAXXCompiler compiler) throws CompilerException { + try { + if (object instanceof CompiledTable) { + CellHandler.setAttribute(((CompiledTable) object).getTableConstraints(), propertyName, stringValue); + } else { + super.setAttribute(object, propertyName, stringValue, inline, compiler); + } + } + catch (UnsupportedAttributeException e) { + super.setAttribute(object, propertyName, stringValue, inline, compiler); + } + } + + class CompiledTable extends CompiledObject { + private List<Integer> rowSpans = new ArrayList<Integer>(); + + private GridBagConstraints tableConstraints; + private GridBagConstraints rowConstraints = null; + private GridBagConstraints cellConstraints = null; + private boolean emptyCell; + + public CompiledTable(String id, ClassDescriptor objectClass, JAXXCompiler compiler) throws CompilerException { + super(id, objectClass, compiler); + tableConstraints = new GridBagConstraints(); + tableConstraints.gridx = -1; + tableConstraints.gridy = -1; + tableConstraints.insets = DEFAULT_INSETS; + } + + @Override + public void addChild(CompiledObject child, String constraints, JAXXCompiler compiler) throws CompilerException { + if (constraints != null) { + compiler.reportError("Table does not accept constraints"); + } + GridBagConstraints c = getCellConstraints(); + if (c == null) { + compiler.reportError("Table tag may only contain row tags"); + return; + } + if (!emptyCell) { + compiler.reportError("Table cells may only have one child component"); + } + while (rowSpans.size() < c.gridx + c.gridwidth) { + rowSpans.add(null); + } + for (int x = c.gridx; x < c.gridx + c.gridwidth; x++) { + rowSpans.set(x, c.gridheight); + } + + super.addChild(child, TypeManager.getJavaCode(c), compiler); + + emptyCell = false; + } + + public GridBagConstraints getTableConstraints() { + return tableConstraints; + } + + public GridBagConstraints getRowConstraints() { + return rowConstraints; + } + + public GridBagConstraints getCellConstraints() { + return cellConstraints; + } + + public void newRow() { + tableConstraints.gridy++; + tableConstraints.gridx = -1; + rowConstraints = (GridBagConstraints) tableConstraints.clone(); + + for (int x = 0; x < rowSpans.size(); x++) { + int rowSpan = rowSpans.get(x); + if (rowSpan > 0) { + rowSpans.set(x, rowSpan - 1); + } + } + } + + public void newCell() { + emptyCell = true; + rowConstraints.gridx++; + while (rowConstraints.gridx < rowSpans.size() && rowSpans.get(rowConstraints.gridx) > 0) { + rowConstraints.gridx++; + } + cellConstraints = (GridBagConstraints) rowConstraints.clone(); + } + } + + @Override + public CompiledObject createCompiledObject(String id, JAXXCompiler compiler) throws CompilerException { + return new CompiledTable(id, getBeanClass(), compiler); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/validator/BeanValidatorHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/validator/BeanValidatorHandler.java new file mode 100644 index 0000000..c59423e --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/validator/BeanValidatorHandler.java @@ -0,0 +1,734 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.validator; + +import jaxx.CompilerException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.introspection.JAXXBeanInfo; +import jaxx.introspection.JAXXPropertyDescriptor; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.runtime.SwingValidatorUtil; +import jaxx.runtime.validator.swing.SwingValidator; +import jaxx.runtime.validator.swing.ui.AbstractBeanValidatorUI; +import jaxx.tags.DefaultObjectHandler; +import jaxx.types.TypeManager; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.w3c.dom.Element; + +import java.beans.IntrospectionException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeMap; + +public class BeanValidatorHandler extends DefaultObjectHandler { + + public static final String TAG = "BeanValidator"; + public static final String BEAN_ATTRIBUTE = "bean"; + public static final String BEAN_CLASS_ATTRIBUTE = "beanClass"; + public static final String BEAN_INITIALIZER_ATTRIBUTE = "beanInitializer"; + public static final String ERROR_LIST_MODEL_ATTRIBUTE = "errorListModel"; + public static final String ERROR_TABLE_MODEL_ATTRIBUTE = "errorTableModel"; + public static final String ERROR_LIST_ATTRIBUTE = "errorList"; + public static final String ERROR_TABLE_ATTRIBUTE = "errorTable"; + public static final String ERROR_LIST_MODEL_DEFAULT = "errors"; + public static final String ERROR_TABLE_MODEL_DEFAULT = "errors2"; + public static final String ERROR_LIST_DEFAULT = "errorList"; + public static final String ERROR_TABLE_DEFAULT = "errorTable"; + public static final String AUTOFIELD_ATTRIBUTE = "autoField"; + public static final String UI_CLASS_ATTRIBUTE = "uiClass"; + public static final String STRICT_MODE_ATTRIBUTE = "strictMode"; + public static final String CONTEXT_NAME_ATTRIBUTE = "contextName"; + //public static final String SCOPE_ATTRIBUTE = "scope"; + public static final String PARENT_VALIDATOR_ATTRIBUTE = "parentValidator"; + /** to use log facility, just put in your code: log.info(\"...\"); */ + static Log log = LogFactory.getLog(BeanValidatorHandler.class); + protected static Map<JAXXCompiler, List<CompiledBeanValidator>> validators = new HashMap<JAXXCompiler, List<CompiledBeanValidator>>(); + protected static Map<JAXXCompiler, List<String>> validatedComponents = new HashMap<JAXXCompiler, List<String>>(); + + public BeanValidatorHandler(ClassDescriptor beanClass) { + super(beanClass); + ClassDescriptorLoader.checkSupportClass(getClass(), beanClass, SwingValidator.class); + } + + @Override + protected CompiledObject createCompiledObject(String id, JAXXCompiler compiler) { + return new CompiledBeanValidator(id, getBeanClass(), compiler); + } + + @Override + protected void compileChildTagFirstPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + if (compiler.getOptions().isVerbose()) { + log.info(tag); + } + if (!tag.getLocalName().equals(FieldValidatorHandler.TAG)) { + compiler.reportError("tag '" + tag.getParentNode().getLocalName() + "' may only contain " + FieldValidatorHandler.TAG + " as children, but found : " + tag.getLocalName()); + } else { + compiler.compileFirstPass(tag); + } + } + + @Override + public void compileSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + + super.compileSecondPass(tag, compiler); + + CompiledBeanValidator info = (CompiledBeanValidator) objectMap.get(tag); + + boolean error = info.addErrorListModel(tag, this, compiler); + + if (!error) { + error = info.addErrorList(tag, compiler); + } + + if (!error) { + error = info.addErrorTableModel(tag, this, compiler); + } + + if (!error) { + error = info.addErrorTable(tag, compiler); + } + + if (!error) { + error = info.addUiClass(this, compiler); + } + + if (!error) { + error = info.addBean(tag, this, compiler); + } + + /*if (!error) { + error = info.addContextName(this, compiler); + }*/ + + /*if (!error) { + error = info.addScope(this, compiler); + }*/ + + if (!error) { + error = info.addParentValidator(tag, this, compiler); + } + + if (error) { + log.warn("error were detected in second compile pass of CompiledObject [" + info + "]"); + } + + // close the compiled object + compiler.closeComponent(info); + } + + @Override + protected void setDefaults(CompiledObject object, Element tag, JAXXCompiler compiler) { + // open the compiled object + compiler.openInvisibleComponent(object); + } + + @Override + public void setAttribute(CompiledObject object, String propertyName, String stringValue, boolean inline, JAXXCompiler compiler) { + if (compiler.getOptions().isVerbose()) { + log.info(propertyName + " : " + stringValue + " for " + object); + } + // delegate to the compiled object with is statefull (but not the tag handler) + object.addProperty(propertyName, stringValue); + } + + /** + * The compiled objet representing a BeanValidator to be generated in JAXXObject + * + * @author chemit + */ + public static class CompiledBeanValidator extends CompiledObject { + + protected Map<String, String> fields; + protected Map<String, String> excludeFields; + protected String bean; + protected String beanClass; + protected String contextName; + protected String uiClass; + protected String errorListModel; + protected String errorList; + protected Boolean autoField; + protected Boolean strictMode; + protected JAXXBeanInfo beanDescriptor; + protected String errorTableModel; + protected String errorTable; + protected String parentValidator; + + public CompiledBeanValidator(String id, ClassDescriptor objectClass, JAXXCompiler compiler) { + //TC-20090524 Use the real class descriptor, not the one by default, + //TC-20090524 otherwise can not override the validator class while generation + //super(id, objectClass, compiler); + super(id, getDescriptor(objectClass, compiler), compiler); + fields = new TreeMap<String, String>(); + excludeFields = new TreeMap<String, String>(); + if (compiler.getOptions().isVerbose()) { + log.info("validator objectClass " + super.getObjectClass()); + } + } + + protected static ClassDescriptor getDescriptor(ClassDescriptor objectClass, JAXXCompiler compiler) { + ClassDescriptor result = objectClass; + Class<?> validatorClass = compiler.getOptions().getValidatorClass(); + result = ClassDescriptorLoader.getClassDescriptor(validatorClass); + return result; + } + + public Map<String, String> getFields() { + return fields; + } + + public Map<String, String> getExcludeFields() { + return excludeFields; + } + + public void setFields(Map<String, String> fields) { + this.fields = fields; + } + + public void setExcludeFields(Map<String, String> excludeFields) { + this.excludeFields = excludeFields; + } + + @Override + public void addProperty(String property, String value) { + + if (BEAN_ATTRIBUTE.equals(property)) { + if (value != null && !value.trim().isEmpty()) { + bean = value.trim(); + } + return; + } + + if (CONTEXT_NAME_ATTRIBUTE.equals(property)) { + if (value != null && !value.trim().isEmpty()) { + contextName = value.trim(); + } + return; + } + + if (BEAN_CLASS_ATTRIBUTE.equals(property)) { + if (value != null && !value.trim().isEmpty()) { + beanClass = value.trim(); + } + return; + } + + if (ERROR_LIST_MODEL_ATTRIBUTE.equals(property)) { + if (value != null && !value.trim().isEmpty()) { + errorListModel = value.trim(); + } + return; + } + + if (ERROR_LIST_ATTRIBUTE.equals(property)) { + if (value != null && !value.trim().isEmpty()) { + errorList = value.trim(); + } + return; + } + + if (ERROR_TABLE_MODEL_ATTRIBUTE.equals(property)) { + if (value != null && !value.trim().isEmpty()) { + errorTableModel = value.trim(); + } + return; + } + + if (ERROR_TABLE_ATTRIBUTE.equals(property)) { + if (value != null && !value.trim().isEmpty()) { + errorTable = value.trim(); + } + return; + } + + if (UI_CLASS_ATTRIBUTE.equals(property)) { + if (value != null && !value.trim().isEmpty()) { + uiClass = value.trim(); + } + return; + } + + if (AUTOFIELD_ATTRIBUTE.equals(property)) { + if (value != null && !value.trim().isEmpty()) { + autoField = (Boolean) TypeManager.convertFromString(value.trim(), Boolean.class); + } + return; + } + + if (STRICT_MODE_ATTRIBUTE.equals(property)) { + if (value != null && !value.trim().isEmpty()) { + strictMode = (Boolean) TypeManager.convertFromString(value.trim(), Boolean.class); + } + return; + } + + if (PARENT_VALIDATOR_ATTRIBUTE.equals(property)) { + if (value != null && !value.trim().isEmpty()) { + parentValidator = value.trim(); + } + return; + } + + throw new CompilerException("property " + property + " is not allowed on object " + this); + } + + public String getBean() { + return bean; + } + + public String getErrorListModel() { + return errorListModel; + } + + public boolean getAutoField() { + return autoField != null && autoField; + } + + public boolean getStrictMode() { + return strictMode != null && strictMode; + } + + public String getUiClass() { + return uiClass; + } + + public String getBeanClass() { + return beanClass; + } + + public String getContextName() { + return contextName; + } + + public String getParentValidator() { + return parentValidator; + } + + public JAXXBeanInfo getBeanDescriptor(JAXXCompiler compiler) { + if (beanDescriptor == null && foundBean()) { + + String beanClassName = null; + try { + //TC-20090111 beanClass is mandatory + // get the real bean class name (from bean or beanClass) + /*if (beanClass != null) { + beanClassName = beanClass; + } else { + beanClassName = compiler.getSymbolTable().getClassTagIds().get(bean); + if (beanClassName == null) { + compiler.reportError("could not find class of the bean '" + bean + "'"); + return null; + } + }*/ + ClassDescriptor beanClassDescriptor = ClassDescriptorLoader.getClassDescriptor(beanClass); + beanDescriptor = DefaultObjectHandler.getJAXXBeanInfo(beanClassDescriptor); + } catch (ClassNotFoundException e) { + compiler.reportError("could not load class " + beanClassName); + } catch (IntrospectionException e) { + compiler.reportError("could not load class " + beanClassName); + } + } + return beanDescriptor; + } + + @Override + public void addChild(CompiledObject child, String constraints, JAXXCompiler compiler) throws CompilerException { + // do nothing + compiler.reportError("can not add CompiledObject in the tag '" + TAG + " (only field tags)"); + } + + public boolean foundBean() { + return !(beanClass == null || beanClass.isEmpty()); + } + + protected boolean addUiClass(BeanValidatorHandler handler, JAXXCompiler compiler) { + boolean withError = false; + if (uiClass == null && compiler.getOptions().getDefaultErrorUI() != null) { + uiClass = compiler.getOptions().getDefaultErrorUI().getName(); + } + if (uiClass != null) { + try { + ClassDescriptor uiClazz = ClassDescriptorLoader.getClassDescriptor(uiClass); + if (!ClassDescriptorLoader.getClassDescriptor(AbstractBeanValidatorUI.class).isAssignableFrom(uiClazz)) { + compiler.reportError("attribute 'ui' :'" + uiClass + "' is not assignable from class " + AbstractBeanValidatorUI.class); + withError = true; + } else { + String code = handler.getSetPropertyCode(getJavaCode(), UI_CLASS_ATTRIBUTE, uiClazz.getName() + ".class", compiler); + appendAdditionCode(code); + } + } catch (ClassNotFoundException e) { + compiler.reportError("class not found '" + uiClass + "'"); + withError = true; + } + } + + return withError; + } + + protected boolean addErrorListModel(Element tag, BeanValidatorHandler handler, JAXXCompiler compiler) { + if (errorListModel == null) { + // try with the default "errors" + if (!compiler.checkReference(tag, ERROR_LIST_MODEL_DEFAULT, false, ERROR_LIST_MODEL_ATTRIBUTE)) { + return false; + } + errorListModel = ERROR_LIST_MODEL_DEFAULT; + } else { + if (errorListModel.startsWith("{") && errorListModel.endsWith("}")) { + // this is a script, no check here + errorListModel = errorListModel.substring(1, errorListModel.length() - 1).trim(); + } else if (!compiler.checkReference(tag, errorListModel, true, ERROR_LIST_MODEL_ATTRIBUTE)) { + // errorListModel is not defined + return true; + } + } + + String code = handler.getSetPropertyCode(getJavaCode(), ERROR_LIST_MODEL_ATTRIBUTE, errorListModel, compiler); + appendAdditionCode(code); + + return false; + + } + + protected boolean addErrorTableModel(Element tag, BeanValidatorHandler handler, JAXXCompiler compiler) { + if (errorTableModel == null) { + // try with the default "errors" + if (!compiler.checkReference(tag, ERROR_TABLE_MODEL_DEFAULT, false, ERROR_LIST_MODEL_ATTRIBUTE)) { + return false; + } + errorTableModel = ERROR_TABLE_MODEL_DEFAULT; + } else { + if (errorTableModel.startsWith("{") && errorTableModel.endsWith("}")) { + // this is a script, no check here + errorTableModel = errorTableModel.substring(1, errorTableModel.length() - 1).trim(); + } else if (!compiler.checkReference(tag, errorTableModel, true, ERROR_TABLE_MODEL_ATTRIBUTE)) { + // errorListModel is not defined + return true; + } + } + + String code = handler.getSetPropertyCode(getJavaCode(), ERROR_TABLE_MODEL_ATTRIBUTE, errorTableModel, compiler); + appendAdditionCode(code); + + return false; + + } + + /*protected boolean addContextName(BeanValidatorHandler handler, JAXXCompiler compiler) { + if (contextName != null) { + String code = handler.getSetPropertyCode(getJavaCode(), CONTEXT_NAME_ATTRIBUTE, TypeManager.getJavaCode(contextName), compiler); + appendAdditionCode(code); + } + return false; + }*/ + + /*protected boolean addScope(BeanValidatorHandler handler, JAXXCompiler compiler) { + if (scope != null) { + String code = handler.getSetPropertyCode(getJavaCode(), SCOPE_ATTRIBUTE, TypeManager.getJavaCode(scope), compiler); + appendAdditionCode(code); + } + return false; + }*/ + protected boolean addParentValidator(Element tag, BeanValidatorHandler handler, JAXXCompiler compiler) { + if (parentValidator != null) { + String initializer; + if (parentValidator.startsWith("{") && parentValidator.endsWith("}")) { + + // todo : should be able to bind + initializer = parentValidator.substring(1, parentValidator.length() - 1); + + } else { + // the attribute referes an existing widget + if (!compiler.checkReference(tag, parentValidator, true, PARENT_VALIDATOR_ATTRIBUTE)) { + // parentValidator is not defined + return true; + } + initializer = parentValidator; + } + String code = handler.getSetPropertyCode(getJavaCode(), PARENT_VALIDATOR_ATTRIBUTE, initializer, compiler); + appendAdditionCode(code); + } + return false; + } + + protected boolean addErrorList(Element tag, JAXXCompiler compiler) { + + if (errorList == null) { + // try with the default "errorList" + if (!compiler.checkReference(tag, ERROR_LIST_DEFAULT, false, ERROR_LIST_ATTRIBUTE)) { + return false; + } + errorList = ERROR_LIST_DEFAULT; + } else { + if (!compiler.checkReference(tag, errorList, true, ERROR_LIST_ATTRIBUTE)) { + return true; + } + } + + String code = SwingValidatorUtil.class.getName() + ".registerErrorListMouseListener(" + errorList + ");"; + appendAdditionCode(code); + + return false; + } + + protected boolean addErrorTable(Element tag, JAXXCompiler compiler) { + + if (errorTable == null) { + // try with the default "errorList" + if (!compiler.checkReference(tag, ERROR_TABLE_DEFAULT, false, ERROR_TABLE_ATTRIBUTE)) { + return false; + } + errorTable = ERROR_TABLE_DEFAULT; + } else { + if (!compiler.checkReference(tag, errorTable, true, ERROR_TABLE_ATTRIBUTE)) { + return true; + } + } + + String code = SwingValidatorUtil.class.getName() + ".registerErrorTableMouseListener(" + errorTable + ");"; + appendAdditionCode(code); + + return false; + } + + protected boolean addBean(Element tag, BeanValidatorHandler handler, JAXXCompiler compiler) { + + if (beanClass == null || beanClass.isEmpty()) { + // try to guest beanClass from bean attribute + if (bean != null && !bean.isEmpty()) { + beanClass = compiler.getSymbolTable().getClassTagIds().get(bean); + if (beanClass == null) { + compiler.reportError("could not find class of the bean '" + bean + "', and no beanClass was setted"); + return true; + } + } + } + if (beanClass == null) { + compiler.reportError("tag '" + tag + "' requires a 'beanClass' attribute, and could not guest it from 'bean' attribute (no bean attribute setted...)"); + return true; + } + + JAXXBeanInfo beanInfo = getBeanDescriptor(compiler); + if (beanInfo == null) { + compiler.reportError(tag, "could not find descriptor of class " + beanClass); + return true; + } + + String beanInitializer = null; + if (bean != null) { + + if (bean.startsWith("{") && bean.endsWith("}")) { + + // just has an intializer + beanInitializer = bean.substring(1, bean.length() - 1); + // this is not a real bean, so delete it + bean = null; + } else { + + if (!compiler.checkReference(tag, bean, true, BEAN_ATTRIBUTE)) { + // could not find bean in compiled object + return true; + } + + if (isBeanUsedByValidator(compiler, bean)) { + compiler.reportError("the bean '" + bean + "' is already used in another the validator, can not used it in '" + tag + "'"); + return true; + } + + /*if (beanInitializer != null) { + compiler.reportWarning("tag '" + tag + "' found a 'bean' and a 'beanInitializer' attributes, 'beanInitializer' is skipped"); + }*/ + beanInitializer = bean; + } + } + + if (beanInitializer != null) { + String code = handler.getSetPropertyCode(getJavaCode(), BEAN_ATTRIBUTE, compiler.checkJavaCode(beanInitializer), compiler); + appendAdditionCode(code); + } + + String beanClassName = beanInfo.getJAXXBeanDescriptor().getClassDescriptor().getName(); + // contextName must be in constructor to able to init validator with his correct contextName + setConstructorParams(beanClassName + ".class, " + TypeManager.getJavaCode(contextName)); + // add generic type to validator + setGenericTypes(new String[]{beanClassName}); + + if (getAutoField()) { + registerAutoFieldBean(tag, compiler, beanInfo); + } + + if (getBeanDescriptor(compiler) != null) { + + // add fieldrepresentation invocations + addFieldRepresentations(tag, compiler); + + // register the validator in compiler + registerValidator(compiler, this); + + } + + return false; + } + + private void registerValidator(JAXXCompiler compiler, CompiledBeanValidator compiledBeanValidator) { + List<CompiledBeanValidator> vals = validators.get(compiler); + if (vals == null) { + vals = new ArrayList<CompiledBeanValidator>(); + validators.put(compiler, vals); + } + vals.add(compiledBeanValidator); + List<String> ids = validatedComponents.get(compiler); + if (ids == null) { + ids = new ArrayList<String>(); + validatedComponents.put(compiler, ids); + } + ids.addAll(compiledBeanValidator.getFields().values()); + } + + protected void addFieldRepresentations(Element tag, JAXXCompiler compiler) { + for (Entry<String, String> entry : fields.entrySet()) { + String propertyName = entry.getKey(); + String component = entry.getValue(); + if (!checkBeanProperty(compiler, propertyName)) { + // property not find on bean + continue; + } + if (!compiler.checkReference(tag, component, true, null)) { + // editor component not find on ui + continue; + } + /*if (compiler.isComponentUsedByValidator(component)) { + // component is already used by another validator + compiler.reportError("component '" + component + "' is already used by another validator."); + continue; + }*/ + String keyCode = TypeManager.getJavaCode(propertyName); + appendAdditionCode(getJavaCode() + ".setFieldRepresentation(" + keyCode + ", " + component + ");"); + } + } + + protected void registerAutoFieldBean(Element tag, JAXXCompiler compiler, JAXXBeanInfo beanInfo) { + for (JAXXPropertyDescriptor beanProperty : beanInfo.getJAXXPropertyDescriptors()) { + String descriptionName = beanProperty.getName(); + if (compiler.getOptions().isVerbose()) { + log.info("try to bind on bean " + beanInfo.getJAXXBeanDescriptor().getName() + " property " + descriptionName); + } + if (beanProperty.getWriteMethodDescriptor() == null) { + // read-only property + continue; + } + if (fields.containsKey(descriptionName)) { + // already defined in field + continue; + } + if (excludeFields.containsKey(descriptionName)) { + // exclude field + continue; + } + if (!compiler.checkReference(tag, descriptionName, getStrictMode(), null)) { + // no editor component found + continue; + } + // ok add the field mapping + registerField(descriptionName, descriptionName, compiler); + } + + for (Entry<String, String> entry : excludeFields.entrySet()) { + String key = entry.getKey(); + if (fields.containsKey(key)) { + compiler.reportWarning("field '" + key + "' can not be used and excluded at same time ! (field is skipped) for validator " + this); + fields.remove(key); + } + } + } + + public void registerField(String id, String component, JAXXCompiler compiler) { + if (fields.containsKey(id)) { + compiler.reportError("duplicate field '" + id + "' for validator " + this); + } else { + if (compiler.getOptions().isVerbose()) { + log.info("add field <" + id + ":" + component + ">"); + } + fields.put(id, component); + } + } + + public void registerExcludeField(String id, String component, JAXXCompiler compiler) { + if (excludeFields.containsKey(id)) { + compiler.reportError("duplicate field '" + id + "' for validator " + this); + } else { + if (compiler.getOptions().isVerbose()) { + log.info("add excludeField <" + id + ":" + component + ">"); + } + excludeFields.put(id, component); + } + } + + protected boolean checkBeanProperty(JAXXCompiler compiler, String propertyName) { + + for (JAXXPropertyDescriptor beanProperty : getBeanDescriptor(compiler).getJAXXPropertyDescriptors()) { + if (beanProperty.getName().equals(propertyName)) { + if (beanProperty.getWriteMethodDescriptor() == null) { + // read-onlyproperty + compiler.reportError("could not bind the readonly property '" + propertyName + "' on bean [" + getBean() + "] "); + return false; + } + return true; + } + } + compiler.reportError("could not find the property '" + propertyName + "' on bean [" + getBean() + "] "); + return false; + } + } + + /** + * Test if a given bean is attached to a validator. + * + * @param compiler current compiler to use + * @param beanId the bean to test + * @return <code>true</code> if the given bean is attached to a validator, <code>false</code> otherwise + */ + public static boolean isBeanUsedByValidator(JAXXCompiler compiler, String beanId) { + List<CompiledBeanValidator> beanValidatorList = validators.get(compiler); + if (beanValidatorList != null) { + for (CompiledBeanValidator validator : beanValidatorList) { + if (beanId.equals(validator.getBean())) { + return true; + } + } + } + return false; + } + + /** + * @param compiler compiler to use + * @return <code>true</code> if some validators were detected, <code>false</code> otherwise + */ + public static boolean hasValidator(JAXXCompiler compiler) { + List<CompiledBeanValidator> beanValidatorList = validators.get(compiler); + return beanValidatorList != null && !beanValidatorList.isEmpty(); + } + + /** + * Test if a given CompiledObject is attached to a validator. + * + * @param compiler compiler to use + * @param componentId the compiled object to test + * @return <code>true</code> if the given compiled object is attached to a validator, <code>false</code> otherwise + */ + public static boolean isComponentUsedByValidator(JAXXCompiler compiler, String componentId) { + List<String> ids = validatedComponents.get(compiler); + return ids != null && ids.contains(componentId); + } + + public static List<CompiledBeanValidator> getValidators(JAXXCompiler compiler) { + return validators.get(compiler); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/validator/ExcludeFieldValidatorHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/validator/ExcludeFieldValidatorHandler.java new file mode 100644 index 0000000..70aaafa --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/validator/ExcludeFieldValidatorHandler.java @@ -0,0 +1,85 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.validator; + +import jaxx.CompilerException; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.runtime.validator.swing.SwingValidator; +import jaxx.tags.TagHandler; +import jaxx.tags.validator.BeanValidatorHandler.CompiledBeanValidator; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.w3c.dom.Element; + +import java.io.IOException; + +public class ExcludeFieldValidatorHandler implements TagHandler { + + public static final String TAG = "excludeField"; + public static final String NAME_ATTRIBUTE = "name"; + public static final String COMPONENT_ATTRIBUTE = "component"; + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(ExcludeFieldValidatorHandler.class); + + public void compileFirstPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + if (compiler.getOptions().isVerbose()) { + log.info(tag); + } + //todo check there is no child + } + + public void compileSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + if (compiler.getOptions().isVerbose()) { + log.debug(tag); + } + + if (!ClassDescriptorLoader.getClassDescriptor(SwingValidator.class).isAssignableFrom(compiler.getOpenComponent().getObjectClass())) { + compiler.reportError(TAG + " tag may only appear within " + BeanValidatorHandler.TAG + " tag but was " + tag); + return; + } + + CompiledBeanValidator info = (CompiledBeanValidator) compiler.getOpenComponent(); + if (!info.getAutoField()) { + compiler.reportError(TAG + " tag can not be used without an 'autoField' validator : " + tag); + return; + } + String name = tag.getAttribute(NAME_ATTRIBUTE); + String component = tag.getAttribute(COMPONENT_ATTRIBUTE); + if (name == null || name.trim().isEmpty()) { + compiler.reportError(TAG + " tag requires a " + NAME_ATTRIBUTE + " attribute"); + return; + } + name = name.trim(); + if (component == null || component.trim().isEmpty()) { + // try to use the name as component + if (!compiler.checkReference(tag, name, false, name)) { + compiler.reportError(TAG + " tag requires a " + COMPONENT_ATTRIBUTE + " attribute, try to use the name attribute [" + name + "] for the component, but no such component found"); + return; + } + component = name; + } + component = component.trim(); + + // check component is not already used by this compiled object + if (info.getFields().containsValue(component)) { + compiler.reportError(TAG + " tag found a attribute " + COMPONENT_ATTRIBUTE + " [" + component + "] already used in this validator"); + return; + } + if (info.getExcludeFields().containsValue(component)) { + compiler.reportError(TAG + " tag found a attribute " + COMPONENT_ATTRIBUTE + " [" + component + "] already used in this validator"); + return; + } + // check component exist (again perharps, but let the error knows exactly which tag failed...) + if (compiler.checkReference(tag, component, true, COMPONENT_ATTRIBUTE)) { + // add a field + info.registerField(name, component, compiler); + } + + + } + +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/validator/FieldValidatorHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/validator/FieldValidatorHandler.java new file mode 100644 index 0000000..1a3167f --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/validator/FieldValidatorHandler.java @@ -0,0 +1,78 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.validator; + +import jaxx.CompilerException; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.runtime.validator.swing.SwingValidator; +import jaxx.tags.TagHandler; +import jaxx.tags.validator.BeanValidatorHandler.CompiledBeanValidator; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.w3c.dom.Element; + +import java.io.IOException; + +public class FieldValidatorHandler implements TagHandler { + + public static final String TAG = "field"; + public static final String NAME_ATTRIBUTE = "name"; + public static final String COMPONENT_ATTRIBUTE = "component"; + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(FieldValidatorHandler.class); + + public void compileFirstPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + if (compiler.getOptions().isVerbose()) { + log.info(tag); + } + //todo check there is no child + } + + public void compileSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { + if (compiler.getOptions().isVerbose()) { + log.info(tag); + } + + if (!ClassDescriptorLoader.getClassDescriptor(SwingValidator.class).isAssignableFrom(compiler.getOpenComponent().getObjectClass())) { + compiler.reportError(TAG + " tag may only appear within " + BeanValidatorHandler.TAG + " tag but was " + tag); + return; + } + + CompiledBeanValidator info = (CompiledBeanValidator) compiler.getOpenComponent(); + + String name = tag.getAttribute(NAME_ATTRIBUTE); + String component = tag.getAttribute(COMPONENT_ATTRIBUTE); + if (name == null || name.trim().isEmpty()) { + compiler.reportError(TAG + " tag requires a " + NAME_ATTRIBUTE + " attribute"); + return; + } + name = name.trim(); + if (component == null || component.trim().isEmpty()) { + // try to use the name as component + if (!compiler.checkReference(tag, name, false, name)) { + compiler.reportError(TAG + " tag requires a " + COMPONENT_ATTRIBUTE + " attribute, try to use the name attribute [" + name + "] for the component, but no such component found"); + return; + } + component = name; + } + component = component.trim(); + + // check component is not already used by this compiled object + if (info.getFields().containsValue(component)) { + compiler.reportError(TAG + " tag found a attribute " + COMPONENT_ATTRIBUTE + " [" + component + "] already used in this validator"); + return; + } + // check component exist (again perharps, but let the error knows exactly which tag failed...) + if (compiler.checkReference(tag, component, true, COMPONENT_ATTRIBUTE)) { + // add a field + info.registerField(name, component, compiler); + } + + + } + +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tags/validator/ValidatorInitializer.java b/trunk/jaxx-compiler/src/main/java/jaxx/tags/validator/ValidatorInitializer.java new file mode 100644 index 0000000..8bb9619 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tags/validator/ValidatorInitializer.java @@ -0,0 +1,22 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.validator; + +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.runtime.validator.swing.SwingValidator; +import jaxx.tags.TagManager; + +public class ValidatorInitializer implements jaxx.spi.Initializer { + + @Override + public void initialize() { + + TagManager.registerTag(JAXXCompiler.JAXX_NAMESPACE, BeanValidatorHandler.TAG, new BeanValidatorHandler(ClassDescriptorLoader.getClassDescriptor(SwingValidator.class))); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(SwingValidator.class), BeanValidatorHandler.class); + TagManager.registerTag(JAXXCompiler.JAXX_NAMESPACE, FieldValidatorHandler.TAG, new FieldValidatorHandler()); + TagManager.registerTag(JAXXCompiler.JAXX_NAMESPACE, ExcludeFieldValidatorHandler.TAG, new FieldValidatorHandler()); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/AbstractContextNode.java b/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/AbstractContextNode.java new file mode 100644 index 0000000..67dd772 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/AbstractContextNode.java @@ -0,0 +1,17 @@ +package jaxx.tools.jaxxcapture; + +import java.util.ArrayList; +import java.util.List; + +public abstract class AbstractContextNode implements ContextNode { + private List<ContextNode> arguments = new ArrayList<ContextNode>(); + + + public void addArgument(ContextNode node) { + arguments.add(node); + } + + public ContextNode[] getArguments() { + return arguments.toArray(new ContextNode[arguments.size()]); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/CapturedObject.java b/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/CapturedObject.java new file mode 100644 index 0000000..7fcdebb --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/CapturedObject.java @@ -0,0 +1,146 @@ +package jaxx.tools.jaxxcapture; + +import jaxx.compiler.JAXXCompiler; +import jaxx.tools.jaxxcapture.handlers.ObjectHandler; + +import java.awt.Component; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +public class CapturedObject extends AbstractContextNode { + private String className; + private ObjectHandler handler; + /** Maps children to their constraints. */ + private Map<CapturedObject, ContextNode> children = new LinkedHashMap<CapturedObject, ContextNode>(); + private CapturedObject parent; + private Map<String, String> properties = new LinkedHashMap<String, String>(); + private Map<String, Object> additionalData = new HashMap<String, Object>(); + private StringBuffer innerXML = new StringBuffer(); + private StringBuffer script = new StringBuffer(); + private boolean inlineable = true; + private JAXXCapture capture; + + public CapturedObject(ObjectHandler handler, String className, JAXXCapture capture) { + this.handler = handler; + this.className = className; + this.capture = capture; + } + + + public ObjectHandler getObjectHandler() { + return handler; + } + + + public void addChild(CapturedObject child, ContextNode constraints) { + children.put(child, constraints); + child.setParent(this); + } + + + public CapturedObject[] getChildren() { + return children.keySet().toArray(new CapturedObject[children.size()]); + } + + + public CapturedObject getParent() { + return parent; + } + + + public void setParent(CapturedObject parent) { + this.parent = parent; + } + + + public ContextNode getConstraints(CapturedObject child) { + return children.get(child); + } + + + public String getClassName() { + return className; + } + + + public String getProperty(String key) { + return properties.get(key); + } + + + public void setProperty(String key, String value) { + properties.put(key, value); + } + + + public Map<String, String> getProperties() { + return properties; + } + + + public Object getAdditionalData(String key) { + return additionalData.get(key); + } + + + public void setAdditionalData(String key, Object value) { + additionalData.put(key, value); + } + + + public Map<String, Object> getAdditionalData() { + return additionalData; + } + + + public void setInlineable(boolean inlineable) { + this.inlineable = inlineable; + } + + + public boolean isInlineable() { + try { + return script.length() == 0 && !Component.class.isAssignableFrom(Class.forName(className, true, capture.getClassLoader())) && inlineable; + } + catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + + public void appendInnerXML(String xml) { + if (this.innerXML.length() > 0) { + this.innerXML.append(JAXXCompiler.getLineSeparator()); + } + this.innerXML.append(xml); + } + + + public String getInnerXML() { + return innerXML.toString(); + } + + + public void appendScriptCode(String script) { + if (this.script.length() > 0) { + this.script.append(JAXXCompiler.getLineSeparator()); + } + this.script.append(script); + } + + + public String getScriptCode() { + return script.toString(); + } + + + public String getXML(JAXXCapture capture) { + return getObjectHandler().getXML(this, capture); + } + + @Override + public String toString() { + return "CapturedObject[" + getProperty("id") + ", " + className + "]"; + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/ContextNode.java b/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/ContextNode.java new file mode 100644 index 0000000..0f38e12 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/ContextNode.java @@ -0,0 +1,7 @@ +package jaxx.tools.jaxxcapture; + +public interface ContextNode { + void addArgument(ContextNode node); + + ContextNode[] getArguments(); +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/JAXXCapture.java b/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/JAXXCapture.java new file mode 100644 index 0000000..9ef39de --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/JAXXCapture.java @@ -0,0 +1,404 @@ +package jaxx.tools.jaxxcapture; + +import jaxx.ClassMap; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.tools.jaxxcapture.handlers.JTabbedPaneHandler; +import jaxx.tools.jaxxcapture.handlers.ObjectHandler; +import jaxx.tools.jaxxcapture.handlers.TableHandler; +import jaxx.types.TypeManager; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; +import org.xml.sax.SAXException; + +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JTabbedPane; +import javax.swing.JWindow; +import javax.swing.SwingUtilities; +import java.awt.AWTEvent; +import java.awt.Component; +import java.awt.Container; +import java.awt.EventQueue; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.event.MouseEvent; +import java.beans.XMLEncoder; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Stack; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.jar.Manifest; + +public class JAXXCapture { + private static ClassMap<Object> objectHandlers = new ClassMap<Object>(); + + static { + //TODO make a serviceLoader mecanism to allow inter-module loading + objectHandlers.put(ClassDescriptorLoader.getClassDescriptor(Object.class), new ObjectHandler()); + objectHandlers.put(ClassDescriptorLoader.getClassDescriptor(JTabbedPane.class), new JTabbedPaneHandler()); + try { + objectHandlers.put(ClassDescriptorLoader.getClassDescriptor("jaxx.runtime.swing.Table"), new TableHandler()); + } catch (ClassNotFoundException e) { + System.err.println(e); + } + } + + private Map<String, Object> sourceObjects = new HashMap<String, Object>(); + private Map<String, CapturedObject> capturedObjects = new HashMap<String, CapturedObject>(); + private ClassLoader classLoader; + private int count; + + + private static class CaptureEventQueue extends EventQueue { + private ClassLoader classLoader; + + + private CaptureEventQueue(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + @Override + public void dispatchEvent(AWTEvent event) { + if (event.getID() == MouseEvent.MOUSE_PRESSED && ((MouseEvent) event).isControlDown()) { + Component target = ((MouseEvent) event).getComponent(); + if (!(target instanceof Window)) { + target = SwingUtilities.getWindowAncestor(target); + } + if (target instanceof JFrame) { + target = ((JFrame) target).getContentPane(); + } else if (target instanceof JDialog) { + target = ((JDialog) target).getContentPane(); + } + if (target instanceof JWindow) { + target = ((JWindow) target).getContentPane(); + } + if (target != null) { + Thread.currentThread().setContextClassLoader(classLoader); + JAXXCapture capture = new JAXXCapture(classLoader); + capture.applyNames(target); + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + XMLEncoder encoder = new XMLEncoder(buffer); + encoder.writeObject(target); + encoder.close(); + try { + System.err.println(new String(buffer.toByteArray())); + System.out.println(capture.convertToJAXX(new ByteArrayInputStream(buffer.toByteArray()))); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + } + super.dispatchEvent(event); + } + } + + + private JAXXCapture(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + + public ClassLoader getClassLoader() { + return classLoader; + } + + + public Map<String, CapturedObject> getCapturedObjects() { + return capturedObjects; + } + + + private void applyNames(Component target) { + String name = target.getName(); + if (name == null || sourceObjects.containsKey(name) || !CompiledObject.isValidID(name)) { + do { + name = "Object" + ++count; + } + while (sourceObjects.containsKey(name)); + } + target.setName(name); + assert !sourceObjects.containsKey(name) : "ID " + name + " is already registered"; + sourceObjects.put(name, target); + + if (target instanceof Container) { + Container container = (Container) target; + for (int i = 0; i < container.getComponentCount(); i++) { + applyNames(container.getComponent(i)); + } + } + } + + + public static String getText(Element tag) { // NOT a safe general-purpose implementation! + return ((Text) tag.getChildNodes().item(0)).getData(); + } + + + private String getArgumentsCode(ContextNode[] arguments) { + StringBuffer result = new StringBuffer(); + result.append('('); + for (int i = 0; i < arguments.length; i++) { + if (i != 0) { + result.append(", "); + } + result.append(getJavaCode(arguments[i])); + } + result.append(')'); + return result.toString(); + } + + + public String getJavaCode(ContextNode node) { + StringBuffer result = new StringBuffer(); + if (node instanceof PropertyNode) { + ContextNode[] arguments = node.getArguments(); + result.append(arguments.length == 0 ? "get" : "set"); + result.append(org.apache.commons.lang.StringUtils.capitalize(((PropertyNode) node).getProperty())); + result.append(getArgumentsCode(arguments)); + } else if (node instanceof MethodNode) { + result.append((((MethodNode) node).getMethodName())); + result.append(getArgumentsCode(node.getArguments())); + } else if (node instanceof CapturedObject) { + CapturedObject object = (CapturedObject) node; + if (object.isInlineable()) { + result.append("new "); + result.append(object.getClassName()); + result.append(getArgumentsCode(node.getArguments())); + } else { + String id = object.getProperty("id"); + assert id != null; + result.append(id); + } + } else if (node instanceof ValueNode) { + result.append(TypeManager.getJavaCode(((ValueNode) node).getValue())); + } else if (node instanceof LiteralNode) { + result.append(((LiteralNode) node).getJavaCode()); + } else { + throw new IllegalArgumentException("unrecognized node type: " + node); + } + return result.toString(); + } + + + // returns the best matching method for the specified argument types + private static Method getMethod(Class target, String methodName, Class[] arguments) { + try { + // use the package-private class java.beans.ReflectionUtils to resolve the method. This isn't 100% safe, but it's better than + // having to rewrite the resolution myself. + Class<?> reflectionUtils = Class.forName("java.beans.ReflectionUtils"); + Method getMethod = reflectionUtils.getDeclaredMethod("getMethod", new Class[]{Class.class, String.class, Class[].class}); + getMethod.setAccessible(true); + return (Method) getMethod.invoke(null, target, methodName, arguments); + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + + + // returns the best matching constructor for the specified argument types + private static Constructor getConstructor(Class target, Class[] arguments) { + try { + // use the package-private class java.beans.ReflectionUtils to resolve the constructor. This isn't 100% safe, but it's better than + // having to rewrite the resolution myself. + Class<?> reflectionUtils = Class.forName("java.beans.ReflectionUtils"); + Method getConstructor = reflectionUtils.getDeclaredMethod("getConstructor", new Class[]{Class.class, Class[].class}); + getConstructor.setAccessible(true); + return (Constructor) getConstructor.invoke(null, target, arguments); + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + + + private Object createInstance(CapturedObject object) { + try { + ContextNode[] argumentNodes = object.getArguments(); + Object[] arguments = new Object[argumentNodes.length]; + Class[] argumentTypes = new Class[argumentNodes.length]; + for (int j = 0; j < argumentNodes.length; j++) { + if (argumentNodes[j] instanceof ValueNode) { + arguments[j] = ((ValueNode) argumentNodes[j]).getValue(); + argumentTypes[j] = arguments[j] != null ? arguments[j].getClass() : null; + } else if (argumentNodes[j] instanceof CapturedObject) { + arguments[j] = createInstance((CapturedObject) argumentNodes[j]); + argumentTypes[j] = arguments[j] != null ? arguments[j].getClass() : null; + } + } + Constructor constructor = getConstructor(Class.forName(object.getClassName(), true, classLoader), argumentTypes); + return constructor.newInstance(arguments); + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + + + public String getJavaCode(Stack/*<ContextNode>*/ context) { + CapturedObject contextCapturedObject = (CapturedObject) context.get(0); + StringBuffer result = new StringBuffer(); + int start = 1; + for (int i = context.size() - 1; i > 1; i--) { + if (context.get(i) instanceof CapturedObject) { + start = i; + contextCapturedObject = (CapturedObject) context.get(i); + break; + } + } + Object contextObject = sourceObjects.get(contextCapturedObject.getProperty("id")); + Class<?> contextClass = contextObject != null ? contextObject.getClass() : null; + + for (int i = start; i < context.size(); i++) { + ContextNode node = (ContextNode) context.get(i); + if (contextObject != null && (node instanceof MethodNode || node instanceof PropertyNode)) { + // need to follow the call chain so we can insert typecasts as necessary + try { + String methodName; + ContextNode[] argumentNodes = node.getArguments(); + if (node instanceof MethodNode) { + methodName = ((MethodNode) node).getMethodName(); + } else { + methodName = (argumentNodes.length == 0 ? "get" : "set") + org.apache.commons.lang.StringUtils.capitalize(((PropertyNode) node).getProperty()); + } + Object[] arguments = new Object[argumentNodes.length]; + Class[] argumentTypes = new Class[argumentNodes.length]; + for (int j = 0; j < argumentNodes.length; j++) { + if (argumentNodes[j] instanceof ValueNode) { + arguments[j] = ((ValueNode) argumentNodes[j]).getValue(); + argumentTypes[j] = arguments[j] != null ? arguments[j].getClass() : null; + } else if (argumentNodes[j] instanceof CapturedObject) { + arguments[j] = createInstance((CapturedObject) argumentNodes[j]); + argumentTypes[j] = arguments[j].getClass(); + } else if (argumentNodes[j] instanceof LiteralNode) { + arguments[j] = ((LiteralNode) argumentNodes[j]).getValue(); + argumentTypes[j] = arguments[j].getClass(); + } else { + throw new IllegalArgumentException("unsupported argument type: " + argumentNodes[j]); + } + } + + Method method = getMethod(contextClass, methodName, argumentTypes); + if (method == null) { + // could not find method in contextClass, must be defined in a subclass -- insert a typecast + result.insert(0, "((" + getOutputName(contextObject.getClass()) + ") "); + result.append(')'); + method = getMethod(contextObject.getClass(), methodName, argumentTypes); + } + if (method == null) { + throw new RuntimeException("could not find method " + methodName + Arrays.asList(argumentTypes) + " in " + contextObject.getClass() + " (context: " + context + ")"); + } + contextObject = method.invoke(contextObject, arguments); + contextClass = method.getReturnType(); + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + + if (i > start) { + result.append('.'); + } + + result.append(getJavaCode(node)); + } + return result + ";"; + } + + + private String getOutputName(Class c) { + return c.getName(); + } + + + public CapturedObject processObject(Element objectTag, Stack<ContextNode> context) { + String className = objectTag.getAttribute("class"); + ObjectHandler handler; + if (className.length() > 0) { + try { + ClassDescriptor descriptor = ClassDescriptorLoader.getClassDescriptor(className, classLoader); + handler = (ObjectHandler) objectHandlers.get(descriptor); + } + catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } else { + handler = (ObjectHandler) objectHandlers.get(ClassDescriptorLoader.getClassDescriptor(Object.class)); + } + + return handler.processObject(objectTag, context, this); + } + + + private synchronized String convertToJAXX(InputStream beansXML) throws IOException { + try { + Document document = JAXXCompiler.parseDocument(beansXML); + Element rootElement = document.getDocumentElement(); + NodeList nodes = rootElement.getChildNodes(); + Stack<ContextNode> context = new Stack<ContextNode>(); + for (int i = 0; i < nodes.getLength(); i++) { + Node child = nodes.item(i); + if (child.getNodeType() == Node.ELEMENT_NODE) { + Element element = (Element) child; + if (!element.getTagName().equals("object")) { + throw new Error("expected tag 'object', found '" + element.getTagName() + "'"); + } + CapturedObject root = processObject(element, context); + for (CapturedObject object : capturedObjects.values()) { // add all orphan objects to the root, so any non-inlineable ones have their XML created + if (object.getParent() == null && object != root) { + root.addChild(object, null); + } + } + return root.getXML(this); + } + } + return null; + } + catch (SAXException e) { + throw new RuntimeException(e); + } + finally { + reset(); + } + } + + + private void reset() { + sourceObjects.clear(); + capturedObjects.clear(); + count = 0; + } + + + public static void main(String[] arg) throws Exception { + File file = new File(arg[0]); + JarFile jarFile = new JarFile(file); + ClassLoader classLoader = new URLClassLoader(new URL[]{file.toURI().toURL()}); + Thread.currentThread().setContextClassLoader(classLoader); + EventQueue systemQueue = Toolkit.getDefaultToolkit().getSystemEventQueue(); + systemQueue.push(new CaptureEventQueue(classLoader)); + Manifest mf = jarFile.getManifest(); + String mainClassName = mf.getMainAttributes().getValue(Attributes.Name.MAIN_CLASS); + Class<?> mainClass = Class.forName(mainClassName, true, classLoader); + Method main = mainClass.getMethod("main", new Class[]{String[].class}); + main.invoke(null, new Object[]{new String[0]}); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/LiteralNode.java b/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/LiteralNode.java new file mode 100644 index 0000000..0683c00 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/LiteralNode.java @@ -0,0 +1,20 @@ +package jaxx.tools.jaxxcapture; + +public class LiteralNode extends AbstractContextNode { + private String javaCode; + private Object value; + + public LiteralNode(String javaCode, Object value) { + this.javaCode = javaCode; + this.value = value; + } + + + public String getJavaCode() { + return javaCode; + } + + public Object getValue() { + return value; + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/MethodNode.java b/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/MethodNode.java new file mode 100644 index 0000000..d1fff14 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/MethodNode.java @@ -0,0 +1,19 @@ +package jaxx.tools.jaxxcapture; + +public class MethodNode extends AbstractContextNode { + private String methodName; + + public MethodNode(String methodName) { + this.methodName = methodName; + } + + + public String getMethodName() { + return methodName; + } + + @Override + public String toString() { + return "Method[" + methodName + ", " + java.util.Arrays.asList(getArguments()) + "]"; + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/PropertyNode.java b/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/PropertyNode.java new file mode 100644 index 0000000..51e5d7c --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/PropertyNode.java @@ -0,0 +1,19 @@ +package jaxx.tools.jaxxcapture; + +public class PropertyNode extends AbstractContextNode { + private String property; + + public PropertyNode(String property) { + this.property = property; + } + + + public String getProperty() { + return property; + } + + + public String toString() { + return "Property[" + property + ", " + java.util.Arrays.asList(getArguments()) + "]"; + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/ValueNode.java b/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/ValueNode.java new file mode 100644 index 0000000..ef4ecb3 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/ValueNode.java @@ -0,0 +1,14 @@ +package jaxx.tools.jaxxcapture; + +public class ValueNode extends AbstractContextNode { + private Object value; + + public ValueNode(Object value) { + this.value = value; + } + + + public Object getValue() { + return value; + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/handlers/JTabbedPaneHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/handlers/JTabbedPaneHandler.java new file mode 100644 index 0000000..ac7058d --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/handlers/JTabbedPaneHandler.java @@ -0,0 +1,25 @@ +package jaxx.tools.jaxxcapture.handlers; + +import jaxx.tools.jaxxcapture.ContextNode; +import jaxx.tools.jaxxcapture.JAXXCapture; +import jaxx.tools.jaxxcapture.MethodNode; +import org.w3c.dom.Element; + +import java.util.Arrays; +import java.util.Stack; + +public class JTabbedPaneHandler extends ObjectHandler { + @Override + protected void evaluateMethod(Element tag, Stack<ContextNode> context, JAXXCapture capture) { + String methodName = tag.getAttribute("method"); + if (methodName.equals("addTab")) { + MethodNode addTab = new MethodNode(methodName); + context.push(addTab); + processChildren(tag, context, capture); + context.pop(); + System.err.println(Arrays.asList(addTab.getArguments())); + } else { + super.evaluateMethod(tag, context, capture); + } + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/handlers/ObjectHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/handlers/ObjectHandler.java new file mode 100644 index 0000000..846c8fb --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/handlers/ObjectHandler.java @@ -0,0 +1,323 @@ +package jaxx.tools.jaxxcapture.handlers; + +import jaxx.compiler.JavaFile; +import jaxx.compiler.JAXXCompiler; +import jaxx.tools.jaxxcapture.CapturedObject; +import jaxx.tools.jaxxcapture.ContextNode; +import jaxx.tools.jaxxcapture.JAXXCapture; +import jaxx.tools.jaxxcapture.LiteralNode; +import jaxx.tools.jaxxcapture.MethodNode; +import jaxx.tools.jaxxcapture.PropertyNode; +import jaxx.tools.jaxxcapture.ValueNode; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import java.awt.Container; +import java.lang.reflect.Field; +import java.util.Map; +import java.util.Stack; + +public class ObjectHandler { + private static int count; + + protected CapturedObject createCapturedObject(String className, JAXXCapture capture) { + return new CapturedObject(this, className, capture); + } + + + // returns true if the tag has any "void" children + protected boolean processChildren(Element tag, Stack<ContextNode> context, JAXXCapture capture) { + boolean result = false; + NodeList children = tag.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + if (child.getNodeType() == Node.ELEMENT_NODE) { + Element innerTag = (Element) child; + if (innerTag.getTagName().equals("void")) { + result = true; + } + evaluate(innerTag, context, capture); + } + } + return result; + } + + + protected void evaluateProperty(Element tag, Stack<ContextNode> context, JAXXCapture capture) { + // determine containing object + CapturedObject contextObject = null; + for (int i = context.size() - 1; i >= 0; i--) { + if (context.get(i) instanceof CapturedObject) { + contextObject = (CapturedObject) context.get(i); + break; + } + } + assert contextObject != null; + + String property = tag.getAttribute("property"); + if (!property.equals("actionCommand")) { // filter out actionCommand due to screwiness in XMLEncoder's handling of it + Object current = context.peek(); + PropertyNode newContext = new PropertyNode(property); + context.push(newContext); + boolean voidChildren = processChildren(tag, context, capture); + + ContextNode[] arguments = newContext.getArguments(); + if (arguments.length == 1) { + if (current instanceof CapturedObject && arguments[0] instanceof ValueNode) // simple property assignment + { + ((CapturedObject) current).setProperty(property, dataBindingEncode(String.valueOf(((ValueNode) arguments[0]).getValue()))); + } else if (current instanceof CapturedObject && arguments[0] instanceof CapturedObject && ((CapturedObject) arguments[0]).isInlineable()) // simple data binding + { + ((CapturedObject) current).setProperty(property, "{" + capture.getJavaCode(arguments[0]) + "}"); + } else { + contextObject.setInlineable(false); + contextObject.appendScriptCode(capture.getJavaCode(context)); + } + } else if (!voidChildren) { + contextObject.setInlineable(false); + contextObject.appendScriptCode(capture.getJavaCode(context)); + } + + assert context.peek() == newContext; + context.pop(); + } + } + + + protected void evaluateAdd(CapturedObject contextObject, CapturedObject child, ContextNode constraints) { + contextObject.addChild(child, constraints); + } + + + protected void evaluateMethod(Element tag, Stack<ContextNode> context, JAXXCapture capture) { + // determine containing object + CapturedObject contextObject = null; + for (int i = context.size() - 1; i >= 0; i--) { + if (context.get(i) instanceof CapturedObject) { + contextObject = (CapturedObject) context.get(i); + break; + } + } + assert contextObject != null; + + try { + String methodName = tag.getAttribute("method"); + MethodNode newContext = new MethodNode(methodName); + context.push(newContext); + boolean voidChildren = processChildren(tag, context, capture); + boolean add = false; + + ContextNode[] arguments = newContext.getArguments(); + if (methodName.equals("add") && arguments.length >= 1 && arguments[0] instanceof CapturedObject) { + Class contextClass = Class.forName(contextObject.getClassName(), true, capture.getClassLoader()); + if (Container.class.isAssignableFrom(contextClass)) { + add = true; + evaluateAdd(contextObject, (CapturedObject) arguments[0], null); + } + } + + if (!voidChildren && !add) { + contextObject.appendScriptCode(capture.getJavaCode(context)); + } + + assert context.peek() == newContext; + context.pop(); + } + catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + + protected void evaluate(Element tag, Stack<ContextNode> context, JAXXCapture capture) { + String tagName = tag.getTagName(); + if (tagName.equals("object")) { + String fieldName = tag.getAttribute("field"); + ContextNode currentNode = context.peek(); + if (fieldName.length() > 0) { + try { + String className = tag.getAttribute("class"); + Field field = Class.forName(className, true, capture.getClassLoader()).getField(fieldName); + Object value = field.get(null); + currentNode.addArgument(new LiteralNode(className + "." + fieldName, value)); + } + catch (Exception e) { + throw new RuntimeException(e); + } + } else { + currentNode.addArgument(capture.processObject(tag, context)); + } + } else if (tagName.equals("void")) { + String property = tag.getAttribute("property"); + if (property.length() > 0) { + evaluateProperty(tag, context, capture); + } else { + evaluateMethod(tag, context, capture); + } + } else if (tagName.equals("string")) { + context.peek().addArgument(new ValueNode(JAXXCapture.getText(tag))); + } else if (tagName.equals("boolean")) { + context.peek().addArgument(new ValueNode(Boolean.valueOf(JAXXCapture.getText(tag)))); + } else if (tagName.equals("char")) { + context.peek().addArgument(new ValueNode(JAXXCapture.getText(tag).charAt(0))); + } else if (tagName.equals("short")) { + context.peek().addArgument(new ValueNode(Short.valueOf(JAXXCapture.getText(tag)))); + } else if (tagName.equals("int")) { + context.peek().addArgument(new ValueNode(Integer.valueOf(JAXXCapture.getText(tag)))); + } else if (tagName.equals("long")) { + context.peek().addArgument(new ValueNode(Long.valueOf(JAXXCapture.getText(tag)))); + } else if (tagName.equals("float")) { + context.peek().addArgument(new ValueNode(Float.valueOf(JAXXCapture.getText(tag)))); + } else if (tagName.equals("double")) { + context.peek().addArgument(new ValueNode(Double.valueOf(JAXXCapture.getText(tag)))); + } else if (tagName.equals("null")) { + context.peek().addArgument(new ValueNode(null)); + } else { + System.err.println("unsupported tag: " + tag.getTagName()); + } + } + + + private static String dataBindingEncode(String value) { + return value.replaceAll("\\{", "\\\\{").replaceAll("\\}", "\\\\}"); + } + + + public CapturedObject processObject(Element objectTag, Stack<ContextNode> context, JAXXCapture capture) { + String className = objectTag.getAttribute("class"); + if (className.length() > 0) { + CapturedObject capturedObject = createCapturedObject(className, capture); + context.push(capturedObject); + NodeList children = objectTag.getChildNodes(); + String id = objectTag.getAttribute("id"); + if (id.length() == 0 || capture.getCapturedObjects().containsKey(id)) { + id = "Auto" + ++count; + } + assert !capture.getCapturedObjects().containsKey(id); + capture.getCapturedObjects().put(id, capturedObject); + capturedObject.setProperty("id", id); + // process object's name before anything else + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + if (child.getNodeType() == Node.ELEMENT_NODE) { + Element element = (Element) child; + if (element.getTagName().equals("void") && element.getAttribute("property").equals("name")) { + evaluate(element, context, capture); + String name = capturedObject.getProperty("name"); + if (name != null && !capture.getCapturedObjects().containsKey(name)) { + capture.getCapturedObjects().put(name, capturedObject); + capturedObject.setProperty("id", name); + capturedObject.getProperties().remove("name"); + } + } + } + } + // process remaining children + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + if (child.getNodeType() == Node.ELEMENT_NODE) { + Element element = (Element) child; + if (!element.getTagName().equals("void") || !element.getAttribute("property").equals("name")) { + evaluate(element, context, capture); + } + } + } + assert context.peek() == capturedObject; + context.pop(); + + return capturedObject; + } else { + CapturedObject result = capture.getCapturedObjects().get(objectTag.getAttribute("idref")); + if (result == null) { + throw new RuntimeException("Internal error: could not find tag with id " + objectTag.getAttribute("idref")); + } + result.setInlineable(false); // we have at least two references to it, and so can't inline it + return result; + } + } + + + private static String xmlEncode(String src) { + return src.replaceAll("'", "&").replaceAll("<", "<"); + } + + + public String getXML(CapturedObject object, JAXXCapture capture) { + StringBuffer result = new StringBuffer(); + result.append('<'); + String className = object.getClassName(); + if (className.startsWith("javax.swing.")) { + className = className.substring("javax.swing.".length()); + } + result.append(className); + Map<String, String> properties = object.getProperties(); + for (Map.Entry<String, String> e : properties.entrySet()) { + result.append(' '); + result.append(e.getKey()); + result.append("='"); + result.append(xmlEncode(e.getValue())); + result.append('\''); + } + ContextNode[] arguments = object.getArguments(); + if (arguments != null && arguments.length > 0) { + result.append(" constructorParams='"); + for (int j = 0; j < arguments.length; j++) { + if (j != 0) { + result.append(", "); + } + result.append(capture.getJavaCode(arguments[j])); + } + result.append('\''); + } + boolean tagClosed = false; + + String children = getChildXML(object, capture); + String lineSeparator = JAXXCompiler.getLineSeparator(); + if (children != null && children.length() > 0) { + if (!tagClosed) { + tagClosed = true; + result.append('>'); + result.append(lineSeparator); + } + result.append(children); + } + + String script = object.getScriptCode(); + if (script != null && script.length() > 0) { + if (!tagClosed) { + tagClosed = true; + result.append('>'); + result.append(lineSeparator); + } + result.append(" <script>"); + result.append(lineSeparator); + result.append(JavaFile.indent(script, 4, false, lineSeparator)); + result.append(lineSeparator); + result.append(" </script>"); + result.append(lineSeparator); + } + if (tagClosed) { + result.append("</"); + result.append(className); + result.append('>'); + } else { + result.append("/>"); + } + return result.toString(); + } + + + protected String getChildXML(CapturedObject object, JAXXCapture capture) { + StringBuffer result = new StringBuffer(); + CapturedObject[] children = object.getChildren(); + String lineSeparator = JAXXCompiler.getLineSeparator(); + for (CapturedObject aChildren : children) { + if (!aChildren.isInlineable()) { + result.append(JavaFile.indent(aChildren.getXML(capture), 2, false, lineSeparator)); + result.append(lineSeparator); + } + } + return result.toString(); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/handlers/TableHandler.java b/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/handlers/TableHandler.java new file mode 100644 index 0000000..ebdfe72 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/tools/jaxxcapture/handlers/TableHandler.java @@ -0,0 +1,12 @@ +package jaxx.tools.jaxxcapture.handlers; + +import jaxx.tools.jaxxcapture.CapturedObject; +import jaxx.tools.jaxxcapture.JAXXCapture; + +public class TableHandler extends ObjectHandler { + protected CapturedObject createCapturedObject(String className, JAXXCapture capture) { + CapturedObject result = new CapturedObject(this, "javax.swing.JPanel", capture); + result.setProperty("layout", "{new GridBagLayout()}"); + return result; + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/types/ColorConverter.java b/trunk/jaxx-compiler/src/main/java/jaxx/types/ColorConverter.java new file mode 100644 index 0000000..b7f3cc5 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/types/ColorConverter.java @@ -0,0 +1,35 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.types; + +import jaxx.types.*; +import java.awt.Color; +import java.lang.reflect.Field; + +public class ColorConverter implements TypeConverter { + public String getJavaCode(Object object) { + Color color = (Color) object; + return "new Color(" + color.getRed() + ", " + color.getGreen() + ", " + color.getBlue() + ")"; + } + + + public Object convertFromString(String string, Class type) { + if (type != Color.class) { + throw new IllegalArgumentException("unsupported type: " + type); + } + if (string.length() == 7 && string.charAt(0) == '#') { + return new Color(Integer.parseInt(string.substring(1), 16)); + } + try { + Field color = Color.class.getField(string); + return color.get(null); + } + catch (NoSuchFieldException e) { + throw new IllegalArgumentException("colors must be of the form #xxxxxx ('#' followed by six hexadecimal digits), or the name of a constant field in java.awt.Color (found: '" + string + "')"); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/types/GridBagConstraintsConverter.java b/trunk/jaxx-compiler/src/main/java/jaxx/types/GridBagConstraintsConverter.java new file mode 100644 index 0000000..5081282 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/types/GridBagConstraintsConverter.java @@ -0,0 +1,22 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.types; + +import jaxx.types.*; +import java.awt.GridBagConstraints; + +public class GridBagConstraintsConverter implements TypeConverter { + public String getJavaCode(Object object) { + GridBagConstraints g = (GridBagConstraints) object; + return "new GridBagConstraints(" + g.gridx + ", " + g.gridy + ", " + g.gridwidth + ", " + g.gridheight + ", " + + g.weightx + ", " + g.weighty + ", " + g.anchor + ", " + g.fill + ", " + + TypeManager.getJavaCode(g.insets) + ", " + g.ipadx + ", " + g.ipady + ")"; + } + + + public Object convertFromString(String string, Class type) { + throw new UnsupportedOperationException("GridBagConstraints must be represented using Java code"); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/types/InsetsConverter.java b/trunk/jaxx-compiler/src/main/java/jaxx/types/InsetsConverter.java new file mode 100644 index 0000000..279e310 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/types/InsetsConverter.java @@ -0,0 +1,37 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.types; + +import jaxx.types.*; +import java.awt.Insets; +import java.util.StringTokenizer; + +public class InsetsConverter implements TypeConverter { + public String getJavaCode(Object object) { + Insets insets = (Insets) object; + return "new Insets(" + insets.top + ", " + insets.left + ", " + insets.bottom + ", " + insets.right + ")"; + } + + + public Object convertFromString(String string, Class type) { + if (type != Insets.class) { + throw new IllegalArgumentException("unsupported type: " + type); + } + StringTokenizer tokenizer = new StringTokenizer(string, ","); + int count = tokenizer.countTokens(); + if (count == 1) { + int i = Integer.parseInt(tokenizer.nextToken().trim()); + return new Insets(i, i, i, i); + } + if (count == 4) { + int[] insets = new int[count]; + for (int i = 0; tokenizer.hasMoreTokens(); i++) { + insets[i] = Integer.parseInt(tokenizer.nextToken().trim()); + } + return new Insets(insets[0], insets[1], insets[2], insets[3]); + } + throw new IllegalArgumentException("unable to convert string '" + string + "' to Insets"); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/types/KeyStrokeConverter.java b/trunk/jaxx-compiler/src/main/java/jaxx/types/KeyStrokeConverter.java new file mode 100644 index 0000000..68080e4 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/types/KeyStrokeConverter.java @@ -0,0 +1,22 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.types; + +import jaxx.types.*; +import javax.swing.KeyStroke; + +public class KeyStrokeConverter implements TypeConverter { + public String getJavaCode(Object object) { + return "KeyStroke.getKeyStroke(\"" + object.toString() + "\")"; + } + + + public Object convertFromString(String string, Class type) { + if (type != KeyStroke.class) { + throw new IllegalArgumentException("unsupported type: " + type); + } + return KeyStroke.getKeyStroke(string); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/types/PrimitiveConverter.java b/trunk/jaxx-compiler/src/main/java/jaxx/types/PrimitiveConverter.java new file mode 100644 index 0000000..8fb7f30 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/types/PrimitiveConverter.java @@ -0,0 +1,78 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.types; + +import jaxx.compiler.JAXXCompiler; + +public class PrimitiveConverter implements TypeConverter { + public String getJavaCode(Object object) { + if (object instanceof Boolean) { + return String.valueOf(((Boolean) object).booleanValue()); + } + if (object instanceof Byte) { + return String.valueOf(((Byte) object).byteValue()); + } + if (object instanceof Short) { + return String.valueOf(((Short) object).shortValue()); + } + if (object instanceof Integer) { + return String.valueOf(((Integer) object).intValue()); + } + if (object instanceof Long) { + return String.valueOf(((Long) object).longValue()) + "L"; + } + if (object instanceof Float) { + return String.valueOf(((Float) object).floatValue()) + "F"; + } + if (object instanceof Double) { + return String.valueOf(((Double) object).doubleValue()); + } + if (object instanceof String) { + return '"' + JAXXCompiler.escapeJavaString((String) object) + '"'; + } + throw new IllegalArgumentException("unsupported object: " + object); + } + + + public Object convertFromString(String string, Class type) { + if (type == String.class || type == Object.class || type == null) { + return string; + } + if (type == int.class || type == Integer.class) { + return Integer.valueOf(string); + } + if (type == boolean.class || type == Boolean.class) { + if (string.toLowerCase().equals("true")) { + return Boolean.TRUE; + } + if (string.toLowerCase().equals("false")) { + return Boolean.FALSE; + } + throw new IllegalArgumentException("expected 'true' or 'false', found '" + string + "'"); + } + if (type == byte.class || type == Byte.class) { + return Byte.valueOf(string); + } + if (type == short.class || type == Short.class) { + return Short.valueOf(string); + } + if (type == long.class || type == Long.class) { + return Long.valueOf(string); + } + if (type == float.class || type == Float.class) { + return Float.valueOf(string); + } + if (type == double.class || type == Double.class) { + return Double.valueOf(string); + } + if (type == char.class || type == Character.class) { + if (string.length() == 1) { + return string.charAt(0); + } + throw new IllegalArgumentException("expected a single character, found '" + string + "'"); + } + throw new IllegalArgumentException("unsupported type: " + type); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/types/TypeConverter.java b/trunk/jaxx-compiler/src/main/java/jaxx/types/TypeConverter.java new file mode 100644 index 0000000..2f15272 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/types/TypeConverter.java @@ -0,0 +1,11 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.types; + +public interface TypeConverter { + String getJavaCode(Object object); + + Object convertFromString(String string, Class type); +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/java/jaxx/types/TypeManager.java b/trunk/jaxx-compiler/src/main/java/jaxx/types/TypeManager.java new file mode 100644 index 0000000..ad01268 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/java/jaxx/types/TypeManager.java @@ -0,0 +1,45 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.types; + +import java.util.HashMap; +import java.util.Map; + +public class TypeManager { + private static Map<Class, TypeConverter> converters = new HashMap<Class, TypeConverter>(); + + private TypeManager() { /* not instantiable */ } + + + public static void registerTypeConverter(Class type, TypeConverter converter) { + converters.put(type, converter); + } + + + public static TypeConverter getTypeConverter(Class type) { + return converters.get(type); + } + + + public static String getJavaCode(Object object) { + if (object == null) { + return "null"; + } + TypeConverter converter = getTypeConverter(object.getClass()); + if (converter == null) { + throw new IllegalArgumentException("unsupported type: " + object.getClass()); + } + return converter.getJavaCode(object); + } + + + public static Object convertFromString(String string, Class type) { + TypeConverter converter = getTypeConverter(type); + if (converter == null) { + throw new IllegalArgumentException("unsupported type: " + type); + } + return converter.convertFromString(string, type); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/main/resources/META-INF/services/jaxx.compiler.Generator b/trunk/jaxx-compiler/src/main/resources/META-INF/services/jaxx.compiler.Generator new file mode 100644 index 0000000..49cf642 --- /dev/null +++ b/trunk/jaxx-compiler/src/main/resources/META-INF/services/jaxx.compiler.Generator @@ -0,0 +1,3 @@ +jaxx.compiler.JAXXObjectGenerator +jaxx.compiler.SwingGenerator +jaxx.compiler.ValidatorGenerator diff --git a/trunk/jaxx-compiler/src/main/resources/META-INF/services/jaxx.spi.Initializer b/trunk/jaxx-compiler/src/main/resources/META-INF/services/jaxx.spi.Initializer new file mode 100644 index 0000000..f766cdb --- /dev/null +++ b/trunk/jaxx-compiler/src/main/resources/META-INF/services/jaxx.spi.Initializer @@ -0,0 +1,3 @@ +jaxx.DefaultInitializer +jaxx.SwingInitializer +jaxx.tags.validator.ValidatorInitializer diff --git a/trunk/jaxx-compiler/src/site/rst/BeanValidator.rst b/trunk/jaxx-compiler/src/site/rst/BeanValidator.rst new file mode 100644 index 0000000..5c910b8 --- /dev/null +++ b/trunk/jaxx-compiler/src/site/rst/BeanValidator.rst @@ -0,0 +1,181 @@ +------------- +BeanValidator +------------- + +.. contents:: + + +Présentation +============ + +Ajout du support de validation dans JAXX. + +La techonologie utilisée est celle de Struts 2 (XWorks 2). + + +Configuration +============= + +La configuration des validateurs se fait via des fichier xml (on peut aussi utiliser des annotations,...). + +Ajout d'un validateur +********************* + +Pour enregister un nouveau validateur sur un bean, il suffit de placer dans le même paquetage que le bean un fichier *XXX-validation.xml* où XXX est le nom non qualifié du bean. + +On peut de plus affecter un context de validation, dans ce cas le fichier doit s'appeler *XXX-YYY-validation.xml*, où YYY est le nom du context de validation. + +Ainsi on peut valider de différentes manières un bean (par exemple selon son cycle de vie :création, modification, ...). + +Ajout d'un nouveau type de validateur +************************************* + +Il est aussi possible de définir de nouveau type de validateurs : + + * créer une classe qui étend FieldValidator + * ajouter un fichier validators.xml (ou ajouter dans un tel fichier la définition du nouveau validator) à la racine du class-path. + +I18n +**** + +Afin de rendre le mécanisme multi-langue, on propose dans les fichiers de validations d'utiliser des clef i18n pour les messages. + +Un nouveau parseur dans notre plugin i18n a été ajouté pour détecter ces clefs. (*maven-i18n-plugin:0.7:parserValidation*) + + +Intégration dans JAXX +===================== + +Deux nouveaux tags ont été conçus pour pouvoir décrire un validateur dans les fichiers JAXX. + +Ce développement est dans le paquetage *jaxx.tags.validator*. + +tag BeanValidator +***************** + +Permet de définir un nouveau validateur dans une classe JAXX. + +TODO Refaire cette doc qui n'est plas à jour suite au refactoring de la validation (20090202) + +Les attributs autorisés sont les suivants : + + * *id* : le nom du validateur + + * *bean* : l'id d'un bean connu par la classe JAXX. On ne peut pas utiliser ici une expression car on n'est pas sûr de pouvoir déterminer le type de cette expression pendant le parsing ? (a verifier). + + * *beanClass* : le FQN de classe du bean à valider. Peut-être non présent si l'attribut *bean* est renseigné. + + * *beanInitializer* : une expression pour initialiser le bean à valider. TODO a revoir : on devrait utiliser uniquement un seul attribut *bean*... + + * *contextName* : le nom du contexte de validation. + + * *autoField* : flag pour indiquer l'inscription implicite des validateurs de champs du bean. Pour ce faire on parcourt l'ensemble des champs du bean et on ne considère uniquement ceux dont on connait dans la classe JAXX un composent d'édition du champ (id=nom du champ). Il est possible de surcharger ce configuration implicite en rajoutant explicitement des champs (voir le tag *field*). + + * *errorList* : le composant graphique pour afficher la liste des erreurs, doit étendre *javax.swing.JList*. Si non présent, on essayera le component d'id *errorList*. + + * *errorListModel* : le modèle qui contient la liste des erreurs (et est liée au composant *errorList*), doit étendre *jaxx.runtime.validator.swing.SwingValidatorErrorListModel*. Si non présent on essayera le composent d'id *errorListModel*. + + * *uiClass* : le FQN de la classe utilisé pour le rendu des erreurs sur les wigets d'édition. La classe doit étendre *jaxx.runtime.validator.swing.ui.AbstractBeanValidatorUI*. Si non présent, on utilise par défaut le render *jaxx.runtime.validator.swing.ui.IconValidationUI*. + + +Le tag supporte aussi l'ajout de tag *field* comme fils pour définir explicitement des champs à validater. + +tag field +********* + +Le tag *field* définit une entrée dans le validateur, on définit une correspondance entre le champ à valider et le composant d'édition de ce champ. + +Le tag supporte les attributs suivants : + + * *name* : le nom de la propriété du bean associée. + Cet attribut est obligatoire. + + * *component* : l'id du composant graphique d'édition associé à la propriété du bean. + Cet attribut peut être omis si le nom de la propriété du bean est identique à celui du composent graphique d'édition. + + +Les classes du runtime +====================== + +Ce développement est dans le paquetage *jaxx.runtime.validator* (sauf pour l'interface *jaxx.runtime.JAXXValidator*). + +Il s'agit de l'ensemble des classes ajoutées dans le module *jaxx-core* pour encapsuler la validation dans les fichiers java générés à partir des fichiers JAXX. + + +interface jaxx.runtime.JAXXValidator +************************************ + +Ce contrat a été ajouté à tous les objets JAXX générés (donc l'interface JAXXObject étend JAXXValidator). + +On définit ici uniquement des méthodes d'accès aux validateurs enregistrés dans le JAXXObject. + +TODO on pourrait ajouter des méthodes pour savoir l'état de validation d'un validateur ? + + +classe jaxx.runtime.validator.swin.SwingValidator +************************************************* + +Il s'agit de la classe principale d'encapsulation d'un validateur XWorks 2. + +Le principe est simple : le validateur écoute les modifications sur le bean associé et revalide le bean à chaque modification. La validation met à jour la liste des erreurs asociées. + +On se base sur les PropertyChangeListener pour écouter les modification des beans. Il faut donc que les beans supporte ces listeners. + +Pour les entités de ToPIA, il suffit de positionner un contexte (topia) au bean pour profiter des listeners liés. + +Pour les DTO de ToPIA, les générateurs ont été modifiés pour gérer ce support. + +Les méthodes à retenir sont : + + * *setBean* pour affecter un bean au validateur (pour déasactiver passer null). Lors de la désactivation d'un bean, les erreurs associés sont retirées de la liste des erreurs. + + * *setContextName* pour affecter un nouveau nom de context de validation (par défaut on utilise pas de context de validation). + + * *validate* pour lancer une validation sur le bean liée (ne sera opérant uniquement si un bean est liée et qu'une liste d'erreur est liée). + + * *isValid* pour connaitre l'état du validateur à un moment donné. + +Normalement la méthode *validate* ne devrait pas être appelée directement. : elle est automatiquement invoquée lorsqu'une propriété du bean est modifiée. + +classe jaxx.runtime.validator.swing.SwingValidatorErrorModel +************************************************************ + +Modélisation d'une erreur renvoyé par le validateur, on conserve ici : + + * le validateur qui a provoqué l'erreur + + * la propriété du bean en faute + + * le composent graphique d'édtion de la propriété + +classe jaxx.runtime.validator.swing.SwingValidatorErrorListModel +**************************************************************** + +Le modèle de la liste des erreurs renvoyées par le validateur. Il s'agit d'une extension d'un *javax.swing.DefaultListModel* qui permet de gérer une liste d'erreurs provenant de plusieurs validateurs en même temps. + +classe jaxx.runtime.validator.swing.SwingValidatorErrorListMouseListener +************************************************************************ + +Un listener écoutant les double clics sur une liste d'erreurs et qui donne le focus au composent graphique d'édition associée à la propriété dont l'erreur est sélectionné. + + +Les conversions +=============== + +Pour l'édition de proriétés qui ne sont pas des chaines de caractères, des erreurs de conversions peuvent survenir (conversion de la valeur de l'édtieur graphique vers le bean), avant que l'on utilise +réellement la mécanique de la validation. + +Pour palier à ce problème on a intégré la gestion des erreurs de conversion dans le validateur. +Pour ce faire, il suffit de faire appel à la méthode suivante pour injecter dans un bean une propriété : + + :: + + jaxx.runtime.Util.convert(validator,"nomDeLaPropriété",widget.getText(),TypeDeLaProriete.class); + + +On obtiendra si une erreur de conversion intervient, une erreur dont le libellé est de la forme *error.convertor.XXX* +où XXX est nom simple en minuscule du type de la propruité. (par exemple : *error.convertor.integer*). + + + + diff --git a/trunk/jaxx-compiler/src/site/rst/I18n.rst b/trunk/jaxx-compiler/src/site/rst/I18n.rst new file mode 100644 index 0000000..8ddfc0f --- /dev/null +++ b/trunk/jaxx-compiler/src/site/rst/I18n.rst @@ -0,0 +1,56 @@ +---- +I18n +---- + +.. contents:: + + +Présentation +============ + +Ajout du support i18n dans JAXX. + +On utilise la système i18n développé dans la librairie des lutins (*lutinlib*). + +Configuration +============= + +Une option a été ajoutée dans le plugin maven de JAXX : *i18nable* pour permettre ou non l'utilisation de ce système. + +Par défaut, l'option est active (donc aucune configuration supplémentaire n'est nécessaire pour utiliser i18n dans JAXX). + + +Fonctionnement +============== + +Le fonctionnement est simple : lors de la compilation JAXX, lorsque l'on rencontre certains attributs on encapsule la +valeur de l'attribution par un appel à la méthode + +:: + + org.nuiton.i18n.I18n._(String) + + +La liste des attributs en question sont les suivants : + + - title + - text + - toolTipText + + +Ensuite l'utilisation du *parserJava* du plugin i18n permet la détection des clefs i18n. + + +Pourquoi ne plus utiliser l'ancien parserJaxx du plugin i18n +============================================================ + +Un parseur avait été développé initialement pour détecter dans les fichiers JAXX (*parserJaxx*), les appels à la méthode de traduction +i18n dans les attributs. + +Ce parseur n'est plus d'actualité car on ne doit plus avoir d'appel explicite à cette méthode dans les fichiers JAXX. + +De plus, même sans avoir mis en place le mécanisme i18n dans JAXX, ce parseur n'était plus d'actualité : il se base +sur une liste prédéfinie d'attributs xml à scanner pour détecter des appels i18n; ce qui n'était pas acceptable à terme +car si on ajoute un nouveau composent dans JAXX, le plugin i18n n'est pas capable de détecter les nouvelles clefs. + +Donc on préconise l'utilisation du *parserJava* du plugin i18n qui lui est capable de détecter tous les appels i18n. diff --git a/trunk/jaxx-compiler/src/site/rst/Interface.rst b/trunk/jaxx-compiler/src/site/rst/Interface.rst new file mode 100644 index 0000000..61844e9 --- /dev/null +++ b/trunk/jaxx-compiler/src/site/rst/Interface.rst @@ -0,0 +1,38 @@ +--------- +Interface +--------- + +.. contents:: + + +Présentation +============ + +Ajout de contrats sur le code généré dans JAXX. + +Mécanisme +========= + +Le compilateur JAXX génère des classes à partir de fichiers JAXX mais n'est pas capable d'ajouter des contrats sur +les objets générés, donc interdit en quelque sorte la programmation par contrat. + +Pour palier à cette limitation, on a ajouté un attribut spécial *implements*. + +Cette attribut ne doit être placé que sur le tag racine d'un fichier JAXX et son contenu est le nom qualifié d'un ou +plusieurs contrats séparaés par des virgules. + +:: + + <JPanel implements='java.lang.Comparable'> + + <script>public int compareTo(JPanel o) { return getName().compareTo(o.getName()); }</script> + + </JPanel> + +La classe générée aura bien le contrat *java.lang.Comparable*. + +TODO +==== + +Il serait intéressant lors de l'injection de contrats sur un objet jaxx de pouvoir vérifier si toutes les méthodes du +contrat sont bien implantées dans la classe, et si ce n'est pas le cas de rendre la classe abstraite. diff --git a/trunk/jaxx-compiler/src/site/rst/JAXXContext.rst b/trunk/jaxx-compiler/src/site/rst/JAXXContext.rst new file mode 100644 index 0000000..465f8fd --- /dev/null +++ b/trunk/jaxx-compiler/src/site/rst/JAXXContext.rst @@ -0,0 +1,161 @@ +----------- +JAXXContext +----------- + +.. contents:: + + +Présentation +============ + +Ajout d'un context applicatif dans JAXX. + +Le besoin initial de ce développement est de pouvoir facilement intégrer un context applicatif dans JAXX et de pouvoir +l'utiliser dans les fichiers JAXX pour injecter par exemple des données dans les widgets. + +jaxx.runtime.JAXXContext +======================== + +Il s'agit du contrat de base du context applicatif. + +Les entrées dans le context +*************************** + +Chaque donnée utilisable dans le context est caractérisée par deux propriétés : + + * la type de l'objet + + * un nom (facultatif) associé à la donnée + +Le type de l'objet correspondant en fait à la classe de la donnée. + +Le nom qui est facultatif permet de pouvoir distinguer plusieurs données d'un même type dans le context. Si le nom +n'est pas utilisé pour caractériser une données on fixera alors sa valeur à *null*. + +Afin de pouvoir caractériser les entrées dans le context, une classe a été définie *jaxx.runtime.JAXXContextEntryDef*. + +Les méthodes de lecture +*********************** + +On a définit deux méthodes de lecture de données dans le context : + + * *getContextValue(Class)* récupère la donnée *non nommée* dont le type correspond à celui passé. + + * *getContextValue(Class,String)* récupère la donnée nommé dont le type correspond à celui passé. + +Les méthodes d'écriture +*********************** + +On a définit quatre méthodes d'écriture de données dans le context : + + * *setContextValue(Object)* enregistre dans le context la donnée *non nommée*. + + * *setContextValue(Object,String)* enregistre dans le context la donnée *nommée*. + + * *removeContextValue(Class)* supprime du context, la donnée *non nommée* dont le type est passé. + + * *removeContextValue(Class, String)* supprime du context, la donnée *nommée* dont le type est passé. + +Afin de pouvoir assurer une cohérence dans le context, chaque injection de donnée, sera toujours précédée par une +suppression d'un éventuellement ancienne valeur qui aurait la même définition d'entrée. + +L'héritage +********** + +Il est possible d'avoir une hériarchie de context qui s'enchaînent. Ce mécanisme a été mis en place pour répondre à un +besion précis : chaque fichier JAXX donne lieu à une nouvelle classe qui possède son propre context. + +On peut avoir des fichiers JAXX qui utilisent d'autres fichiers JAXX, il faut donc être capable de lier le context du +composent parent avec ses fils. + +La mise en place de l'héritage est transparente pour l'utilisateur : aucune méthode supplémentaire n'est requise. + +Les implantations de context +============================ + +jaxx.runtime.DefaultJAXXContext +******************************* + +Il s'agit de l'implantation par défaut utilisée par les objects *JAXXObject* (objets générés). + +A noter que pour les opérations d'injection ou de suppression, on effectuera les opérations sur le context qui contient +réellement la donnée, ce qui est important pour conserver la cohérence des contexts dans les contexts chaînés. + +Pour traiter le context parent, aucune méthode publique supplémentaire n'a été rajoutée, il suffit d'injecter un objet +de type *JAXXContext* *non nommé* qui le context courant qui sera détecté comme une entrée de type context. + +Cette entrée spéciale ne sera pas stockée avec les autres entrées afin d'optimiser les algorithmes d'injection et de +restitution. + +jaxx.runtime.JAXXInitialContext +******************************* + +On a implanté un second type de context qui lui peut servir à l'initialisation des JAXXObject. + +Ce second type de context ajoute des méthodes pour préparer le context avant l'instanciation des JAXXObject. + +Ce context admet certaine limitation (pas de suppression dans le context), et apporte trois nouvelles méthodes : + + * add(Object) : injecte dans le context une entrée non nommée et retourne l'instance du context. + + * add(String,Object) : injecte dans le context une entrée nommé et retourne l'instance du context. + + * to(JAXXContext) : injecte dans le context passé toutes les entrée du context. + +Les méthodes *add* peuvent être chaînées comme dans l'exemple suivant : + +:: + + JAXXInitialContext context = new JAXXInitialContext().add("string").add(0).add("currentDate",new Date()); + + +Intégration dans les JAXXObject +=============================== + +Le traitement d'un fichier JAXX donne lieu à une classe qui possède le contrat *jaxx.runtime.JAXXObject*. + +Ce contrat hérite donc du contrat *JAXXContext* (afin de pouvoir l'utiliser de manière transparente dans les fichiers JAXX). + +Afin de simplifier la génération et les évolutions du context indépendemment des évolutions des JAXXObject, on utilise +un pattern de délégation au sein des object générés. + +Paramétrage de l'implantation du context +**************************************** + +Une propriété a été rajoutée sur le plugin JAXX, afin de pouvoir préciser l'implantation de context à utiliser : + +:: + + jaxx.jaxxContextImplementorClass + +Il s'agit du nom qualifié de la classe d'implantation à utiliser. + +Par défaut, si rien n'est renseigné, on utilisera un *jaxx.runtime.DefaultJAXXContext*. + + +Initialisation d'un JAXXObject +****************************** + +Un nouveau constructeur a été ajouté dans les JAXXObjet générés afin de pouvoir facilement initialisé un tel objet à +partir d'un context parent, son unique paramètre est le context parent. Ce constructeur est capable de différencer le +type de context passé : + + * s'il s'agit d'un *JAXXInitialContext*, on recopie alors dans le context réel de l'objet toutes les entrées du context passé. + + * sinon le context passé est simplement injecté dans le context de l'objet (et donc sera utilisé comme le context parent de celui de l'objet). + +Voici un exemple d'initialisation d'un JAXXObject : + +:: + + java.util.Date currentDate = new java.util.Date(); + JAXXInitialContext context = new JAXXInitialContext().add("string").add(0).add("currentDate",currentDate); + JAXXObject ui = new MyUI(context); + + assert "string".equals(myUI.getContextValue(String.class)); + assert 0 == myUI.getContextValue(Integer.class); + assert currentDate.equals(myUI.getContextValue(java.util.Date.class,"currentDate")); + +A noter, que l'initialisation du context d'un *JAXXObject* sera toujours effectuée avant la méthode *$initialize* générée +par le compilateur JAXX, ce qui permet de pouvoir utiliser le context pour l'initialisation des widgets dans les fichiers JAXX. + diff --git a/trunk/jaxx-compiler/src/site/rst/JavaBean.rst b/trunk/jaxx-compiler/src/site/rst/JavaBean.rst new file mode 100644 index 0000000..e474c96 --- /dev/null +++ b/trunk/jaxx-compiler/src/site/rst/JavaBean.rst @@ -0,0 +1,50 @@ +-------- +JavaBean +-------- + +.. contents:: + + +Présentation +============ + +Ajout du support complêt des javaBean dans JAXX. + +Mécanisme +========= + +Il est possible dans JAXX de rajouter des objets quelconques via leur nom qualifié de classe : + +:: + + <JPanel> + <java.lang.Boolean id='myState' constructorParams='true'/> + <JLabel text='text' visible='{isMySate()}'/> + </JPanel> + +Avant l'ajout de la fonctionnalité, le code généré possèdait : + + * une propriété en lecture seul nommé *myState*. + +Aucun support javaBean n'était présent et le databinding sur la propriété *visible* du label n'est pas créé. Cela veut +dire que le label sera initialisé avec la valeur initiale du boolean et c'est tout... + +Avec l'ajout du support javaBean, on peut maintenant faire ces bindings, pour ce faire il suffit d'ajouter un attribut +*javaBean* sur l'objet : + +:: + + <JPanel> + <java.lang.Boolean id='myState' constructorParams='true' javaBean='anyValue'/> + <JLabel text='text' visible='{isMySate()}'/> + </JPanel> + +On aura donc en plus : + + * un mutateur sur la propriété *myState* qui déclanchera l'envoie d'un *PropertyChange* sur la propriété lors de modification de valeur. + +Ainsi le compilateur JAXX sera capable d'enregistrer un novueau dataBindig sur la propriété *visible* du label et la +modification de l'état *myState* sera automatiquement répercuté sur la propriété. + + + diff --git a/trunk/jaxx-compiler/src/site/rst/NavigationTreeModel.rst b/trunk/jaxx-compiler/src/site/rst/NavigationTreeModel.rst new file mode 100644 index 0000000..e773acb --- /dev/null +++ b/trunk/jaxx-compiler/src/site/rst/NavigationTreeModel.rst @@ -0,0 +1,168 @@ +------------------- +NavigationTreeModel +------------------- + +.. contents:: + + +Présentation +============ + +Ajout d'un modèle d'arbre de navigation. + +Le but de cette fonctionnalité est de pouvoir créer un arbre de navigation lié au context de JAXX, de définir des UI +rattachés à chaque noeud. + +Le développement est effectué dans le paquetage *jaxx.runtime.swing.navigation*. + +jaxx.runtime.swing.navigation.NavigationTreeModel +================================================= + +Il s'agit du modèle de l'arbre utilisé, c'est une extension d'un *javax.swing.tree.DefaultTreeModel*. + +Les noeuds présents dans ce modèle sont aussi typés en *jaxx.runtime.swing.navigation.NavigationTreeModel.NavigationTreeNode*. + +L'idée principale est de pouvoir associé à un noeud précis un chemin depuis la racine, ce que l'on appele *chemin de navigation*. + +Pour obtenir le chemin de navigation d'un noeud donné, on récupère l'enmseble des neoud depuis la racine vers ce noeud +et les concatène en suffixant par le caractère séparateur défini. + +Définition d'un noeud +===================== + +Le noeud (*jaxx.runtime.swing.navigation.NavigationTreeModel.NavigationTreeNode*) est une extension d'un *javax.swing.tree.DefaultMutableTreeNode*. + +Il apporte les nouvelles propriétés suivantes : + + * *navigationPAth* : nom de chemin de navigation de ce noeud. + + * *jaxxClass* : nom qualifié de la classe d'ui associé à ce noeud (doit être obligatoirement un *JAXXObject*) + + * *jaxxActionClass* : nom qualifié de la classe d'handler d'ui associé à ce noeud (doit être obligatoirement un *JAXXAction*). + + * *jaxxContextEntryDef* : définition de l'entrée dans le context JAXX associé à ce noeud. + + * *jaxxContextEntryJXPath* : définition d'une expression JXPath à appliquer sur le bean associé au noeud. + + +Retrouver un noeud à partir du chemin de navigation +*************************************************** + +Il est possible en connaissant le chemin de navigation d'un noued de récupérer le noeud dans l'arbre via la méthode + +:: + + model.findNode("chemin.de.navigation") + +Trouver la valeur associée dans le context JAXX à partir du chemin de navigation +******************************************************************************** + +Il est possible en connaissant le chemin de navigation d'un noued de récupérer la valeur associée dans le context JAXX. + +:: + + model.getJAXXContextValue(myJAXXContext, "chemin.de.navigation")* . + +L'algrotihme est le suivant : + + * récupération du noeud associé au chemin de navigation + + * recherche du premier noeud (dans les noeuds qui remontent vers la racine de l'arbre) dont la propriété *jaxxContextEntry* est non nulle, il s'agit du point d'entré dans le context JAXX. + + * redescendre à partir de ce noeud vers le noeud d'origine (si ce noeud était différent) et en descendant conjointement dans l'objet du context JAXX : + + - on utilise l'expression JXPath pour obtenir l'objet associé au noeud + +Exemple : + +:: + + "$root" + <-- la racine de l'abre + | + + "string" <-- attaché au context JAXX <java.lang.String,"string"> + | + + "liste" + <-- attaché au context JAXX <java.util.List.class,"liste"> + | | + | + "0" <-- le premier élément de la liste + | | + | + "1" <-- le second élément de la liste + | | + | + "2" <-- le troisième élément de la liste + | + + "locale" + <-- attaché au context JAXX <java.util.Locale> + | + + country + | + + language + + // preparation du context + java.util.List myList = java.util.Arrays.asList("one","two","three"); + java.util.Locale myLocale = java.util.Locale.FRENCH; + context.setContextValue(myList, "liste"); + context.setContextValue("stringValue","string"); + context.setContextValue(myLocale); + + + // récupération des valeurs dans le context à partir de chemin de navigation + assert model.getJAXXContextValue(context, "$root") == null; + assert model.getJAXXContextValue(context, "$root.string") == "stringValue"; + assert model.getJAXXContextValue(context, "$root.liste") == myList; + assert model.getJAXXContextValue(context, "$root.liste.0") == "one"; + assert model.getJAXXContextValue(context, "$root.liste.1") == "two"; + assert model.getJAXXContextValue(context, "$root.liste.2") == "three"; + assert model.getJAXXContextValue(context, "$root.locale") == myLocale; + assert model.getJAXXContextValue(context, "$root.locale.country") == myLocale.getCountry(); + assert model.getJAXXContextValue(context, "$root.locale.language") == myLocale.getLanguage(); + +TODO mettre à jour cet exemple suite à l'utilisation de JXPath pour naviguer dans les objets. + +A noter qu'une seconde méthode de récupération de valeur du context JAXX est disponible pour pouvoir récupérer cette +valeur en connaissant le noeud : + +:: + + model.getJAXXContextValue(context, myNode); + +jaxx.runtime.swing.navigation.NavigationTreeSelectionAdapter +============================================================ + +Il s'agit d'un listener sur la sélection d'un noeud dans l'arbre de navigation basé sur notre modèle de navigation. Il +étend *javax.swing.event.TreeSelectionListener*. + +Ce listener contient la gestion de passage d'un noeud à un autre avec interaction avec le context JAXX et affichage automatique de l'ui associé au noeud sélectionné. + +**Attention : la mécanique ne fonctionne que pour un arbre à selection unique.** + +Algorithme +********** + +Voici l'algorithme utilisé lors de la sélection d'un nouveau noeud : + + * *closeUI* : tentative de fermeture de l'ui lié au noeud précédemment selectionné, si cela n'aboutit pas on retourne sur le noeud précédent. + + * *attachBeanFromNodeToContext* : injection dans le context JAXX de la valeur associée au nouveau noeud + + * *createUI* : création de la nouvelle ui (si elle n'existe pas) + + * *openUI* : ouverture de la nouvelle ui + +Si une erreur survient lors de ces opérations, on entre dans la méthode *goBackToPreviousNode* qui est abstraite et permet de notifier les erreur de retourner au noeud précdent. + +jaxx.runtime.swing.navigation.NavigationTreeSelectionAdapterWithCardLayout +************************************************************************** + +Il s'agit d'une implantation du listener précédent qui suppose que les uis associées aux noeuds sont affichées dans un +unique container en utilisant le layout *jaxx.runtime.swing.CardLayout2*. + +La contrainte de chaque ui sera extactement le chemin de navigation du noeud associé. + +Il possède deux méthodes abstraites : + + * *getContentContainer* : qui indique le container d'ui. + + * *getContentLayout* : qui indique le layout utilisé. + +Pour pouvoir utilisé cet *adapter*, il vous suffit de définir la méthode suivante (en plus des deux méthodes abstraites) : + + * *goBackToPreviousNode* : comment gérer les erreurs et retourner au noeud précedent. + diff --git a/trunk/jaxx-compiler/src/site/rst/Todo.rst b/trunk/jaxx-compiler/src/site/rst/Todo.rst new file mode 100644 index 0000000..2493ab1 --- /dev/null +++ b/trunk/jaxx-compiler/src/site/rst/Todo.rst @@ -0,0 +1,15 @@ +==== +TODO +==== + + - réorganiser ce module maven en deux modules : + + * un premier module de runtime + + * un second module contenant uniquement le compilateur et non nécessaire au runtime. + + Le second module pourrait être facultatif et le code pourrait directement être placé dans le module du plugin. + + Cependant cela n'est pas possible actuelement car certains objets du runtime contiennent aussi du code utilisé + par le compilateur JAXX (par exemple StyleSheet). Il faut avant tout cloisonner le code non runtime. + \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/site/rst/index.rst b/trunk/jaxx-compiler/src/site/rst/index.rst new file mode 100644 index 0000000..555128f --- /dev/null +++ b/trunk/jaxx-compiler/src/site/rst/index.rst @@ -0,0 +1,41 @@ +jaxx-core +========= + +.. contents:: + + +Présentation +------------ + +Le compilateur Jaxx TODO + +**Veuillez consulter la JavaDoc pour de plus ample détails sur les différentes +librairies.** + +Nouvelles fonctionnalités +------------------------- + + * I18n_ + + * JAXXContext_ + + * BeanValidator_ + + * NavigationTreeModel_ + + * JavaBean_ + + * Interface_ + + +.. _I18n: I18n.html + +.. _JAXXContext: JAXXContext.html + +.. _BeanValidator: BeanValidator.html + +.. _NavigationTreeModel: NavigationTreeModel.html + +.. _Javabean: JavaBean.html + +.. _Interface: Interface.html \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/site/site.xml b/trunk/jaxx-compiler/src/site/site.xml new file mode 100644 index 0000000..6c8144f --- /dev/null +++ b/trunk/jaxx-compiler/src/site/site.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project name="${project.name}"> + + <bannerLeft> + <name>${project.name}</name> + <src>${site.home.url}/jaxx.png</src> + <href>index.html</href> + </bannerLeft> + + <body> + + <breadcrumbs> + <item name="${project.name}" href="${project.url}" /> + </breadcrumbs> + + <menu ref="parent"/> + + <menu name="Utilisateur" inherited="top"/> + + <menu ref="reports"/> + + <menu ref="modules"/> + + </body> +</project> diff --git a/trunk/jaxx-compiler/src/test/java/jaxx/beaninfos/BeanIntoUtilTest.java b/trunk/jaxx-compiler/src/test/java/jaxx/beaninfos/BeanIntoUtilTest.java new file mode 100644 index 0000000..5852bb9 --- /dev/null +++ b/trunk/jaxx-compiler/src/test/java/jaxx/beaninfos/BeanIntoUtilTest.java @@ -0,0 +1,34 @@ +package jaxx.beaninfos; + +import org.junit.Assert; +import org.junit.Test; + +import java.beans.Introspector; + +/** @author chemit */ +public class BeanIntoUtilTest { + + @Test + public void testExtraBeanInfoPath() { + BeanInfoUtil.reset(); + String[] searchPath0 = Introspector.getBeanInfoSearchPath(); + + BeanInfoUtil.addJaxxBeanInfoPath("jaxx.beaninfos"); + + String[] searchPath = Introspector.getBeanInfoSearchPath(); + Assert.assertEquals(searchPath0.length + 1, searchPath.length); + + BeanInfoUtil.reset(); + Assert.assertEquals(searchPath0.length, Introspector.getBeanInfoSearchPath().length); + + String packageName = getClass().getPackage().getName()+".dummy"; + BeanInfoUtil.addJaxxBeanInfoPath("jaxx.beaninfos", packageName); + + searchPath = Introspector.getBeanInfoSearchPath(); + Assert.assertEquals(searchPath0.length + 2, searchPath.length); + Assert.assertEquals(packageName, searchPath[searchPath.length - 1]); + + BeanInfoUtil.reset(); + Assert.assertEquals(searchPath0.length, Introspector.getBeanInfoSearchPath().length); + } +} diff --git a/trunk/jaxx-compiler/src/test/java/jaxx/junit/ClassDescriptorTest.java b/trunk/jaxx-compiler/src/test/java/jaxx/junit/ClassDescriptorTest.java new file mode 100644 index 0000000..e3b3b92 --- /dev/null +++ b/trunk/jaxx-compiler/src/test/java/jaxx/junit/ClassDescriptorTest.java @@ -0,0 +1,63 @@ +package jaxx.junit; + +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.reflect.MethodDescriptor; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import org.junit.Test; + +public class ClassDescriptorTest { + + /*@Test + public void testGetClassDescriptor() throws Exception { + ClassDescriptorLoader.getClassDescriptor("jaxx.runtime.swing.navigation.NavigationTreeModel.NavigationTreeNode"); + }*/ + + @Test + public void testBuiltInClassName() throws ClassNotFoundException, NoSuchMethodException { + ClassDescriptor object = ClassDescriptorLoader.getClassDescriptor("java.lang.Object"); + MethodDescriptor toString = object.getMethodDescriptor("toString"); + assertEquals(toString.getName(), "toString"); + assertEquals(toString.getParameterTypes().length, 0); + + MethodDescriptor equals = object.getMethodDescriptor("equals", object); + assertEquals(equals.getName(), "equals"); + assertEquals(equals.getParameterTypes().length, 1); + assertEquals(equals.getParameterTypes()[0], object); + } + + @Test + public void testBuiltInClass() throws ClassNotFoundException, NoSuchMethodException { + ClassDescriptor object1 = ClassDescriptorLoader.getClassDescriptor("java.lang.Object"); + ClassDescriptor object2 = ClassDescriptorLoader.getClassDescriptor(Object.class); + assertEquals(object1, object2); + } + + @Test + public void testUserClassName() throws ClassNotFoundException, NoSuchMethodException { + ClassDescriptor me = ClassDescriptorLoader.getClassDescriptor("jaxx.junit.ClassDescriptorTest", getClass().getClassLoader()); + MethodDescriptor testUserClassName = me.getMethodDescriptor("testUserClassName"); + assertEquals(testUserClassName.getName(), "testUserClassName"); + assertEquals(testUserClassName.getParameterTypes().length, 0); + } + + @Test(expected = ClassNotFoundException.class) + public void testWrongCase() throws ClassNotFoundException { + //try { + //ClassDescriptor object = + ClassDescriptorLoader.getClassDescriptor("jaxx.junit.classdescriptortest", getClass().getClassLoader()); + // fail("Found descriptor using wrong case: " + object); + //} + //catch (ClassNotFoundException e) { + //} + } + + @Test + public void testArrays() throws ClassNotFoundException { + ClassDescriptor intArray = ClassDescriptorLoader.getClassDescriptor(int[].class); + assertNotNull(intArray); + ClassDescriptor objectArray = ClassDescriptorLoader.getClassDescriptor(Object[].class); + assertNotNull(objectArray); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/test/java/jaxx/junit/ColorConverterTest.java b/trunk/jaxx-compiler/src/test/java/jaxx/junit/ColorConverterTest.java new file mode 100644 index 0000000..0c1010e --- /dev/null +++ b/trunk/jaxx-compiler/src/test/java/jaxx/junit/ColorConverterTest.java @@ -0,0 +1,51 @@ +package jaxx.junit; + +import jaxx.types.ColorConverter; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.awt.Color; + +public class ColorConverterTest { + + ColorConverter converter; + + @Before + public void setUp() { + converter = new ColorConverter(); + } + + @Test + public void testHexValue() { + Color value = (Color) converter.convertFromString("#3000FF", Color.class); + Assert.assertEquals(value, new Color(48, 0, 255)); + } + + @Test + public void testUpperCaseConstant() { + Color value = (Color) converter.convertFromString("RED", Color.class); + Assert.assertEquals(value, Color.RED); + } + + @Test + public void testLowerCaseConstant() { + Color value = (Color) converter.convertFromString("blue", Color.class); + Assert.assertEquals(value, Color.blue); + } + + @Test(expected = IllegalArgumentException.class) + public void testMissingHash() { + converter.convertFromString("ABCDEF", Color.class); + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidNumber() { + converter.convertFromString("#ABCDEG", Color.class); + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidConstant() { + converter.convertFromString("rEd", Color.class); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/test/java/jaxx/junit/InsetsConverterTest.java b/trunk/jaxx-compiler/src/test/java/jaxx/junit/InsetsConverterTest.java new file mode 100644 index 0000000..3ea4c5d --- /dev/null +++ b/trunk/jaxx-compiler/src/test/java/jaxx/junit/InsetsConverterTest.java @@ -0,0 +1,50 @@ +package jaxx.junit; + +import jaxx.types.InsetsConverter; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.awt.Insets; + +public class InsetsConverterTest { + + InsetsConverter converter; + + @Before + public void setUp() { + converter = new InsetsConverter(); + } + + @Test + public void testSingleValue() { + Insets value = (Insets) converter.convertFromString("3", Insets.class); + Assert.assertEquals(value, new Insets(3, 3, 3, 3)); + } + + @Test + public void testFourValues() { + Insets value = (Insets) converter.convertFromString("3, 0, 12, 1000000", Insets.class); + Assert.assertEquals(value, new Insets(3, 0, 12, 1000000)); + } + + @Test(expected = IllegalArgumentException.class) + public void testTwoValues() { + converter.convertFromString("0, 4", Insets.class); + } + + @Test(expected = IllegalArgumentException.class) + public void testThreeValues() { + converter.convertFromString("0, 4, 9", Insets.class); + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidNumber() { + converter.convertFromString("0, 4, 9, A", Insets.class); + } + + @Test(expected = IllegalArgumentException.class) + public void testBadFormatting() { + converter.convertFromString("0 - 1 - 2 - 3", Insets.class); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/test/java/jaxx/junit/JavaFileParserTest.java b/trunk/jaxx-compiler/src/test/java/jaxx/junit/JavaFileParserTest.java new file mode 100644 index 0000000..d151cd9 --- /dev/null +++ b/trunk/jaxx-compiler/src/test/java/jaxx/junit/JavaFileParserTest.java @@ -0,0 +1,57 @@ +package jaxx.junit; + +import jaxx.CompilerException; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.JavaFileParser; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.File; +import java.io.FileReader; +import java.io.Reader; + +public class JavaFileParserTest { + + + /** log */ + protected static final Log log = LogFactory.getLog(JavaFileParserTest.class); + + static File basedir; + + @BeforeClass + public static void initBaseDir() { + // get maven env basedir + String basedir = System.getenv("basedir"); + if (basedir == null) { + basedir = new File("").getAbsolutePath(); + } + JavaFileParserTest.basedir = new File(basedir); + } + + @Test + public void testParseJavaSourceFile() throws Exception { + + File testSourceRoot = new File(basedir, "src" + File.separator + "test" + File.separator + "java"); + Assert.assertTrue(testSourceRoot.exists()); + + File src = new File(testSourceRoot, getClass().getName().replaceAll("\\.", File.separator) + ".java"); + Assert.assertTrue(src.exists()); + log.info("trying parsing file " + src); + Reader reader = new FileReader(src); + try { + ClassDescriptor result = JavaFileParser.parseJavaFile("TestParserJava", reader, getClass().getClassLoader()); + Assert.assertNotNull(result); + + } catch (CompilerException e) { + log.error("could not parse file " + src + " for reason " + e.getMessage(), e); + Assert.fail(e.getMessage()); + } + finally { + reader.close(); + } + } + +} diff --git a/trunk/jaxx-compiler/src/test/java/jaxx/junit/JavaMethodTest.java b/trunk/jaxx-compiler/src/test/java/jaxx/junit/JavaMethodTest.java new file mode 100644 index 0000000..59b66ba --- /dev/null +++ b/trunk/jaxx-compiler/src/test/java/jaxx/junit/JavaMethodTest.java @@ -0,0 +1,52 @@ +package jaxx.junit; + +import jaxx.compiler.JavaMethod; +import jaxx.compiler.JavaMethod.MethodOrder; +import org.junit.Assert; +import org.junit.Test; + +import java.lang.reflect.Modifier; +import java.util.EnumSet; + +/** @author chemit */ +public class JavaMethodTest { + + @Test + public void testGetMethodOrderScope() { + EnumSet<MethodOrder> allConstants = EnumSet.allOf(MethodOrder.class); + + EnumSet<MethodOrder> constants; + + constants = JavaMethod.getMethodOrderScope(allConstants, Modifier.STATIC); + + Assert.assertEquals(1, constants.size()); + Assert.assertTrue(constants.contains(MethodOrder.statics)); + + constants = JavaMethod.getMethodOrderScope(allConstants, Modifier.PUBLIC); + + Assert.assertEquals(8, constants.size()); + Assert.assertTrue(constants.contains(MethodOrder.constructors)); + Assert.assertTrue(constants.contains(MethodOrder.JAXXObject)); + Assert.assertTrue(constants.contains(MethodOrder.JAXXContext)); + Assert.assertTrue(constants.contains(MethodOrder.JAXXValidation)); + Assert.assertTrue(constants.contains(MethodOrder.events)); + Assert.assertTrue(constants.contains(MethodOrder.publicGetters)); + Assert.assertTrue(constants.contains(MethodOrder.publicSetters)); + Assert.assertTrue(constants.contains(MethodOrder.otherPublic)); + + constants = JavaMethod.getMethodOrderScope(allConstants, Modifier.PROTECTED); + + Assert.assertEquals(3, constants.size()); + Assert.assertTrue(constants.contains(MethodOrder.protectedGetters)); + Assert.assertTrue(constants.contains(MethodOrder.protecteds)); + Assert.assertTrue(constants.contains(MethodOrder.createMethod)); + + + constants = JavaMethod.getMethodOrderScope(allConstants, Modifier.PRIVATE); + Assert.assertEquals(3, constants.size()); + Assert.assertTrue(constants.contains(MethodOrder.createMethod)); + Assert.assertTrue(constants.contains(MethodOrder.packageLocal)); + Assert.assertTrue(constants.contains(MethodOrder.privates)); + + } +} diff --git a/trunk/jaxx-compiler/src/test/java/jaxx/junit/PrimitiveConverterTest.java b/trunk/jaxx-compiler/src/test/java/jaxx/junit/PrimitiveConverterTest.java new file mode 100644 index 0000000..843e03a --- /dev/null +++ b/trunk/jaxx-compiler/src/test/java/jaxx/junit/PrimitiveConverterTest.java @@ -0,0 +1,113 @@ +package jaxx.junit; + +import jaxx.types.PrimitiveConverter; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class PrimitiveConverterTest { + + PrimitiveConverter converter; + + + @Before + public void setUp() { + converter = new PrimitiveConverter(); + } + + @Test + public void testBoolean() { + Boolean value = (Boolean) converter.convertFromString("true", Boolean.class); + Assert.assertTrue(value); + + value = (Boolean) converter.convertFromString("false", Boolean.class); + Assert.assertFalse(value); + + } + + @Test(expected = IllegalArgumentException.class) + public void testBoolean2() { + converter.convertFromString("yes", Boolean.class); + } + + @Test + public void testByte() { + Byte value = (Byte) converter.convertFromString(String.valueOf(Byte.MAX_VALUE), Byte.class); + Assert.assertEquals(value.byteValue(), Byte.MAX_VALUE); + + } + + @Test(expected = IllegalArgumentException.class) + public void testByte2() { + + converter.convertFromString(String.valueOf(1 + Byte.MAX_VALUE), Byte.class); + } + + @Test + public void testShort() { + Short value = (Short) converter.convertFromString(String.valueOf(Short.MAX_VALUE), Short.class); + Assert.assertEquals(value.shortValue(), Short.MAX_VALUE); + + + } + + @Test(expected = IllegalArgumentException.class) + public void testShort2() { + + converter.convertFromString(String.valueOf(1 + Short.MAX_VALUE), Short.class); + } + + @Test + public void testInteger() { + Integer value = (Integer) converter.convertFromString(String.valueOf(Integer.MAX_VALUE), Integer.class); + Assert.assertEquals(value.intValue(), Integer.MAX_VALUE); + } + + @Test(expected = IllegalArgumentException.class) + public void testInteger2() { + + converter.convertFromString(String.valueOf(1L + Integer.MAX_VALUE), Integer.class); + } + + @Test + public void testLong() { + Long value = (Long) converter.convertFromString(String.valueOf(Long.MAX_VALUE), Long.class); + Assert.assertEquals(value.longValue(), Long.MAX_VALUE); + } + + @Test + public void testFloat() { + Float value = (Float) converter.convertFromString("3.1415", Float.class); + Assert.assertTrue(value == 3.1415f); + } + + @Test + public void testDouble() { + Double value = (Double) converter.convertFromString("3.1415", Double.class); + Assert.assertTrue(value == 3.1415); + } + + @Test + public void testCharacter() { + Character value = (Character) converter.convertFromString("A", Character.class); + Assert.assertEquals(value.charValue(), 'A'); + } + + @Test(expected = IllegalArgumentException.class) + public void testCharacter2() { + + converter.convertFromString("12", Character.class); + + } + + @Test(expected = IllegalArgumentException.class) + public void testCharacter3() { + converter.convertFromString("", Character.class); + } + + @Test + public void testString() { + String value = (String) converter.convertFromString("Test", String.class); + Assert.assertEquals(value, "Test"); + } +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/test/java/jaxx/junit/TagManagerTest.java b/trunk/jaxx-compiler/src/test/java/jaxx/junit/TagManagerTest.java new file mode 100644 index 0000000..446a4ac --- /dev/null +++ b/trunk/jaxx-compiler/src/test/java/jaxx/junit/TagManagerTest.java @@ -0,0 +1,143 @@ +package jaxx.junit; + +import jaxx.compiler.JAXXCompiler; +import jaxx.compiler.JAXXCompilerLaunchor; +import jaxx.compiler.SwingCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.tags.DefaultComponentHandler; +import jaxx.tags.DefaultObjectHandler; +import jaxx.tags.TagHandler; +import jaxx.tags.TagManager; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import javax.swing.JPopupMenu; +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; + +public class TagManagerTest { + + protected JAXXCompiler compiler; + + public static class TestHandler extends DefaultObjectHandler { + public TestHandler(ClassDescriptor beanClass) { + super(beanClass); + } + } + + @BeforeClass + public static void initTagManaer() throws Exception { + + TagManager.reset(true); + + } + + @Before + public void setUp() { + JAXXCompilerLaunchor.newLaunchor(); + compiler = new SwingCompiler(SwingCompiler.class.getClassLoader()); + compiler.addImport("javax.swing.*"); + + } + + @Test + public void testRegisterBean() { + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(InputStream.class), TestHandler.class); + + Assert.assertTrue(TagManager.getTagHandler(ClassDescriptorLoader.getClassDescriptor(InputStream.class)) instanceof TestHandler); + Assert.assertTrue(TagManager.getTagHandler(ClassDescriptorLoader.getClassDescriptor(FileInputStream.class)) instanceof TestHandler); + } + + @Test + public void testRegisterDefaultNamespace() { + + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(OutputStream.class), TestHandler.class); + + TagManager.registerDefaultNamespace("OutputStream", "java.io.*"); + Assert.assertTrue("Could not find handler for OutputStream despite default namespace", TagManager.getTagHandler(null, "OutputStream", compiler) instanceof TestHandler); + + PrintStream oldErr = System.err; + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + System.setErr(new PrintStream(buffer)); + TagManager.registerDefaultNamespace("OutputStream", "java.dummy.*"); + Assert.assertNull("Found handler for OutputStream despite ambiguous default namespace", TagManager.getTagHandler(null, "OutputStream", compiler)); + System.setErr(oldErr); + Assert.assertTrue("No errors were produced with an ambiguous default namespace", buffer.size() > 0); + Assert.assertTrue(buffer.size() > 0); + } + + @Test + public void testResolveClassName() { + Assert.assertEquals("Could not resolve class name 'Object'", TagManager.resolveClassName("Object", compiler), "java.lang.Object"); + Assert.assertEquals("Could not resolve class name 'java.lang.Object'", TagManager.resolveClassName("java.lang.Object", compiler), "java.lang.Object"); + Assert.assertNull("Unexpectedly resolved class name 'java.awt.Object'", TagManager.resolveClassName("java.awt.Object", compiler)); + } + + @Test + public void testPackages() { + Assert.assertNull("Unexpectedly found handler for java.awt.JButton", TagManager.getTagHandler(null, "java.awt.JButton", compiler)); + Assert.assertNotNull("Did not find handler for JButton with default namespace of java.awt.*", TagManager.getTagHandler("java.awt.*", "JButton", compiler)); + Assert.assertNull("Unexpectedly found handler for java.awt.*:JButton", TagManager.getTagHandler("java.awt.*", "JButton", true, compiler)); + Assert.assertNotNull("Did not find handler for javax.swing.JButton", TagManager.getTagHandler(null, "javax.swing.JButton", compiler)); + Assert.assertNotNull("Did not find handler for JButton with default namespace of java.swing.*", TagManager.getTagHandler("java.swing.*", "JButton", compiler)); + Assert.assertNotNull("Did not find handler for javax.swing.*:JButton", TagManager.getTagHandler("javax.swing.*", "JButton", true, compiler)); + } + + @Test + public void testImport() throws Exception { + Assert.assertNull("Found handler for ActionListener despite no java.awt.event.* import", TagManager.getTagHandler(null, "ActionListener", compiler)); + + compiler.addImport("java.awt.event.*"); + + Assert.assertNotNull("Did not find ActionListener with java.awt.event.* import", TagManager.getTagHandler(null, "ActionListener", compiler)); + } + + @Test + public void testAmbiguousImport() throws Exception { + compiler.addImport("java.sql.*"); + Assert.assertNotNull("Did not find java.sql.Date with only java.sql.* imported", TagManager.getTagHandler(null, "Date", compiler)); + + PrintStream oldErr = System.err; + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + System.setErr(new PrintStream(buffer)); + compiler.addImport("java.util.*"); + TagManager.reset(true); + Assert.assertNull("Still found a handler for Date with an ambiguous import", TagManager.getTagHandler(null, "Date", compiler)); + System.setErr(oldErr); + Assert.assertTrue("No errors were produced with an ambiguous import", buffer.size() > 0); + + compiler.addImport("java.util.Date"); + Assert.assertNotNull("Did not find java.util.Date with a disambiguating import", TagManager.getTagHandler(null, "Date", compiler)); + } + + @Test + public void testInnerClass() { + TagHandler handler = TagManager.getTagHandler(null, "JPopupMenu.Separator", compiler); + Assert.assertTrue("Unable to resolve tag <JPopupMenu.Separator>", handler instanceof DefaultComponentHandler); + Assert.assertTrue(((DefaultComponentHandler) handler).getBeanClass().getName().equals(JPopupMenu.Separator.class.getName())); + + handler = TagManager.getTagHandler(null, "javax.swing.JPopupMenu.Separator", compiler); + Assert.assertTrue("Unable to resolve tag <javax.swing.JPopupMenu.Separator>", handler instanceof DefaultComponentHandler); + Assert.assertTrue(((DefaultComponentHandler) handler).getBeanClass().getName().equals(JPopupMenu.Separator.class.getName())); + } + + @Test + public void testWrongCase() { + Assert.assertNull("Unexpectedly found handler for 'object'", TagManager.getTagHandler(null, "object", compiler)); + Assert.assertNull("Unexpectedly found handler for 'tagmanagertest'", TagManager.getTagHandler(null, "tagmanagertest", compiler)); + } + + @Test + public void testAliasing() { + Assert.assertEquals("JComboBox is not aliased to jaxx.runtime.swing.JAXXComboBox", "jaxx.runtime.swing.JAXXComboBox", TagManager.resolveClassName("JComboBox", compiler)); + Assert.assertEquals("javax.swing.JComboBox is not aliased to jaxx.runtime.swing.JAXXComboBox", "jaxx.runtime.swing.JAXXComboBox", TagManager.resolveClassName("javax.swing.JComboBox", compiler)); + } + + +} \ No newline at end of file diff --git a/trunk/jaxx-compiler/src/test/java/jaxx/runtime/swing/navigation/NavigationTreeModelTest.java b/trunk/jaxx-compiler/src/test/java/jaxx/runtime/swing/navigation/NavigationTreeModelTest.java new file mode 100644 index 0000000..90564a7 --- /dev/null +++ b/trunk/jaxx-compiler/src/test/java/jaxx/runtime/swing/navigation/NavigationTreeModelTest.java @@ -0,0 +1,394 @@ +package jaxx.runtime.swing.navigation; + +import jaxx.runtime.swing.navigation.*; +import jaxx.runtime.DefaultJAXXContext; +import jaxx.runtime.JAXXContext; +import jaxx.runtime.JAXXContextEntryDef; +import jaxx.runtime.swing.navigation.NavigationTreeModel.NavigationTreeNode; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + + +/** + * Test du model de navigation. + * + * @author chemit + */ +public class NavigationTreeModelTest { + + private static final String ROOT_CONTEXT = "$root"; + private static final String FAKE = "-fake"; + + private static final String separator = "/"; + + @Test + public void testFindNode() throws Exception { + + NavigationTreeModelBuilder builder = new NavigationTreeModelBuilder(separator); + + NavigationTreeNode rootNode = builder.build(null, (String) null, (String) null, ROOT_CONTEXT, null, null); + + for (int i = 0; i < 4; i++) { + NavigationTreeNode sonNode = builder.build(rootNode, (String) null, (String) null, getNodeContext(i), null, null); + for (int j = 0; j < 4; j++) { + NavigationTreeNode sonSonNode = builder.build(sonNode, (String) null, (String) null, getNodeContext(i, j), null, null); + for (int k = 0; k < 4; k++) { + builder.build(sonSonNode, (String) null, (String) null, getNodeContext(i, j, k), null, null); + } + } + } + + NavigationTreeModel model = builder.getModel(); + + NavigationTreeNode node; + String contextPath; + String currentNode; + + contextPath = ROOT_CONTEXT; + node = model.findNode(contextPath); + assertNodeEquals(contextPath, ROOT_CONTEXT, 0, node, true); + + node = model.findNode(ROOT_CONTEXT + FAKE); + Assert.assertNull(node); + + for (int i = 0; i < 4; i++) { + currentNode = getNodeContext(i); + contextPath = ROOT_CONTEXT + separator + currentNode; + node = model.findNode(contextPath); + assertNodeEquals(contextPath, currentNode, 1, node, false); + + for (int j = 0; j < 4; j++) { + currentNode = getNodeContext(i, j); + contextPath = ROOT_CONTEXT + separator + getNodeContext(i) + separator + currentNode; + node = model.findNode(contextPath); + assertNodeEquals(contextPath, currentNode, 2, node, false); + + for (int k = 0; k < 4; k++) { + currentNode = getNodeContext(i, j, k); + contextPath = ROOT_CONTEXT + separator + getNodeContext(i) + separator + getNodeContext(i, j) + separator + currentNode; + node = model.findNode(contextPath); + assertNodeEquals(contextPath, currentNode, 3, node, false); + } + + node = model.findNode(ROOT_CONTEXT + separator + getNodeContext(i) + separator + getNodeContext(i, j) + separator + currentNode + FAKE); + Assert.assertNull(node); + } + + node = model.findNode(ROOT_CONTEXT + separator + getNodeContext(i) + separator + currentNode + FAKE); + Assert.assertNull(node); + + } + + } + + /** + * Test the {@link NavigationTreeModel#getJAXXContextValue(jaxx.runtime.JAXXContext, String)} with an entry point + * as a bean. + * <p/> + * Tree is like this + * <pre> + * $root + + * - name <-- attached to context entry : java.lang.String.class,"name" + * - name2 <-- attached to context entry : java.lang.String.class,"name2" + * - model + <-- attached to context entry : Model.class,null + * - name + * -integerValue + * - sons + + * - 0 + + * - name + * - integerValue + * - sons + * - 1 + + * - name + * - integerValue + * - sons + * - 2 + + * - name + * - integerValue + * - sons + * </pre> + * <p/> + * With this tree, we will have to results : + * <pre> + * $root.name => context.get(String.class,"name") + * $root.name2 => context.get(String.class,"name2") + * $root.model => context.get(Model.class) + * $root.model.name => context.get(Model.class).getName() + * $root.model.integerValue => context.get(Model.class).getIntegerValue() + * $root.model.sons => context.get(Model.class).getSons() + * $root.model.sons.0 => context.get(Model.class).getSons().get(0) + * </pre> + * + * @throws Exception if any pb + */ + @Test + public void testGetJAXXContextValue() throws Exception { + + NavigationTreeModelBuilder builder = new NavigationTreeModelBuilder(separator); + + NavigationTreeNode rootNode = builder.build(null, (String) null, (String) null, ROOT_CONTEXT, null, null); + + NavigationTreeNode sonNode; + NavigationTreeNode sonSonNode; + NavigationTreeNode sonSonSonNode; + + builder.build(rootNode, (String) null, JAXXContextEntryDef.newDef("name", String.class), "name", null, null); + builder.build(rootNode, (String) null, JAXXContextEntryDef.newDef("name2", String.class), "name2", null, null); + + sonNode = builder.build(rootNode, (String) null, JAXXContextEntryDef.newDef(Model.class), "model", null, null); + + builder.build(sonNode, (String) null, "../name", "name", null, null); + builder.build(sonNode, (String) null, "../integerValue", "integerValue", null, null); + + sonSonNode = builder.build(sonNode, (String) null, "../sons", "sons", null, null); + + sonSonSonNode = builder.build(sonSonNode, (String) null, "..[1]", 0 + "", null, null); + + builder.build(sonSonSonNode, (String) null, "../name", "name", null, null); + builder.build(sonSonSonNode, (String) null, "../integerValue", "integerValue", null, null); + builder.build(sonSonSonNode, (String) null, "../sons", "sons", null, null); + + sonSonSonNode = builder.build(sonSonNode, (String) null, "..[2]", 1 + "", null, null); + + builder.build(sonSonSonNode, (String) null, "../name", "name", null, null); + builder.build(sonSonSonNode, (String) null, "../integerValue", "integerValue", null, null); + builder.build(sonSonSonNode, (String) null, "../sons", "sons", null, null); + + sonSonSonNode = builder.build(sonSonNode, (String) null, (String) null, 2 + "", null, null); + //sonSonSonNode = model.new NavigationTreeNode(null, "..[3]", 2 + "", null, null); + sonSonNode.insert(sonSonSonNode, 2); + builder.build(sonSonSonNode, (String) null, "../..[3]/name", "name", null, null); + builder.build(sonSonSonNode, (String) null, "../..[3]/integerValue", "integerValue", null, null); + builder.build(sonSonSonNode, (String) null, "../..[3]/sons", "sons", null, null); + + NavigationTreeModel model = builder.getModel(); + + JAXXContext context = new DefaultJAXXContext(); + context.setContextValue("the name", "name"); + context.setContextValue("the name2", "name2"); + + + context.setContextValue( + new Model("modelName", 10, + Arrays.asList( + new Model("one", 1, Collections.<Model>emptyList()), + new Model("two", 2, Collections.<Model>emptyList()), + new Model("three", 3, Collections.<Model>emptyList()) + ) + ) + ); + + Assert.assertNull(model.getJAXXContextValue(context, "$root.name" + FAKE)); + + testBinding(model, context, "$root/name", context.getContextValue(String.class, "name")); + testBinding(model, context, "$root/name2", context.getContextValue(String.class, "name2")); + + Model bean = context.getContextValue(Model.class); + + testBinding(model, context, "$root/model", bean); + testBinding(model, context, "$root/model/name", bean.getName()); + testBinding(model, context, "$root/model/integerValue", bean.getIntegerValue()); + testBinding(model, context, "$root/model/sons", bean.getSons()); + + testBinding(model, context, "$root/model/sons/0/name", bean.getSons().get(0).getName()); + testBinding(model, context, "$root/model/sons/0/integerValue", bean.getSons().get(0).getIntegerValue()); + testBinding(model, context, "$root/model/sons/0/sons", bean.getSons().get(0).getSons()); + + + testBinding(model, context, "$root/model/sons/1/name", bean.getSons().get(1).getName()); + testBinding(model, context, "$root/model/sons/1/integerValue", bean.getSons().get(1).getIntegerValue()); + testBinding(model, context, "$root/model/sons/1/sons", bean.getSons().get(1).getSons()); + + testBinding(model, context, "$root/model/sons/2/name", bean.getSons().get(2).getName()); + testBinding(model, context, "$root/model/sons/2/integerValue", bean.getSons().get(2).getIntegerValue()); + testBinding(model, context, "$root/model/sons/2/sons", bean.getSons().get(2).getSons()); + } + + /** + * Test the {@link NavigationTreeModel#getJAXXContextValue(jaxx.runtime.JAXXContext, String)} with an entry point + * as a list. + * <p/> + * Tree is like this + * <pre> + * $root + + * - models + <-- attached to context entry : java.util.List.class,"models" + * - 0 + + * - name + * -integerValue + * - sons + + * - 0 + + * - name + * - 1 + + * - name + * - integerValue + * - sons + * - 2 + + * - name + * - integerValue + * - sons + * </pre> + * <p/> + * With this tree, we will have to results : + * <pre> + * $root.models => context.get(List.class,"models") + * $root.models.0 => context.get(List.class,"models").get(0) + * $root.models.0.name => context.get(List.class,"models").get(0).getName() + * </pre> + * + * @throws Exception if any pb + */ + @Test + public void testGetJAXXContextValueFromList() throws Exception { + + NavigationTreeModelBuilder builder = new NavigationTreeModelBuilder(separator); + + NavigationTreeNode rootNode = builder.build(null, (String) null, (String) null, ROOT_CONTEXT, null, null); + + NavigationTreeNode sonNode; + NavigationTreeNode sonSonNode; + NavigationTreeNode sonSonSonNode; + + // first son is a list of models + sonNode = builder.build(rootNode, (String) null, JAXXContextEntryDef.newListDef("models"), "models", null, null); + + // first son son is a model + sonSonNode = builder.build(sonNode, (String) null, "..[1]", "0", null, null); + + builder.build(sonSonNode, (String) null, "../name", "name", null, null); + builder.build(sonSonNode, (String) null, "../integerValue", "integerValue", null, null); + sonSonNode = builder.build(sonSonNode, (String) null, "../sons", "sons", null, null); + + sonSonSonNode = builder.build(sonSonNode, (String) null, "..[1]", "0", null, null); + builder.build(sonSonSonNode, (String) null, "../name", "name", null, null); + + // second son son is a model + sonSonNode = builder.build(sonNode, (String) null, "..[2]", "1", null, null); + + builder.build(sonSonNode, (String) null, "../name", "name", null, null); + builder.build(sonSonNode, (String) null, "../integerValue", "integerValue", null, null); + builder.build(sonSonNode, (String) null, "../sons", "sons", null, null); + + // third son son is a model + sonSonNode = builder.build(sonNode, (String) null, "..[3]", "2", null, null); + + builder.build(sonSonNode, (String) null, "../name", "name", null, null); + builder.build(sonSonNode, (String) null, "../integerValue", "integerValue", null, null); + builder.build(sonSonNode, (String) null, "../sons", "sons", null, null); + + NavigationTreeModel model = builder.getModel(); + + + List<Model> list = Arrays.asList( + new Model("entryOne", 10, + Arrays.asList( + new Model("one", 1, Collections.<Model>emptyList()), + new Model("two", 2, Collections.<Model>emptyList()), + new Model("three", 3, Collections.<Model>emptyList()) + ) + ), + new Model("entryTwo", 20, + Arrays.asList( + new Model("2one", 1, Collections.<Model>emptyList()), + new Model("2two", 2, Collections.<Model>emptyList()), + new Model("2three", 3, Collections.<Model>emptyList()) + ) + ), + new Model("entryThree", 30, + Arrays.asList( + new Model("3one", 1, Collections.<Model>emptyList()), + new Model("3two", 2, Collections.<Model>emptyList()), + new Model("3three", 3, Collections.<Model>emptyList()) + ) + ) + ); + JAXXContext context = new DefaultJAXXContext(); + context.setContextValue(list, "models"); + + Model bean; + + testBinding(model, context, "$root/models", list); + + bean = list.get(0); + testBinding(model, context, "$root/models/0", bean); + testBinding(model, context, "$root/models/0/name", bean.getName()); + testBinding(model, context, "$root/models/0/integerValue", bean.getIntegerValue()); + testBinding(model, context, "$root/models/0/sons", bean.getSons()); + testBinding(model, context, "$root/models/0/sons/0", bean.getSons().get(0)); + testBinding(model, context, "$root/models/0/sons/0/name", bean.getSons().get(0).getName()); + + bean = list.get(1); + testBinding(model, context, "$root/models/1", bean); + testBinding(model, context, "$root/models/1/name", bean.getName()); + testBinding(model, context, "$root/models/1/integerValue", bean.getIntegerValue()); + testBinding(model, context, "$root/models/1/sons", bean.getSons()); + + bean = list.get(2); + testBinding(model, context, "$root/models/2", bean); + testBinding(model, context, "$root/models/2/name", bean.getName()); + testBinding(model, context, "$root/models/2/integerValue", bean.getIntegerValue()); + testBinding(model, context, "$root/models/2/sons", bean.getSons()); + + } + + protected void testBinding(NavigationTreeModel model, JAXXContext context, String contextPath, Object expected) throws Exception { + + Object value; + value = model.getJAXXContextValue(context, contextPath); + Assert.assertNotNull(value); + Assert.assertEquals(expected, value); + } + + protected String getNodeContext(int... context) { + String result = ""; + for (int i : context) { + result += i; + } + return result; + } + + protected void assertNodeEquals(String contextPath, String nodeContext, int level, NavigationTreeNode node, boolean root) { + //System.out.println(contextPath + " : " + (node == null ? null : node.getContextPath())); + Assert.assertNotNull(node); + Assert.assertEquals(root, node.isRoot()); + Assert.assertEquals(level, node.getLevel()); + Assert.assertEquals(nodeContext, node.getNavigationPath()); + Assert.assertEquals(contextPath, node.getContextPath()); + } + + public static class Model { + + protected String name; + + protected int integerValue; + + protected List<Model> sons; + + public Model(String name, int integerValue, List<Model> sons) { + this.name = name; + this.integerValue = integerValue; + this.sons = sons; + } + + public String getName() { + return name; + } + + public int getIntegerValue() { + return integerValue; + } + + public List<Model> getSons() { + return sons; + } + + @Override + public String toString() { + return super.toString() + "<name:" + name + ",integerValue:" + integerValue + ",sons: " + sons + ">"; + } + } + +} diff --git a/trunk/jaxx-compiler/src/test/resources/log4j.properties b/trunk/jaxx-compiler/src/test/resources/log4j.properties new file mode 100644 index 0000000..8459ad0 --- /dev/null +++ b/trunk/jaxx-compiler/src/test/resources/log4j.properties @@ -0,0 +1,8 @@ +# Global logging configuration +log4j.rootLogger=ERROR, stdout +# Console output... +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) %M - %m%n + +log4j.logger.jaxx=DEBUG diff --git a/trunk/jaxx-example/LICENSE.txt b/trunk/jaxx-example/LICENSE.txt new file mode 100644 index 0000000..3f7b8b1 --- /dev/null +++ b/trunk/jaxx-example/LICENSE.txt @@ -0,0 +1,166 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/trunk/jaxx-example/README.txt b/trunk/jaxx-example/README.txt new file mode 100644 index 0000000..d2e50d3 --- /dev/null +++ b/trunk/jaxx-example/README.txt @@ -0,0 +1,2 @@ +To deploy new version of pom: mvn deploy +To install localy: mvn install diff --git a/trunk/jaxx-example/changelog.txt b/trunk/jaxx-example/changelog.txt new file mode 100644 index 0000000..bd48171 --- /dev/null +++ b/trunk/jaxx-example/changelog.txt @@ -0,0 +1,18 @@ +1.5 + * 20090404 [chemit] - use module jaxx-runtime-swing-widget + +1.3 chemit 20090409 + * 20090319 [chemit] - refactor Validator : now can deal with scopes, improve design + * 20090313 [chemit] - improve demo + +1.1 chemit 20090220 + * 20090202 [chemit] - no more scope attribute on validator + - fix I18NTableCellRenderer (must have tip inside) + * 20090122 [chemit] - refactor poms (sibling dependencies, pluginsManagment,...) + - rename i18n bundles according artifactId + +1.0 chemit 20090111 + * 20090111 [chemit] - use lutinproject 3.3 + - refactor examples : now onyl one module, with one webstart demo (cost very less time to release) +0.7 chemit 200812?? + * 20081207 [chemit] use lutinproject 3.1 \ No newline at end of file diff --git a/trunk/jaxx-example/pom.xml b/trunk/jaxx-example/pom.xml new file mode 100644 index 0000000..7bad1bf --- /dev/null +++ b/trunk/jaxx-example/pom.xml @@ -0,0 +1,294 @@ + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <!-- ************************************************************* --> + <!-- *** POM Relationships *************************************** --> + <!-- ************************************************************* --> + + <parent> + <groupId>org.nuiton</groupId> + <artifactId>jaxx</artifactId> + <version>1.7.1</version> + </parent> + + <groupId>org.nuiton.jaxx</groupId> + <artifactId>jaxx-example</artifactId> + + <dependencies> + + <!-- sibiling dependencies --> + + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>jaxx-runtime-swing</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>jaxx-runtime-swing-widget</artifactId> + <version>${project.version}</version> + </dependency> + + <!-- test dependencies --> + + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>jaxx-runtime-api</artifactId> + <version>${project.version}</version> + <scope>test</scope> + <classifier>tests</classifier> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </dependency> + + </dependencies> + + <!-- ************************************************************* --> + <!-- *** Project Information ************************************* --> + <!-- ************************************************************* --> + + <name>${project.artifactId}</name> + <description>Jaxx Examples</description> + + <!-- ************************************************************* --> + <!-- *** Build Settings ****************************************** --> + <!-- ************************************************************* --> + + <packaging>jar</packaging> + + <properties> + + <maven.jar.main.class>jaxx.demo.JAXXDemo</maven.jar.main.class> + + <jaxx.addProjectClassPath>true</jaxx.addProjectClassPath> + <jaxx.addSourcesToClassPath>true</jaxx.addSourcesToClassPath> + + <!-- jnlp --> + <keystorepath>${nuiton.keystorepath}</keystorepath> + <keystorealias>${nuiton.keystorealias}</keystorealias> + <keystorepass>${nuiton.keystorepass}</keystorepass> + + <jnlp.build.directory>${project.build.directory}/jnlp</jnlp.build.directory> + + + </properties> + + <build> + + <resources> + <resource> + <directory>src/main/java</directory> + <includes> + <include>**/*.jaxx</include> + </includes> + </resource> + <resource> + <directory>src/main/resources</directory> + <includes> + <include>**/*</include> + </includes> + </resource> + </resources> + + <pluginManagement> + <plugins> + + <plugin> + <artifactId>maven-jar-plugin</artifactId> + <configuration> + <archive> + <manifest> + <addClasspath>true</addClasspath> + <classpathPrefix>./lib/</classpathPrefix> + </manifest> + </archive> + </configuration> + </plugin> + + </plugins> + + </pluginManagement> + + <plugins> + + <plugin> + <groupId>org.nuiton.jaxx</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <version>${project.version}</version> + <executions> + <execution> + <goals> + <goal>generate</goal> + </goals> + </execution> + </executions> + </plugin> + + <plugin> + <groupId>org.nuiton.i18n</groupId> + <artifactId>maven-i18n-plugin</artifactId> + <configuration> + <entries> + <entry> + <basedir>${maven.gen.dir}/java/</basedir> + <includes> + <param>**\/**.java</param> + </includes> + </entry> + </entries> + </configuration> + <executions> + <execution> + <goals> + <goal>parserJava</goal> + <goal>gen</goal> + </goals> + </execution> + </executions> + </plugin> + + <plugin> + <artifactId>maven-dependency-plugin</artifactId> + <configuration> + <outputDirectory>${project.build.directory}/lib</outputDirectory> + </configuration> + </plugin> + + </plugins> + </build> + + <!-- ************************************************************* --> + <!-- *** Build Environment ************************************** --> + <!-- ************************************************************* --> + + <profiles> + <!-- by default jnlp is only perform on a release stage when using the maven-release-plugin --> + <profile> + <id>release-profile</id> + <activation> + <property> + <name>performRelease</name> + <value>true</value> + </property> + </activation> + <build> + <plugins> + <plugin> + + <artifactId>maven-antrun-plugin</artifactId> + <executions> + <!-- Ajout des libs signe par Sun dans un fichier jnlp separe --> + <execution> + <id>JnlpSun</id> + <phase>verify</phase> + <configuration> + <tasks> + <mkdir dir="${jnlp.build.directory}" /> + <copy file="${project.basedir}/src/main/jnlp/sun.jnlp" verbose="${maven.verbose}" todir="${jnlp.build.directory}" failonerror="false"> + <filterset> + <filter token="lib" value="javahelp-2.0.02.jar" /> + <filter token="url" value="${project.url}" /> + </filterset> + </copy> + <copy file="${project.basedir}/src/main/jnlp/jxlayer.jnlp" verbose="${maven.verbose}" todir="${jnlp.build.directory}" failonerror="false"> + <filterset> + <filter token="lib" value="jxlayer-3.0.1.jar" /> + <filter token="url" value="${project.url}" /> + </filterset> + </copy> + <copy file="${project.build.directory}/lib/javahelp-2.0.02.jar" verbose="${maven.verbose}" todir="${jnlp.build.directory}/lib" failonerror="false" /> + <copy file="${project.build.directory}/lib/jxlayer-3.0.1.jar" verbose="${maven.verbose}" todir="${jnlp.build.directory}/lib" failonerror="false" /> + </tasks> + </configuration> + <goals> + <goal>run</goal> + </goals> + </execution> + + <execution> + <id>JnlpToSite</id> + <phase>pre-site</phase> + <configuration> + <tasks> + <mkdir dir="target/site" /> + <copy todir="target/site" verbose="${maven.verbose}" failonerror="false" overwrite="false"> + <fileset dir="${jnlp.build.directory}"> + <include name="**" /> + </fileset> + </copy> + </tasks> + </configuration> + <goals> + <goal>run</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.nuiton.thirdparty</groupId> + <artifactId>webstart-maven-plugin</artifactId> + <version>1.0-alpha-2-cl_20090204</version> + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>jnlp-inline</goal> + </goals> + </execution> + </executions> + <configuration> + <force>false</force> + <dependencies> + <excludes> + <exclude>javax.help:javahelp</exclude> + <exclude>org.swinglabs:jxlayer</exclude> + </excludes> + </dependencies> + <libPath>lib</libPath> + <extensions> + <sun>sun.jnlp</sun> + <jxlayer>jxlayer.jnlp</jxlayer> + </extensions> + <jnlp> + <outputFile>launch-demo.jnlp</outputFile> + <mainClass>${maven.jar.main.class}</mainClass> + <allPermissions>true</allPermissions> + <offlineAllowed>true</offlineAllowed> + </jnlp> + + <sign> + <keystore>${keystorepath}</keystore> + <keypass /> + <storepass>${keystorepass}</storepass> + <storetype /> + <alias>${keystorealias}</alias> + <validity /> + <dnameCn /> + <dnameOu /> + <dnameO /> + <dnameL /> + <dnameSt /> + <dnameC /> + <verify>true</verify> + <keystoreConfig> + <delete>false</delete> + <gen>false</gen> + </keystoreConfig> + </sign> + + <pack200>false</pack200> + <gzip>true</gzip> + <verbose>false</verbose> + </configuration> + </plugin> + </plugins> + </build> + </profile> + </profiles> + +</project> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/BaseBeanDataBinding.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/BaseBeanDataBinding.jaxx new file mode 100644 index 0000000..9ff1ab9 --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/BaseBeanDataBinding.jaxx @@ -0,0 +1,21 @@ +<DemoPanel> + + <!-- a full java bean property of the class --> + <Boolean id='editing' javaBean='false'/> + + <!-- not full java bean property (must add script...) --> + <Boolean id='editing2' constructorParams='false'/> + + <String id='contentMessage' javaBean='"message..."'/> + + <script> + public Boolean isEditing2() { return editing2; } + + public void setEditing2(Boolean newValue) { + Boolean oldValue = this.editing2; + this.editing2 = newValue; + firePropertyChange("editing2", oldValue, newValue) ; + } + </script> + +</DemoPanel> diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/BeanDataBindingDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/BeanDataBindingDemo.jaxx new file mode 100644 index 0000000..031d308 --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/BeanDataBindingDemo.jaxx @@ -0,0 +1,47 @@ +<BaseBeanDataBinding> + + <Boolean id='editing3' javaBean='true'/> + + <Table id='demoPanel'> + <row> + <cell columns='2'> + <JLabel text='{getContentMessage()}'/> + </cell> + </row> + <row> + <cell> + <JPanel> + <JButton visible='{!isEditing()}' text='edit' onActionPerformed='setEditing(true);'/> + <JButton visible='{isEditing()}' text='close' onActionPerformed='setEditing(false);'/> + </JPanel> + </cell> + <cell weightx='1' fill='both'> + <JTextField enabled='{isEditing()}' text='to edit'/> + </cell> + </row> + <row> + <cell> + <JPanel> + <JButton visible='{!isEditing2()}' text='edit2' onActionPerformed='setEditing2(true);'/> + <JButton visible='{isEditing2()}' text='close2' onActionPerformed='setEditing2(false);'/> + </JPanel> + </cell> + <cell weightx='1' fill='both'> + <JTextField enabled='{isEditing2()}' text="to edit 2"/> + </cell> + </row> + <row> + <cell> + <JPanel> + <JButton visible='{!isEditing3()}' text='edit3' onActionPerformed='setEditing3(true);'/> + <JButton visible='{isEditing3()}' text='close3' onActionPerformed='setEditing3(false);'/> + </JPanel> + </cell> + <cell weightx='1' fill='both'> + <JTextField id='edit3' enabled='{isEditing3()}' text="{getContentMessage()}" + onKeyReleased='setContentMessage(edit3.getText())'/> + </cell> + </row> + </Table> + +</BaseBeanDataBinding> diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/BoxedDecoratorDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/BoxedDecoratorDemo.jaxx new file mode 100644 index 0000000..763199f --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/BoxedDecoratorDemo.jaxx @@ -0,0 +1,91 @@ + +<DemoPanel> + <jaxx.runtime.swing.BlockingLayerUI id='layerUI' + blockIcon='{SwingUtil.createImageIcon("action-block.png")}' + acceptIcon='{SwingUtil.createImageIcon("action-accept.png")}' + useIcon='true' + blockingColor='{new Color(50,50,50)}' + acceptAction='{new AbstractAction() { private static final long serialVersionUID = 1L; + @Override + public void actionPerformed(ActionEvent e) { + accept(e, "from icon of layer"); + } + }}' /> + <jaxx.runtime.swing.BlockingLayerUI2 id='layerUI2' + blockIcon='{SwingUtil.createImageIcon("action-block.png")}' + acceptIcon='{SwingUtil.createImageIcon("action-accept.png")}' + acceptAction='{new AbstractAction() { private static final long serialVersionUID = 1L; + @Override + public void actionPerformed(ActionEvent e) { + accept(e, "from icon of layer"); + } + }}' /> + <script><![CDATA[ +import jaxx.runtime.SwingUtil; + +void $afterCompleteSetup() { + for (JComponent boxed : SwingUtil.getLayeredComponents(this)) { + if (boxed == d) { + SwingUtil.getLayer(boxed).setUI(layerUI2); + continue; + } + + jaxx.runtime.swing.BlockingLayerUI ui = layerUI.clone(); + if ( boxed == c) { + ui.setBlock(true); + } + SwingUtil.getLayer(boxed).setUI(ui); + } +} + +public void setLayer(boolean active) { + for (JComponent boxed : SwingUtil.getLayeredComponents(this)) { + if (boxed == d) { + continue; + } + jaxx.runtime.swing.BlockingLayerUI ui = (jaxx.runtime.swing.BlockingLayerUI)SwingUtil.getLayer(boxed).getUI(); + if ( boxed == c) { + ui.setBlock(active); + } + ui.setUseIcon(active); + } +} + +protected void accept(ActionEvent e, String suffix) { + JButton source = (JButton) e.getSource(); + String clickedMessage = (String) source.getClientProperty("clickedText"); + String msg = "'" + source.getText() + "' clicked - " + suffix + " : " + clickedMessage; + ((DefaultListModel)messages.getModel()).addElement(msg); +}]]> + </script> + <Table id='demoPanel' fill='both' weightx='1'> + <row> + <cell> + <JCheckBox id='toggle' selected='true' + text='{toggle.isSelected() ? "Active layer" : "No layer"}' + onActionPerformed='setLayer(toggle.isSelected());'/> + </cell> + </row> + <row> + <cell weighty='0.5'> + <JPanel layout='{new GridLayout(1,3,3,3)}'> + <JButton text='button A' decorator='boxed' _clickedText='"button A was clicked"' + onActionPerformed='accept(event, "from button (no layer)")'/> + <JButton text='button B' decorator='boxed' _clickedText='"button B was clicked"' + onActionPerformed='accept(event, "from button (no layer)")'/> + <JButton id='c' text='button C (full block)' decorator='boxed' _clickedText='"button C was clicked"' + onActionPerformed='accept(event, "from button (no layer)");'/> + <JButton id='d' text='button D (full block 2)' decorator='boxed' _clickedText='"button D was clicked"' + onActionPerformed='accept(event, "from button (no layer)");'/> + </JPanel> + </cell> + </row> + <row> + <cell weighty='0.5'> + <JScrollPane> + <JList id='messages' model='{new DefaultListModel()}'/> + </JScrollPane> + </cell> + </row> + </Table> +</DemoPanel> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/Calculator.css b/trunk/jaxx-example/src/main/java/jaxx/demo/Calculator.css new file mode 100644 index 0000000..9abfe7c --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/Calculator.css @@ -0,0 +1,68 @@ +#table { + border: { BorderFactory . createEmptyBorder( 4, 4, 4, 4 ) +} + +; +font-face: + +"Trebuchet MS" +; +} + +#display { + background: #BCE5AD; + opaque: true; + horizontalAlignment: right; + border: { BorderFactory . createBevelBorder( BevelBorder . LOWERED ) +} + +; +font-size: + +22 +; +font-weight: bold + +; +} + +#display:{ + object . getText( ) . startsWith( "-" ) +} + +{ +foreground: red + +; +} + +JButton { + font-size: 18; + width: 80; + height: 35; +} + +JButton.digit { + foreground: blue; +} + +JButton#dot { + font-size: 20; +} + +JButton.operator { + font-size: 16; + foreground: #009900; +} + +JButton.clear { + foreground: red; +} + +JButton:mouseover { + font-weight: bold; +} + +JButton.operator:mouseover { + font-weight: normal; +} \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/CalculatorDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/CalculatorDemo.jaxx new file mode 100644 index 0000000..ebc8134 --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/CalculatorDemo.jaxx @@ -0,0 +1,89 @@ +<DemoPanel> + <style source='Calculator.css'/> + <script><![CDATA[ + plus.setText("+"); + sign.setText("+/-"); +]]></script> + <!-- use fully-qualified name just in case this is compiled into a different package --> + <CalculatorEngine id='engine'/> + + <Table id='demoPanel' fill='both'> + <row> + <cell columns='4'> + <JLabel id='display' text='{engine.getDisplayText()}'/> + </cell> + </row> + + <row> + <cell columns='2'> + <JButton id='c' text='C' onActionPerformed='engine.clear()' styleClass='clear'/> + </cell> + <cell> + <JButton id='ce' text='CE' onActionPerformed='engine.clearEntry()' styleClass='clear'/> + </cell> + <cell> + <JButton id='equals' text='=' onActionPerformed='engine.equal()' styleClass='operator'/> + </cell> + </row> + + <row> + <cell> + <JButton id='d7' text='7' onActionPerformed='engine.digit(7)' styleClass='digit'/> + </cell> + <cell> + <JButton id='d8' text='8' onActionPerformed='engine.digit(8)' styleClass='digit'/> + </cell> + <cell> + <JButton id='d9' text='9' onActionPerformed='engine.digit(9)' styleClass='digit'/> + </cell> + <cell> + <JButton id='plus' onActionPerformed='engine.add()' styleClass='operator'/> + </cell> + </row> + + <row> + <cell> + <JButton id='d4' text='4' onActionPerformed='engine.digit(4)' styleClass='digit'/> + </cell> + <cell> + <JButton id='d5' text='5' onActionPerformed='engine.digit(5)' styleClass='digit'/> + </cell> + <cell> + <JButton id='d6' text='6' onActionPerformed='engine.digit(6)' styleClass='digit'/> + </cell> + <cell> + <JButton id='subtract' text='-' onActionPerformed='engine.subtract()' styleClass='operator'/> + </cell> + </row> + + <row> + <cell> + <JButton id='d1' text='1' onActionPerformed='engine.digit(1)' styleClass='digit'/> + </cell> + <cell> + <JButton id='d2' text='2' onActionPerformed='engine.digit(2)' styleClass='digit'/> + </cell> + <cell> + <JButton id='d3' text='3' onActionPerformed='engine.digit(3)' styleClass='digit'/> + </cell> + <cell> + <JButton id='multiply' text='x' onActionPerformed='engine.multiply()' styleClass='operator'/> + </cell> + </row> + + <row> + <cell> + <JButton id='d0' text='0' onActionPerformed='engine.digit(0)' styleClass='digit'/> + </cell> + <cell> + <JButton id='sign' onActionPerformed='engine.toggleSign()' styleClass='operator'/> + </cell> + <cell> + <JButton id='dot' text='.' onActionPerformed='engine.dot()' styleClass='digit'/> + </cell> + <cell> + <JButton id='divide' text='÷' onActionPerformed='engine.divide()' styleClass='operator'/> + </cell> + </row> + </Table> +</DemoPanel> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/CalculatorEngine.java b/trunk/jaxx-example/src/main/java/jaxx/demo/CalculatorEngine.java new file mode 100644 index 0000000..7476e76 --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/CalculatorEngine.java @@ -0,0 +1,177 @@ +package jaxx.demo; + +import java.beans.*; +import java.math.*; + +public class CalculatorEngine { + public static final String DISPLAY_TEXT_PROPERTY = "displayText"; + + public static final int ADD = 0; + public static final int SUBTRACT = 1; + public static final int MULTIPLY = 2; + public static final int DIVIDE = 3; + public static final int RESULT = 4; + + private int operation = -1; + private boolean clear = true; // true to clear on next key + private String displayText = "0"; + private BigDecimal value; + private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); + + + public String getDisplayText() { + return displayText; + } + + + public void setDisplayText(String displayText) { + String oldDisplayText = this.displayText; + this.displayText = displayText; + firePropertyChange(DISPLAY_TEXT_PROPERTY, oldDisplayText, displayText); + } + + + public void clear() { + clearEntry(); + value = new BigDecimal(0); + operation = -1; + } + + + public void clearEntry() { + setDisplayText("0"); + clear = true; + } + + + private void checkClear() { + if (clear) { + setDisplayText(""); + clear = false; + } + } + + + public void digit(int digit) { + checkClear(); + setDisplayText(getDisplayText() + String.valueOf(digit)); + } + + + public void dot() { + checkClear(); + if (getDisplayText().indexOf('.') == -1) { + if (getDisplayText().length() == 0) { + setDisplayText("0."); + } else { + setDisplayText(getDisplayText() + '.'); + } + } + } + + + public void toggleSign() { + String text = getDisplayText(); + if (text.startsWith("-")) { + text = text.substring(1); + } else if (!text.equals("0")) { + text = '-' + text; + } + setDisplayText(text); + } + + + public void equal() { + BigDecimal displayValue = new BigDecimal(getDisplayText()); + BigDecimal newValue = displayValue; + switch (operation) { + case ADD: + newValue = value.add(displayValue); + break; + case SUBTRACT: + newValue = value.subtract(displayValue); + break; + case MULTIPLY: + newValue = value.multiply(displayValue); + break; + case DIVIDE: + newValue = value.divide(displayValue, 8, BigDecimal.ROUND_HALF_UP); + break; + } + value = newValue; + setDisplayText(toString(newValue)); + clear = true; + operation = -1; + } + + + public static String toString(BigDecimal decimal) { + // can't use stripTrailingZeros, as it wasn't introduced until 1.5 + String result = decimal.toString(); + if (result.indexOf(".") != -1) { + while (result.endsWith("0")) { + result = result.substring(0, result.length() - 1); + } + if (result.endsWith(".")) { + result = result.substring(0, result.length() - 1); + } + } + return result; + } + + + public void operation(int operation) { + if (this.operation != -1) { + equal(); + } else { + value = new BigDecimal(getDisplayText()); + clear = true; + } + this.operation = operation; + } + + + public void add() { + operation(ADD); + } + + + public void subtract() { + operation(SUBTRACT); + } + + + public void multiply() { + operation(MULTIPLY); + } + + + public void divide() { + operation(DIVIDE); + } + + + public void addPropertyChangeListener(PropertyChangeListener listener) { + propertyChangeSupport.addPropertyChangeListener(listener); + } + + + public void addPropertyChangeListener(String property, PropertyChangeListener listener) { + propertyChangeSupport.addPropertyChangeListener(property, listener); + } + + + public void removePropertyChangeListener(PropertyChangeListener listener) { + propertyChangeSupport.removePropertyChangeListener(listener); + } + + + public void removePropertyChangeListener(String property, PropertyChangeListener listener) { + propertyChangeSupport.removePropertyChangeListener(property, listener); + } + + + protected void firePropertyChange(String property, Object oldValue, Object newValue) { + propertyChangeSupport.firePropertyChange(property, oldValue, newValue); + } +} \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/ComboEditorDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/ComboEditorDemo.jaxx new file mode 100644 index 0000000..d1cc7de --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/ComboEditorDemo.jaxx @@ -0,0 +1,35 @@ + +<DemoPanel> + <Table id='demoPanel' fill='both'> + <row> + <cell> + <JLabel text='Locale editor:' labelFor='{localeEditor}'/> + </cell> + + <cell> + <LocaleEditor id='localeEditor'/> + </cell> + </row> + <row> + <cell> + <JLabel text='EnumEditor (language) :' labelFor='{languageEditor}'/> + </cell> + <cell> + <EnumEditor id='languageEditor' constructorParams='org.nuiton.i18n.LanguageEnum.class'/> + </cell> + </row> + <row> + <cell> + <JLabel text='EnumEditor (country) :' labelFor='{countryEditor}'/> + </cell> + <cell> + <EnumEditor id='countryEditor' constructorParams='org.nuiton.i18n.CountryEnum.class'/> + </cell> + </row> + <row> + <cell columns="2"> + <JTextArea text='{"locale : "+ localeEditor.getSelectedItem() + "\nlanguage : "+ languageEditor.getSelectedItem() + "\ncountry : " + countryEditor.getSelectedItem()}'/> + </cell> + </row> + </Table> +</DemoPanel> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/CounterDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/CounterDemo.jaxx new file mode 100644 index 0000000..9f706ff --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/CounterDemo.jaxx @@ -0,0 +1,12 @@ +<DemoPanel> + <script>int count;</script> + <JPanel id='demoPanel'> + <JTextField text='{count}' constraints='BorderLayout.NORTH'/> + <HBox constraints='BorderLayout.SOUTH'> + <JButton text='Dec (-)' onActionPerformed='count--'/> + <JButton text='Reset' onActionPerformed='count = 0'/> + <JButton text='Inc (+)' onActionPerformed='count++'/> + </HBox> + </JPanel> + +</DemoPanel> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/DemoPanel.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/DemoPanel.jaxx new file mode 100644 index 0000000..1d6fac5 --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/DemoPanel.jaxx @@ -0,0 +1,45 @@ +<JTabbedPane id='top'> + <script><![CDATA[ + import java.io.*; + + public String getLabel() { + String name = getClass().getName(); + name = name.substring(name.lastIndexOf(".") + 1); + if (name.endsWith("Demo")) + name = name.substring(0, name.length() - "Demo".length()); + return name; + } + + + public String getDemoTabTitle() { + return getLabel() + " Demo"; + } + + + public String loadSource() { + try { + String className = getClass().getName(); + Reader in = new InputStreamReader(getClass().getResourceAsStream(className.substring(className.lastIndexOf(".") + 1) + ".jaxx")); + StringWriter out = new StringWriter(); + char[] buffer = new char[2048]; + int c; + while ((c = in.read(buffer)) > 0) + out.write(buffer, 0, c); + return out.toString(); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + ]]></script> + + <tab title='{getDemoTabTitle()}'> + <JPanel id='demoPanel'/> + </tab> + + <tab title='Source'> + <JScrollPane height='100'> + <JTextArea text='{loadSource()}' editable='false'/> + </JScrollPane> + </tab> +</JTabbedPane> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/EmptyDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/EmptyDemo.jaxx new file mode 100644 index 0000000..0c38829 --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/EmptyDemo.jaxx @@ -0,0 +1,5 @@ +<DemoPanel> +<JPanel id='demoPanel'> + <JLabel text='emptyNode'/> +</JPanel> +</DemoPanel> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/I18nEditorDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/I18nEditorDemo.jaxx new file mode 100644 index 0000000..2efd86a --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/I18nEditorDemo.jaxx @@ -0,0 +1,46 @@ + +<DemoPanel> + <script><![CDATA[ +//localeEditor.loadI18nBundles(); +]]> + </script> + <Table id='demoPanel' fill='both'> + <row> + <cell> + <JLabel text='Empty I18n editor:' labelFor='{localeEmptyEditor}'/> + </cell> + <cell> + <jaxx.runtime.swing.editor.I18nEditor id='localeEmptyEditor' /> + </cell> + </row> + <row> + <cell> + <JLabel text='I18n editor:' labelFor='{localeEditor}'/> + </cell> + <cell> + <jaxx.runtime.swing.editor.I18nEditor id='localeEditor' + locales='{java.util.Arrays.asList(org.nuiton.i18n.I18n.getLoader().getLocales())}'/> + </cell> + </row> + <row> + <cell> + <JLabel text='I18n editor with no text :' labelFor='{localeWithNoTextEditor}'/> + </cell> + <cell> + <jaxx.runtime.swing.editor.I18nEditor id='localeWithNoTextEditor' + locales='{java.util.Arrays.asList(org.nuiton.i18n.I18n.getLoader().getLocales())}' + showText='false'/> + </cell> + </row> + <row> + <cell> + <JLabel text='I18n editor with no icon :' labelFor='{localeWithNoIconEditor}'/> + </cell> + <cell> + <jaxx.runtime.swing.editor.I18nEditor id='localeWithNoIconEditor' + locales='{java.util.Arrays.asList(org.nuiton.i18n.I18n.getLoader().getLocales())}' + showIcon='false'/> + </cell> + </row> + </Table> +</DemoPanel> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/Identity.java b/trunk/jaxx-example/src/main/java/jaxx/demo/Identity.java new file mode 100644 index 0000000..2166c2c --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/Identity.java @@ -0,0 +1,103 @@ +package jaxx.demo; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.File; + +public class Identity { + + protected String firstName = ""; + + protected String lastName = ""; + + protected String email = "dummy@codelutin.com"; + + protected int age = 51; + + protected File config = new File("/tmp"); + + protected File dir = new File("/tmp"); + + PropertyChangeSupport p; + + public Identity() { + p = new PropertyChangeSupport(this); + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + p.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + p.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + p.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + p.removePropertyChangeListener(propertyName, listener); + } + + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public String getEmail() { + return email; + } + + public int getAge() { + return age; + } + + public File getConfig() { + return config; + } + + public File getDir() { + return dir; + } + + public void setFirstName(String firstName) { + String oldFirstName = this.firstName; + this.firstName = firstName; + p.firePropertyChange("firstName", oldFirstName, firstName); + } + + public void setLastName(String lastName) { + String oldLastName = this.lastName; + this.lastName = lastName; + p.firePropertyChange("lastName", oldLastName, lastName); + } + + public void setEmail(String email) { + String oldEmail = this.email; + this.email = email; + p.firePropertyChange("email", oldEmail, email); + } + + public void setAge(int age) { + int oldAge = this.age; + this.age = age; + p.firePropertyChange("age", oldAge, age); + } + + public void setConfig(File config) { + File oldConfig = this.config; + this.config = config; + p.firePropertyChange("config", oldConfig, config); + } + + public void setDir(File dir) { + File oldDir = this.dir; + this.dir = dir; + p.firePropertyChange("dir", oldDir, dir); + } +} \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/JAXXDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/JAXXDemo.jaxx new file mode 100644 index 0000000..dc4b903 --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/JAXXDemo.jaxx @@ -0,0 +1,132 @@ +<Application title="JAXX Demo" width='1024' height='800' defaultCloseOperation='exit_on_close'> + <script><![CDATA[ + +static { +org.nuiton.i18n.I18n.init("fr", "FR"); +} + +void $afterCompleteSetup() { + + + try { jaxx.runtime.SwingUtil.initNimbusLoookAndFeel(); } catch (Exception e) { log.error(e.getMessage(), e); } + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + int i=0; + while( i < list.getRowCount()) { + list.expandRow(i++); + } + } + }); +} + +]]></script> + <JSplitPane> + <!--JSplitPane dividerLocation='200'--> + <JScrollPane> + <JTree id='list' showsRootHandles='true' + onValueChanged='cardLayout.show(preview, list.getSelectionValue() instanceof DemoPanel ? ((DemoPanel) list.getSelectionValue()).getLabel() : emptyDemo.getLabel())' + cellRenderer='{new javax.swing.tree.DefaultTreeCellRenderer() { + public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { + if (value instanceof DemoPanel) + value = ((DemoPanel) value).getLabel(); + return super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); + } + } + }'> + <item value="Components"> + <item value='Buttons'> + <item value='{buttonDemo}'/> + <item value='{checkBoxDemo}'/> + <item value='{radioButtonDemo}'/> + <item value='{toggleButtonDemo}'/> + </item> + + <item value='Form elements'> + <item value='Text'> + <item value='{passwordFieldDemo}'/> + <item value='{textFieldDemo}'/> + <item value='{textAreaDemo}'/> + </item> + + <item value='{comboBoxDemo}'/> + <item value='{listDemo}'/> + <item value='{sliderDemo}'/> + <item value='{spinnerDemo}'/> + </item> + + <item value='Layout components'> + <item value='{splitPaneDemo}'/> + </item> + + <item value='Menus'> + <item value='{menuItemDemo}'/> + <item value='{checkBoxMenuItemDemo}'/> + <item value='{radioButtonMenuItemDemo}'/> + </item> + + <item value='Windows'> + <item value='{dialogDemo}'/> + </item> + + <item value='{progressBarDemo}'/> + + </item> + + <item value='{labelStyleDemo}'/> + + <item value='{counterDemo}'/> + <item value='{calculatorDemo}'/> + + <item value='New features'> + <item value='Validation'> + <item value='{validationDemo1}'/> + <item value='{validationDemo2}'/> + </item> + <item value='{dataBindingDemo}'/> + <item value='{boxedDecoratorDemo}'/> + <item value='{statusMessagePanelDemo}'/> + <item value='Editors'> + <item value='{numberEditorDemo}'/> + <item value='{comboEditorDemo}'/> + <item value='{i18nEditorDemo}'/> + </item> + </item> + </JTree> + </JScrollPane> + + <java.awt.CardLayout id='cardLayout'/> + + <JPanel id='preview' layout='{cardLayout}'> + <EmptyDemo id='emptyDemo' constraints='emptyDemo.getLabel()'/> + <JButtonDemo id='buttonDemo' constraints='buttonDemo.getLabel()'/> + <JCheckBoxDemo id='checkBoxDemo' constraints='checkBoxDemo.getLabel()'/> + <JCheckBoxMenuItemDemo id='checkBoxMenuItemDemo' constraints='checkBoxMenuItemDemo.getLabel()'/> + <JComboBoxDemo id='comboBoxDemo' constraints='comboBoxDemo.getLabel()'/> + <JDialogDemo id='dialogDemo' constraints='dialogDemo.getLabel()'/> + <JListDemo id='listDemo' constraints='listDemo.getLabel()'/> + <JMenuItemDemo id='menuItemDemo' constraints='menuItemDemo.getLabel()'/> + <JPasswordFieldDemo id='passwordFieldDemo' constraints='passwordFieldDemo.getLabel()'/> + <JProgressBarDemo id='progressBarDemo' constraints='progressBarDemo.getLabel()'/> + <JSliderDemo id='sliderDemo' constraints='sliderDemo.getLabel()'/> + <JSpinnerDemo id='spinnerDemo' constraints='spinnerDemo.getLabel()'/> + <JSplitPaneDemo id='splitPaneDemo' constraints='splitPaneDemo.getLabel()'/> + <JRadioButtonDemo id='radioButtonDemo' constraints='radioButtonDemo.getLabel()'/> + <JRadioButtonMenuItemDemo id='radioButtonMenuItemDemo' constraints='radioButtonMenuItemDemo.getLabel()'/> + <JToggleButtonDemo id='toggleButtonDemo' constraints='toggleButtonDemo.getLabel()'/> + <JTextFieldDemo id='textFieldDemo' constraints='textFieldDemo.getLabel()'/> + <JTextAreaDemo id='textAreaDemo' constraints='textAreaDemo.getLabel()'/> + <ValidationListDemo id='validationDemo1' constraints='validationDemo1.getLabel()'/> + <ValidationTableDemo id='validationDemo2' constraints='validationDemo2.getLabel()'/> + <BeanDataBindingDemo id='dataBindingDemo' constraints='dataBindingDemo.getLabel()'/> + <LabelStyleDemo id='labelStyleDemo' constraints='labelStyleDemo.getLabel()'/> + <CounterDemo id='counterDemo' constraints='counterDemo.getLabel()'/> + <CalculatorDemo id='calculatorDemo' constraints='calculatorDemo.getLabel()'/> + <BoxedDecoratorDemo id='boxedDecoratorDemo' constraints='boxedDecoratorDemo.getLabel()'/> + <NumberEditorDemo id='numberEditorDemo' constraints='numberEditorDemo.getLabel()'/> + <ComboEditorDemo id='comboEditorDemo' constraints='comboEditorDemo.getLabel()'/> + <I18nEditorDemo id='i18nEditorDemo' constraints='i18nEditorDemo.getLabel()'/> + <StatusMessagePanelDemo id='statusMessagePanelDemo' constraints='statusMessagePanelDemo.getLabel()'/> + </JPanel> + </JSplitPane> +</Application> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/JButtonDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/JButtonDemo.jaxx new file mode 100644 index 0000000..db42c63 --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/JButtonDemo.jaxx @@ -0,0 +1,29 @@ +<DemoPanel> + <style> + JButton.fancy { + foreground: blue; + font-face: Arial; + font-size: 18; + } + + JButton.fancy:mouseover { + foreground: red; + font-style: italic; + } + </style> + + <script> + public void buttonClicked(JButton button) { + JOptionPane.showMessageDialog(this, button.getText() + " clicked!", "onActionPerformed", + JOptionPane.INFORMATION_MESSAGE); + } + </script> + + <javax.swing.ImageIcon id='pencil' constructorParams='getClass().getResource("images/pencil_black.gif")'/> + + <VBox id='demoPanel' horizontalAlignment='center' verticalAlignment='middle'> + <JButton text='Simple Button' onActionPerformed='buttonClicked((JButton) event.getSource())'/> + <JButton text='Fancy Button' styleClass='fancy' icon='{pencil}' + onActionPerformed='buttonClicked((JButton) event.getSource())'/> + </VBox> +</DemoPanel> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/JCheckBoxDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/JCheckBoxDemo.jaxx new file mode 100644 index 0000000..19fb5ec --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/JCheckBoxDemo.jaxx @@ -0,0 +1,38 @@ +<DemoPanel> + <script><![CDATA[ + public String getText(boolean bold, boolean italic, boolean underline) { + String text ="Sample Text"; + if (bold) + text = "<b>" + text + "</b>"; + if (italic) + text = "<i>" + text + "</i>"; + if (underline) + text = "<u>" + text + "</u>"; + return "<html>" + text; + } + ]]></script> + + <VBox id='demoPanel' horizontalAlignment='center' verticalAlignment='middle'> + <Table anchor='west'> + <row> + <cell> + <JCheckBox id='bold' text='Bold' mnemonic='B'/> + </cell> + <cell rows='3'> + <JLabel font='{new Font("Arial", 0, 18)}' + text='{getText(bold.isSelected(), italic.isSelected(), underline.isSelected())}'/> + </cell> + </row> + <row> + <cell> + <JCheckBox id='italic' text='Italic' mnemonic='I'/> + </cell> + </row> + <row> + <cell> + <JCheckBox id='underline' text='Underline' mnemonic='U'/> + </cell> + </row> + </Table> + </VBox> +</DemoPanel> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/JCheckBoxMenuItemDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/JCheckBoxMenuItemDemo.jaxx new file mode 100644 index 0000000..8769306 --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/JCheckBoxMenuItemDemo.jaxx @@ -0,0 +1,59 @@ +<JMenuItemDemo> + <style> + .form { + enabled: { enabledCheckBox.isSelected() }; + editable: { editableCheckBox.isSelected() }; + } + </style> + + <JMenuBar id='menuBar'> + <JMenu text='View'> + <JCheckBoxMenuItem id='enabledCheckBox' text='Enabled' selected='true'/> + <JCheckBoxMenuItem id='editableCheckBox' text='Editable' selected='true'/> + </JMenu> + </JMenuBar> + + <Table id='framePanel' anchor='northwest'> + <row> + <cell> + <JLabel text='First Name:' displayedMnemonic='F' labelFor='{firstName}'/> + </cell> + + <cell weightx='1' fill='horizontal'> + <JTextField id='firstName' styleClass="form"/> + </cell> + </row> + + <row> + <cell> + <JLabel text='Last Name:' displayedMnemonic='L' labelFor='{lastName}'/> + </cell> + + <cell fill='horizontal'> + <JTextField id='lastName' styleClass="form"/> + </cell> + </row> + + <row> + <cell> + <JLabel text='Email Address:' displayedMnemonic='E' labelFor='{email}'/> + </cell> + + <cell fill='horizontal'> + <JTextField id='email' styleClass="form"/> + </cell> + </row> + + <row> + <cell> + <JLabel text='Comments:' displayedMnemonic='C' labelFor='{comments}'/> + </cell> + + <cell weightx='1' weighty='1' fill='both'> + <JScrollPane width='150' height='75'> + <JTextArea id='comments' styleClass="form"/> + </JScrollPane> + </cell> + </row> + </Table> +</JMenuItemDemo> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/JComboBoxDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/JComboBoxDemo.jaxx new file mode 100644 index 0000000..1ce9790 --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/JComboBoxDemo.jaxx @@ -0,0 +1,22 @@ + +<DemoPanel> + <Table id='demoPanel'> + <row> + <cell> + <JLabel text='Button label:'/> + </cell> + + <cell> + <JComboBox id='comboBox' editable='true'> + <item value='OK' selected='true'/> + <item value='Cancel'/> + <item value='Help'/> + </JComboBox> + </cell> + + <cell> + <JButton text='{comboBox.getSelectedItem()}'/> + </cell> + </row> + </Table> +</DemoPanel> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/JDialogDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/JDialogDemo.jaxx new file mode 100644 index 0000000..565d5b2 --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/JDialogDemo.jaxx @@ -0,0 +1,79 @@ +<DemoPanel> + <script> + String username; + String password; + + private class OKAction extends javax.swing.AbstractAction { + public OKAction() { + putValue(NAME, "OK"); + } + + + public void actionPerformed(ActionEvent e) { + username = usernameField.getText(); + password = new String(passwordField.getPassword()); + dialog.dispose(); + } + } + + + private class CancelAction extends javax.swing.AbstractAction { + public CancelAction() { + putValue(NAME, "Cancel"); + } + + + public void actionPerformed(ActionEvent e) { + dialog.dispose(); + } + } + { + JRootPane rootPane = dialog.getRootPane(); + rootPane.setDefaultButton(ok); + rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("ESCAPE"), "cancel"); + rootPane.getActionMap().put("cancel", new CancelAction()); + } + </script> + + <JDialog title='Sign on' id='dialog' modal='true' onWindowOpened='dialog.setLocationRelativeTo(demoPanel); + passwordField.setText("");'> + <Table> + <row> + <cell> + <JLabel text='Username:' displayedMnemonic='U' labelFor='{usernameField}'/> + </cell> + + <cell> + <JTextField id='usernameField'/> + </cell> + </row> + + <row> + <cell> + <JLabel text='Password:' displayedMnemonic='P' labelFor='{passwordField}'/> + </cell> + + <cell> + <JPasswordField id='passwordField'/> + </cell> + </row> + + <row> + <cell columns='2'> + <JPanel layout='{new GridLayout(1, 0, 6, 6)}'> + <JButton id='ok' text='OK' action='{new OKAction()}'/> + <JButton text='Cancel' action='{new CancelAction()}'/> + </JPanel> + </cell> + </row> + </Table> + </JDialog> + + <VBox id='demoPanel' horizontalAlignment='center' verticalAlignment='middle'> + <JButton text='Show password dialog' onActionPerformed='dialog.setVisible(true)'/> + <VBox> + <JLabel text='{username != null ? "Username: " + username : ""}'/> + <JLabel text='{password != null ? "Password: " + password : ""}'/> + </VBox> + </VBox> +</DemoPanel> diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/JListDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/JListDemo.jaxx new file mode 100644 index 0000000..6ec324f --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/JListDemo.jaxx @@ -0,0 +1,59 @@ +<DemoPanel> + <Table id='demoPanel'> + <row> + <cell> + <JLabel text='Supported Swing components:'/> + </cell> + </row> + + <row> + <cell> + <JScrollPane> + <JList> + <item value='JApplet'/> + <item value='JButton'/> + <item value='JCheckBox'/> + <item value='JCheckBoxMenuItem'/> + <item value='JColorChooser'/> + <item value='JComboBox'/> + <item value='JDesktopPane'/> + <item value='JDialog'/> + <item value='JEditorPane'/> + <item value='JFileChooser'/> + <item value='JFormattedTextField'/> + <item value='JFrame'/> + <item value='JInternalFrame'/> + <item value='JLabel'/> + <item value='JLayeredPane'/> + <item value='JList'/> + <item value='JMenu'/> + <item value='JMenuBar'/> + <item value='JMenuItem'/> + <item value='JOptionPane'/> + <item value='JPanel'/> + <item value='JPasswordField'/> + <item value='JPopupMenu'/> + <item value='JProgressBar'/> + <item value='JRadioButton'/> + <item value='JRadioButtonMenuItem'/> + <item value='JScrollBar'/> + <item value='JScrollPane'/> + <item value='JSeparator'/> + <item value='JSlider'/> + <item value='JSpinner'/> + <item value='JSplitPane'/> + <item value='JTabbedPane'/> + <item value='JTable'/> + <item value='JTextArea'/> + <item value='JTextField'/> + <item value='JTextPane'/> + <item value='JToggleButton'/> + <item value='JToolBar'/> + <item value='JTree'/> + <item value='JWindow'/> + </JList> + </JScrollPane> + </cell> + </row> + </Table> +</DemoPanel> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/JMenuItemDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/JMenuItemDemo.jaxx new file mode 100644 index 0000000..8cd5da5 --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/JMenuItemDemo.jaxx @@ -0,0 +1,23 @@ +<DemoPanel> + <script> + private void displayMessage() { + JOptionPane.showMessageDialog(demoPanel, "Menu item clicked"); + } + </script> + + <JPanel id='demoPanel'> + <JDesktopPane width='350' height='400' background='{null}'> + <JInternalFrame title='JMenu demo' width='300' height='250' resizable='true'> + <JMenuBar id='menuBar'> + <JMenu text='Demo'> + <JMenuItem text='Message Box' onActionPerformed='displayMessage()'/> + </JMenu> + </JMenuBar> + + <JPanel id='framePanel'> + <JLabel text='JMenu demo' id='demoMessage' horizontalAlignment='center'/> + </JPanel> + </JInternalFrame> + </JDesktopPane> + </JPanel> +</DemoPanel> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/JPasswordFieldDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/JPasswordFieldDemo.jaxx new file mode 100644 index 0000000..b266c65 --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/JPasswordFieldDemo.jaxx @@ -0,0 +1,10 @@ +<DemoPanel> + <VBox id='demoPanel' horizontalAlignment='center' verticalAlignment='middle'> + <HBox> + <JLabel text='Password:' displayedMnemonic='P' labelFor='{password}'/> + <JPasswordField id='password'/> + </HBox> + + <JLabel text='You entered: {new String(password.getPassword())}'/> + </VBox> +</DemoPanel> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/JProgressBarDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/JProgressBarDemo.jaxx new file mode 100644 index 0000000..8c38933 --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/JProgressBarDemo.jaxx @@ -0,0 +1,77 @@ +<DemoPanel> + <script><![CDATA[ + import javax.swing.Timer; + + int red = 0; + int green = 0; + int blue = 0; + int speed = 2; + int redDirection = 1; + int greenDirection = 1; + int blueDirection = 1; + + Timer redTimer = new Timer(5, new ActionListener() { + public void actionPerformed(ActionEvent e) { + red = Math.max(0, Math.min(255, red + speed * redDirection)); + if (red == 0 || red == 255) + redDirection = -redDirection; + } + }); + + Timer greenTimer = new Timer(50, new ActionListener() { + public void actionPerformed(ActionEvent e) { + green = Math.max(0, Math.min(255, green + speed * greenDirection)); + if (green == 0 || green == 255) + greenDirection = -greenDirection; + } + }); + + Timer blueTimer = new Timer(500, new ActionListener() { + public void actionPerformed(ActionEvent e) { + blue = Math.max(0, Math.min(255, blue + speed * blueDirection)); + if (blue == 0 || blue == 255) + blueDirection = -blueDirection; + } + }); + + redTimer.start(); + greenTimer.start(); + blueTimer.start(); + ]]></script> + + <Table insets='6' id='demoPanel'> + <row> + <cell columns='3'> + <JLabel text='Welcome to the JAXX framework!' font='{UIManager.getFont("Label.font").deriveFont(18f)}' + foreground='{new Color(red, green, blue)}'/> + </cell> + </row> + + <row> + <cell columns='3' fill='horizontal'> + <JProgressBar foreground='{new Color(red, 0, 0)}' value='{red}' maximum='255'/> + </cell> + </row> + + <row> + <cell columns='3' fill='horizontal'> + <JProgressBar foreground='{new Color(0, green, 0)}' value='{green}' maximum='255'/> + </cell> + </row> + + <row> + <cell columns='3' fill='horizontal'> + <JProgressBar foreground='{new Color(0, 0, blue)}' value='{blue}' maximum='255'/> + </cell> + </row> + + <row> + <cell weightx='1' anchor='east'> + <JButton text='Start' onActionPerformed='redTimer.start(); greenTimer.start(); blueTimer.start()'/> + </cell> + <cell> + <JButton text='Stop' onActionPerformed='redTimer.stop(); greenTimer.stop(); blueTimer.stop()'/> + </cell> + </row> + </Table> +</DemoPanel> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/JRadioButtonDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/JRadioButtonDemo.jaxx new file mode 100644 index 0000000..ccd4088 --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/JRadioButtonDemo.jaxx @@ -0,0 +1,11 @@ +<DemoPanel> + <HBox id='demoPanel' horizontalAlignment='center' verticalAlignment='middle'> + <VBox> + <JRadioButton text='Animal' value='Lynx.jpg' buttonGroup='radioButtons' selected='true'/> + <JRadioButton text='Vegetable' buttonGroup='radioButtons' value='Tomato.jpg'/> + <JRadioButton text='Mineral' buttonGroup='radioButtons' value='Amethyst.jpg'/> + </VBox> + + <JLabel icon='{new ImageIcon(getClass().getResource("images/" + radioButtons.getSelectedValue()))}'/> + </HBox> +</DemoPanel> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/JRadioButtonMenuItemDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/JRadioButtonMenuItemDemo.jaxx new file mode 100644 index 0000000..62a3996 --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/JRadioButtonMenuItemDemo.jaxx @@ -0,0 +1,14 @@ +<JMenuItemDemo> + <JMenuBar id='menuBar'> + <JMenu text='Font size'> + <JRadioButtonMenuItem text='10' value='{new Integer(10)}' buttonGroup='fontSize'/> + <JRadioButtonMenuItem text='12' value='{new Integer(12)}' buttonGroup='fontSize' selected='true'/> + <JRadioButtonMenuItem text='14' value='{new Integer(14)}' buttonGroup='fontSize'/> + <JRadioButtonMenuItem text='18' value='{new Integer(18)}' buttonGroup='fontSize'/> + <JRadioButtonMenuItem text='24' value='{new Integer(24)}' buttonGroup='fontSize'/> + </JMenu> + </JMenuBar> + + <JLabel id='demoMessage' text='Font size: {fontSize.getSelectedValue()}' horizontalAlignment='center' + font='{UIManager.getFont("Label.font").deriveFont(fontSize.getSelectedValue() != null ? (float) ((Integer) fontSize.getSelectedValue()).intValue() : 12)}'/> +</JMenuItemDemo> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/JSliderDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/JSliderDemo.jaxx new file mode 100644 index 0000000..fcebefb --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/JSliderDemo.jaxx @@ -0,0 +1,12 @@ +<DemoPanel> + <HBox id='demoPanel' horizontalAlignment='center' verticalAlignment='middle'> + <VBox> + <JSlider id='red' maximum='255' value='200'/> + <JSlider id='green' maximum='255' value='180'/> + <JSlider id='blue' maximum='255' value='240'/> + </VBox> + + <JPanel border='{BorderFactory.createEtchedBorder()}' width='64' height='64' + background='{new Color(red.getValue(), green.getValue(), blue.getValue())}'/> + </HBox> +</DemoPanel> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/JSpinnerDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/JSpinnerDemo.jaxx new file mode 100644 index 0000000..a4c74ae --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/JSpinnerDemo.jaxx @@ -0,0 +1,13 @@ +<DemoPanel> + <HBox id='demoPanel' horizontalAlignment='center' verticalAlignment='middle'> + <JLabel text='Spacing:' displayedMnemonic='S' labelFor='{spinner}'/> + + <JSpinner minimum='0' maximum='50' id='spinner'/> + + <VBox spacing='{((Integer) spinner.getValue()).intValue()}'> + <JLabel text='Use the spinner to'/> + <JLabel text='adjust the spacing'/> + <JLabel text='between these lines'/> + </VBox> + </HBox> +</DemoPanel> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/JSplitPaneDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/JSplitPaneDemo.jaxx new file mode 100644 index 0000000..4aafbc4 --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/JSplitPaneDemo.jaxx @@ -0,0 +1,13 @@ +<DemoPanel> + <JPanel id='demoPanel' layout='{new BorderLayout()}'> + <JSplitPane> + <JScrollPane> + <JLabel icon='{new ImageIcon(getClass().getResource("images/Amethyst.jpg"))}'/> + </JScrollPane> + + <JScrollPane> + <JLabel icon='{new ImageIcon(getClass().getResource("images/Lynx.jpg"))}'/> + </JScrollPane> + </JSplitPane> + </JPanel> +</DemoPanel> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/JTextAreaDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/JTextAreaDemo.jaxx new file mode 100644 index 0000000..4cac85a --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/JTextAreaDemo.jaxx @@ -0,0 +1,33 @@ +<DemoPanel> + <Table id='demoPanel' anchor='northwest'> + <row> + <cell> + <JLabel text='Normal text:' displayedMnemonic='N' labelFor='{textArea}'/> + </cell> + + <cell weightx='1' fill='both'> + <JScrollPane height='120'> + <JTextArea id='textArea' text='Try typing some text here.'/> + </JScrollPane> + </cell> + </row> + + <row> + <cell> + <JLabel text='Upper case text:'/> + </cell> + + <cell weightx='1' fill='both'> + <JScrollPane height='120'> + <JTextArea editable='false' background='{null}' text='{textArea.getText().toUpperCase()}'/> + </JScrollPane> + </cell> + </row> + + <row> + <cell weighty='1'> + <JPanel/> + </cell> + </row> + </Table> +</DemoPanel> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/JTextFieldDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/JTextFieldDemo.jaxx new file mode 100644 index 0000000..584f6dc --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/JTextFieldDemo.jaxx @@ -0,0 +1,22 @@ +<DemoPanel> + <JPanel id='demoPanel'> + <Table> + <row> + <cell> + <JLabel text='Your name:' displayedMnemonic='n' labelFor='{textField}'/> + </cell> + + <cell> + <JTextField id='textField'/> + </cell> + </row> + + <row> + <cell columns='2'> + <JButton text='Greet' + onActionPerformed='JOptionPane.showMessageDialog(demoPanel, "Hello, " + textField.getText() + "!")'/> + </cell> + </row> + </Table> + </JPanel> +</DemoPanel> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/JToggleButtonDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/JToggleButtonDemo.jaxx new file mode 100644 index 0000000..01f29de --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/JToggleButtonDemo.jaxx @@ -0,0 +1,9 @@ +<DemoPanel> + <HBox id='demoPanel' horizontalAlignment='center' verticalAlignment='middle'> + <JToggleButton text='1' id='one'/> + <JToggleButton text='2' id='two'/> + <JToggleButton text='3' id='three'/> + + <JLabel text='Total: {(one.isSelected() ? 1 : 0) + (two.isSelected() ? 2 : 0) + (three.isSelected() ? 3 : 0)}'/> + </HBox> +</DemoPanel> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/LabelStyle.css b/trunk/jaxx-example/src/main/java/jaxx/demo/LabelStyle.css new file mode 100644 index 0000000..8fe50a3 --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/LabelStyle.css @@ -0,0 +1,43 @@ +JSlider { + paintTicks: true; +} + +JSlider.color { + minorTickSpacing: 10; + majorTickSpacing: 50; + border: { BorderFactory . createEmptyBorder( 1, 1, 1, 1 ) +} + +; +} + +JSlider.color:focused { + border: { BorderFactory . createLineBorder( Color . BLACK, 1 ) +} + +; +} + +JSlider#red:focused { + background: #E7ADAD; +} + +JSlider#green:focused { + background: #B2E7AD; +} + +JSlider#blue:focused { + background: #ADB2E7; +} + +JSlider#dummySize { + minorTickSpacing: 2; + majorTickSpacing: 6; +} + +JRadioButton { + enabled: { backgroundCheckbox . isSelected( ) +} + +; +} \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/LabelStyleDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/LabelStyleDemo.jaxx new file mode 100644 index 0000000..8862635 --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/LabelStyleDemo.jaxx @@ -0,0 +1,85 @@ +<DemoPanel> + <style source="LabelStyle.css"/> + + <Table id='demoPanel' anchor='north' fill='both'> + <row> + <cell weightx='1' weighty='1' insets='6, 3, 0, 0'> + <Table anchor='west' fill='both'> + <row> + <cell> + <JLabel text='Text:'/> + </cell> + <cell weightx='1'> + <JTextField id='text' text='Data Binding'/> + </cell> + </row> + + <row> + <cell> + <JLabel text='Red:'/> + </cell> + <cell> + <JSlider id='red' value='128' maximum='255' styleClass='color'/> + </cell> + </row> + + <row> + <cell> + <JLabel text='Green:'/> + </cell> + <cell> + <JSlider id='green' value='0' maximum='255' styleClass='color'/> + </cell> + </row> + + <row> + <cell> + <JLabel text='Blue:'/> + </cell> + <cell> + <JSlider id='blue' value='255' maximum='255' styleClass='color'/> + </cell> + </row> + + <row> + <cell> + <JLabel text='Size:'/> + </cell> + <cell> + <JSlider id='dummySize' value='36' minimum='6' maximum='60'/> + </cell> + </row> + + <row> + <cell columns='2' fill='both' weighty='1'> + <JPanel border='{BorderFactory.createTitledBorder("Preview")}' + height='90' + layout='{new BorderLayout()}'> + <VBox background='{(Color)( backgroundCheckbox.isSelected() ? backgroundColor.getSelectedValue() : null)}' + margin='0' + horizontalAlignment='center' + verticalAlignment='middle'> + <JLabel text='{text.getText()}' font-size='{dummySize.getValue()}' + foreground='{new Color(red.getValue(), green.getValue(), blue.getValue())}'/> + </VBox> + </JPanel> + </cell> + </row> + </Table> + </cell> + + <cell> + <VBox spacing='0' border='{BorderFactory.createTitledBorder("Background")}'> + <JCheckBox id='backgroundCheckbox' text='Show Background'/> + <JRadioButton text='Red' buttonGroup='backgroundColor' value='{Color.RED}' selected='true'/> + <JRadioButton text='Orange' buttonGroup='backgroundColor' value='{Color.ORANGE}'/> + <JRadioButton text='Yellow' buttonGroup='backgroundColor' value='{Color.YELLOW}'/> + <JRadioButton text='Green' buttonGroup='backgroundColor' value='{Color.GREEN}'/> + <JRadioButton text='Cyan' buttonGroup='backgroundColor' value='{Color.CYAN}'/> + <JRadioButton text='Blue' buttonGroup='backgroundColor' value='{Color.BLUE}'/> + <JRadioButton text='Purple' buttonGroup='backgroundColor' value='{new Color(160, 30, 255)}'/> + </VBox> + </cell> + </row> + </Table> +</DemoPanel> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/Model.java b/trunk/jaxx-example/src/main/java/jaxx/demo/Model.java new file mode 100644 index 0000000..873d638 --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/Model.java @@ -0,0 +1,66 @@ +package jaxx.demo; + +import java.beans.*; + +public class Model { + + protected String text = "text"; + + protected String text2 = "text2"; + + protected int ratio = 51; + + + PropertyChangeSupport p; + + public Model() { + p = new PropertyChangeSupport(this); + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + p.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + p.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + p.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + p.removePropertyChangeListener(propertyName, listener); + } + + + public String getText() { + return text; + } + + public String getText2() { + return text2; + } + + public int getRatio() { + return ratio; + } + + public void setText(String text) { + String oldText = this.text; + this.text = text; + p.firePropertyChange("text", oldText, text); + } + + public void setText2(String text2) { + String oldText2 = this.text2; + this.text2 = text2; + p.firePropertyChange("text2", oldText2, text2); + } + + public void setRatio(int ratio) { + int oldRatio = this.ratio; + this.ratio = ratio; + p.firePropertyChange("ratio", oldRatio, ratio); + } +} \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/NumberEditorDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/NumberEditorDemo.jaxx new file mode 100644 index 0000000..c7d822d --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/NumberEditorDemo.jaxx @@ -0,0 +1,132 @@ + +<DemoPanel> + <script><![CDATA[ +import jaxx.runtime.swing.editor.NumberEditor; + +void $afterCompleteSetup() { + positifIntegerEditor.init(); + positifIntegerEditor2.init(); + normalIntegerEditor.init(); + normalIntegerEditor2.init(); + positifFloatEditor.init(); + positifFloatEditor2.init(); + normalFloatEditor.init(); + normalFloatEditor2.init(); +} +]]> + </script> + + <!-- model --> + <NumberEditorDemoModel id='demoModel'/> + + <Table id='demoPanel' insets='0' fill='both'> + <row> + <cell weightx='0.5'> + <JLabel horizontalAlignment='center' text='numbereditor.type'/> + </cell> + <cell weightx='0.25'> + <JLabel horizontalAlignment='center' text='numbereditor.without.auto.popup'/> + </cell> + <cell weightx='0.25'> + <JLabel horizontalAlignment='center' text='numbereditor.with.auto.popup'/> + </cell> + </row> + <row> + <cell> + <JLabel text='{_("numbereditor.positive.int", demoModel.getPositifInteger())}'/> + </cell> + <cell> + <NumberEditor id='positifIntegerEditor' + property='positifInteger' + constructorParams='this' + bean='{demoModel}' + autoPopup='false' + showPopupButton='true' + showReset='true'/> + </cell> + <cell> + <NumberEditor id='positifIntegerEditor2' + property='positifInteger' + constructorParams='this' + bean='{demoModel}' + autoPopup='true' + showPopupButton='true' + showReset='true'/> + </cell> + </row> + <row> + <cell> + <JLabel text='{_("numbereditor.normal.int", demoModel.getNormalInteger())}'/> + </cell> + <cell> + <NumberEditor id='normalIntegerEditor' + property='normalInteger' + constructorParams='this' + bean='{demoModel}' + autoPopup='false' + showPopupButton='true' + showReset='true' + useSign='true'/> + </cell> + <cell> + <NumberEditor id='normalIntegerEditor2' + property='normalInteger' + constructorParams='this' + bean='{demoModel}' + autoPopup='true' + showPopupButton='true' + showReset='true' + useSign='true'/> + </cell> + </row> + <row> + <cell> + <JLabel text='{_("numbereditor.positive.float", demoModel.getPositifFloat())}'/> + </cell> + <cell> + <NumberEditor id='positifFloatEditor' + property='positifFloat' + constructorParams='this' + bean='{demoModel}' + autoPopup='false' + showPopupButton='true' + showReset='true'/> + </cell> + <cell> + <NumberEditor id='positifFloatEditor2' + property='positifFloat' + constructorParams='this' + bean='{demoModel}' + autoPopup='true' + showPopupButton='true' + showReset='true'/> + </cell> + </row> + <row> + <cell> + <JLabel text='{_("numbereditor.normal.float", demoModel.getNormalFloat())}'/> + </cell> + <cell> + <NumberEditor id='normalFloatEditor' + property='normalFloat' + constructorParams='this' + bean='{demoModel}' + autoPopup='false' + showPopupButton='true' + showReset='true' + useSign='true'/> + </cell> + <cell> + <NumberEditor id='normalFloatEditor2' + property='normalFloat' + constructorParams='this' + bean='{demoModel}' + autoPopup='true' + showPopupButton='true' + showReset='true' + useSign='true'/> + </cell> + </row> + </Table> + +</DemoPanel> diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/NumberEditorDemoModel.java b/trunk/jaxx-example/src/main/java/jaxx/demo/NumberEditorDemoModel.java new file mode 100644 index 0000000..0e64f8d --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/NumberEditorDemoModel.java @@ -0,0 +1,78 @@ +package jaxx.demo; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; + +/** + * + * @author chemit + * @since 1.5 + */ +public class NumberEditorDemoModel { + + protected PropertyChangeSupport p; + protected int positifInteger; + protected int normalInteger; + protected float positifFloat; + protected float normalFloat; + + public NumberEditorDemoModel() { + p = new PropertyChangeSupport(this); + } + + public float getNormalFloat() { + return normalFloat; + } + + public int getNormalInteger() { + return normalInteger; + } + + public float getPositifFloat() { + return positifFloat; + } + + public int getPositifInteger() { + return positifInteger; + } + + public void setNormalFloat(float normalFloat) { + float old = this.normalFloat; + this.normalFloat = normalFloat; + p.firePropertyChange("normalFloat", old, normalFloat); + } + + public void setNormalInteger(int normalInteger) { + int old = this.normalInteger; + this.normalInteger = normalInteger; + p.firePropertyChange("normalInteger", old, normalInteger); + } + + public void setPositifFloat(float positifFloat) { + float old = this.positifFloat; + this.positifFloat = positifFloat; + p.firePropertyChange("positifFloat", old, positifFloat); + } + + public void setPositifInteger(int positifInteger) { + int old = this.positifInteger; + this.positifInteger = positifInteger; + p.firePropertyChange("positifInteger", old, positifInteger); + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + p.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + p.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + p.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + p.removePropertyChangeListener(propertyName, listener); + } +} diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/StatusMessagePanelDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/StatusMessagePanelDemo.jaxx new file mode 100644 index 0000000..45ee421 --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/StatusMessagePanelDemo.jaxx @@ -0,0 +1,11 @@ +<DemoPanel> + <JPanel id='demoPanel' layout='{new BorderLayout()}'> + <JPanel layout='{new GridLayout(0,1)}' constraints='BorderLayout.CENTER'> + <JButton text='Fool me once' + onActionPerformed='p.setStatus(((JButton)event.getSource()).getText() + " ? shame on you!")'/> + <JButton text='Fool me twice' + onActionPerformed='p.setStatus(((JButton)event.getSource()).getText() + " ? shame on ...")'/> + </JPanel> + <jaxx.runtime.swing.StatusMessagePanel id='p' constraints='BorderLayout.SOUTH'/> + </JPanel> +</DemoPanel> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/Validation.css b/trunk/jaxx-example/src/main/java/jaxx/demo/Validation.css new file mode 100644 index 0000000..7479d16 --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/Validation.css @@ -0,0 +1,5 @@ +JSlider { + paintTicks: true; + minorTickSpacing: 5; + majorTickSpacing: 10; +} diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/ValidationListDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/ValidationListDemo.jaxx new file mode 100644 index 0000000..888c5df --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/ValidationListDemo.jaxx @@ -0,0 +1,325 @@ +<DemoPanel> + <style source="Validation.css"/> + +<script><![CDATA[ +import static org.nuiton.i18n.I18n.n_; +void $afterCompleteSetup() { +}]]> +</script> + <!-- models --> + <Model id='model1'/> + <Model id='model2'/> + <Identity id='identity'/> + + <!-- errors model --> + <!-- Not existing :) --> + <!--jaxx.runtime.validator.gwt.GWTValidatorMessageListModel id='errors'--> + <jaxx.runtime.validator.swing.SwingValidatorMessageListModel id='errors' + onContentsChanged='ok.setEnabled(errors.isEmpty())'/> + + <!-- validators --> + <BeanValidator id='validator' bean='model1' uiClass="jaxx.runtime.validator.swing.ui.ImageValidationUI"> + <field name="text"/> + <field name="text2"/> + <field name="ratio"/> + </BeanValidator> + <BeanValidator id='validator2' bean='model2' uiClass="jaxx.runtime.validator.swing.ui.IconValidationUI"> + <field name="text" component="_text"/> + <field name="text2" component="_text2"/> + <field name="ratio" component="_ratio"/> + </BeanValidator> + <BeanValidator id='validator3' autoField='true' bean='identity' + uiClass="jaxx.runtime.validator.swing.ui.TranslucentValidationUI"> + <field name="email" component="email2"/> + </BeanValidator> + + <Table fill='both' id='demoPanel'> + <row> + <cell weightx='1' weighty='1' insets='6, 3, 0, 0'> + <JPanel border='{BorderFactory.createTitledBorder("Form")}' + layout='{new GridLayout()}' width='250' height='120'> + <Table anchor='west' fill='both'> + <row> + <cell> + <JLabel text='Text:'/> + </cell> + <cell weightx='1'> + <JTextField id='text' text='{model1.getText()}' + _validatorLabel='{n_("form.text")}' + onKeyReleased='model1.setText(text.getText())'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Text2:'/> + </cell> + <cell weightx='1'> + <JTextField id='text2' text='{model1.getText2()}' + _validatorLabel='{n_("form.text2")}' + onKeyReleased='model1.setText2(text2.getText())'/> + </cell> + </row> + + <row> + <cell> + <JLabel text='Ratio:'/> + </cell> + <cell> + <JSlider id='ratio' minimum='0' maximum='100' + value='{model1.getRatio()}' + _validatorLabel='{n_("form.ratio")}' + onStateChanged='model1.setRatio(ratio.getValue())'/> + </cell> + </row> + </Table> + </JPanel> + </cell> + <cell weightx='1' weighty='1' insets='6, 3, 0, 0'> + <JPanel border='{BorderFactory.createTitledBorder("Model")}' + layout='{new GridLayout()}' width='250' height='120'> + <Table anchor='west' fill='both'> + <row> + <cell> + <JLabel text='Text:'/> + </cell> + <cell weightx='1'> + <JLabel text='{model1.getText()}'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Text2:'/> + </cell> + <cell weightx='1'> + <JLabel text='{model1.getText2()}'/> + </cell> + </row> + + <row> + <cell> + <JLabel text='Ratio:'/> + </cell> + <cell> + <JLabel text='{model1.getRatio()}'/> + </cell> + </row> + </Table> + </JPanel> + </cell> + </row> + <row> + <cell weightx='1' weighty='1' insets='6, 3, 0, 0'> + <JPanel border='{BorderFactory.createTitledBorder("Form2")}' + layout='{new GridLayout()}' width='250' height='120'> + <Table anchor='west' fill='both'> + <row> + <cell> + <JLabel text='Text:'/> + </cell> + <cell weightx='1'> + <JTextField id='_text' text='{model2.getText()}' + _validatorLabel='{n_("form2.text")}' + onKeyReleased='model2.setText(_text.getText())'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Text2:'/> + </cell> + <cell weightx='1'> + <JTextField id='_text2' text='{model2.getText2()}' + _validatorLabel='{n_("form2.text2")}' + onKeyReleased='model2.setText2(_text2.getText())'/> + </cell> + </row> + + <row> + <cell> + <JLabel text='Ratio:'/> + </cell> + <cell> + <JSlider id='_ratio' minimum='0' maximum='100' + value='{model2.getRatio()}' + _validatorLabel='{n_("form2.ratio")}' + onStateChanged='model2.setRatio(_ratio.getValue())'/> + </cell> + </row> + </Table> + </JPanel> + </cell> + <cell weightx='1' weighty='1' insets='6, 3, 0, 0'> + <JPanel border='{BorderFactory.createTitledBorder("Model2")}' + layout='{new GridLayout()}' width='250' height='120'> + <Table anchor='west' fill='both'> + <row> + <cell> + <JLabel text='Text:'/> + </cell> + <cell weightx='1'> + <JLabel text='{model2.getText()}'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Text2:'/> + </cell> + <cell weightx='1'> + <JLabel text='{model2.getText2()}'/> + </cell> + </row> + + <row> + <cell> + <JLabel text='Ratio:'/> + </cell> + <cell> + <JLabel text='{model2.getRatio()}'/> + </cell> + </row> + </Table> + </JPanel> + </cell> + </row> + <row> + <cell weightx='1' weighty='1' insets='6, 3, 0, 0'> + <JPanel border='{BorderFactory.createTitledBorder("Identify Form")}' + layout='{new GridLayout()}' width='250' height='180'> + <Table anchor='west' fill='both'> + <row> + <cell> + <JLabel text='FirstName:'/> + </cell> + <cell weightx='1'> + <JTextField id='firstName' text='{identity.getFirstName()}' + onKeyReleased='identity.setFirstName(firstName.getText())'/> + </cell> + </row> + <row> + <cell> + <JLabel text='LastName:'/> + </cell> + <cell weightx='1'> + <JTextField id='lastName' text='{identity.getLastName()}' + onKeyReleased='identity.setLastName(lastName.getText())'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Email:'/> + </cell> + <cell weightx='1'> + <JTextField id='email2' text='{identity.getEmail()}' + onKeyReleased='identity.setEmail(email2.getText())'/> + </cell> + </row> + + <row> + <cell> + <JLabel text='Age:'/> + </cell> + <cell> + <JSlider id='age' minimum='0' maximum='100' value='{identity.getAge()}' + onStateChanged='identity.setAge(age.getValue())'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Config file :'/> + </cell> + <cell> + <JTextField id='config' text='{identity.getConfig()}' + onKeyReleased='identity.setConfig(new java.io.File(config.getText()))'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Working directory:'/> + </cell> + <cell> + <JTextField id='dir' text='{identity.getDir()}' + onKeyReleased='identity.setDir(new java.io.File(dir.getText()))'/> + </cell> + </row> + </Table> + </JPanel> + </cell> + <cell weightx='1' weighty='1' insets='6, 3, 0, 0'> + <JPanel border='{BorderFactory.createTitledBorder("Identity Model")}' + layout='{new GridLayout()}' width='250' height='120'> + <Table anchor='west' fill='both'> + <row> + <cell> + <JLabel text='FirstName:'/> + </cell> + <cell weightx='1'> + <JLabel text='{identity.getFirstName()}'/> + </cell> + </row> + <row> + <cell> + <JLabel text='LastName:'/> + </cell> + <cell weightx='1'> + <JLabel text='{identity.getLastName()}'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Email:'/> + </cell> + <cell weightx='1'> + <JLabel text='{identity.getEmail()}'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Age:'/> + </cell> + <cell> + <JLabel text='{identity.getAge()}'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Config file:'/> + </cell> + <cell> + <JLabel text='{identity.getConfig()}'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Directory file:'/> + </cell> + <cell> + <JLabel text='{identity.getDir()}'/> + </cell> + </row> + </Table> + </JPanel> + </cell> + </row> + <row> + <cell columns='2' fill="both"> + <JPanel border='{BorderFactory.createTitledBorder("Messages")}' layout='{new GridLayout()}' height='200' + width='500'> + <JScrollPane> + <JList id='errorList' model='{errors}' + cellRenderer='{new jaxx.runtime.validator.swing.SwingValidatorMessageListRenderer()}'/> + </JScrollPane> + </JPanel> + </cell> + </row> + <row> + <cell columns='2' fill="both"> + <JPanel layout='{new GridLayout(1,2,0,0)}'> + <JButton id='cancel' text='cancel' + onActionPerformed='JOptionPane.showMessageDialog(this, cancel.getText() + " clicked!", "onActionPerformed", JOptionPane.INFORMATION_MESSAGE);'/> + <JButton id='ok' text='valid' + onActionPerformed='JOptionPane.showMessageDialog(this, ok.getText() + " clicked!", "onActionPerformed", JOptionPane.INFORMATION_MESSAGE);'/> + </JPanel> + </cell> + </row> + </Table> + +</DemoPanel> diff --git a/trunk/jaxx-example/src/main/java/jaxx/demo/ValidationTableDemo.jaxx b/trunk/jaxx-example/src/main/java/jaxx/demo/ValidationTableDemo.jaxx new file mode 100644 index 0000000..41b586d --- /dev/null +++ b/trunk/jaxx-example/src/main/java/jaxx/demo/ValidationTableDemo.jaxx @@ -0,0 +1,331 @@ +<DemoPanel> + <style source="Validation.css"/> + + <!-- models --> + <Model id='model1'/> + <Model id='model2'/> + <Identity id='identity'/> + + <!-- errors model --> + <!-- Not existing :) --> + <!--jaxx.runtime.validator.gwt.GWTValidatorMessageTableModel id='errors2'/--> + <jaxx.runtime.validator.swing.SwingValidatorMessageTableModel id='errors2' + onTableChanged='ok.setEnabled(errors2.getRowCount()==0)'/> + + <!-- validators --> + <BeanValidator id='validator' bean='model1' uiClass="jaxx.runtime.validator.swing.ui.ImageValidationUI"> + <field name="text"/> + <field name="text2"/> + <field name="ratio"/> + </BeanValidator> + <BeanValidator id='validator2' bean='model2' uiClass="jaxx.runtime.validator.swing.ui.IconValidationUI"> + <field name="text" component="_text"/> + <field name="text2" component="_text2"/> + <field name="ratio" component="_ratio"/> + </BeanValidator> + <BeanValidator id='validator3' autoField='true' bean='identity' + uiClass="jaxx.runtime.validator.swing.ui.TranslucentValidationUI"> + <field name="email" component="email2"/> + </BeanValidator> + + <script><![CDATA[ +import static org.nuiton.i18n.I18n.n_; +import jaxx.runtime.SwingUtil; + +void $afterCompleteSetup() { + jaxx.runtime.SwingValidatorUtil.installUI(errorTable, new jaxx.runtime.validator.swing.SwingValidatorMessageTableRenderer()); +} +]]></script> + + <Table fill='both' id='demoPanel'> + <row> + <cell weightx='1' weighty='1' insets='6, 3, 0, 0'> + <JPanel border='{BorderFactory.createTitledBorder("Form")}' + layout='{new GridLayout()}' width='250' height='120'> + <Table anchor='west' fill='both'> + <row> + <cell> + <JLabel text='Text:'/> + </cell> + <cell weightx='1'> + <JTextField id='text' text='{model1.getText()}' + onKeyReleased='model1.setText(text.getText())' + _validatorLabel='{n_("form.text")}' + /> + </cell> + </row> + <row> + <cell> + <JLabel text='Text2:'/> + </cell> + <cell weightx='1'> + <JTextField id='text2' text='{model1.getText2()}' + onKeyReleased='model1.setText2(text2.getText())' + _validatorLabel='{n_("form.text2")}' + /> + </cell> + </row> + + <row> + <cell> + <JLabel text='Ratio:'/> + </cell> + <cell> + <JSlider id='ratio' minimum='0' maximum='100' + value='{model1.getRatio()}' + _validatorLabel='{n_("form.ratio")}' + onStateChanged='model1.setRatio(ratio.getValue())'/> + </cell> + </row> + </Table> + </JPanel> + </cell> + <cell weightx='1' weighty='1' insets='6, 3, 0, 0'> + <JPanel border='{BorderFactory.createTitledBorder("Model")}' + layout='{new GridLayout()}' width='250' height='120'> + <Table anchor='west' fill='both'> + <row> + <cell> + <JLabel text='Text:'/> + </cell> + <cell weightx='1'> + <JLabel text='{model1.getText()}'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Text2:'/> + </cell> + <cell weightx='1'> + <JLabel text='{model1.getText2()}'/> + </cell> + </row> + + <row> + <cell> + <JLabel text='Ratio:'/> + </cell> + <cell> + <JLabel text='{model1.getRatio()}'/> + </cell> + </row> + </Table> + </JPanel> + </cell> + </row> + <row> + <cell weightx='1' weighty='1' insets='6, 3, 0, 0'> + <JPanel border='{BorderFactory.createTitledBorder("Form2")}' + layout='{new GridLayout()}' width='250' height='120'> + <Table anchor='west' fill='both'> + <row> + <cell> + <JLabel text='Text:'/> + </cell> + <cell weightx='1'> + <JTextField id='_text' text='{model2.getText()}' + _validatorLabel='{n_("form2.text")}' + onKeyReleased='model2.setText(_text.getText())'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Text2:'/> + </cell> + <cell weightx='1'> + <JTextField id='_text2' text='{model2.getText2()}' + _validatorLabel='{n_("form2.text2")}' + onKeyReleased='model2.setText2(_text2.getText())'/> + </cell> + </row> + + <row> + <cell> + <JLabel text='Ratio:'/> + </cell> + <cell> + <JSlider id='_ratio' minimum='0' maximum='100' + value='{model2.getRatio()}' + _validatorLabel='{n_("form2.ratio")}' + onStateChanged='model2.setRatio(_ratio.getValue())'/> + </cell> + </row> + </Table> + </JPanel> + </cell> + <cell weightx='1' weighty='1' insets='6, 3, 0, 0'> + <JPanel border='{BorderFactory.createTitledBorder("Model2")}' + layout='{new GridLayout()}' width='250' height='120'> + <Table anchor='west' fill='both'> + <row> + <cell> + <JLabel text='Text:'/> + </cell> + <cell weightx='1'> + <JLabel text='{model2.getText()}'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Text2:'/> + </cell> + <cell weightx='1'> + <JLabel text='{model2.getText2()}'/> + </cell> + </row> + + <row> + <cell> + <JLabel text='Ratio:'/> + </cell> + <cell> + <JLabel text='{model2.getRatio()}'/> + </cell> + </row> + </Table> + </JPanel> + </cell> + </row> + <row> + <cell weightx='1' weighty='1' insets='6, 3, 0, 0'> + <JPanel border='{BorderFactory.createTitledBorder("Identify Form")}' + layout='{new GridLayout()}' width='250' height='180'> + <Table anchor='west' fill='both'> + <row> + <cell> + <JLabel text='FirstName:'/> + </cell> + <cell weightx='1'> + <JTextField id='firstName' text='{identity.getFirstName()}' + onKeyReleased='identity.setFirstName(firstName.getText())'/> + </cell> + </row> + <row> + <cell> + <JLabel text='LastName:'/> + </cell> + <cell weightx='1'> + <JTextField id='lastName' text='{identity.getLastName()}' + onKeyReleased='identity.setLastName(lastName.getText())'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Email:'/> + </cell> + <cell weightx='1'> + <JTextField id='email2' text='{identity.getEmail()}' + onKeyReleased='identity.setEmail(email2.getText())'/> + </cell> + </row> + + <row> + <cell> + <JLabel text='Age:'/> + </cell> + <cell> + <JSlider id='age' minimum='0' maximum='100' value='{identity.getAge()}' + onStateChanged='identity.setAge(age.getValue())'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Config file :'/> + </cell> + <cell> + <JTextField id='config' text='{identity.getConfig()}' + onKeyReleased='identity.setConfig(new java.io.File(config.getText()))'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Working directory:'/> + </cell> + <cell> + <JTextField id='dir' text='{identity.getDir()}' + onKeyReleased='identity.setDir(new java.io.File(dir.getText()))'/> + </cell> + </row> + </Table> + </JPanel> + </cell> + <cell weightx='1' weighty='1' insets='6, 3, 0, 0'> + <JPanel border='{BorderFactory.createTitledBorder("Identity Model")}' + layout='{new GridLayout()}' width='250' height='120'> + <Table anchor='west' fill='both'> + <row> + <cell> + <JLabel text='FirstName:'/> + </cell> + <cell weightx='1'> + <JLabel text='{identity.getFirstName()}'/> + </cell> + </row> + <row> + <cell> + <JLabel text='LastName:'/> + </cell> + <cell weightx='1'> + <JLabel text='{identity.getLastName()}'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Email:'/> + </cell> + <cell weightx='1'> + <JLabel text='{identity.getEmail()}'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Age:'/> + </cell> + <cell> + <JLabel text='{identity.getAge()}'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Config file:'/> + </cell> + <cell> + <JLabel text='{identity.getConfig()}'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Directory file:'/> + </cell> + <cell> + <JLabel text='{identity.getDir()}'/> + </cell> + </row> + </Table> + </JPanel> + </cell> + </row> + <row> + <cell columns='2' fill="both"> + <JPanel border='{BorderFactory.createTitledBorder("Messages")}' layout='{new GridLayout()}' height='200' + width='500'> + <JScrollPane columnHeaderView='{errorTable.getTableHeader()}'> + <JTable id='errorTable' model='{errors2}' rowSelectionAllowed='true' autoCreateRowSorter='true' + autoResizeMode='2' cellSelectionEnabled='false' selectionMode='0'/> + </JScrollPane> + </JPanel> + </cell> + </row> + <row> + <cell columns='2' fill="both"> + <JPanel layout='{new GridLayout(1,2,0,0)}'> + <JButton id='cancel' text='cancel' + onActionPerformed='JOptionPane.showMessageDialog(this, cancel.getText() + " clicked!", "onActionPerformed", JOptionPane.INFORMATION_MESSAGE);'/> + <JButton id='ok' text='valid' + onActionPerformed='JOptionPane.showMessageDialog(this, ok.getText() + " clicked!", "onActionPerformed", JOptionPane.INFORMATION_MESSAGE);'/> + </JPanel> + </cell> + </row> + </Table> + +</DemoPanel> diff --git a/trunk/jaxx-example/src/main/jnlp/jxlayer.jnlp b/trunk/jaxx-example/src/main/jnlp/jxlayer.jnlp new file mode 100644 index 0000000..ef01376 --- /dev/null +++ b/trunk/jaxx-example/src/main/jnlp/jxlayer.jnlp @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<jnlp spec="1.0+" codebase="@url@" href="jxlayer.jnlp"> + <information> + <title>Sun MicroSystems</title> + <vendor>Sun MicroSystems, Inc.</vendor> + <offline-allowed/> + </information> + <resources> + <jar href="lib/@lib@"/> + </resources> + <component-desc/> +</jnlp> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/jnlp/sun.jnlp b/trunk/jaxx-example/src/main/jnlp/sun.jnlp new file mode 100644 index 0000000..f345d95 --- /dev/null +++ b/trunk/jaxx-example/src/main/jnlp/sun.jnlp @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<jnlp spec="1.0+" codebase="@url@" href="sun.jnlp"> + <information> + <title>Sun MicroSystems</title> + <vendor>Sun MicroSystems, Inc.</vendor> + <offline-allowed/> + </information> + <resources> + <jar href="lib/@lib@"/> + </resources> + <component-desc/> +</jnlp> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/resources/i18n/jaxx-example-en_GB.properties b/trunk/jaxx-example/src/main/resources/i18n/jaxx-example-en_GB.properties new file mode 100644 index 0000000..48f0c56 --- /dev/null +++ b/trunk/jaxx-example/src/main/resources/i18n/jaxx-example-en_GB.properties @@ -0,0 +1,142 @@ +-= +.= +0= +1= +10= +12= +14= +18= +2= +24= +3= +4= +5= +6= +7= +8= +9= +Age\:= +Animal= +Blue= +Blue\:= +Bold= +Button\ label\:= +C= +CE= +Cancel= +Change\ layer\ state= +Click\ me= +Comments\:= +Config\ file\ \:= +Config\ file\:= +Cyan= +Dec\ (-)= +Demo= +Directory\ file\:= +Editable= +Email\ Address\:= +Email\:= +Empty\ I18n\ editor\:= +Enabled= +EnumEditor\ (country)\ \:= +EnumEditor\ (language)\ \:= +Fancy\ Button= +First\ Name\:= +FirstName\:= +Font\ size= +Fool\ me\ once= +Fool\ me\ twice= +Green= +Green\:= +Greet= +I18n\ editor\ with\ no\ icon\ \:= +I18n\ editor\ with\ no\ text\ \:= +I18n\ editor\:= +Inc\ (+)= +Italic= +JAXX\ Demo= +JMenu\ demo= +Last\ Name\:= +LastName\:= +Locale\ editor\:= +Message\ Box= +Mineral= +Normal\ text\:= +OK= +Orange= +Password\:= +Purple= +Ratio\:= +Red= +Red\:= +Reset= +Show\ Background= +Show\ password\ dialog= +Sign\ on= +Simple\ Button= +Size\:= +Source= +Spacing\:= +Start= +Stop= +Supported\ Swing\ components\:= +Text2\:= +Text\:= +Underline= +Upper\ case\ text\:= +Use\ the\ spinner\ to= +Username\:= +Vegetable= +View= +Welcome\ to\ the\ JAXX\ framework\!= +Working\ directory\:= +Yellow= +Your\ name\:= +\\u00f7= +adjust\ the\ spacing= +between\ these\ lines= +button\ A= +button\ B= +button\ C= +button\ C\ (full\ block)= +button\ D\ (full\ block\ 2)= +button\ with\ layer= +cancel= +close= +close2= +close3= +edit= +edit2= +edit3= +emptyNode=< empty node > +form.ratio=Form \: ratio +form.text=Form \: text +form.text2=Form \: text2 +form2.ratio=Form2 \: ratio +form2.text=Form2 \: text +form2.text2=Form2 \: text2 +no\ layer= +numbereditor.normal.float= +numbereditor.normal.float.value= +numbereditor.normal.int= +numbereditor.normal.int.value= +numbereditor.positive.float= +numbereditor.positive.float.value= +numbereditor.positive.int= +numbereditor.positive.int.value= +numbereditor.positive.integer=Simple positive integer editor +numbereditor.type= +numbereditor.with.auto.popup= +numbereditor.without.auto.popup= +valid= +validator.field=Champ +validator.field.header.tip= +validator.field.tip= +validator.message=Message +validator.message.header.tip= +validator.message.tip= +validator.scope=... +validator.scope.header.tip= +validator.scope.tip= +with\ layer= +x= diff --git a/trunk/jaxx-example/src/main/resources/i18n/jaxx-example-fr_FR.properties b/trunk/jaxx-example/src/main/resources/i18n/jaxx-example-fr_FR.properties new file mode 100644 index 0000000..d96a3a3 --- /dev/null +++ b/trunk/jaxx-example/src/main/resources/i18n/jaxx-example-fr_FR.properties @@ -0,0 +1,134 @@ +-= +.= +0= +1= +10= +12= +14= +18= +2= +24= +3= +4= +5= +6= +7= +8= +9= +Age\:= +Animal= +Blue= +Blue\:= +Bold= +Button\ label\:= +C= +CE= +Cancel= +Change\ layer\ state= +Click\ me= +Comments\:= +Config\ file\ \:= +Config\ file\:= +Cyan= +Dec\ (-)= +Demo= +Directory\ file\:= +Editable= +Email\ Address\:= +Email\:= +Empty\ I18n\ editor\:= +Enabled= +EnumEditor\ (country)\ \:= +EnumEditor\ (language)\ \:= +Fancy\ Button= +First\ Name\:= +FirstName\:= +Font\ size= +Fool\ me\ once= +Fool\ me\ twice= +Green= +Green\:= +Greet= +I18n\ editor\ with\ no\ icon\ \:= +I18n\ editor\ with\ no\ text\ \:= +I18n\ editor\:= +Inc\ (+)= +Italic= +JAXX\ Demo= +JMenu\ demo= +Last\ Name\:= +LastName\:= +Locale\ editor\:= +Message\ Box= +Mineral= +Normal\ text\:= +OK= +Orange= +Password\:= +Purple= +Ratio\:= +Red= +Red\:= +Reset= +Show\ Background= +Show\ password\ dialog= +Sign\ on= +Simple\ Button= +Size\:= +Source= +Spacing\:= +Start= +Stop= +Supported\ Swing\ components\:= +Text2\:= +Text\:= +Underline= +Upper\ case\ text\:= +Use\ the\ spinner\ to= +Username\:= +Vegetable= +View= +Welcome\ to\ the\ JAXX\ framework\!= +Working\ directory\:= +Yellow= +Your\ name\:= +\\u00f7= +adjust\ the\ spacing= +between\ these\ lines= +button\ A= +button\ B= +button\ C= +button\ C\ (full\ block)= +button\ D\ (full\ block\ 2)= +button\ with\ layer= +cancel= +close= +close2= +close3= +edit= +edit2= +edit3= +emptyNode=< empty node > +form.ratio=Form \: ratio +form.text=Form \: text +form.text2=Form \: text2 +form2.ratio=Form2 \: ratio +form2.text=Form2 \: text +form2.text2=Form2 \: text2 +no\ layer= +numbereditor.normal.float=D\u00E9cimal primitif \: [%1$s] +numbereditor.normal.int=Entier primitif \: [%1$s] +numbereditor.positive.float=D\u00E9cimal primitif positif \: [%1$s] +numbereditor.positive.int=Entier primitif positif \: [%1$s] +numbereditor.type=Type d'\u00E9diteur +numbereditor.with.auto.popup=Avec popup auto +numbereditor.without.auto.popup=Sans popup auto +valid= +validator.field= +validator.field.header.tip= +validator.message= +validator.message.header.tip= +validator.scope= +validator.scope.header.tip= +with\ layer= +x= diff --git a/trunk/jaxx-example/src/main/resources/icons/action-accept.png b/trunk/jaxx-example/src/main/resources/icons/action-accept.png new file mode 100644 index 0000000..89c8129 Binary files /dev/null and b/trunk/jaxx-example/src/main/resources/icons/action-accept.png differ diff --git a/trunk/jaxx-example/src/main/resources/icons/action-block.png b/trunk/jaxx-example/src/main/resources/icons/action-block.png new file mode 100644 index 0000000..aba044b Binary files /dev/null and b/trunk/jaxx-example/src/main/resources/icons/action-block.png differ diff --git a/trunk/jaxx-example/src/main/resources/jaxx/demo/Identity-error-validation.xml b/trunk/jaxx-example/src/main/resources/jaxx/demo/Identity-error-validation.xml new file mode 100644 index 0000000..86da73d --- /dev/null +++ b/trunk/jaxx-example/src/main/resources/jaxx/demo/Identity-error-validation.xml @@ -0,0 +1,49 @@ +<!DOCTYPE validators PUBLIC + "-//OpenSymphony Group//XWork Validator 1.0.2//EN" + "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"> +<validators> + <field name="firstName"> + <field-validator type="requiredstring" short-circuit="true"> + <message>You must enter a firstName.</message> + </field-validator> + </field> + <field name="lastName"> + <field-validator type="requiredstring" short-circuit="true"> + <message>You must enter a lastName.</message> + </field-validator> + </field> + + <field name="email"> + <field-validator type="requiredstring" short-circuit="true"> + <message>You must enter a value for email.</message> + </field-validator> + <field-validator type="email" short-circuit="true"> + <message>Not a valid e-mail.</message> + </field-validator> + </field> + + <field name="config"> + <field-validator type="requiredFile" short-circuit="true"> + <message>You must enter a value for config.</message> + </field-validator> + <field-validator type="existingFile" short-circuit="true"> + <message>The configuration file ${config} does not exist.</message> + </field-validator> + </field> + + <field name="dir"> + <field-validator type="requiredFile" short-circuit="true"> + <message>You must enter a value for dir.</message> + </field-validator> + <field-validator type="existingDirectory" short-circuit="true"> + <message>The directory ${dir} does not exist.</message> + </field-validator> + </field> + + <field name="age"> + <field-validator type="int"> + <param name="min">18</param> + <message>Your are too young (min ${min} )</message> + </field-validator> + </field> +</validators> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/resources/jaxx/demo/Identity-info-validation.xml b/trunk/jaxx-example/src/main/resources/jaxx/demo/Identity-info-validation.xml new file mode 100644 index 0000000..b515a92 --- /dev/null +++ b/trunk/jaxx-example/src/main/resources/jaxx/demo/Identity-info-validation.xml @@ -0,0 +1,49 @@ +<!DOCTYPE validators PUBLIC + "-//OpenSymphony Group//XWork Validator 1.0.2//EN" + "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"> +<validators> + <!--field name="firstName"> + <field-validator type="requiredstring" short-circuit="true"> + <message>You must enter a firstName.</message> + </field-validator> + </field> + <field name="lastName"> + <field-validator type="requiredstring" short-circuit="true"> + <message>You must enter a lastName.</message> + </field-validator> + </field> + + <field name="email"> + <field-validator type="requiredstring" short-circuit="true"> + <message>You must enter a value for email.</message> + </field-validator> + <field-validator type="email" short-circuit="true"> + <message>Not a valid e-mail.</message> + </field-validator> + </field> + + <field name="config"> + <field-validator type="requiredFile" short-circuit="true"> + <message>You must enter a value for config.</message> + </field-validator> + <field-validator type="existingFile" short-circuit="true"> + <message>The configuration file ${config} does not exist.</message> + </field-validator> + </field> + + <field name="dir"> + <field-validator type="requiredFile" short-circuit="true"> + <message>You must enter a value for dir.</message> + </field-validator> + <field-validator type="existingDirectory" short-circuit="true"> + <message>The directory ${dir} does not exist.</message> + </field-validator> + </field--> + + <field name="age"> + <field-validator type="int"> + <param name="min">25</param> + <message>You are still young ( old ${min} ) </message> + </field-validator> + </field> +</validators> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/resources/jaxx/demo/Identity-warning-validation.xml b/trunk/jaxx-example/src/main/resources/jaxx/demo/Identity-warning-validation.xml new file mode 100644 index 0000000..ece44f3 --- /dev/null +++ b/trunk/jaxx-example/src/main/resources/jaxx/demo/Identity-warning-validation.xml @@ -0,0 +1,49 @@ +<!DOCTYPE validators PUBLIC + "-//OpenSymphony Group//XWork Validator 1.0.2//EN" + "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"> +<validators> + <!--field name="firstName"> + <field-validator type="requiredstring" short-circuit="true"> + <message>You must enter a firstName.</message> + </field-validator> + </field> + <field name="lastName"> + <field-validator type="requiredstring" short-circuit="true"> + <message>You must enter a lastName.</message> + </field-validator> + </field> + + <field name="email"> + <field-validator type="requiredstring" short-circuit="true"> + <message>You must enter a value for email.</message> + </field-validator> + <field-validator type="email" short-circuit="true"> + <message>Not a valid e-mail.</message> + </field-validator> + </field> + + <field name="config"> + <field-validator type="requiredFile" short-circuit="true"> + <message>You must enter a value for config.</message> + </field-validator> + <field-validator type="existingFile" short-circuit="true"> + <message>The configuration file ${config} does not exist.</message> + </field-validator> + </field> + + <field name="dir"> + <field-validator type="requiredFile" short-circuit="true"> + <message>You must enter a value for dir.</message> + </field-validator> + <field-validator type="existingDirectory" short-circuit="true"> + <message>The directory ${dir} does not exist.</message> + </field-validator> + </field--> + + <field name="age"> + <field-validator type="int"> + <param name="max">88</param> + <message>Info : Your are older than ${max} !</message> + </field-validator> + </field> +</validators> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/resources/jaxx/demo/Model-error-validation.xml b/trunk/jaxx-example/src/main/resources/jaxx/demo/Model-error-validation.xml new file mode 100644 index 0000000..05c0d34 --- /dev/null +++ b/trunk/jaxx-example/src/main/resources/jaxx/demo/Model-error-validation.xml @@ -0,0 +1,35 @@ +<!DOCTYPE validators PUBLIC + "-//OpenSymphony Group//XWork Validator 1.0.2//EN" + "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"> +<validators> + <!-- Field Validators for email field --> + <field name="text"> + <field-validator type="requiredstring" short-circuit="true"> + <message>You must enter a value for text.</message> + </field-validator> + </field> + + <field name="text2"> + <field-validator type="requiredstring" short-circuit="true"> + <message>You must enter a value for text2.</message> + </field-validator> + </field> + + <field name="ratio"> + <field-validator type="int"> + <param name="min">20</param> + <param name="max">50</param> + <message>Ratio needs to be between ${min} and ${max}</message> + </field-validator> + </field> + + <!-- Plain Validator 1 --> + <validator type="expression"> + <param name="expression">text.startsWith("poussin")</param> + <message>Email not starts with poussin</message> + </validator> + <validator type="expression"> + <param name="expression">text2.startsWith("chemit")</param> + <message>Email not starts with chemit</message> + </validator> +</validators> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/resources/jaxx/demo/Model-info-validation.xml b/trunk/jaxx-example/src/main/resources/jaxx/demo/Model-info-validation.xml new file mode 100644 index 0000000..efd6249 --- /dev/null +++ b/trunk/jaxx-example/src/main/resources/jaxx/demo/Model-info-validation.xml @@ -0,0 +1,13 @@ +<!DOCTYPE validators PUBLIC + "-//OpenSymphony Group//XWork Validator 1.0.2//EN" + "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"> +<validators> + <!-- Field Validators for email field --> + <field name="text"> + <field-validator type="fieldexpression"> + <param name="expression"><![CDATA[ text != null && text.length() > 10]]></param> + <message>Text should have more than 10 caracters</message> + </field-validator> + </field> + +</validators> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/resources/jaxx/demo/Model-warning-validation.xml b/trunk/jaxx-example/src/main/resources/jaxx/demo/Model-warning-validation.xml new file mode 100644 index 0000000..2e2e90d --- /dev/null +++ b/trunk/jaxx-example/src/main/resources/jaxx/demo/Model-warning-validation.xml @@ -0,0 +1,18 @@ +<!DOCTYPE validators PUBLIC + "-//OpenSymphony Group//XWork Validator 1.0.2//EN" + "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"> +<validators> + <!-- Field Validators for email field --> + <field name="text"> + <field-validator type="email" short-circuit="true"> + <message>Not a valid e-mail for text.</message> + </field-validator> + </field> + + <field name="text2"> + <field-validator type="requiredstring" short-circuit="true"> + <message>You must enter a value for text2.</message> + </field-validator> + </field> + +</validators> \ No newline at end of file diff --git a/trunk/jaxx-example/src/main/resources/jaxx/demo/images/Amethyst.jpg b/trunk/jaxx-example/src/main/resources/jaxx/demo/images/Amethyst.jpg new file mode 100644 index 0000000..72aabd2 Binary files /dev/null and b/trunk/jaxx-example/src/main/resources/jaxx/demo/images/Amethyst.jpg differ diff --git a/trunk/jaxx-example/src/main/resources/jaxx/demo/images/Lynx.jpg b/trunk/jaxx-example/src/main/resources/jaxx/demo/images/Lynx.jpg new file mode 100644 index 0000000..779ef43 Binary files /dev/null and b/trunk/jaxx-example/src/main/resources/jaxx/demo/images/Lynx.jpg differ diff --git a/trunk/jaxx-example/src/main/resources/jaxx/demo/images/Tomato.jpg b/trunk/jaxx-example/src/main/resources/jaxx/demo/images/Tomato.jpg new file mode 100644 index 0000000..f6223b2 Binary files /dev/null and b/trunk/jaxx-example/src/main/resources/jaxx/demo/images/Tomato.jpg differ diff --git a/trunk/jaxx-example/src/main/resources/jaxx/demo/images/pencil_black.gif b/trunk/jaxx-example/src/main/resources/jaxx/demo/images/pencil_black.gif new file mode 100644 index 0000000..1dae579 Binary files /dev/null and b/trunk/jaxx-example/src/main/resources/jaxx/demo/images/pencil_black.gif differ diff --git a/trunk/jaxx-example/src/main/resources/log4j.properties b/trunk/jaxx-example/src/main/resources/log4j.properties new file mode 100644 index 0000000..e49816c --- /dev/null +++ b/trunk/jaxx-example/src/main/resources/log4j.properties @@ -0,0 +1,10 @@ +# Global logging configuration +log4j.rootLogger=ERROR, stdout +# Console output... +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) %M - %m%n + +log4j.logger.demo=DEBUG +log4j.logger.jaxx=INFO +log4j.logger.org.nuiton=INFO diff --git a/trunk/jaxx-example/src/site/rst/images/Components-screenshot.gif b/trunk/jaxx-example/src/site/rst/images/Components-screenshot.gif new file mode 100644 index 0000000..68bec67 Binary files /dev/null and b/trunk/jaxx-example/src/site/rst/images/Components-screenshot.gif differ diff --git a/trunk/jaxx-example/src/site/rst/images/webstart.gif b/trunk/jaxx-example/src/site/rst/images/webstart.gif new file mode 100644 index 0000000..079fc1b Binary files /dev/null and b/trunk/jaxx-example/src/site/rst/images/webstart.gif differ diff --git a/trunk/jaxx-example/src/site/rst/index.rst b/trunk/jaxx-example/src/site/rst/index.rst new file mode 100644 index 0000000..9e8f78f --- /dev/null +++ b/trunk/jaxx-example/src/site/rst/index.rst @@ -0,0 +1,40 @@ +=================== +Examples/Components +=================== + +The Components demo displays many different Swing components being used in a variety of ways; it is JAXX's equivalent +of the SwingSet demo. Various pages use advanced features such as data binding, scripting, event handling, and +CSS stylesheets. + +Examples/Calculator +=================== + +This is an implementation of Challenge #2 from the `XUL Grand Coding Challenge 2004`_ . Because this example program +has been implemented in so many different languages, you can easily compare JAXX's +syntax against the competition and decide for yourself which you prefer. + +Screen shot +----------- + +.. image:: images/Components-screenshot.gif + +Set it in action +---------------- + +|webstart| + +To run this example in `Java Web Start`_, click the `following link`_. + + +Source code +----------- + +Unlike the other examples, the source code for Components is too big to display here. You can view it yourself by +downloading JAXX, and you can also view the source code for the individual demos by clicking the "Source" tabs. + + +.. _Java Web Start: http://java.sun.com/products/javawebstart/ + +.. |webstart| image:: images/webstart.gif + +.. _following link: ./launch-demo.jnlp diff --git a/trunk/jaxx-example/src/site/site.xml b/trunk/jaxx-example/src/site/site.xml new file mode 100644 index 0000000..9174ab8 --- /dev/null +++ b/trunk/jaxx-example/src/site/site.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project name="${project.name}"> + + <bannerLeft> + <name>${project.name}</name> + <src>${site.home.url}/jaxx.png</src> + <href>index.html</href> + </bannerLeft> + + <body> + + <breadcrumbs> + <item name="${project.name}" href="${project.url}" /> + </breadcrumbs> + + <menu ref="parent"/> + + <menu name="Utilisateur" inherited="top"> + <item name="Lancer la démo" href="launch-demo.jnlp"/> + </menu> + + <menu ref="reports"/> + + <menu ref="modules"/> + + </body> +</project> diff --git a/trunk/jaxx-example/src/test/java/jaxx/demo/BeanValidatorDetectorTest.java b/trunk/jaxx-example/src/test/java/jaxx/demo/BeanValidatorDetectorTest.java new file mode 100644 index 0000000..e49ff8b --- /dev/null +++ b/trunk/jaxx-example/src/test/java/jaxx/demo/BeanValidatorDetectorTest.java @@ -0,0 +1,34 @@ +package jaxx.demo; + +import java.io.File; +import java.util.Iterator; +import java.util.SortedSet; +import jaxx.runtime.validator.AbstractBeanValidatorDetectorTest; +import jaxx.runtime.validator.BeanValidator; +import org.junit.BeforeClass; +import static org.junit.Assert.*; + +/** + * + * @author chemit + */ +public class BeanValidatorDetectorTest extends AbstractBeanValidatorDetectorTest { + + @BeforeClass + public static void setUpClass() throws Exception { + AbstractBeanValidatorDetectorTest.setUpClass(); + } + + public BeanValidatorDetectorTest() { + super(new File(basedir, "src" + File.separator + "main" + File.separator + "resources"), Identity.class, Model.class); + } + + @Override + protected void assertDetect(SortedSet<BeanValidator<?>> validators) { + assertFalse(validators.isEmpty()); + assertEquals(2, validators.size()); + Iterator<BeanValidator<?>> itrV = validators.iterator(); + assertValidator(Identity.class, null, itrV.next()); + assertValidator(Model.class, null, itrV.next()); + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/LICENSE.txt b/trunk/jaxx-runtime-api/LICENSE.txt new file mode 100644 index 0000000..3f7b8b1 --- /dev/null +++ b/trunk/jaxx-runtime-api/LICENSE.txt @@ -0,0 +1,166 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/trunk/jaxx-runtime-api/README.txt b/trunk/jaxx-runtime-api/README.txt new file mode 100644 index 0000000..d2e50d3 --- /dev/null +++ b/trunk/jaxx-runtime-api/README.txt @@ -0,0 +1,2 @@ +To deploy new version of pom: mvn deploy +To install localy: mvn install diff --git a/trunk/jaxx-runtime-api/changelog.txt b/trunk/jaxx-runtime-api/changelog.txt new file mode 100644 index 0000000..f7baf57 --- /dev/null +++ b/trunk/jaxx-runtime-api/changelog.txt @@ -0,0 +1,109 @@ +1.5 + * 20090506 [chemit] - super-pom has no dependencies + +1.3 chemit 20090409 + * 20090404 [chemit] - introduce DataContext class + * 20090331 [chemit] - introduce DecoratorUtils class + * 20090302 [chemit] - add pcs in ApplicationContext + - add method in Util to filter JAXX property changed listeners + +1.2 letellier 2009022? + * 2009021 [chemit] - introduce DefaultApplicationContext iwth annotation system. + +1.1 chemit 20090220 + * 20090124 [chemit] - add methods to retreave icons from UIManager in Util class + * 20090123 [chemit] - add a simple createIcon method in Util classe (to create an icon with no path prefix) + - add a UIManager key "default.icon.path" to be able to change the path where to find icons + * 20090122 [chemit] - refactor poms (sibling dependencies, pluginsManagment,...) + +1.0 chemit 20090111 + * 20090111 [chemit] - integrate new architecture to allow to have runtime code with NO link with compiler :) + +0.8 ??? 200812?? + * 20081228 [chemit] - generify ClassDescriptor + - introduce StylesheetHelper helper class to detach Stylesheet, Rule and Selector classes from + JAXXCompiler and make possible to extract compiler engine from runtime + + * 20081227 [chemit] - add PCS on ValidatorErrorTable to be used by table validation + * 20081218 [chemit] - improve generation of methods + * 20081214 [chemit] - can now in validation, put error with args (all args must be separated by a ##) + - improve event naming : replace the $evXXX by doMEthodName__on__field (except with optimize option) + - add jaww.runtime.swing.Utils.fillComboBox to fill a combobox model from a collection + - add addSourcesToClassPath property to add sources directories in class-path + - improve classloader managment + - keep in DataSource objetCode + - fix bug when processDataBinding on a null objectCode + - always clean node cached values when selected it + - add usefull databinding method in Util + + * 20081213 [chemit] - improve navigation tree node rendering with some caches + - introduce a ChildBuilder to simplify building of child nodes from a collection or array + +0.7 chemit 20081210 + * 20081210 [chemit] - fix bug 1751 + * 20081210 [chemit] - improve JAXXButtonGroup (add ActionChangeListener and toolTipText mecanism) + * 20081208 [chemit] - javabBean attribute use to initialize bean + - introduce Base64Coder to fix bug 1750 and control serailVersionUI (put them to 1L for the moment) + - introduce MultiJXPathDecorator + - add a resetAfterCompile parameter toCompilerOption to keep in test used compilers + + * 20081207 [chemit] use lutinproject 3.1 + - can exclude field from validator + * 20081202 [chemit] - add strategy for loading ui in NavigationTreeSelectionAdapter + - fix bug when searching for a inner class + + * 20081201 [chemit] - implements jaxx.runtime.JXPathDecorator + - add setcontextValue and removeContextValue on JAXXContextEntryDef + - introduce scope in BeanValidator (ERROR or WARNING) and related swing stuff + - only enter once in $initialize method in generated code + + 0.6 chemit 20081117 + * 20081118 [chemit] introduce NavigationUtil, save in context selected node + * 20081107 [chemit] improve data binding and code generation : + - make possible inheritance in binding + - add an attribute javaBean to an object : will generate a full java bean support property + - make possible binding to the javaBean added properties + - clean generated code + + * 20081105 [chemit] - introduce a CardLayout2 to extends awt CardLayout + - introduce a NavigationTreeModel + - introduce a Decorator to render Object + - propagate constructor JAXXContext(JAXXContext) in JAXXObject generation + - begin of rst documentation + + * 20081104 [chemit] can add extra beanInfoSearchPath in SwingInitializer + * 20081104 [chemit] add jaxxContextImplementorClass in option to make possible use of other JAXXContext implementor. + * 20081102 [chemit] improve JAXXContext : + - introduce a JAXXContextEntryDef to qualify an entry of a JAXXContext + - do javadoc in JAXXContext + - add logic in DefaultJAXXContext : seek in parent context if entry not found + * 20081102 [chemit] improve tests : + - fix the last failed test from Jaxx original version :) + - dumps tests to JUnit4 :) + * 20081030 [chemit] improve BeanValidator : + - add full PropertyChangeEvent java-bean support and a property valid + - when remove bean from validator, must remove errors from model + - make possible to have a dynamic errorListModel in jaxx files + * 20081030 [chemit] improve JAXXContext : + - fix setContextValue bug when setting twice a same type for a same key + - implements a DefaultJAXXContext + - use this default implementation with delegate pattern in JAXXObject + * 20081030 [chemit] add JAXXAction contract to simplify init of ui with JAXXInitialContext + * 20081027 [chemit] fix bug 1722 + * 20081027 [chemit] add conversion support in validator + * 20081025 [chemit] improve BeanValidator tag : + - add a errorList attribute for set a ErrorListMouseListener on the errorList + - add a beanInitializer attribute for set the validator's bean at runtime + - add a default errorListModel value 'errors' + * 20081025 [chemit] introduce JAXXInitialContext to fill JAXXContext at runtime before $initialize() method + * 20081024 [chemit] fix validator context lost if UI is launched from another thread + 0.5 chemit 20081002 + * 20081017 [chemit] add validator support + * 20081013 [chemit] can generate logger on jaxx files + * 20081011 [chemit] improve site + * 20081011 [chemit] fix bug on JavaFileParser : works again + * 20081002 [chemit] Using lutinproject 3.0, changing groupId to org.codelutin + * 20081002 [chemit] use a single module jaxx-core (no more core, runtime and jaxx-swing modules) + * 20081002 [chemit] Introduce JAXXContext + * 20081002 [chemit] Fix bug on method creation via scripting + * 20081002 [chemit] Improve i18n integration (works now also for tabs) diff --git a/trunk/jaxx-runtime-api/pom.xml b/trunk/jaxx-runtime-api/pom.xml new file mode 100644 index 0000000..e804ce9 --- /dev/null +++ b/trunk/jaxx-runtime-api/pom.xml @@ -0,0 +1,138 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <!-- ************************************************************* --> + <!-- *** POM Relationships *************************************** --> + <!-- ************************************************************* --> + + <parent> + <groupId>org.nuiton</groupId> + <artifactId>jaxx</artifactId> + <version>1.7.1</version> + </parent> + + <groupId>org.nuiton.jaxx</groupId> + <artifactId>jaxx-runtime-api</artifactId> + + <dependencies> + + <dependency> + <groupId>org.nuiton</groupId> + <artifactId>nuiton-utils</artifactId> + </dependency> + + <dependency> + <groupId>commons-lang</groupId> + <artifactId>commons-lang</artifactId> + </dependency> + + <!-- pour utiliser javaHelp --> + <dependency> + <groupId>javax.help</groupId> + <artifactId>javahelp</artifactId> + </dependency> + + <dependency> + <groupId>org.swinglabs</groupId> + <artifactId>jxlayer</artifactId> + </dependency> + + <dependency> + <groupId>commons-jxpath</groupId> + <artifactId>commons-jxpath</artifactId> + </dependency> + + <!-- validation framework --> + + <dependency> + <groupId>com.opensymphony</groupId> + <artifactId>xwork</artifactId> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </dependency> + + </dependencies> + + <!-- ************************************************************* --> + <!-- *** Project Information ************************************* --> + <!-- ************************************************************* --> + + <name>${project.artifactId}</name> + <description>Jaxx runtime api</description> + + <!-- ************************************************************* --> + <!-- *** Build Settings ****************************************** --> + <!-- ************************************************************* --> + <packaging>jar</packaging> + + <build> + <plugins> + <plugin> + <groupId>org.nuiton.i18n</groupId> + <artifactId>maven-i18n-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>parserJava</goal> + <goal>gen</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + + <pluginManagement> + <plugins> + <plugin> + <artifactId>maven-jar-plugin</artifactId> + <executions> + <execution> + <id>attach-test</id> + <goals> + <goal>test-jar</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </pluginManagement> + </build> + + <!-- ************************************************************* --> + <!-- *** Build Environment ************************************** --> + <!-- ************************************************************* --> + <profiles> + <!-- perform only on a release stage when using the maven-release-plugin --> + <profile> + <id>release-profile</id> + <activation> + <property> + <name>performRelease</name> + <value>true</value> + </property> + </activation> + + <build> + <plugins> + + <!-- always compute tests source jar --> + <plugin> + <artifactId>maven-source-plugin</artifactId> + <executions> + <execution> + <id>attach-test-sources</id> + </execution> + </executions> + </plugin> + + </plugins> + </build> + </profile> + </profiles> + +</project> diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/Base64Coder.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/Base64Coder.java new file mode 100644 index 0000000..1d9d0f8 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/Base64Coder.java @@ -0,0 +1,240 @@ +package jaxx; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +/** + * A Base64 Encoder/Decoder. + * <p/> + * <p/> + * This class is used to encode and decode data in Base64 format as described in RFC 1521. + * <p/> + * <p/> + * This is "Open Source" software and released under the <a href="http://www.gnu.org/licenses/lgpl.html">GNU/LGPL</a> license.<br> + * It is provided "as is" without warranty of any kind.<br> + * Copyright 2003: Christian d'Heureuse, Inventec Informatik AG, Switzerland.<br> + * Home page: <a href="http://www.source-code.biz">www.source-code.biz</a><br> + * <p/> + * <p/> + * Version history:<br> + * 2003-07-22 Christian d'Heureuse (chdh): Module created.<br> + * 2005-08-11 chdh: Lincense changed from GPL to LGPL.<br> + * 2006-11-21 chdh:<br> + * Method encode(String) renamed to encodeString(String).<br> + * Method decode(String) renamed to decodeString(String).<br> + * New method encode(byte[],int) added.<br> + * New method decode(String) added.<br> + */ + +public class Base64Coder { + + // Mapping table from 6-bit nibbles to Base64 characters. + private static char[] map1 = new char[64]; + + static { + int i = 0; + for (char c = 'A'; c <= 'Z'; c++) { + map1[i++] = c; + } + for (char c = 'a'; c <= 'z'; c++) { + map1[i++] = c; + } + for (char c = '0'; c <= '9'; c++) { + map1[i++] = c; + } + map1[i++] = '+'; + map1[i] = '/'; + } + + // Mapping table from Base64 characters to 6-bit nibbles. + private static byte[] map2 = new byte[128]; + + static { + for (int i = 0; i < map2.length; i++) { + map2[i] = -1; + } + for (int i = 0; i < 64; i++) { + map2[map1[i]] = (byte) i; + } + } + + /** + * Read the object from Base64 string. + * + * @param s the string representation of serialized object. + * @param gzip if gzip stream + * @return the deserialize object + * @throws java.io.IOException if any io pb + * @throws ClassNotFoundException if class not found ? + */ + public static Object deserialize(String s, boolean gzip) throws IOException, + ClassNotFoundException { + byte[] data = Base64Coder.decode(s); + InputStream stream = new ByteArrayInputStream(data); + if (gzip) { + stream = new GZIPInputStream(stream); + } + ObjectInputStream ois = new ObjectInputStream(stream); + Object o = ois.readObject(); + ois.close(); + return o; + } + + /** + * Write the object to a Base64 string. + * + * @param o the object to serialize + * @param gzip if gzip stream + * @return the string representation + * @throws java.io.IOException if any io pb + */ + public static String serialize(Object o, boolean gzip) throws IOException { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + ObjectOutputStream oos; + if (gzip) { + oos = new ObjectOutputStream(new GZIPOutputStream(stream)); + } else { + oos = new ObjectOutputStream(stream); + } + oos.writeObject(o); + oos.close(); + return new String(Base64Coder.encode(stream.toByteArray())); + } + + /** + * Encodes a string into Base64 format. + * No blanks or line breaks are inserted. + * + * @param s a String to be encoded. + * @return A String with the Base64 encoded data. + */ + public static String encodeString(String s) { + return new String(encode(s.getBytes())); + } + + /** + * Encodes a byte array into Base64 format. + * No blanks or line breaks are inserted. + * + * @param in an array containing the data bytes to be encoded. + * @return A character array with the Base64 encoded data. + */ + public static char[] encode(byte[] in) { + return encode(in, in.length); + } + + /** + * Encodes a byte array into Base64 format. + * No blanks or line breaks are inserted. + * + * @param in an array containing the data bytes to be encoded. + * @param iLen number of bytes to process in <code>in</code>. + * @return A character array with the Base64 encoded data. + */ + public static char[] encode(byte[] in, int iLen) { + int oDataLen = (iLen * 4 + 2) / 3; // output length without padding + int oLen = ((iLen + 2) / 3) * 4; // output length including padding + char[] out = new char[oLen]; + int ip = 0; + int op = 0; + while (ip < iLen) { + int i0 = in[ip++] & 0xff; + int i1 = ip < iLen ? in[ip++] & 0xff : 0; + int i2 = ip < iLen ? in[ip++] & 0xff : 0; + int o0 = i0 >>> 2; + int o1 = ((i0 & 3) << 4) | (i1 >>> 4); + int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6); + int o3 = i2 & 0x3F; + out[op++] = map1[o0]; + out[op++] = map1[o1]; + out[op] = op < oDataLen ? map1[o2] : '='; + op++; + out[op] = op < oDataLen ? map1[o3] : '='; + op++; + } + return out; + } + + /** + * Decodes a string from Base64 format. + * + * @param s a Base64 String to be decoded. + * @return A String containing the decoded data. + * @throws IllegalArgumentException if the input is not valid Base64 encoded data. + */ + public static String decodeString(String s) { + return new String(decode(s)); + } + + /** + * Decodes a byte array from Base64 format. + * + * @param s a Base64 String to be decoded. + * @return An array containing the decoded data bytes. + * @throws IllegalArgumentException if the input is not valid Base64 encoded data. + */ + public static byte[] decode(String s) { + return decode(s.toCharArray()); + } + + /** + * Decodes a byte array from Base64 format. + * No blanks or line breaks are allowed within the Base64 encoded data. + * + * @param in a character array containing the Base64 encoded data. + * @return An array containing the decoded data bytes. + * @throws IllegalArgumentException if the input is not valid Base64 encoded data. + */ + public static byte[] decode(char[] in) { + int iLen = in.length; + if (iLen % 4 != 0) { + throw new IllegalArgumentException("Length of Base64 encoded input string is not a multiple of 4."); + } + while (iLen > 0 && in[iLen - 1] == '=') { + iLen--; + } + int oLen = (iLen * 3) / 4; + byte[] out = new byte[oLen]; + int ip = 0; + int op = 0; + while (ip < iLen) { + int i0 = in[ip++]; + int i1 = in[ip++]; + int i2 = ip < iLen ? in[ip++] : 'A'; + int i3 = ip < iLen ? in[ip++] : 'A'; + if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127) { + throw new IllegalArgumentException("Illegal character in Base64 encoded data."); + } + int b0 = map2[i0]; + int b1 = map2[i1]; + int b2 = map2[i2]; + int b3 = map2[i3]; + if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0) { + throw new IllegalArgumentException("Illegal character in Base64 encoded data."); + } + int o0 = (b0 << 2) | (b1 >>> 4); + int o1 = ((b1 & 0xf) << 4) | (b2 >>> 2); + int o2 = ((b2 & 3) << 6) | b3; + out[op++] = (byte) o0; + if (op < oLen) { + out[op++] = (byte) o1; + } + if (op < oLen) { + out[op++] = (byte) o2; + } + } + return out; + } + + // Dummy constructor. + private Base64Coder() { + } + +} // end class Base64Coder + diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/css/Rule.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/css/Rule.java new file mode 100644 index 0000000..230b93a --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/css/Rule.java @@ -0,0 +1,54 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.css; + +import java.util.Map; + +public class Rule implements java.io.Serializable, Comparable<Rule> { + public static final String INLINE_ATTRIBUTE = "<inline attribute>"; + public static final String DATA_BINDING = "<data binding>"; + + private Selector[] selectors; + private Map<String, String> properties; + private static final long serialVersionUID = 1L; + + + public Rule(Selector[] selectors, Map<String, String> properties) { + this.selectors = selectors; + java.util.Arrays.sort(selectors); + this.properties = properties; + } + + + public Rule(Selector[] selectors, String[] keys, String[] values) { + this.selectors = selectors; + java.util.Arrays.sort(selectors); + this.properties = new java.util.HashMap<String, String>(); + if (keys.length != values.length) { + throw new IllegalArgumentException("keys and values must have the same number of entries"); + } + for (int i = 0; i < keys.length; i++) { + properties.put(keys[i], values[i]); + } + } + + public Selector[] getSelectors() { + return selectors; + } + + public Map<String, String> getProperties() { + return properties; + } + + @Override + public int compareTo(Rule o) { + return selectors[0].compareTo(o.selectors[0]); // they are already sorted so we only need to compare the highest-ranked from each one + } + + @Override + public String toString() { + return "Rule[" + java.util.Arrays.asList(selectors) + ", " + properties + "]"; + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/css/Selector.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/css/Selector.java new file mode 100644 index 0000000..b00235b --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/css/Selector.java @@ -0,0 +1,99 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.css; + +public class Selector implements java.io.Serializable, Comparable<Selector> { + public static final int NEVER_APPLIES = 0; + public static final int PSEUDOCLASS_APPLIES_INHERIT_ONLY = 1; + public static final int PSEUDOCLASS_APPLIES = 2; + public static final int ALWAYS_APPLIES_INHERIT_ONLY = 3; + public static final int ALWAYS_APPLIES = 4; + + private String javaClassName; + private String styleClass; + private String pseudoClass; + private String id; + private boolean inline; + private static final long serialVersionUID = 1L; + + + public Selector(String javaClassName, String styleClass, String pseudoClass, String id) { + this(javaClassName, styleClass, pseudoClass, id, false); + } + + + public Selector(String javaClassName, String styleClass, String pseudoClass, String id, boolean inline) { + this.javaClassName = javaClassName; + this.styleClass = styleClass; + this.pseudoClass = pseudoClass; + this.id = id; + this.inline = inline; + } + + + public String getJavaClassName() { + return javaClassName; + } + + + public String getStyleClass() { + return styleClass; + } + + + public String getPseudoClass() { + return pseudoClass; + } + + + public String getId() { + return id; + } + + + public boolean isInline() { + return inline; + } + + @Override + public int compareTo(Selector selector) { + if (inline && !selector.inline) { + return 1; + } + if (!inline && selector.inline) { + return -1; + } + if (pseudoClass != null && selector.pseudoClass == null) { + return 1; + } + if (pseudoClass == null && selector.pseudoClass != null) { + return -1; + } + if (id != null && selector.id == null) { + return 1; + } + if (id == null && selector.id != null) { + return -1; + } + if (styleClass != null && selector.styleClass == null) { + return 1; + } + if (styleClass == null && selector.styleClass != null) { + return -1; + } + if (javaClassName != null && selector.javaClassName == null) { + return 1; + } + if (javaClassName == null && selector.javaClassName != null) { + return -1; + } + return 0; + } + + @Override + public String toString() { + return "Selector[" + javaClassName + ", " + styleClass + ", " + pseudoClass + ", " + id + "]"; + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/css/Stylesheet.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/css/Stylesheet.java new file mode 100644 index 0000000..8d8f930 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/css/Stylesheet.java @@ -0,0 +1,45 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.css; + +public class Stylesheet implements java.io.Serializable { + private Rule[] rules; + private static final long serialVersionUID = 1L; + + + public Stylesheet() { + rules = new Rule[0]; + } + + public Stylesheet(Rule[] rules) { + this.rules = rules; + java.util.Arrays.sort(rules); + } + + public Rule[] getRules() { + return rules; + } + + public void add(Rule newRule) { + Rule[] oldRules = rules; + rules = new Rule[oldRules.length + 1]; + System.arraycopy(oldRules, 0, rules, 0, oldRules.length); + rules[rules.length - 1] = newRule; + java.util.Arrays.sort(rules); + } + + public void add(Rule[] newRules) { + Rule[] oldRules = rules; + rules = new Rule[oldRules.length + newRules.length]; + System.arraycopy(oldRules, 0, rules, 0, oldRules.length); + System.arraycopy(newRules, 0, rules, oldRules.length, newRules.length); + java.util.Arrays.sort(rules); + } + + @Override + public String toString() { + return "Stylesheet" + java.util.Arrays.asList(rules); + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/BeanValidatorUtil.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/BeanValidatorUtil.java new file mode 100644 index 0000000..a819d04 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/BeanValidatorUtil.java @@ -0,0 +1,176 @@ +package jaxx.runtime; + +import jaxx.runtime.*; +import com.opensymphony.xwork2.config.Configuration; +import com.opensymphony.xwork2.config.ConfigurationManager; +import com.opensymphony.xwork2.util.ValueStack; +import com.opensymphony.xwork2.util.ValueStackFactory; +import jaxx.runtime.validator.*; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.beans.BeanInfo; +import java.beans.EventSetDescriptor; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; + +/** + * The helper class for validation module. + * + * @author chemit + */ +public class BeanValidatorUtil { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private final Log log = LogFactory.getLog(BeanValidatorUtil.class); + /** + * a shared value stack to allow external operations on it (for example + * add some datas in stack to be usedby validators + */ + static private ValueStack sharedValueStack; + + public static synchronized ValueStack getSharedValueStack() { + if (sharedValueStack == null) { + + // init context + ConfigurationManager confManager = new ConfigurationManager(); + Configuration conf = confManager.getConfiguration(); + + sharedValueStack = conf.getContainer().getInstance(ValueStackFactory.class).createValueStack(); + if (log.isDebugEnabled()) { + log.debug("init shared value stack " + sharedValueStack); + } + } + return sharedValueStack; + } + + protected BeanValidatorUtil() { + // no instance + } + + /** + * Convinient method to attach a bean to all validators of an JAXXObject. + * <p/> + * It is possible to exclude some validator to be treated. + * + * @param ui the ui containing the validatros to treate + * @param bean the bean to attach in validators (can be null) + * @param excludeIds the list of validator id to exclude + */ + @SuppressWarnings({"unchecked"}) + public static void setValidatorBean(JAXXObject ui, Object bean, String... excludeIds) { + if (!JAXXValidator.class.isAssignableFrom(ui.getClass())) { + return; + } + JAXXValidator jaxxValidator = (JAXXValidator) ui; + List<String> validatorIds = jaxxValidator.getValidatorIds(); + if (excludeIds.length > 0) { + validatorIds = new ArrayList<String>(validatorIds); + for (String excludeId : excludeIds) { + validatorIds.remove(excludeId); + } + } + for (String validatorId : validatorIds) { + BeanValidator beanValidator = jaxxValidator.getValidator(validatorId); + if (bean == null || beanValidator.getBeanClass().isAssignableFrom(bean.getClass())) { + // touch validator, only if fits the bean type (or bean is null) + beanValidator.setBean(bean); + } + } + } + + /** + * Convinient method to set the changed property to all validators of an JAXXObject. + * <p/> + * It is possible to exclude some validator to be treated. + * + * @param ui the ui containing the validatros to treate + * @param newValue the new value to set in changed validator property + * @param excludeIds the list of validator id to exclude + */ + @SuppressWarnings({"unchecked"}) + public static void setValidatorChanged(JAXXObject ui, boolean newValue, String... excludeIds) { + if (!JAXXValidator.class.isAssignableFrom(ui.getClass())) { + return; + } + JAXXValidator jaxxValidator = (JAXXValidator) ui; + List<String> validatorIds = jaxxValidator.getValidatorIds(); + if (excludeIds.length > 0) { + validatorIds = new ArrayList<String>(validatorIds); + for (String excludeId : excludeIds) { + validatorIds.remove(excludeId); + } + } + for (String validatorId : validatorIds) { + BeanValidator beanValidator = jaxxValidator.getValidator(validatorId); + beanValidator.setChanged(newValue); + } + } + + /** + * Convert a value to a given type and then if was succesffull try to set it in the bean manage by the validator. + * + * @param validator validator to be involved + * @param fieldName the name of the bean property + * @param value the actual value to convert + * @param valueClass the type of the conversion + */ + public static void convert(BeanValidator<?> validator, String fieldName, String value, Class<?> valueClass) { + + Object result = validator.convert(fieldName, value, valueClass); + if (result != null) { + try { + BeanInfo info = Introspector.getBeanInfo(validator.getBean().getClass()); + + for (PropertyDescriptor descriptor : info.getPropertyDescriptors()) { + if (fieldName.equals(descriptor.getName()) && descriptor.getWriteMethod() != null) { + + descriptor.getWriteMethod().invoke(validator.getBean(), result); + break; + } + } + } catch (IntrospectionException e) { + log.error("could not obtain beanInfo for " + valueClass.getClass() + ", reason : " + e.getMessage(), e); + } catch (InvocationTargetException e) { + log.error("could not obtain beanInfo for " + valueClass.getClass() + ", reason : " + e.getMessage(), e); + } catch (IllegalAccessException e) { + log.error("could not obtain beanInfo for " + valueClass.getClass() + ", reason : " + e.getMessage(), e); + } + } else { + //fixme : conversion failed, we should be able to notify ui that values has changed ? + // otherwise, bean value has not changed,... + } + } + + public static EventSetDescriptor getPropertyChangeListenerDescriptor(Class beanClass) { + try { + // check that the bean is listenable, otherwise, can't use + // the validator on it + BeanInfo infos = Introspector.getBeanInfo(beanClass); + EventSetDescriptor[] events = infos.getEventSetDescriptors(); + for (EventSetDescriptor event : events) { + if ("propertyChange".equals(event.getName())) { + + if (event.getAddListenerMethod() == null) { + // no property event listener, so can not use the validator + throw new IllegalStateException("no addPropertyChangeListener method found for " + beanClass); + } + if (event.getRemoveListenerMethod() == null) { + // no property event listener, so can not use the validator + throw new IllegalStateException("no removePropertyChangeListener method found for " + beanClass); + } + return event; + } + } + + // no property event listener, so can not use the validator + throw new IllegalStateException("no PropertyChangeListener access method found for " + beanClass); + } catch (IntrospectionException ex) { + throw new IllegalStateException("could not acquire PropertyChangeListener bean info for " + beanClass + " for reason " + ex.getMessage(), ex); + } + } +} diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/ComponentDescriptor.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/ComponentDescriptor.java new file mode 100644 index 0000000..57e22ca --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/ComponentDescriptor.java @@ -0,0 +1,49 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime; + +import java.io.Serializable; + +public class ComponentDescriptor implements Serializable { + String id; + String javaClassName; + String styleClass; + ComponentDescriptor parent; + private static final long serialVersionUID = 1L; + + + public ComponentDescriptor(String id, String javaClassName, String styleClass, ComponentDescriptor parent) { + this.id = id; + this.javaClassName = javaClassName; + this.styleClass = styleClass; + this.parent = parent; + } + + + public String getId() { + return id; + } + + + public String getJavaClassName() { + return javaClassName; + } + + + public String getStyleClass() { + return styleClass; + } + + + public ComponentDescriptor getParent() { + return parent; + } + + + @Override + public String toString() { + return "ComponentDescriptor[" + id + ", " + javaClassName + ", " + styleClass + "]"; + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/DataBindingListener.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/DataBindingListener.java new file mode 100644 index 0000000..d5694ae --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/DataBindingListener.java @@ -0,0 +1,46 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + + +/** + * A <code>PropertyChangeListener</code> which processes a data binding when it receives a + * <code>PropertyChangeEvent</code>. + */ +public class DataBindingListener implements PropertyChangeListener { + private JAXXObject object; + private String dest; + + /** + * Creates a new <code>DataBindingListener</code> which will run the given data binding + * when it receives a <code>PropertyChangeEvent</code>. + * + * @param object the object in which the data binding exists + * @param dest the name of the data binding to run + */ + public DataBindingListener(JAXXObject object, String dest) { + this.object = object; + this.dest = dest; + } + + + /** + * Processes the data binding in response to a <code>PropertyChangeEvent</code>. + * + * @param e the event which triggered the binding + */ + public void propertyChange(PropertyChangeEvent e) { + object.processDataBinding(dest); + + // for now, handle dependency changes by always removing & reapplying + // the binding. We should be more efficient and only do this when it's + // actually necessary + object.removeDataBinding(dest); + object.applyDataBinding(dest); + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/DataBindingUpdateListener.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/DataBindingUpdateListener.java new file mode 100644 index 0000000..f220ecc --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/DataBindingUpdateListener.java @@ -0,0 +1,46 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + + +/** + * A <code>PropertyChangeListener</code> which removes and re-applies a data binding + * when it receives a <code>PropertyChangeEvent</code>. + */ +public class DataBindingUpdateListener implements PropertyChangeListener { + private JAXXObject object; + private String dest; + + /** + * Creates a new <code>DataBindingUpdateListener</code> which will remove and re-apply a + * data binding when it receives a <code>PropertyChangeEvent</code>. + * + * @param object the object in which the data binding exists + * @param dest the name of the data binding to reapply + */ + public DataBindingUpdateListener(JAXXObject object, String dest) { + this.object = object; + this.dest = dest; + } + + + public String getBindingName() { + return dest; + } + + + /** + * Updates the data binding in response to a <code>PropertyChangeEvent</code>. + * + * @param e the event which triggered the binding + */ + public void propertyChange(PropertyChangeEvent e) { + object.removeDataBinding(dest); + object.applyDataBinding(dest); + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/DataContext.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/DataContext.java new file mode 100644 index 0000000..4d014d0 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/DataContext.java @@ -0,0 +1,400 @@ +package jaxx.runtime; + +import java.awt.Container; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.regex.Pattern; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Un contexte de données qui permet l'utilisation des bindings sur les + * entrées du contexte. + * + * TODO javadoc + * + * @author tony + * @since 1.3 + */ +public abstract class DataContext { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(DataContext.class); + /** le context qui contient les données */ + protected final DefaultJAXXContext delegate; + /** la definition de l'entree actuallement selectionnee */ + protected DataContextEntry<?> currentEntry; + /** to manage properties modifications */ + protected final PropertyChangeSupport pcs; + protected DataContextEntry<?>[] entries; + protected final String[] DEFAULT_JAXX_PCS; + + public abstract String getContextPath(Object... e); + + public DataContext(String[] DEFAULT_JAXX_PCS, DataContextEntry<?>[] entries) { + this.DEFAULT_JAXX_PCS = DEFAULT_JAXX_PCS; + this.entries = entries; + delegate = new DefaultJAXXContext() { + + @Override + protected void setUi(JAXXObject ui) { + throw new IllegalStateException("can not use this method for this type of context"); + } + + @Override + public <O extends Container> O getParentContainer(Class<O> clazz) { + throw new IllegalStateException("can not use this method for this type of context"); + } + + @Override + public <O extends Container> O getParentContainer(Object top, Class<O> clazz) { + throw new IllegalStateException("can not use this method for this type of context"); + } + + @Override + protected JAXXObject getUi() { + throw new IllegalStateException("can not use this method for this type of context"); + } + + @Override + protected void setParentContext(JAXXContext parentContext) { + throw new IllegalStateException("can not use this method for this type of context"); + } + + @Override + protected JAXXContext getParentContext() { + return null; + } + + @Override + public <T> void removeContextValue(Class<T> klazz, String name) { + if (log.isTraceEnabled()) { + log.trace(klazz + " - " + name); + } + super.removeContextValue(klazz, name); + } + + @Override + public <T> void setContextValue(T o, String name) { + if (log.isTraceEnabled()) { + log.trace(name + " - " + o.getClass()); + } + super.setContextValue(o, name); + } + }; + pcs = new PropertyChangeSupport(this); + } + + public DefaultJAXXContext getDelegate() { + return delegate; + } + + public Iterable<? extends DataContextEntry<?>> iterateOnAll() { + return new Iterable<DataContextEntry<?>>() { + + @Override + public Iterator<DataContextEntry<?>> iterator() { + return new DataContextEntryIterator(entries); + } + }; + } + + public Iterable<? extends DataContextEntry<?>> iterateToLevel(final int level) { + return new Iterable<DataContextEntry<?>>() { + + @Override + public Iterator<DataContextEntry<?>> iterator() { + return new DataContextEntryIterator(entries, level); + } + }; + } + + public Iterable<? extends DataContextEntry<?>> reverseIterateOnAll() { + + return new Iterable<DataContextEntry<?>>() { + + @Override + public Iterator<DataContextEntry<?>> iterator() { + return new DataContextEntryIterator(entries, true); + } + }; + } + + public DataContextEntry<?> getCurrentEntry() { + return currentEntry; + } + + public DataContextEntry<?> getEntry(String path) { + for (DataContextEntry<?> scope : reverseIterateOnAll()) { + if (scope.acceptPath(path)) { + return scope; + } + } + return null; + } + + public DataContextEntry<?> getEntry(Class<?> type) { + for (DataContextEntry<?> scope : iterateOnAll()) { + if (scope.acceptType(type)) { + return scope; + } + } + return null; + } + + public <T> T getContextValue(DataContextEntry<T> entry, String key) { + String contextKey = getKey(entry, key); + T result = delegate.getContextValue(entry.getKlass(), contextKey); + return result; + } + + public void setContextValue(DataContextEntry entry, Object value, String key) { + String contextKey = getKey(entry, key); + delegate.setContextValue(value, contextKey); + } + + public void removeContextValue(DataContextEntry entry, Object value, String key) { + String contextKey = getKey(entry, key); + delegate.removeContextValue(value.getClass(), contextKey); + } + + @SuppressWarnings("unchecked") + public void updateSelectedData(String path, Object data, UpdateDataContext updator) { + + if (log.isDebugEnabled()) { + log.debug("----------------------------------------------------------------"); + } + if (currentEntry != null) { + + if (log.isDebugEnabled()) { + log.debug("remove from old entry " + currentEntry); + } + for (DataContextEntry<?> s : currentEntry) { + if (log.isDebugEnabled()) { + log.debug("remove entry " + s); + } + updator.onRemovingData(this, s); + } + } + + currentEntry = getEntry(path); + + if (log.isDebugEnabled()) { + log.debug("new entry " + currentEntry + " for path " + path); + } + + if (currentEntry != null) { + + for (DataContextEntry<?> s : iterateToLevel(currentEntry.getLevel())) { + + if (log.isDebugEnabled()) { + log.debug("add entry " + s); + } + updator.onAddingData(this, s, path); + } + } + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + pcs.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + pcs.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.removePropertyChangeListener(propertyName, listener); + } + + public synchronized boolean hasListeners(String propertyName) { + return pcs.hasListeners(propertyName); + } + + public synchronized PropertyChangeListener[] getPropertyChangeListeners(String propertyName) { + return pcs.getPropertyChangeListeners(propertyName); + } + + public synchronized PropertyChangeListener[] getPropertyChangeListeners() { + return pcs.getPropertyChangeListeners(); + } + + public void removeJaxxPropertyChangeListener() { + PropertyChangeListener[] toRemove = Util.findJaxxPropertyChangeListener(DEFAULT_JAXX_PCS, getPropertyChangeListeners()); + if (toRemove == null || toRemove.length == 0) { + return; + } + if (log.isDebugEnabled()) { + log.debug("before remove : " + getPropertyChangeListeners().length); + log.debug("toRemove : " + toRemove.length); + } + for (PropertyChangeListener listener : toRemove) { + removePropertyChangeListener(listener); + } + if (log.isDebugEnabled()) { + log.debug("after remove : " + getPropertyChangeListeners().length); + } + } + + protected void firePropertyChange(String name, Object oldValue, Object newValue) { + pcs.firePropertyChange(name, oldValue, newValue); + } + + protected String getKey(DataContextEntry entry, String key) { + String result = null; + if (key != null) { + result = entry.hashCode() + "#" + key; + } + return result; + } + + public void close() throws Exception { + clear(); + + // suppression des ecouteurs + + for (PropertyChangeListener l : getPropertyChangeListeners()) { + removePropertyChangeListener(l); + } + } + + public void clear() { + delegate.clear(); + } + + public static abstract class DataContextEntry<E> implements Iterable<DataContextEntry<?>> { + + private final int level; + private final DataContextEntry<?> previous; + private final DataContextEntry[] parents; + private Class<E> klass; + + public DataContextEntry(Class<E> klass, DataContextEntry<?> previous) { + this.previous = previous; + this.level = previous.level + 1; + this.klass = klass; + this.parents = new DataContextEntry[level]; + int i = level; + while (i > 0) { + parents[--i] = previous; + previous = previous.previous; + } + } + + public DataContextEntry(Class<E> klass) { + this.level = 0; + this.klass = klass; + this.previous = null; + this.parents = new DataContextEntry[0]; + } + + public Class<E> getKlass() { + return klass; + } + + public int getLevel() { + return level; + } + + public DataContextEntry[] getParents() { + return parents; + } + + public abstract Pattern getPattern(); + + public abstract String getContextPath(Object... args); + + public boolean acceptPath(String path) { + return getPattern().matcher(path).matches(); + } + + public boolean acceptType(Class<?> type) { + return klass.isAssignableFrom(type); + } + + @Override + public Iterator<DataContextEntry<?>> iterator() { + int length = parents.length; + DataContextEntry[] t = new DataContextEntry[length + 1]; + System.arraycopy(parents, 0, t, 0, length); + t[length] = this; + return new DataContextEntryIterator(t, true); + } + + @Override + public String toString() { + return super.toString() + "<type: " + klass.getSimpleName() + ">"; + } + } + + public static interface UpdateDataContext<D extends DataContext> { + + void onRemovingData(D context, DataContextEntry<?> entry); + + void onAddingData(D context, DataContextEntry entry, String path); + } + + public static class DataContextEntryIterator implements Iterator<DataContextEntry<?>> { + + protected final DataContextEntry[] datas; + protected final boolean reverse; + protected final int level; + protected int index; + + public DataContextEntryIterator(DataContextEntry[] datas) { + this(datas, false, -1); + } + + public DataContextEntryIterator(DataContextEntry[] datas, int level) { + this(datas, false, level); + } + + public DataContextEntryIterator(DataContextEntry[] datas, boolean reverse) { + this(datas, reverse, -1); + } + + DataContextEntryIterator(DataContextEntry[] datas, boolean reverse, int level) { + this.datas = datas; + this.reverse = reverse; + if (reverse) { + index = datas.length; + } else { + index = -1; + } + this.level = level; + } + + @Override + public boolean hasNext() { + if (reverse) { + return index > 0; + } else { + return index + 1 < datas.length && (level == -1 || datas[index + 1].getLevel() <= level); + } + } + + @Override + public DataContextEntry<?> next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + if (reverse) { + index--; + } else { + index++; + } + return datas[index]; + } + + @Override + public void remove() { + throw new UnsupportedOperationException("Not supported yet."); + } + } +} diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/Decorator.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/Decorator.java new file mode 100644 index 0000000..8cd51bb --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/Decorator.java @@ -0,0 +1,36 @@ +package jaxx.runtime; + +/** + * A simple contract to define a String decorator on any java objet. + * + * @param <O> the type of decorated object + * @author chemit + */ +public abstract class Decorator<O> implements java.io.Serializable { + + protected final Class<O> internalClass; + private static final long serialVersionUID = -1L; + + /** + * @param internalClass the class of objects to be decorated. + * @throws NullPointerException if internalClass parameter is null + */ + public Decorator(Class<O> internalClass) throws NullPointerException { + if (internalClass == null) { + throw new NullPointerException("internalClass can not be null."); + } + this.internalClass = internalClass; + } + + /** + * @param bean the bean to decorate + * @return the string value of the given bean + */ + public abstract String toString(Object bean); + + + public final Class<O> getInternalClass() { + return internalClass; + } + +} diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/DecoratorUtils.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/DecoratorUtils.java new file mode 100644 index 0000000..f1e1916 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/DecoratorUtils.java @@ -0,0 +1,111 @@ +package jaxx.runtime; + +import java.util.List; + +/** + * + * Some usefull methods on {@link Decorator} to store and obtain decorators. + * + * Use the method {@link #registerDecorator(String, Decorator)} to register a new + * decorator. + * + * Use the method {@link #getDecorator(String)} to obtain a registred + * decorator based on his registred name. + * + * Use the method {@link #getDecorator(Class, tring)} to obtain a registred + * decorator based on the type of decorator and the registred name. + * + * @author tony + * @since 1.3 + */ +public class DecoratorUtils { + + protected static List<DecoratorContext<?>> cache; + + public static <T> void registerDecorator(String context, Decorator<T> decorator) { + DecoratorContext<T> result = getDecoratorContext(decorator.getInternalClass(), context); + + if (result != null) { + throw new IllegalArgumentException("there is an already register decorator " + result); + } + + if (cache == null) { + cache = new java.util.ArrayList<DecoratorContext<?>>(); + } + cache.add(new DecoratorContext<T>(context, decorator)); + } + + public static <T> Decorator<T> getDecorator(String context) { + Decorator<T> result = getDecorator(null, context); + return result; + } + + public static <T> Decorator<T> getDecorator(Class<T> type, String context) { + DecoratorContext<T> decoratorContext = getDecoratorContext(type, context); + Decorator<T> result = decoratorContext == null ? null : decoratorContext.getDecorator(); + return result; + } + + public static void clear() { + if (cache != null) { + cache.clear(); + } + } + + @SuppressWarnings({"unchecked"}) + protected static <T> DecoratorContext<T> getDecoratorContext(Class<T> type, String context) { + DecoratorContext<T> result = null; + if (cache != null) { + for (DecoratorContext<?> d : cache) { + if (type == null) { + if (d.accept(context)) { + result = (DecoratorContext<T>) d; + break; + } + continue; + } + if (d.accept(type, context)) { + result = (DecoratorContext<T>) d; + break; + } + } + } + return result; + } + + public static class DecoratorContext<T> { + + final String context; + final Decorator<T> decorator; + + public DecoratorContext(String context, Decorator<T> decorator) { + this.context = context; + this.decorator = decorator; + } + + public String getContext() { + return context; + } + + public Decorator<T> getDecorator() { + return decorator; + } + + public Class<T> getType() { + return decorator.getInternalClass(); + } + + public boolean accept(Class<?> type, String context) { + return getType().isAssignableFrom(type) && accept(context); + } + + public boolean accept(String context) { + return ((this.context == null && context == null) || (this.context != null && this.context.equals(context))); + } + + @Override + public String toString() { + return super.toString() + "<type: " + getType().getName() + ", context :" + context + ">"; + } + } +} diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/DefaultApplicationContext.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/DefaultApplicationContext.java new file mode 100644 index 0000000..895a32e --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/DefaultApplicationContext.java @@ -0,0 +1,281 @@ +package jaxx.runtime; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.lang.annotation.*; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * The default context to be used for an application. + * + * This extends the {@link DefaultJAXXContext} and add a possibility to auto-instanciate + * some classes asked via {@link #getContextValue(java.lang.Class)} and + * {@link #getContextValue(java.lang.Class, java.lang.String)} methods. + * + * To registred a such class, just annotate your class with {@link AutoLoad}. + * + * @author chemit + * @since 1.2 + * @see DefaultJAXXContext + */ +public class DefaultApplicationContext extends DefaultJAXXContext { + + /** + * A class annotated @AutoLoad is used by context to auto + * instanciate the class when required. + * + * Note : A such class always have a public default constructor. + * + * @author chemit + * @version 1.0, 21/02/09 + * @since 1.2 + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + public static @interface AutoLoad { + //TODO use this to add a method to init + + String initMethod() default ""; + } + + /** + * A class annotated @MethodAccess is used by context to obtain the value + * of an entry via a declared method. + * + * Note : A such class must have a method called {@link #methodName()} with + * a single String parameter. + * + * @author chemit + * @version 1.0, 21/02/09 + * @since 1.2 + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + public static @interface MethodAccess { + + /** + * Define a forward to a target class. When the target class + * will be asked with method {@link #getContextValue(java.lang.Class, java.lang.String)} + * it will be delegating to this class. + * + * @return the forwarded class + */ + Class<?> target() default Object.class; + + /** + * @return the name of the method to access data + */ + String methodName(); + } + /** + * Map of forwarded classes (key) to classes (values). + */ + protected Map<Class, Class> forwards; + + public DefaultApplicationContext() { + super(); + forwards = new HashMap<Class, Class>(); + pcs = new PropertyChangeSupport(this); + } + + public DefaultApplicationContext(JAXXObject ui) { + super(ui); + } + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private final Log log = LogFactory.getLog(DefaultApplicationContext.class); + + /** to manage properties modifications */ + protected PropertyChangeSupport pcs; + + @SuppressWarnings({"unchecked"}) + @Override + public <T> T getContextValue(Class<T> clazz, String name) { + Object value = null; + MethodAccess access; + + Class<?> realClass; + + if (forwards.containsKey(clazz)) { + // this is a forward class + realClass = forwards.get(clazz); + // always call the forwarder with no name + value = getContextValue(realClass, null); + if (log.isDebugEnabled()) { + log.debug("detect forward from " + clazz + " to " + realClass + " (" + value + ")"); + } + + } else { + realClass = clazz; + value = super.getContextValue(realClass, name); + } + + if (value == null) { + AutoLoad anno = clazz.getAnnotation(AutoLoad.class); + + if (anno == null) { + // no annotation, so do nothing + return null; + } + + if (name != null) { + throw new IllegalArgumentException("an " + AutoLoad.class.getName() + " can not have a named context but was call with this one : " + name); + } + value = newInstance(clazz); + if (!anno.initMethod().trim().isEmpty()){ + // apply method on class + newAccess(clazz, value, anno.initMethod().trim()); + } + if (log.isDebugEnabled()) { + log.debug("new instance " + clazz + " : " + value); + } + // save new instance + setContextValue(value, null); + } + + access = realClass.getAnnotation(MethodAccess.class); + + if (access != null) { + if (name == null) { + if (access.target() != Object.class) { + // register forward + Class<?> targetClass = access.target(); + if (!forwards.containsKey(targetClass)) { + // register forward + forwards.put(targetClass, clazz); + if (log.isDebugEnabled()) { + log.debug("register forward from " + targetClass + " to " + clazz); + } + } + } + } else { + // specialized access + value = newAccess(realClass, value, access.methodName(), name); + } + } + return (T) value; + } + + @Override + public <T> void removeContextValue(Class<T> klazz, String name) { + Entry<Class, Class> entry; + if (name == null && forwards.containsValue(klazz)) { + // remove forward + Iterator<Entry<Class, Class>> itr = forwards.entrySet().iterator(); + while (itr.hasNext()) { + entry = itr.next(); + if (entry.getValue().equals(klazz)) { + itr.remove(); + if (log.isDebugEnabled()) { + log.debug("removed forward from " + entry.getKey() + " to " + klazz); + } + break; + } + } + } + //FIXME should update forwards state + super.removeContextValue(klazz, name); + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + pcs.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + pcs.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.removePropertyChangeListener(propertyName, listener); + } + + public synchronized boolean hasListeners(String propertyName) { + return pcs.hasListeners(propertyName); + } + + public synchronized PropertyChangeListener[] getPropertyChangeListeners(String propertyName) { + return pcs.getPropertyChangeListeners(propertyName); + } + + public synchronized PropertyChangeListener[] getPropertyChangeListeners() { + return pcs.getPropertyChangeListeners(); + } + + protected Object newInstance(Class<?> clazz) throws IllegalArgumentException { + + Object value = null; + + Constructor<?> constructor = null; + try { + constructor = clazz.getConstructor(); + // auto instanciate the class + if (constructor == null) { + throw new IllegalArgumentException(clazz + " has no public constructor"); + } + } catch (NoSuchMethodException ex) { + throw new IllegalArgumentException(ex); + } catch (SecurityException ex) { + throw new IllegalArgumentException(ex); + } + try { + value = constructor.newInstance(); + + } catch (InstantiationException ex) { + throw new IllegalArgumentException(ex); + } catch (IllegalAccessException ex) { + throw new IllegalArgumentException(ex); + } catch (InvocationTargetException ex) { + throw new IllegalArgumentException(ex); + } + return value; + } + + protected Object newAccess(Class<?> clazz, Object parent, String methodName, String name) throws IllegalArgumentException { + Object value; + try { + Method m = clazz.getMethod(methodName, String.class); + value = m.invoke(parent, name); + return value; + } catch (NoSuchMethodException ex) { + throw new IllegalArgumentException(ex); + } catch (SecurityException ex) { + throw new IllegalArgumentException(ex); + } catch (IllegalAccessException ex) { + throw new IllegalArgumentException(ex); + } catch (InvocationTargetException ex) { + throw new IllegalArgumentException(ex); + } + } + + protected Object newAccess(Class<?> clazz, Object parent, String methodName) throws IllegalArgumentException { + Object value; + try { + Method m = clazz.getMethod(methodName); + value = m.invoke(parent); + return value; + } catch (NoSuchMethodException ex) { + throw new IllegalArgumentException(ex); + } catch (SecurityException ex) { + throw new IllegalArgumentException(ex); + } catch (IllegalAccessException ex) { + throw new IllegalArgumentException(ex); + } catch (InvocationTargetException ex) { + throw new IllegalArgumentException(ex); + } + } + + protected void firePropertyChange(String name, Object oldValue, Object newValue) { + pcs.firePropertyChange(name, oldValue, newValue); + } +} diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/DefaultJAXXContext.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/DefaultJAXXContext.java new file mode 100644 index 0000000..1505751 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/DefaultJAXXContext.java @@ -0,0 +1,214 @@ +package jaxx.runtime; + +import static jaxx.runtime.JAXXContextEntryDef.newDef; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.awt.Container; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +/** + * The default {@link JAXXContext} to be used in a {@link JAXXObject} by delegation. + * <p/> + * The values are store in a {@link Map} but we can not use directly the values as key. + * <p/> + * Because, it does not work if we add for the same object multi entries (named and unamed)... + * <p/> + * We prefer use as entry the {@link JAXXContextEntryDef} associated with the value. + * + * @author chemit + */ +public class DefaultJAXXContext implements JAXXContext { + + protected static final JAXXContextEntryDef<JAXXContext> PARENT_CONTEXT_ENTRY = newDef(JAXXContext.class); + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private final Log log = LogFactory.getLog(DefaultJAXXContext.class); + /** l'ui auquel est rattache le context */ + protected JAXXObject ui; + /** le context parent */ + protected JAXXContext parentContext; + /** les données contenues dans le context */ + protected final Map<JAXXContextEntryDef, Object> data; + + public DefaultJAXXContext() { + data = new HashMap<JAXXContextEntryDef, Object>(); + } + + public DefaultJAXXContext(JAXXObject ui) { + this(); + this.ui = ui; + } + + @Override + public <T> void setContextValue(T o) { + setContextValue(o, null); + } + + @Override + public <T> void setContextValue(T o, String name) { + if (name == null && PARENT_CONTEXT_ENTRY.accept2(o.getClass(), null)) { + setParentContext((JAXXContext) o); + return; + } + JAXXContextEntryDef<?> entry = getKey(name, o.getClass()); + // first remove entry + Object oldValue = remove0(o.getClass(), name); + if (oldValue != null) { + if (log.isDebugEnabled()) { + log.debug("remove value " + oldValue.getClass() + " for " + entry); + } + } + // then can put safely + data.put(entry, o); + } + + @Override + public <T> T getContextValue(Class<T> clazz) { + return getContextValue(clazz, null); + } + + @SuppressWarnings({"unchecked"}) + @Override + public <T> T getContextValue(Class<T> clazz, String name) { + if (parentContext != null && parentContext.getClass() == clazz || PARENT_CONTEXT_ENTRY.accept(clazz, name)) { + return (T) getParentContext(); + } + for (Entry<JAXXContextEntryDef, Object> entry : data.entrySet()) { + if (entry.getKey().accept(clazz, name)) { + return (T) entry.getValue(); + } + } + + // no value found in this context, will try in the parent context + if (JAXXContext.class == clazz) { + // no seek in the parent context, since we are already looking for it + return null; + } + + JAXXContext parent = getParentContext(); + if (parent == null) { + // no parent context, so no value find + return null; + } + // seek in parent context + return parent.getContextValue(clazz, name); + } + + @Override + public <T> void removeContextValue(Class<T> klazz) { + removeContextValue(klazz, null); + } + + @Override + public <T> void removeContextValue(Class<T> klazz, String name) { + remove0(klazz, name); + } + + @Override + public <O extends Container> O getParentContainer(Class<O> clazz) { + return this.getParentContainer(ui, clazz); + } + + @SuppressWarnings({"unchecked"}) + @Override + public <O extends Container> O getParentContainer(Object top, Class<O> clazz) { + if (ui == null) { + throw new IllegalStateException("no ui attached to this context"); + } + if (top == null) { + throw new IllegalArgumentException("top parameter can not be null"); + } + if (!Container.class.isAssignableFrom(top.getClass())) { + throw new IllegalArgumentException("top parameter " + top + " is not a " + Container.class); + } + Container parent = ((Container) top).getParent(); + if (parent != null && !clazz.isAssignableFrom(parent.getClass())) { + parent = getParentContainer(parent, clazz); + } + return (O) parent; + } + + /** + * Obtain all the keys of data for a given type. + * + * @param klass the type of searched keys + * @return the array of all names of keys for the given type of data + * @since 1.3 + */ + public String[] getKeys(Class<?> klass) { + List<String> keys = new java.util.ArrayList<String>(); + for (JAXXContextEntryDef key : data.keySet()) { + if (key.getKlass() == klass) { + keys.add(key.getName()); + } + } + return keys.toArray(new String[keys.size()]); + + } + + public void clear() { + data.clear(); + } + + protected JAXXObject getUi() { + return ui; + } + + protected void setUi(JAXXObject ui) { + this.ui = ui; + } + + protected JAXXContextEntryDef<?> getKey(String name, Class<?> klass) { + return JAXXContextEntryDef.newDef(name, klass); + } + + @SuppressWarnings({"unchecked"}) + protected <T> T remove0(Class<T> klazz, String name) { + if (PARENT_CONTEXT_ENTRY.accept(klazz, name)) { + JAXXContext old = getParentContext(); + setParentContext(null); + return (T) old; + } + JAXXContextEntryDef entry = null; + for (JAXXContextEntryDef entryDef : data.keySet()) { + if (entryDef.accept(klazz, name)) { + entry = entryDef; + break; + } + } + if (entry != null) { + return (T) data.remove(entry); + } + + if (JAXXContext.class == klazz) { + return null; + } + // try in parentContext + JAXXContext parent = getParentContext(); + + if (parent == null) { + return null; + } + + if (parent instanceof DefaultJAXXContext) { + return ((DefaultJAXXContext) parent).remove0(klazz, name); + } + + return null; + } + + protected JAXXContext getParentContext() { + return parentContext; + } + + protected void setParentContext(JAXXContext parentContext) { + if (parentContext instanceof JAXXObject) { + // keep the real context, not the ui + parentContext = ((JAXXObject) parentContext).getDelegateContext(); + } + this.parentContext = parentContext; + } +} diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/JAXXAction.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/JAXXAction.java new file mode 100644 index 0000000..647e41f --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/JAXXAction.java @@ -0,0 +1,19 @@ +package jaxx.runtime; + +/** + * This is the contract to be realized by any class to be used as Action class for an ui. + * + * @author chemit + */ +public interface JAXXAction { + + /** + * Prepare the initial context of the ui. + * + * @param parentContent the context of the parent of the ui (can be null if no parent is required) + * @param datas other datas to inject in initial context + * @return the {@link jaxx.runtime.JAXXInitialContext} to be injected in the ui via the constructor of the {@link jaxx.runtime.JAXXObject} + */ + JAXXInitialContext init(JAXXContext parentContent, Object... datas); + +} diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/JAXXContext.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/JAXXContext.java new file mode 100644 index 0000000..4d4a421 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/JAXXContext.java @@ -0,0 +1,99 @@ +package jaxx.runtime; + +import java.awt.Container; + +/** + * The {@link jaxx.runtime.JAXXContext} contract defines a generic context. + * <p/> + * A context contains two king of entries : + * <p/> + * <h2>Unamed entry</h2> + * a such entry maps filter only on the clas of the object of the entry. + * <p/> + * To add a <b>unamed</b> entry, use {@link #setContextValue(Object)} and {@link #getContextValue(Class)} to reteave a + * such entry. + * <p/> + * <h2>named entry</h2> + * a such entry filter on class of the object and on the name of the entry. + * <p/> + * To add a <b>named</b> entry, use {@link #setContextValue(Object,String)} and {@link #getContextValue(Class,String)} + * to reteave a such entry. + * + * @author letellier + * @author chemit + */ +public interface JAXXContext { + + /** + * Push in the context a new unamed entry. + * <p/> + * If a previous entry exists in context (unamed and same class), it will be removed. + * + * @param o the value to push in context + */ + public <T> void setContextValue(T o); + + /** + * * Push in the context a new amed entry. + * <p/> + * If a previous entry exists in context (same name and class), it will be removed. + * + * @param o the value to push in context + * @param name the name of the new entry + */ + public <T> void setContextValue(T o, String name); + + /** + * Remove from context the value with the given klazz as an unamed entry + * + * @param klazz the klazz entry + */ + public <T> void removeContextValue(Class<T> klazz); + + /** + * Remove from context the value with the given klazz as an unamed (if name is null) or named entry + * + * @param klazz the klazz entry + * @param name extra name of the entry + */ + + public <T> void removeContextValue(Class<T> klazz, String name); + + /** + * Seek for a unamed entry in the context + * <p/> + * This is an exemple to call a method in JAXX : + * <p/> + * <code><JButton onActionPerformed='{getContextValue(Action.class).method(args[])}'/></code> + * + * @param clazz the class of unamed entry to seek in context + * @return the value of the unamed entry for the given class, or <code>null</code> if no such entry. + */ + public <T> T getContextValue(Class<T> clazz); + + /** + * Seek for a named entry in the context + * + * @param clazz the class of named entry to seek in context + * @param name the name of the entry to seek in context + * @return the value of the named entry for the given class, or <code>null</code> if no such entry. + */ + public <T> T getContextValue(Class<T> clazz, String name); + + /** + * Return parent's container corresponding to the Class clazz + * + * @param clazz clazz desired + * @return parent's container + */ + public <O extends Container> O getParentContainer(Class<O> clazz); + + /** + * Return parent's container corresponding to the Class clazz + * + * @param top the top container + * @param clazz desired + * @return parent's container + */ + public <O extends Container> O getParentContainer(Object top, Class<O> clazz); +} diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/JAXXContextEntryDef.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/JAXXContextEntryDef.java new file mode 100644 index 0000000..f9489e0 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/JAXXContextEntryDef.java @@ -0,0 +1,118 @@ +package jaxx.runtime; + +import java.util.Collections; +import java.util.List; + +/** + * To qualify an entry in a {@link JAXXContext}. + * <p/> + * Use the factory methods <code>newDef</code> and <code>newListDef</code< to obtain new instances. + * + * @author chemit + */ +public class JAXXContextEntryDef<O> implements java.io.Serializable { + + /** name of the entry, can be nuill for a unamed entry. */ + protected String name; + + /** class of the entry, can not be null */ + protected Class<O> klass; + + private static final long serialVersionUID = 1L; + + public static <O> JAXXContextEntryDef<O> newDef(Class<O> klass) { + return newDef(null, klass); + } + + public static <O> JAXXContextEntryDef<O> newDef(String name, Class<O> klass) { + return new JAXXContextEntryDef<O>(name, klass); + } + + public static <O> JAXXContextEntryDef<List<O>> newListDef() { + return newListDef(null); + } + + @SuppressWarnings({"unchecked"}) + public static <O> JAXXContextEntryDef<List<O>> newListDef(String name) { + JAXXContextEntryDef contextEntryDef = new JAXXContextEntryDef<List<O>>(name, JAXXContextEntryDef.<O>castList()); + contextEntryDef.klass = List.class; + return contextEntryDef; + } + + + public String getName() { + return name; + } + + public Class<O> getKlass() { + return klass; + } + + public O getContextValue(JAXXContext context) { + return context.getContextValue(klass, name); + } + + public void removeContextValue(JAXXContext context) { + context.removeContextValue(klass, name); + } + + public void setContextValue(JAXXContext context, O value) { + context.setContextValue(value, name); + } + + @Override + public String toString() { + return super.toString() + "<" + klass + ":" + name + ">"; + } + + protected JAXXContextEntryDef(Class<O> klass) { + this(null, klass); + } + + protected JAXXContextEntryDef(String name, Class<O> klass) { + if (klass == null) { + throw new IllegalArgumentException("class can not be null"); + } + this.name = name; + this.klass = klass; + } + + @SuppressWarnings({"unchecked"}) + protected static <O> Class<List<O>> castList() { + return (Class<List<O>>) Collections.emptyList().getClass(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof JAXXContextEntryDef)) { + return false; + } + JAXXContextEntryDef that = (JAXXContextEntryDef) o; + return klass.equals(that.klass) && !(name != null ? !name.equals(that.name) : that.name != null); + + } + + @Override + public int hashCode() { + int result = (name != null ? name.hashCode() : 0); + return 31 * result + klass.hashCode(); + } + + public boolean accept(Class<?> klass, String name) { + if (klass == Object.class && this.klass != Object.class) { + // try on name only + return (this.name != null && name != null && this.name.equals(name)); + } + return klass.isAssignableFrom(this.klass) && (this.name == null && name == null + || (this.name != null && name != null && this.name.equals(name))); + } + + public boolean accept2(Class<?> klass, String name) { + return !(klass == Object.class && this.klass != Object.class) && + this.klass.isAssignableFrom(klass) && (this.name == null && + name == null || (this.name != null && name != null && this.name.equals(name))); + } +} diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/JAXXInitialContext.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/JAXXInitialContext.java new file mode 100644 index 0000000..4682ed3 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/JAXXInitialContext.java @@ -0,0 +1,93 @@ +package jaxx.runtime; + +import java.awt.Container; +import java.util.Map.Entry; + +/** + * An initial context to be inject in a {@link JAXXObject}. + * <p/> + * The method {@link #add(Object)} register a simple value. + * <p/> + * The method {@link #add(String, Object)} register a named value. + * <p/> + * The method {@link #to(JAXXContext)} inject in the {@link JAXXObject} the values registred in the initial context. + * <p/> + * The initial context is also a "limited" {@link JAXXContext}, since we can only use the two methods + * <p/> + * {@link #getContextValue(Class)} or {@link #getContextValue(Class, String)}. + * + * @see JAXXContext + */ +public class JAXXInitialContext extends DefaultJAXXContext { + + public JAXXInitialContext() { + super(); + } + + /** + * Register a simple (none named) value in the context. + * + * @param value the value to be registred in the context + * @return the instance of the context + */ + public JAXXInitialContext add(Object value) { + return add(null, value); + } + + /** + * Register a named value in the context. + * + * @param name the name of the value + * @param value the value to registred + * @return the instance of the context + */ + public JAXXInitialContext add(String name, Object value) { + super.setContextValue(value, name); + return this; + } + + /** + * Inject all the registed values into the {@link JAXXObject} + * + * @param dst the object to fill. + */ + public void to(JAXXContext dst) { + if (parentContext != null) { + dst.setContextValue(parentContext); + } + for (Entry<JAXXContextEntryDef, Object> entry : data.entrySet()) { + dst.setContextValue(entry.getValue(), entry.getKey().getName()); + } + } + + @Override + public void setContextValue(Object o) { + throw new RuntimeException("not implemented"); + } + + @Override + public void setContextValue(Object o, String name) { + throw new RuntimeException("not implemented"); + } + + @Override + public <T> void removeContextValue(Class<T> klazz) { + throw new RuntimeException("not implemented"); + } + + @Override + public <T> void removeContextValue(Class<T> klazz, String name) { + throw new RuntimeException("not implemented"); + } + + @Override + public <O extends Container> O getParentContainer(Class<O> clazz) { + throw new RuntimeException("not implemented"); + } + + @Override + public <O extends Container> O getParentContainer(Object top, Class<O> clazz) { + throw new RuntimeException("not implemented"); + } + +} diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/JAXXObject.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/JAXXObject.java new file mode 100644 index 0000000..1e40966 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/JAXXObject.java @@ -0,0 +1,52 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime; + +/** The <code>JAXXObject</code> interface is implemented by all classes produced by the JAXX compiler. */ +public interface JAXXObject extends JAXXContext { + /** + * Retrieves an object defined in an XML tag by its ID. + * + * @param id the id of the component to retrieve + * @return the object + */ + public Object getObjectById(String id); + + /** + * Pretrieves the dictonary of knwon objects indexed by their ids. + * + * @return the dictonary of objects. + */ + public java.util.Map<String, Object> get$objectMap(); + + public void applyDataBinding(String id); + + + public void removeDataBinding(String id); + + public jaxx.runtime.JAXXContext getDelegateContext(); + + /** + * Processes a data binding by name. Data binding names are comprised of an object ID and a property name: + * for example, the data binding in the tag <code><JLabel id='label' text='{foo.getText()}'/></code> is + * named <code>"label.text"</code>. Processing a data binding causes it to reevaluate its expression, in this + * case <code>foo.getText()</code>. + * + * @param dest the name of the data binding to run + */ + public void processDataBinding(String dest); + + + /** + * All <code>JAXXObject</code> implements are capable of broadcasting <code>PropertyChangeEvent</code>, and + * furthermore (for technical reasons) must allow code in outside packages, specifically the JAXX runtime, + * to trigger these events. + * + * @param name the name of the property which changed + * @param oldValue the old value of the property + * @param newValue the new value of the property + */ + public void firePropertyChange(String name, Object oldValue, Object newValue); +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/JAXXObjectDescriptor.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/JAXXObjectDescriptor.java new file mode 100644 index 0000000..31d513f --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/JAXXObjectDescriptor.java @@ -0,0 +1,42 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime; + +import jaxx.css.Stylesheet; + +import java.io.Serializable; + +public class JAXXObjectDescriptor implements Serializable { + private ComponentDescriptor[] descriptors; + private Stylesheet stylesheet; + private static final long serialVersionUID = 1L; + + + public JAXXObjectDescriptor(ComponentDescriptor[] descriptors, + Stylesheet stylesheet) { + this.descriptors = descriptors; + this.stylesheet = stylesheet; + } + + + public ComponentDescriptor[] getComponentDescriptors() { + return descriptors; + } + + + public Stylesheet getStylesheet() { + return stylesheet; + } + + @Override + public String toString() { + StringBuilder buffer = new StringBuilder(); + for (ComponentDescriptor descriptor : descriptors) { + buffer.append("\n").append(descriptor); + } + buffer.append("\n").append(stylesheet); + return buffer.toString(); + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/JAXXValidator.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/JAXXValidator.java new file mode 100644 index 0000000..c504292 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/JAXXValidator.java @@ -0,0 +1,25 @@ +package jaxx.runtime; + + +import java.util.List; +import jaxx.runtime.validator.BeanValidator; + +/** + * The contract of a validator-able object. + * + * @author chemit + */ +public interface JAXXValidator { + + /** + * Obtain a validator from his id + * + * @param validatorId validator id + * @return the associated validator, or <code>null</code> if not find + */ + BeanValidator<?> getValidator(String validatorId); + + /** @return the list of ids of all registred validator */ + List<String> getValidatorIds(); + +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/JXPathDecorator.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/JXPathDecorator.java new file mode 100644 index 0000000..81458fb --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/JXPathDecorator.java @@ -0,0 +1,278 @@ +package jaxx.runtime; + +import org.apache.commons.jxpath.JXPathContext; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * JXPath decorator based on {@link String#format(String, Object[])} method. + * <p/> + * To use it, give to him a expression where all jxpath to apply on bean are boxed in <code>${}</code>. + * <p/> + * After the jxpath token you must specifiy the formatter to apply of the jxpath token. + * <p/> + * For example : + * <pre> + * Decorator<Object> d = JXPathDecorator.newDecorator(JXPathDecorator.class,"expr = ${expressions}$s"); + * assert "expr = %1$s" == d.getExpression(); + * assert 1 == d.getNbToken(); + * assert java.util.Arrays.asList("expression") == d.getTokens(); + * assert "expr = %1$s" == d.toString(d); + * </pre> + * + * @param <O> type of data + * @author chemit + * @see Decorator + */ +public class JXPathDecorator<O> extends Decorator<O> { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + private static final Log log = LogFactory.getLog(JXPathDecorator.class); + private static final long serialVersionUID = 1L; + + /** + * Factory method to instanciate a new {@link JXPathDecorator} for the given class {@link O} and expression. + * + * @param internalClass the class of the objects decorated by the new decorator + * @param expression the expression to use to decorated objects + * @param <O> the generic type of class to be decorated by the new decorator + * @return the new instanciated decorator + * @throws IllegalArgumentException if the expression is not valid, says: + * <p/> + * - a missing right brace was detected. + * <p/> + * - a ${ was found in a jxpath token. + * @throws NullPointerException if internalClass parameter is null. + */ + public static <O> JXPathDecorator<O> newDecorator(Class<O> internalClass, String expression) + throws IllegalArgumentException, NullPointerException { + return new JXPathDecorator<O>(internalClass, expression, true); + } + + /** + * Sort a list of data based on the first token property of a given context + * in a given decorator. + * + * @param <O> type of data to sort + * @param decorator the decorator to use to sort + * @param datas the list of data to sort + * @param pos the index of context to used in decorator to obtain sorted property. + */ + public static <O> void sort(JXPathDecorator<O> decorator, List<O> datas, int pos) { + Comparator<O> c = null; + boolean cachedComparator = false; + try { + c = decorator.getComparator(pos); + cachedComparator = c instanceof JXPathComparator<?>; + + if (cachedComparator) { + ((JXPathComparator<O>) c).init(decorator, datas); + } + Collections.sort(datas, c); + } finally { + if (cachedComparator) { + ((JXPathComparator<?>) c).clear(); + } + } + } + + public static class JXPathComparator<O> implements Comparator<O> { + + protected Map<O, Comparable<Comparable<?>>> valueCache; + private final String expression; + + public JXPathComparator(String expression) { + this.expression = expression; + this.valueCache = new HashMap<O, Comparable<Comparable<?>>>(); + } + + @Override + public int compare(O o1, O o2) { + Comparable<Comparable<?>> c1 = valueCache.get(o1); + Comparable<Comparable<?>> c2 = valueCache.get(o2); + return c1.compareTo(c2); + } + + public void clear() { + valueCache.clear(); + } + + public void init(JXPathDecorator<O> decorator, List<O> datas) { + clear(); + for (O data : datas) { + JXPathContext jxcontext = JXPathContext.newContext(data); + Comparable<Comparable<?>> key = decorator.getTokenValue(jxcontext, expression); + valueCache.put(data, key); + } + } + } + + public static class Context<O> implements java.io.Serializable { + + /** + * expression to format using {@link String#format(String, Object[])}, all variables are compute + * using using the jxpath tokens. + */ + protected String expression; + /** list of jxpath tokens to apply on expression */ + protected String[] tokens; + protected transient Comparator<O> comparator; + private static final long serialVersionUID = 1L; + + public Context(String expression, String[] tokens) { + this.expression = expression; + this.tokens = tokens; + } + + public String getFirstProperty() { + return tokens[0]; + } + + public Comparator<O> getComparator(int pos) { + if (comparator == null) { + comparator = new JXPathComparator<O>(tokens[pos]); + } + return comparator; + } + + public void setComparator(Comparator<O> comparator) { + this.comparator = comparator; + } + + @Override + public String toString() { + return "<expression:" + expression + ", tokens:" + Arrays.toString(tokens) + ">"; + } + } + /** the computed context of the decorator */ + protected Context<O> context; + /** nb jxpath tokens to compute */ + protected int nbToken; + /** the initial expression used to compute the decorator context. */ + protected String initialExpression; + + @Override + public String toString(Object bean) { + if (bean == null) { + return null; + } + JXPathContext jxcontext = JXPathContext.newContext(bean); + Object[] args = new Object[nbToken]; + + for (int i = 0; i < nbToken; i++) { + try { + args[i] = getTokenValue(jxcontext, context.tokens[i]); + } catch (Exception e) { + log.error("can not obtain token " + context.tokens[i] + "on object " + bean + " for reason " + e.getMessage(), e); + + } + } + + return String.format(context.expression, args); + } + + @SuppressWarnings({"unchecked"}) + protected Comparable<Comparable<?>> getTokenValue(JXPathContext jxcontext, String token) { + // assume all values are comparable + return (Comparable<Comparable<?>>) jxcontext.getValue(token); + } + + public String getProperty(int pos) { + return getTokens()[pos]; + } + + public String getExpression() { + return context.expression; + } + + public String[] getTokens() { + return context.tokens; + } + + public int getNbToken() { + return nbToken; + } + + public String getInitialExpression() { + return initialExpression; + } + + @Override + public String toString() { + return super.toString() + "<" + context + ">"; + } + + public void setContext(Context<O> context) { + this.context = context; + this.nbToken = context.tokens.length; + // always reset comparator + //this.context.comparator = null; + if (log.isDebugEnabled()) { + log.debug(context); + } + } + + public JXPathDecorator(Class<O> internalClass, String expression, boolean creatContext) throws IllegalArgumentException, NullPointerException { + super(internalClass); + this.initialExpression = expression; + if (creatContext) { + setContext(JXPathDecorator.<O>createInitialContext(expression)); + if (log.isDebugEnabled()) { + log.debug(expression + " --> " + this.context); + } + } + } + + @SuppressWarnings({"unchecked"}) + protected Comparator<O> getComparator(int pos) { + ensureTokenIndex(this, pos); + return context.getComparator(pos); + } + + public static <O> Context<O> createInitialContext(String expression) { + List<String> lTokens = new ArrayList<String>(); + StringBuilder buffer = new StringBuilder(); + int size = expression.length(); + int end = -1; + int start; + while ((start = expression.indexOf("${", end + 1)) > -1) { + if (start > end + 1) { + // prefix of next jxpath token + buffer.append(expression.substring(end + 1, start)); + } + // seek end of jxpath + end = expression.indexOf("}", start + 1); + if (end == -1) { + throw new IllegalArgumentException("could not find the rigth brace starting at car " + start + " : " + expression.substring(start + 2)); + } + String jxpath = expression.substring(start + 2, end); + // not allowed ${ inside a jxpath token + if (jxpath.indexOf("${") > -1) { + throw new IllegalArgumentException("could not find a ${ inside a jxpath expression at car " + (start + 2) + " : " + jxpath); + } + // save the jxpath token + lTokens.add(jxpath); + // replace jxpath token in expresion with a string format variable + buffer.append("%").append(lTokens.size()); + } + if (size > (end + 1)) { + // suffix after end jxpath (or all expression if no jxpath) + buffer.append(expression.substring(end + 1)); + } + return new Context<O>(buffer.toString(), lTokens.toArray(new String[lTokens.size()])); + } + + protected static void ensureTokenIndex(JXPathDecorator<?> decorator, int pos) { + if (pos < -1 || pos > decorator.getNbToken()) { + throw new ArrayIndexOutOfBoundsException("token index " + pos + " is out of bound, can be inside [" + 0 + "," + decorator.nbToken + "]"); + } + } +} diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/MultiJXPathDecorator.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/MultiJXPathDecorator.java new file mode 100644 index 0000000..21eb609 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/MultiJXPathDecorator.java @@ -0,0 +1,129 @@ +package jaxx.runtime; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.StringTokenizer; + +/** + * TODO + * + * @param <O> type of decorated objects + * @author chemit + * @see jaxx.runtime.Decorator + */ +public class MultiJXPathDecorator<O> extends JXPathDecorator<O> { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + private static final Log log = LogFactory.getLog(MultiJXPathDecorator.class); + + private static final long serialVersionUID = 1L; + + public static <O> MultiJXPathDecorator<O> newDecorator(Class<O> internalClass, + String expression, + String separator) + throws IllegalArgumentException, NullPointerException { + + return newDecorator(internalClass, expression, separator, separator); + } + + public static <O> MultiJXPathDecorator<O> newDecorator(Class<O> internalClass, + String expression, + String separator, + String separatorReplacement) + throws IllegalArgumentException, NullPointerException { + + Context<O>[] contexts = createInitialContexts(expression, separator, separatorReplacement); + + return new MultiJXPathDecorator<O>(internalClass, expression, separator, separatorReplacement, contexts); + } + + protected Context<O>[] contexts; + protected String separator; + protected String separatorReplacement; + + + public MultiJXPathDecorator(Class<O> internalClass, String expression, + String separator, String separatorReplacement, + Context<O>[] contexts) throws IllegalArgumentException, NullPointerException { + super(internalClass, expression, false); + this.separator = separator; + this.separatorReplacement = separatorReplacement; + this.contexts = contexts; + + setContextIndex(0); + + if (log.isDebugEnabled()) { + log.debug(expression + " --> " + this.context); + } + } + + public void setContextIndex(int index) { + ensureContextIndex(this, index); + setContext(contexts[index]); + } + + public int getNbContext() { + return contexts.length; + } + + public String getSeparator() { + return separator; + } + + public String getSeparatorReplacement() { + return separatorReplacement; + } + + @Override + protected Comparator<O> getComparator(int pos) { + ensureContextIndex(this, pos); + Context<O> context1 = contexts[pos]; + return context1.getComparator(0); + } + + public static <O> Context<O>[] createInitialContexts(String expression, String separator, String separatorReplacement) { + int sep = expression.indexOf(separator); + if (sep == -1) { + Context<O>[] result = MultiJXPathDecorator.newInstance(1); + result[0] = createInitialContext(expression); + return result; + } + + List<String> tokens = new ArrayList<String>(); + StringTokenizer stk = new StringTokenizer(expression, separator); + while (stk.hasMoreTokens()) { + tokens.add(stk.nextToken()); + } + + int nbTokens = tokens.size(); + Context<O>[] contexts = newInstance(nbTokens); + for (int i = 0; i < nbTokens; i++) { + StringBuilder buffer = new StringBuilder(expression.length()); + for (int j = 0; j < nbTokens; j++) { + int index = (i + j) % nbTokens; + String str = tokens.get(index); + //todo replace %index with %j + buffer.append(separatorReplacement).append(str); + } + contexts[i] = createInitialContext(buffer.substring(separatorReplacement.length())); + } + return contexts; + } + + protected static void ensureContextIndex(MultiJXPathDecorator<?> decorator, int pos) { + if (pos < -1 || pos > decorator.contexts.length) { + throw new ArrayIndexOutOfBoundsException("context index " + pos + " is out of bound, can be inside [" + 0 + "," + decorator.contexts.length + "]"); + } + } + + @SuppressWarnings("unchecked") + protected static <O> Context<O>[] newInstance(int size) { + // fixme how to instanciate a typed array with no checking warning ? + return new Context[size]; + } + +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/PropertyDecorator.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/PropertyDecorator.java new file mode 100644 index 0000000..ce871a6 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/PropertyDecorator.java @@ -0,0 +1,94 @@ +package jaxx.runtime; + +import org.apache.commons.beanutils.PropertyUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; + +/** + * Simple property decorator based on {@link String#format(String, Object[])} method. + * <p/> + * To use it, give him a class and the property name to render. + * <p/> + * For example : + * <pre> + * Decorator<Object> d = PropertyDecorator.newDecorator(PropertyDecorator.class,"expressions"); + * </pre> + * + * @param <O> type of decorated objects + * @author chemit + * @see Decorator + */ +public class PropertyDecorator<O> extends Decorator<O> { + + private static final long serialVersionUID = 1L; + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private final Log log = LogFactory.getLog(PropertyDecorator.class); + + /** + * Factory method to instanciate a new {@link jaxx.runtime.PropertyDecorator} for the given class {@link O} and a + * readable property name. + * + * @param internalClass the class of the objects decorated by the new decorator + * @param property the property + * @param <O> the generic type of class to be decorated by the new decorator + * @return the new instanciated decorator + * @throws IllegalArgumentException if the expression is not valid, says: + * <p/> + * - a missing right brace was detected. + * <p/> + * - a ${ was found in a jxpath token. + * @throws NullPointerException if internalClass parameter is null. + */ + public static <O> PropertyDecorator<O> newDecorator(Class<O> internalClass, String property) + throws IllegalArgumentException, NullPointerException { + return new PropertyDecorator<O>(internalClass, property); + } + + protected String property; + + protected transient Method m; + + @Override + public String toString(Object bean) { + try { + return getM().invoke(bean) + ""; + } catch (Exception e) { + log.error("could not convert for reason : " + e, e); + return ""; + } + } + + public String getProperty() { + return property; + } + + protected PropertyDecorator(Class<O> internalClass, String property) throws NullPointerException { + super(internalClass); + if (property == null) { + throw new NullPointerException("property can not be null."); + } + this.property = property; + // init method + getM(); + } + + + protected Method getM() { + if (m == null) { + for (PropertyDescriptor propertyDescriptor : PropertyUtils.getPropertyDescriptors(internalClass)) { + if (propertyDescriptor.getName().equals(property)) { + this.m = propertyDescriptor.getReadMethod(); + break; + } + } + if (m == null) { + throw new IllegalArgumentException("could not find the property " + property + " in " + internalClass); + } + } + return m; + } +} diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/Util.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/Util.java new file mode 100644 index 0000000..1f1ec83 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/Util.java @@ -0,0 +1,465 @@ +package jaxx.runtime; + +import jaxx.Base64Coder; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import javax.swing.JList; +import javax.swing.UIManager; +import java.awt.Component; +import java.awt.Dimension; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeListenerProxy; +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EventListener; +import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; + +public class Util { + + public static final String DEFAULT_ICON_PATH = "/icons/"; + public static final String DEFAULT_ICON_PATH_PROPERTY = "default.icon.path"; + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private final Log log = LogFactory.getLog(Util.class); + + + // Maps root objects to lists of event listeners + private static Map<Object, WeakReference<List<EventListenerDescriptor>>> eventListeners = new WeakHashMap<Object, WeakReference<List<EventListenerDescriptor>>>(); + private static Map<JAXXObject, WeakReference<List<DataBindingUpdateListener>>> dataBindingUpdateListeners = new WeakHashMap<JAXXObject, WeakReference<List<DataBindingUpdateListener>>>(); + + + private static class EventListenerDescriptor { + Class listenerClass; + String listenerMethodName; + String methodName; + Object eventListener; + } + + + /** + * Decodes the serialized representation of a JAXXObjectDescriptor. The string must be a byte-to-character mapping + * of the binary serialization data for a JAXXObjectDescriptor. See the comments in JAXXCompiler.createJAXXObjectDescriptorField + * for the rationale behind this (admittedly ugly) approach. + * + * @param descriptor descriptor to decode + * @return the dedoced descriptor + */ + public static JAXXObjectDescriptor decodeJAXXObjectDescriptor(String descriptor) { + try { + return (JAXXObjectDescriptor) Base64Coder.deserialize(descriptor, false); + /*byte[] data = new byte[descriptor.length()]; + // copy low-order bytes into the array. The high-order bytes should all be zero. + System.arraycopy(descriptor.getBytes(), 0, data, 0, data.length); + //descriptor.getBytes(0, descriptor.length(), data, 0); + ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(data)); + return (JAXXObjectDescriptor) in.readObject();*/ + } + catch (IOException e) { + throw new RuntimeException("Internal error: can't-happen error", e); + } + catch (ClassNotFoundException e) { + throw new RuntimeException("Internal error: can't-happen error", e); + } + } + + + public static JAXXObjectDescriptor decodeCompressedJAXXObjectDescriptor(String descriptor) { + try { + return (JAXXObjectDescriptor) Base64Coder.deserialize(descriptor, true); + + /*byte[] data = new byte[descriptor.length()]; + // copy low-order bytes into the array. The high-order bytes should all be zero. + System.arraycopy(descriptor.getBytes(), 0, data, 0, data.length); + //descriptor.getBytes(0, descriptor.length(), data, 0); + ObjectInputStream in = new ObjectInputStream(new GZIPInputStream(new ByteArrayInputStream(data))); + return (JAXXObjectDescriptor) in.readObject();*/ + } + catch (IOException e) { + throw new RuntimeException("Internal error: can't-happen error", e); + } + catch (ClassNotFoundException e) { + throw new RuntimeException("Internal error: can't-happen error", e); + } + } + + + public static Object getEventListener(Class<? extends EventListener> listenerClass, final String listenerMethodName, final Object methodContainer, final String methodName) { + WeakReference<List<EventListenerDescriptor>> ref = eventListeners.get(methodContainer); + List<EventListenerDescriptor> descriptors = ref != null ? ref.get() : null; + if (descriptors == null) { + descriptors = new ArrayList<EventListenerDescriptor>(); + eventListeners.put(methodContainer, new WeakReference<List<EventListenerDescriptor>>(descriptors)); + } else { + for (EventListenerDescriptor descriptor : descriptors) { + if (listenerClass == descriptor.listenerClass && + (listenerMethodName == null ? descriptor.listenerMethodName == null : listenerMethodName.equals(descriptor.listenerMethodName)) && + methodName.equals(descriptor.methodName)) { + return descriptor.eventListener; + } + } + } + + // else we need to create a new listener + final EventListenerDescriptor descriptor = new EventListenerDescriptor(); + descriptor.listenerClass = listenerClass; + descriptor.listenerMethodName = listenerMethodName; + descriptor.methodName = methodName; + try { + final List<Method> listenerMethods = Arrays.asList(listenerClass.getMethods()); + Method listenerMethod = null; + if (listenerMethodName != null) { + for (Method listenerMethod1 : listenerMethods) { + if ((listenerMethod1).getName().equals(listenerMethodName)) { + listenerMethod = listenerMethod1; + break; + } + } + } + if (listenerMethodName != null && listenerMethod == null) { + throw new IllegalArgumentException("no method named " + listenerMethodName + " found in class " + listenerClass.getName()); + } + Class[] parameterTypes = listenerMethods.get(0).getParameterTypes(); + Class<?> methodContainerClass = methodContainer.getClass(); + final Method targetMethod = methodContainerClass.getMethod(methodName, parameterTypes); + descriptor.eventListener = Proxy.newProxyInstance(listenerClass.getClassLoader(), + new Class[]{listenerClass}, + new InvocationHandler() { + public Object invoke(Object proxy, Method method, Object[] args) { + String methodName = method.getName(); + if ((listenerMethodName == null && listenerMethods.contains(method)) || methodName.equals(listenerMethodName)) { + try { + return targetMethod.invoke(methodContainer, args); + } + catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + } + if (methodName.equals("toString")) { + return toString(); + } + if (methodName.equals("equals")) { + return descriptor.eventListener == args[0]; + } + if (methodName.equals("hashCode")) { + return hashCode(); + } + return null; + } + }); + descriptors.add(descriptor); + return descriptor.eventListener; + } + catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + + public static Object getEventListener(Class<? extends EventListener> listenerClass, final Object methodContainer, final String methodName) { + return getEventListener(listenerClass, null, methodContainer, methodName); + } + + + public static DataBindingUpdateListener getDataBindingUpdateListener(JAXXObject object, String bindingName) { + WeakReference<List<DataBindingUpdateListener>> ref = dataBindingUpdateListeners.get(object); + List<DataBindingUpdateListener> listeners = ref == null ? null : ref.get(); + if (listeners == null) { + listeners = new ArrayList<DataBindingUpdateListener>(); + dataBindingUpdateListeners.put(object, new WeakReference<List<DataBindingUpdateListener>>(listeners)); + } else { + for (DataBindingUpdateListener listener : listeners) { + if (bindingName.equals(listener.getBindingName())) { + return listener; + } + } + } + DataBindingUpdateListener listener = new DataBindingUpdateListener(object, bindingName); + listeners.add(listener); + return listener; + } + + + public static void setComponentWidth(Component component, int width) { + component.setSize(width, component.getHeight()); + if (component instanceof JComponent) { + JComponent jcomponent = (JComponent) component; + jcomponent.setPreferredSize(new Dimension(width, jcomponent.getPreferredSize().height)); + jcomponent.setMinimumSize(new Dimension(width, jcomponent.getPreferredSize().height)); + if (jcomponent.isDisplayable()) { + jcomponent.revalidate(); + } + } + } + + + public static void setComponentHeight(Component component, int height) { + component.setSize(component.getWidth(), height); + if (component instanceof JComponent) { + JComponent jcomponent = (JComponent) component; + jcomponent.setPreferredSize(new Dimension(jcomponent.getPreferredSize().width, height)); + jcomponent.setMinimumSize(new Dimension(jcomponent.getPreferredSize().width, height)); + if (jcomponent.isDisplayable()) { + jcomponent.revalidate(); + } + } + } + + + public static boolean assignment(boolean value, String name, JAXXObject src) { + src.firePropertyChange(name.trim(), null, "dummy value"); + return value; + } + + + public static byte assignment(byte value, String name, JAXXObject src) { + src.firePropertyChange(name.trim(), null, "dummy value"); + return value; + } + + + public static short assignment(short value, String name, JAXXObject src) { + src.firePropertyChange(name.trim(), null, "dummy value"); + return value; + } + + + public static int assignment(int value, String name, JAXXObject src) { + src.firePropertyChange(name.trim(), null, "dummy value"); + return value; + } + + + public static long assignment(long value, String name, JAXXObject src) { + src.firePropertyChange(name.trim(), null, "dummy value"); + return value; + } + + + public static float assignment(float value, String name, JAXXObject src) { + src.firePropertyChange(name.trim(), null, "dummy value"); + return value; + } + + + public static double assignment(double value, String name, JAXXObject src) { + src.firePropertyChange(name.trim(), null, "dummy value"); + return value; + } + + + public static char assignment(char value, String name, JAXXObject src) { + src.firePropertyChange(name.trim(), null, "dummy value"); + return value; + } + + + public static java.lang.Object assignment(java.lang.Object value, String name, JAXXObject src) { + src.firePropertyChange(name.trim(), null, "dummy value"); + return value; + } + + /** + * Compute the string representation of an object. + * <p/> + * Return empty string if given object is null + * + * @param value the value to write + * @return the string representation of the given object or an empty string if object is null. + */ + public static String getStringValue(Object value) { + String result; + result = value == null ? "" : value.toString(); + return result; + } + + /** + * Test if a type of entry exists in a given context and throw an IllegalArgumentException if not found. + * <p/> + * If entry is found, return his value in context. + * + * @param <T> the type of required data + * @param context the context to test + * @param def the definition of the entry to seek in context + * @return the value from the context + * @throws IllegalArgumentException if the entry is not found in context. + */ + public static <T> T checkJAXXContextEntry(JAXXContext context, JAXXContextEntryDef<T> def) throws IllegalArgumentException { + + T value = def.getContextValue(context); + + if (value == null) { + throw new IllegalArgumentException("the context entry [" + def + "] ] was not found in context " + context); + } + + return value; + } + + /** + * Convinient method to apply more than one binding on a JAXX ui. + * + * @param src the ui to treate + * @param bindings the list of binding to process. + */ + public static void applyDataBinding(JAXXObject src, String... bindings) { + for (String binding : bindings) { + src.applyDataBinding(binding); + } + } + + /** + * Convinient method to process more than one binding on a JAXX ui. + * + * @param src the ui to treate + * @param bindings the list of binding to process. + */ + public static void processDataBinding(JAXXObject src, String... bindings) { + for (String binding : bindings) { + src.processDataBinding(binding); + } + } + + /** + * Convinient method to remove more than one binding on a JAXX ui. + * + * @param src the ui to treate + * @param bindings the list of binding to process. + */ + public static void removeDataBinding(JAXXObject src, String... bindings) { + for (String binding : bindings) { + src.removeDataBinding(binding); + } + } + + public static <O> DefaultListCellRenderer newDecoratedListCellRenderer(final Decorator<O> decorator) { + return new DefaultListCellRenderer() { + + private static final long serialVersionUID = 1L; + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + String decorated; + if (value instanceof String) { + decorated = (String) value; + } else { + decorated = decorator.toString(value); + } + return super.getListCellRendererComponent(list, decorated, index, isSelected, cellHasFocus); + } + }; + } + + public static ImageIcon createIcon(String path) { + java.net.URL imgURL = Util.class.getResource(path); + if (imgURL != null) { + return new ImageIcon(imgURL); + } else { + throw new IllegalArgumentException("could not find icon " + path); + } + } + + /** + * @param path the location of icons in root directory icons + * @return the icon at {@link #getIconPath()}+path + */ + public static ImageIcon createImageIcon(String path) { + String iconPath = getIconPath(); + return createIcon(iconPath + path); + } + + /** + * @param key the key of the icon to retreave from {@link UIManager} + * @return the icon, or <code>null if no icon found in {@link UIManager} + */ + public static Icon getUIManagerIcon(String key) { + return UIManager.getIcon(key); + } + + /** + * retreave for the {@link UIManager} the icon prefixed by <code>action.</code> + * + * @param key the key of the action icon to retreave from {@link UIManager} + * @return the icon, or <code>null if no icon found in {@link UIManager} + */ + public static Icon getUIManagerActionIcon(String key) { + return getUIManagerIcon("action." + key); + } + + + public static ImageIcon createActionIcon(String name) { + String iconPath = getIconPath(); + return createIcon(iconPath + "action-" + name + ".png"); + } + + public static ImageIcon createI18nIcon(String name) { + String iconPath = getIconPath(); + return createIcon(iconPath + "i18n/" + name + ".png"); + } + + /** + * detects all PropertychangedListener added by Jaxx uis + * (should be a {@link DataBindingListener} + * + * @param propertyNames the array of property names to find + * @param listeners the array of listeners to filter + * @return the filtered listeners + */ + public static PropertyChangeListener[] findJaxxPropertyChangeListener(String[] propertyNames, PropertyChangeListener... listeners) { + if (listeners == null || listeners.length == 0) { + return new PropertyChangeListener[0]; + } + List<String> pNames = Arrays.asList(propertyNames); + + List<PropertyChangeListener> toRemove = new ArrayList<PropertyChangeListener>(); + + for (PropertyChangeListener listener : listeners) { + String pName = null; + PropertyChangeListenerProxy plistener = null; + if (listener instanceof PropertyChangeListenerProxy) { + plistener = (PropertyChangeListenerProxy) listener; + if (!pNames.contains(plistener.getPropertyName())) { + // not on the good property + continue; + } + listener = (PropertyChangeListener) plistener.getListener(); + pName = plistener.getPropertyName(); + } + if (plistener != null && pName != null && listener instanceof DataBindingListener) { + if (log.isDebugEnabled()) { + log.debug("find config listener to remove [" + pName + "] : " + listener); + } + toRemove.add(plistener); + //toRemove.add(listener); + } + } + return toRemove.toArray(new PropertyChangeListener[toRemove.size()]); + } + + private static String getIconPath() { + String iconPath = UIManager.getString(DEFAULT_ICON_PATH_PROPERTY); + if (iconPath == null) { + iconPath = DEFAULT_ICON_PATH; + } else { + if (!iconPath.endsWith("/")) { + iconPath += "/"; + } + } + return iconPath; + } + +} diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/css/DataBinding.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/css/DataBinding.java new file mode 100644 index 0000000..2d5ed61 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/css/DataBinding.java @@ -0,0 +1,31 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.css; + +/** + * Represents a data binding bound to an attribute at runtime. Used by {@link Pseudoclasses} to keep + * track of which data bindings are in effect. + */ +public class DataBinding { + private String id; + + public DataBinding(String id) { + this.id = id; + } + + public String getId() { + return id; + } + + @Override + public boolean equals(Object o) { + return o instanceof DataBinding && ((DataBinding) o).getId().equals(getId()); + } + + @Override + public int hashCode() { + return id.hashCode(); + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/css/Pseudoclasses.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/css/Pseudoclasses.java new file mode 100644 index 0000000..cab9819 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/css/Pseudoclasses.java @@ -0,0 +1,176 @@ +package jaxx.runtime.css; + +import jaxx.runtime.JAXXObject; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; + +public class Pseudoclasses { + public static final String NO_PSEUDOCLASS = "no pseudoclass"; + + private static Map<Object, Map<String, List<PropertyValue>>> properties = new WeakHashMap<Object, Map<String, List<PropertyValue>>>(); + + + private static class PropertyValue implements Comparable<PropertyValue> { + private Object value; + private int id; + + public PropertyValue(Object value, int id) { + this.value = value; + this.id = id; + } + + public Object getValue() { + return value; + } + + public int getId() { + return id; + } + + public int compareTo(PropertyValue o) { + return getId() - o.getId(); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof PropertyValue)) { + return false; + } + PropertyValue value = (PropertyValue) o; + if (value.getId() != getId()) { + return false; + } + if (value.getValue() == null) { + return getValue() == null; + } + return value.getValue().equals(getValue()); + } + + @Override + public int hashCode() { + return (value != null ? value.hashCode() : 0) ^ id; + } + + @Override + public String toString() { + return "PropertyValue[" + value + ", " + id + "]"; + } + } + + private static List<PropertyValue> getPropertyList(Object object, String property) { + Map<String, List<PropertyValue>> propertyMap = properties.get(object); + if (propertyMap == null) { + propertyMap = new HashMap<String, List<PropertyValue>>(); + properties.put(object, propertyMap); + } + + List<PropertyValue> propertyList = propertyMap.get(property); + if (propertyList == null) { + propertyList = new ArrayList<PropertyValue>(); + propertyMap.put(property, propertyList); + } + + return propertyList; + } + + public static boolean isPropertyApplied(Object object, String property, int id) { + for (PropertyValue aPropertyList : getPropertyList(object, property)) { + if (aPropertyList.getId() == id) { + return true; + } + } + return false; + } + + public static void propertyApplied(Object object, String property, Object value, int id) { + List<PropertyValue> propertyList = getPropertyList(object, property); + propertyList.add(new PropertyValue(value, id)); + Collections.sort(propertyList); + } + + public static void propertyRemoved(Object object, String property, Object value, int id) { + List<PropertyValue> propertyList = getPropertyList(object, property); + propertyList.remove(new PropertyValue(value, id)); + } + + public static Object getCurrentValue(Object object, String property) { + List<PropertyValue> propertyList = getPropertyList(object, property); + if (propertyList.size() > 0) { + return propertyList.get(propertyList.size() - 1).getValue(); + } + return NO_PSEUDOCLASS; + } + + public static Object applyProperty(JAXXObject parent, Object object, String property, Object newValue, Object currentValue, int id) { + if (!isPropertyApplied(object, property, id)) { + Object value = getCurrentValue(object, property); + if (value == NO_PSEUDOCLASS) { + propertyApplied(object, property, wrap(currentValue), -1); + } + propertyApplied(object, property, wrap(newValue), id); + value = getCurrentValue(object, property); + if (value instanceof DataBinding) { + parent.applyDataBinding(((DataBinding) value).getId()); + } + return value; + } else + return currentValue; + } + + public static Object removeProperty(JAXXObject parent, Object object, String property, Object oldValue, Object currentValue, int id) { + if (isPropertyApplied(object, property, id)) { + Object value = getCurrentValue(object, property); + if (value == NO_PSEUDOCLASS) { + throw new IllegalStateException("found NO_PSEUDOCLASS value for a property which does not have a default value"); + } + if (value instanceof DataBinding) { + parent.removeDataBinding(((DataBinding) value).getId()); + } + propertyRemoved(object, property, wrap(oldValue), id); + value = getCurrentValue(object, property); + return value; + } else + return currentValue; + } + + public static Object wrap(boolean value) { + return value; + } + + public static Object wrap(byte value) { + return value; + } + + public static Object wrap(short value) { + return value; + } + + public static Object wrap(int value) { + return value; + } + + public static Object wrap(long value) { + return value; + } + + public static Object wrap(float value) { + return value; + } + + public static Object wrap(double value) { + return value; + } + + public static Object wrap(char value) { + return value; + } + + public static Object wrap(Object value) { + return value; + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/BeanValidator.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/BeanValidator.java new file mode 100644 index 0000000..f3df692 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/BeanValidator.java @@ -0,0 +1,490 @@ +package jaxx.runtime.validator; + +import jaxx.runtime.BeanValidatorUtil; +import java.beans.EventSetDescriptor; +import org.apache.commons.beanutils.ConversionException; +import org.apache.commons.beanutils.Converter; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.util.ConverterUtil; + +import java.beans.Introspector; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.TreeMap; +import javax.swing.event.EventListenerList; + +/** + * + * A customized validator for a given bean. + * + * <b>Note:</b> The bean must be listenable on properyChange events (means + * must have public addPropertychangeListener and removePropertyChangeListener methods). + * + * @param <B> type of the bean to validate. + * + * @author chemit + */ +public class BeanValidator<B> { + + /** la nom de la propriété bean */ + static public final String BEAN_PROERTY = "bean"; + /** la nom de la propriété contextName */ + static public final String CONTEXT_NAME_PROPERTY = "contextName"; + /** la nom de l'état valid */ + static public final String VALID_PROERTY = "valid"; + /** la nom de l'état changed */ + static public final String CHANGED_PROERTY = "changed"; + /** to use log facility, just put in your code: log.info(\"...\"); */ + static protected final Log log = LogFactory.getLog(BeanValidator.class); + /** the type of bean to watch */ + protected final Class<B> beanClass; + /** the validation named context (can be null) */ + protected String contextName; + /** to chain to a prent validator */ + protected BeanValidator<?> parentValidator; + /** state to indicate that validator has changed since the last time bean was setted */ + protected boolean changed = false; + /** state of the validator (is true if no errors of error scope is found) */ + protected boolean valid = true; + /** bean to be watched */ + protected B bean = null; + /** to add and remove PropertyChangeListener on watched beans */ + protected EventSetDescriptor beanEventDescriptor; + /** list of fields watched by this validator */ + protected Set<BeanValidatorField<B>> fields; + /** map of conversion errors detected by this validator */ + protected Map<String, String> conversionErrors; + /** xworks scope validator **/ + protected EnumMap<BeanValidatorScope, XWorkBeanValidator<B>> validators; + /** listener that listens on bean modification */ + protected PropertyChangeListener l; + /** delegate property change support */ + protected PropertyChangeSupport pcs; + /** A list of event listeners for this validators */ + protected EventListenerList listenerList = new EventListenerList(); + + public BeanValidator(Class<B> beanClass, String contextName) { + this.beanClass = beanClass; + this.pcs = new PropertyChangeSupport(this); + this.conversionErrors = new TreeMap<String, String>(); + this.validators = new EnumMap<BeanValidatorScope, XWorkBeanValidator<B>>(BeanValidatorScope.class); + + setContextName(contextName); + + l = new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + doValidate(); + } + }; + } + + public Class<B> getBeanClass() { + return beanClass; + } + + public BeanValidator<?> getParentValidator() { + return parentValidator; + } + + public String getContextName() { + return contextName; + } + + public Set<BeanValidatorField<B>> getFields() { + return fields; + } + + public Set<BeanValidatorScope> getScopes() { + return new java.util.HashSet<BeanValidatorScope>(validators.keySet()); + } + + /** + * Retourne vrai si l'objet bean a ete modifie depuis le dernier + * {@link #setBean} + * + * @return <code>true</code> if bean was modify since last {@link #setBean(Object)} invocation + */ + public boolean isChanged() { + return changed; + } + + public boolean isValid() { + return valid; + } + + public B getBean() { + return bean; + } + + public BeanValidatorField<B> getField(String fieldName) { + for (BeanValidatorField<B> field : fields) { + if (fieldName.equals(field.getName())) { + return field; + } + } + return null; + } + + public boolean hasErrors() { + for (BeanValidatorField<B> field : fields) { + if (field.hasErrors()) { + return true; + } + } + return false; + } + + public boolean hasWarnings() { + for (BeanValidatorField<B> field : fields) { + if (field.hasWarnings()) { + return true; + } + } + return false; + } + + public boolean hasInfos() { + for (BeanValidatorField<B> field : fields) { + if (field.hasInfos()) { + return true; + } + } + return false; + } + + /** + * Test a the validator contains the field given his name + * + * @param fieldName the name of the searched field + * @return <code>true</code> if validator contaisn this field, <code>false</code> otherwise + */ + public boolean containsField(String fieldName) { + BeanValidatorField<B> field = getField(fieldName); + return field != null; + } + + public boolean isValid(String fieldName) { + BeanValidatorField<B> field = getField(fieldName); + if (field == null) { + throw new IllegalArgumentException("could not find a validator field " + fieldName); + } + return field.isValid(); + } + + /** + * Permet de force la remise a false de l'etat de changement du bean + * + * @param changed flag to force reset of property {@link #changed} + */ + public void setChanged(boolean changed) { + this.changed = changed; + // force the property to be fired (never pass the older value) + pcs.firePropertyChange(CHANGED_PROERTY, null, changed); + } + + public void setValid(boolean valid) { + this.valid = valid; + // force the property to be fired (never pass the older value) + pcs.firePropertyChange(VALID_PROERTY, null, valid); + } + + public void setBean(B bean) { + B oldBean = this.bean; + if (log.isDebugEnabled()) { + log.debug(this + " : " + bean); + } + + // clean conversions of previous bean + conversionErrors.clear(); + + if (oldBean != null) { + try { + getBeanEventDescriptor(oldBean).getRemoveListenerMethod().invoke(oldBean, l); + } catch (Exception eee) { + log.info("Can't register as listener for bean " + beanClass + " for reason " + eee.getMessage(), eee); + } + } + this.bean = bean; + + if (bean == null) { + + // remove all messages for all fields of the validator + + for (BeanValidatorField<B> f : fields) { + + f.updateMessages(this, null, null); + } + + } else { + try { + getBeanEventDescriptor(bean).getAddListenerMethod().invoke(bean, l); + } catch (Exception eee) { + log.info("Can't register as listener for bean " + beanClass + " for reason " + eee.getMessage(), eee); + } + validate(); + } + setChanged(false); + setValid(!hasErrors()); + pcs.firePropertyChange(BEAN_PROERTY, oldBean, bean); + } + + public void setContextName(String contextName) { + String oldValidationContextName = this.contextName; + this.contextName = contextName; + // changing contextName could change fields definition + // so dettach bean, must rebuild the fields + if (bean != null) { + setBean(null); + } + // rebuild the fields + initFields(); + pcs.firePropertyChange(CONTEXT_NAME_PROPERTY, oldValidationContextName, contextName); + } + + public void setParentValidator(BeanValidator<?> parentValidator) { + this.parentValidator = parentValidator; + } + + /** + * Convert a value. + * <p/> + * If an error occurs, then add an error in validator. + * + * @param <T> the type of conversion + * @param fieldName the name of the bean property + * @param value the value to convert + * @param valueClass the type of converted value + * @return the converted value, or null if conversion was not ok + */ + @SuppressWarnings({"unchecked"}) + public <T> T convert(String fieldName, String value, Class<T> valueClass) { + if (fieldName == null) { + throw new IllegalArgumentException("fieldName can not be null"); + } + if (valueClass == null) { + throw new IllegalArgumentException("valueClass can not be null"); + } + + // on ne convertit pas si il y a un bean et que le resultat de la validation + // pourra etre affiche quelque part + if (!canValidate() || value == null) { + return null; + } + + // remove the previous conversion error for the field + conversionErrors.remove(fieldName); + + T result; + try { + Converter converter = ConverterUtil.getConverter(valueClass); + if (converter == null) { + throw new RuntimeException("could not find converter for the type " + valueClass); + } + result = (T) converter.convert(valueClass, value); + /* Why this test ? if (result != null && !value.equals(result.toString())) { + conversionErrors.put(fieldName, "error.convertor." + Introspector.decapitalize(valueClass.getSimpleName())); + result = null; + validate(); + }*/ + } catch (ConversionException e) { + // get + conversionErrors.put(fieldName, "error.convertor." + Introspector.decapitalize(valueClass.getSimpleName())); + result = null; + validate(); + } + return result; + } + + /** + * Methode pour forcer la revalidation d'un bean en mettant a jour les etats + * internes. + * + * La méthode appelle {@link #validate()} puis met à jour les etats internes + * {@link #valid} et {@link #changed}. + * + * @since 1.5 + */ + public void doValidate() { + validate(); + setValid(!hasErrors()); + setChanged(true); + } + + /** + * il faut eviter le code re-intrant (durant une validation, une autre est + * demandee). Pour cela on fait la validation dans un thread, et tant + * que la premiere validation n'est pas fini, on ne repond pas aux + * solicitations. + * Cette method est public pour permettre de force une validation par + * programmation, ce qui est utile par exemple si le bean ne supporte + * pas les {@link PropertyChangeListener} + * + * TODO la methode devra repasser en protected et on preperar utiliser la + * methode {@link #doRevalidate()} car {@link #validate()} ne modifie pas + * les etats internes et cela en rends son utilisation delicate (le + * validateur entre dans un etat incoherent par rapport aux messages envoyés). + */ + public void validate() { + + // on ne valide que si il y a un bean et que le resultat de la validation + // pourra etre affiche quelque part + if (!canValidate()) { + return; + } + + for (BeanValidatorScope scope : validators.keySet()) { + + XWorkBeanValidator<B> validator = validators.get(scope); + + Map<String, List<String>> newMessages = validator.validate(bean); + + if (scope == BeanValidatorScope.ERROR) { + // treate conversion errors + // reinject them + for (Entry<String, String> entry : conversionErrors.entrySet()) { + // remove from validation, errors occurs on this field + List<String> errors = newMessages.get(entry.getKey()); + String conversionError = entry.getValue(); + if (errors != null) { + errors.clear(); + errors.add(conversionError); + } else { + errors = java.util.Collections.singletonList(conversionError); + if (newMessages == XWorkBeanValidator.EMPTY_RESULT) { + newMessages = new java.util.HashMap<String, List<String>>(); + } + // add the concrete conversion error + newMessages.put(entry.getKey(), errors); + } + } + } + + // for each field, update his list of messages + for (BeanValidatorField<B> field : fields) { + List<String> messagesForField = newMessages.get(field.getName()); + if (field.getScopes().contains(scope)) { + field.updateMessages(this, scope, messagesForField); + } + } + } + + if (parentValidator != null) { + // chained validation + // the parent validator should not be changed from this validation + boolean wasModified = parentValidator.isChanged(); + parentValidator.doValidate(); + if (!wasModified) { + // push back old state + parentValidator.setChanged(false); + } + } + + } + + @Override + public String toString() { + return super.toString() + "<beanClass:" + beanClass + ", contextName:" + contextName + ">"; + } + + public void addBeanValidatorListener(BeanValidatorListener listener) { + listenerList.add(BeanValidatorListener.class, listener); + } + + public void removeBeanValidatorListener(BeanValidatorListener listener) { + listenerList.remove(BeanValidatorListener.class, listener); + } + + public BeanValidatorListener[] getBeanValidatorListeners() { + return listenerList.getListeners(BeanValidatorListener.class); + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + pcs.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + pcs.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.removePropertyChangeListener(propertyName, listener); + } + + /** @return <code>true</code> if validation is enabled, <code>false</code> otherwise. */ + protected boolean canValidate() { + return !(bean == null || fields.isEmpty()); + } + + protected void fireFieldChanged(BeanValidatorField<B> field, BeanValidatorScope scope, String[] toAdd, String[] toDelete) { + + BeanValidatorEvent evt = new BeanValidatorEvent(this, field, scope, toAdd, toDelete); + + for (BeanValidatorListener listener : listenerList.getListeners(BeanValidatorListener.class)) { + listener.onFieldChanged(evt); + } + } + + protected synchronized void initFields() { + + Set<String> detectedFieldNames = new java.util.HashSet<String>(); + EnumMap<BeanValidatorScope, Set<String>> tmp = new EnumMap<BeanValidatorScope, Set<String>>(BeanValidatorScope.class); + Set<BeanValidatorField<B>> detectedFields = new java.util.HashSet<BeanValidatorField<B>>(); + + validators.clear(); + + for (BeanValidatorScope scope : BeanValidatorScope.values()) { + String scopeContext = (contextName == null ? "" : contextName + "-") + scope.name().toLowerCase(); + + XWorkBeanValidator<B> newValidator = new XWorkBeanValidator<B>(beanClass, scopeContext, false); + Set<String> fieldNames = newValidator.getFieldNames(); + if (log.isDebugEnabled()) { + log.debug("detected validators for scope " + scopeContext + " : " + fieldNames); + } + if (!fieldNames.isEmpty()) { + // fields detected in this validator, keep it + validators.put(scope, newValidator); + detectedFieldNames.addAll(fieldNames); + tmp.put(scope, fieldNames); + } + } + + List<BeanValidatorScope> scopes = new ArrayList<BeanValidatorScope>(); + for (String fieldName : detectedFieldNames) { + scopes.clear(); + // detect scopes for the field + for (BeanValidatorScope scope : BeanValidatorScope.values()) { + if (tmp.containsKey(scope) && tmp.get(scope).contains(fieldName)) { + scopes.add(scope); + } + } + BeanValidatorField<B> f = new BeanValidatorField<B>(beanClass, fieldName, scopes); + detectedFields.add(f); + } + tmp.clear(); + detectedFieldNames.clear(); + + this.fields = java.util.Collections.unmodifiableSet(detectedFields); + } + + protected EventSetDescriptor getBeanEventDescriptor(B bean) { + if (beanEventDescriptor == null) { + // check that the bean is listenable, otherwise, can't use the validator on it + this.beanEventDescriptor = BeanValidatorUtil.getPropertyChangeListenerDescriptor(bean.getClass()); + } + return beanEventDescriptor; + } +} diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/BeanValidatorDetector.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/BeanValidatorDetector.java new file mode 100644 index 0000000..4a7fbae --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/BeanValidatorDetector.java @@ -0,0 +1,208 @@ +package jaxx.runtime.validator; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Un detecteur de validateurs pour un liste de classes données et un + * répertoire où chercher les fichiers de validation. + * + * @author chemit + * + * @since 1.6.0 + */ +public class BeanValidatorDetector { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + private static final Log log = LogFactory.getLog(BeanValidatorDetector.class); + + public SortedSet<BeanValidator<?>> detect(File sourceRoot, Class<?>... types) { + SortedSet<BeanValidator<?>> result = detect(BeanValidator.class, sourceRoot, null, types); + return result; + } + + public SortedSet<BeanValidator<?>> detect(Class<?> validatorClass, File sourceRoot, Pattern contextFilter, Class<?>... types) { + + SortedSet<BeanValidator<?>> result = new TreeSet<BeanValidator<?>>(new BeanValidatorComparator()); + + for (Class<?> c : types) { + File dir = getClassDir(sourceRoot, c); + if (!dir.exists()) { + // pas de repertoire adequate + log.debug("skip non existing directory " + dir); + continue; + } + String[] contexts = getContexts(c, dir); + if (log.isDebugEnabled()) { + log.debug("contexts : " + Arrays.toString(contexts)); + } + + if (contexts.length > 0) { + String[] realContexts = getContextsWithoutScopes(contexts); + + if (log.isDebugEnabled()) { + log.debug("realContexts : " + Arrays.toString(realContexts)); + } + + if (contextFilter != null) { + // filter contexts + realContexts = getFilterContexts(contextFilter, realContexts); + if (log.isDebugEnabled()) { + log.debug("filterContexts : " + Arrays.toString(realContexts)); + } + } + + for (String context : realContexts) { + + // on cherche le validateur + BeanValidator<?> validator = getValidator(validatorClass, c, context.isEmpty() ? null : context); + if (validator != null) { + // on enregistre le validateur + result.add(validator); + } + } + } + } + return result; + } + + /** + * Pour un context et un type d'entité donné, instancie un validateur + * et test si ce validateur est utilisable (i.e qu'il admet des champs + * à valider). + * + * Si aucun champ n'est trouvé dans le validateur, alors on retourne null. + * + * @param <B> le type du bean + * @param validatorClass le type de validateur a instancie + * @param klass le type du bean + * @param context le context du validateur + * @return le validateur initialisé, ou <code>null</code> si aucun scope + * détecté dans le validateur. + */ + protected <B> BeanValidator<B> getValidator(Class<?> validatorClass, Class<B> klass, String context) { + +// BeanValidator<B> valitator = new BeanValidator<B>(klass, context); + BeanValidator<B> valitator; + try { + valitator = (BeanValidator<B>) validatorClass.getConstructor(Class.class, String.class).newInstance(klass, context); + } catch (Exception ex) { + throw new RuntimeException("could not instanciate validator " + validatorClass + " for reason " + ex.getMessage(), ex); + } + + Set<BeanValidatorScope> scopes = valitator.getScopes(); + if (scopes.isEmpty()) { + valitator = null; + if (log.isDebugEnabled()) { + log.debug(klass + " : validator skip (no scopes detected)"); + } + } else { + if (log.isDebugEnabled()) { + log.debug(klass + " : keep validator " + valitator); + } + } + return valitator; + } + + protected File getClassDir(File sourceRoot, Class<?> clazz) { + String path = clazz.getPackage().getName().replaceAll("\\.", File.separator); + File dir = new File(sourceRoot, path); + return dir; + } + + protected String[] getContexts(Class<?> clazz, File dir) { + Set<String> result = new TreeSet<String>(); + ValidatorFilenameFilter filter = new ValidatorFilenameFilter(clazz); + if (log.isDebugEnabled()) { + log.debug("dir : " + dir); + } + String[] files = dir.list(filter); + for (String file : files) { + if (log.isDebugEnabled()) { + log.debug("file " + file); + } + String context = file.substring(filter.prefix.length(), file.length() - ValidatorFilenameFilter.SUFFIX.length()); + if (log.isDebugEnabled()) { + log.debug("detect " + clazz.getSimpleName() + " context [" + context + "]"); + } + result.add(context); + } + return result.toArray(new String[result.size()]); + } + + protected String[] getContextsWithoutScopes(String[] contexts) { + Set<String> result = new TreeSet<String>(); + BeanValidatorScope[] scopes = BeanValidatorScope.values(); + for (String context : contexts) { + for (BeanValidatorScope scope : scopes) { + String scopeName = scope.name().toLowerCase(); + if (!context.endsWith(scopeName)) { + // pas concerne par ce scope + continue; + } + if (log.isDebugEnabled()) { + log.debug("detect context : " + context); + } + String realContext = context.substring(0, context.length() - scopeName.length()); + if (realContext.endsWith("-")) { + realContext = realContext.substring(0, realContext.length() - 1); + } + result.add(realContext); + } + } + return result.toArray(new String[result.size()]); + } + + protected String[] getFilterContexts(Pattern contextFilter, String[] realContexts) { + List<String> result = new ArrayList<String>(); + for (String c : realContexts) { + Matcher m = contextFilter.matcher(c); + if (m.matches()) { + result.add(c); + } + } + return result.toArray(new String[result.size()]); + } + + protected static class ValidatorFilenameFilter implements FilenameFilter { + + protected static final String SUFFIX = "-validation.xml"; + protected Class<?> clazz; + protected String prefix; + + public ValidatorFilenameFilter(Class<?> clazz) { + this.clazz = clazz; + this.prefix = clazz.getSimpleName() + "-"; + } + + @Override + public boolean accept(File dir, String name) { + boolean result = name.endsWith(SUFFIX); + if (result) { + result = name.startsWith(prefix); + } + return result; + } + } + + protected static class BeanValidatorComparator implements Comparator<BeanValidator<?>> { + + @Override + public int compare(BeanValidator<?> o1, BeanValidator<?> o2) { + String contextName1 = o1.getBeanClass().getSimpleName() + "-" + (o1.getContextName() == null ? "" : o1.getContextName()); + String contextName2 = o2.getBeanClass().getSimpleName() + "-" + (o2.getContextName() == null ? "" : o2.getContextName()); + return contextName1.compareTo(contextName2); + } + } +} diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/BeanValidatorEvent.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/BeanValidatorEvent.java new file mode 100644 index 0000000..19d2069 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/BeanValidatorEvent.java @@ -0,0 +1,52 @@ +package jaxx.runtime.validator; + +/** + * The definition of an event on {@link BeanValidatorListener} + * to be fired by a {@link BeanValidator}. + * + * @author chemit + * @since 1.3 + */ +public class BeanValidatorEvent extends java.util.EventObject { + + private static final long serialVersionUID = 1L; + /** the field impacted by the validator */ + BeanValidatorField<?> field; + /** the scope impacted by the event */ + BeanValidatorScope scope; + String[] messagestoAdd; + String[] messagestoDelete; + + public BeanValidatorEvent(BeanValidator source, BeanValidatorField<?> field, BeanValidatorScope scope, String[] toAdd, String[] toDelete) { + super(source); + this.field = field; + this.scope = scope; + this.messagestoAdd = toAdd; + this.messagestoDelete = toDelete; + } + + @Override + public BeanValidator getSource() { + return (BeanValidator) super.getSource(); + } + + public String getFieldName() { + return field.getName(); + } + + public String[] getMessagesToAdd() { + return messagestoAdd; + } + + public String[] getMessagesToDelete() { + return messagestoDelete; + } + + public BeanValidatorScope getScope() { + return scope; + } + + public BeanValidatorField getField() { + return field; + } +} diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/BeanValidatorField.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/BeanValidatorField.java new file mode 100644 index 0000000..7277ab2 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/BeanValidatorField.java @@ -0,0 +1,239 @@ +package jaxx.runtime.validator; + +import static org.nuiton.i18n.I18n._; + +import javax.swing.event.EventListenerList; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.StringTokenizer; + +/** + * Definition of a field to be handled in a {@link BeanValidator}. + * <p/> + * A such class is only registred in {@link BeanValidator } when the field of the bean + * was found in validator xml configuration file for a {@link com.opensymphony.xwork2.validator.FieldValidator} only. + * <p/> + * This class use properties {@link #beanClass}, {@link #name} to define + * his naturel order. + * + * @author chemit + * @param <B> the type of the bean handled by the validator and this field of validation. + * @since 1.3 + */ +public class BeanValidatorField<B> { + + /** the class of bean */ + protected final Class<B> beanClass; + /** name of field in bean */ + protected final String name; + protected EnumMap<BeanValidatorScope, Set<String>> messages; + /** A list of event listeners for this validators */ + protected EventListenerList listenerList = new EventListenerList(); + + public BeanValidatorField(Class<B> beanClass, String name, List<BeanValidatorScope> scopes) { + this.beanClass = beanClass; + this.name = name; + messages = new EnumMap<BeanValidatorScope, Set<String>>(BeanValidatorScope.class); + for (BeanValidatorScope scope : scopes) { + messages.put(scope, new HashSet<String>()); + } + } + + public String getName() { + return name; + } + + public Class<B> getBeanClass() { + return beanClass; + } + + /** + * @return <code>true</code> if this field is valid (says is in error + * scope and has errors), <code>false</code> otherwise. + */ + public boolean isValid() { + return !hasErrors(); + } + + public BeanValidatorScope getScope() { + if (hasErrors()) { + return BeanValidatorScope.ERROR; + } + if (hasWarnings()) { + return BeanValidatorScope.WARNING; + } + if (hasInfos()) { + return BeanValidatorScope.INFO; + } + return null; + } + + public Set<BeanValidatorScope> getScopes() { + return messages.keySet(); + } + + public boolean hasErrors() { + return hasMessages(BeanValidatorScope.ERROR); + } + + public boolean hasWarnings() { + return hasMessages(BeanValidatorScope.WARNING); + } + + public boolean hasInfos() { + return hasMessages(BeanValidatorScope.INFO); + } + + public Set<String> getErrors() { + return getMessages(BeanValidatorScope.ERROR); + } + + public Set<String> getWarnings() { + return getMessages(BeanValidatorScope.WARNING); + } + + public Set<String> getInfos() { + return getMessages(BeanValidatorScope.INFO); + } + + public boolean hasMessages(BeanValidatorScope scope) { + return messages.containsKey(scope) && !getMessages(scope).isEmpty(); + } + + public Set<String> getMessages(BeanValidatorScope scope) { + return messages.get(scope); + } + + public void updateMessages(BeanValidator<B> validator, BeanValidatorScope scope, List<String> messages) { + + if (scope == null) { + + // special case to reset all messages from all scopes + + for (BeanValidatorScope s : getScopes()) { + + clearMessages(s, validator); + } + return; + } + + if (!this.messages.containsKey(scope)) { + throw new IllegalArgumentException("the scope " + scope + " was not registred for " + this); + } + + if (messages == null || messages.isEmpty()) { + + // no incoming message for this scope + + clearMessages(scope, validator); + return; + } + + // build the diff of messages (the one to delete, the one to add) + + boolean hasChanged = false; + + Set<String> currentMessages = getMessages(scope); + + // detect messages to delete + Set<String> toDelete = new java.util.HashSet<String>(currentMessages); + toDelete.removeAll(messages); + + if (!toDelete.isEmpty()) { + // apply delete + currentMessages.removeAll(toDelete); + hasChanged = true; + } + + // detect messages to add + Set<String> toAdd = new java.util.HashSet<String>(messages); + toAdd.removeAll(currentMessages); + + if (!toAdd.isEmpty()) { + // apply add + currentMessages.addAll(toAdd); + hasChanged = true; + } + + if (hasChanged) { + + // something has changed, fire notifications + String[] del = toDelete.toArray(new String[toDelete.size()]); + String[] add = toAdd.toArray(new String[toAdd.size()]); + + validator.fireFieldChanged(this, scope, add, del); + } + toAdd.clear(); + toDelete.clear(); + + } + + public String getI18nError(String error) { + String text; + if (error.indexOf("##") == -1) { + text = _(error); + } else { + StringTokenizer stk = new StringTokenizer(error, "##"); + String errorName = stk.nextToken(); + List<String> args = new ArrayList<String>(); + while (stk.hasMoreTokens()) { + args.add(stk.nextToken()); + } + text = _(errorName, args.toArray()); + } + return text; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof BeanValidatorField)) { + return false; + } + + BeanValidatorField that = (BeanValidatorField) o; + return beanClass.equals(that.beanClass) && name.equals(that.name); + } + + @Override + public int hashCode() { + int result = beanClass.hashCode(); + result = 31 * result + name.hashCode(); + return result; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("<").append(super.toString()); + sb.append(" beanClass:").append(beanClass); + sb.append(", name:").append(name); + sb.append(", scopes:").append(messages == null ? "[]" : messages.keySet()); + sb.append(", scope:").append(getScope()); + //sb.append(", errors:").append(errors); + sb.append('>'); + return sb.toString(); + } + + protected void clearMessages(BeanValidatorScope scope, BeanValidator<B> validator) { + // remove all messages + Set<String> toDelete = getMessages(scope); + + if (!toDelete.isEmpty()) { + + // there is some messages to delete + String[] toDel = toDelete.toArray(new String[toDelete.size()]); + + // apply deletion + toDelete.clear(); + + // fire + validator.fireFieldChanged(this, scope, null, toDel); + } + } +} diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/BeanValidatorListener.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/BeanValidatorListener.java new file mode 100644 index 0000000..54437c6 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/BeanValidatorListener.java @@ -0,0 +1,17 @@ +package jaxx.runtime.validator; + +/** + * The listener contract to be used on {@link BeanValidator] + * + * @author chemit + * @since 1.3 + */ +public interface BeanValidatorListener extends java.util.EventListener { + + /** + * Invoked when a validator detects some changes on a field. + * + * @param event the event + */ + void onFieldChanged(BeanValidatorEvent event); +} diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/BeanValidatorMessage.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/BeanValidatorMessage.java new file mode 100644 index 0000000..6435c8a --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/BeanValidatorMessage.java @@ -0,0 +1,72 @@ +package jaxx.runtime.validator; + +/** + * The object to box a validation message. + * + * @param <E> type of message (use for override {@link #compareTo(E)} method. + * + * @author chemit + * @since 1.3 + */ +public class BeanValidatorMessage<E extends BeanValidatorMessage> implements Comparable<E> { + + /** + * the validator that produce the message + */ + protected BeanValidator validator; + /** + * the field thatproduce the message + */ + protected BeanValidatorField field; + /** + * the label of the message (to be displayed somewhere) + */ + protected String message; + /** + * the scope of the message + */ + protected BeanValidatorScope scope; + + public BeanValidatorMessage(BeanValidator validator, BeanValidatorField field, String message, BeanValidatorScope scope) { + this.field = field; + this.validator = validator; + this.message = message; + this.scope = scope; + } + + public BeanValidator getValidator() { + return validator; + } + + public BeanValidatorField getField() { + return field; + } + + public BeanValidatorScope getScope() { + return scope; + } + + public String getMessage() { + return message; + } + + @Override + public int compareTo(E o) { + // sort on scope + int result = getScope().compareTo(o.getScope()); + if (result == 0) { + // sort on field name + result = field.getName().compareTo(o.field.getName()); + if (result == 0) { + // sort on message + result = message.compareTo(o.message); + } + } + return result; + } + + @Override + public String toString() { + return scope + " - " + field.getI18nError(message); + } +} diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/BeanValidatorScope.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/BeanValidatorScope.java new file mode 100644 index 0000000..12ecafb --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/BeanValidatorScope.java @@ -0,0 +1,46 @@ +package jaxx.runtime.validator; + +import static org.nuiton.i18n.I18n.n_; + +/** + * The differents levels of messages in validation process. + * <p/> + * The order of the enum defines the severity of validation. + * <p/> + * Always begin with error, then if no error found, try warning, then info... + * + * @author chemit + */ +public enum BeanValidatorScope { + + /** + * the error scope level. + * + * When a message of a such scope is found on a validator, then the validator + * is invalid and modified. + */ + ERROR(n_("validator.scope.error.label")), + /** + * the warning scope level. + * + * When a message of a such scope is found on a validator, then the validator + * is still valid but modified. + */ + WARNING(n_("validator.scope.warning.label")), + /** + * the information scope level. + * + * When a message of a sucg scope is found on a validator, then the + * validator is still valid and not modified. + */ + INFO(n_("validator.scope.info.label")); + private final String label; + + private BeanValidatorScope(String label) { + this.label = label; + } + + public String getLabel() { + return label; + } +} diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/XWorkBeanValidator.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/XWorkBeanValidator.java new file mode 100644 index 0000000..7eced3d --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/XWorkBeanValidator.java @@ -0,0 +1,252 @@ +package jaxx.runtime.validator; + +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.ValidationAwareSupport; +import com.opensymphony.xwork2.config.Configuration; +import com.opensymphony.xwork2.config.ConfigurationManager; +import com.opensymphony.xwork2.util.ValueStack; +import com.opensymphony.xwork2.util.ValueStackFactory; +import com.opensymphony.xwork2.validator.ActionValidatorManager; +import com.opensymphony.xwork2.validator.DelegatingValidatorContext; +import com.opensymphony.xwork2.validator.FieldValidator; +import com.opensymphony.xwork2.validator.ValidationException; +import com.opensymphony.xwork2.validator.Validator; +import java.util.Collection; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import jaxx.runtime.BeanValidatorUtil; + +/** + * + * A customized validator for a given bean. + * + * Use the method {@link #validate(java.lang.Object)} to obtain the messages + * detected by the validator for the given bean. + * + * @param <B> type of the bean to validate. + * + * @author chemit + * @since 1.3 + */ +public class XWorkBeanValidator<B> { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + private static final Log log = LogFactory.getLog(XWorkBeanValidator.class); + protected final static Map<String, List<String>> EMPTY_RESULT = Collections.unmodifiableMap(new HashMap<String, List<String>>()); + /** the type of bean to validate */ + protected final Class<B> beanClass; + /** the validation named context (can be null) */ + protected String contextName; + /** the list of field names detected for this validator */ + protected Set<String> fieldNames; + /** a flag to include or not the default context validators */ + protected boolean includeDefaultContext; + // -- + // XWorks fields + // -- + protected ValidationAwareSupport validationSupport; + protected DelegatingValidatorContext validationContext; + protected transient ActionValidatorManager validator; + protected ActionContext context; + + public XWorkBeanValidator(Class<B> beanClass, String contextName) { + this(beanClass, contextName, true, BeanValidatorUtil.getSharedValueStack()); + } + + public XWorkBeanValidator(Class<B> beanClass, String contextName, ValueStack vs) { + this(beanClass, contextName, true, vs); + } + + public XWorkBeanValidator(Class<B> beanClass, String contextName, boolean includeDefaultContext) { + this(beanClass, contextName, includeDefaultContext, BeanValidatorUtil.getSharedValueStack()); + } + + public XWorkBeanValidator(Class<B> beanClass, String contextName, boolean includeDefaultContext, ValueStack vs) { + + this.beanClass = beanClass; + this.includeDefaultContext = includeDefaultContext; + validationSupport = new ValidationAwareSupport(); + validationContext = new DelegatingValidatorContext(validationSupport); + + if (vs == null) { + // create a standalone value stack + ConfigurationManager confManager = new ConfigurationManager(); + Configuration conf = confManager.getConfiguration(); + vs = conf.getContainer().getInstance(ValueStackFactory.class).createValueStack(); + if (log.isDebugEnabled()) { + log.info("create a standalone value stack " + vs); + } + } else { + if (log.isDebugEnabled()) { + log.debug("use given value stack " + vs); + } + } + + context = new ActionContext(vs.getContext()); + ActionContext.setContext(context); + + // init validator + validator = context.getContainer().getInstance(ActionValidatorManager.class, "no-annotations"); + + // init context + setContextName(contextName); + } + + public boolean isIncludeDefaultContext() { + return includeDefaultContext; + } + + public Class<B> getBeanClass() { + return beanClass; + } + + public String getContextName() { + return contextName; + } + + public Set<String> getFieldNames() { + return fieldNames; + } + + public ActionValidatorManager getValidator() { + return validator; + } + + /** + * Test a the validator contains the field given his name + * + * @param fieldName the name of the searched field + * @return <code>true</code> if validator contaisn this field, <code>false</code> otherwise + */ + public boolean containsField(String fieldName) { + return fieldNames.contains(fieldName); + } + + public void setIncludeDefaultContext(boolean includeDefaultContext) { + this.includeDefaultContext = includeDefaultContext; + if (contextName != null) { + // reload context + setContextName(contextName); + } + } + + public void setContextName(String contextName) { + this.contextName = contextName; + // changing contextName may change fields definition + // so reload fields + initFields(); + } + + /** + * Valide le bean donné et retourne les messages produits. + * + * @param bean le bean a valider (il doit etre non null) + * + * @return le dictionnaire des messages produits par la validation indexées + * par le nom du champs du bean impacté. + */ + public Map<String, List<String>> validate(B bean) { + + if (bean == null) { + throw new NullPointerException("bean can not be null in method validate"); + } + + Map<String, List<String>> result = EMPTY_RESULT; + + // on lance la validation uniquement si des champs sont a valider + if (!fieldNames.isEmpty()) { + + try { + + //TC - 20081024 : since context is in a ThreadLocal variable, we must do the check + if (ActionContext.getContext() == null) { + ActionContext.setContext(context); + } + + validator.validate(bean, contextName, validationContext); + + if (log.isTraceEnabled()) { + log.trace("Action errors: " + validationContext.getActionErrors()); + log.trace("Action messages: " + validationContext.getActionMessages()); + log.trace("Field errors: " + validationContext.getFieldErrors()); + } + + if (log.isDebugEnabled()) { + log.debug(this + " : " + validationContext.getFieldErrors()); + } + + if (validationContext.hasFieldErrors()) { + Map messages = validationContext.getFieldErrors(); + result = new HashMap<String, List<String>>(messages.size()); + for (Object fieldName : messages.keySet()) { + Collection c = (Collection) messages.get(fieldName); + List<String> mm = new java.util.ArrayList<String>(c.size()); + for (Object message : c) { + mm.add(message + ""); + } + result.put(fieldName + "", mm); + } + } + + } catch (ValidationException eee) { + log.warn("Error during validation on " + beanClass + " for reason : " + eee.getMessage(), eee); + + } finally { + // on nettoye toujours le validateur apres operation + validationSupport.clearErrorsAndMessages(); + } + } + + return result; + } + + @Override + public String toString() { + return super.toString() + "<beanClass:" + beanClass + ", contextName:" + contextName + ">"; + } + + /** + * update the property {@link #fieldNames}, says search in XWorks + */ + protected synchronized void initFields() { + + if (fieldNames != null) { + fieldNames = null; + } + + Set<String> detectedFieldNames = new java.util.HashSet<String>(); + + int skip = 0; + if (contextName != null && !includeDefaultContext) { + // count the number of validator to skip + for (Validator v : validator.getValidators(beanClass, null)) { + // we only work on FieldValidator at the moment + if (v instanceof FieldValidator) { + skip++; + } + } + } + + for (Validator v : validator.getValidators(beanClass, contextName)) { + // we only work on FieldValidator at the moment + if (v instanceof FieldValidator) { + if (skip > 0) { + skip--; + continue; + } + FieldValidator fieldValidator = (FieldValidator) v; + log.debug("context " + contextName + " - field " + fieldValidator.getFieldName()); + String fName = fieldValidator.getFieldName(); + detectedFieldNames.add(fName); + } + } + + fieldNames = Collections.unmodifiableSet(detectedFieldNames); + } +} diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/field/CollectionFieldExpressionValidator.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/field/CollectionFieldExpressionValidator.java new file mode 100644 index 0000000..87abf3c --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/field/CollectionFieldExpressionValidator.java @@ -0,0 +1,448 @@ +package jaxx.runtime.validator.field; + +import com.opensymphony.xwork2.util.ValueStack; +import com.opensymphony.xwork2.validator.ValidationException; +import com.opensymphony.xwork2.validator.validators.FieldExpressionValidator; + +import java.util.Collection; +import java.util.Set; +import org.apache.commons.lang.builder.HashCodeBuilder; + +/** + * Un validateur basé sur {@link FieldExpressionValidator} qui valide sur une collection de propriéte. + * + * @author chemit + */ +public class CollectionFieldExpressionValidator extends FieldExpressionValidator { + + public enum Mode { + + /** au moins une entrée de la collection doit etre valide */ + AT_LEAST_ONE, + /** exactement une entrée dela collection doit être valide */ + EXACTLY_ONE, + /** toutes les valeurs de la collection doivent etre valides */ + ALL, + /** aucune valeur de la collection doivent etre valides */ + NONE, + /** detection de clef unique */ + UNIQUE_KEY + } + /** le mode de validation sur la liste */ + protected Mode mode; + /** + * pour indiquer la propriété qui contient la liste à valider. + * + * Si cette prorpiété n'est pas renseignée alors on utilise la + * {@link #getFieldName()} pour obtenir la collection. + * + * Cela permet d'effectuer une validation si une collection mais portant + * en fait sur un autre champs + * @since 1.5 + */ + protected String collectionFieldName; + /** + * drapeau pour utiliser le contexte de parcours pour valider + * l'expression, on dispose donc alors des variables previous, current, + * index, size et empty dans l'expression. + * + * Sinon l'expression s'applique directement sur l'entrée courant dans le + * parcours sans préfixe. + */ + protected boolean useSensitiveContext; + /** + * expression a valider sur la premiètre entrée de la collection. + * + * Note : Pour le moment, on autorise uniquement cela en mode ALL. + */ + protected String expressionForFirst; + /** + * expression a valider sur la dernière entrée de la collection. + * + * Note : Pour le moment, on autorise uniquement cela en mode ALL. + */ + protected String expressionForLast; + /** + * la liste des propriétés d'une entrée de la collection qui définit la + * clef unique (en mode UNIQUE_KEY). + */ + protected String[] keys; + /** le context de parcours */ + protected WalkerContext c; + private boolean useFirst, useLast; + + public Mode getMode() { + return mode; + } + + public void setMode(Mode mode) { + this.mode = mode; + } + + public String getCollectionFieldName() { + return collectionFieldName; + } + + public void setCollectionFieldName(String collectionFieldName) { + this.collectionFieldName = collectionFieldName; + } + + public boolean isUseSensitiveContext() { + return useSensitiveContext; + } + + public void setUseSensitiveContext(boolean useSensitiveContext) { + this.useSensitiveContext = useSensitiveContext; + } + + public String getExpressionForFirst() { + return expressionForFirst; + } + + public void setExpressionForFirst(String expressionForFirst) { + this.expressionForFirst = expressionForFirst; + } + + public String getExpressionForLast() { + return expressionForLast; + } + + public void setExpressionForLast(String expressionForLast) { + this.expressionForLast = expressionForLast; + } + + public String[] getKeys() { + return keys; + } + + public void setKeys(String[] keys) { + if (keys != null && keys.length == 1 && keys[0].indexOf(",") != -1) { + this.keys = keys[0].split(","); + } else { + this.keys = keys; + } + } + + @Override + public void validate(Object object) throws ValidationException { + if (mode == null) { + throw new ValidationException("no mode defined!"); + } + useFirst = expressionForFirst != null && !expressionForFirst.trim().isEmpty(); + useLast = expressionForLast != null && !expressionForLast.trim().isEmpty(); + + if (useFirst && mode != Mode.ALL) { + throw new ValidationException("can only use expressionForFirst in mode ALL but was " + mode); + } + if (useLast && mode != Mode.ALL) { + throw new ValidationException("can only use expressionForLast in mode ALL but was " + mode); + } + + String fieldName = getFieldName(); + + Collection<?> col = getCollection(object); + + if (useSensitiveContext) { + c = new WalkerContext(col.size()); + } + + boolean answer; + + boolean pop = false; + + if (!stack.getRoot().contains(object)) { + stack.push(object); + pop = true; + } + + switch (mode) { + case ALL: + answer = validateAllEntries(col); + break; + case AT_LEAST_ONE: + answer = validateAtLeastOneEntry(col); + break; + case EXACTLY_ONE: + answer = validateExtacltyOneEntry(col); + break; + case NONE: + answer = validateNoneEntry(col); + break; + case UNIQUE_KEY: + if (keys == null || keys.length == 0) { + throw new ValidationException("no unique keys defined"); + } + answer = validateUniqueKey(col); + break; + + default: + // should never come here... + answer = false; + } + + if (!answer) { + addFieldError(fieldName, object); + } + if (pop) { + stack.pop(); + } + } + protected ValueStack stack; + + @Override + public void setValueStack(ValueStack stack) { + super.setValueStack(stack); + this.stack = stack; + } + + @Override + public String getMessage(Object object) { + boolean pop = false; + + if (useSensitiveContext && !stack.getRoot().contains(c)) { + stack.push(c); + pop = true; + } + String message = super.getMessage(object); + + if (pop) { + stack.pop(); + } + return message; + } + + protected Boolean validateAllEntries(Collection<?> col) throws ValidationException { + boolean answer = true; + for (Object entry : col) { + answer = validateOneEntry(entry); + if (!answer) { + // validation on one entry has failed + // no need to continue + break; + } + } + return answer; + } + + protected Boolean validateNoneEntry(Collection<?> col) throws ValidationException { + boolean answer = true; + for (Object entry : col) { + boolean b = validateOneEntry(entry); + if (b) { + // one entry has sucessed, validation has failed + // no need to continue + answer = false; + break; + } + } + return answer; + } + + protected Boolean validateAtLeastOneEntry(Collection<?> col) throws ValidationException { + boolean answer = false; + for (Object entry : col) { + answer = validateOneEntry(entry); + if (answer) { + // one entry was succes, validation is ok, + // no need to continue + break; + } + } + return answer; + } + + protected Boolean validateExtacltyOneEntry(Collection<?> col) throws ValidationException { + int count = 0; + for (Object entry : col) { + boolean answer = validateOneEntry(entry); + if (answer) { + // one entry has succed + count++; + if (count > 1) { + // more than one entriy was successfull + // so validation has failed + break; + } + + } + } + return count == 1; + } + + protected Boolean validateUniqueKey(Collection<?> col) throws ValidationException { + boolean answer = true; + + Set<Integer> hashCodes = new java.util.HashSet<Integer>(); + int index = -1; + for (Object entry : col) { + index++; + // construction du hash de la clef d'unicite + Integer hash = getUniqueKeyHashCode(entry); + if (!hashCodes.contains(hash)) { + hashCodes.add(hash); + continue; + } + // une entree avec ce hash a deja ete trouvee + // on est donc en violation sur la clef unique + answer = false; + if (log.isDebugEnabled()) { + log.debug("duplicated uniquekey " + hash + " for entry " + index); + } + } + hashCodes.clear(); + return answer; + } + + protected boolean validateOneEntry(Object object) throws ValidationException { + + Boolean answer = Boolean.FALSE; + + boolean extraExpression = false; + + if (useSensitiveContext) { + c.addCurrent(object); + object = c; + + if (c.isFirst() && useFirst) { + // on valide l'expression sur la premiètre entrée + answer = evaluateExpression(expressionForFirst, object); + extraExpression = true; + } + if (c.isLast() && useLast) { + // on valide l'expression sur la dernière entrée + answer = (!extraExpression || answer) && evaluateExpression(expressionForLast, object); + extraExpression = true; + } + } + + answer = (!extraExpression || answer) && evaluateExpression(getExpression(), object); + + return answer; + } + + protected boolean evaluateExpression(String expression, Object object) throws ValidationException { + Object obj = null; + try { + obj = getFieldValue(expression, object); + } catch (ValidationException e) { + throw e; + } catch (Exception e) { + log.error(e.getMessage(), e); + // let this pass, but it will be logged right below + } + + Boolean answer = Boolean.FALSE; + + if (obj != null && obj instanceof Boolean) { + answer = (Boolean) obj; + } else { + log.warn("Got result of " + obj + " when trying to get Boolean for expression " + expression); + } + return answer; + } + + /** + * @param object the incoming object containing the collection to test + * @return the collection of the incoming object given by the fieldName property + * @throws ValidationException if any pb to retreave the collection + */ + protected Collection<?> getCollection(Object object) throws ValidationException { + String fieldName = getCollectionFieldName(); + if (fieldName == null || fieldName.trim().isEmpty()) { + // on travaille directement sur le fieldName + fieldName = getFieldName(); + } + + Object obj = null; + + // obtain the collection to test + try { + obj = getFieldValue(fieldName, object); + } catch (ValidationException e) { + throw e; + } catch (Exception e) { + // let this pass, but it will be logged right below + } + + if (obj == null) { + // la collection est nulle, donc on renvoie une collection vide + return java.util.Collections.EMPTY_LIST; + } + + if (!Collection.class.isInstance(obj)) { + throw new ValidationException("field " + fieldName + " is not a collection type! (" + obj.getClass() + ")"); + } + return (Collection<?>) obj; + } + + /** + * Calcule pour une entrée donné, le hash de la clef unique + * + * @param o l'entree de la collection dont on va calculer le hash de la clef unique + * @return le hashCode calclé de la clef unique sur l'entrée donné + * @throws ValidationException if any pb to retreave properties values + */ + protected Integer getUniqueKeyHashCode(Object o) throws ValidationException { + // calcul du hash à la volée + HashCodeBuilder builder = new HashCodeBuilder(); + for (String key : this.keys) { + Object property = getFieldValue(key, o); + if (log.isDebugEnabled()) { + log.debug("key " + key + " : " + property); + } + builder.append(property); + } + return builder.toHashCode(); + } + + @Override + public String getValidatorType() { + return "collectionFieldExpression"; + } + + public class WalkerContext { + + protected final int size; + + public WalkerContext(int size) { + this.size = size; + } + protected int index = -1; + protected Object current; + protected Object previous; + + public void addCurrent(Object current) { + index++; + previous = this.current; + this.current = current; + } + + public Object getCurrent() { + return current; + } + + public int getIndex() { + return index; + } + + public Object getPrevious() { + return previous; + } + + public int getSize() { + return size; + } + + public boolean isEmpty() { + return size == 0; + } + + public boolean isFirst() { + return index == 0; + } + + public boolean isLast() { + return index == size - 1; + } + } +} diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/field/CollectionUniqueKeyValidator.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/field/CollectionUniqueKeyValidator.java new file mode 100644 index 0000000..4d1e9b4 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/field/CollectionUniqueKeyValidator.java @@ -0,0 +1,208 @@ +package jaxx.runtime.validator.field; + +import com.opensymphony.xwork2.validator.ValidationException; +import com.opensymphony.xwork2.validator.validators.FieldExpressionValidator; +import org.apache.commons.lang.builder.HashCodeBuilder; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * Un validateur basé sur {@link FieldExpressionValidator} qui valide une clef + * unique sur une collection. + * <p/> + * Le {@link #fieldName} sert à récupérer la propriété de type de collection du bean. + * + * @author chemit + */ +public class CollectionUniqueKeyValidator extends FieldExpressionValidator { + + /** + * pour indiquer la propriété qui contient la liste à valider. + * + * Si cette prorpiété n'est pas renseignée alors on utilise la + * {@link #getFieldName()} pour obtenir la collection. + * + * Cela permet d'effectuer une validation si une collection mais portant + * en fait sur un autre champs + * @since 1.5 + */ + protected String collectionFieldName; + /** + * la liste des propriétés d'une entrée de la collection qui définit la + * clef unique. + */ + protected String[] keys; + /** + * Une propriété optionnelle pour valider que l'objet reflétée par cette + * propriété ne viole pas l'intégrité de la clef unique. + * Cela permet de valider l'unicité sans que l'objet soit dans la collection + */ + protected String againstProperty; + /** + * Lors de l'utilisation de la againstProperty et qu'un ne peut pas utiliser + * le equals sur l'objet, on peut spécifier une expression pour exclure des tests + * à exclure lors de la recherche de la violation de clef unique. + */ + protected String againstIndexExpression; + + public String getCollectionFieldName() { + return collectionFieldName; + } + + public void setCollectionFieldName(String collectionFieldName) { + this.collectionFieldName = collectionFieldName; + } + + public String[] getKeys() { + return keys; + } + + public void setKeys(String[] keys) { + if (keys != null && keys.length == 1 && keys[0].indexOf(",") != -1) { + this.keys = keys[0].split(","); + } else { + this.keys = keys; + } + } + + public String getAgainstProperty() { + return againstProperty; + } + + public void setAgainstProperty(String againstProperty) { + this.againstProperty = againstProperty; + } + + public String getAgainstIndexExpression() { + return againstIndexExpression; + } + + public void setAgainstIndexExpression(String againstIndexExpression) { + this.againstIndexExpression = againstIndexExpression; + } + + @Override + public void validate(Object object) throws ValidationException { + + if (keys == null || keys.length == 0) { + throw new ValidationException("no unique keys defined"); + } + + String fieldName = getFieldName(); + + Collection<?> col = getCollection(object); + + Object againstBean = againstProperty == null ? null : getFieldValue(againstProperty, object); + + Integer againstIndex = (Integer) (againstIndexExpression == null ? -1 : getFieldValue(againstIndexExpression, object)); + if (againstIndex == null) { + againstIndex = -1; + } + if (againstBean == null && col.size() < 2) { + // la liste ne contient pas deux entrées donc c'est valide + return; + } + + boolean answer = true; + + Integer againstHashCode = againstBean == null ? null : getUniqueKeyHashCode(againstBean); + + List<Integer> hashCodes = new ArrayList<Integer>(); + + int index = 0; + for (Object o : col) { + Integer hash = getUniqueKeyHashCode(o); + if (againstBean == null) { + if (hashCodes.contains(hash)) { + // on a deja rencontre cette clef unique, + // donc la validation a echouee + answer = false; + break; + } + } else { + // utilisation de againstBean + if (againstIndex != -1) { + if (index != againstIndex && hash.equals(againstHashCode)) { + // on a deja rencontre cette clef unique, + // donc la validation a echouee + answer = false; + break; + } + } else { + if (!againstBean.equals(o) && hash.equals(againstHashCode)) { + // on a deja rencontre cette clef unique, + // donc la validation a echouee + answer = false; + break; + } + } + } + // nouveau hashcode enregistre + hashCodes.add(hash); + // index suivant + index++; + } + + if (!answer) { + addFieldError(fieldName, object); + } + } + + /** + * Calcule pour une entrée donné, le hash de la clef unique + * + * @param o l'entree de la collection dont on va calculer le hash de la clef unique + * @return le hashCode calclé de la clef unique sur l'entrée donné + * @throws ValidationException if any pb to retreave properties values + */ + protected Integer getUniqueKeyHashCode(Object o) throws ValidationException { + // calcul du hash à la volée + HashCodeBuilder builder = new HashCodeBuilder(); + for (String key : this.keys) { + Object property = getFieldValue(key, o); + builder.append(property); + } + return builder.toHashCode(); + } + + /** + * @param object the incoming object containing the collection to test + * @return the collection of the incoming object given by the fieldName property + * @throws ValidationException if any pb to retreave the collection + */ + protected Collection<?> getCollection(Object object) throws ValidationException { + String fieldName = getCollectionFieldName(); + if (fieldName == null || fieldName.trim().isEmpty()) { + // on travaille directement sur le fieldName + fieldName = getFieldName(); + } + + Object obj = null; + + // obtain the collection to test + try { + obj = getFieldValue(fieldName, object); + } catch (ValidationException e) { + throw e; + } catch (Exception e) { + // let this pass, but it will be logged right below + } + + if (obj == null) { + // la collection est nulle, donc on renvoie une collection vide + return java.util.Collections.EMPTY_LIST; + } + + if (!Collection.class.isInstance(obj)) { + throw new ValidationException("field " + fieldName + " is not a collection type! (" + obj.getClass() + ")"); + } + return (Collection<?>) obj; + } + + @Override + public String getValidatorType() { + return "collectionUniqueKey"; + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/field/ExistingDirectoryFieldValidator.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/field/ExistingDirectoryFieldValidator.java new file mode 100644 index 0000000..ee2e4a7 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/field/ExistingDirectoryFieldValidator.java @@ -0,0 +1,72 @@ +package jaxx.runtime.validator.field; + +import com.opensymphony.xwork2.validator.ValidationException; +import com.opensymphony.xwork2.validator.validators.FieldValidatorSupport; + +import java.io.File; + +/** + * <!-- START SNIPPET: javadoc --> + * ExistingDirectoryFieldValidator checks that a File field exists and is a directory. + * <!-- END SNIPPET: javadoc --> + * <p/> + * <p/> + * <!-- START SNIPPET: parameters --> + * <ul> + * <li>fieldName - The field name this validator is validating. Required if using Plain-Validator Syntax otherwise not required</li> + * </ul> + * <!-- END SNIPPET: parameters --> + * <p/> + * <p/> + * <pre> + * <!-- START SNIPPET: examples --> + * <validators> + * <!-- Plain-Validator Syntax --> + * <validator type="existingDirectory"> + * <param name="fieldName">tmp</param> + * <message>tmp is not an existing directory</message> + * </validator> + * <p/> + * <!-- Field-Validator Syntax --> + * <field name="tmp"> + * <field-validator type="existingDirectory"> + * <message>tmp is not an existing directory</message> + * </field-validator> + * </field> + * </validators> + * <!-- END SNIPPET: examples --> + * </pre> + * + * @author chemit + */ +public class ExistingDirectoryFieldValidator extends FieldValidatorSupport { + + public void validate(Object object) throws ValidationException { + String fieldName = getFieldName(); + Object value = this.getFieldValue(fieldName, object); + if (value==null) { + // no value defined + addFieldError(fieldName, object); + return; + } + File f; + if (value instanceof File) { + f = (File) value; + } else if (value instanceof String) { + f = new File((String) value); + } else { + addFieldError(fieldName, object); + return; + } + + if (!(f.isDirectory() && f.exists())) { + // f is not a directory, nor exists + addFieldError(fieldName, object); + } + } + + @Override + public String getValidatorType() { + return "existingDirectory"; + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/field/ExistingFileFieldValidator.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/field/ExistingFileFieldValidator.java new file mode 100644 index 0000000..72219b0 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/field/ExistingFileFieldValidator.java @@ -0,0 +1,72 @@ +package jaxx.runtime.validator.field; + +import com.opensymphony.xwork2.validator.ValidationException; +import com.opensymphony.xwork2.validator.validators.FieldValidatorSupport; + +import java.io.File; + +/** + * <!-- START SNIPPET: javadoc --> + * ExistingFileFieldValidator checks that a File field exists. * + * <!-- END SNIPPET: javadoc --> + * <p/> + * <p/> + * <!-- START SNIPPET: parameters --> + * <ul> + * <li>fieldName - The field name this validator is validating. Required if using Plain-Validator Syntax otherwise not required</li> + * </ul> + * <!-- END SNIPPET: parameters --> + * <p/> + * <p/> + * <pre> + * <!-- START SNIPPET: examples --> + * <validators> + * <!-- Plain-Validator Syntax --> + * <validator type="fileExisting"> + * <param name="fieldName">tmp</param> + * <message>tmp is not an existing file</message> + * </validator> + * <p/> + * <!-- Field-Validator Syntax --> + * <field name="tmp"> + * <field-validator type="fileExisting"> + * <message>tmp is not an existing file</message> + * </field-validator> + * </field> + * </validators> + * <!-- END SNIPPET: examples --> + * </pre> + * + * @author chemit + */ +public class ExistingFileFieldValidator extends FieldValidatorSupport { + + public void validate(Object object) throws ValidationException { + String fieldName = getFieldName(); + Object value = this.getFieldValue(fieldName, object); + if (value == null) { + // no value defined + addFieldError(fieldName, object); + return; + } + File f; + if (value instanceof File) { + f = (File) value; + } else if (value instanceof String) { + f = new File((String) value); + } else { + addFieldError(fieldName, object); + return; + } + + if (!(f.isFile() && f.exists())) { + // f is not a file nor exists + addFieldError(fieldName, object); + } + } + + @Override + public String getValidatorType() { + return "existingFile"; + } +} diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/field/FieldExpressionWithParamsValidator.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/field/FieldExpressionWithParamsValidator.java new file mode 100644 index 0000000..1ab01cf --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/field/FieldExpressionWithParamsValidator.java @@ -0,0 +1,175 @@ +package jaxx.runtime.validator.field; + +import com.opensymphony.xwork2.util.ValueStack; +import com.opensymphony.xwork2.validator.ValidationException; +import com.opensymphony.xwork2.validator.validators.FieldExpressionValidator; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.nuiton.util.ConverterUtil; + +/** + * Extends {@link FieldExpressionValidator} to add some extra parameters available + * in the {@link #getExpression()} + * + * @author tony + * @since 1.3 + */ +public class FieldExpressionWithParamsValidator extends FieldExpressionValidator { + + protected static final Pattern EXTRA_BOOLEAN_PARAM_ENTRY_PATTERN = Pattern.compile("(\\w+)\\:(false|true)"); + protected static final Pattern EXTRA_SHORT_PARAM_ENTRY_PATTERN = Pattern.compile("(\\w+)\\:(\\d+)"); + protected static final Pattern EXTRA_INT_PARAM_ENTRY_PATTERN = Pattern.compile("(\\w+)\\:(\\d+)"); + protected static final Pattern EXTRA_LONG_PARAM_ENTRY_PATTERN = Pattern.compile("(\\w+)\\:(\\d+)"); + protected static final Pattern EXTRA_DOUBLE_PARAM_ENTRY_PATTERN = Pattern.compile("(\\w+)\\:(\\d+\\.\\d+)"); + protected static final Pattern EXTRA_STRING_PARAM_ENTRY_PATTERN = Pattern.compile("(\\w+)\\:(.+)"); + protected ValueStack stack; + protected String booleanParams; + protected String shortParams; + protected String intParams; + protected String longParams; + protected String doubleParams; + protected String stringParams; + protected Map<String, Boolean> booleans; + protected Map<String, Short> shorts; + protected Map<String, Integer> ints; + protected Map<String, Long> longs; + protected Map<String, Double> doubles; + protected Map<String, String> strings; + + public String getBooleanParams() { + return booleanParams; + } + + public void setBooleanParams(String booleanParams) { + this.booleanParams = booleanParams; + } + + public String getDoubleParams() { + return doubleParams; + } + + public void setDoubleParams(String doubleParams) { + this.doubleParams = doubleParams; + } + + public String getIntParams() { + return intParams; + } + + public void setIntParams(String intParams) { + this.intParams = intParams; + } + + public String getLongParams() { + return longParams; + } + + public void setLongParams(String longParams) { + this.longParams = longParams; + } + + public String getShortParams() { + return shortParams; + } + + public void setShortParams(String shortParams) { + this.shortParams = shortParams; + } + + public String getStringParams() { + return stringParams; + } + + public void setStringParams(String stringParams) { + this.stringParams = stringParams; + } + + public Map<String, Boolean> getBooleans() { + return booleans; + } + + public Map<String, Double> getDoubles() { + return doubles; + } + + public Map<String, Integer> getInts() { + return ints; + } + + public Map<String, Long> getLongs() { + return longs; + } + + public Map<String, Short> getShorts() { + return shorts; + } + + public Map<String, String> getStrings() { + return strings; + } + + @Override + public String getValidatorType() { + return "fieldexpressionwithparams"; + } + + @Override + public void setValueStack(ValueStack stack) { + super.setValueStack(stack); + this.stack = stack; + } + + @Override + public void validate(Object object) throws ValidationException { + + booleans = initParams(Boolean.class, booleanParams, EXTRA_BOOLEAN_PARAM_ENTRY_PATTERN); + shorts = initParams(Short.class, shortParams, EXTRA_SHORT_PARAM_ENTRY_PATTERN); + ints = initParams(Integer.class, intParams, EXTRA_INT_PARAM_ENTRY_PATTERN); + longs = initParams(Long.class, longParams, EXTRA_LONG_PARAM_ENTRY_PATTERN); + doubles = initParams(Double.class, doubleParams, EXTRA_DOUBLE_PARAM_ENTRY_PATTERN); + strings = initParams(String.class, stringParams, EXTRA_STRING_PARAM_ENTRY_PATTERN); + + boolean pop = false; + if (!stack.getRoot().contains(this)) { + stack.push(this); + pop = true; + } + + try { + super.validate(object); + } finally { + if (pop) { + stack.pop(); + } + } + + } + + protected <T> Map<String, T> initParams(Class<T> klass, String extraParams, Pattern pattern) throws ValidationException { + + if (extraParams == null || extraParams.isEmpty()) { + // not using + return null; + } + + StringTokenizer stk = new StringTokenizer(extraParams, "|"); + Map<String, T> result = new java.util.TreeMap<String, T>(); + while (stk.hasMoreTokens()) { + String entry = stk.nextToken(); + Matcher matcher = pattern.matcher(entry); + if (!matcher.matches()) { + throw new ValidationException("could not parse for extra params " + extraParams + " for type " + klass.getName()); + } + String paramName = matcher.group(1); + String paramValueStr = matcher.group(2); + T paramValue = ConverterUtil.convert(klass, paramValueStr); + if (log.isDebugEnabled()) { + log.debug("detected extra param : <type:" + klass + ", name:" + paramName + ", value:" + paramValue + ">"); + } + result.put(paramName, paramValue); + } + return result; + } +} diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/field/NotExistingDirectoryFieldValidator.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/field/NotExistingDirectoryFieldValidator.java new file mode 100644 index 0000000..7d38e41 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/field/NotExistingDirectoryFieldValidator.java @@ -0,0 +1,72 @@ +package jaxx.runtime.validator.field; + +import com.opensymphony.xwork2.validator.ValidationException; +import com.opensymphony.xwork2.validator.validators.FieldValidatorSupport; + +import java.io.File; + +/** + * <!-- START SNIPPET: javadoc --> + * NotExistingDirectoryFieldValidator checks that a File field as a directory does not exist. * + * <!-- END SNIPPET: javadoc --> + * <p/> + * <p/> + * <!-- START SNIPPET: parameters --> + * <ul> + * <li>fieldName - The field name this validator is validating. Required if using Plain-Validator Syntax otherwise not required</li> + * </ul> + * <!-- END SNIPPET: parameters --> + * <p/> + * <p/> + * <pre> + * <!-- START SNIPPET: examples --> + * <validators> + * <!-- Plain-Validator Syntax --> + * <validator type="notExistingDirectory"> + * <param name="fieldName">tmp</param> + * <message>tmp is an existing directory</message> + * </validator> + * <p/> + * <!-- Field-Validator Syntax --> + * <field name="tmp"> + * <field-validator type="notExistingDirectory"> + * <message>tmp is an existing directory</message> + * </field-validator> + * </field> + * </validators> + * <!-- END SNIPPET: examples --> + * </pre> + * + * @author chemit + */ +public class NotExistingDirectoryFieldValidator extends FieldValidatorSupport { + + @Override + public void validate(Object object) throws ValidationException { + String fieldName = getFieldName(); + Object value = this.getFieldValue(fieldName, object); + if (value == null) { + // no value defined + addFieldError(fieldName, object); + return; + } + File f; + if (value instanceof File) { + f = (File) value; + } else if (value instanceof String) { + f = new File((String) value); + } else { + addFieldError(fieldName, object); + return; + } + + if (f.exists() || f.isFile()) { + addFieldError(fieldName, object); + } + } + + @Override + public String getValidatorType() { + return "notExistingDirectory"; + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/field/NotExistingFileFieldValidator.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/field/NotExistingFileFieldValidator.java new file mode 100644 index 0000000..1ef8788 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/field/NotExistingFileFieldValidator.java @@ -0,0 +1,73 @@ +package jaxx.runtime.validator.field; + +import com.opensymphony.xwork2.validator.ValidationException; +import com.opensymphony.xwork2.validator.validators.FieldValidatorSupport; + +import java.io.File; + +/** + * <!-- START SNIPPET: javadoc --> + * NotExistingFileFieldValidator checks that a File field as a file does not exist. * + * <!-- END SNIPPET: javadoc --> + * <p/> + * <p/> + * <!-- START SNIPPET: parameters --> + * <ul> + * <li>fieldName - The field name this validator is validating. Required if using Plain-Validator Syntax otherwise not required</li> + * </ul> + * <!-- END SNIPPET: parameters --> + * <p/> + * <p/> + * <pre> + * <!-- START SNIPPET: examples --> + * <validators> + * <!-- Plain-Validator Syntax --> + * <validator type="notExistingFile"> + * <param name="fieldName">tmp</param> + * <message>tmp is an existing file</message> + * </validator> + * <p/> + * <!-- Field-Validator Syntax --> + * <field name="tmp"> + * <field-validator type="notExistingFile"> + * <message>tmp is an existing file</message> + * </field-validator> + * </field> + * </validators> + * <!-- END SNIPPET: examples --> + * </pre> + * + * @author chemit + */ +public class NotExistingFileFieldValidator extends FieldValidatorSupport { + + @Override + public void validate(Object object) throws ValidationException { + String fieldName = getFieldName(); + Object value = this.getFieldValue(fieldName, object); + if (value==null) { + // no value defined + addFieldError(fieldName, object); + return; + } + File f; + if (value instanceof File) { + f = (File) value; + } else if (value instanceof String) { + f = new File((String) value); + } else { + addFieldError(fieldName, object); + return; + } + + if (f.exists() || f.isDirectory()) { + // f is not a file and exist + addFieldError(fieldName, object); + } + } + + @Override + public String getValidatorType() { + return "notExistingFile"; + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/field/RequiredFileFieldValidator.java b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/field/RequiredFileFieldValidator.java new file mode 100644 index 0000000..6bf973a --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/java/jaxx/runtime/validator/field/RequiredFileFieldValidator.java @@ -0,0 +1,72 @@ +package jaxx.runtime.validator.field; + +import com.opensymphony.xwork2.validator.ValidationException; +import com.opensymphony.xwork2.validator.validators.FieldValidatorSupport; + +import java.io.File; + +/** + * <!-- START SNIPPET: javadoc --> + * RequiredFileFieldValidator checks that a File field is not null nor have an empty filename. + * <!-- END SNIPPET: javadoc --> + * <p/> + * <p/> + * <!-- START SNIPPET: parameters --> + * <ul> + * <li>fieldName - The field name this validator is validating. Required if using Plain-Validator Syntax otherwise not required</li> + * </ul> + * <!-- END SNIPPET: parameters --> + * <p/> + * <p/> + * <pre> + * <!-- START SNIPPET: examples --> + * <validators> + * <!-- Plain-Validator Syntax --> + * <validator type="requiredFile"> + * <param name="fieldName">tmp</param> + * <message>tmp is required</message> + * </validator> + * <p/> + * <!-- Field-Validator Syntax --> + * <field name="tmp"> + * <field-validator type="requiredFile"> + * <message>tmp is required</message> + * </field-validator> + * </field> + * </validators> + * <!-- END SNIPPET: examples --> + * </pre> + * + * @author chemit + */ +public class RequiredFileFieldValidator extends FieldValidatorSupport { + + public void validate(Object object) throws ValidationException { + String fieldName = getFieldName(); + Object value = this.getFieldValue(fieldName, object); + if (value == null) { + // no value defined + addFieldError(fieldName, object); + return; + } + File f; + if (value instanceof File) { + f = (File) value; + } else if (value instanceof String) { + f = new File((String) value); + } else { + addFieldError(fieldName, object); + return; + } + + if (f.getPath().trim().isEmpty()) { + // f is not a directory nor exists + addFieldError(fieldName, object); + } + } + + @Override + public String getValidatorType() { + return "requiredFile"; + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/main/resources/i18n/jaxx-runtime-api-en_GB.properties b/trunk/jaxx-runtime-api/src/main/resources/i18n/jaxx-runtime-api-en_GB.properties new file mode 100644 index 0000000..0474916 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/resources/i18n/jaxx-runtime-api-en_GB.properties @@ -0,0 +1,3 @@ +validator.scope.error.label=Error +validator.scope.info.label=Information +validator.scope.warning.label=Warning diff --git a/trunk/jaxx-runtime-api/src/main/resources/i18n/jaxx-runtime-api-fr_FR.properties b/trunk/jaxx-runtime-api/src/main/resources/i18n/jaxx-runtime-api-fr_FR.properties new file mode 100644 index 0000000..0e3fddc --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/resources/i18n/jaxx-runtime-api-fr_FR.properties @@ -0,0 +1,3 @@ +validator.scope.error.label=Erreur +validator.scope.info.label=Information +validator.scope.warning.label=Avertissement diff --git a/trunk/jaxx-runtime-api/src/main/resources/validators.xml b/trunk/jaxx-runtime-api/src/main/resources/validators.xml new file mode 100644 index 0000000..028fed7 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/main/resources/validators.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE validators PUBLIC + "-//OpenSymphony Group//XWork Validator Config 1.0//EN" + "http://www.opensymphony.com/xwork/xwork-validator-config-1.0.dtd"> + +<!-- START SNIPPET: validators --> +<validators> + <validator name="requiredFile" class="jaxx.runtime.validator.field.RequiredFileFieldValidator"/> + <validator name="existingFile" class="jaxx.runtime.validator.field.ExistingFileFieldValidator"/> + <validator name="notExistingFile" class="jaxx.runtime.validator.field.NotExistingFileFieldValidator"/> + <validator name="existingDirectory" class="jaxx.runtime.validator.field.ExistingDirectoryFieldValidator"/> + <validator name="notExistingDirectory" class="jaxx.runtime.validator.field.NotExistingDirectoryFieldValidator"/> + <validator name="collectionFieldExpression" + class="jaxx.runtime.validator.field.CollectionFieldExpressionValidator"/> + <validator name="collectionUniqueKey" + class="jaxx.runtime.validator.field.CollectionUniqueKeyValidator"/> +</validators> + <!-- END SNIPPET: validators --> diff --git a/trunk/jaxx-runtime-api/src/site/site.xml b/trunk/jaxx-runtime-api/src/site/site.xml new file mode 100644 index 0000000..6c8144f --- /dev/null +++ b/trunk/jaxx-runtime-api/src/site/site.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project name="${project.name}"> + + <bannerLeft> + <name>${project.name}</name> + <src>${site.home.url}/jaxx.png</src> + <href>index.html</href> + </bannerLeft> + + <body> + + <breadcrumbs> + <item name="${project.name}" href="${project.url}" /> + </breadcrumbs> + + <menu ref="parent"/> + + <menu name="Utilisateur" inherited="top"/> + + <menu ref="reports"/> + + <menu ref="modules"/> + + </body> +</project> diff --git a/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/DefaultApplicationContextTest.java b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/DefaultApplicationContextTest.java new file mode 100644 index 0000000..f5deedc --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/DefaultApplicationContextTest.java @@ -0,0 +1,117 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package jaxx.runtime; + +import jaxx.runtime.DefaultApplicationContext.AutoLoad; +import jaxx.runtime.DefaultApplicationContext.MethodAccess; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * + * @author tony + */ +public class DefaultApplicationContextTest { + + static int helloCount; + static int helloGetCount; + + @AutoLoad + @MethodAccess(methodName = "hello", target = String.class) + public static class Hello { + + public Hello() { + helloCount++; + } + + public String hello(String name) { + helloGetCount++; + return "hello " + name; + } + } + DefaultApplicationContext context; + + @BeforeClass + public static void setUpClass() throws Exception { + helloCount = 0; + helloGetCount = 0; + } + + @AfterClass + public static void tearDownClass() throws Exception { + } + + @Before + public void setUp() { + context = new DefaultApplicationContext(); + assertEquals(0, helloCount); + assertEquals(0, helloGetCount); + } + + @After + public void tearDown() { + context = null; + helloCount = helloGetCount = 0; + } + + @Test(expected = IllegalArgumentException.class) + public void testAutoLoadNamed() { + context.getContextValue(Hello.class, "fakeName"); + } + + @Test + public void testAutoLoad() { + Hello hello = context.getContextValue(Hello.class); + assertNotNull(hello); + assertEquals(1, helloCount); + + Hello hello2 = context.getContextValue(Hello.class); + assertNotNull(hello2); + assertEquals(1, helloCount); + assertEquals(hello, hello2); + } + + @Test + public void testForward() { + context.getContextValue(Hello.class); + assertEquals(1, helloCount); + String response = context.getContextValue(String.class, "John"); + assertNotNull(response); + assertEquals(1, helloGetCount); + assertEquals(new Hello().hello("John"), response); + } + + @Test + public void testRemove() { + String response; + + context.getContextValue(Hello.class); + assertEquals(1, helloCount); + assertEquals(1, context.forwards.size()); + response = context.getContextValue(String.class, "John"); + assertNotNull(response); + + context.removeContextValue(Hello.class); + assertEquals(0, context.forwards.size()); + response = context.getContextValue(String.class, "John"); + assertEquals(1, helloCount); + assertNull(response); + + // reinstanciate the service + context.getContextValue(Hello.class); + assertEquals(2, helloCount); + assertEquals(1, context.forwards.size()); + + // no effect with a name + context.removeContextValue(Hello.class, "fake"); + assertEquals(1, context.forwards.size()); + context.getContextValue(Hello.class); + assertEquals(2, helloCount); + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/DefaultJAXXContextTest.java b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/DefaultJAXXContextTest.java new file mode 100644 index 0000000..96fc62f --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/DefaultJAXXContextTest.java @@ -0,0 +1,299 @@ +package jaxx.runtime; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.awt.Container; +import java.util.Map; + +/** @author chemit */ +public class DefaultJAXXContextTest { + + DefaultJAXXContext ctxt; + + @Before + public void initContext() throws Exception { + + // instanciate a new empty context + ctxt = new DefaultJAXXContext(); + } + + @Test(expected = IllegalStateException.class) + public void testParentContainerFail_IllegalStateException() throws Exception { + ctxt.getParentContainer(Container.class); + } + + @Test(expected = IllegalStateException.class) + public void testParentContainerFail_IllegalStateException2() throws Exception { + ctxt.getParentContainer("null", Container.class); + } + + + @Test(expected = IllegalArgumentException.class) + public void testParentContainerFail_IllegalArgumentException() throws Exception { + + // attach a fake ui (which is NOT a Container) + ctxt.setUi(new MyJAXXObject()); + ctxt.getParentContainer(Container.class); + } + + @Test(expected = IllegalArgumentException.class) + public void testParentContainerFail_IllegalArgumentException2() throws Exception { + + // attach a fake ui (which is NOT a Container) + ctxt.setUi(new MyJAXXObject()); + ctxt.getParentContainer(null, Container.class); + } + + @Test(expected = IllegalArgumentException.class) + public void testParentContainerFail_IllegalArgumentException3() throws Exception { + + // attach a fake ui (which is NOT a Container) + ctxt.setUi(new MyJAXXObject()); + ctxt.getParentContainer("null", Container.class); + } + + @Test + public void testGetParentContext() throws Exception { + JAXXContext expected, result; + expected = null; + result = ctxt.getContextValue(JAXXContext.class); + Assert.assertEquals(expected, result); + + DefaultJAXXContext parentContext = new DefaultJAXXContext(); + + ctxt.setContextValue(parentContext); + + expected = parentContext; + result = ctxt.getContextValue(JAXXContext.class); + Assert.assertEquals(expected, result); + } + + @Test + public void testSetGetContextValue() throws Exception { + String expected; + String result; + + result = ctxt.getContextValue(String.class); + Assert.assertNull(result); + + expected = "yo"; + ctxt.setContextValue(expected); + result = ctxt.getContextValue(String.class); + Assert.assertEquals(expected, result); + + expected = "ya"; + ctxt.setContextValue(expected, "second"); + result = ctxt.getContextValue(String.class, "second"); + Assert.assertEquals(expected, result); + + expected = "yi"; + ctxt.setContextValue(expected, "second"); + result = ctxt.getContextValue(String.class, "second"); + Assert.assertEquals(expected, result); + } + + @Test + public void testSetGetContextValueInParentContext() throws Exception { + + // attach parent context + JAXXContext parentContext = new DefaultJAXXContext(); + ctxt.setContextValue(parentContext); + + String expected; + String result; + + result = ctxt.getContextValue(String.class); + Assert.assertNull(result); + + expected = "yo"; + result = ctxt.getContextValue(String.class); + Assert.assertNull(result); + parentContext.setContextValue(expected); + result = ctxt.getContextValue(String.class); + Assert.assertEquals(expected, result); + + expected = "ya"; + result = ctxt.getContextValue(String.class, "second"); + Assert.assertNull(result); + parentContext.setContextValue(expected, "second"); + result = ctxt.getContextValue(String.class, "second"); + Assert.assertEquals(expected, result); + + expected = "yi"; + result = ctxt.getContextValue(String.class, "second"); + parentContext.setContextValue(expected, "second"); + Assert.assertEquals("ya", result); + result = ctxt.getContextValue(String.class, "second"); + Assert.assertEquals(expected, result); + } + + @Test + public void testSetGetContextValue2() throws Exception { + + // attach parent context + JAXXContext parentContext = new DefaultJAXXContext(); + ctxt.setContextValue(parentContext); + + String expected; + String result; + + result = ctxt.getContextValue(String.class); + Assert.assertNull(result); + result = ctxt.getContextValue(String.class, "yo"); + Assert.assertNull(result); + + expected = "yo"; + ctxt.setContextValue(expected, "yo"); + + result = ctxt.getContextValue(String.class); + Assert.assertNull(result); + result = ctxt.getContextValue(String.class, "yo"); + Assert.assertEquals(expected, result); + } + + @Test + public void testSetGetContextValueInParentParentContext() throws Exception { + + // attach parent parent context + JAXXContext parentParentContext = new DefaultJAXXContext(); + JAXXContext parentContext = new DefaultJAXXContext(); + parentContext.setContextValue(parentParentContext); + ctxt.setContextValue(parentContext); + + String expected; + String result; + + result = ctxt.getContextValue(String.class); + Assert.assertNull(result); + + expected = "yo"; + result = ctxt.getContextValue(String.class); + Assert.assertNull(result); + parentParentContext.setContextValue(expected); + result = ctxt.getContextValue(String.class); + Assert.assertEquals(expected, result); + + expected = "ya"; + result = ctxt.getContextValue(String.class, "second"); + Assert.assertNull(result); + parentParentContext.setContextValue(expected, "second"); + result = ctxt.getContextValue(String.class, "second"); + Assert.assertEquals(expected, result); + + expected = "yi"; + result = ctxt.getContextValue(String.class, "second"); + parentParentContext.setContextValue(expected, "second"); + Assert.assertEquals("ya", result); + result = ctxt.getContextValue(String.class, "second"); + Assert.assertEquals(expected, result); + } + + @Test + public void testEntrySet() throws Exception { + Object o = new Object(); + + ctxt.setContextValue(o); + + Assert.assertEquals(1, ctxt.data.size()); + Assert.assertEquals(o, ctxt.getContextValue(Object.class)); + Assert.assertEquals(null, ctxt.getContextValue(Object.class, "named")); + + ctxt.setContextValue(o, "named"); + + Assert.assertEquals(2, ctxt.data.size()); + Assert.assertEquals(o, ctxt.getContextValue(Object.class)); + Assert.assertEquals(o, ctxt.getContextValue(Object.class, "named")); + + ctxt.removeContextValue(Object.class); + Assert.assertEquals(1, ctxt.data.size()); + Assert.assertEquals(null, ctxt.getContextValue(Object.class)); + Assert.assertEquals(o, ctxt.getContextValue(Object.class, "named")); + + ctxt.removeContextValue(Object.class); + Assert.assertEquals(1, ctxt.data.size()); + Assert.assertEquals(null, ctxt.getContextValue(Object.class)); + Assert.assertEquals(o, ctxt.getContextValue(Object.class, "named")); + + ctxt.removeContextValue(Object.class, "named"); + Assert.assertEquals(0, ctxt.data.size()); + Assert.assertEquals(null, ctxt.getContextValue(Object.class)); + Assert.assertEquals(null, ctxt.getContextValue(Object.class, "named")); + + } + + @Test + public void testEntrySetWithParent() throws Exception { + + DefaultJAXXContext parentContext = new DefaultJAXXContext(); + + ctxt.setContextValue(parentContext); + + class Object2 { + + } + Object o = new Object2(); + + parentContext.setContextValue(o); + + Assert.assertEquals(0, ctxt.data.size()); + Assert.assertEquals(1, parentContext.data.size()); + Assert.assertEquals(o, ctxt.getContextValue(Object2.class)); + Assert.assertEquals(null, ctxt.getContextValue(Object2.class, "named")); + + parentContext.setContextValue(o, "named"); + + Assert.assertEquals(0, ctxt.data.size()); + Assert.assertEquals(2, parentContext.data.size()); + Assert.assertEquals(o, ctxt.getContextValue(Object2.class)); + Assert.assertEquals(o, ctxt.getContextValue(Object2.class, "named")); + + parentContext.removeContextValue(Object2.class); + Assert.assertEquals(0, ctxt.data.size()); + Assert.assertEquals(1, parentContext.data.size()); + Assert.assertEquals(null, ctxt.getContextValue(Object2.class)); + Assert.assertEquals(o, ctxt.getContextValue(Object2.class, "named")); + + parentContext.removeContextValue(Object2.class); + Assert.assertEquals(0, ctxt.data.size()); + Assert.assertEquals(1, parentContext.data.size()); + Assert.assertEquals(null, ctxt.getContextValue(Object2.class)); + Assert.assertEquals(o, ctxt.getContextValue(Object2.class, "named")); + + ctxt.removeContextValue(Object2.class, "named"); + Assert.assertEquals(0, ctxt.data.size()); + Assert.assertEquals(0, parentContext.data.size()); + Assert.assertEquals(null, ctxt.getContextValue(Object2.class)); + Assert.assertEquals(null, ctxt.getContextValue(Object2.class, "named")); + + } + + private static class MyJAXXObject extends DefaultJAXXContext implements JAXXObject { + + public Object getObjectById(String id) { + return null; + } + + public Map<String, Object> get$objectMap() { + return null; + } + + public void applyDataBinding(String id) { + } + + public void removeDataBinding(String id) { + } + + public JAXXContext getDelegateContext() { + return null; + } + + public void processDataBinding(String dest) { + } + + public void firePropertyChange(String name, Object oldValue, Object newValue) { + } + + } +} diff --git a/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/JXPathDecoratorTest.java b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/JXPathDecoratorTest.java new file mode 100644 index 0000000..a67d758 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/JXPathDecoratorTest.java @@ -0,0 +1,163 @@ +package jaxx.runtime; + +import jaxx.runtime.JXPathDecorator.Context; +import org.junit.After; +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** @author chemit */ +public class JXPathDecoratorTest { + + + protected JXPathDecorator<?> decorator; + protected String expected; + protected String result; + + @After + public void after() { + decorator = null; + } + + @Test(expected = NullPointerException.class) + public void testNullInternalClass() throws Exception { + decorator = JXPathDecorator.newDecorator(null, "hello"); + } + + @Test(expected = IllegalArgumentException.class) + public void testMissingRightBrace() throws Exception { + decorator = JXPathDecorator.newDecorator(Object.class, "${haha"); + } + + @Test(expected = IllegalArgumentException.class) + public void testMissingRightBrace2() throws Exception { + decorator = JXPathDecorator.newDecorator(Object.class, "${haha${hum}"); + } + + @Test + public void testNullBean() throws Exception { + decorator = JXPathDecorator.newDecorator(Object.class, "hello"); + expected = "hello"; + assertEquals(expected, decorator.getExpression()); + assertEquals(0, decorator.nbToken); + assertEquals(0, decorator.getTokens().length); + + result = decorator.toString(null); + assertEquals(null, result); + } + + @Test + public void testNoJXPath() throws Exception { + decorator = JXPathDecorator.newDecorator(Object.class, "hello"); + expected = "hello"; + assertEquals(expected, decorator.getExpression()); + assertEquals(0, decorator.nbToken); + assertEquals(0, decorator.getTokens().length); + + result = decorator.toString(this); + assertEquals(expected, result); + } + + @Test + public void testDecorator() throws Exception { + + decorator = JXPathDecorator.newDecorator(JXPathDecorator.class, "${expression}$s - ${nbToken}$d"); + assertEquals("%1$s - %2$d", decorator.getExpression()); + assertDecoratorInternal(); + + decorator = JXPathDecorator.newDecorator(JXPathDecorator.class, "${expression}${nbToken}"); + assertEquals("%1%2", decorator.getExpression()); + assertDecoratorInternal(); + + decorator = JXPathDecorator.newDecorator(JXPathDecorator.class, "before ${expression}$s - ${nbToken}$d after"); + assertEquals("before %1$s - %2$d after", decorator.getExpression()); + assertDecoratorInternal(); + + decorator = JXPathDecorator.newDecorator(JXPathDecorator.class, "before${expression}$s-${nbToken}$dafter"); + assertEquals("before%1$s-%2$dafter", decorator.getExpression()); + assertDecoratorInternal(); + } + + public static class Data { + int pos; + String name; + + protected static List<Data> generate(int nb) { + List<Data> datas = new ArrayList<Data>(nb); + for (int i = 0; i < nb; i++) { + datas.add(new Data(i, "name_" + (nb - i))); + } + return datas; + } + + Data(int pos, String name) { + this.pos = pos; + this.name = name; + } + + public int getPos() { + return pos; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return "Data{pos=" + pos + ", name='" + name + '\'' + '}'; + } + } + + @Test + public void testSort() throws Exception { + + List<Data> datas = Data.generate(10); + JXPathDecorator<Data> decorator = JXPathDecorator.newDecorator(Data.class, "${pos}$d ${name}$s"); + + List<Data> sortData = new ArrayList<Data>(datas); + JXPathDecorator.sort(decorator, sortData, 0); + for (int i = 0; i < datas.size(); i++) { + Data data = datas.get(i); + Data sData = sortData.get(i); + assertEquals(data, sData); + } + Collections.sort(datas, new Comparator<Data>() { + @Override + public int compare(Data o1, Data o2) { + return o1.name.compareTo(o2.name); + } + }); + Context<Data> context = decorator.context; + context.setComparator(null); + JXPathDecorator.sort(decorator, sortData, 1); + for (int i = 0; i < datas.size(); i++) { + Data data = datas.get(i); + Data sData = sortData.get(i); + assertEquals(data, sData); + } + } + + + public void assertDecoratorInternal(String... tokens) { + assertTokens(tokens); + expected = String.format(decorator.getExpression(), decorator.getExpression(), decorator.getNbToken()); + result = decorator.toString(decorator); + assertEquals(expected, result); + } + + private void assertTokens(String... tokens) { + if (tokens.length == 0) { + tokens = new String[]{"expression", "nbToken"}; + } + assertEquals(2, decorator.nbToken); + assertEquals(2, decorator.getTokens().length); + assertEquals(tokens[0], decorator.getTokens()[0]); + assertEquals(tokens[1], decorator.getTokens()[1]); + } + +} diff --git a/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/MultiJXPathDecoratorTest.java b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/MultiJXPathDecoratorTest.java new file mode 100644 index 0000000..4e3d4a4 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/MultiJXPathDecoratorTest.java @@ -0,0 +1,184 @@ +package jaxx.runtime; + +import jaxx.runtime.JXPathDecoratorTest.Data; +import org.junit.After; +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** @author chemit */ +public class MultiJXPathDecoratorTest { + + + protected MultiJXPathDecorator<?> decorator; + protected String expected; + protected String result; + + @After + public void after() { + decorator = null; + } + + @Test(expected = NullPointerException.class) + public void testNullInternalClass() throws Exception { + decorator = MultiJXPathDecorator.newDecorator(null, "hello", "#"); + } + + @Test(expected = IllegalArgumentException.class) + public void testMissingRightBrace() throws Exception { + decorator = MultiJXPathDecorator.newDecorator(Object.class, "${haha", "#"); + } + + @Test(expected = IllegalArgumentException.class) + public void testMissingRightBrace2() throws Exception { + decorator = MultiJXPathDecorator.newDecorator(Object.class, "${haha${hum}", "#"); + } + + @Test + public void testNullBean() throws Exception { + decorator = MultiJXPathDecorator.newDecorator(Object.class, "hello", ""); + expected = "hello"; + assertEquals(expected, decorator.getExpression()); + assertEquals(0, decorator.nbToken); + assertEquals(0, decorator.getTokens().length); + + result = decorator.toString(null); + assertEquals(null, result); + } + + @Test + public void testMultiDecorator() throws Exception { + + decorator = MultiJXPathDecorator.newDecorator(JXPathDecorator.class, "${expression}$s#${nbToken}$d", "#", " - "); + assertEquals("%1$s - %2$d", decorator.getExpression()); + assertDecoratorInternal(); + assertEquals(2, decorator.contexts.length); + decorator.setContextIndex(1); + assertEquals("%1$d - %2$s", decorator.getExpression()); + assertTokens("nbToken", "expression"); + expected = String.format(decorator.getExpression(), decorator.getNbToken(), decorator.getExpression()); + result = decorator.toString(decorator); + assertEquals(expected, result); + + decorator = MultiJXPathDecorator.newDecorator(JXPathDecorator.class, "${expression}$s ## ${nbToken}$d", " ## ", " - "); + assertEquals("%1$s - %2$d", decorator.getExpression()); + assertDecoratorInternal(); + assertEquals(2, decorator.contexts.length); + decorator.setContextIndex(1); + assertEquals("%1$d - %2$s", decorator.getExpression()); + assertTokens("nbToken", "expression"); + expected = String.format(decorator.getExpression(), decorator.getNbToken(), decorator.getExpression()); + result = decorator.toString(decorator); + assertEquals(expected, result); + } + + @Test + public void testMultiDecorator2() throws Exception { + + decorator = MultiJXPathDecorator.newDecorator(JXPathDecorator.class, "${expression}$s#${nbToken}$d#${separator}$s", "#", " - "); + + assertEquals("%1$s - %2$d - %3$s", decorator.getExpression()); + assertTokens("expression", "nbToken", "separator"); + assertEquals(3, decorator.contexts.length); + + expected = String.format(decorator.getExpression(), decorator.getExpression(), decorator.getNbToken(), decorator.getSeparator()); + result = decorator.toString(decorator); + assertEquals(expected, result); + + decorator.setContextIndex(1); + assertEquals("%1$d - %2$s - %3$s", decorator.getExpression()); + assertTokens("nbToken", "separator", "expression"); + expected = String.format(decorator.getExpression(), decorator.getNbToken(), decorator.getSeparator(), decorator.getExpression()); + result = decorator.toString(decorator); + assertEquals(expected, result); + + decorator.setContextIndex(2); + assertEquals("%1$s - %2$s - %3$d", decorator.getExpression()); + assertTokens("separator", "expression", "nbToken"); + + expected = String.format(decorator.getExpression(), decorator.getSeparator(), decorator.getExpression(), decorator.getNbToken()); + result = decorator.toString(decorator); + assertEquals(expected, result); + } + + @Test + public void testMultiDecoratorWithMultiRef() throws Exception { + + decorator = MultiJXPathDecorator.newDecorator(JXPathDecorator.class, "${expression}$s#${nbToken}$d#${separator}$s %3$s", "#", " - "); + + assertEquals("%1$s - %2$d - %3$s %3$s", decorator.getExpression()); + assertTokens("expression", "nbToken", "separator"); + assertEquals(3, decorator.contexts.length); + + expected = String.format(decorator.getExpression(), decorator.getExpression(), decorator.getNbToken(), decorator.getSeparator()); + result = decorator.toString(decorator); + assertEquals(expected, result); + + decorator.setContextIndex(1); + assertEquals("%1$d - %2$s %3$s - %3$s", decorator.getExpression()); + assertTokens("nbToken", "separator", "expression"); + expected = String.format(decorator.getExpression(), decorator.getNbToken(), decorator.getSeparator(), decorator.getExpression()); + result = decorator.toString(decorator); + assertEquals(expected, result); + + decorator.setContextIndex(2); + assertEquals("%1$s %3$s - %2$s - %3$d", decorator.getExpression()); + assertTokens("separator", "expression", "nbToken"); + + expected = String.format(decorator.getExpression(), decorator.getSeparator(), decorator.getExpression(), decorator.getNbToken()); + result = decorator.toString(decorator); + assertEquals(expected, result); + } + + @Test + public void testSort() throws Exception { + + List<Data> datas = Data.generate(10); + + MultiJXPathDecorator<Data> decorator = MultiJXPathDecorator.newDecorator(Data.class, "${pos}$d-${name}$s", "-"); + + List<Data> sortData = new ArrayList<Data>(datas); + JXPathDecorator.sort(decorator, sortData, 0); + for (int i = 0; i < datas.size(); i++) { + Data data = datas.get(i); + Data sData = sortData.get(i); + assertEquals(data, sData); + } + Collections.sort(datas, new Comparator<Data>() { + @Override + public int compare(Data o1, Data o2) { + return o1.name.compareTo(o2.name); + } + }); + decorator.setContextIndex(1); + JXPathDecorator.sort(decorator, sortData, 1); + for (int i = 0; i < datas.size(); i++) { + Data data = datas.get(i); + Data sData = sortData.get(i); + assertEquals(data, sData); + } + } + + public void assertDecoratorInternal(String... tokens) { + assertTokens(tokens); + expected = String.format(decorator.getExpression(), decorator.getExpression(), decorator.getNbToken()); + result = decorator.toString(decorator); + assertEquals(expected, result); + } + + private void assertTokens(String... tokens) { + if (tokens.length == 0) { + tokens = new String[]{"expression", "nbToken"}; + } + assertEquals(tokens.length, decorator.nbToken); + assertEquals(tokens.length, decorator.getTokens().length); + for (int i = 0; i < tokens.length; i++) { + assertEquals(tokens[i], decorator.getTokens()[i]); + } + } + +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/UtilTest.java b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/UtilTest.java new file mode 100644 index 0000000..dc0327e --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/UtilTest.java @@ -0,0 +1,29 @@ +package jaxx.runtime; + +import org.junit.Assert; +import org.junit.Test; + +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + +public class UtilTest { + + int count; + + @Test + public void testGetEventListener() { + count = 0; + DocumentListener listener = (DocumentListener) jaxx.runtime.Util.getEventListener(javax.swing.event.DocumentListener.class, this, "incCount"); + listener.insertUpdate(null); + Assert.assertEquals(count, 1); + DocumentListener listener2 = (DocumentListener) jaxx.runtime.Util.getEventListener(javax.swing.event.DocumentListener.class, this, "incCount"); + listener2.removeUpdate(null); + Assert.assertEquals(count, 2); + //assertTrue("Received two different event listeners despite using identical parameters", listener == listener2); + } + + + public void incCount(DocumentEvent e) { + count++; + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/AbstractBeanValidatorDetectorTest.java b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/AbstractBeanValidatorDetectorTest.java new file mode 100644 index 0000000..1a6892f --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/AbstractBeanValidatorDetectorTest.java @@ -0,0 +1,108 @@ +package jaxx.runtime.validator; + +import java.io.File; +import java.util.Arrays; +import java.util.Collection; +import java.util.SortedSet; +import java.util.regex.Pattern; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * An abstract test to detects validators for a given list of objets types and + * + * a given sourceroot directory where to find validations definitions. + * + * You just have to implements to {@link #assertDetect(SortedSet)} which contains + * the set of validators detected. + * + * See {@link BeanValidatorDetectorTest} for an example. + * + * Note : An implementation of this test should be produced in evry projects which + * defines some validation definitions just to test they are syntax valid. + * + * @author chemit + * @since 1.6.0 + */ +public abstract class AbstractBeanValidatorDetectorTest { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + private static final Log log = LogFactory.getLog(AbstractBeanValidatorDetectorTest.class); + protected static File basedir; + protected BeanValidatorDetector instance; + protected Class<?>[] classes; + protected Class<?> validatorClass; + protected File sourceRoot; + + protected AbstractBeanValidatorDetectorTest(File sourceRoot, Class<?>... classes) { + this(BeanValidator.class, sourceRoot, classes); + } + + protected AbstractBeanValidatorDetectorTest(Class<?> validatorClass, File sourceRoot, Class<?>... classes) { + this.sourceRoot = sourceRoot; + this.classes = classes; + this.validatorClass = validatorClass; + + log.info("sourceRoot " + sourceRoot); + log.info("validatorClass " + validatorClass); + log.info("classes " + Arrays.toString(classes)); + } + + protected AbstractBeanValidatorDetectorTest(File sourceRoot, Collection<Class<?>> classes) { + this(sourceRoot, classes.toArray(new Class<?>[classes.size()])); + } + + public static void setUpClass() throws Exception { + String b = System.getenv("basedir"); + if (b == null) { + b = new File("").getAbsolutePath(); + } + basedir = new File(b); + log.info("basedir " + basedir); + } + + @Before + public void setUp() { + instance = new BeanValidatorDetector(); + } + + @After + public void tearDown() { + instance = null; + } + + /** + * Test of detect method, of class BeanValidatorDetector. + */ + @Test + public void testDetect() { + SortedSet<BeanValidator<?>> result = detect(sourceRoot, classes, null); + log.info(printValidators("testDetect : ", result)); + assertDetect(result); + } + + protected abstract void assertDetect(SortedSet<BeanValidator<?>> validators); + + protected SortedSet<BeanValidator<?>> detect(File sourceRoot, Class<?>[] classes, Pattern contextPattern) { + SortedSet<BeanValidator<?>> result = instance.detect(validatorClass, sourceRoot, contextPattern, classes); + return result; + } + + protected void assertValidator(Class<?> expectedBeanClass, String expectedContextName, BeanValidator<?> validator) { + assertEquals(expectedBeanClass, validator.getBeanClass()); + assertEquals(expectedContextName, validator.getContextName()); + } + + protected String printValidators(String prefix, SortedSet<BeanValidator<?>> result) { + StringBuilder buffer = new StringBuilder(); + buffer.append(prefix).append(result.size()).append("\n"); + for (BeanValidator<?> v : result) { + buffer.append(prefix).append(v).append("\n"); + } + return buffer.toString(); + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/BeanValidatorDetectorTest.java b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/BeanValidatorDetectorTest.java new file mode 100644 index 0000000..0337559 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/BeanValidatorDetectorTest.java @@ -0,0 +1,101 @@ +package jaxx.runtime.validator; + +import java.io.File; +import java.util.SortedSet; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * + * @author chemit + */ +public class BeanValidatorDetectorTest extends AbstractBeanValidatorDetectorTest { + + @BeforeClass + public static void setUpClass() throws Exception { + AbstractBeanValidatorDetectorTest.setUpClass(); + + } + + public BeanValidatorDetectorTest() { + super(new File(basedir, "src" + File.separator + "test" + File.separator + "resources"), SimpleBean.class); + } + + /** + * Test of detect method, of class BeanValidatorDetector. + */ + @Test + public void testDetectNothing() { + + SortedSet<BeanValidator<?>> validators = instance.detect(sourceRoot, new Class<?>[]{Object.class}); + assertEquals(0, validators.size()); + } + + @Override + protected void assertDetect(SortedSet<BeanValidator<?>> validators) { + assertEquals(1, validators.size()); + BeanValidator<?> validator = validators.iterator().next(); + assertEquals(classes[0], validator.getBeanClass()); + assertNull(validator.getContextName()); + } + + /** + * Test of getValidator method, of class BeanValidatorDetector. + */ + @Test + public void testGetValidator() { + Class<?>[] types = {SimpleBean.class}; + SortedSet<BeanValidator<?>> result = instance.detect(sourceRoot, types); + assertEquals(1, result.size()); + BeanValidator<?> validator = result.iterator().next(); + assertEquals(types[0], validator.getBeanClass()); + assertNull(validator.getContextName()); + + types = new Class<?>[]{Object.class}; + result = instance.detect(sourceRoot, types); + assertEquals(0, result.size()); + + } + + /** + * Test of getClassDir method, of class BeanValidatorDetector. + */ + @Test + public void testGetClassDir() { + Class<?> clazz = classes[0]; + + File expected = new File(sourceRoot, "jaxx" + File.separator + "runtime" + File.separator + "validator"); + File result = instance.getClassDir(sourceRoot, clazz); + assertEquals(expected, result); + } + + /** + * Test of getContexts method, of class BeanValidatorDetector. + */ + @Test + public void testGetContexts() { + + String[] expResult = {"error", "info", "simple", "warning"}; + Class<?> clazz = classes[0]; + File dir = instance.getClassDir(sourceRoot,clazz); + String[] result = instance.getContexts(clazz, dir); + assertEquals(expResult.length, result.length); + } + + /** + * Test of getContextsWithoutScopes method, of class BeanValidatorDetector. + */ + @Test + public void testGetContextsWithoutScopes() { + System.out.println("getContextsWithoutScopes"); + + Class<?> clazz = SimpleBean.class; + String[] expResult = {""}; + File dir = instance.getClassDir(sourceRoot, clazz); + String[] contexts = instance.getContexts(clazz, dir); + String[] result = instance.getContextsWithoutScopes(contexts); + assertEquals(expResult.length, result.length); + + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/BeanValidatorTest.java b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/BeanValidatorTest.java new file mode 100644 index 0000000..782935f --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/BeanValidatorTest.java @@ -0,0 +1,198 @@ +package jaxx.runtime.validator; + +import java.util.List; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * + * @author tony + */ +public class BeanValidatorTest { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static protected final Log log = LogFactory.getLog(BeanValidator.class); + protected BeanValidator<SimpleBean> validator; + protected SimpleBean bean; + BeanValidatorListenerImpl errorListener; + BeanValidatorListenerImpl warningListener; + BeanValidatorListenerImpl infoListener; + + @Before + public void setUp() { + bean = new SimpleBean(); + validator = new BeanValidator<SimpleBean>(SimpleBean.class, null); + validator.addBeanValidatorListener(errorListener = new BeanValidatorListenerImpl(BeanValidatorScope.ERROR)); + validator.addBeanValidatorListener(warningListener = new BeanValidatorListenerImpl(BeanValidatorScope.WARNING)); + validator.addBeanValidatorListener(infoListener = new BeanValidatorListenerImpl(BeanValidatorScope.INFO)); + } + + @After + public void tearDown() { + bean = null; + if (validator != null) { + validator.setBean(null); + validator = null; + } + } + private static final String STRING_VALUE_ERROR = "stringValue.error"; + private static final String STRING_VALUE_WARNING = "stringValue.warning"; + private static final String INT_VALUE_ERROR = "intValue.error"; + private static final String INT_VALUE_INFO = "intValue.info"; + + @Test + public void testValidate() { + + assertMessages(errorListener); + assertMessages(warningListener); + assertMessages(infoListener); + + log.info("-----------------------------------------------"); + validator.setBean(bean); + + assertMessages(errorListener, STRING_VALUE_ERROR, INT_VALUE_ERROR); + assertMessages(warningListener, STRING_VALUE_WARNING); + assertMessages(infoListener, INT_VALUE_INFO); + + log.info("-----------------------------------------------"); + bean.setStringValue("one"); + + assertMessages(errorListener, INT_VALUE_ERROR); + assertMessages(warningListener, STRING_VALUE_WARNING); + assertMessages(infoListener, INT_VALUE_INFO); + + log.info("-----------------------------------------------"); + bean.setStringValue("oneone"); + + assertMessages(errorListener, INT_VALUE_ERROR); + assertMessages(warningListener); + assertMessages(infoListener, INT_VALUE_INFO); + + log.info("-----------------------------------------------"); + bean.setIntValue(1); + + assertMessages(errorListener); + assertMessages(warningListener); + assertMessages(infoListener, INT_VALUE_INFO); + + log.info("-----------------------------------------------"); + bean.setIntValue(10); + + assertMessages(errorListener); + assertMessages(warningListener); + assertMessages(infoListener); + + log.info("-----------------------------------------------"); + + bean.setStringValue(null); + bean.setIntValue(0); + + assertMessages(errorListener, STRING_VALUE_ERROR, INT_VALUE_ERROR); + assertMessages(warningListener, STRING_VALUE_WARNING); + assertMessages(infoListener, INT_VALUE_INFO); + + + log.info("-----------------------------------------------"); + } + + @Test + public void testConvert() { + + + assertMessages(errorListener); + assertMessages(warningListener); + assertMessages(infoListener); + + log.info("-----------------------------------------------"); + + validator.setBean(bean); + + assertMessages(errorListener, STRING_VALUE_ERROR, INT_VALUE_ERROR); + assertMessages(warningListener, STRING_VALUE_WARNING); + assertMessages(infoListener, INT_VALUE_INFO); + + + log.info("-----------------------------------------------"); + + Object value = validator.convert("intValue", "abc", Class.class); + + Assert.assertNull(value); + + assertMessages(errorListener, STRING_VALUE_ERROR, "error.convertor.class"); + assertMessages(warningListener, STRING_VALUE_WARNING); + assertMessages(infoListener, INT_VALUE_INFO); + + log.info("-----------------------------------------------"); + bean.setStringValue("one"); + + assertMessages(errorListener, "error.convertor.class"); + assertMessages(warningListener, STRING_VALUE_WARNING); + assertMessages(infoListener, INT_VALUE_INFO); + + log.info("-----------------------------------------------"); + + value = validator.convert("intValue", "3", Integer.class); + + bean.setIntValue((Integer) value); + + assertMessages(errorListener); + assertMessages(warningListener, STRING_VALUE_WARNING); + assertMessages(infoListener, INT_VALUE_INFO); + + log.info("-----------------------------------------------"); + + bean.setIntValue(-1); + assertMessages(errorListener, INT_VALUE_ERROR); + assertMessages(warningListener, STRING_VALUE_WARNING); + assertMessages(infoListener, INT_VALUE_INFO); + + log.info("-----------------------------------------------"); + } + + void assertMessages(BeanValidatorListenerImpl listener, String... expected) { + List<String> actual = listener.getMessages(); + Assert.assertEquals(" shoudl have " + java.util.Arrays.toString(expected) + " but had " + actual, expected.length, actual.size()); + for (String m : expected) { + Assert.assertEquals("could not find " + m + " in " + actual, true, actual.contains(m)); + } + } + + class BeanValidatorListenerImpl implements BeanValidatorListener { + + final BeanValidatorScope scope; + + public BeanValidatorListenerImpl(BeanValidatorScope scope) { + this.scope = scope; + } + java.util.List<String> messages = new java.util.ArrayList<String>(); + + public List<String> getMessages() { + return messages; + } + + @Override + public void onFieldChanged(BeanValidatorEvent event) { + if (scope != event.getScope()) { + return; + } + String[] messagesToDelete = event.getMessagesToDelete(); + if (messagesToDelete != null && messagesToDelete.length > 0) { + log.info(event.getScope() + " messages to delete : " + java.util.Arrays.toString(messagesToDelete)); + for (String m : messagesToDelete) { + messages.remove(m); + } + } + String[] messagesToAdd = event.getMessagesToAdd(); + if (messagesToAdd != null && messagesToAdd.length > 0) { + log.info(event.getScope() + " messages to add : " + java.util.Arrays.toString(messagesToAdd)); + for (String m : messagesToAdd) { + messages.add(m); + } + } + } + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/SimpleBean.java b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/SimpleBean.java new file mode 100644 index 0000000..00c7961 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/SimpleBean.java @@ -0,0 +1,51 @@ +package jaxx.runtime.validator; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; + +public class SimpleBean { + + protected int intValue; + protected String stringValue; + final PropertyChangeSupport p; + + public SimpleBean() { + p = new PropertyChangeSupport(this); + } + + public int getIntValue() { + return intValue; + } + + public String getStringValue() { + return stringValue; + } + + public void setStringValue(String stringValue) { + String old = this.stringValue; + this.stringValue = stringValue; + p.firePropertyChange("stringValue", old, stringValue); + } + + public void setIntValue(int intValue) { + int old = this.intValue; + this.intValue = intValue; + p.firePropertyChange("intValue", old, intValue); + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + p.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + p.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + p.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + p.removePropertyChangeListener(propertyName, listener); + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/XWorkBeanValidatorTest.java b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/XWorkBeanValidatorTest.java new file mode 100644 index 0000000..b470273 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/XWorkBeanValidatorTest.java @@ -0,0 +1,156 @@ +package jaxx.runtime.validator; + +import java.util.List; +import java.util.Map; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * + * @author tony + * @since 1.3 + */ +public class XWorkBeanValidatorTest { + + protected XWorkBeanValidator<SimpleBean> validator; + protected SimpleBean bean; + protected Map<String, List<String>> messages; + + @Before + public void setUp() { + bean = new SimpleBean(); + validator = new XWorkBeanValidator<SimpleBean>(SimpleBean.class, "simple"); + } + + @After + public void tearDown() { + bean = null; + messages = null; + } + + @Test + public void testUnknownField() { + Assert.assertEquals(false, validator.containsField("fake_" + System.nanoTime())); + } + + @Test(expected = NullPointerException.class) + public void testValidateNPE() { + validator.validate(null); + } + + @Test + public void testValidate() { + + + messages = validator.validate(bean); + + assertFieldInError("stringValue", "stringValue.null", true, messages); + assertFieldInError("intValue", "intValue.null", true, messages); + + bean.setStringValue("notnull"); + messages = validator.validate(bean); + + assertFieldInError("stringValue", "stringValue.null", false, messages); + assertFieldInError("intValue", "intValue.null", true, messages); + + bean.setIntValue(1); + messages = validator.validate(bean); + + assertFieldInError("stringValue", "stringValue.null", false, messages); + assertFieldInError("intValue", "intValue.null", false, messages); + + } + + @Test + public void testSetContextName() { + + + String expected = "simple"; + + Assert.assertEquals(expected, validator.getContextName()); + Assert.assertEquals(true, validator.containsField("stringValue")); + Assert.assertEquals(true, validator.containsField("intValue")); + + validator.setContextName(expected = "error"); + + Assert.assertEquals(expected, validator.getContextName()); + Assert.assertEquals(true, validator.containsField("stringValue")); + Assert.assertEquals(true, validator.containsField("intValue")); + + validator.setContextName(expected = "warning"); + + Assert.assertEquals(expected, validator.getContextName()); + Assert.assertEquals(true, validator.containsField("stringValue")); + Assert.assertEquals(false, validator.containsField("intValue")); + + validator.setContextName(expected = "info"); + + Assert.assertEquals(expected, validator.getContextName()); + Assert.assertEquals(false, validator.containsField("stringValue")); + Assert.assertEquals(true, validator.containsField("intValue")); + + validator.setContextName(expected = "fake_" + System.nanoTime()); + + Assert.assertEquals(expected, validator.getContextName()); + Assert.assertEquals(false, validator.containsField("stringValue")); + Assert.assertEquals(false, validator.containsField("intValue")); + + } + + @Test + public void testSetIncludeDefaultContext() { + + validator.setIncludeDefaultContext(false); + + String expected = "simple"; + + Assert.assertEquals(expected, validator.getContextName()); + Assert.assertEquals(true, validator.containsField("stringValue")); + Assert.assertEquals(true, validator.containsField("intValue")); + + validator.setContextName(expected = "error"); + + Assert.assertEquals(expected, validator.getContextName()); + Assert.assertEquals(true, validator.containsField("stringValue")); + Assert.assertEquals(true, validator.containsField("intValue")); + + validator.setContextName(expected = "warning"); + + Assert.assertEquals(expected, validator.getContextName()); + Assert.assertEquals(true, validator.containsField("stringValue")); + Assert.assertEquals(false, validator.containsField("intValue")); + + validator.setContextName(expected = "info"); + + Assert.assertEquals(expected, validator.getContextName()); + Assert.assertEquals(false, validator.containsField("stringValue")); + Assert.assertEquals(true, validator.containsField("intValue")); + + validator.setContextName(expected = "fake_" + System.nanoTime()); + + Assert.assertEquals(expected, validator.getContextName()); + Assert.assertEquals(false, validator.containsField("stringValue")); + Assert.assertEquals(false, validator.containsField("intValue")); + + } + + protected void assertFieldInError(String fieldName, String error, boolean required, Map<String, List<String>> messages) { + + Assert.assertEquals(true, validator.containsField(fieldName)); + List<String> fieldMessages = messages.get(fieldName); + //Assert.assertEquals(true,validator.containsField(fieldName)); + if (fieldMessages != null) { + for (String o : fieldMessages) { + if (o.equals(error)) { + Assert.assertTrue(required); + return; + } + } + } + + // error was not found + Assert.assertFalse(required); + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/AbstractFieldValidatorTest.java b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/AbstractFieldValidatorTest.java new file mode 100644 index 0000000..e5fd9ba --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/AbstractFieldValidatorTest.java @@ -0,0 +1,97 @@ +package jaxx.runtime.validator.field; + +import java.io.File; +import jaxx.runtime.validator.BeanValidator; +import jaxx.runtime.validator.BeanValidatorField; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; + +/** + * Abstract class to test a specific validator. + * <p/> + * To implements a test on a new validator, just extends this class + * and implements the method {@link #testValidator()}. + * + * @param <B> the type of bean to validate. + * + * @author chemit + */ +public abstract class AbstractFieldValidatorTest<B> extends Assert { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private final Log log = LogFactory.getLog(AbstractFieldValidatorTest.class); + protected static BeanValidator<?> cacheValidator; + protected static File basedir; + protected final Class<B> type; + protected BeanValidator<B> validator; + protected B bean; + + public AbstractFieldValidatorTest(Class<B> type) { + this.type = type; + } + + /** + * the method to test the given validator on the given bean. + * + * When coming here a validator and bean were instanciated and the bean was + * setted into validator via setBean method. + * + * @throws Exception if any error ? + */ + public abstract void testValidator() throws Exception; + + @Before + @SuppressWarnings("unchecked") + public void setUp() throws Exception { + log.debug("start test " + getClass().getSimpleName()); + bean = type.newInstance(); + if (cacheValidator == null) { + validator = validator = new BeanValidator<B>(type, null); + cacheValidator = validator; + } else { + validator = (BeanValidator<B>) cacheValidator; + } + validator.setBean(bean); + } + + @After + @SuppressWarnings("unchecked") + public void tearDown() { + validator.setBean(null); + } + + @AfterClass + public static void afterclass() throws Exception { + cacheValidator = null; + } + + @BeforeClass + public static void initValidator() throws Exception { + + String b = System.getenv("basedir"); + if (b == null) { + b = new File("").getAbsolutePath(); + } + basedir = new File(b); + } + + @SuppressWarnings("unchecked") + protected void assertFieldInError(String fieldName, String error, boolean required) { + BeanValidatorField<B> field = validator.getField(fieldName); + if (field != null && field.getErrors() != null) { + for (String o : field.getErrors()) { + if (o.equals(error)) { + assertTrue("error " + error + " should not exist but was found.", required); + return; + } + } + } + // error was not found + assertFalse("error " + error + " should exist but was not found.", required); + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/AbstractValidatorBeanFieldValidatorTest.java b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/AbstractValidatorBeanFieldValidatorTest.java new file mode 100644 index 0000000..1238dfe --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/AbstractValidatorBeanFieldValidatorTest.java @@ -0,0 +1,14 @@ +package jaxx.runtime.validator.field; + +/** + * Abstract class to test a specific validator for the {@link Validatorbean}. + * + * @author chemit + * @since 1.3 + */ +public abstract class AbstractValidatorBeanFieldValidatorTest extends AbstractFieldValidatorTest<ValidatorBean> { + + public AbstractValidatorBeanFieldValidatorTest() { + super(ValidatorBean.class); + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/CollectionFieldExpressionValidatorTest.java b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/CollectionFieldExpressionValidatorTest.java new file mode 100644 index 0000000..587d59c --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/CollectionFieldExpressionValidatorTest.java @@ -0,0 +1,234 @@ +package jaxx.runtime.validator.field; + +import jaxx.runtime.validator.field.ValidatorBean.ValidatorBeanEntry; + +import java.util.Arrays; + +/** @author chemit */ +public class CollectionFieldExpressionValidatorTest extends AbstractValidatorBeanFieldValidatorTest { + + protected static final String PROPERTY = "entries"; + static protected ValidatorBeanEntry beanEntry0 = new ValidatorBeanEntry(0, "stringValue"); + static protected ValidatorBeanEntry beanEntry0Bis = new ValidatorBeanEntry(0, "fake"); + static protected ValidatorBeanEntry beanEntry1 = new ValidatorBeanEntry(1, "fake"); + static protected ValidatorBeanEntry beanEntry3 = new ValidatorBeanEntry(3, "fake"); + static protected ValidatorBeanEntry beanEntry5 = new ValidatorBeanEntry(5, "fake"); + + @org.junit.Test + @Override + public void testValidator() throws Exception { + assertNull(bean.getEntries()); + + // no entry + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.all", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.none", false); + + + // add a matching etry + bean.setEntries(Arrays.asList(beanEntry0)); + + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.all", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.none", true); + + // two matching etries + bean.setEntries(Arrays.asList(beanEntry0, beanEntry0)); + + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.all", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.none", true); + + // add a none matching etry + bean.setEntries(Arrays.asList(beanEntry0Bis)); + + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.all", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.none", false); + + // add a none matching etry and a matching entry + bean.setEntries(Arrays.asList(beanEntry0Bis, beanEntry0)); + + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.all", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.none", true); + } + + @org.junit.Test + public void testValidatorWithContext() throws Exception { + assertNull(bean.getEntries()); + + // no entry + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.all.useSensitiveContext", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.none.useSensitiveContext", false); + + // add a matching etry + bean.setEntries(Arrays.asList(beanEntry0)); + + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.all.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.none.useSensitiveContext", false); + + // add a none matching etry + bean.setEntries(Arrays.asList(beanEntry0Bis)); + + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.all.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.none.useSensitiveContext", false); + + // add a none matching etry and a matching entry + bean.setEntries(Arrays.asList(beanEntry0Bis, beanEntry0)); + + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.all.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.none.useSensitiveContext", false); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry1)); + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne.useSensitiveContext", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.all.useSensitiveContext", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.none.useSensitiveContext", false); + + bean.setEntries(Arrays.asList(beanEntry1, beanEntry0)); + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.all.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.none.useSensitiveContext", false); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry1, beanEntry3)); + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne.useSensitiveContext", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.all.useSensitiveContext", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne.useSensitiveContext", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.none.useSensitiveContext", true); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry1, beanEntry3, beanEntry5)); + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne.useSensitiveContext", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.all.useSensitiveContext", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.none.useSensitiveContext", true); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry3, beanEntry1)); + assertFieldInError(PROPERTY, "collectionFieldExpression.atLeastOne.useSensitiveContext", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.all.useSensitiveContext", true); + assertFieldInError(PROPERTY, "collectionFieldExpression.exactlyOne.useSensitiveContext", false); + assertFieldInError(PROPERTY, "collectionFieldExpression.none.useSensitiveContext", false); + } + + @org.junit.Test + public void testValidatorWithContextAndFirst() throws Exception { + assertNull(bean.getEntries()); + String message = "collectionFieldExpression.all.useFirst"; + + // no entry + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry0)); + assertFieldInError(PROPERTY, message, false); + + + bean.setEntries(Arrays.asList(beanEntry0Bis)); + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry1)); + assertFieldInError(PROPERTY, message, true); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry1)); + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry1, beanEntry0)); + assertFieldInError(PROPERTY, message, true); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry1, beanEntry3)); + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry1, beanEntry3, beanEntry5)); + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry3, beanEntry1)); + assertFieldInError(PROPERTY, message, true); + } + + @org.junit.Test + public void testValidatorWithContextAndLast() throws Exception { + assertNull(bean.getEntries()); + String message = "collectionFieldExpression.all.useLast"; + + // no entry + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry0)); + assertFieldInError(PROPERTY, message, true); + + + bean.setEntries(Arrays.asList(beanEntry0Bis)); + assertFieldInError(PROPERTY, message, true); + + bean.setEntries(Arrays.asList(beanEntry1)); + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry1)); + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry1, beanEntry0)); + assertFieldInError(PROPERTY, message, true); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry1, beanEntry3)); + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry1, beanEntry3)); + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry1, beanEntry3, beanEntry5)); + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry3, beanEntry1)); + assertFieldInError(PROPERTY, message, true); + } + + @org.junit.Test + public void testValidatorWithContextAndFirstAndLast() throws Exception { + assertNull(bean.getEntries()); + + String message = "collectionFieldExpression.all.useFirstAndLast"; + // no entry + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry0)); + assertFieldInError(PROPERTY, message, true); + + + bean.setEntries(Arrays.asList(beanEntry0Bis)); + assertFieldInError(PROPERTY, message, true); + + bean.setEntries(Arrays.asList(beanEntry1)); + assertFieldInError(PROPERTY, message, true); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry1)); + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry1, beanEntry0)); + assertFieldInError(PROPERTY, message, true); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry1, beanEntry3)); + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry1, beanEntry3)); + assertFieldInError(PROPERTY, message, true); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry1, beanEntry3, beanEntry5)); + assertFieldInError(PROPERTY, message, false); + + bean.setEntries(Arrays.asList(beanEntry0, beanEntry3, beanEntry1)); + assertFieldInError(PROPERTY, message, true); + } +} diff --git a/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/CollectionUniqueKeyValidatorTest.java b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/CollectionUniqueKeyValidatorTest.java new file mode 100644 index 0000000..6569a4f --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/CollectionUniqueKeyValidatorTest.java @@ -0,0 +1,86 @@ +package jaxx.runtime.validator.field; + +import jaxx.runtime.validator.field.ValidatorBean.ValidatorBeanEntry; + +import java.util.Arrays; + +/** @author chemit */ +public class CollectionUniqueKeyValidatorTest extends AbstractValidatorBeanFieldValidatorTest { + + static protected ValidatorBeanEntry beanEntry = new ValidatorBeanEntry(0, "stringValue"); + static protected ValidatorBeanEntry beanEntry2 = new ValidatorBeanEntry(0, "fake"); + static protected ValidatorBeanEntry beanEntry3 = new ValidatorBeanEntry(0, "stringValue", "stringValue2"); + + @org.junit.Test + @Override + public void testValidator() throws Exception { + assertNull(bean.getEntries()); + + // no entry + assertFieldInError("entries", "collectionUniqueKey.one.failed", false); + assertFieldInError("entries", "collectionUniqueKey.two.failed", false); + assertFieldInError("entries", "collectionUniqueKey.three.failed", false); + assertFieldInError("entries", "collectionUniqueKey.four.failed", false); + assertFieldInError("entries", "collectionUniqueKey.five.failed", false); + + // add a entry + bean.setEntries(Arrays.asList(beanEntry)); + + assertFieldInError("entries", "collectionUniqueKey.one.failed", false); + assertFieldInError("entries", "collectionUniqueKey.two.failed", false); + assertFieldInError("entries", "collectionUniqueKey.three.failed", false); + assertFieldInError("entries", "collectionUniqueKey.four.failed", false); + assertFieldInError("entries", "collectionUniqueKey.five.failed", false); + + // add violating property + bean.setEntry(beanEntry3); + assertFieldInError("entries", "collectionUniqueKey.one.failed", false); + assertFieldInError("entries", "collectionUniqueKey.two.failed", false); + assertFieldInError("entries", "collectionUniqueKey.three.failed", false); + assertFieldInError("entries", "collectionUniqueKey.four.failed", false); + assertFieldInError("entries", "collectionUniqueKey.five.failed", true); + + + // two entries with same key + bean.setEntries(Arrays.asList(beanEntry, beanEntry)); + + assertFieldInError("entries", "collectionUniqueKey.one.failed", true); + assertFieldInError("entries", "collectionUniqueKey.two.failed", true); + assertFieldInError("entries", "collectionUniqueKey.three.failed", true); + assertFieldInError("entries", "collectionUniqueKey.four.failed", true); + + // add a entry + bean.setEntries(Arrays.asList(beanEntry2)); + + assertFieldInError("entries", "collectionUniqueKey.one.failed", false); + assertFieldInError("entries", "collectionUniqueKey.two.failed", false); + assertFieldInError("entries", "collectionUniqueKey.three.failed", false); + assertFieldInError("entries", "collectionUniqueKey.four.failed", false); + + // add two entries (will violated unique key on intValue) + bean.setEntries(Arrays.asList(beanEntry2, beanEntry)); + + assertFieldInError("entries", "collectionUniqueKey.one.failed", true); + assertFieldInError("entries", "collectionUniqueKey.two.failed", false); + assertFieldInError("entries", "collectionUniqueKey.three.failed", false); + assertFieldInError("entries", "collectionUniqueKey.four.failed", false); + + + // two entries with same key (except validator four) + bean.setEntries(Arrays.asList(beanEntry, beanEntry3)); + assertFieldInError("entries", "collectionUniqueKey.one.failed", true); + assertFieldInError("entries", "collectionUniqueKey.two.failed", true); + assertFieldInError("entries", "collectionUniqueKey.three.failed", true); + assertFieldInError("entries", "collectionUniqueKey.four.failed", false); + + beanEntry.setStringValue2("stringValue2"); + // two entries with same key + bean.setEntries(Arrays.asList(beanEntry, beanEntry3)); + assertFieldInError("entries", "collectionUniqueKey.one.failed", true); + assertFieldInError("entries", "collectionUniqueKey.two.failed", true); + assertFieldInError("entries", "collectionUniqueKey.three.failed", true); + assertFieldInError("entries", "collectionUniqueKey.four.failed", true); + + + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/ExistingDirectoryFieldValidatorTest.java b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/ExistingDirectoryFieldValidatorTest.java new file mode 100644 index 0000000..4bb372d --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/ExistingDirectoryFieldValidatorTest.java @@ -0,0 +1,30 @@ +package jaxx.runtime.validator.field; + +import java.io.File; + +/** @author chemit */ +public class ExistingDirectoryFieldValidatorTest extends AbstractValidatorBeanFieldValidatorTest { + + @org.junit.Test + @Override + public void testValidator() throws Exception { + + assertNull(bean.getExistingDirectory()); + assertFieldInError("existingDirectory", "existingDirectory.required", true); + + bean.setExistingDirectory(new File("")); + assertFieldInError("existingDirectory", "existingDirectory.required", true); + + // existing file + bean.setExistingDirectory(new File(basedir, "pom.xml")); + assertFieldInError("existingDirectory", "existingDirectory.required", false); + assertFieldInError("existingDirectory", "existingDirectory.not.exist", true); + + // existing directory + bean.setExistingDirectory(basedir); + assertFieldInError("existingDirectory", "existingDirectory.required", false); + assertFieldInError("existingDirectory", "existingDirectory.not.exist", false); + + } + +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/ExistingFileFieldValidatorTest.java b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/ExistingFileFieldValidatorTest.java new file mode 100644 index 0000000..f08b8f1 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/ExistingFileFieldValidatorTest.java @@ -0,0 +1,30 @@ +package jaxx.runtime.validator.field; + +import java.io.File; + +/** @author chemit */ +public class ExistingFileFieldValidatorTest extends AbstractValidatorBeanFieldValidatorTest { + + @org.junit.Test + @Override + public void testValidator() throws Exception { + + assertNull(bean.getExistingFile()); + assertFieldInError("existingFile", "existingFile.required", true); + + bean.setExistingFile(new File("")); + assertFieldInError("existingFile", "existingFile.required", true); + + // existing directory + bean.setExistingFile(basedir); + assertFieldInError("existingFile", "existingFile.required", false); + assertFieldInError("existingFile", "existingFile.not.exist", true); + + // existing file + bean.setExistingFile(new File(basedir, "pom.xml")); + assertFieldInError("existingFile", "existingFile.required", false); + assertFieldInError("existingFile", "existingFile.not.exist", false); + + } + +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/FieldExpressionBean.java b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/FieldExpressionBean.java new file mode 100644 index 0000000..79e0a8e --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/FieldExpressionBean.java @@ -0,0 +1,103 @@ +package jaxx.runtime.validator.field; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; + +/** + * + * @author tony + */ +public class FieldExpressionBean { + + protected final PropertyChangeSupport p; + protected boolean booleanValue; + protected short shortValue; + protected int intValue; + protected long longValue; + protected double doubleValue; + protected String stringValue; + + public FieldExpressionBean() { + p = new PropertyChangeSupport(this); + } + + public boolean isBooleanValue() { + return booleanValue; + } + + public double getDoubleValue() { + return doubleValue; + } + + public int getIntValue() { + return intValue; + } + + public long getLongValue() { + return longValue; + } + + public short getShortValue() { + return shortValue; + } + + public String getStringValue() { + return stringValue; + } + + public void setBooleanValue(boolean newValue) { + Object oldValue = this.booleanValue; + this.booleanValue = newValue; + firePropertyChange("booleanValue", oldValue, newValue); + } + + public void setDoubleValue(double newValue) { + Object oldValue = this.doubleValue; + this.doubleValue = newValue; + firePropertyChange("doubleValue", oldValue, newValue); + } + + public void setIntValue(int newValue) { + Object oldValue = this.stringValue; + this.intValue = newValue; + firePropertyChange("intValue", oldValue, newValue); + } + + public void setLongValue(long newValue) { + Object oldValue = this.longValue; + this.longValue = newValue; + firePropertyChange("longValue", oldValue, newValue); + } + + public void setShortValue(short newValue) { + Object oldValue = this.shortValue; + this.shortValue = newValue; + firePropertyChange("shortValue", oldValue, newValue); + } + + public void setStringValue(String newValue) { + Object oldValue = this.stringValue; + this.stringValue = newValue; + firePropertyChange("stringValue", oldValue, newValue); + } + + protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { + p.firePropertyChange(propertyName, oldValue, newValue); + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + p.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + p.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + p.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + p.removePropertyChangeListener(propertyName, listener); + } +} diff --git a/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/FieldExpressionWithParamsValidatorTest.java b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/FieldExpressionWithParamsValidatorTest.java new file mode 100644 index 0000000..94f6d73 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/FieldExpressionWithParamsValidatorTest.java @@ -0,0 +1,116 @@ +package jaxx.runtime.validator.field; + +/** @author chemit */ +public class FieldExpressionWithParamsValidatorTest extends AbstractFieldValidatorTest<FieldExpressionBean> { + + public static final String MESSAGE = "expression.too.big##100"; + public static final String MESSAGE2 = "expression.too.big##100##2000"; + + public FieldExpressionWithParamsValidatorTest() { + super(FieldExpressionBean.class); + } + + @org.junit.Test + @Override + public void testValidator() throws Exception { + + testBooleanType(); + testShortType(); + testIntType(); + testLongType(); + testDoubleType(); + testStringType(); + + + } + + protected void testBooleanType() { + + assertEquals(false, bean.isBooleanValue()); + assertFieldInError("booleanValue", "expression.boolean.not.equals##true", true); + assertFieldInError("booleanValue", "expression.boolean.not.equals##false", false); + + bean.setBooleanValue(true); + assertFieldInError("booleanValue", "expression.boolean.not.equals##true", false); + assertFieldInError("booleanValue", "expression.boolean.not.equals##false", true); + } + + protected void testShortType() { + assertEquals(0, bean.getShortValue()); + assertFieldInError("shortValue", MESSAGE, false); + assertFieldInError("shortValue", MESSAGE2, false); + bean.setShortValue((short) 10); + assertFieldInError("shortValue", MESSAGE, false); + assertFieldInError("shortValue", MESSAGE2, false); + bean.setShortValue((short) 1000); + assertFieldInError("shortValue", MESSAGE, true); + assertFieldInError("shortValue", MESSAGE2, false); + bean.setShortValue((short) 3000); + assertFieldInError("shortValue", MESSAGE, true); + assertFieldInError("shortValue", MESSAGE2, true); + } + + protected void testIntType() { + assertEquals(0, bean.getIntValue()); + assertFieldInError("intValue", MESSAGE, false); + assertFieldInError("intValue", MESSAGE2, false); + bean.setIntValue(10); + assertFieldInError("intValue", MESSAGE, false); + assertFieldInError("intValue", MESSAGE2, false); + bean.setIntValue(1000); + assertFieldInError("intValue", MESSAGE, true); + assertFieldInError("intValue", MESSAGE2, false); + bean.setIntValue(3000); + assertFieldInError("intValue", MESSAGE, true); + assertFieldInError("intValue", MESSAGE2, true); + } + + protected void testLongType() { + assertEquals(0, bean.getLongValue()); + assertFieldInError("longValue", MESSAGE, false); + assertFieldInError("longValue", MESSAGE2, false); + bean.setLongValue(10); + assertFieldInError("longValue", MESSAGE, false); + assertFieldInError("longValue", MESSAGE2, false); + bean.setLongValue(1000); + assertFieldInError("longValue", MESSAGE, true); + assertFieldInError("longValue", MESSAGE2, false); + bean.setLongValue(3000); + assertFieldInError("longValue", MESSAGE, true); + assertFieldInError("longValue", MESSAGE2, true); + } + + protected void testDoubleType() { + assertEquals(0.0, bean.getDoubleValue(), 0); + assertFieldInError("doubleValue", MESSAGE + ".0", false); + assertFieldInError("doubleValue", "expression.too.big##100.0##2000.0", false); + bean.setDoubleValue(10); + assertFieldInError("doubleValue", MESSAGE + ".0", false); + assertFieldInError("doubleValue", "expression.too.big##100.0##2000.0", false); + bean.setDoubleValue(1000); + assertFieldInError("doubleValue", MESSAGE + ".0", true); + assertFieldInError("doubleValue", "expression.too.big##100.0##2000.0", false); + bean.setDoubleValue(3000); + assertFieldInError("doubleValue", MESSAGE + ".0", true); + assertFieldInError("doubleValue", "expression.too.big##100.0##2000.0", true); + } + + protected void testStringType() { + assertEquals(null, bean.getStringValue()); + + assertFieldInError("stringValue", "expression.stringNotValue##1000", true); + assertFieldInError("stringValue", "expression.stringNotValue##1000##3000", true); + bean.setStringValue("100"); + + assertFieldInError("stringValue", "expression.stringNotValue##1000", true); + assertFieldInError("stringValue", "expression.stringNotValue##1000##3000", true); + + bean.setStringValue("1000"); + assertFieldInError("stringValue", "expression.stringNotValue##1000", false); + assertFieldInError("stringValue", "expression.stringNotValue##1000##3000", false); + + bean.setStringValue("3000"); + assertFieldInError("stringValue", "expression.stringNotValue##1000", true); + assertFieldInError("stringValue", "expression.stringNotValue##1000##3000", false); + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/NotExistingDirectoryFieldValidatorTest.java b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/NotExistingDirectoryFieldValidatorTest.java new file mode 100644 index 0000000..631e502 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/NotExistingDirectoryFieldValidatorTest.java @@ -0,0 +1,33 @@ +package jaxx.runtime.validator.field; + +import java.io.File; + +/** @author chemit */ +public class NotExistingDirectoryFieldValidatorTest extends AbstractValidatorBeanFieldValidatorTest { + + @org.junit.Test + @Override + public void testValidator() throws Exception { + assertNull(bean.getNotExistingDirectory()); + assertFieldInError("notExistingDirectory", "notExistingDirectory.required", true); + + bean.setNotExistingDirectory(new File("")); + assertFieldInError("notExistingDirectory", "notExistingDirectory.required", true); + + // existing directory + bean.setNotExistingDirectory(basedir); + assertFieldInError("notExistingDirectory", "notExistingDirectory.required", false); + assertFieldInError("notExistingDirectory", "notExistingDirectory.exist", true); + + // existing file + bean.setNotExistingDirectory(new File(basedir, "pom.xml")); + assertFieldInError("notExistingDirectory", "notExistingDirectory.required", false); + assertFieldInError("notExistingDirectory", "notExistingDirectory.exist", true); + + // none existing directory + bean.setNotExistingDirectory(new File(basedir, "pom.xml-" + System.currentTimeMillis())); + assertFieldInError("notExistingDirectory", "notEexistingFile.required", false); + assertFieldInError("notExistingDirectory", "notExistingDirectory.exist", false); + } + +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/NotExistingFileFieldValidatorTest.java b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/NotExistingFileFieldValidatorTest.java new file mode 100644 index 0000000..8ac7ef2 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/NotExistingFileFieldValidatorTest.java @@ -0,0 +1,37 @@ +package jaxx.runtime.validator.field; + +import java.io.File; + +/** @author chemit */ +public class NotExistingFileFieldValidatorTest extends AbstractValidatorBeanFieldValidatorTest { + + + @org.junit.Test + @Override + public void testValidator() throws Exception { + + assertNull(bean.getNotExistingFile()); + assertFieldInError("notExistingFile", "notExistingFile.required", true); + + bean.setNotExistingFile(new File("")); + assertFieldInError("notExistingFile", "notExistingFile.required", true); + + // existing directory + bean.setNotExistingFile(basedir); + assertFieldInError("notExistingFile", "notExistingFile.required", false); + assertFieldInError("notExistingFile", "notExistingFile.exist", true); + + // existing file + bean.setNotExistingFile(new File(basedir, "pom.xml")); + assertFieldInError("notExistingFile", "notExistingFile.required", false); + assertFieldInError("notExistingFile", "notExistingFile.exist", true); + + // none existing file + bean.setNotExistingFile(new File(basedir, "pom.xml-" + System.currentTimeMillis())); + assertFieldInError("notExistingFile", "notEexistingFile.required", false); + assertFieldInError("notExistingFile", "notExistingFile.exist", false); + + + } + +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/RequiredFileFieldValidatorTest.java b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/RequiredFileFieldValidatorTest.java new file mode 100644 index 0000000..aee45a7 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/RequiredFileFieldValidatorTest.java @@ -0,0 +1,29 @@ +package jaxx.runtime.validator.field; + +import java.io.File; + +/** @author chemit */ +public class RequiredFileFieldValidatorTest extends AbstractValidatorBeanFieldValidatorTest { + + @org.junit.Test + @Override + public void testValidator() throws Exception { + + assertNull(bean.getExistingFile()); + assertFieldInError("existingFile", "existingFile.required", true); + + bean.setExistingFile(new File("")); + assertFieldInError("existingFile", "existingFile.required", true); + + bean.setExistingFile(basedir); + assertFieldInError("existingFile", "existingFile.required", false); + + assertFieldInError("existingFile", "existingFile.not.exist", true); + + bean.setExistingFile(new File(basedir, "pom.xml")); + assertFieldInError("existingFile", "existingFile.required", false); + assertFieldInError("existingFile", "existingFile.not.exist", false); + + } + +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/ValidatorBean.java b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/ValidatorBean.java new file mode 100644 index 0000000..aa1b765 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/java/jaxx/runtime/validator/field/ValidatorBean.java @@ -0,0 +1,149 @@ +package jaxx.runtime.validator.field; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.File; +import java.util.Collection; + +public class ValidatorBean { + + public static class ValidatorBeanEntry { + + protected int intValue; + protected String stringValue; + protected String stringValue2; + + public ValidatorBeanEntry(int intValue, String stringValue) { + this.intValue = intValue; + this.stringValue = stringValue; + } + + public ValidatorBeanEntry(int intValue, String stringValue, String stringValue2) { + this.intValue = intValue; + this.stringValue = stringValue; + this.stringValue2 = stringValue2; + } + + public int getIntValue() { + return intValue; + } + + public void setIntValue(int intValue) { + this.intValue = intValue; + } + + public String getStringValue() { + return stringValue; + } + + public void setStringValue(String stringValue) { + this.stringValue = stringValue; + } + + public String getStringValue2() { + return stringValue2; + } + + public void setStringValue2(String stringValue2) { + this.stringValue2 = stringValue2; + } + } + protected File existingFile; + protected File notExistingFile; + protected File existingDirectory; + protected File notExistingDirectory; + protected Collection<ValidatorBeanEntry> entries; + protected String stringValue; + protected ValidatorBeanEntry entry; + PropertyChangeSupport p; + + public ValidatorBean() { + p = new PropertyChangeSupport(this); + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + p.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + p.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + p.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + p.removePropertyChangeListener(propertyName, listener); + } + + public String getStringValue() { + return stringValue; + } + + public File getExistingFile() { + return existingFile; + } + + public File getNotExistingFile() { + return notExistingFile; + } + + public File getExistingDirectory() { + return existingDirectory; + } + + public File getNotExistingDirectory() { + return notExistingDirectory; + } + + public ValidatorBeanEntry getEntry() { + return entry; + } + + public Collection<ValidatorBeanEntry> getEntries() { + return entries; + } + + public void setStringValue(String stringValue) { + String old = this.stringValue; + this.stringValue = stringValue; + p.firePropertyChange("stringValue", old, existingFile); + } + + public void setExistingFile(File existingFile) { + File old = this.existingFile; + this.existingFile = existingFile; + p.firePropertyChange("existingFile", old, existingFile); + } + + public void setNotExistingFile(File notExistingFile) { + File old = this.notExistingFile; + this.notExistingFile = notExistingFile; + p.firePropertyChange("notExistingFile", old, notExistingFile); + } + + public void setExistingDirectory(File existingDirectory) { + File old = this.existingDirectory; + this.existingDirectory = existingDirectory; + p.firePropertyChange("existingDirectory", old, existingDirectory); + } + + public void setNotExistingDirectory(File notExistingDirectory) { + File old = this.notExistingDirectory; + this.notExistingDirectory = notExistingDirectory; + p.firePropertyChange("notExistingDirectory", old, notExistingDirectory); + } + + public void setEntries(Collection<ValidatorBeanEntry> entries) { + this.entries = entries; + // set null oldValue to always fire event + // otherwise it could been not sent... + p.firePropertyChange("entries", null, entries); + } + + public void setEntry(ValidatorBeanEntry entry) { + this.entry = entry; + p.firePropertyChange("entry", null, entry); + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/test/resources/jaxx/runtime/validator/SimpleBean-error-validation.xml b/trunk/jaxx-runtime-api/src/test/resources/jaxx/runtime/validator/SimpleBean-error-validation.xml new file mode 100644 index 0000000..4e7de94 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/resources/jaxx/runtime/validator/SimpleBean-error-validation.xml @@ -0,0 +1,19 @@ +<!DOCTYPE validators PUBLIC + "-//OpenSymphony Group//XWork Validator 1.0.2//EN" + "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"> +<validators> + + <field name="stringValue"> + <field-validator type="requiredstring"> + <message>stringValue.error</message> + </field-validator> + </field> + + <field name="intValue"> + <field-validator type="int"> + <param name="min">1</param> + <message>intValue.error</message> + </field-validator> + </field> + +</validators> \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/test/resources/jaxx/runtime/validator/SimpleBean-info-validation.xml b/trunk/jaxx-runtime-api/src/test/resources/jaxx/runtime/validator/SimpleBean-info-validation.xml new file mode 100644 index 0000000..d0466cf --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/resources/jaxx/runtime/validator/SimpleBean-info-validation.xml @@ -0,0 +1,13 @@ +<!DOCTYPE validators PUBLIC + "-//OpenSymphony Group//XWork Validator 1.0.2//EN" + "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"> +<validators> + + <field name="intValue"> + <field-validator type="int"> + <param name="min">10</param> + <message>intValue.info</message> + </field-validator> + </field> + +</validators> \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/test/resources/jaxx/runtime/validator/SimpleBean-simple-validation.xml b/trunk/jaxx-runtime-api/src/test/resources/jaxx/runtime/validator/SimpleBean-simple-validation.xml new file mode 100644 index 0000000..2f558aa --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/resources/jaxx/runtime/validator/SimpleBean-simple-validation.xml @@ -0,0 +1,19 @@ +<!DOCTYPE validators PUBLIC + "-//OpenSymphony Group//XWork Validator 1.0.2//EN" + "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"> +<validators> + + <field name="stringValue"> + <field-validator type="requiredstring"> + <message>stringValue.null</message> + </field-validator> + </field> + + <field name="intValue"> + <field-validator type="int"> + <param name="min">1</param> + <message>intValue.null</message> + </field-validator> + </field> + +</validators> \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/test/resources/jaxx/runtime/validator/SimpleBean-warning-validation.xml b/trunk/jaxx-runtime-api/src/test/resources/jaxx/runtime/validator/SimpleBean-warning-validation.xml new file mode 100644 index 0000000..1de039a --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/resources/jaxx/runtime/validator/SimpleBean-warning-validation.xml @@ -0,0 +1,13 @@ +<!DOCTYPE validators PUBLIC + "-//OpenSymphony Group//XWork Validator 1.0.2//EN" + "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"> +<validators> + + <field name="stringValue"> + <field-validator type="fieldexpression"> + <param name="expression"><![CDATA[ stringValue != null && stringValue.length() > 5]]></param> + <message>stringValue.warning</message> + </field-validator> + </field> + +</validators> \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/test/resources/jaxx/runtime/validator/field/FieldExpressionBean-error-validation.xml b/trunk/jaxx-runtime-api/src/test/resources/jaxx/runtime/validator/field/FieldExpressionBean-error-validation.xml new file mode 100644 index 0000000..2571a52 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/resources/jaxx/runtime/validator/field/FieldExpressionBean-error-validation.xml @@ -0,0 +1,99 @@ +<!DOCTYPE validators PUBLIC + "-//OpenSymphony Group//XWork Validator 1.0.2//EN" + "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"> +<validators> + +<field name="booleanValue"> + <field-validator type="fieldexpressionwithparams"> + <param name="booleanParams">boolean:true</param> + <param name="expression"><![CDATA[ booleanValue == booleans.boolean]]> + </param> + <message>expression.boolean.not.equals##${booleans.boolean}</message> + </field-validator> + <field-validator type="fieldexpressionwithparams"> + <param name="booleanParams">boolean:false</param> + <param name="expression"><![CDATA[ booleanValue == booleans.boolean]]> + </param> + <message>expression.boolean.not.equals##${booleans.boolean}</message> + </field-validator> + </field> + + <field name="shortValue"> + <field-validator type="fieldexpressionwithparams"> + <param name="shortParams">short:100</param> + <param name="expression"><![CDATA[ shortValue < shorts.short]]> + </param> + <message>expression.too.big##${shorts.short}</message> + </field-validator> + <field-validator type="fieldexpressionwithparams"> + <param name="shortParams">short:100|short2:2000</param> + <param name="expression"><![CDATA[ shortValue < shorts.short || shortValue < shorts.short2]]> + </param> + <message>expression.too.big##${shorts.short}##${shorts.short2}</message> + </field-validator> + </field> + + <field name="intValue"> + <field-validator type="fieldexpressionwithparams"> + <param name="intParams">int:100</param> + <param name="expression"><![CDATA[ intValue < ints.int]]> + </param> + <message>expression.too.big##${ints.int}</message> + </field-validator> + <field-validator type="fieldexpressionwithparams"> + <param name="intParams">int:100|int2:2000</param> + <param name="expression"><![CDATA[ intValue < ints.int || intValue < ints.int2]]> + </param> + <message>expression.too.big##${ints.int}##${ints.int2}</message> + </field-validator> + </field> + + <field name="longValue"> + <field-validator type="fieldexpressionwithparams"> + <param name="longParams">long:100</param> + <param name="expression"><![CDATA[ longValue < longs.long]]> + </param> + <message>expression.too.big##${longs.long}</message> + </field-validator> + <field-validator type="fieldexpressionwithparams"> + <param name="longParams">long:100|long2:2000</param> + <param name="expression"><![CDATA[ longValue < longs.long || longValue < longs.long2]]> + </param> + <message>expression.too.big##${longs.long}##${longs.long2}</message> + </field-validator> + </field> + + <field name="doubleValue"> + <field-validator type="fieldexpressionwithparams"> + <param name="doubleParams">double:100.0</param> + <param name="expression"><![CDATA[ doubleValue < doubles.double]]> + </param> + <message>expression.too.big##${doubles.double}</message> + </field-validator> + <field-validator type="fieldexpressionwithparams"> + <param name="doubleParams">double:100.0|double2:2000.0</param> + <param name="expression"><![CDATA[ doubleValue < doubles.double || doubleValue < doubles.double2]]> + </param> + <message>expression.too.big##${doubles.double}##${doubles.double2}</message> + </field-validator> + </field> + + <field name="stringValue"> + <field-validator type="fieldexpressionwithparams"> + <param name="stringParams">string:1000</param> + <param name="expression"><![CDATA[ stringValue.equals(strings.string)]]> + </param> + <message>expression.stringNotValue##${strings.string}</message> + </field-validator> + <field-validator type="fieldexpressionwithparams"> + <param name="stringParams">string:1000|string2:3000</param> + <param name="expression"><![CDATA[ stringValue.equals(strings.string) || stringValue.equals(strings.string2)]]> + </param> + <message>expression.stringNotValue##${strings.string}##${strings.string2}</message> + </field-validator> + </field> + + + + +</validators> \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/test/resources/jaxx/runtime/validator/field/ValidatorBean-error-validation.xml b/trunk/jaxx-runtime-api/src/test/resources/jaxx/runtime/validator/field/ValidatorBean-error-validation.xml new file mode 100644 index 0000000..7000c04 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/resources/jaxx/runtime/validator/field/ValidatorBean-error-validation.xml @@ -0,0 +1,155 @@ +<!DOCTYPE validators PUBLIC + "-//OpenSymphony Group//XWork Validator 1.0.2//EN" + "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"> +<validators> + + <field name="stringValue"> + <field-validator type="requiredstring" short-circuit="true"> + <message>stringValue.required</message> + </field-validator> + </field> + + <field name="existingFile"> + <field-validator type="requiredFile" short-circuit="true"> + <message>existingFile.required</message> + </field-validator> + <field-validator type="existingFile" short-circuit="true"> + <message>existingFile.not.exist</message> + </field-validator> + </field> + + <field name="notExistingFile"> + <field-validator type="requiredFile" short-circuit="true"> + <message>notExistingFile.required</message> + </field-validator> + <field-validator type="notExistingFile" short-circuit="true"> + <message>notExistingFile.exist</message> + </field-validator> + </field> + + <field name="existingDirectory"> + <field-validator type="requiredFile" short-circuit="true"> + <message>existingDirectory.required</message> + </field-validator> + + <field-validator type="existingDirectory" short-circuit="true"> + <message>existingDirectory.not.exist</message> + </field-validator> + </field> + + <field name="notExistingDirectory"> + <field-validator type="requiredFile" short-circuit="true"> + <message>notExistingDirectory.required</message> + </field-validator> + + <field-validator type="notExistingDirectory" short-circuit="true"> + <message>notExistingDirectory.exist</message> + </field-validator> + </field> + + <field name="entries"> + + <field-validator type="collectionUniqueKey"> + <param name="keys">intValue</param> + <message>collectionUniqueKey.one.failed</message> + </field-validator> + <field-validator type="collectionUniqueKey"> + <param name="keys">stringValue</param> + <message>collectionUniqueKey.two.failed</message> + </field-validator> + <field-validator type="collectionUniqueKey"> + <param name="keys">intValue,stringValue</param> + <message>collectionUniqueKey.three.failed</message> + </field-validator> + <field-validator type="collectionUniqueKey"> + <param name="keys">intValue,stringValue,stringValue2</param> + <message>collectionUniqueKey.four.failed</message> + </field-validator> + <field-validator type="collectionUniqueKey"> + <param name="keys">stringValue</param> + <param name="againstProperty">entry</param> + <message>collectionUniqueKey.five.failed</message> + </field-validator> + + <field-validator type="collectionFieldExpression"> + <param name="mode">AT_LEAST_ONE</param> + <param name="expression"><![CDATA[ intValue == 0 && stringValue == "stringValue" ]]> + </param> + <message>collectionFieldExpression.atLeastOne</message> + </field-validator> + <field-validator type="collectionFieldExpression"> + <param name="mode">EXACTLY_ONE</param> + <param name="expression"><![CDATA[ intValue == 0 && stringValue == "stringValue" ]]> + </param> + <message>collectionFieldExpression.exactlyOne</message> + </field-validator> + <field-validator type="collectionFieldExpression"> + <param name="mode">ALL</param> + <param name="expression"><![CDATA[ intValue == 0 && stringValue == "stringValue" ]]> + </param> + <message>collectionFieldExpression.all</message> + </field-validator> + <field-validator type="collectionFieldExpression"> + <param name="mode">NONE</param> + <param name="expression"><![CDATA[ intValue == 0 && stringValue == "stringValue" ]]> + </param> + <message>collectionFieldExpression.none</message> + </field-validator> + + <!-- useContext --> + <field-validator type="collectionFieldExpression"> + <param name="mode">AT_LEAST_ONE</param> + <param name="useSensitiveContext">true</param> + <param name="expression"><![CDATA[ size > 1 && previous != null && previous.intValue < current.intValue]]></param> + <message>collectionFieldExpression.atLeastOne.useSensitiveContext</message> + </field-validator> + <field-validator type="collectionFieldExpression"> + <param name="mode">EXACTLY_ONE</param> + <param name="useSensitiveContext">true</param> + <param name="expression"><![CDATA[ size > 1 && previous != null && ( previous.intValue == 2 + current.intValue || current.intValue == 2 + previous.intValue) ]]></param> + <message>collectionFieldExpression.exactlyOne.useSensitiveContext</message> + </field-validator> + <field-validator type="collectionFieldExpression"> + <param name="mode">ALL</param> + <param name="useSensitiveContext">true</param> + <param name="expression"><![CDATA[ size > 1 && (previous == null || previous.intValue < current.intValue)]]></param> + <message>collectionFieldExpression.all.useSensitiveContext</message> + </field-validator> + <field-validator type="collectionFieldExpression"> + <param name="mode">NONE</param> + <param name="useSensitiveContext">true</param> + <param name="expression"><![CDATA[ size > 1 && previous != null && ( current.intValue == 2 + previous.intValue)]]></param> + <message>collectionFieldExpression.none.useSensitiveContext</message> + </field-validator> + + <!-- useFirst --> + <field-validator type="collectionFieldExpression"> + <param name="mode">ALL</param> + <param name="useSensitiveContext">true</param> + <param name="expressionForFirst"><![CDATA[ current.intValue == 0]]></param> + <param name="expression"><![CDATA[ previous == null || previous.intValue < current.intValue]]></param> + <message>collectionFieldExpression.all.useFirst</message> + </field-validator> + + <!-- useLast --> + <field-validator type="collectionFieldExpression"> + <param name="mode">ALL</param> + <param name="useSensitiveContext">true</param> + <param name="expressionForLast"><![CDATA[ current.intValue > 0]]></param> + <param name="expression"><![CDATA[ previous == null || previous.intValue < current.intValue]]></param> + <message>collectionFieldExpression.all.useLast</message> + </field-validator> + + <!-- useFirstAndLast --> + <field-validator type="collectionFieldExpression"> + <param name="mode">ALL</param> + <param name="useSensitiveContext">true</param> + <param name="expressionForFirst"><![CDATA[ current.intValue == 0]]></param> + <param name="expressionForLast"><![CDATA[ current.intValue > 0]]></param> + <param name="expression"><![CDATA[ previous == null || previous.intValue < current.intValue]]></param> + <message>collectionFieldExpression.all.useFirstAndLast</message> + </field-validator> + + </field> + +</validators> \ No newline at end of file diff --git a/trunk/jaxx-runtime-api/src/test/resources/log4j.properties b/trunk/jaxx-runtime-api/src/test/resources/log4j.properties new file mode 100644 index 0000000..8459ad0 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/resources/log4j.properties @@ -0,0 +1,8 @@ +# Global logging configuration +log4j.rootLogger=ERROR, stdout +# Console output... +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) %M - %m%n + +log4j.logger.jaxx=DEBUG diff --git a/trunk/jaxx-runtime-api/src/test/resources/validators.xml b/trunk/jaxx-runtime-api/src/test/resources/validators.xml new file mode 100644 index 0000000..1737f20 --- /dev/null +++ b/trunk/jaxx-runtime-api/src/test/resources/validators.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE validators PUBLIC + "-//OpenSymphony Group//XWork Validator Config 1.0//EN" + "http://www.opensymphony.com/xwork/xwork-validator-config-1.0.dtd"> +<validators> + <!-- default validators from XWork framework --> + <validator name="required" class="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator"/> + <validator name="requiredstring" class="com.opensymphony.xwork2.validator.validators.RequiredStringValidator"/> + <validator name="int" class="com.opensymphony.xwork2.validator.validators.IntRangeFieldValidator"/> + <validator name="long" class="com.opensymphony.xwork2.validator.validators.LongRangeFieldValidator"/> + <validator name="short" class="com.opensymphony.xwork2.validator.validators.ShortRangeFieldValidator"/> + <validator name="double" class="com.opensymphony.xwork2.validator.validators.DoubleRangeFieldValidator"/> + <validator name="date" class="com.opensymphony.xwork2.validator.validators.DateRangeFieldValidator"/> + <validator name="expression" class="com.opensymphony.xwork2.validator.validators.ExpressionValidator"/> + <validator name="fieldexpression" class="com.opensymphony.xwork2.validator.validators.FieldExpressionValidator"/> + <validator name="email" class="com.opensymphony.xwork2.validator.validators.EmailValidator"/> + <validator name="url" class="com.opensymphony.xwork2.validator.validators.URLValidator"/> + <validator name="visitor" class="com.opensymphony.xwork2.validator.validators.VisitorFieldValidator"/> + <validator name="conversion" class="com.opensymphony.xwork2.validator.validators.ConversionErrorFieldValidator"/> + <validator name="stringlength" class="com.opensymphony.xwork2.validator.validators.StringLengthFieldValidator"/> + <validator name="regex" class="com.opensymphony.xwork2.validator.validators.RegexFieldValidator"/> + <validator name="conditionalvisitor" + class="com.opensymphony.xwork2.validator.validators.ConditionalVisitorFieldValidator"/> + + <!-- jaxx validators --> + <validator name="collectionFieldExpression" + class="jaxx.runtime.validator.field.CollectionFieldExpressionValidator"/> + <validator name="collectionUniqueKey" class="jaxx.runtime.validator.field.CollectionUniqueKeyValidator"/> + <validator name="requiredFile" class="jaxx.runtime.validator.field.RequiredFileFieldValidator"/> + <validator name="existingFile" class="jaxx.runtime.validator.field.ExistingFileFieldValidator"/> + <validator name="notExistingFile" class="jaxx.runtime.validator.field.NotExistingFileFieldValidator"/> + <validator name="existingDirectory" class="jaxx.runtime.validator.field.ExistingDirectoryFieldValidator"/> + <validator name="notExistingDirectory" class="jaxx.runtime.validator.field.NotExistingDirectoryFieldValidator"/> + <validator name="fieldexpressionwithparams" class="jaxx.runtime.validator.field.FieldExpressionWithParamsValidator"/> + +</validators> \ No newline at end of file diff --git a/trunk/jaxx-runtime-swing-widget/LICENSE.txt b/trunk/jaxx-runtime-swing-widget/LICENSE.txt new file mode 100644 index 0000000..3f7b8b1 --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/LICENSE.txt @@ -0,0 +1,166 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/trunk/jaxx-runtime-swing-widget/README.txt b/trunk/jaxx-runtime-swing-widget/README.txt new file mode 100644 index 0000000..d2e50d3 --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/README.txt @@ -0,0 +1,2 @@ +To deploy new version of pom: mvn deploy +To install localy: mvn install diff --git a/trunk/jaxx-runtime-swing-widget/changelog.txt b/trunk/jaxx-runtime-swing-widget/changelog.txt new file mode 100644 index 0000000..1e285bd --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/changelog.txt @@ -0,0 +1,5 @@ +1.6.0 + * introduce StatusMessageBar and AboutPanel (fork from nuiton-widgets but in JAXX :)) + +1.5 + * 20090404 [chemit] - initial version diff --git a/trunk/jaxx-runtime-swing-widget/pom.xml b/trunk/jaxx-runtime-swing-widget/pom.xml new file mode 100644 index 0000000..81fec60 --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/pom.xml @@ -0,0 +1,123 @@ + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <!-- ************************************************************* --> + <!-- *** POM Relationships *************************************** --> + <!-- ************************************************************* --> + + <parent> + <groupId>org.nuiton</groupId> + <artifactId>jaxx</artifactId> + <version>1.7.1</version> + </parent> + + <groupId>org.nuiton.jaxx</groupId> + <artifactId>jaxx-runtime-swing-widget</artifactId> + + <dependencies> + + <!-- sibiling dependencies --> + + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>jaxx-runtime-swing</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>org.swinglabs</groupId> + <artifactId>swingx</artifactId> + </dependency> + + <dependency> + <groupId>org.swinglabs</groupId> + <artifactId>swing-worker</artifactId> + </dependency> + + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + </dependency> + + </dependencies> + + <!-- ************************************************************* --> + <!-- *** Project Information ************************************* --> + <!-- ************************************************************* --> + + <name>${project.artifactId}</name> + <description>Jaxx runtime swing widgets</description> + + <!-- ************************************************************* --> + <!-- *** Build Settings ****************************************** --> + <!-- ************************************************************* --> + + <packaging>jar</packaging> + + <properties> + <jaxx.addSourcesToClassPath>true</jaxx.addSourcesToClassPath> + <!--jaxx.useUIManagerForIcon>true</jaxx.useUIManagerForIcon--> + </properties> + + <build> + + <resources> + <resource> + <directory>src/main/java</directory> + <includes> + <include>**/*.jaxx</include> + </includes> + </resource> + <resource> + <directory>src/main/resources</directory> + <includes> + <include>**/*</include> + </includes> + </resource> + </resources> + + <plugins> + + <plugin> + <groupId>${project.groupId}</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <version>${project.version}</version> + <executions> + <execution> + <goals> + <goal>generate</goal> + </goals> + </execution> + </executions> + </plugin> + + <plugin> + <groupId>org.nuiton.i18n</groupId> + <artifactId>maven-i18n-plugin</artifactId> + <configuration> + <silent>true</silent> + <entries> + <entry> + <basedir>${maven.gen.dir}/java/</basedir> + <includes> + <param>**\/**.java</param> + </includes> + </entry> + </entries> + </configuration> + <executions> + <execution> + <goals> + <goal>parserJava</goal> + <goal>gen</goal> + </goals> + </execution> + </executions> + </plugin> + + </plugins> + </build> + +</project> \ No newline at end of file diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/AboutPanel.jaxx b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/AboutPanel.jaxx new file mode 100644 index 0000000..86395e6 --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/AboutPanel.jaxx @@ -0,0 +1,224 @@ +<!-- + +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ + +--> +<Table insets='1' + background='{getBackgroundColor()}' + border='{BorderFactory.createLineBorder(Color.BLACK, 1)}'> + +<String id='title' javaBean='null'/> + +<String id='iconPath' javaBean='null'/> + +<String id='aboutText' javaBean='null'/> + +<String id='bottomText' javaBean='null'/> + +<String id='licenseText' javaBean='null'/> + +<String id='thirdpartyText' javaBean='null'/> + +<Color id='backgroundColor' javaBean='null'/> + + <script><![CDATA[ +import org.nuiton.util.Resource; +import jaxx.runtime.SwingUtil; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import org.apache.commons.io.IOUtils; + +final Action closeAction = new AbstractAction("close") { + private static final long serialVersionUID = 1L; + + @Override + public void actionPerformed(ActionEvent e) { + JDialog container = getParentContainer(JDialog.class); + if (container != null) { + container.dispose(); + } else { + setVisible(false); + } + } +}; + +public void setLicenseFile(String filename) { + String load = load(filename); + setLicenseText(load); +} + +public void setThirdpartyFile(String filename) { + String load = load(filename); + setThirdpartyText(load); +} + +public void buildTopPanel() { + // image + JLabel labelIcon; + if (iconPath != null) { + Icon logoIcon = Resource.getIcon(iconPath); + labelIcon = new JLabel(logoIcon); + } else { + labelIcon = new JLabel(); + } + topPanel.add(labelIcon); +} + +public void init() { + if (getAboutText() == null) { + tabs.remove(aboutContent); + } + if (getLicenseText() == null) { + tabs.remove(licenseContent); + } else { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + licenseTextArea.setCaretPosition(0); + } + }); + + } + if (getThirdpartyText() == null) { + tabs.remove(thirdpartyContent); + } else { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + thirdpartyTextArea.setCaretPosition(0); + } + }); + } +} + +public void showInDialog(Frame ui, boolean undecorated) { + JDialog f = new JDialog(ui, true); + f.add(this); + if (iconPath != null) { + f.setIconImage(SwingUtil.createIcon(iconPath).getImage()); + } + f.setResizable(false); + f.setSize(550, 450); + f.setUndecorated(undecorated); + JRootPane rootPane = f.getRootPane(); + rootPane.setDefaultButton(close); + rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("ESCAPE"), "close"); + rootPane.getActionMap().put("close", closeAction); + SwingUtil.center(ui, f); + f.setVisible(true); +} + +protected String load(String filename) { + InputStream licenseStream = getClass().getResourceAsStream("/" + filename); + String result = null; + try { + if (licenseStream != null) { + result = IOUtils.toString(licenseStream); + } + } catch (IOException ex) { + // ignore it + } finally { + if (licenseStream != null) { + try { + licenseStream.close(); + } catch (IOException ex) { + log.error("could not close file " + filename); + } + } + } + if (result == null) { + result = "resource " + filename + " not found"; + } + return result; +} + +void $afterCompleteSetup() { + buildTopPanel(); + close.setText(_("aboutframe.ok")); +} + +]]> + </script> + <row> + <cell weightx='1' fill='both'> + <JPanel background='{Color.WHITE}' layout='{new BorderLayout()}'> + <JLabel text='{SwingUtil.getStringValue(getTitle())}' + visible='{getTitle() != null}' + font-size='12' + constraints='BorderLayout.CENTER'/> + </JPanel> + </cell> + </row> + <row> + <cell weightx='1' fill='both'> + <JPanel id='topPanel'/> + </cell> + </row> + <row> + <cell weighty='1' fill='both'> + <JTabbedPane id='tabs'> + <tab title="aboutframe.about"> + <JScrollPane id='aboutContent' border='{null}'> + <JEditorPane contentType='text/html' + editable='false' + border='{null}' + text='{SwingUtil.getStringValue(getAboutText())}' + onHyperlinkUpdate='SwingUtil.openLink(event)'/> + </JScrollPane> + </tab> + <tab title="aboutframe.license"> + <JScrollPane id='licenseContent' border='{null}'> + <JTextArea id='licenseTextArea' + editable='false' + font-size='11' + border='{null}' + text='{SwingUtil.getStringValue(getLicenseText())}'/> + </JScrollPane> + </tab> + <tab title="aboutframe.thirdparty"> + <JScrollPane id='thirdpartyContent' border='{null}'> + <JTextArea id='thirdpartyTextArea' + editable='false' + font-size='11' + border='{null}' + text='{SwingUtil.getStringValue(getThirdpartyText())}'/> + </JScrollPane> + </tab> + </JTabbedPane> + </cell> + </row> + <row> + <cell fill='both'> + <JPanel layout='{new BorderLayout()}'> + <JLabel id='bottomLabel' + constraints='BorderLayout.CENTER' + horizontalAlignment='{SwingConstants.CENTER}' + text='{SwingUtil.getStringValue(getBottomText())}' + visible='{getBottomText() != null}'/> + <JButton id='close' action='{closeAction}' constraints='BorderLayout.EAST'/> + </JPanel> + </cell> + </row> + +</Table> diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/ClockWidget.jaxx b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/ClockWidget.jaxx new file mode 100644 index 0000000..a777613 --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/ClockWidget.jaxx @@ -0,0 +1,55 @@ +<!-- + +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ + +--> +<JLabel implements='ActionListener' + foreground='{Color.BLACK}' + background='{Color.WHITE}'> + +<javax.swing.Timer id='timer' constructorParams='60000,this' /> + + <script><![CDATA[ + +@Override +public void actionPerformed(ActionEvent evt) { + update(); +} + +/** Adds a feature to the Notify attribute of the Clock object */ +@Override +public void addNotify() { + super.addNotify(); + update(); + timer.start(); +} + +@Override +public void removeNotify() { + timer.stop(); + super.removeNotify(); +} + +protected void update() { + setText(java.text.DateFormat.getTimeInstance(3).format(new Date())); +} +]]> + </script> +</JLabel> diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/EntityComboBox.jaxx b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/EntityComboBox.jaxx new file mode 100644 index 0000000..f2cf273 --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/EntityComboBox.jaxx @@ -0,0 +1,131 @@ +<!-- + +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ + +--> +<Table fill='both' insets='0' + onFocusGained='combobox.requestFocus()' + onFocusLost='hidePopup()'> + + <!-- auto complete property --> + <Boolean id='autoComplete' javaBean='false'/> + + <!-- show reset property --> + <Boolean id='showReset' javaBean='false'/> + + <!-- show decorator property --> + <Boolean id='showDecorator' javaBean='true'/> + + <Boolean id='editable' javaBean='true'/> + + <!-- bean property linked state --> + <String id='property' javaBean='""'/> + + <!-- bean property --> + <Object id='bean' javaBean='null'/> + + <!-- selectedItem property --> + <Object id='selectedItem' javaBean='null'/> + + <!-- sort index property --> + <Integer id='index' javaBean='0'/> + + <!-- datas of the combo-box --> + <java.util.List id='data' javaBean='null'/> + + <!-- model of sorted property --> + <ButtonGroup id='indexes' useToolTipText='true' + onStateChanged='setIndex((Integer)indexes.getSelectedValue())'/> + + <!-- ui handler --> + <EntityComboBoxHandler id='handler' constructorParams='this'/> + + <String id='selectedToolTipText' javaBean='null'/> + + <String id='notSelectedToolTipText' javaBean='null'/> + + <String id='popupTitleText' javaBean='null'/> + + <String id='i18nPrefix' javaBean='"entitycombobox.common."'/> + + <!-- popup to change sorted property--> + <JPopupMenu id='popup' + border='{new TitledBorder(_("entitycombobox.popup.title"))}' + onPopupMenuWillBecomeInvisible='getChangeDecorator().setSelected(false)' + onPopupMenuCanceled='getChangeDecorator().setSelected(false)'> + <JLabel id='popupLabel'/> + <JSeparator/> + </JPopupMenu> + + <script><![CDATA[ +import static org.nuiton.i18n.I18n.n_; + +public static final String DEFAULT_POPUP_LABEL = n_("entitycombobox.popup.label"); + +public static final String DEFAULT_SELECTED_TOOLTIP = n_("entitycombobox.sort.on"); + +public static final String DEFAULT_NOT_SELECTED_TOOLTIP = n_("entitycombobox.sort.off"); + +public <O> void init(jaxx.runtime.JXPathDecorator<O> decorator, java.util.List<O> data) { + handler.init(decorator, data); +} + +protected void hidePopup() { + if (popup.isVisible()) { + popup.setVisible(false); + } +} +]]> + </script> + <row> + <cell anchor='west'> + <!-- le boutton pour reinitialiser la valeur sélectionnée --> + <JToolBar floatable='false' borderPainted='false' visible='{isShowReset()}'> + <JButton actionIcon='combobox-reset' + toolTipText='entitycombobox.action.reset.tip' + focusable='false' + focusPainted='false' + enabled='{isEnabled()}' + onActionPerformed='setSelectedItem(null)'/> + </JToolBar> + + </cell> + <cell weightx='1'> + <!-- la liste déroulante --> + <JComboBox id='combobox' + selectedItem='{getSelectedItem()}' + enabled='{isEnabled()}' + editable='{isEditable()}' + onFocusGained='hidePopup()' + onItemStateChanged='setSelectedItem(combobox.getSelectedItem())'/> + </cell> + <cell anchor='east' fill='both' insets='0'> + <!-- le boutton pour changer le tri --> + <JToolBar floatable='false' borderPainted='false' visible='{isShowDecorator()}'> + <JToggleButton id='changeDecorator' + actionIcon='combobox-sort' + toolTipText='entitycombobox.action.sort.tip' + focusable='false' + focusPainted='false' + onActionPerformed='getHandler().togglePopup()'/> + </JToolBar> + </cell> + </row> +</Table> diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/EntityComboBoxHandler.java b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/EntityComboBoxHandler.java new file mode 100644 index 0000000..fcd3218 --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/EntityComboBoxHandler.java @@ -0,0 +1,470 @@ +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ +package jaxx.runtime.swing; + +import java.awt.Component; +import jaxx.runtime.JXPathDecorator; +import jaxx.runtime.MultiJXPathDecorator; +import jaxx.runtime.Util; +import jaxx.runtime.SwingUtil; +import org.apache.commons.beanutils.PropertyUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import static org.nuiton.i18n.I18n._; +import static org.nuiton.i18n.I18n.n_; +import org.jdesktop.swingx.autocomplete.ObjectToStringConverter; + +import javax.swing.JPopupMenu; +import javax.swing.JRadioButtonMenuItem; +import javax.swing.JToggleButton; +import javax.swing.SwingUtilities; +import javax.swing.text.Document; +import javax.swing.text.JTextComponent; +import java.awt.Dimension; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.beans.Introspector; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; +import java.util.List; +import javax.swing.JComboBox; +import jaxx.runtime.Decorator; +import org.jdesktop.swingx.autocomplete.AutoCompletePropertyChangeListener; + +/** + * Le handler d'un {@link EntityComboBox}. + * <p/> + * Note: ce handler n'est pas staeless et n'est donc pas partageable entre plusieurs ui. + * + * @param <O> le type des objet contenus dans le modèle du composant. + * + * @author chemit + * @see EntityComboBox + */ +public class EntityComboBoxHandler<O> implements PropertyChangeListener { + + public static final Log log = LogFactory.getLog(EntityComboBoxHandler.class); + public static final String SELECTED_ITEM_PROPERTY = "selectedItem"; + public static final String INDEX_PROPERTY = "index"; + public static final String AUTO_COMPLETE_PROPERTY = "autoComplete"; + public static final String DATA_PROPERTY = "data"; + /** ui if the handler */ + protected EntityComboBox ui; + /** the mutator method on the property of boxed bean in the ui */ + protected Method mutator; + /** the original document of the combbo box editor (keep it to make possible undecorate) */ + protected Document originalDocument; + /** the convertor used to auto-complete */ + protected ObjectToStringConverter convertor; + /** the decorator of data */ + protected MultiJXPathDecorator<O> decorator; + protected boolean init; + + public EntityComboBoxHandler(EntityComboBox ui) { + this.ui = ui; + } + protected final FocusListener EDITOR_TEXT_COMP0NENT_FOCUSLISTENER = new FocusListener() { + + @Override + public void focusGained(FocusEvent e) { + if (log.isDebugEnabled()) { + log.debug("close popup from " + e); + } + ui.getPopup().setVisible(false); + } + + @Override + public void focusLost(FocusEvent e) { + } + }; + + /** + * Initialise le handler de l'ui + * + * @param decorator le decorateur a utiliser + * @param data la liste des données a gérer + */ + public void init(JXPathDecorator<O> decorator, List<O> data) { + + if (init) { + throw new IllegalStateException("can not init the handler twice"); + } + init = true; + if (decorator == null) { + throw new NullPointerException("can not have a null decorator as parameter"); + } + + JAXXButtonGroup indexes = ui.getIndexes(); + + MultiJXPathDecorator<O> d; + if (decorator instanceof MultiJXPathDecorator<?>) { + // should clone decorator ? + d = (MultiJXPathDecorator<O>) decorator; + } else { + d = MultiJXPathDecorator.newDecorator(decorator.getInternalClass(), decorator.getInitialExpression(), " - "); + } + this.decorator = d; + + // init combobox renderer base on given decorator + ui.getCombobox().setRenderer(Util.newDecoratedListCellRenderer(d)); + + this.convertor = newDecoratedObjectToStringConverter(d); + + // keep a trace of original document (to make possible reverse autom-complete) + JTextComponent editorComponent = (JTextComponent) ui.getCombobox().getEditor().getEditorComponent(); + this.originalDocument = editorComponent.getDocument(); + + // build popup + preparePopup(d); + + ui.autoComplete = true; + + ui.addPropertyChangeListener(this); + + // set datas + ui.setData(data); + + // select sort button + indexes.setSelectedButton(ui.getIndex()); + } + + /** Toggle the popup visible state. */ + public void togglePopup() { + boolean newValue = !ui.getPopup().isVisible(); + + if (log.isTraceEnabled()) { + log.trace(newValue); + } + + if (!newValue) { + if (ui.getPopup() != null) { + ui.getPopup().setVisible(false); + } + return; + } + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + ui.getPopup().pack(); + Dimension dim = ui.getPopup().getPreferredSize(); + JToggleButton invoker = ui.getChangeDecorator(); + ui.getPopup().show(invoker, (int) (invoker.getPreferredSize().getWidth() - dim.getWidth()), invoker.getHeight()); + } + }); + } + + /** + * Modifie l'état autoComplete de l'ui. + * + * @param oldValue l'ancienne valeur + * @param newValue la nouvelle valeur + */ + protected void setAutoComplete(Boolean oldValue, Boolean newValue) { + oldValue = oldValue != null && oldValue; + newValue = newValue != null && newValue; + if (oldValue == newValue) { + return; + } + if (log.isDebugEnabled()) { + log.debug("autocomplete state : <" + oldValue + " to " + newValue + ">"); + } + if (!newValue) { + JTextComponent editorComponent = (JTextComponent) ui.getCombobox().getEditor().getEditorComponent(); + editorComponent.removeFocusListener(EDITOR_TEXT_COMP0NENT_FOCUSLISTENER); + undecorate(ui.getCombobox(), originalDocument); + } else { + decorate(ui.getCombobox(), convertor); + JTextComponent editorComponent = (JTextComponent) ui.getCombobox().getEditor().getEditorComponent(); + editorComponent.addFocusListener(EDITOR_TEXT_COMP0NENT_FOCUSLISTENER); + } + } + + /** + * Modifie l'index du décorateur + * + * @param oldValue l'ancienne valeur + * @param newValue la nouvelle valeur + */ + @SuppressWarnings({"unchecked"}) + protected void setIndex(Integer oldValue, Integer newValue) { + if (newValue.equals(oldValue)) { + return; + } + if (log.isDebugEnabled()) { + log.debug("check state : <" + oldValue + " to " + newValue + ">"); + } + + // change decorator context + decorator.setContextIndex(newValue); + + // keep selected item + Object previousSelectedItem = ui.getSelectedItem(); + Boolean wasAutoComplete = ui.isAutoComplete(); + + if (wasAutoComplete) { + ui.setAutoComplete(false); + } + + // remove autocomplete + if (previousSelectedItem != null) { + ui.getCombobox().setSelectedItem(null); + ui.selectedItem = null; + } + + + try { + // Sort data with the decorator jxpath tokens. + JXPathDecorator.sort(decorator, ui.getData(), newValue); + } catch (Exception e) { + log.warn(e.getMessage(), e); + //System.out.println("newValue :: "+decorator+" : "+newValue); + //System.out.println("datas :: "+ui.getData()); + } + + // reload the model + SwingUtil.fillComboBox(ui.getCombobox(), ui.getData(), null); + + if (wasAutoComplete) { + ui.setAutoComplete(true); + } + + if (previousSelectedItem != null) { + ui.setSelectedItem(previousSelectedItem); + } + + ui.getCombobox().requestFocus(); + } + + /** + * Modifie la valeur sélectionnée dans la liste déroulante. + * + * @param oldValue l'ancienne valeur + * @param newValue la nouvelle valeur + */ + protected void setSelectedItem(Object oldValue, Object newValue) { + if (ui.getBean() == null) { + return; + } + + if (newValue == null) { + if (ui.getCombobox().getSelectedItem() == null) { + return; + } + ui.getCombobox().setSelectedItem(null); + + if (ui.isAutoComplete()) { + ui.setAutoComplete(false); + ui.setAutoComplete(true); + } + + if (oldValue == null) { + return; + } + } + if (log.isDebugEnabled()) { + log.debug(ui.getProperty() + " on " + ui.getBean().getClass() + " :: " + oldValue + " to " + newValue); + } + + try { + Method mut = getMutator(); + if (mut != null) { + mut.invoke(ui.getBean(), newValue); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** @return le document de l'éditeur avant complétion. */ + public Document getOriginalDocument() { + return originalDocument; + } + + public MultiJXPathDecorator<O> getDecorator() { + return decorator; + } + + /** + * Creation de l'ui pour modifier le décorateur. + * + * @param decorator le decorateur a utiliser + */ + protected void preparePopup(MultiJXPathDecorator<?> decorator) { + String selectedTip = ui.getSelectedToolTipText(); + if (selectedTip == null) { + // use default selected tip text + selectedTip = EntityComboBox.DEFAULT_SELECTED_TOOLTIP; + } + String notSelectedTip = ui.getNotSelectedToolTipText(); + if (notSelectedTip == null) { + // use default selected tip text + notSelectedTip = EntityComboBox.DEFAULT_NOT_SELECTED_TOOLTIP; + } + JPopupMenu popup = ui.getPopup(); + + //Container container = ui.getIndexesContainer(); + for (int i = 0, max = decorator.getNbContext(); i < max; i++) { + String property = ui.getI18nPrefix() + decorator.getProperty(i); + String propertyI18n = _(property); + JRadioButtonMenuItem button = new JRadioButtonMenuItem(propertyI18n); + button.putClientProperty(JAXXButtonGroup.BUTTON8GROUP_CLIENT_PROPERTY, ui.getIndexes()); + button.putClientProperty(JAXXButtonGroup.VALUE_CLIENT_PROPERTY, i); + popup.add(button); + if (selectedTip != null) { + button.putClientProperty(JAXXButtonGroup.SELECTED_TIP_CLIENT_PROPERTY, _(selectedTip, propertyI18n)); + } + if (notSelectedTip != null) { + button.putClientProperty(JAXXButtonGroup.NOT_SELECTED_TIP_CLIENT_PROPERTY, _(notSelectedTip, propertyI18n)); + } + button.setSelected(false); + ui.getIndexes().add(button); + } + String title = ui.getPopupTitleText(); + if (title == null) { + // use default popup title + title = EntityComboBox.DEFAULT_POPUP_LABEL; + + Class<?> internalClass = decorator.getInternalClass(); + String beanI18nKey; + if (internalClass == null) { + beanI18nKey = n_("entitycombobox.unknown.type"); + } else { + beanI18nKey = ui.getI18nPrefix() + Introspector.decapitalize(internalClass.getSimpleName()); + } + String beanI18n = _(beanI18nKey); + title = _(title, beanI18n); + } else { + title = _(title); + } + ui.getPopupLabel().setText(title); + ui.getPopup().setLabel(title); + ui.getPopup().invalidate(); + } + + public Class<?> getTargetClass() { + Method m = getMutator(); + return m == null ? null : m.getParameterTypes()[0]; + } + + /** @return le mutateur a utiliser pour modifier le bean associé. */ + protected Method getMutator() { + if (mutator == null) { + Object bean = ui.getBean(); + if (bean == null) { + throw new NullPointerException("could not find bean in " + ui); + } + String property = ui.getProperty(); + if (property == null) { + throw new NullPointerException("could not find property in " + ui); + } + + try { + PropertyDescriptor descriptor = PropertyUtils.getPropertyDescriptor(bean, property); + if (descriptor != null) { + mutator = descriptor.getWriteMethod(); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + return mutator; + } + + /** + * Encapsule un {@link Decorator} dans un {@link ObjectToStringConverter}. + * + * @param decorator le decorateur a encapsuler. + * @return le converter encapsule dans un {@link ObjectToStringConverter} + */ + public static ObjectToStringConverter newDecoratedObjectToStringConverter(final Decorator<?> decorator) { + + return new ObjectToStringConverter() { + + @Override + public String getPreferredStringForItem(Object item) { + return item instanceof String ? (String) item : (item == null ? "" : decorator.toString(item)); + } + }; + } + + /** + * Ajout l'auto-complétion sur une liste déroulante, en utilisant le + * converteur donné pour afficher les données. + * + * @param combo la combo à décorer + * @param convertor le converter utilisé pour afficher les données. + */ + public static void decorate(JComboBox combo, ObjectToStringConverter convertor) { + + org.jdesktop.swingx.autocomplete.AutoCompleteDecorator.decorate(combo, convertor); + } + + /** + * Désactive l'aut-complétion sur une liste déroulante, en y repositionnant + * le modèle du document d'édition d'avant auto-complétion. + * + * @param combo la liste déroulante à décorer + * @param originalDocument le document original de l'édtieur de la + * liste déroulante. + */ + public static void undecorate(JComboBox combo, Document originalDocument) { + + // has not to be editable + combo.setEditable(false); + + // configure the text component=editor component + Component c = combo.getEditor().getEditorComponent(); + JTextComponent editorComponent = (JTextComponent) c; + editorComponent.setDocument(originalDocument); + editorComponent.setText(null); + //remove old property change listener + for (PropertyChangeListener l : c.getPropertyChangeListeners("editor")) { + if (l instanceof AutoCompletePropertyChangeListener) { + c.removePropertyChangeListener("editor", l); + } + } + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + String propertyName = evt.getPropertyName(); + + if (SELECTED_ITEM_PROPERTY.equals(propertyName)) { + setSelectedItem(evt.getOldValue(), evt.getNewValue()); + return; + } + + if (INDEX_PROPERTY.equals(propertyName)) { + setIndex((Integer) evt.getOldValue(), (Integer) evt.getNewValue()); + return; + } + if (AUTO_COMPLETE_PROPERTY.equals(propertyName)) { + setAutoComplete((Boolean) evt.getOldValue(), (Boolean) evt.getNewValue()); + return; + } + if (DATA_PROPERTY.equals(propertyName)) { + // list has changed, force reload of index + setIndex(-1, ui.getIndex()); + } + + } +} diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/ErrorDialogUI.jaxx b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/ErrorDialogUI.jaxx new file mode 100644 index 0000000..4943b57 --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/ErrorDialogUI.jaxx @@ -0,0 +1,88 @@ +<!-- + +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ + +--> +<JDialog title='errorUI.title' modal='true'> + <script><![CDATA[ +protected static ErrorDialogUI instance; +public static void init(Frame frame) { + disposeUI(); + instance = new ErrorDialogUI(frame); + instance.setModalityType(ModalityType.TOOLKIT_MODAL); +} +public static void showError(Exception e) { + if (instance == null) { + instance = new ErrorDialogUI(); + } + instance.getErrorMessage().setText(e.getMessage()); + StringWriter w = new StringWriter(); + e.printStackTrace(new PrintWriter(w)); + instance.getErrorStack().setText(w.toString()); + instance.getErrorStack().setCaretPosition(0); + instance.pack(); + jaxx.runtime.SwingUtil.center(instance.getContextValue(JFrame.class,"parent"), instance); + instance.setVisible(true); +} +public static void disposeUI() { + instance=null; +} + +public ErrorDialogUI(Frame frame) { + super(frame); + if (frame!=null) { + setContextValue(frame); + setContextValue(frame,"parent"); + } + +} + +JRootPane rootPane = getRootPane(); +rootPane.setDefaultButton(close); +rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("ESCAPE"), "close"); +rootPane.getActionMap().put("close", close.getAction()); + ]]></script> + <Table> + <row fill='both'> + <cell> + <JPanel> + <JLabel text='errorUI.message'/> + </JPanel> + </cell> + </row> + <row fill='both'> + <cell> + <JLabel id='errorMessage'/> + </cell> + </row> + <row fill='both' weightx='1' weighty='1'> + <cell> + <JScrollPane width='600' height='200'> + <JTextArea id='errorStack' editable='false' font-size='9'/> + </JScrollPane> + </cell> + </row> + <row fill='horizontal'> + <cell> + <JButton id='close' text='errorUI.action.close' onActionPerformed='dispose()'/> + </cell> + </row> + </Table> +</JDialog> diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/MemoryStatusWidget.jaxx b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/MemoryStatusWidget.jaxx new file mode 100644 index 0000000..035427b --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/MemoryStatusWidget.jaxx @@ -0,0 +1,113 @@ +<!-- + +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ + +--> + +<JComponent implements='ActionListener' + foreground='{Color.BLACK}' + background='{Color.WHITE}' + font='{new JLabel().getFont()}'> + + <javax.swing.Timer id='timer' javaBean='null'/> + + <Color id='progressBackground' javaBean='Color.decode("#666699a")'/> + <Color id='progressForeground' javaBean='Color.decode("#cccccc")'/> + + <script><![CDATA[ +import java.awt.font.FontRenderContext; +import java.awt.font.LineMetrics; +import java.awt.geom.Rectangle2D; + +private final static String memoryTestStr = "99999/99999Mb"; + +private FontRenderContext frc = new FontRenderContext(null, false, false); + +private LineMetrics lm = new JLabel().getFont().getLineMetrics(memoryTestStr, frc); + +@Override +public void actionPerformed(ActionEvent evt) { + repaint(); +} + +/** Adds a feature to the Notify attribute of the MemoryStatus object */ +@Override +public void addNotify() { + super.addNotify(); + setTimer(new javax.swing.Timer(2000, this)); + timer.start(); +} + +@Override +public void removeNotify() { + if (timer != null) { + timer.stop(); + timer = null; + } + super.removeNotify(); +} + +@Override +public void paintComponent(Graphics g) { + Insets insets = new Insets(0, 0, 0, 0); + Runtime runtime = Runtime.getRuntime(); + int freeMemory = (int) (runtime.freeMemory() / 1024L); + int totalMemory = (int) (runtime.totalMemory() / 1024L); + int usedMemory = totalMemory - freeMemory; + int width = getWidth() - insets.left - insets.right; + int height = getHeight() - insets.top - insets.bottom - 1; + float fraction = (float) usedMemory / (float) totalMemory; + g.setColor(progressBackground); + g.fillRect(insets.left, insets.top, (int) ((float) width * fraction), height); + // No i18n string was : + // String str = usedMemory / 1024 + "/" + totalMemory / 1024 + "Mb"; + String str = _("memorywidget.memory", usedMemory / 1024, totalMemory / 1024); + //FontRenderContext frc = new FontRenderContext(null, false, false); + Rectangle2D bounds = g.getFont().getStringBounds(str, frc); + Graphics g2 = g.create(); + g2.setClip(insets.left, insets.top, + (int) ((float) width * fraction), height); + g2.setColor(progressForeground); + g2.drawString(str, insets.left + + (int) ((double) width - bounds.getWidth()) / 2, + (int) ((float) insets.top + lm.getAscent())); + g2.dispose(); + g2 = g.create(); + g2.setClip(insets.left + (int) ((float) width * fraction), + insets.top, getWidth() - insets.left + - (int) ((float) width * fraction), height); + g2.setColor(getForeground()); + g2.drawString(str, insets.left + + (int) ((double) width - bounds.getWidth()) / 2, + (int) ((float) insets.top + lm.getAscent())); + g2.dispose(); +} + + +void $afterCompleteSetup() { + //FontRenderContext frc = new FontRenderContext(null, false, false); + Rectangle2D bounds = getFont().getStringBounds(memoryTestStr, frc); + Dimension dim = new Dimension((int) bounds.getWidth(), (int) bounds .getHeight()); + setPreferredSize(dim); + setMaximumSize(dim); +} +]]> + </script> +</JComponent> diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/StatusMessagePanel.jaxx b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/StatusMessagePanel.jaxx new file mode 100644 index 0000000..1624b60 --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/StatusMessagePanel.jaxx @@ -0,0 +1,84 @@ +<!-- + +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ + +--> + +<Table border='{BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.LOWERED)}' + insets='0' + implements='ActionListener'> + + <Boolean id='showMemoryStatus' javaBean='Boolean.TRUE'/> + <Boolean id='showClock' javaBean='Boolean.TRUE'/> + <Boolean id='showI18n' javaBean='Boolean.FALSE'/> + + <StatusMessagePanelHandler id='handler' /> + + <script><![CDATA[ + +// To ensure status bar constant height, no matter what font are in use... +protected final static String EMPTY_STATUS = " "; + +public void clearStatus() { + handler.stopStatusFader(this); + getStatusLabel().setText(EMPTY_STATUS); +} + +public void setStatus(String status) { + handler.stopStatusFader(this); + getStatusLabel().setText(status); + handler.startStatusFader(this); +} + +@Override +public void actionPerformed(ActionEvent evt) { + handler.fadeStatus(this); +} + +public <U extends Component> U getWidget(Class<U> clazz) { + for (Component component : box.getComponents()) { + if (clazz == component.getClass()) { + return (U) component; + } + } + return null; +} + +public void addWidget(Component w) { + box.add(w); +} + +public void addWidget(Component w, int index) { + box.add(w, index); +} +]]> + </script> + <row> + <cell anchor='west' weightx='1' insets='2'> + <JLabel id='statusLabel'/> + </cell> + <cell anchor='east'> + <Box id='box' constructorParams='0'> + <MemoryStatusWidget/> + <ClockWidget/> + </Box> + </cell> + </row> +</Table> diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/StatusMessagePanelHandler.java b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/StatusMessagePanelHandler.java new file mode 100644 index 0000000..ad45863 --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/StatusMessagePanelHandler.java @@ -0,0 +1,75 @@ +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ +package jaxx.runtime.swing; + +import java.awt.Color; +import java.awt.event.ActionListener; +import javax.swing.Timer; + +/** + * + * @author chemit + * @since 1.6.0 + */ +public class StatusMessagePanelHandler { + + protected Color statusForeground = null; + protected String statusReferenceContent = null; + protected javax.swing.Timer timer = null; + + protected void fadeStatus(StatusMessagePanel ui) { + for (int i = 0; i < 8; i++) { + // synchronized (this) { + if (!statusReferenceContent.equals(ui.getStatusLabel().getText())) { + return; + } + Color currentForeground = ui.getStatusLabel().getForeground(); + Color newColor = new Color(currentForeground.getRed(), + currentForeground.getGreen(), currentForeground.getBlue(), + currentForeground.getAlpha() - 25); + ui.getStatusLabel().setForeground(newColor); + ui.getStatusLabel().repaint(); + // } + // TC-2000311 je comprends pas a quoi ca sert, a part frizzer les ui ? + // si on utilise un Timer, pourquoi utiliser ça ? + /*try { + Thread.sleep(200); + } catch (InterruptedException eee) { + eee.printStackTrace(); + }*/ + } + } + + protected void startStatusFader(StatusMessagePanel ui) { + statusReferenceContent = ui.getStatusLabel().getText(); + + int millisecondsPerMinute = 5000; + timer = new Timer(millisecondsPerMinute, (ActionListener) ui); + timer.setRepeats(false); + timer.setInitialDelay((int) ((long) millisecondsPerMinute - System.currentTimeMillis() % (long) millisecondsPerMinute) + 500); + timer.start(); + } + + protected void stopStatusFader(StatusMessagePanel ui) { + if (timer != null) { + timer.stop(); + ui.getStatusLabel().setForeground(statusForeground); + } + } +} diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/ColumnSelector.jaxx b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/ColumnSelector.jaxx new file mode 100644 index 0000000..26c47b4 --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/ColumnSelector.jaxx @@ -0,0 +1,152 @@ +<!-- + +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ + +--> +<JPanel implements='PropertyChangeListener, ActionListener' + layout='{new BorderLayout()}' + onFocusGained='button.requestFocus()' + onFocusLost='setPopupVisible(false)'> + + <!-- table to works with --> + <Object id='myTable' javaBean='null'/> + + <!-- internal state --> + <Boolean id='popupVisible' javaBean='false'/> + + <!-- ui handler --> + <!--ColumnSelectorHandler id='handler' constructorParams='this'/--> + + <JPopupMenu id='popup' + border='{new TitledBorder(_("i18neditor.popup.title"))}' + onPopupMenuWillBecomeInvisible='button.setSelected(false)' + onPopupMenuCanceled='button.setSelected(false)'> + <JLabel id='popupLabel' enabled='false' text='i18neditor.empty.locales'/> + </JPopupMenu> + + <script><![CDATA[ +import javax.swing.table.TableColumn; +import javax.swing.table.TableCellRenderer; +import jaxx.runtime.swing.I18nTableCellRenderer; + +public static final String TABLE_PROPERTY = "myTable"; +public static final String POPUP_VISIBLE_PROPERTY = "popupVisible"; + +@Override +public void propertyChange(PropertyChangeEvent evt) { + String name = evt.getPropertyName(); + if (log.isDebugEnabled()) { + log.debug(name+" <old:"+evt.getOldValue()+" - new:"+evt.getNewValue()+">"); + } + //log.info(name+" <old:"+evt.getOldValue()+" - new:"+evt.getNewValue()+">"); + if (TABLE_PROPERTY.equals(name)) { + // table has changed, rebuild the popup + try { + + popup.removeAll(); + JTable t = (JTable) evt.getNewValue(); + if (t != null) { + log.info("table has changed ! " + t.getName()); + for (int i = 0, columnCount = t.getColumnCount(); i < columnCount; i++) { + TableColumn column = t.getColumnModel().getColumn(i); + TableCellRenderer defaultRenderer = t.getTableHeader().getDefaultRenderer(); + String columnName = column.getHeaderValue() + ""; + if (defaultRenderer instanceof I18nTableCellRenderer) { + I18nTableCellRenderer renderer = (I18nTableCellRenderer) defaultRenderer; + columnName = _(renderer.getKeys()[i]); + } + JRadioButtonMenuItem b = new JRadioButtonMenuItem(columnName, null, true); + popup.add(b); + b.addActionListener(this); + b.putClientProperty("columnIndex", i); + b.putClientProperty("columnName", columnName); + b.putClientProperty("column", column); + } + } + } finally { + popup.invalidate(); + } + return; + } + if (POPUP_VISIBLE_PROPERTY.equals(name)) { + Boolean newValue = (Boolean) evt.getNewValue(); + if (newValue == null || !newValue) { + if (getPopup() != null && getPopup().isVisible()) { + getPopup().setVisible(false); + } + return; + } + if (!getPopup().isVisible()) { + SwingUtilities.invokeLater(showPopupRunnable); + } + return; + } + +} + +@Override +public void actionPerformed(ActionEvent event) { + JRadioButtonMenuItem source = (JRadioButtonMenuItem) event.getSource(); + boolean selected = source.isSelected(); + TableColumn column = (TableColumn) source.getClientProperty("column"); + Integer columnIndex = (Integer) source.getClientProperty("columnIndex"); + String columnName = (String) source.getClientProperty("columnName"); + log.info(columnName + ", selected : " + selected); + JTable t = (JTable) myTable; + if (selected) { + // reinject the column in table + t.getColumnModel().addColumn(column); + } else { + // remove column from table + t.getColumnModel().removeColumn(column); + } +} + +protected Runnable showPopupRunnable = new Runnable() { + @Override + public void run() { + getPopup().pack(); + Dimension dim = getPopup().getPreferredSize(); + JToggleButton invoker = getButton(); + getPopup().show(invoker, (int) (invoker.getPreferredSize().getWidth() - dim.getWidth()), invoker.getHeight()); + } +}; + + +addPropertyChangeListener(TABLE_PROPERTY,this); +addPropertyChangeListener(POPUP_VISIBLE_PROPERTY,this); +]]> + </script> + <JToolBar floatable='false' + opaque='false' + borderPainted='false'> + <JToggleButton + id='button' + toolTipText='columnselector.action.tip' + actionIcon='numbereditor-calculator' + constraints='BorderLayout.CENTER' + selected='{popup.isVisible()}' + focusable='true' + focusPainted='false' + borderPainted='false' + rolloverEnabled='false' + onItemStateChanged='if (event.getStateChange() == ItemEvent.SELECTED) { setPopupVisible(true); } else { popupVisible = false; }'/> + </JToolBar> +</JPanel> \ No newline at end of file diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/I18nEditor.jaxx b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/I18nEditor.jaxx new file mode 100644 index 0000000..ceccd33 --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/I18nEditor.jaxx @@ -0,0 +1,211 @@ +<!-- + +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ + +--> + +<JPanel implements='PropertyChangeListener, ActionListener' + id='content' + layout='{new BorderLayout()}' + onFocusGained='button.requestFocus()' + onFocusLost='setPopupVisible(false)'> + + <String id='selectedToolTipText' javaBean='null'/> + <String id='notSelectedToolTipText' javaBean='null'/> + + <Boolean id='showText' javaBean='Boolean.TRUE'/> + <Boolean id='showIcon' javaBean='Boolean.TRUE'/> + <Boolean id='popupVisible' javaBean='Boolean.FALSE'/> + + <java.util.List id='locales' javaBean='null' genericType='Locale'/> + + <Locale id='selectedLocale' javaBean='Locale.getDefault()'/> + + <jaxx.runtime.swing.LocaleListCellRenderer id='renderer' javaBean='new LocaleListCellRenderer(showIcon , showText)' showIcon='{isShowIcon()}' showText='{isShowText()}'/> + + <!-- popup to change sorted property--> + <JPopupMenu id='popup' + border='{new TitledBorder(_("i18neditor.popup.title"))}' + onPopupMenuWillBecomeInvisible='button.setSelected(false)' + onPopupMenuCanceled='button.setSelected(false)'> + <JLabel id='popupLabel' enabled='false' text='i18neditor.empty.locales'/> + </JPopupMenu> + + <JToggleButton + id='button' + text='{SwingUtil.getStringValue(renderer.getText(getSelectedLocale()))}' + toolTipText='{getTip(getSelectedLocale())}' + icon='{renderer.getIcon(getSelectedLocale())}' + constraints='BorderLayout.CENTER' + selected='{popup.isVisible()}' + focusable='true' + focusPainted='false' + onItemStateChanged='if (event.getStateChange() == ItemEvent.SELECTED) { setPopupVisible(true); } else { popupVisible = false; }'/> + + <ButtonGroup id='indexes' onStateChanged='log.info(indexes.getSelectedValue())'/> + + <script><![CDATA[ +import java.util.Locale; +import jaxx.runtime.SwingUtil; +import jaxx.runtime.swing.LocaleListCellRenderer; +import static org.nuiton.i18n.I18n.n_; + +public static final String DEFAULT_SELECTED_TOOLTIP = n_("i18neditor.selected"); +public static final String DEFAULT_NOT_SELECTED_TOOLTIP = n_("i18neditor.unselected"); + +public static final String LOCALES_PROPERTY = "locales"; +public static final String SELECTED_LOCALE_PROPERTY = "selectedLocale"; +public static final String SHOW_ICON_PROPERTY = "showIcon"; +public static final String SHOW_TEXT_PROPERTY = "showText"; +public static final String POPUP_VISIBLE_PROPERTY = "popupVisible"; + +@Override +public void propertyChange(PropertyChangeEvent evt) { + String name = evt.getPropertyName(); + if (log.isDebugEnabled()) { + log.debug(name+" <old:"+evt.getOldValue()+" - new:"+evt.getNewValue()+">"); + } + log.info(name+" <old:"+evt.getOldValue()+" - new:"+evt.getNewValue()+">"); + if (LOCALES_PROPERTY.equals(name)) { + Locale oldLocale = getSelectedLocale(); + java.util.Collection<?> newLocales = (java.util.Collection<?>) evt.getNewValue(); + // mise a jour de la popup + boolean oldShowText = renderer.isShowText(); + try { + renderer.setShowText(true); + popup.removeAll(); + for (Object o : newLocales) { + Locale l = (Locale) o; + boolean selected = l.equals(selectedLocale); + String text = renderer.getText(l); + Icon icon = renderer.getIcon(l); + JRadioButtonMenuItem b = new JRadioButtonMenuItem(text, icon, selected); + popup.add(b); + b.addActionListener(this); + b.putClientProperty("locale", l); + b.setToolTipText(getTip(l)); + b.putClientProperty(JAXXButtonGroup.BUTTON8GROUP_CLIENT_PROPERTY, getIndexes()); + b.putClientProperty(JAXXButtonGroup.VALUE_CLIENT_PROPERTY, l); + } + } finally { + renderer.setShowText(oldShowText); + popup.invalidate(); + } + return; + } + if (SHOW_ICON_PROPERTY.equals(name)) { + renderer.setShowIcon((Boolean) evt.getNewValue()); + processDataBinding("button.icon"); + return; + } + if (SHOW_TEXT_PROPERTY.equals(name)) { + renderer.setShowText((Boolean) evt.getNewValue()); + processDataBinding("button.text"); + return; + } + if (POPUP_VISIBLE_PROPERTY.equals(name)) { + Boolean newValue = (Boolean) evt.getNewValue(); + if (newValue == null || !newValue) { + if (getPopup() != null && getPopup().isVisible()) { + getPopup().setVisible(false); + } + return; + } + if (!getPopup().isVisible()) { + SwingUtilities.invokeLater(showPopupRunnable); + } + return; + } + if (SELECTED_LOCALE_PROPERTY.equals(name)) { + Locale newLocale = (Locale) evt.getNewValue(); + // mise a jour de la popup + try { + for (Component c : popup.getComponents()) { + if (c instanceof JRadioButtonMenuItem) { + JRadioButtonMenuItem b = (JRadioButtonMenuItem) c; + Locale l = (Locale) b.getClientProperty("locale"); + b.setSelected(newLocale.equals(l)); + } + } + } finally { + popup.invalidate(); + } + return; + } +} + +@Override +public void actionPerformed(ActionEvent event) { + Locale value = (Locale) ((JComponent)event.getSource()).getClientProperty("locale"); + if (log.isDebugEnabled()) { + log.debug("new locale : " + value); + } + setSelectedLocale(value); +} + +public void loadI18nBundles() { + Locale[] locales = org.nuiton.i18n.I18n.getLoader().getLocales(); + setLocales(java.util.Arrays.asList(org.nuiton.i18n.I18n.getLoader().getLocales())); +} + +protected String getTip(Locale l) { + boolean selected = l.equals(selectedLocale); + String tip = selected ? getSelectedTip(l):getNotSelectedTip(l); + return tip; +} + +protected String getSelectedTip(Locale l) { + String selectedTip = getSelectedToolTipText(); + if (selectedTip == null) { + // use default selected tip text + selectedTip = DEFAULT_SELECTED_TOOLTIP; + } + String tip = renderer.getToolTipText(l); + tip = _(selectedTip, tip); + return tip; +} + +protected String getNotSelectedTip(Locale l) { + String selectedTip = getNotSelectedToolTipText(); + if (selectedTip == null) { + // use default not selected tip text + selectedTip = DEFAULT_NOT_SELECTED_TOOLTIP; + } + String tip = renderer.getToolTipText(l); + tip = _(selectedTip, tip); + return tip; +} + +protected Runnable showPopupRunnable = new Runnable() { + @Override + public void run() { + getPopup().pack(); + Dimension dim = getPopup().getPreferredSize(); + JToggleButton invoker = getButton(); + getPopup().show(invoker, (int) (invoker.getPreferredSize().getWidth() - dim.getWidth()), invoker.getHeight()); +// getPopup().setVisible(true); + } +}; + +addPropertyChangeListener(this); + +]]> + </script> +</JPanel> diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/NumberEditor.jaxx b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/NumberEditor.jaxx new file mode 100644 index 0000000..9d08d46 --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/NumberEditor.jaxx @@ -0,0 +1,167 @@ +<!-- + +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ + +--> + +<JPanel layout='{new BorderLayout()}' + onFocusGained='textField.requestFocus()' + onFocusLost='setPopupVisible(false);popup.setVisible(false);' + onMouseExited='setPopupVisible(false);popup.setVisible(false);'> + + <!-- onFocusGained='if (autoPopup) setPopupVisible(true); textField.requestFocus();'--> + + <!-- bean property associated with the editing value --> + <String id='property' javaBean='""'/> + + <!-- bean property --> + <Object id='bean' javaBean='null'/> + + <!-- editor model --> + <Number id="model" javaBean='null'/> + + <!-- useFloat property --> + <Boolean id='useFloat' javaBean='false'/> + + <!-- useSign property --> + <Boolean id='useSign' javaBean='false'/> + + <!-- autoPopup property --> + <Boolean id='autoPopup' javaBean='false'/> + + <!-- showPopupButton property --> + <Boolean id='showPopupButton' javaBean='false'/> + + <!-- show reset property --> + <Boolean id='showReset' javaBean='false'/> + + <!-- internal editor model as text --> + <String id="modelText" javaBean='""'/> + + <!-- internal state --> + <Boolean id='popupVisible' javaBean='false'/> + + <!-- ui handler --> + <NumberEditorHandler id='handler' constructorParams='this'/> + + <!-- popup digital number editor --> + <JPopupMenu id='popup' + onPopupMenuWillBecomeVisible='button.setSelected(true)' + onPopupMenuWillBecomeInvisible='button.setSelected(false)' + onPopupMenuCanceled='button.setSelected(false)'> + <style source='NumberEditorPopup.css'/> + <JPanel layout='{new GridLayout(4,4)}' + border='{BorderFactory.createEmptyBorder(4, 4, 4, 4)}' + background='{Color.WHITE}'> + <JButton text='numbereditor.7' onActionPerformed='addChar(event)' styleClass='digit'/> + <JButton text='numbereditor.8' onActionPerformed='addChar(event)' styleClass='digit'/> + <JButton text='numbereditor.9' onActionPerformed='addChar(event)' styleClass='digit'/> + <JButton text='numbereditor.clearAll' onActionPerformed='setModel(null)' styleClass='clear' + enabled='{!getModelText().isEmpty()}'/> + + + <JButton text='numbereditor.4' onActionPerformed='addChar(event)' styleClass='digit'/> + <JButton text='numbereditor.5' onActionPerformed='addChar(event)' styleClass='digit'/> + <JButton text='numbereditor.6' onActionPerformed='addChar(event)' styleClass='digit'/> + <JButton text='numbereditor.clearOne' onActionPerformed='getHandler().removeChar()' styleClass='clear' + enabled='{!(getModelText().isEmpty() || textField.getCaretPosition() ==0 )}'/> + + <JButton text='numbereditor.1' onActionPerformed='addChar(event)' styleClass='digit'/> + <JButton text='numbereditor.2' onActionPerformed='addChar(event)' styleClass='digit'/> + <JButton text='numbereditor.3' onActionPerformed='addChar(event)' styleClass='digit'/> + + <JButton enabled="false"/> + + <JButton text='numbereditor.0' onActionPerformed='addChar(event)' styleClass='digit' + enabled='{!getEditor().getModelText().equals("0")}'/> + + <JButton id='toggleSign' text='numbereditor.toggleSign' styleClass='operator' + onActionPerformed='getHandler().toggleSign()' + enabled='{isUseSign() && !getEditor().getModelText().isEmpty()}'/> + + <JButton id='dot' text='numbereditor..' styleClass='operator' + onActionPerformed='addChar(event)' + enabled='{isUseFloat() && getEditor().getModelText().indexOf(".") == -1 }'/> + + <JButton actionIcon='numbereditor-validate' onActionPerformed="getHandler().validate()"/> + </JPanel> + </JPopupMenu> + <script><![CDATA[ +public void init() { + handler.init(); +} + +public NumberEditor getEditor() { + return this; +} + +public void addChar(ActionEvent event) { + getHandler().addChar(((JButton)event.getSource()).getText()); +} + +void showPopup() { + if ( popupVisible || autoPopup ) { + if (!popupVisible) { + setPopupVisible(true); + } else if (!getPopup().isVisible()) { + getHandler().setPopupVisible(true); + } + } +} + +]]> + </script> + + <JToolBar floatable='false' + borderPainted='false' + visible='{isShowReset()}' + constraints='BorderLayout.WEST'> + <JButton id='resetButton' + actionIcon='numbereditor-reset' + toolTipText='numbereditor.action.reset.tip' + focusable='false' + focusPainted='false' + enabled='{isEnabled()}' + onActionPerformed='setModel(null)'/> + </JToolBar> + + <JTextField id='textField' + constraints='BorderLayout.CENTER' + text='{getModelText()}' + enabled='{isEnabled()}' + onKeyReleased='getHandler().setModel(textField.getText())' + onFocusGained='showPopup()'/> + + <JToolBar constraints='BorderLayout.EAST' + floatable='false' + opaque='false' + borderPainted='false' + visible='{isShowPopupButton()}' + maximumSize='{new Dimension(24,24)}'> + <JToggleButton id='button' + focusable='false' + focusPainted='false' + actionIcon='numbereditor-calculator' + toolTipText='numbereditor.action.show.tip' + enabled='{isEnabled()}' + onActionPerformed='getHandler().setPopupVisible(!popup.isVisible())'/> + </JToolBar> + +</JPanel> diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/NumberEditorHandler.java b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/NumberEditorHandler.java new file mode 100644 index 0000000..276c3d2 --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/NumberEditorHandler.java @@ -0,0 +1,468 @@ +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ +package jaxx.runtime.swing.editor; + +import java.awt.Dimension; +import java.lang.reflect.InvocationTargetException; +import javax.swing.JTextField; +import org.apache.commons.beanutils.PropertyUtils; +import org.apache.commons.lang.math.NumberUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.swing.SwingUtilities; +import javax.swing.text.BadLocationException; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; +import javax.swing.JToggleButton; + +/** + * Le handler de l'éditeur graphique de nombres. + * <p/> + * Note: Ce handler n'est pas staless, et chaque ui possède le sien. + * + * @author chemit + * @see NumberEditor + */ +public class NumberEditorHandler { + + public static final Log log = LogFactory.getLog(NumberEditorHandler.class); + public static final String BEAN_PROPERTY = "bean"; + public static final String PROPERTY_PROPERTY = "property"; + public static final String MODEL_PROPERTY = "model"; + public static final String AUTO_POPUP_PROPERTY = "autoPopup"; + public static final String POPUP_VISIBLE_PROPERTY = "popupVisible"; +// public static final String USE_FLOAT_PROPERTY = "useFloat"; + public static final String USE_SIGN_PROPERTY = "useSign"; + public static final String VALIDATE_PROPERTY = "validate"; + /** editor ui */ + protected NumberEditor editor; + /** the mutator method on the property of boxed bean in the editor */ + protected Method mutator; + /** the getter method on the property */ + protected Method getter; + /** a flag to known if mutator accept null value */ + protected Boolean acceptNull; + + public NumberEditorHandler(NumberEditor ui) { + this.editor = ui; + } + + /** initialise l'ui et les listeners d'évènements. */ + public void init() { + try { + if (editor.getBean() == null) { + throw new NullPointerException("can not have a null bean in ui " + editor); + } + editor.addPropertyChangeListener(MODEL_PROPERTY, new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (log.isDebugEnabled()) { + log.debug("set new model " + evt.getNewValue() + " for " + editor.getProperty()); + } + setModel((Number) evt.getOldValue(), (Number) evt.getNewValue()); + } + }); + editor.addPropertyChangeListener(POPUP_VISIBLE_PROPERTY, new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + setPopupVisible((Boolean) evt.getNewValue()); + } + }); + editor.getTextField().addMouseListener(new PopupListener()); + + // Determine si c'est un float + Class<?> type = getGetter().getReturnType(); + //FIXME le test n'est pas assez fort (on peut avoir un long, short,...) + editor.setUseFloat(!type.equals(Integer.class) && !type.equals(int.class)); + + // Initialise le model + if (editor.getModel() == null){ + Number num = (Number)getGetter().invoke(editor.getBean()); + editor.setModel(num); + } + + /*if (editor.getResetButton().getIcon() == null) { + editor.getResetButton().setIcon(SwingUtil.createActionIcon("numbereditor-reset")); + } + if (editor.getButton().getIcon() == null) { + editor.getButton().setIcon(SwingUtil.createActionIcon("numbereditor-calculator")); + }*/ + } catch (IllegalAccessException ex) { + log.error(ex); + } catch (IllegalArgumentException ex) { + log.error(ex); + } catch (InvocationTargetException ex) { + log.error(ex); + } + } + + /** + * Affiche ou cache la popup. + * + * @param newValue la nouvelle valeur de visibilité de la popup. + */ + public void setPopupVisible(Boolean newValue) { + + if (log.isTraceEnabled()) { + log.trace(newValue); + } + + if (newValue == null || !newValue) { + editor.getPopup().setVisible(false); + return; + } + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + JToggleButton invoker = editor.getButton(); + Dimension dim = editor.getPopup().getPreferredSize(); + editor.getPopup().show(invoker, (int) (invoker.getPreferredSize().getWidth() - dim.getWidth()), invoker.getHeight()); + editor.getTextField().requestFocus(); + } + }); + } + + /** + * Modifie le modèle de la donnée à éditer à partir d'un evenement clavier + * + * TODO utiliser une filtre sur les donnes en entrees pour ne pas a avoir + * faire les tests ici. + * + * @param s la nouvelle valeur du modèle + */ + public void setModel(String s) { + + String text = editor.getModelText(); + if (text.equals(s)) { + // le modeèle n'a pas changé, rien a faire sur le modèle + if (log.isDebugEnabled()) { + log.debug("modelText is the same, skip !"); + } + return; + } + + boolean canApply = false; + + boolean endWithDot = false; + + boolean isLess = false; + + Number newValue = null; + + if (s.trim().isEmpty()) { + // le champ est vide donc c'est la valeur null a reaffecter + s = null; + canApply = true; + } else if (s.endsWith(".")) { + s += "0"; + endWithDot = true; + } else if (editor.isUseSign() && s.length() == 1 && s.startsWith("-")) { + s = "0"; + isLess = true; + } + + if (s != null && NumberUtils.isNumber(s)) { + + // on a un nombre valide + + try { + Float f = Float.parseFloat(s); + if (!editor.isUseSign() && (s.startsWith("-"))) { + if (log.isDebugEnabled()) { + log.debug("will skip since can not allow sign on this editor but was " + f); + } + } else { + + if (!editor.isUseFloat() && s.contains(".")) { + if (log.isDebugEnabled()) { + log.debug("will skip since can not allow float on this editor but was " + f); + } + } else { + // ok on peut utilise ce modele + if (editor.isUseFloat()) { + newValue = f; + } else { + newValue = f.intValue(); + } + canApply = true; + } + } + + } catch (NumberFormatException e) { + // rien a faire + log.debug(e); + } + } + JTextField field = editor.getTextField(); + + int oldPosition = field.getCaretPosition(); + + if (canApply) { + if (log.isDebugEnabled()) { + log.debug("can apply new model value : " + newValue); + } + if (isLess){ + editor.setModelText("-"); + return; + } + // on peut mettre a jour le model + editor.setModel(newValue); + if (endWithDot) { + editor.setModelText(s.substring(0, s.length() - 1)); + field.setCaretPosition(oldPosition); + } + return; + } + + // on ne peut pas appliquer, on repositionne l'ancien texte + // dans l'éditeur + + if (log.isDebugEnabled()) { + log.debug("invalid text " + s + " reput old text " + text); + } + + if (oldPosition > 0) { + oldPosition--; + } + field.setText(text); + try { + field.setCaretPosition(oldPosition); + } + catch(IllegalArgumentException ex){ + log.debug("CaretPosition is invalid for position : " + oldPosition, ex); + } + } + + /** + * Ajoute le caractère donné à l'endroit où est le curseur dans la zone de + * saisie et met à jour le modèle. + * + * @param s le caractère à ajouter. + */ + public void addChar(String s) { + char c = s.charAt(0); + try { + editor.getTextField().getDocument().insertString(editor.getTextField().getCaretPosition(), c + "", null); + setModel(editor.getTextField().getText()); + //setModel(editor.getModelText() + c); + + } catch (BadLocationException e) { + log.warn(e); + } + } + + /** + * Supprime le caractère juste avant le curseur du modèle (textuel) et + * met à jour la zone de saisie. + */ + public void removeChar() { + String s = editor.getModelText(); + int position = editor.getTextField().getCaretPosition(); + if (position < 1 || s.isEmpty()) { + if (log.isDebugEnabled()) { + log.debug("cannot remove when caret on first position or text empty"); + } + // on est au debut du doc, donc rien a faire + return; + } + try { + editor.getTextField().getDocument().remove(position - 1, 1); + } catch (BadLocationException ex) { + // ne devrait jamais arrive vu qu'on a fait le controle... + log.debug(ex); + return; + } + String newText = editor.getTextField().getText(); + if (log.isDebugEnabled()) { + log.debug("text updated : " + newText); + } + position--; + editor.getTextField().setCaretPosition(position); + setModel(newText); + } + + /** + * Permute le signe dans la zone de saisie et + * dans le modèle. + */ + public void toggleSign() { + String newValue = editor.getModelText(); + + if (newValue.startsWith("-")) { + setModel(newValue.substring(1)); + } else { + setModel("-" + newValue); + } + } + + /** @return l'éditeur au quel est rattaché le handler. */ + public NumberEditor getEditor() { + return editor; + } + + protected void setModel(Number oldValue, Number newValue) { + if (editor.getBean() == null) { + return; + } + + if (log.isDebugEnabled()) { + log.debug(editor.getProperty() + " on " + editor.getBean().getClass() + " :: " + oldValue + " to " + newValue); + } + + try { + if (newValue == null && !getAcceptNull()) { + // valeur nulle sur une propriete primitive + // on ne peut pas utiliser la valeur null, mais 0 à la place + if (editor.isUseFloat()) { + getMutator().invoke(editor.getBean(), 0.0f); + } else { + getMutator().invoke(editor.getBean(), 0); + } + + } else { + getMutator().invoke(editor.getBean(), newValue); + } + String strValue; + if (newValue == null) { + strValue = ""; + } else { + strValue = newValue + ""; + if (editor.isUseFloat()) { + Float n = Float.parseFloat(strValue); + if (((float) n.intValue()) == n) { + strValue = n.intValue() + ""; + } + } + } + + editor.setModelText(strValue); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + protected void validate() { + + setPopupVisible(false); + // fire validate property (to be able to notify listeners) + editor.firePropertyChange(VALIDATE_PROPERTY, null, true); + } + + protected class PopupListener extends MouseAdapter { + + @Override + public void mousePressed(MouseEvent e) { + maybeShowPopup(e); + } + + @Override + public void mouseReleased(MouseEvent e) { + maybeShowPopup(e); + } + + protected void maybeShowPopup(MouseEvent e) { + if (!e.isPopupTrigger()) { + return; + } + if (editor.isAutoPopup()) { + if (editor.isPopupVisible()) { + if (!editor.getPopup().isVisible()) { + setPopupVisible(true); + } + // popup already visible + + } else { + // set popup auto + editor.setPopupVisible(true); + + } + } else { + if (editor.isPopupVisible()) { + setPopupVisible(true); + } + } + } + } + + protected Method getMutator() { + if (mutator == null) { + Object bean = editor.getBean(); + if (bean == null) { + throw new NullPointerException("could not find bean in " + editor); + } + String property = editor.getProperty(); + if (property == null) { + throw new NullPointerException("could not find property in " + editor); + } + + try { + PropertyDescriptor descriptor = PropertyUtils.getPropertyDescriptor(bean, property); + mutator = descriptor.getWriteMethod(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + return mutator; + } + + protected Method getGetter() { + if (getter == null) { + Object bean = editor.getBean(); + if (bean == null) { + throw new NullPointerException("could not find bean in " + editor); + } + String property = editor.getProperty(); + if (property == null) { + throw new NullPointerException("could not find property in " + editor); + } + + try { + PropertyDescriptor descriptor = PropertyUtils.getPropertyDescriptor(bean, property); + getter = descriptor.getReadMethod(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + return getter; + } + + public Boolean getAcceptNull() { + if (acceptNull == null) { + Method m = getMutator(); + if (m == null) { + // should never happens + throw new IllegalStateException("could not find the mutator"); + } + Class<?> returnType = m.getParameterTypes()[0]; + acceptNull = !returnType.isPrimitive(); + if (log.isDebugEnabled()) { + log.debug(acceptNull + " for mutator " + m.getName() + " type : " + returnType); + } + } + return acceptNull; + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/NumberEditorPopup.css b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/NumberEditorPopup.css new file mode 100644 index 0000000..ad4e3bb --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/NumberEditorPopup.css @@ -0,0 +1,43 @@ +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ +JButton { + font-size: 14; + focusPainted: false; + focusable: false; +} + +JButton.digit { + foreground: blue; +} + +JButton.operator { + foreground: #009900; +} + +JButton.clear { + foreground: red; +} + +JButton:mouseover { + font-weight: bold; +} + +JButton.operator:mouseover { + font-weight: normal; +} diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/TimeEditor.css b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/TimeEditor.css new file mode 100644 index 0000000..cf596d5 --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/TimeEditor.css @@ -0,0 +1,49 @@ +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ +#title{ + text:{getLabel()}; + horizontalAlignment:center; +} + +#hour{ + value:{getTimeModel()/60}; + enabled:{isEnabled()}; + model:{new SpinnerNumberModel(0,0,23,1)}; +} + +#labelH { + text:"timeeditor.H"; + horizontalAlignment:center; +} +#minute{ + value:{getTimeModel()%60}; + enabled:{isEnabled()}; + model:{new SpinnerNumberModel(0,0,59,1)}; +} + +#slider{ + font-size: 11; + paintTicks:true; + paintLabels:true; + majorTickSpacing:60; + minorTickSpacing:30; + value:{getTimeModel()}; + enabled:{isEnabled()}; + model:{new DefaultBoundedRangeModel(0,1,0,60*24)}; +} diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/TimeEditor.jaxx b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/TimeEditor.jaxx new file mode 100644 index 0000000..547fa34 --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/TimeEditor.jaxx @@ -0,0 +1,78 @@ +<!-- + +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ + +--> + +<JPanel layout='{new BorderLayout()}'> + + <style source='TimeEditor.css'/> + + <!-- bean property --> + <String id='property' javaBean='""'/> + + <!-- title --> + <String id='label' javaBean='""'/> + + <!-- bean --> + <Object id='bean' javaBean='null'/> + + <!-- time model --> + <Integer id="timeModel" javaBean='0'/> + + <!-- the real date --> + <java.util.Date id="date" javaBean='null'/> + + <!-- ui handler --> + <TimeEditorHandler id='handler' constructorParams='this'/> + + <script><![CDATA[ +public void init() { + handler.init(); +} +]]> + </script> + + <Table constraints='BorderLayout.NORTH' fill='horizontal' insets='0'> + <row> + <cell> + <JLabel id='title'/> + </cell> + <cell weightx='1'> + <JLabel/> + </cell> + <cell> + <JSpinner id='hour' + onStateChanged='setTimeModel((Integer)hour.getValue()* 60 + timeModel % 60)'/> + </cell> + <cell> + <JLabel id='labelH'/> + </cell> + <cell> + <JSpinner id='minute' + onStateChanged='setTimeModel((timeModel / 60) * 60 + (Integer) minute.getValue())'/> + </cell> + </row> + </Table> + + <JSlider id='slider' constraints='BorderLayout.SOUTH' + onStateChanged='if (!slider.getValueIsAdjusting()) setTimeModel(slider.getValue());'/> + +</JPanel> diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/TimeEditorHandler.java b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/TimeEditorHandler.java new file mode 100644 index 0000000..48f00f5 --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/TimeEditorHandler.java @@ -0,0 +1,222 @@ +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ +package jaxx.runtime.swing.editor; + +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import org.apache.commons.beanutils.PropertyUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.swing.JLabel; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; +import java.util.Calendar; +import java.util.Date; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.Map; +import javax.swing.JSlider; +import javax.swing.plaf.basic.BasicSliderUI; + +/** @author chemit */ +public class TimeEditorHandler { + + public static final Log log = LogFactory.getLog(TimeEditorHandler.class); + public static final String BEAN_PROPERTY = "bean"; + public static final String PROPERTY_PROPERTY = "property"; + public static final String DATE_PROPERTY = "date"; + public static final String TIME_MODEL_PROPERTY = "timeModel"; + /** editor ui */ + protected TimeEditor editor; + /** the mutator method on the property of boxed bean in the editor */ + protected Method mutator; + protected Calendar calendar; + + public TimeEditorHandler(TimeEditor ui) { + this.editor = ui; + this.calendar = Calendar.getInstance(); + } + + public void init() { + + if (editor.getBean() == null) { + throw new NullPointerException("can not have a null bean in ui " + editor); + } + + // create slider labels + Map<Integer, JLabel> labelTable = new Hashtable<Integer, JLabel>(); + for (int i = 0; i < 25; i += 2) { + labelTable.put(i * 60, new JLabel(i + "")); + } + JSlider slider = editor.getSlider(); + slider.setLabelTable((Dictionary<?,?>) labelTable); + + MouseAdapter m = new MouseAdapter() { + + @Override + public void mouseClicked(MouseEvent e) { + // set the value + int value = getSliderValue(e); + JSlider slider = (JSlider) e.getComponent(); + slider.setValueIsAdjusting(true); + slider.setValue(value); + slider.setValueIsAdjusting(false); + showToolTip(e); + e.consume(); + } + + @Override + public void mouseDragged(MouseEvent e) { + showToolTip(e); + } + + @Override + public void mouseEntered(MouseEvent e) { + showToolTip(e); + } + + @Override + public void mouseMoved(MouseEvent e) { + showToolTip(e); + } + + @Override + public void mouseReleased(MouseEvent e) { + showToolTip(e); + } + + int getSliderValue(MouseEvent e) { + JSlider slider = (JSlider) e.getSource(); + int value = -1; + if (slider.getUI() instanceof BasicSliderUI) { + BasicSliderUI ui = (BasicSliderUI) slider.getUI(); + value = slider.getOrientation() == JSlider.HORIZONTAL + ? ui.valueForXPosition(e.getX()) + : ui.valueForYPosition(e.getY()); + } + return value; + } + + void showToolTip(MouseEvent e) { + + int value = getSliderValue(e); + if (value == -1) { + return; + } + int h = value / 60; + int m = value % 60; + + String text = ""; + if (h < 10) { + text = "0"; + } + text += h + " : "; + if (m < 10) { + text += "0"; + } + text += m; + + JSlider slider = (JSlider) e.getSource(); + slider.setToolTipText(text); + + } + }; + slider.addMouseListener(m); + slider.addMouseMotionListener(m); + + // listen when date changes (should come from outside) + editor.addPropertyChangeListener(DATE_PROPERTY, new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + Date date = (Date) evt.getNewValue(); + + if (date == null) { + return; + } + calendar.setTime(date); + int hours = calendar.get(Calendar.HOUR_OF_DAY); + int minutes = calendar.get(Calendar.MINUTE); + if (log.isDebugEnabled()) { + log.debug("date changed : new value " + hours + ":" + minutes); + } + getEditor().setTimeModel((hours * 60) + minutes); + } + }); + + // listen when time model changes (should come from editor) + editor.addPropertyChangeListener(TIME_MODEL_PROPERTY, new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + Integer time = (Integer) evt.getNewValue(); + int hours = time / 60; + int minutes = time % 60; + calendar.set(Calendar.HOUR_OF_DAY, hours); + calendar.set(Calendar.MINUTE, minutes); + setDate(null, calendar.getTime()); + } + }); + } + + public TimeEditor getEditor() { + return editor; + } + + protected void setDate(Date oldValue, Date newValue) { + if (editor.getBean() == null) { + return; + } + + if (log.isDebugEnabled()) { + log.debug(editor.getProperty() + " on " + editor.getBean().getClass() + " :: " + oldValue + " to " + newValue); + } + + try { + getMutator().invoke(editor.getBean(), newValue); + + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + protected Method getMutator() { + if (mutator == null) { + Object bean = editor.getBean(); + if (bean == null) { + throw new NullPointerException("could not find bean in " + editor); + } + String property = editor.getProperty(); + if (property == null) { + throw new NullPointerException("could not find property in " + editor); + } + + try { + PropertyDescriptor descriptor = PropertyUtils.getPropertyDescriptor(bean, property); + mutator = descriptor.getWriteMethod(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + return mutator; + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigCategoryUI.css b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigCategoryUI.css new file mode 100644 index 0000000..a4206f0 --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigCategoryUI.css @@ -0,0 +1,60 @@ +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* +*/ + +#categoryLabelPanel { + background:{Color.WHITE}; +} + +#descriptionPane { + columnHeaderView:{new JLabel(_("config.descrition"), jaxx.runtime.Util.getUIManagerActionIcon("information"), 10)}; +} + +#description { + rows:3; + editable:false; + focusable:false; + font-size:10; + text:{_("config.no.option.selected")}; +} + +#tablePane { + columnHeaderView:{table.getTableHeader()}; + verticalScrollBarPolicy:{ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS}; +horizontalScrollBarPolicy:{ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER}; +} + +#table { + rowSelectionAllowed:false; + autoCreateRowSorter:true; + autoResizeMode:{JTable.AUTO_RESIZE_ALL_COLUMNS}; +} + +#reset{ + text:"config.action.reset"; + toolTipText:"config.action.reset.tip"; + actionIcon:"config-reset"; + enabled:{getCategoryModel().isModified()}; +} + +#save{ + text:"config.action.save"; + toolTipText:"config.action.save.tip"; + actionIcon:"config-save"; + enabled:{getCategoryModel().isModified() && getCategoryModel().isValid()}; +} diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigCategoryUI.jaxx b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigCategoryUI.jaxx new file mode 100644 index 0000000..d4e1c6b --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigCategoryUI.jaxx @@ -0,0 +1,120 @@ +<!-- + +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ + +--> + +<JPanel layout='{new BorderLayout()}'> + + <style source='ConfigCategoryUI.css'/> + + <script><![CDATA[ +import jaxx.runtime.SwingUtil; +import jaxx.runtime.swing.editor.config.model.*; +import jaxx.runtime.swing.editor.ColumnSelector; +import static org.nuiton.i18n.I18n.n_; + +void $afterCompleteSetup() { + // prepare table + SwingUtil.setI18nTableHeaderRenderer(table, + n_("config.key"), + n_("config.key.tip"), + n_("config.value"), + n_("config.value.tip"), + n_("config.defaultValue"), + n_("config.defaultValue.tip")); + + ConfigTableRenderer renderer = new ConfigTableRenderer(); + SwingUtil.setTableColumnRenderer(table, 0, renderer); + SwingUtil.setTableColumnRenderer(table, 1, renderer); + SwingUtil.setTableColumnRenderer(table, 2, renderer); + Font f = table.getFont().deriveFont(Font.ITALIC | Font.BOLD); + int width = SwingUtil.computeTableColumnWidth(table, f, 0, "___*"); + SwingUtil.fixTableColumnWidth(table, 0, width); + SwingUtil.setTableColumnEditor(table, 1, new ConfigTableEditor((ConfigTableModel) table.getModel())); + //TODO to be continued... + //columnSelector.setMyTable(table); + //tablePane.setCorner(ScrollPaneConstants.UPPER_RIGHT_CORNER, columnSelector); +} + +protected void updateDescriptionText() { + OptionModel option; + if (selectionModel.isSelectionEmpty()) { + option = null; + } else { + int row = selectionModel.getAnchorSelectionIndex(); + ConfigTableModel m = (ConfigTableModel) table.getModel(); + option = m.getEntry(row); + if (log.isDebugEnabled()) { + log.debug(row + " : " + option); + } + } + StringBuilder buffer = new StringBuilder(); + if (option == null) { + buffer.append(_("config.no.option.selected")); + } else { + buffer.append(_("config.option.label", option.getKey(), _(option.getDescription()))).append('\n'); + if (option.isModified()) { + buffer.append(_("config.option.modified", option.getOriginalValue(), option.getValue())).append('\n'); + } + if (option.isFinal()) { + buffer.append(_("config.option.final")).append('\n'); + } + } + description.setText(buffer.toString()); +} +]]> + </script> + + <CategoryModel id='categoryModel' javaBean='getContextValue(CategoryModel.class)'/> + + <ConfigTableModel id='tableModel' constructorParams='categoryModel' + onTableChanged='updateDescriptionText()'/> + + <ListSelectionModel id='selectionModel' javaBean='new DefaultListSelectionModel()' + onValueChanged='if (!event.getValueIsAdjusting()) { updateDescriptionText(); }'/> + + <!--<ColumnSelector id='columnSelector' />--> + + <!-- categorie label --> + <JPanel id="categoryLabelPanel" constraints='BorderLayout.NORTH'> + <JLabel id='categoryLabel'/> + </JPanel> + + <!-- table of options --> + <JScrollPane id='tablePane' constraints='BorderLayout.CENTER'> + <JTable id="table" constructorParams='tableModel' + selectionModel='{selectionModel}'/> + </JScrollPane> + + <JPanel layout='{new BorderLayout()}' constraints='BorderLayout.SOUTH'> + + <!-- description of selected option in table --> + <JScrollPane id="descriptionPane" constraints='BorderLayout.CENTER'> + <JTextArea id='description'/> + </JScrollPane> + + <!-- actions of the category --> + <JPanel layout='{new GridLayout(1,0)}' constraints='BorderLayout.SOUTH'> + <JButton id='reset' onActionPerformed='getContextValue(ConfigUIModel.class).reset()'/> + <JButton id='save' onActionPerformed='getContextValue(ConfigUIModel.class).saveModified()'/> + </JPanel> + </JPanel> +</JPanel> diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigTableEditor.java b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigTableEditor.java new file mode 100644 index 0000000..609440b --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigTableEditor.java @@ -0,0 +1,125 @@ +/* +* *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ +package jaxx.runtime.swing.editor.config; + +import jaxx.runtime.swing.editor.config.model.ConfigTableModel; +import javax.swing.DefaultCellEditor; +import javax.swing.JTable; +import javax.swing.event.CellEditorListener; +import javax.swing.table.TableCellEditor; +import java.awt.Component; +import java.util.EventObject; +import java.util.Locale; +import jaxx.runtime.swing.editor.ClassCellEditor; +import jaxx.runtime.swing.editor.EnumEditor; +import jaxx.runtime.swing.editor.LocaleEditor; + +/** + * L'éditeur des valeurs des propriétés d'une configuration + * + * @author chemit + */ +public class ConfigTableEditor implements TableCellEditor { + + protected TableCellEditor delegate; + protected ConfigTableModel model; + + public ConfigTableEditor(ConfigTableModel model) { + this.model = model; + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + delegate = findDelegate(table, model.getEntry(row).getType()); + return delegate.getTableCellEditorComponent(table, value, isSelected, row, column); + } + + @Override + public Object getCellEditorValue() { + return !hasDelegate() ? null : delegate.getCellEditorValue(); + } + + @Override + public boolean isCellEditable(EventObject anEvent) { + return !hasDelegate() || delegate.isCellEditable(anEvent); + } + + @Override + public boolean shouldSelectCell(EventObject anEvent) { + return hasDelegate() && delegate.shouldSelectCell(anEvent); + } + + @Override + public boolean stopCellEditing() { + return !hasDelegate() || delegate.stopCellEditing(); + } + + @Override + public void cancelCellEditing() { + if (hasDelegate()) { + delegate.cancelCellEditing(); + } + } + + @Override + public void addCellEditorListener(CellEditorListener l) { + if (hasDelegate()) { + delegate.addCellEditorListener(l); + } + } + + @Override + public void removeCellEditorListener(CellEditorListener l) { + if (hasDelegate()) { + delegate.removeCellEditorListener(l); + } + } + + protected TableCellEditor findDelegate(JTable table, Class<?> type) { + TableCellEditor editor = table.getDefaultEditor(type); + TableCellEditor defaultEditor = table.getDefaultEditor(Object.class); + if (editor == defaultEditor) { + // find not a specialized editor for the type + if (type.isEnum()) { + // add a EnumEditor to table + editor = new DefaultCellEditor(EnumEditor.newEditor((Class<Enum>) type)); + table.setDefaultEditor(type, editor); + } else if (type == Class.class) { + editor = new ClassCellEditor(); + table.setDefaultEditor(type, editor); + } //else if (type == File.class){ + // TODO a FileEditor + // table.setDefaultEditor(type, delegate); + //} + else if (type.equals(Locale.class)) { + editor = new DefaultCellEditor(LocaleEditor.newEditor()); + table.setDefaultEditor(Locale.class, editor); + } else { + editor = table.getDefaultEditor(String.class); + } + } + if (editor == null) { + throw new IllegalStateException("could not find a editor for type +" + type); + } + return editor; + } + + protected boolean hasDelegate() { + return delegate != null; + } +} diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigTableRenderer.java b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigTableRenderer.java new file mode 100644 index 0000000..d0dd247 --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigTableRenderer.java @@ -0,0 +1,112 @@ +/* + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ +package jaxx.runtime.swing.editor.config; + +import static org.nuiton.i18n.I18n._; + +import javax.swing.JComponent; +import javax.swing.JTable; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableCellRenderer; +import java.awt.Color; +import java.awt.Component; +import java.awt.Font; +import jaxx.runtime.swing.editor.config.model.ConfigTableModel; +import jaxx.runtime.swing.editor.config.model.OptionModel; + +/** + * Pour le rendu du tableau des options d'une categorie + * + * @author chemit + * @see ConfigTableModel + */ +public class ConfigTableRenderer extends DefaultTableCellRenderer { + + private static final long serialVersionUID = 1L; + protected static Color col; + protected static Font font; + protected static Font font2; + + public ConfigTableRenderer() { + col = getForeground(); + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + int modelRow = table.convertRowIndexToModel(row); + int modelColumn = table.convertColumnIndexToModel(column); + ConfigTableModel model = (ConfigTableModel) table.getModel(); + OptionModel key = model.getEntry(modelRow); + boolean isModified = key.isModified(); + + boolean isValid = key.isValid(); + + if (font == null) { + font = getFont(); + font2 = font.deriveFont(Font.ITALIC | Font.BOLD); + } + Component cellRenderer = null; + switch (modelColumn) { + case 0: + cellRenderer = getKeyCellRenderer(table, value, isSelected, hasFocus, modelRow, modelColumn, key, isValid, isModified); + break; + case 1: + cellRenderer = getValueCellRenderer(table, value, isSelected, hasFocus, modelRow, modelColumn, key, isValid, isModified); + break; + case 2: + cellRenderer = getValueCellRenderer(table, value, isSelected, hasFocus, modelRow, modelColumn, key, isValid, isModified); + break; + default: + throw new IllegalStateException("no renderer find for column " + modelColumn); + } + return cellRenderer; + } + + protected Component getKeyCellRenderer(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column, OptionModel key, boolean isValid, boolean isModified) { + String tooltip = _(key.getDescription()); + Object originalValue = key.getOriginalValue(); + boolean isFinal = key.isFinal(); + if (isFinal) { + tooltip += " [" + _("config.unmodifiable") + ']'; + } + if (isModified) { + String s = _("config.modified", originalValue); + value = value + " *"; + tooltip += " [" + s + ']'; + } + if (!isValid) { + String s2 = _("config.unvalid", originalValue, key.getType()); + tooltip += " (" + s2 + ")"; + value = value + " !"; + } + JComponent result = (JComponent) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + result.setToolTipText(tooltip); + result.setForeground(isValid ? col : Color.RED); + result.setFont(isModified || !isValid ? font2 : font); + result.setEnabled(!isFinal); + return result; + } + + protected Component getValueCellRenderer(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column, OptionModel key, boolean isValid, boolean isModified) { + TableCellRenderer defaultRenderer = table.getDefaultRenderer(key.getType()); + + Component result; + result = defaultRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + return result; + } +} diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigUI.css b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigUI.css new file mode 100644 index 0000000..87a0f5d --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigUI.css @@ -0,0 +1,27 @@ +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* +*/ +#quit{ + text:"config.action.quit"; + toolTipText:"config.action.quit.tip"; + actionIcon:"config-quit"; +} + +#categories{ + tabPlacement:{JTabbedPane.LEFT}; +} diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigUI.jaxx b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigUI.jaxx new file mode 100644 index 0000000..92f2921 --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigUI.jaxx @@ -0,0 +1,72 @@ +<!-- + +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ + +--> + +<JPanel layout='{new BorderLayout()}'> + + <style source='ConfigUI.css'/> + + <script><![CDATA[ + import jaxx.runtime.swing.editor.config.model.ConfigUIModel; + + categories.setModel(new DefaultSingleSelectionModel() { + + private static final long serialVersionUID = 1L; + + @Override + public void setSelectedIndex(int index) { + // check if catgeory can be quit + boolean canContinue = !isSelected() || ConfigUIBuilder.canQuitCategory(ConfigUI.this); + if (canContinue) { + if (log.isDebugEnabled()) { + log.debug("new index : " + index); + } + // was authorized to continue + super.setSelectedIndex(index); + } + } + }); + + protected void changeCategory(ChangeEvent e) { + JPanel p = (JPanel) getCategories().getSelectedComponent(); + if (p == null) { + // pas de selection + return; + } + getModel().setCategory(p.getName()); + getCategories().invalidate(); + } + ]]> + </script> + + <!-- le modele de l'ui --> + <ConfigUIModel id='model' javaBean='getContextValue(ConfigUIModel.class)'/> + + <!-- les differentes categories de la configuration --> + <JTabbedPane id='categories' constraints='BorderLayout.CENTER' + onStateChanged='changeCategory(event)' /> + + <!-- pour quitter l'ui --> + <JPanel layout='{new GridLayout(1,0)}' constraints='BorderLayout.SOUTH'> + <JButton id='quit'/> + </JPanel> +</JPanel> diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigUIBuilder.java b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigUIBuilder.java new file mode 100644 index 0000000..043356b --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigUIBuilder.java @@ -0,0 +1,246 @@ +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ +package jaxx.runtime.swing.editor.config; + +import java.awt.Frame; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.List; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JOptionPane; +import javax.swing.JRootPane; +import javax.swing.KeyStroke; +import jaxx.runtime.JAXXContext; +import jaxx.runtime.JAXXInitialContext; +import jaxx.runtime.SwingUtil; + +import jaxx.runtime.swing.editor.config.model.CategoryModel; +import jaxx.runtime.swing.editor.config.model.ConfigUIModel; +import jaxx.runtime.swing.editor.config.model.OptionModel; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import static org.nuiton.i18n.I18n._; + +/** + * La classe pour construire l'ui + * @author chemit + */ +public class ConfigUIBuilder { + + public static final Log log = LogFactory.getLog(ConfigUIBuilder.class); + + /** + * Construire l'ui de configuration (sous forme de panel) + * + * @param parentContext le context applicatif + * @param model le modele de l'ui de configuration + * @param defaultCategory la categorie a selectionner + * @return l'ui instanciate + */ + public static ConfigUI newConfigUI(jaxx.runtime.JAXXContext parentContext, final ConfigUIModel model, String defaultCategory) { + JAXXContext tx = new JAXXInitialContext().add(parentContext).add(model); + + final ConfigUI ui = new ConfigUI(tx); + JButton quitButton = ui.getQuit(); + + // prepare quit action + Action quitAction = new AbstractAction(quitButton.getText(), quitButton.getIcon()) { + + private static final long serialVersionUID = 1L; + + @Override + public void actionPerformed(ActionEvent e) { + if (!canQuitCategory(ui)) { + return; + } + + if (model.isSaved() && !model.isStandalone()) { + StringBuilder buffer = new StringBuilder(); + // on doit verifier si des options sauvees necessite + // un redemarrage de l'application + for (CategoryModel cat : model) { + List<OptionModel> savedOptions = cat.getSavedOptions(); + if (!savedOptions.isEmpty()) { + buffer.append("\n").append(_("config.category.saved", _(cat.getCategory()))).append("\n"); + for (OptionModel option : savedOptions) { + buffer.append("\n- ").append(option.getKey()); + } + } + + } +// askUser(ui, +// _("config.title.will.reload.application"), buffer.toString(), +// JOptionPane.INFORMATION_MESSAGE, +// new Object[]{ +// _("config.choice.ok")}, +// 0); + } + ui.getParentContainer(Window.class).dispose(); + } + }; + String tip = quitButton.getToolTipText(); + quitButton.setAction(quitAction); + quitButton.setToolTipText(tip); + + // build categories tabs + for (CategoryModel categoryModel : model) { + String category = categoryModel.getCategory(); + String categoryLabel = _(categoryModel.getCategoryLabel()); + ConfigCategoryUI p = new ConfigCategoryUI(new JAXXInitialContext().add(ui).add(categoryModel)); + p.getCategoryLabel().setText(categoryLabel); + p.setName(category); + ui.getCategories().addTab(_(category), null, p, categoryLabel); + } + + model.setCategory(defaultCategory); + int categoryIndex = model.getCategoryIndex(defaultCategory); + if (log.isDebugEnabled()) { + log.debug("index of default category (" + defaultCategory + ") : " + categoryIndex); + } + ui.getCategories().setSelectedIndex(categoryIndex); + return ui; + } + + /** + * Affiche l'ui de configuration dans un boite de dialogue. + * + * @param configUI l'ui de configuration + * @param ui l'ui parent de la boite de dialogue a afficher (peut etre nulle) + * @param undecorated un drapeau pour savoir si on affiche les decorations de fenetre + */ + public static void showConfigUI(final ConfigUI configUI, Frame ui, boolean undecorated) { + JDialog f = new JDialog(ui, true); + f.setTitle(_("config.title")); + f.add(configUI); + if (ui != null) { + f.setIconImage(ui.getIconImage()); + } + // pour savoir si l'ui est autonome + configUI.getModel().setStandalone(ui == null); + + f.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); + f.addWindowListener(new WindowAdapter() { + + @Override + public void windowClosing(WindowEvent e) { + ActionEvent myEvent = new ActionEvent(e.getSource(), 1, "quit"); + configUI.getQuit().getAction().actionPerformed(myEvent); +// if (canQuitCategory(configUI)) { +// e.getWindow().dispose(); +// } + } + }); + f.setUndecorated(undecorated); + JRootPane rootPane = f.getRootPane(); + rootPane.setDefaultButton(configUI.getQuit()); + rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("ESCAPE"), "quit"); + rootPane.getActionMap().put("quit", configUI.getQuit().getAction()); + f.pack(); + SwingUtil.center(ui, f); + f.setVisible(true); + } + + protected static boolean canQuitCategory(ConfigUI ui) { + boolean canContinue = true; + ConfigUIModel model = ui.getModel(); + CategoryModel categoryModel = model.getCategoryModel(); + String categoryName = _(categoryModel.getCategory()); + if (!categoryModel.isValid()) { + + // the category is not valid + // get all the invalid options + + StringBuilder buffer = new StringBuilder(); + buffer.append(_("config.message.quit.invalid.category", categoryName)).append('\n'); + for (OptionModel m : categoryModel.getInvalidOptions()) { + buffer.append("\n- ").append(m.getKey()); + } + buffer.append('\n'); + int reponse = askUser(ui, + _("config.title.need.confirm"), + buffer.toString(), + JOptionPane.ERROR_MESSAGE, + new Object[]{ + _("config.choice.continue"), + _("config.choice.cancel")}, + 0); + + switch (reponse) { + case JOptionPane.CLOSED_OPTION: + case 1: + canContinue = false; + break; + case 0: + if (categoryModel.isModified()) { + // wil reset category + model.reset(); + } + break; + } + } else if (categoryModel.isModified()) { + + // category was modified, ask user if wants to save + + StringBuilder buffer = new StringBuilder(); + buffer.append(_("config.message.quit.valid.and.modified.category", categoryName)).append('\n'); + for (OptionModel m : categoryModel.getModifiedOptions()) { + buffer.append("\n- ").append(m.getKey()); + } + buffer.append('\n'); + + int reponse = askUser(ui, + _("config.title.need.confirm"), buffer.toString(), + JOptionPane.WARNING_MESSAGE, + new Object[]{ + _("config.choice.save"), + _("config.choice.doNotSave"), + _("config.choice.cancel")}, + 0); + + switch (reponse) { + case JOptionPane.CLOSED_OPTION: + case 2: + canContinue = false; + break; + case 0: + // will save ui + model.saveModified(); + break; + case 1: + // wil reset ui + model.reset(); + break; + } + + } + return canContinue; + } + + public static int askUser(ConfigUI parent, String title, String message, int typeMessage, Object[] options, int defaultOption) { + + int response = JOptionPane.showOptionDialog(parent, message, title, JOptionPane.DEFAULT_OPTION, typeMessage, null, options, options[defaultOption]); + return response; + } +} diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/CategoryModel.java b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/CategoryModel.java new file mode 100644 index 0000000..76919c3 --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/CategoryModel.java @@ -0,0 +1,175 @@ +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ +package jaxx.runtime.swing.editor.config.model; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +/** + * le modele d'une categorie d'options. + * + * Une categorie est un ensemble d'options. + * + * @author tchemit + */ +public class CategoryModel implements Iterable<OptionModel> { + + public static final String RELOAD_PROPERTY_NAME = "reload"; + public static final String MODIFIED_PROPERTY_NAME = "modified"; + public static final String VALID_PROPERTY_NAME = "valid"; + /** category short name (i18n key) */ + protected String category; + /** category long name (i18n key) */ + protected String categoryLabel; + /** options of the category */ + protected List<OptionModel> entries; + /** suport of modification */ + protected PropertyChangeSupport pcs = new PropertyChangeSupport(this); + + public CategoryModel(String category, String categoryLabel, OptionModel[] entries) { + super(); + this.category = category; + this.categoryLabel = categoryLabel; + this.entries = Collections.unmodifiableList(Arrays.asList(entries)); + } + + public String getCategory() { + return category; + } + + public String getCategoryLabel() { + return categoryLabel; + } + + public List<OptionModel> getEntries() { + return entries; + } + + public boolean isModified() { + boolean modified = false; + for (OptionModel m : this) { + if (m.isModified()) { + modified = true; + break; + } + } + return modified; + } + + public boolean isValid() { + boolean valid = true; + for (OptionModel m : this) { + if (!m.isValid()) { + valid = false; + break; + } + } + return valid; + } + + public void setValue(OptionModel key, Object val) { + boolean wasModified = isModified(); + boolean wasValid = isValid(); + key.setValue(val); + boolean modified = isModified(); + boolean valid = isValid(); + if (wasModified != modified) { + // change modified state + firePropertyChange(MODIFIED_PROPERTY_NAME, wasModified, modified); + } + if (wasValid != valid) { + // change valid state + firePropertyChange(VALID_PROPERTY_NAME, wasValid, valid); + } + } + + @Override + public Iterator<OptionModel> iterator() { + return entries.iterator(); + } + + public List<OptionModel> getInvalidOptions() { + + List<OptionModel> result = new ArrayList<OptionModel>(); + for (OptionModel m : this) { + if (!m.isValid()) { + result.add(m); + } + } + return result; + } + + public List<OptionModel> getModifiedOptions() { + + List<OptionModel> result = new ArrayList<OptionModel>(); + for (OptionModel m : this) { + if (m.isModified()) { + result.add(m); + } + } + return result; + } + + public List<OptionModel> getSavedOptions() { + List<OptionModel> result = new ArrayList<OptionModel>(); + for (OptionModel option : this) { + if (option.isSaved()) { + result.add(option); + } + } + return result; + } + + public void firePropertyChange(String propertyName, Object oldValue, Object newValue) { + pcs.firePropertyChange(propertyName, oldValue, newValue); + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + pcs.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + pcs.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.removePropertyChangeListener(propertyName, listener); + } + + public synchronized boolean hasListeners(String propertyName) { + return pcs.hasListeners(propertyName); + } + + public synchronized PropertyChangeListener[] getPropertyChangeListeners(String propertyName) { + return pcs.getPropertyChangeListeners(propertyName); + } + + public synchronized PropertyChangeListener[] getPropertyChangeListeners() { + return pcs.getPropertyChangeListeners(); + } +} diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/ConfigTableModel.java b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/ConfigTableModel.java new file mode 100644 index 0000000..c44a999 --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/ConfigTableModel.java @@ -0,0 +1,134 @@ +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ +package jaxx.runtime.swing.editor.config.model; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import javax.swing.table.AbstractTableModel; +import org.nuiton.util.ConverterUtil; + +/** + * le modele du tableau d'options pour une categorie donnee. + * + * Le modele se base sur le modele d'une categorie d'option. + * + * @author tchemit + * + * @see CategoryModel + */ +public class ConfigTableModel extends AbstractTableModel { + + private static final long serialVersionUID = 1L; + private static final Class<?>[] columnClass = {String.class, Object.class, String.class}; + /** le modele d'une categorie */ + protected final CategoryModel categoryModel; + + public ConfigTableModel(CategoryModel categoryModel) { + this.categoryModel = categoryModel; + // listen of property reload of the category model + // to known when to refresh table + this.categoryModel.addPropertyChangeListener(CategoryModel.RELOAD_PROPERTY_NAME, new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + fireTableDataChanged(); + } + }); + } + + public CategoryModel getCategoryModel() { + return categoryModel; + } + + public OptionModel getEntry(int rowIndex) { + return categoryModel.getEntries().get(rowIndex); + } + + @Override + public int getRowCount() { + return categoryModel.getEntries().size(); + } + + @Override + public int getColumnCount() { + return columnClass.length; + } + + @Override + public Class<?> getColumnClass(int columnIndex) { + return columnClass[columnIndex]; + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return columnIndex == 1 && !getEntry(rowIndex).isFinal(); + } + + @Override + public Object getValueAt(int row, int column) { + OptionModel key = getEntry(row); + Object value = null; + switch (column) { + case 0: + value = key.getKey(); + break; + case 1: + value = key.getValue(); + break; + case 2: + value = key.getDefaultValue(); + if (value != null) { + value = ConverterUtil.convert(key.getType(), value); + } + break; + } + return value; +// if (column == 0) { +// return key.getKey(); +// } +// return key.getValue(); + } + + @Override + public void setValueAt(Object aValue, int row, int column) { + if (column != 1) { + // seul la colonne 1 est editable (valeur de l'option) + throw new IllegalArgumentException("can not edit column " + column); + } + OptionModel key = getEntry(row); + Object val; + if (aValue == null || key.getType() == aValue.getClass()) { + val = aValue; + } else { + String valStr = String.valueOf(aValue).trim(); + try { + val = ConverterUtil.convert(key.getType(), valStr); + if (val != null && val instanceof Integer) { + if (new Integer(0).equals(val) && !valStr.equals("0")) { + val = null; + } + } + } catch (Exception e) { + val = null; + } + } + categoryModel.setValue(key, val); + fireTableRowsUpdated(row, row); + } +} diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/ConfigUIModel.java b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/ConfigUIModel.java new file mode 100644 index 0000000..554f00b --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/ConfigUIModel.java @@ -0,0 +1,224 @@ +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ +package jaxx.runtime.swing.editor.config.model; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.nuiton.util.ApplicationConfig; +import org.nuiton.util.ApplicationConfig.OptionDef; +import static org.nuiton.i18n.I18n._; + +/** + * Le modele de l'ui des preferences. + * + * Ce modele contient les catégories des options. + * + * @author chemit + */ +public class ConfigUIModel implements Iterable<CategoryModel> { + + public static final String CATEGORY_MODEL_PROPERTY_NAME = "categoryModel"; + /** le dictionnaire des options disponibles par categorie */ + protected final Map<String, CategoryModel> categories; + /** La configuration de l'application */ + protected final ApplicationConfig config; + /** la cateogrie en cours d'utilisation */ + protected CategoryModel categoryModel; + /** + * un drapeau pour savoir si la configuration a été modifiée au moins une + * fois. + * + * On utilise ce drapeau lors de la sortie pour verifier s'il faut ou non + * redemarer l'application (si non en mode standalone) + */ + protected boolean saved; + /** + * un drapeau pour savoir si l'ui de configuration a été lancée en mode + * standalone ou pas. + * + * Si pas lancée en mode standalone, et si la confi a été sauvé on vérifie + * s'il ne faut pas relancer l'application. + */ + protected boolean standalone; + /** suport of modification */ + protected final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + + public ConfigUIModel(ApplicationConfig config) { + this.config = config; + this.categories = new LinkedHashMap<String, CategoryModel>(); + } + + /** + * Ajoute une categorie dans le modele. + * + * @param category l'id de la categorie (la clef de traduction du nom de la categorie) + * @param categoryLabel la clef de traduction de la description de la categorie + * @param keys les options de la categorie + */ + public void addCategory(String category, String categoryLabel, OptionDef... keys) { + if (categories.containsKey(category)) { + throw new IllegalArgumentException(_("config.error.category.already.exists", category)); + } + OptionModel[] entries = new OptionModel[keys.length]; + int index = 0; + for (OptionDef d : keys) { + Object value = config.getOption(d); + OptionModel e = new OptionModel(d, value); + entries[index++] = e; + } + CategoryModel m = new CategoryModel(category, categoryLabel, entries); + categories.put(category, m); + } + + /** + * Change la categorie en cours d'édition. + * + * @param category l'id de la categorie courante + */ + public void setCategory(String category) { + if (!categories.containsKey(category)) { + throw new IllegalArgumentException(_("config.error.category.not.found", category)); + } + CategoryModel newCategoryModel = categories.get(category); + setCategoryModel(newCategoryModel); + newCategoryModel.firePropertyChange(CategoryModel.MODIFIED_PROPERTY_NAME, false, getCategoryModel().isModified()); + newCategoryModel.firePropertyChange(CategoryModel.VALID_PROPERTY_NAME, false, getCategoryModel().isValid()); + } + + @Override + public Iterator<CategoryModel> iterator() { + return categories.values().iterator(); + } + + public CategoryModel getCategoryModel() { + return categoryModel; + } + + public void setCategoryModel(CategoryModel categoryModel) { + CategoryModel old = this.categoryModel; + this.categoryModel = categoryModel; + firePropertyChange(CATEGORY_MODEL_PROPERTY_NAME, old, categoryModel); + } + + public boolean isSaved() { + return saved; + } + + public void setSaved(boolean saved) { + this.saved = saved; + } + + public boolean isStandalone() { + return standalone; + } + + public void setStandalone(boolean standalone) { + this.standalone = standalone; + } + + public void saveModified() { + // compute transients keys (to never be saved) + List<String> transients = new ArrayList<String>(); + + for (OptionModel option : categoryModel) { + if (option.isModified()) { + Object value = option.getValue(); + //TODO TC-20090245 : should try to seek for a mutator, since + // mutator could have extra code to be done when modify an option + config.setOption(option.getKey(), value == null ? null : value.toString()); + // l'option a été sauvegardée, on la marque + option.setSaved(true); + // this is the new original value + option.initValue(value); + } + if (option.isTransient()) { + transients.add(option.getKey()); + } + } + setSaved(true); + // save config + config.saveForUser(transients.toArray(new String[transients.size()])); + // notify data has changed + categoryModel.firePropertyChange(CategoryModel.MODIFIED_PROPERTY_NAME, categoryModel.isModified(), true); + categoryModel.firePropertyChange(CategoryModel.VALID_PROPERTY_NAME, false, categoryModel.isValid()); + categoryModel.firePropertyChange(CategoryModel.RELOAD_PROPERTY_NAME, false, true); + } + + public void reset() { + // reset all modified options of the current category + for (OptionModel key : categoryModel) { + if (key.isModified()) { + key.initValue(key.getOriginalValue()); + } + } + // notify data has changed + categoryModel.firePropertyChange(CategoryModel.MODIFIED_PROPERTY_NAME, categoryModel.isModified(), true); + categoryModel.firePropertyChange(CategoryModel.VALID_PROPERTY_NAME, false, categoryModel.isValid()); + categoryModel.firePropertyChange(CategoryModel.RELOAD_PROPERTY_NAME, false, true); + } + + public int getCategoryIndex(String category) { + int i = 0; + for (CategoryModel m : this) { + if (category.equals(m.getCategory())) { + return i; + } + i++; + } + // not found + return -1; + } + + public void firePropertyChange(String propertyName, Object oldValue, Object newValue) { + pcs.firePropertyChange(propertyName, oldValue, newValue); + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + pcs.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + pcs.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.removePropertyChangeListener(propertyName, listener); + } + + public synchronized boolean hasListeners(String propertyName) { + return pcs.hasListeners(propertyName); + } + + public synchronized PropertyChangeListener[] getPropertyChangeListeners(String propertyName) { + return pcs.getPropertyChangeListeners(propertyName); + } + + public synchronized PropertyChangeListener[] getPropertyChangeListeners() { + return pcs.getPropertyChangeListeners(); + } +} diff --git a/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/OptionModel.java b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/OptionModel.java new file mode 100644 index 0000000..9990127 --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/OptionModel.java @@ -0,0 +1,112 @@ +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ +package jaxx.runtime.swing.editor.config.model; + +import org.nuiton.util.ApplicationConfig.OptionDef; + +/** + * le modele d'une option de la configuration a editer. + * + * @author tchemit + */ +public class OptionModel implements OptionDef { + + /** la definition de l'option ( venant de la config) */ + protected final OptionDef def; + /** un drapeau pour savoir si l'option est valide (n'est pas utilisé actuellement) */ + protected boolean valid = true; + /** un drapeau pour savoir si l'option a été sauvée */ + protected boolean saved = false; + /** la valeur non modifié de l'option */ + protected Object originalValue; + /** la valeur actuelle de l'option (peut être la valeur orignal si non modifée)*/ + protected Object value; + + protected OptionModel(OptionDef def, Object value) { + this.def = def; + initValue(value); + } + + @Override + public String getKey() { + return def.getKey(); + } + + @Override + public Class<?> getType() { + return def.getType(); + } + + @Override + public String getDescription() { + return def.getDescription(); + } + + @Override + public String getDefaultValue() { + return def.getDefaultValue(); + } + + @Override + public boolean isTransient() { + return def.isTransient(); + } + + @Override + public boolean isFinal() { + return def.isFinal(); + } + + public Object getOriginalValue() { + return originalValue; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } + + public boolean isModified() { + return !originalValue.equals(value); + } + + public boolean isValid() { + return valid; + } + + public void setValid(boolean valid) { + this.valid = valid; + } + + public boolean isSaved() { + return saved; + } + + public void setSaved(boolean saved) { + this.saved = saved; + } + + public void initValue(Object originalValue) { + this.originalValue = originalValue; + this.value = originalValue; + } +} diff --git a/trunk/jaxx-runtime-swing-widget/src/main/resources/i18n/jaxx-runtime-swing-widget-en_GB.properties b/trunk/jaxx-runtime-swing-widget/src/main/resources/i18n/jaxx-runtime-swing-widget-en_GB.properties new file mode 100644 index 0000000..27e055b --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/resources/i18n/jaxx-runtime-swing-widget-en_GB.properties @@ -0,0 +1,71 @@ +aboutframe.about=About +aboutframe.license=License +aboutframe.ok=OK +aboutframe.thirdparty=Third party +columnselection.action.tip= +columnselector.action.tip= +config.action.quit=Quit +config.action.quit.tip=Quit the configuration editor +config.action.reset=Cancel +config.action.reset.tip=Cancel the modifications for the category +config.action.save=Save +config.action.save.tip=Save the modifications for the category +config.category.saved=The category '%1$s' was modified \: +config.choice.cancel=Cancel +config.choice.continue=Continue +config.choice.doNotSave=Do not save +config.choice.ok=Ok +config.choice.save=Save +config.defaultValue=Default value +config.defaultValue.tip=Default value of the option +config.descrition=Description +config.error.category.already.exists=category with name '%1$s' does already exist\! +config.error.category.not.found=category with name '%1$s' does not exist\! +config.key=Key +config.key.tip=Key of the option +config.message.quit.invalid.category=The category '%1$s' is not valid\! +config.message.quit.valid.and.modified.category=The category '%1$s' has some modified options \: +config.modified=Option was modified (previous value \: %1$s) +config.no.option.selected=< No selected option > +config.option.final=This option can not be modified +config.option.label=Option '%1$s' (%2$s) +config.option.modified=Value is modified < original value \: '%1$s' - new value \: '%2$s' > +config.title=Preferences +config.title.need.confirm=A confirmation is required +config.title.will.reload.application=The application need to be restarted +config.unmodifiable=Can not be modified +config.unvalid=Option is not valid \! (previous value \: %1$s, required type \: %2$s) +config.value=Value +config.value.tip=Value of the option +entitycombobox.action.reset.tip=Reset the selected value +entitycombobox.action.sort.tip=Change the sorted property +entitycombobox.popup.label=Object '%1$s' +entitycombobox.popup.title=Change the sorted property +entitycombobox.sort.off=Click to activate the sort on this property +entitycombobox.sort.on=This is the property actually used +entitycombobox.unknown.type=Object of unkown type +errorUI.action.close=Close +errorUI.message=An error wad detected... +errorUI.title=Error... +i18neditor.empty.locales=< No locale to select > +i18neditor.popup.title=Change language +i18neditor.selected=Selected language \: %1$s +i18neditor.unselected=Select this langage \: %1$s +memorywidget.memory=%d/%dMb +numbereditor..=. +numbereditor.0=0 +numbereditor.1=1 +numbereditor.2=2 +numbereditor.3=3 +numbereditor.4=4 +numbereditor.5=5 +numbereditor.6=6 +numbereditor.7=7 +numbereditor.8=8 +numbereditor.9=9 +numbereditor.action.reset.tip=Reset +numbereditor.action.show.tip=Show numeric panel +numbereditor.clearAll=C +numbereditor.clearOne=CE +numbereditor.toggleSign=+/- +timeeditor.H=H diff --git a/trunk/jaxx-runtime-swing-widget/src/main/resources/i18n/jaxx-runtime-swing-widget-fr_FR.properties b/trunk/jaxx-runtime-swing-widget/src/main/resources/i18n/jaxx-runtime-swing-widget-fr_FR.properties new file mode 100644 index 0000000..533b545 --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/main/resources/i18n/jaxx-runtime-swing-widget-fr_FR.properties @@ -0,0 +1,72 @@ +aboutframe.about=\u00C0 propos +aboutframe.license=Licence +aboutframe.ok=OK +aboutframe.thirdparty=Tierce partie +columnselection.action.tip= +columnselector.action.tip= +config.action.quit=Quitter +config.action.quit.tip=Quitter l'\u00E9diteur de configuration +config.action.reset=Annuler +config.action.reset.tip=Annuler les modifications de cette cat\u00E9gorie +config.action.save=Enregistrer +config.action.save.tip=Sauver les modifications de cette cat\u00E9gorie +config.category.saved=La cat\u00E9gorie '%1$s' a \u00E9t\u00E9 modifi\u00E9e \: +config.choice.cancel=Annuler +config.choice.continue=Continuer +config.choice.doNotSave=Ne pas enregistrer +config.choice.ok=Ok +config.choice.save=Enregistrer +config.defaultValue=Valeur par d\u00E9faut +config.defaultValue.tip=Valeur par d\u00E9faut de l'option +config.descrition=Description +config.error.category.already.exists=La cat\u00E9gorie de nom '%1$s' existe d\u00E9j\u00E0\! +config.error.category.not.found=La cat\u00E9gorie de nom '%1$s' n'existe pas\! +config.key=Clef +config.key.tip=Clef de l'option +config.message.quit.invalid.category=La cat\u00E9gorie '%1$s' n'est pas valide\! +config.message.quit.valid.and.modified.category=La cat\u00E9gorie '%1$s' poss\u00E8dent des options modifi\u00E9es \: +config.modified=Option modifi\u00E9e (valeur originale \: %1$s) +config.no.option.selected=< Pas d'option s\u00E9lectionn\u00E9e > +config.option.final=Option non modifiable +config.option.label=Option '%1$s' (%2$s) +config.option.modified=Valeur modifi\u00E9e < nouvelle valeur \: '%1$s' - ancienne valeur \: '%2$s' > +config.option.valid=Valeur non valide +config.title=Pr\u00E9f\u00E9rences +config.title.need.confirm=Une confirmation de votre part est requise... +config.title.will.reload.application=L'application doit \u00EAtre red\u00E9marrer... +config.unmodifiable=Ne peut pas \u00EAtre modifi\u00E9 +config.unvalid=Option non valide (valeur originale \: %1$s, type requis \: %2$s) +config.value=Valeur +config.value.tip=Valeur de l'option +entitycombobox.action.reset.tip=R\u00E9initialiser la valeur de la liste d\u00E9roulante +entitycombobox.action.sort.tip=Modifier le tri de la liste d\u00E9roulante +entitycombobox.popup.label=Objet '%1$s' +entitycombobox.popup.title=Modifier le tri +entitycombobox.sort.off=Cliquer pour activer le tri sur la propri\u00E9t\u00E9 '%1$s' +entitycombobox.sort.on=Le tri est effectu\u00E9 sur la propri\u00E9t\u00E9 '%1$s' +entitycombobox.unknown.type=Objet de type inconnu +errorUI.action.close=Fermer +errorUI.message=Une erreur est survenue \! +errorUI.title=Erreur... +i18neditor.empty.locales=< Aucune locale \u00E0 s\u00E9lectionner > +i18neditor.popup.title=Changer de langue +i18neditor.selected=Langue actuellement utilis\u00E9e \: %1$s +i18neditor.unselected=Pour utiliser cette langue \: %1$s +memorywidget.memory=%d/%dMo +numbereditor..=. +numbereditor.0=0 +numbereditor.1=1 +numbereditor.2=2 +numbereditor.3=3 +numbereditor.4=4 +numbereditor.5=5 +numbereditor.6=6 +numbereditor.7=7 +numbereditor.8=8 +numbereditor.9=9 +numbereditor.action.reset.tip=R\u00E9initialiser +numbereditor.action.show.tip=Afficher le pav\u00E9 num\u00E9rique +numbereditor.clearAll=C +numbereditor.clearOne=CE +numbereditor.toggleSign=+/- +timeeditor.H=H diff --git a/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-config-quit.png b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-config-quit.png new file mode 100644 index 0000000..2541d2b Binary files /dev/null and b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-config-quit.png differ diff --git a/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-config-reset.png b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-config-reset.png new file mode 100644 index 0000000..c149c2b Binary files /dev/null and b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-config-reset.png differ diff --git a/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-config-save.png b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-config-save.png new file mode 100644 index 0000000..41b3f43 Binary files /dev/null and b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-config-save.png differ diff --git a/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-be.png b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-be.png new file mode 100644 index 0000000..d86ebc8 Binary files /dev/null and b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-be.png differ diff --git a/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-ca.png b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-ca.png new file mode 100644 index 0000000..1f20419 Binary files /dev/null and b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-ca.png differ diff --git a/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-ch.png b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-ch.png new file mode 100644 index 0000000..242ec01 Binary files /dev/null and b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-ch.png differ diff --git a/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-de.png b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-de.png new file mode 100644 index 0000000..ac4a977 Binary files /dev/null and b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-de.png differ diff --git a/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-dk.png b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-dk.png new file mode 100644 index 0000000..e2993d3 Binary files /dev/null and b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-dk.png differ diff --git a/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-es.png b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-es.png new file mode 100644 index 0000000..c2de2d7 Binary files /dev/null and b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-es.png differ diff --git a/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-fi.png b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-fi.png new file mode 100644 index 0000000..14ec091 Binary files /dev/null and b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-fi.png differ diff --git a/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-fr.png b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-fr.png new file mode 100644 index 0000000..8332c4e Binary files /dev/null and b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-fr.png differ diff --git a/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-gb.png b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-gb.png new file mode 100644 index 0000000..ff701e1 Binary files /dev/null and b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-gb.png differ diff --git a/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-it.png b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-it.png new file mode 100644 index 0000000..89692f7 Binary files /dev/null and b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-it.png differ diff --git a/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-nl.png b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-nl.png new file mode 100644 index 0000000..fe44791 Binary files /dev/null and b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-nl.png differ diff --git a/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-no.png b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-no.png new file mode 100644 index 0000000..160b6b5 Binary files /dev/null and b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-no.png differ diff --git a/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-se.png b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-se.png new file mode 100644 index 0000000..1994653 Binary files /dev/null and b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-se.png differ diff --git a/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-us.png b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-us.png new file mode 100644 index 0000000..10f451f Binary files /dev/null and b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-i18n-us.png differ diff --git a/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-numbereditor-calculator.png b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-numbereditor-calculator.png new file mode 100644 index 0000000..701a60a Binary files /dev/null and b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-numbereditor-calculator.png differ diff --git a/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-numbereditor-reset.png b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-numbereditor-reset.png new file mode 100644 index 0000000..0fb00f9 Binary files /dev/null and b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-numbereditor-reset.png differ diff --git a/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-numbereditor-validate.png b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-numbereditor-validate.png new file mode 100644 index 0000000..a9925a0 Binary files /dev/null and b/trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-numbereditor-validate.png differ diff --git a/trunk/jaxx-runtime-swing-widget/src/site/rst/images/Components-screenshot.gif b/trunk/jaxx-runtime-swing-widget/src/site/rst/images/Components-screenshot.gif new file mode 100644 index 0000000..68bec67 Binary files /dev/null and b/trunk/jaxx-runtime-swing-widget/src/site/rst/images/Components-screenshot.gif differ diff --git a/trunk/jaxx-runtime-swing-widget/src/site/rst/images/webstart.gif b/trunk/jaxx-runtime-swing-widget/src/site/rst/images/webstart.gif new file mode 100644 index 0000000..079fc1b Binary files /dev/null and b/trunk/jaxx-runtime-swing-widget/src/site/rst/images/webstart.gif differ diff --git a/trunk/jaxx-runtime-swing-widget/src/site/rst/index.rst b/trunk/jaxx-runtime-swing-widget/src/site/rst/index.rst new file mode 100644 index 0000000..9e8f78f --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/site/rst/index.rst @@ -0,0 +1,40 @@ +=================== +Examples/Components +=================== + +The Components demo displays many different Swing components being used in a variety of ways; it is JAXX's equivalent +of the SwingSet demo. Various pages use advanced features such as data binding, scripting, event handling, and +CSS stylesheets. + +Examples/Calculator +=================== + +This is an implementation of Challenge #2 from the `XUL Grand Coding Challenge 2004`_ . Because this example program +has been implemented in so many different languages, you can easily compare JAXX's +syntax against the competition and decide for yourself which you prefer. + +Screen shot +----------- + +.. image:: images/Components-screenshot.gif + +Set it in action +---------------- + +|webstart| + +To run this example in `Java Web Start`_, click the `following link`_. + + +Source code +----------- + +Unlike the other examples, the source code for Components is too big to display here. You can view it yourself by +downloading JAXX, and you can also view the source code for the individual demos by clicking the "Source" tabs. + + +.. _Java Web Start: http://java.sun.com/products/javawebstart/ + +.. |webstart| image:: images/webstart.gif + +.. _following link: ./launch-demo.jnlp diff --git a/trunk/jaxx-runtime-swing-widget/src/site/site.xml b/trunk/jaxx-runtime-swing-widget/src/site/site.xml new file mode 100644 index 0000000..6c8144f --- /dev/null +++ b/trunk/jaxx-runtime-swing-widget/src/site/site.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project name="${project.name}"> + + <bannerLeft> + <name>${project.name}</name> + <src>${site.home.url}/jaxx.png</src> + <href>index.html</href> + </bannerLeft> + + <body> + + <breadcrumbs> + <item name="${project.name}" href="${project.url}" /> + </breadcrumbs> + + <menu ref="parent"/> + + <menu name="Utilisateur" inherited="top"/> + + <menu ref="reports"/> + + <menu ref="modules"/> + + </body> +</project> diff --git a/trunk/jaxx-runtime-swing/LICENSE.txt b/trunk/jaxx-runtime-swing/LICENSE.txt new file mode 100644 index 0000000..3f7b8b1 --- /dev/null +++ b/trunk/jaxx-runtime-swing/LICENSE.txt @@ -0,0 +1,166 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/trunk/jaxx-runtime-swing/README.txt b/trunk/jaxx-runtime-swing/README.txt new file mode 100644 index 0000000..d2e50d3 --- /dev/null +++ b/trunk/jaxx-runtime-swing/README.txt @@ -0,0 +1,2 @@ +To deploy new version of pom: mvn deploy +To install localy: mvn install diff --git a/trunk/jaxx-runtime-swing/changelog.txt b/trunk/jaxx-runtime-swing/changelog.txt new file mode 100644 index 0000000..459960e --- /dev/null +++ b/trunk/jaxx-runtime-swing/changelog.txt @@ -0,0 +1,114 @@ +1.5 + * 20090506 [chemit] - add some usefull renderer and other stuffs + +1.3 chemit 20090409 + * 20090404 [chemit] - introduce dimension factory in SwingUtil for min and max dimensions + * 20090327 [chemit] - add javax help mecanism + * 20090318 [chemit] - introduce the BlockingLayerUI2 class (should be merge with BlockingLayerUI) + * 20090318 [chemit] - introduce the CardLayout2Ext class + * 20090312 [chemit] - add some usefull code from ObServe (load Nimbus L&F, load ui configuration) + * 20090309 [chemit] - in BlockingLayerUI, add a new state 'block' to enable/disable blocking mode with a blockingColor + * 20090303 [chemit] - in BlockingLayerUI, add a new state 'useIcon' to enable/disable use of the action icon + - add a simple WizardModel + * 20090301 [chemit] - add usefull methods in JAXXButtonGroup + +1.2 letellier 2009022? + * 20090223 [chemit] - rename jaxx.runtime.swing.Utils to jaxx.runtime.SwingUtil + +1.1 chemit 20090220 + * 20090124 [chemit] - add a cache on context path to improve performance on NavigationTreeNode + - improve I18nTableCellRenderer to display toolTipText + * 20090123 [chemit] - improve NavigationTreeNodeRenderer (now can customized node internalClass) + * 20090121 [letellier] - add some usefull methods in JAXXList and JAXXComboBox + +1.0 chemit 20090111 + * 20090111 [chemit] - integrate new architecture to allow to have runtime code with NO link with compiler :) + * 20090105 [chemit] - improve CardLayout2 +0.8 ??? 200812?? + * 20081228 [chemit] - generify ClassDescriptor + - introduce StylesheetHelper helper class to detach Stylesheet, Rule and Selector classes from + JAXXCompiler and make possible to extract compiler engine from runtime + + * 20081227 [chemit] - add PCS on ValidatorErrorTable to be used by table validation + * 20081218 [chemit] - improve generation of methods + * 20081214 [chemit] - can now in validation, put error with args (all args must be separated by a ##) + - improve event naming : replace the $evXXX by doMEthodName__on__field (except with optimize option) + - add jaww.runtime.swing.Utils.fillComboBox to fill a combobox model from a collection + - add addSourcesToClassPath property to add sources directories in class-path + - improve classloader managment + - keep in DataSource objetCode + - fix bug when processDataBinding on a null objectCode + - always clean node cached values when selected it + - add usefull databinding method in Util + +* 20081213 [chemit] - improve navigation tree node rendering with some caches + - introduce a ChildBuilder to simplify building of child nodes from a collection or array + +0.7 chemit 20081210 +* 20081210 [chemit] - fix bug 1751 +* 20081210 [chemit] - improve JAXXButtonGroup (add ActionChangeListener and toolTipText mecanism) +* 20081208 [chemit] - javabBean attribute use to initialize bean + - introduce Base64Coder to fix bug 1750 and control serailVersionUI (put them to 1L for the moment) + - introduce MultiJXPathDecorator + - add a resetAfterCompile parameter toCompilerOption to keep in test used compilers + + * 20081207 [chemit] use lutinproject 3.1 + - can exclude field from validator + * 20081202 [chemit] - add strategy for loading ui in NavigationTreeSelectionAdapter + - fix bug when searching for a inner class + + * 20081201 [chemit] - implements jaxx.runtime.JXPathDecorator + - add setcontextValue and removeContextValue on JAXXContextEntryDef + - introduce scope in BeanValidator (ERROR or WARNING) and related swing stuff + - only enter once in $initialize method in generated code + + 0.6 chemit 20081117 + * 20081118 [chemit] introduce NavigationUtil, save in context selected node + * 20081107 [chemit] improve data binding and code generation : + - make possible inheritance in binding + - add an attribute javaBean to an object : will generate a full java bean support property + - make possible binding to the javaBean added properties + - clean generated code + + * 20081105 [chemit] - introduce a CardLayout2 to extends awt CardLayout + - introduce a NavigationTreeModel + - introduce a Decorator to render Object + - propagate constructor JAXXContext(JAXXContext) in JAXXObject generation + - begin of rst documentation + + * 20081104 [chemit] can add extra beanInfoSearchPath in SwingInitializer + * 20081104 [chemit] add jaxxContextImplementorClass in option to make possible use of other JAXXContext implementor. + * 20081102 [chemit] improve JAXXContext : + - introduce a JAXXContextEntryDef to qualify an entry of a JAXXContext + - do javadoc in JAXXContext + - add logic in DefaultJAXXContext : seek in parent context if entry not found + * 20081102 [chemit] improve tests : + - fix the last failed test from Jaxx original version :) + - dumps tests to JUnit4 :) + * 20081030 [chemit] improve BeanValidator : + - add full PropertyChangeEvent java-bean support and a property valid + - when remove bean from validator, must remove errors from model + - make possible to have a dynamic errorListModel in jaxx files + * 20081030 [chemit] improve JAXXContext : + - fix setContextValue bug when setting twice a same type for a same key + - implements a DefaultJAXXContext + - use this default implementation with delegate pattern in JAXXObject + * 20081030 [chemit] add JAXXAction contract to simplify init of ui with JAXXInitialContext + * 20081027 [chemit] fix bug 1722 + * 20081027 [chemit] add conversion support in validator + * 20081025 [chemit] improve BeanValidator tag : + - add a errorList attribute for set a ErrorListMouseListener on the errorList + - add a beanInitializer attribute for set the validator's bean at runtime + - add a default errorListModel value 'errors' + * 20081025 [chemit] introduce JAXXInitialContext to fill JAXXContext at runtime before $initialize() method + * 20081024 [chemit] fix validator context lost if UI is launched from another thread + ver-0-5 chemit 20081002 + * 20081017 [chemit] add validator support + * 20081013 [chemit] can generate logger on jaxx files + * 20081011 [chemit] improve site + * 20081011 [chemit] fix bug on JavaFileParser : works again + * 20081002 [chemit] Using lutinproject 3.0, changing groupId to org.codelutin + * 20081002 [chemit] use a single module jaxx-core (no more core, runtime and jaxx-swing modules) + * 20081002 [chemit] Introduce JAXXContext + * 20081002 [chemit] Fix bug on method creation via scripting + * 20081002 [chemit] Improve i18n integration (works now also for tabs) diff --git a/trunk/jaxx-runtime-swing/pom.xml b/trunk/jaxx-runtime-swing/pom.xml new file mode 100644 index 0000000..231d2a2 --- /dev/null +++ b/trunk/jaxx-runtime-swing/pom.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <!-- ************************************************************* --> + <!-- *** POM Relationships *************************************** --> + <!-- ************************************************************* --> + + <parent> + <groupId>org.nuiton</groupId> + <artifactId>jaxx</artifactId> + <version>1.7.1</version> + </parent> + + <groupId>org.nuiton.jaxx</groupId> + <artifactId>jaxx-runtime-swing</artifactId> + + <dependencies> + + <!-- sibling dependencies --> + + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>jaxx-runtime-api</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>org.nuiton</groupId> + <artifactId>nuiton-utils</artifactId> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </dependency> + + </dependencies> + + <!-- ************************************************************* --> + <!-- *** Project Information ************************************* --> + <!-- ************************************************************* --> + + <name>${project.artifactId}</name> + <description>Jaxx runtime swing extension</description> + + <!-- ************************************************************* --> + <!-- *** Build Settings ****************************************** --> + <!-- ************************************************************* --> + <packaging>jar</packaging> + +</project> diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/beaninfos/HBoxBeanInfo.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/beaninfos/HBoxBeanInfo.java new file mode 100644 index 0000000..c114688 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/beaninfos/HBoxBeanInfo.java @@ -0,0 +1,58 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.beaninfos; + +import jaxx.runtime.swing.HBox; + +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.beans.SimpleBeanInfo; + +public class HBoxBeanInfo extends SimpleBeanInfo { + public BeanInfo[] getAdditionalBeanInfo() { + try { + return new BeanInfo[]{Introspector.getBeanInfo(JPanel.class)}; + } + catch (IntrospectionException e) { + throw new RuntimeException(e); + } + } + + + public PropertyDescriptor[] getPropertyDescriptors() { + try { + PropertyDescriptor spacing = new PropertyDescriptor("spacing", HBox.class); + spacing.setBound(true); + + PropertyDescriptor margin = new PropertyDescriptor("margin", HBox.class); + margin.setBound(true); + + PropertyDescriptor horizontalAlignment = new PropertyDescriptor("horizontalAlignment", HBox.class); + horizontalAlignment.setBound(true); + horizontalAlignment.setValue("enumerationValues", new Object[]{ + "left", SwingConstants.LEFT, "SwingConstants.LEFT", + "center", SwingConstants.CENTER, "SwingConstants.CENTER", + "right", SwingConstants.RIGHT, "SwingConstants.RIGHT" + }); + + PropertyDescriptor verticalAlignment = new PropertyDescriptor("verticalAlignment", HBox.class); + verticalAlignment.setBound(true); + verticalAlignment.setValue("enumerationValues", new Object[]{ + "top", SwingConstants.TOP, "SwingConstants.TOP", + "middle", SwingConstants.CENTER, "SwingConstants.CENTER", + "bottom", SwingConstants.BOTTOM, "SwingConstants.BOTTOM" + }); + + return new PropertyDescriptor[]{spacing, margin, horizontalAlignment, verticalAlignment}; + } + catch (IntrospectionException e) { + throw new RuntimeException(e); + } + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/beaninfos/VBoxBeanInfo.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/beaninfos/VBoxBeanInfo.java new file mode 100644 index 0000000..419e063 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/beaninfos/VBoxBeanInfo.java @@ -0,0 +1,58 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.beaninfos; + +import jaxx.runtime.swing.VBox; + +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.beans.SimpleBeanInfo; + +public class VBoxBeanInfo extends SimpleBeanInfo { + public BeanInfo[] getAdditionalBeanInfo() { + try { + return new BeanInfo[]{Introspector.getBeanInfo(JPanel.class)}; + } + catch (IntrospectionException e) { + throw new RuntimeException(e); + } + } + + + public PropertyDescriptor[] getPropertyDescriptors() { + try { + PropertyDescriptor spacing = new PropertyDescriptor("spacing", VBox.class); + spacing.setBound(true); + + PropertyDescriptor margin = new PropertyDescriptor("margin", VBox.class); + margin.setBound(true); + + PropertyDescriptor horizontalAlignment = new PropertyDescriptor("horizontalAlignment", VBox.class); + horizontalAlignment.setBound(true); + horizontalAlignment.setValue("enumerationValues", new Object[]{ + "left", SwingConstants.LEFT, "SwingConstants.LEFT", + "center", SwingConstants.CENTER, "SwingConstants.CENTER", + "right", SwingConstants.RIGHT, "SwingConstants.RIGHT" + }); + + PropertyDescriptor verticalAlignment = new PropertyDescriptor("verticalAlignment", VBox.class); + verticalAlignment.setBound(true); + verticalAlignment.setValue("enumerationValues", new Object[]{ + "top", SwingConstants.TOP, "SwingConstants.TOP", + "middle", SwingConstants.CENTER, "SwingConstants.CENTER", + "bottom", SwingConstants.BOTTOM, "SwingConstants.BOTTOM" + }); + + return new PropertyDescriptor[]{spacing, margin, horizontalAlignment, verticalAlignment}; + } + catch (IntrospectionException e) { + throw new RuntimeException(e); + } + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/JaxxHelpUI.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/JaxxHelpUI.java new file mode 100644 index 0000000..a47a663 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/JaxxHelpUI.java @@ -0,0 +1,23 @@ +package jaxx.runtime; + +import java.awt.Component; +import jaxx.runtime.swing.JaxxHelpBroker; + +/** + * + * Contract to be added on JAXXObject wihch wants to use javax help. + * + * @param <B> type of broker. + * + * @author tony + * @since 1.3 + * @see JaxxHelpBroker + */ +public interface JaxxHelpUI<B extends JaxxHelpBroker<?>> { + + B getBroker(); + + void registerHelpId(B broker, Component component, String helpId); + + void showHelp(String helpId); +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/SwingUtil.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/SwingUtil.java new file mode 100644 index 0000000..dd85678 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/SwingUtil.java @@ -0,0 +1,739 @@ +package jaxx.runtime; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Desktop; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Rectangle; +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import javax.swing.DefaultComboBoxModel; +import javax.swing.JComboBox; +import javax.swing.JTable; +import javax.swing.SwingUtilities; +import javax.swing.table.TableCellEditor; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; +import javax.swing.text.AbstractDocument; +import javax.swing.text.JTextComponent; +import java.lang.reflect.Field; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.ListIterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.NoSuchElementException; +import java.util.Properties; +import javax.swing.DefaultListCellRenderer; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JLayeredPane; +import javax.swing.JList; +import javax.swing.JRootPane; +import javax.swing.JTabbedPane; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import javax.swing.event.HyperlinkEvent; +import javax.swing.table.DefaultTableCellRenderer; +import jaxx.runtime.swing.BooleanCellRenderer; +import jaxx.runtime.swing.DecoratorTableCellRenderer; +import jaxx.runtime.swing.EmptyNumberTableCellRenderer; +import jaxx.runtime.swing.EnumTableCellRenderer; +import jaxx.runtime.swing.I18nTableCellRenderer; +import jaxx.runtime.swing.Item; +import jaxx.runtime.swing.JAXXComboBox; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.jdesktop.jxlayer.JXLayer; + +/** + * The runtime swing util class with some nice stuff. + * + * Note : Replace previous class jaxx.runtime.swing.Utils in previous versions. + * + * @author tony + * @since 1.2 + */ +public class SwingUtil extends Util { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private final Log log = LogFactory.getLog(SwingUtil.class); + private static Field numReaders; + private static Field notifyingListeners; + public static final String ICON_PREFIX = "icon."; + public static final String COLOR_PREFIX = "color."; + + public static Dimension newMinDimension() { + return new Dimension(0, 0); + } + + public static Dimension newMaxXDimension() { + return new Dimension(Short.MAX_VALUE, 0); + } + + public static Dimension newMaxYDimension() { + return new Dimension(0, Short.MAX_VALUE); + } + + public static Dimension newMaxXYDimension() { + return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE); + } + + public static void setText(final JTextComponent c, final String text) { + try { + // AbstractDocument deadlocks if we try to acquire a write lock while a read lock is held by the current thread + // If there are any readers, dispatch an invokeLater. This should only happen in the event of circular bindings. + // Similarly, circular bindings can result in an "Attempt to mutate in notification" error, which we deal with + // by checking for the 'notifyingListeners' property. + AbstractDocument document = (AbstractDocument) c.getDocument(); + if (numReaders == null) { + numReaders = AbstractDocument.class.getDeclaredField("numReaders"); + numReaders.setAccessible(true); + } + if (notifyingListeners == null) { + notifyingListeners = AbstractDocument.class.getDeclaredField("notifyingListeners"); + notifyingListeners.setAccessible(true); + } + + if (notifyingListeners.get(document).equals(Boolean.TRUE)) { + return; + } + + if ((Integer) numReaders.get(document) > 0) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + if (!c.getText().equals(text)) { + c.setText(text); + } + } + }); + return; + } + + String oldText = c.getText(); + if (oldText == null || !oldText.equals(text)) { + c.setText(text); + } + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (SecurityException e) { + c.setText(text); + } + } + + /** + * Fill a combo box model with some datas, and select after all the given object + * + * @param combo the combo to fill + * @param data data ot inject in combo + * @param select the object to select in combo after reflling his model + */ + public static void fillComboBox(JComboBox combo, Collection<?> data, Object select) { + if (!(combo.getModel() instanceof DefaultComboBoxModel)) { + throw new IllegalArgumentException("this method need a DefaultComboBoxModel for this model but was " + combo.getModel().getClass()); + } + DefaultComboBoxModel model = (DefaultComboBoxModel) combo.getModel(); + // evince the model + model.removeListDataListener(combo); + model.removeAllElements(); + if (data != null) { + for (Object o : data) { + model.addElement(o); + } + } + // attach the model + model.addListDataListener(combo); + model.setSelectedItem(select); + } + + /** + * Fill a combo box model with some datas, and select after all the given object + * + * @param combo the combo to fill + * @param data data ot inject in combo + * @param select the object to select in combo after reflling his model + * @param firstNull add a first null element + */ + public static void fillComboBox(JAXXComboBox combo, Collection<?> data, Object select, boolean firstNull) { + List<Item> items = new ArrayList<Item>(); + if (firstNull) { + items.add(new Item("null", " ", null, false)); + } + if (data != null) { + for (Object d : data) { + items.add(new Item(d.toString(), d.toString(), d, d.equals(select))); + } + } + combo.setItems(items); + } + + public static int computeTableColumnWidth(JTable table, Font font, int columnIndex, String suffix) { + int width = 0; + if (font == null) { + font = table.getFont(); + } +// if (font == null) { +// TableColumn column = table.getColumnModel().getColumn(columnIndex); +// font = ((JComponent) column.getCellRenderer()).getFont(); +// } + FontMetrics fontMetrics = table.getFontMetrics(font); + for (int i = 0, rowCount = table.getRowCount(); i < rowCount; i++) { + String key = (String) table.getModel().getValueAt(i, 0); + int w = fontMetrics.stringWidth(key + suffix); + if (w > width) { + width = w; + } + } + return width; + } + + public static void fixTableColumnWidth(JTable table, int columnIndex, int width) { + TableColumn column = table.getColumnModel().getColumn(columnIndex); + column.setMaxWidth(width); + column.setMinWidth(width); + column.setWidth(width); + column.setPreferredWidth(width); + } + + public static void setTableColumnEditor(JTable table, int columnIndex, TableCellEditor editor) { + TableColumn column = table.getColumnModel().getColumn(columnIndex); + column.setCellEditor(editor); + } + + public static void setTableColumnRenderer(JTable table, int columnIndex, TableCellRenderer editor) { + TableColumn column = table.getColumnModel().getColumn(columnIndex); + column.setCellRenderer(editor); + } + + public static void setI18nTableHeaderRenderer(JTable table, String... libelles) { + table.getTableHeader().setDefaultRenderer(new I18nTableCellRenderer(table.getTableHeader().getDefaultRenderer(), libelles)); + } + + public static TableCellRenderer newStringTableCellRenderer(final DefaultTableCellRenderer renderer, final int length, final boolean tooltip) { + + return new DefaultTableCellRenderer() { + + private static final long serialVersionUID = 1l; + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + + renderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + String val = renderer.getText(); + String val2 = val; + if (val.length() > length) { + val2 = val.substring(0, length - 3) + "..."; + } + + JComponent comp = (JComponent) super.getTableCellRendererComponent(table, val2, isSelected, hasFocus, row, column); + if (tooltip) { + comp.setToolTipText(val); + } + return comp; + } + }; + } + + /** + * Box a component in a {@link org.jdesktop.jxlayer.JXLayer}. + * + * @param component the component to box + * @return the {@link org.jdesktop.jxlayer.JXLayer} boxing the component + */ + public static JXLayer<?> boxComponentWithJxLayer(JComponent component) { + JXLayer<?> layer = getLayer(component); + if (layer != null) { + return layer; + } + layer = new org.jdesktop.jxlayer.JXLayer<JComponent>(); + layer.add(component); + return layer; + } + + public static List<JComponent> getLayeredComponents(JAXXObject object) { + List<JComponent> result = new ArrayList<JComponent>(); + for (Entry<String, Object> child : object.get$objectMap().entrySet()) { + if (child.getValue() == null) { + log.warn("find a null object in $objectMap " + child.getKey()); + continue; + } + if (JComponent.class.isAssignableFrom(child.getValue().getClass())) { + JComponent comp = (JComponent) child.getValue(); + if (isLayered(comp)) { + result.add(comp); + } + } + } + return result; + } + + @SuppressWarnings("unchecked") + public static JXLayer<JComponent> getLayer(JComponent comp) { + if (!isLayered(comp)) { + return null; + } + return (JXLayer<JComponent>) comp.getParent(); + } + + public static boolean isLayered(JComponent comp) { + Container parent = comp.getParent(); + return parent != null && parent instanceof JXLayer<?>; + } + + /** + * recherche les composants portant le meme nom que les champs de la classe + * clazz. Cette methode est statique pour pouvoir eventuellement l'utiliser + * dans un autre context (je pense par exemple a la generation jaxx). + * <p/> + * <p/> + * Si la recherche echoue pour quelque raison que se soit, aucune exception + * n'est leve, et la map retournee est tout simplement vide ou incomplete + * + * @param clazz la classe ou recherche les champs + * @param container le container ou rechercher les composants d'edition + * @return le dictionnaire des composants recherches. + */ + public static Map<String, JComponent> lookingForEditor(Class<?> clazz, Container container) { + Map<String, JComponent> result = new HashMap<String, JComponent>(); + try { + // looking for all component with name set + Map<String, JComponent> allNamedComponent = new HashMap<String, JComponent>(); + List<Container> todo = new LinkedList<Container>(); + todo.add(container); + while (todo.size() > 0) { + for (ListIterator<Container> i = todo.listIterator(); i.hasNext();) { + Container parent = i.next(); + i.remove(); + for (Component c : parent.getComponents()) { + if (c instanceof Container) { + i.add((Container) c); + String name = c.getName(); + if (c instanceof JComponent && + name != null && !"".equals(name)) { + allNamedComponent.put(name, (JComponent) c); + } + } + } + } + } + + // looking for all properties on class + BeanInfo info = Introspector.getBeanInfo(clazz); + PropertyDescriptor[] props = info.getPropertyDescriptors(); + + // find if one properties have same name that component + for (PropertyDescriptor prop : props) { + String name = prop.getName(); + if (allNamedComponent.containsKey(name)) { + result.put(name, allNamedComponent.get(name)); + } + } + + } catch (IntrospectionException eee) { + log.warn("Can't introspect bean", eee); + } + + if (log.isDebugEnabled()) { + log.debug("Result: " + result); + } + + return result; + } + + /** + * Centrer un component graphique au center d'un autre component. + * + * <b>Note:</b> si le parent est null, alors on ne fait rien. + * + * @param parent le component parent + * @param component le component à centrer + */ + public static void center(Component parent, Component component) { + if (parent == null) { + return; + } + Rectangle r = parent.getBounds(); + int x = r.x + (r.width - component.getSize().width) / 2; + int y = r.y + (r.height - component.getSize().height) / 2; + component.setLocation(x, y); + } + + /** + * Try to load the Nimbus look and feel. + * <p/> + * @throws UnsupportedLookAndFeelException + * if nimbus is not applicable + * @throws ClassNotFoundException + * @throws InstantiationException + * @throws IllegalAccessException + */ + public static void initNimbusLoookAndFeel() throws UnsupportedLookAndFeelException, ClassNotFoundException, InstantiationException, IllegalAccessException { + + for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) { + if ("Nimbus".equals(laf.getName())) { + UIManager.setLookAndFeel(laf.getClassName()); + } + } + } + + /** + * Load the ui.properties file and set in {@link UIManager} colors and icons found. + * + * @param defaultUIConfig le path vers le fichier de la config d'ui par défaut (doit etre dansle class-path) + * @param extraUIConfig le path vers une surcharge de la config d'ui (doit etre dans le class-path) + * + * @throws IOException if could not load the ui.properties file + */ + public static void loadUIConfig(String defaultUIConfig, String extraUIConfig) throws IOException { + + Properties p = new Properties(); + log.info("loading default UI config " + defaultUIConfig); + p.load(SwingUtil.class.getResourceAsStream(defaultUIConfig)); + if (log.isDebugEnabled()) { + log.debug(p.toString()); + } + if (extraUIConfig != null) { + InputStream extraStream = SwingUtil.class.getResourceAsStream(extraUIConfig); + if (extraStream == null) { + log.warn("could not find extraUIConfig : " + extraUIConfig); + } else { + log.info("loading extra UI config " + extraUIConfig); + Properties p2 = new Properties(p); + p2.load(extraStream); + if (log.isDebugEnabled()) { + log.debug(p2.toString()); + } + p.putAll(p2); + } + } + for (Entry<Object, Object> entry : p.entrySet()) { + String key = (String) entry.getKey(); + if (key.startsWith(ICON_PREFIX)) { + ImageIcon icon; + try { + icon = createImageIcon((String) entry.getValue()); + UIManager.put(key.substring(ICON_PREFIX.length()), icon); + } catch (Exception e) { + log.warn("could not load icon " + entry.getValue()); + } + continue; + } + if (key.startsWith(COLOR_PREFIX)) { + String value = (String) entry.getValue(); + String[] rgb = value.split(","); + UIManager.put(key.substring(COLOR_PREFIX.length()), new Color(Integer.valueOf(rgb[0]), Integer.valueOf(rgb[1]), Integer.valueOf(rgb[2]))); + } + } + } + + /** + * Iterate the components of a {@link JTabbedPane} in natural order. + * + * Says using method {@link JTabbedPane#getComponent(int)} + * @param tabs the + * @return + * @since 1.4 + */ + public static TabbedPaneIterator<Component> newTabbedPaneIterator(JTabbedPane tabs) { + return new TabbedPaneIterator<Component>(false, tabs) { + + @Override + protected Component get(int index, Component comp) { + return comp; + } + }; + } + + /** + * A simple iterator on a {@link JTabbedPane}. + * + * Implements the method {@link #get(int, java.awt.Component)} to obtain + * the data required given the component (or index). + * + * You can also inverse the order by usin the method {@link #reverse()}. + * + * Note: After the use of the method {@link #reverse()} the iterator returns + * to the first element. + * + * @param <O> the type of return elements. + * @since 1.4 + */ + public static abstract class TabbedPaneIterator<O> implements Iterator<O> { + + final JTabbedPane tabs; + boolean reverse; + int index; + int increment; + + protected abstract O get(int index, Component comp); + + public TabbedPaneIterator(boolean reverse, JTabbedPane tabs) { + this.tabs = tabs; + setReverse(reverse); + } + + public void reset() { + setReverse(reverse); + } + + public int size() { + return tabs.getTabCount(); + } + + public TabbedPaneIterator<O> reverse() { + setReverse(!reverse); + return this; + } + + @Override + public boolean hasNext() { + return reverse ? index > 0 : index < tabs.getTabCount(); + } + + public int getIndex() { + return index; + } + + @Override + public O next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + Component next = tabs.getComponentAt(index); + O result = get(index, next); + index += increment; + return result; + } + + @Override + public void remove() { + throw new IllegalStateException("not implemented for " + this); + } + + @Override + public String toString() { + return super.toString() + "< reverse:" + reverse + ", index:" + index + ", size:" + tabs.getTabCount() + " >"; + } + + protected void setReverse(boolean reverse) { + if (reverse) { + index = tabs.getTabCount() - 1; + increment = -1; + } else { + index = 0; + increment = 1; + } + this.reverse = reverse; + } + } + + public static JLabel newLabel(String text, Object iconKey, int aligment) { + Icon icon = null; + if (iconKey instanceof Icon) { + icon = (Icon) iconKey; + } else if (iconKey instanceof String) { + icon = jaxx.runtime.Util.getUIManagerActionIcon((String) iconKey); + } + JLabel result; + if (icon == null) { + result = new JLabel(text, aligment); + } else { + result = new JLabel(text, icon, aligment); + } + return result; + } + + /** + * Gets the higest visible component in a ancestor hierarchy at + * specific x,y coordinates + * @param parent + * @param x + * @param y + * @return + */ + public static Component getDeepestObjectAt(Component parent, int x, int y) { + + if (parent instanceof Container) { + Container cont = (Container) parent; + // use a copy of 1.3 Container.findComponentAt + Component child = findComponentAt(cont, cont.getWidth(), cont.getHeight(), x, y); + if (child != null && child != cont) { + //log.info("child find : " + child.getName()); + if (child instanceof JRootPane) { + JLayeredPane lp = ((JRootPane) child).getLayeredPane(); + Rectangle b = lp.getBounds(); + child = getDeepestObjectAt(lp, x - b.x, y - b.y); + } + if (child != null) { + return child; + } + } + } + // if the parent is not a Container then it might be a MenuItem. + // But even if it isn't a MenuItem just return the parent because + // that's a close as we can come. + return parent; + } + + public static Component findComponentAt(Container cont, int width, int height, int x, int y) { + //log.info("container : " + cont.getName()); + synchronized (cont.getTreeLock()) { + + if (!((x >= 0) && (x < width) && (y >= 0) && (y < height) && cont.isVisible() && cont.isEnabled())) { + return null; + } + + Component[] component = cont.getComponents(); + int ncomponents = cont.getComponentCount(); + + // Two passes: see comment in sun.awt.SunGraphicsCallback + for (int i = 0; i < ncomponents; i++) { + Component comp = component[i]; + Rectangle rect = null; + + if (comp != null && !comp.isLightweight()) { + if (rect == null || rect.width == 0 || rect.height == 0) { + rect = comp.getBounds(); + } + if (comp instanceof JXLayer<?>) { + JXLayer<?> layer = (JXLayer<?>) comp; + comp = layer.getView(); + } + if (comp instanceof Container) { + comp = findComponentAt((Container) comp, rect.width, rect.height, x - rect.x, y - rect.y); + } else { + comp = comp.getComponentAt(x - rect.x, y - rect.y); + } + if (comp != null && comp.isVisible() && comp.isEnabled()) { + return comp; + } + } + } + + for (int i = 0; i < ncomponents; i++) { + Component comp = component[i]; + Rectangle rect = null; + + if (comp != null && comp.isLightweight()) { + if (rect == null || rect.width == 0 || rect.height == 0) { + rect = comp.getBounds(); + } + if (comp instanceof JXLayer<?>) { + JXLayer<?> layer = (JXLayer<?>) comp; + comp = layer.getView(); + } + if (comp instanceof Container) { + comp = findComponentAt((Container) comp, rect.width, rect.height, x - rect.x, y - rect.y); + } else { + comp = comp.getComponentAt(x - rect.x, y - rect.y); + } + if (comp != null && comp.isVisible() && comp.isEnabled()) { + return comp; + } + } + } + return cont; + } + } + + /** + * Génère un renderer de liste graphique basée sur un décorateur donné. + * + * @param <O> le type des données gérées par le décorateur + * @param decorator le décorateur à encapsuler + * @return le nouveau renderer + * @see Decorator + */ + public static <O> DefaultListCellRenderer newDecoratedListCellRenderer(final Decorator<O> decorator) { + return new DefaultListCellRenderer() { + + private static final long serialVersionUID = 1L; + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + String decorated; + if (value instanceof String) { + decorated = (String) value; + } else { + decorated = decorator.toString(value); + } + JComponent component = (JComponent) super.getListCellRendererComponent(list, decorated, index, isSelected, cellHasFocus); + return component; + } + }; + } + + public static TableCellRenderer newDeleteCellRenderer(DefaultTableCellRenderer renderer) { + Icon icon = UIManager.getIcon("Table.removeIcon"); + if (icon == null) { + // try with default icon + icon = createActionIcon("delete"); + } + return new BooleanCellRenderer(renderer, icon); + } + + public static TableCellRenderer newBooleanTableCellRenderer(DefaultTableCellRenderer renderer) { + return new BooleanCellRenderer(renderer); + } + + public static DecoratorTableCellRenderer newDecorateTableCellRenderer(TableCellRenderer renderer, Decorator<?> decorator) { + return new DecoratorTableCellRenderer(renderer, decorator); + } + + public static EmptyNumberTableCellRenderer newEmptyNumberTableCellRenderer(TableCellRenderer renderer) { + return new EmptyNumberTableCellRenderer(renderer); + } + + public static <E extends Enum<E>> EnumTableCellRenderer<E> newEnumTableCellRenderer(TableCellRenderer renderer, Class<E> enumClass) { + return new EnumTableCellRenderer<E>(renderer, enumClass); + } + + /** + * Open a link coming from a {@link HyperlinkEvent}. + * + * And try to open the link if an url in a browser. + * + * @param he the event to treate + * @since 1.6.0 + */ + public static void openLink(HyperlinkEvent he) { + if (he.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { + + if (Desktop.isDesktopSupported()) { + try { + URL u = he.getURL(); + if (u.getProtocol().equalsIgnoreCase("mailto") || u.getProtocol().equalsIgnoreCase("http") || u.getProtocol().equalsIgnoreCase("ftp")) { + Desktop.getDesktop().browse(u.toURI()); + } + } catch (IOException e) { + if (log.isErrorEnabled()) { + log.error("Error while opening link", e); + } + } catch (URISyntaxException e) { + if (log.isErrorEnabled()) { + log.error("Error while opening link", e); + } + } + } + } + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/SwingValidatorUtil.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/SwingValidatorUtil.java new file mode 100644 index 0000000..bcb068e --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/SwingValidatorUtil.java @@ -0,0 +1,200 @@ +package jaxx.runtime; + +import jaxx.runtime.*; +import jaxx.runtime.validator.BeanValidatorScope; +import jaxx.runtime.validator.*; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.swing.JList; +import javax.swing.JTable; +import java.awt.event.MouseListener; +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import javax.swing.RowSorter; +import javax.swing.SortOrder; +import jaxx.runtime.validator.swing.SwingValidatorMessageTableMouseListener; +import jaxx.runtime.validator.swing.SwingValidatorMessageListMouseListener; +import jaxx.runtime.validator.swing.SwingValidatorMessage; +import jaxx.runtime.validator.swing.SwingValidatorMessageTableRenderer; +import static org.nuiton.i18n.I18n.n_; + +/** + * The helper class for validation module. + * + * @author chemit + */ +public class SwingValidatorUtil extends BeanValidatorUtil { + + static ImageIcon errorIcon; + static ImageIcon warningIcon; + static ImageIcon infoIcon; + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private final Log log = LogFactory.getLog(SwingValidatorUtil.class); + + public static ImageIcon getErrorIcon() { + if (errorIcon == null) { + errorIcon = jaxx.runtime.Util.createImageIcon("error.png"); + } + return errorIcon; + } + + public static ImageIcon getInfoIcon() { + if (infoIcon == null) { + infoIcon = jaxx.runtime.Util.createImageIcon("info.png"); + } + return infoIcon; + } + + public static ImageIcon getWarningIcon() { + if (warningIcon == null) { + warningIcon = jaxx.runtime.Util.createImageIcon("warning.png"); + } + return warningIcon; + } + + protected SwingValidatorUtil() { + // no instance + } + + /** + * Prepare the ui where to display the validators messages. + * + * @param errorTable the table where to display validators messages + */ + public static void installUI(JTable errorTable, SwingValidatorMessageTableRenderer render) { + errorTable.setDefaultRenderer(Object.class, render); + errorTable.getRowSorter().setSortKeys(java.util.Arrays.asList(new RowSorter.SortKey(0, SortOrder.ASCENDING))); + SwingUtil.setI18nTableHeaderRenderer(errorTable, + n_("validator.scope.header"), + n_("validator.scope.header.tip"), + n_("validator.field.header"), + n_("validator.field.header.tip"), + n_("validator.message.header"), + n_("validator.message.header.tip")); + // register a single 'goto widget error' mouse listener on errorTable + registerErrorTableMouseListener(errorTable); + SwingUtil.fixTableColumnWidth(errorTable, 0, 25); + } + + /** + * Register for a given validator list ui a validator mouse listener. + * + * Note: there is only one listener registred for a given list model, so + * invoking this method tiwce or more will have no effect. + * + * @param list the validation ui list + * @return the listener instanciate or found + * @see SwingValidatorMessageListMouseListener + */ + public static SwingValidatorMessageListMouseListener registerErrorListMouseListener(JList list) { + SwingValidatorMessageListMouseListener listener = getErrorListMouseListener(list); + + if (listener != null) { + return listener; + } + listener = new SwingValidatorMessageListMouseListener(); + if (log.isDebugEnabled()) { + log.debug(listener.toString()); + } + list.addMouseListener(listener); + return listener; + } + + /** + * Register for a given validator table ui a validator mouse listener + * + * Note: there is onlt one listener registred for a givne table model, so + * invokin this method twice or more will have no effect. + * + * @param table the validator table ui + * @return the listener instanciate or found + * @see SwingValidatorMessageTableMouseListener + */ + public static SwingValidatorMessageTableMouseListener registerErrorTableMouseListener(JTable table) { + SwingValidatorMessageTableMouseListener listener = getErrorTableMouseListener(table); + + if (listener != null) { + return listener; + } + listener = new SwingValidatorMessageTableMouseListener(); + if (log.isDebugEnabled()) { + log.debug(listener.toString()); + } + table.addMouseListener(listener); + return listener; + } + + /** + * @param list the validator list ui + * @return the validator list mouse listener, or <code>null</code> if not found + * @see SwingValidatorMessageListMouseListener + */ + public static SwingValidatorMessageListMouseListener getErrorListMouseListener(JList list) { + if (list != null) { + for (MouseListener listener : list.getMouseListeners()) { + if (listener instanceof SwingValidatorMessageTableMouseListener) { + return (SwingValidatorMessageListMouseListener) listener; + } + } + } + return null; + } + + /** + * @param table the validator table ui + * @return the validator table mouse listener, or <code>null</code> if not found + * @see SwingValidatorMessageTableMouseListener + */ + public static SwingValidatorMessageTableMouseListener getErrorTableMouseListener(JTable table) { + if (table != null) { + for (MouseListener listener : table.getMouseListeners()) { + if (listener instanceof SwingValidatorMessageTableMouseListener) { + return (SwingValidatorMessageTableMouseListener) listener; + } + } + } + return null; + } + + public static String getMessage(SwingValidatorMessage model) { + String text = model.getMessage(); + if (model.getField() != null) { + text = model.getField().getI18nError(text); + } + return text; + } + + public static String getFieldName(SwingValidatorMessage model, String value) { + String text = null; + JComponent editor = model.getEditor(); + if (editor != null) { + text = (String) editor.getClientProperty("validatorLabel"); + /*if (l != null) { + text = I18n._(l); + } else { + // TODO should try the text + }*/ + } + if (text == null) { + text = value; + } + return text; + } + + public static ImageIcon getIcon(BeanValidatorScope scope) { + ImageIcon icon = null; + switch (scope) { + case ERROR: + icon = getErrorIcon(); + break; + case WARNING: + icon = getWarningIcon(); + break; + case INFO: + icon = getInfoIcon(); + break; + } + return icon; + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/Application.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/Application.java new file mode 100644 index 0000000..5d9cc65 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/Application.java @@ -0,0 +1,56 @@ +package jaxx.runtime.swing; + +import javax.swing.JFrame; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import java.awt.GraphicsConfiguration; + +public class Application extends JFrame { + // Special: jaxxc will automatically add a main() method to any components which + // extend <Application> + + + public Application() { + } + + + public Application(GraphicsConfiguration gc) { + super(gc); + } + + + public Application(String title) { + super(title); + } + + + public Application(String title, GraphicsConfiguration gc) { + super(title, gc); + } + + + public void setLookAndFeel(String lookAndFeel) { + if (lookAndFeel.equals("system")) + lookAndFeel = UIManager.getSystemLookAndFeelClassName(); + else if (lookAndFeel.equals("cross_platform")) + lookAndFeel = UIManager.getCrossPlatformLookAndFeelClassName(); + try { + UIManager.setLookAndFeel(lookAndFeel); + if (isDisplayable()) + SwingUtilities.updateComponentTreeUI(this); + } + catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + catch (InstantiationException e) { + throw new RuntimeException(e); + } + catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + catch (UnsupportedLookAndFeelException e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/BlockingLayerUI.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/BlockingLayerUI.java new file mode 100644 index 0000000..96e16ce --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/BlockingLayerUI.java @@ -0,0 +1,259 @@ +package jaxx.runtime.swing; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.RenderingHints; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.image.BufferedImage; +import javax.swing.Action; +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import org.jdesktop.jxlayer.JXLayer; + +/** + * + * A JXLayer ui implementation that permits to block a component but still + * allow an action when clicking on the right-top icon painted on the layer. + * + * You can change the blocking and accepting icon. + * + * To hook an click on the layer's icon, you can : + * + * <ul><li>pass an Action via method {@link #setAcceptAction(Action)}</li> + * <li>override the method {@link #acceptEvent(java.awt.event.MouseEvent, org.jdesktop.jxlayer.JXLayer)}</li> + * </ul> + * + * @author tony + * @since 1.2 + */ +public class BlockingLayerUI extends org.jdesktop.jxlayer.plaf.AbstractLayerUI<JComponent> { + + public static final String CAN_CLICK_PROPERTY = "canClick"; + public static final String ACCEPT_ICON_PROPERTY = "acceptIcon"; + public static final String BLOCK_ICON_PROPERTY = "blockIcon"; + public static final String BLOCK_PROPERTY = "block"; + private static final long serialVersionUID = 1L; + /** + * Action to be treated when click on icon + */ + protected Action acceptAction; + /** + * Icon when you can not click + */ + protected BufferedImage blockIcon; + /** + * Icon when you can click + */ + protected BufferedImage acceptIcon; + /** + * Optinal color to put fill background when blocking + */ + protected Color blockingColor; + /** + * Internal state to known when we can accept click + */ + protected boolean canClick; + /** + * A flag to enable or disable the use of the icon. + * + * If set to false, no icon will be displayed and no action + * will be possible. + * + * By default, this is active. + */ + protected boolean useIcon = true; + /** + * Internal state when should block event and paint layer + */ + protected boolean block; + + public void setAcceptAction(Action acceptAction) { + this.acceptAction = acceptAction; + } + + public void setAcceptIcon(ImageIcon acceptIcon) { + this.acceptIcon = prepareIcon(acceptIcon); + firePropertyChange(ACCEPT_ICON_PROPERTY, null, acceptIcon); + setDirty(true); + } + + public void setBlockIcon(ImageIcon blockIcon) { + this.blockIcon = prepareIcon(blockIcon); + firePropertyChange(BLOCK_ICON_PROPERTY, null, blockIcon); + setDirty(true); + } + + public void setCanClick(boolean canClick) { + boolean oldvalue = this.canClick; + this.canClick = canClick; + firePropertyChange(CAN_CLICK_PROPERTY, oldvalue, canClick); + if (oldvalue != canClick) { + setDirty(true); + } + } + + public void setBlock(boolean block) { + boolean oldvalue = this.block; + this.block = block; + firePropertyChange(BLOCK_PROPERTY, oldvalue, block); + if (oldvalue != block) { + setDirty(true); + } + } + + @Override + public void setDirty(boolean isDirty) { + super.setDirty(isDirty); + } + + public void setBlockIcon(BufferedImage blockIcon) { + this.blockIcon = blockIcon; + } + + public void setBlockingColor(Color blockingColor) { + this.blockingColor = blockingColor; + } + + public BufferedImage getBlockIcon() { + return blockIcon; + } + + protected BufferedImage getAcceptIcon() { + return acceptIcon; + } + + public boolean isCanClick() { + return canClick; + } + + public void setUseIcon(boolean useIcon) { + boolean oldvalue = this.useIcon; + this.useIcon = useIcon; + if (oldvalue != useIcon) { + setDirty(true); + } + } + + @Override + public BlockingLayerUI clone() { + BlockingLayerUI clone = new BlockingLayerUI(); + clone.acceptAction = acceptAction; + clone.acceptIcon = acceptIcon; + clone.blockIcon = blockIcon; + clone.useIcon = useIcon; + clone.block = block; + clone.blockingColor = blockingColor; + clone.setCanClick(false); + return clone; + } + + @Override + protected void processKeyEvent(KeyEvent e, JXLayer<JComponent> l) { + if (useIcon || block) { + e.consume(); + } + } + + @Override + protected void processMouseMotionEvent(MouseEvent e, JXLayer<JComponent> l) { + if (useIcon) { + updateCanClickState(l, e); + } + if (useIcon || block) { + e.consume(); + } + } + + @Override + protected void processMouseEvent(MouseEvent e, JXLayer<JComponent> l) { + if (useIcon) { + switch (e.getID()) { + case MouseEvent.MOUSE_ENTERED: + updateCanClickState(l, e); + break; + case MouseEvent.MOUSE_EXITED: + setCanClick(false); + break; + case MouseEvent.MOUSE_CLICKED: + if (canClick) { + acceptEvent(e, l); + } + break; + } + } + if (useIcon || block) { + e.consume(); + } + + } + + @Override + protected void paintLayer(Graphics2D g2, JXLayer<JComponent> l) { + super.paintLayer(g2, l); + if (block && blockingColor != null) { + // to be in sync with the view if the layer has a border + /*Insets layerInsets = l.getInsets(); + g2.translate(layerInsets.left, layerInsets.top); + + JComponent view = l.getView(); + // To prevent painting on view's border + Insets insets = view.getInsets(); + g2.clip(new Rectangle(insets.left, insets.top, + view.getWidth() - insets.left - insets.right, + view.getHeight() - insets.top - insets.bottom)); + */ + + g2.setColor(blockingColor); + g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .1f)); + g2.fillRect(0, 0, l.getWidth(), l.getHeight()); + } + if (useIcon && getCurrentIcon() != null) { + g2.drawImage(getCurrentIcon(), l.getWidth() - getCurrentIcon().getWidth() - 1, 0, null); + } + } + + protected void acceptEvent(MouseEvent e, JXLayer<JComponent> l) { + if (acceptAction != null) { + acceptAction.putValue("layer", l); + Component source = l.getView(); + acceptAction.actionPerformed(new ActionEvent(source, 0, "accept")); + } + } + + protected BufferedImage getCurrentIcon() { + return canClick ? acceptIcon : blockIcon; + } + + protected BufferedImage prepareIcon(ImageIcon image) { + BufferedImage icon = new BufferedImage(image.getIconWidth(), image.getIconHeight(), BufferedImage.TYPE_INT_ARGB); + Graphics2D g2 = (Graphics2D) icon.getGraphics(); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); + g2.drawImage(image.getImage(), 0, 0, null); + g2.dispose(); + return icon; + } + + protected void updateCanClickState(JXLayer<JComponent> l, MouseEvent e) { + // udpate toolTipText + Point layerLocation = l.getView().getLocation(); + Point mousePoint = e.getPoint(); + BufferedImage currentIcon = getCurrentIcon(); + if (currentIcon == null) { + setCanClick(false); + return; + } + int minX = (int) layerLocation.getX() + l.getWidth() - currentIcon.getWidth(); + int maxX = (int) layerLocation.getX() + l.getWidth(); + int minY = 0; + int maxY = currentIcon.getHeight(); + boolean accept = minX <= mousePoint.getX() && mousePoint.getX() <= maxX; + accept &= minY <= mousePoint.getLocation().getY() && mousePoint.getLocation().getY() <= maxY; + setCanClick(accept); + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/BlockingLayerUI2.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/BlockingLayerUI2.java new file mode 100644 index 0000000..271071f --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/BlockingLayerUI2.java @@ -0,0 +1,217 @@ +package jaxx.runtime.swing; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.RenderingHints; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.image.BufferedImage; +import javax.swing.Action; +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import org.jdesktop.jxlayer.JXLayer; + +/** + * + * A JXLayer ui implementation that permits to block a component but still + * allow an action when clicking everywhere on the layer. + * + * Moreover, an icon can be added on the right-top icon painted and changed + * when the mouse is over the layer. + * + * You can change the blocking and accepting icon. + * + * To hook an click on the layer's icon, you can : + * + * <ul><li>pass an Action via method {@link #setAcceptAction(Action)}</li> + * <li>override the method {@link #acceptEvent(java.awt.event.MouseEvent, org.jdesktop.jxlayer.JXLayer)}</li> + * </ul> + * + * @author tony + * @since 1.3 + */ +public class BlockingLayerUI2 extends org.jdesktop.jxlayer.plaf.AbstractLayerUI<JComponent> { + + public static final String CAN_CLICK_PROPERTY = "canClick"; + public static final String ACCEPT_ICON_PROPERTY = "acceptIcon"; + public static final String BLOCK_ICON_PROPERTY = "blockIcon"; + private static final long serialVersionUID = 1L; + /** + * Action to be treated when click on icon + */ + protected Action acceptAction; + /** + * Icon when you can not click + */ + protected BufferedImage blockIcon; + /** + * Icon when you can click + */ + protected BufferedImage acceptIcon; + /** + * Optinal color to put fill background when blocking + */ + protected Color blockingColor; + /** + * Internal state to known when we can accept click + */ + protected boolean canClick; + + public void setAcceptAction(Action acceptAction) { + this.acceptAction = acceptAction; + } + + public void setAcceptIcon(ImageIcon acceptIcon) { + this.acceptIcon = prepareIcon(acceptIcon); + firePropertyChange(ACCEPT_ICON_PROPERTY, null, acceptIcon); + setDirty(true); + } + + public void setBlockIcon(ImageIcon blockIcon) { + this.blockIcon = prepareIcon(blockIcon); + firePropertyChange(BLOCK_ICON_PROPERTY, null, blockIcon); + setDirty(true); + } + + public void setCanClick(boolean canClick) { + boolean oldvalue = this.canClick; + this.canClick = canClick; + firePropertyChange(CAN_CLICK_PROPERTY, oldvalue, canClick); + if (oldvalue != canClick) { + setDirty(true); + } + } + + @Override + public void setDirty(boolean isDirty) { + super.setDirty(isDirty); + } + + public void setBlockingColor(Color blockingColor) { + this.blockingColor = blockingColor; + } + + public void setBlockIcon(BufferedImage blockIcon) { + this.blockIcon = blockIcon; + } + + public BufferedImage getBlockIcon() { + return blockIcon; + } + + protected BufferedImage getAcceptIcon() { + return acceptIcon; + } + + public boolean isCanClick() { + return canClick; + } + + @Override + public BlockingLayerUI2 clone() { + BlockingLayerUI2 clone = new BlockingLayerUI2(); + clone.acceptAction = acceptAction; + clone.acceptIcon = acceptIcon; + clone.blockIcon = blockIcon; + clone.blockingColor = blockingColor; + clone.setCanClick(false); + return clone; + } + + @Override + protected void processKeyEvent(KeyEvent e, JXLayer<JComponent> l) { + e.consume(); + } + + @Override + protected void processMouseMotionEvent(MouseEvent e, JXLayer<JComponent> l) { + e.consume(); + } + + @Override + protected void processMouseEvent(MouseEvent e, JXLayer<JComponent> l) { + switch (e.getID()) { + case MouseEvent.MOUSE_ENTERED: + setCanClick(true); + break; + case MouseEvent.MOUSE_EXITED: + setCanClick(false); + break; + case MouseEvent.MOUSE_CLICKED: + if (canClick) { + acceptEvent(e, l); + } + break; + } + e.consume(); + } + + @Override + protected void paintLayer(Graphics2D g2, JXLayer<JComponent> l) { + super.paintLayer(g2, l); + if (blockingColor != null) { + // to be in sync with the view if the layer has a border + /*Insets layerInsets = l.getInsets(); + g2.translate(layerInsets.left, layerInsets.top); + + JComponent view = l.getView(); + // To prevent painting on view's border + Insets insets = view.getInsets(); + g2.clip(new Rectangle(insets.left, insets.top, + view.getWidth() - insets.left - insets.right, + view.getHeight() - insets.top - insets.bottom)); + */ + + g2.setColor(blockingColor); + g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .1f)); + g2.fillRect(0, 0, l.getWidth(), l.getHeight()); + } + if (getCurrentIcon() != null) { + g2.drawImage(getCurrentIcon(), l.getWidth() - getCurrentIcon().getWidth() - 1, 0, null); + } + } + + protected void acceptEvent(MouseEvent e, JXLayer<JComponent> l) { + if (acceptAction != null) { + acceptAction.putValue("layer", l); + Component source = l.getView(); + acceptAction.actionPerformed(new ActionEvent(source, 0, "accept")); + } + } + + protected BufferedImage getCurrentIcon() { + return canClick ? acceptIcon : blockIcon; + } + + protected BufferedImage prepareIcon(ImageIcon image) { + BufferedImage icon = new BufferedImage(image.getIconWidth(), image.getIconHeight(), BufferedImage.TYPE_INT_ARGB); + Graphics2D g2 = (Graphics2D) icon.getGraphics(); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); + g2.drawImage(image.getImage(), 0, 0, null); + g2.dispose(); + return icon; + } + + protected void updateCanClickState(JXLayer<JComponent> l, MouseEvent e) { + // udpate toolTipText + Point layerLocation = l.getView().getLocation(); + Point mousePoint = e.getPoint(); + BufferedImage currentIcon = getCurrentIcon(); + if (currentIcon == null) { + setCanClick(false); + return; + } + int minX = (int) layerLocation.getX() + l.getWidth() - currentIcon.getWidth(); + int maxX = (int) layerLocation.getX() + l.getWidth(); + int minY = 0; + int maxY = currentIcon.getHeight(); + boolean accept = minX <= mousePoint.getX() && mousePoint.getX() <= maxX; + accept &= minY <= mousePoint.getLocation().getY() && mousePoint.getLocation().getY() <= maxY; + setCanClick(accept); + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/BooleanCellRenderer.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/BooleanCellRenderer.java new file mode 100644 index 0000000..85187a3 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/BooleanCellRenderer.java @@ -0,0 +1,61 @@ +package jaxx.runtime.swing; + +import javax.swing.Icon; +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTable; +import javax.swing.table.TableCellRenderer; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; + +/** @author chemit + * @since 1.5 + */ +public class BooleanCellRenderer extends JPanel implements TableCellRenderer { + + private static final long serialVersionUID = 1L; + protected TableCellRenderer defaultDelegate; + protected JCheckBox checkBox; + + public BooleanCellRenderer(TableCellRenderer delegate) { + //super(new BorderLayout()); + this.checkBox = new JCheckBox(); + add(checkBox, BorderLayout.CENTER); + checkBox.setHorizontalAlignment(JLabel.CENTER); + checkBox.setBorderPainted(true); + this.defaultDelegate = delegate; + } + + public BooleanCellRenderer(TableCellRenderer delegate, Icon icon) { + //super(new BorderLayout()); + this.checkBox = new JCheckBox(icon); + add(checkBox, BorderLayout.NORTH); + checkBox.setHorizontalAlignment(JLabel.CENTER); + checkBox.setVerticalTextPosition(JLabel.TOP); + checkBox.setBorderPainted(true); + this.defaultDelegate = delegate; + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + ((JComponent) defaultDelegate).setBackground(null); + JComponent render = (JComponent) defaultDelegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if (isSelected) { + setForeground(table.getSelectionForeground()); + setBackground(table.getSelectionBackground()); + } else { + setForeground(render.getForeground()); + setBackground(render.getBackground()); + //fixme make this works... and remove the test + if (row % 2 == 1) { + setBackground(Color.WHITE); + } + } + checkBox.setSelected((value != null && (Boolean) value)); + setBorder(render.getBorder()); + return this; + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/CardLayout2.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/CardLayout2.java new file mode 100644 index 0000000..66fb367 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/CardLayout2.java @@ -0,0 +1,221 @@ +package jaxx.runtime.swing; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.awt.CardLayout; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Insets; +import java.io.Serializable; +import java.util.LinkedList; +import java.util.List; + +/** + * An override of the awt {@link java.awt.CardLayout}. + * <p/> + * Because in the original layout is not overridable : everything is package level accessible. + * <p/> + * This new class offers to test if a constrains (as a Serializable) is actually dealed by the layout, + * via the method {@link #contains(java.io.Serializable)}. + * <p/> + * We had also another method to obtain the current visible component in a container layouted by the class, + * via the method {@link #getVisibleComponent(java.awt.Container)}. + * + * @author chemit + * @version 1.0 + */ +public class CardLayout2 extends CardLayout { + + /** log */ + static private Log log = LogFactory.getLog(CardLayout2.class); + + private static final long serialVersionUID = 1L; + + /** list of already loaded context (since the {@link #vector} attribute is package visible... */ + protected List<Serializable> contexts = new LinkedList<Serializable>(); + + /** + * A flag to compute dimension only on visible component. + * <p/> + * This is usefull when we only care of the visible component. + */ + protected boolean useOnlyVisibleComponentDimension; + + @Override + public void addLayoutComponent(Component comp, Object constraints) { + super.addLayoutComponent(comp, constraints); + contexts.add((Serializable) constraints); + if (log.isDebugEnabled()) { + log.debug(this + " new constraints : " + constraints); + } + } + + /** + * Test if a constrains is contained in the layout. + * + * @param constraints l'identifiant a tester + * @return <code>true</code> si l'identifiant est deja present dans le layout, <code>false</code> autrement. + */ + public boolean contains(Serializable constraints) { + return contexts.contains(constraints); + } + + /** + * Obtain the visible component in the container. + * + * @param container the container using this layout + * @return the component visible in the container. + */ + public Component getVisibleComponent(Container container) { + if (container.getLayout() != this) { + throw new IllegalArgumentException("the container is not managed by the current layout"); + } + for (Component component : container.getComponents()) { + if (component.isVisible()) { + return component; + } + } + // no component actually visible + return null; + } + + public Component getComponent(Container container, String constraints) { + if (container.getLayout() != this) { + throw new IllegalArgumentException("the container is not manage by the current layout"); + } + if (!contexts.contains(constraints)) { + throw new IllegalArgumentException("the constraints '" + constraints + "' is not supported by this layout : " + contexts); + } + int index = contexts.indexOf(constraints); + return container.getComponents()[index]; + } + + /** + * Determines the preferred size of the container argument using + * this card layout. + * + * @param parent the parent container in which to do the layout + * @return the preferred dimensions to lay out the subcomponents + * of the specified container + * @see java.awt.Container#getPreferredSize + * @see java.awt.CardLayout#minimumLayoutSize + */ + @Override + public Dimension preferredLayoutSize(Container parent) { + Dimension dimension = null; + if (useOnlyVisibleComponentDimension) { + Component comp = getVisibleComponent(parent); + if (comp != null) { + dimension = comp.getPreferredSize(); + } + } + if (dimension == null) { + dimension = super.preferredLayoutSize(parent); + } + return dimension; + } + + /** + * Calculates the minimum size for the specified panel. + * + * @param parent the parent container in which to do the layout + * @return the minimum dimensions required to lay out the + * subcomponents of the specified container + * @see java.awt.Container#doLayout + * @see java.awt.CardLayout#preferredLayoutSize + */ + @Override + public Dimension minimumLayoutSize(Container parent) { + Dimension dimension = null; + if (useOnlyVisibleComponentDimension) { + Component comp = getVisibleComponent(parent); + if (comp != null) { + dimension = comp.getMinimumSize(); + } + } + if (dimension == null) { + dimension = super.minimumLayoutSize(parent); + } + return dimension; + } + + /** + * Returns the maximum dimensions for this layout given the components + * in the specified target container. + * + * @param target the component which needs to be laid out + * @see java.awt.Container + * @see #minimumLayoutSize + * @see #preferredLayoutSize + */ + @Override + public Dimension maximumLayoutSize(Container target) { + Dimension dimension = null; + if (useOnlyVisibleComponentDimension) { + Component comp = getVisibleComponent(target); + if (comp != null) { + dimension = comp.getMaximumSize(); + } + } + if (dimension == null) { + dimension = super.maximumLayoutSize(target); + } + return dimension; + } + + /** + * Lays out the specified container using this card layout. + * <p/> + * Each component in the <code>parent</code> container is reshaped + * to be the size of the container, minus space for surrounding + * insets, horizontal gaps, and vertical gaps. + * + * @param parent the parent container in which to do the layout + * @see java.awt.Container#doLayout + */ + @Override + public void layoutContainer(Container parent) { + if (useOnlyVisibleComponentDimension) { + Component comp = getVisibleComponent(parent); + if (comp != null) { + //dimension = comp.getMinimumSize(); + Insets insets = parent.getInsets(); + comp.setBounds(getHgap() + insets.left, getVgap() + insets.top, + parent.getWidth() - (getHgap() * 2 + insets.left + insets.right), + parent.getHeight() - (getVgap() * 2 + insets.top + insets.bottom)); + } else { + super.layoutContainer(parent); + } + } else { + super.layoutContainer(parent); + } + } + + public boolean isUseOnlyVisibleComponentDimension() { + return useOnlyVisibleComponentDimension; + } + + public void setUseOnlyVisibleComponentDimension(boolean useOnlyVisibleComponentDimension) { + this.useOnlyVisibleComponentDimension = useOnlyVisibleComponentDimension; + } + + /** + * remove from cardlayout and linked container all his components. + * + * @param parent the parent container linked with the layout + */ + public void reset(Container parent) { + if (parent.getLayout() != this) { + throw new IllegalArgumentException("wrong parent for CardLayout"); + } + for (Component component : parent.getComponents()) { + removeLayoutComponent(component); + parent.remove(component); + } + contexts.clear(); + + } + +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/CardLayout2Ext.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/CardLayout2Ext.java new file mode 100644 index 0000000..859d4a1 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/CardLayout2Ext.java @@ -0,0 +1,99 @@ +package jaxx.runtime.swing; + +import java.awt.Container; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import jaxx.runtime.JAXXObject; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Une extension de {@link CardLayout2} pour pouvoir automatiquement afficher un + * contenu à partir de la propriété {@link #selected}. + * + * Ainsi, en changeant cette propriété via la méthode {@link #setSelected(String)}, + * le contenu sera changé automatiquement, ce qui permet une utilisation direct + * dans jaxx sans à avoir à écrire d'écouteur. + * + * @author tony + * @since 1.3 + * @see CardLayout2 + */ +public class CardLayout2Ext extends CardLayout2 { + + /** log */ + static private Log log = LogFactory.getLog(CardLayout2.class); + private static final long serialVersionUID = 1L; + public static final String SELECTED_PROPERTY_NAME = "selected"; + /** + * pour propager les changements dans le modèle vers l'ui + */ + protected PropertyChangeSupport pcs; + /** + * le contenu sélectionné + */ + protected String selected; + private String containerName; + private JAXXObject ui; + private Container container; + + public CardLayout2Ext(JAXXObject ui, String containerName) { + pcs = new PropertyChangeSupport(this); + this.ui = ui; + this.containerName = containerName; + } + + public String getSelected() { + return selected; + } + + public String getPreviousSelected() { + int index = contexts.indexOf(selected); + if (index < 1) { + return null; + } + return contexts.get(index - 1) + ""; + } + + public String getNextSelected() { + int index = contexts.indexOf(selected); + if (index >= contexts.size()) { + return null; + } + return contexts.get(index + 1) + ""; + } + + public void setSelected(String selected) { + this.selected = selected; + show(getContainer(), selected); + } + + public Container getContainer() { + if (container == null) { + container = (Container) ui.getObjectById(containerName); + } + return container; + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + pcs.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + pcs.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.removePropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListeners() { + for (PropertyChangeListener l : pcs.getPropertyChangeListeners()) { + pcs.removePropertyChangeListener(l); + } + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/DecoratorTableCellRenderer.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/DecoratorTableCellRenderer.java new file mode 100644 index 0000000..0760f28 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/DecoratorTableCellRenderer.java @@ -0,0 +1,33 @@ +package jaxx.runtime.swing; + +import jaxx.runtime.Decorator; + +import javax.swing.JTable; +import javax.swing.table.TableCellRenderer; +import java.awt.Component; + +/** + * A simple TableCellRenderer using a delegate TableCellRenderer to render everything elese thant the text : + * the text is I18nalize. + * + * @author chemit + */ +public class DecoratorTableCellRenderer implements TableCellRenderer { + + /** the delegate cell renderer */ + protected TableCellRenderer delegate; + + protected Decorator decorator; + + public DecoratorTableCellRenderer(TableCellRenderer delegate, Decorator decorator) { + this.delegate = delegate; + this.decorator = decorator; + } + + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasfocus, int row, int column) { + if (value != null) { + value = decorator.toString(value); + } + return delegate.getTableCellRendererComponent(table, value, isSelected, hasfocus, row, column); + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/EmptyNumberTableCellRenderer.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/EmptyNumberTableCellRenderer.java new file mode 100644 index 0000000..d7876e7 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/EmptyNumberTableCellRenderer.java @@ -0,0 +1,37 @@ +package jaxx.runtime.swing; + +import javax.swing.JTable; +import javax.swing.table.TableCellRenderer; +import java.awt.Component; +import javax.swing.table.DefaultTableCellRenderer; + +/** + * A {@link TableCellRenderer} which does not display numbers when they are + * equals to 0. + * + * @author chemit + * @since 1.5 + */ +public class EmptyNumberTableCellRenderer implements TableCellRenderer { + + protected final Integer ZERO = 0; + protected final Float ZEROF = 0F; + protected final Double ZEROD = 0D; + private TableCellRenderer delegate; + + public EmptyNumberTableCellRenderer() { + this(new DefaultTableCellRenderer()); + } + + public EmptyNumberTableCellRenderer(TableCellRenderer delegate) { + this.delegate = delegate; + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + if (value == null || ZERO.equals(value) || ZEROF.equals(value) || ZEROD.equals(value)) { + value = null; + } + return delegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/EnumTableCellRenderer.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/EnumTableCellRenderer.java new file mode 100644 index 0000000..3e89df9 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/EnumTableCellRenderer.java @@ -0,0 +1,47 @@ +package jaxx.runtime.swing; + +import javax.swing.JTable; +import javax.swing.table.TableCellRenderer; +import java.awt.Component; +import java.util.EnumSet; + +/** + * + * + * A {@link TableCellRenderer} which displays enum values from their ordinal value. + * + * @param <E> le type de l'énumération. + * + * @author chemit + * @since 1.5 + */ +public class EnumTableCellRenderer<E extends Enum<E>> implements TableCellRenderer { + + private TableCellRenderer delegate; + private EnumSet<E> enumValues; + + public EnumTableCellRenderer(TableCellRenderer delegate, Class<E> enumClass) { + this.delegate = delegate; + this.enumValues = EnumSet.allOf(enumClass); + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + + if (value != null) { + //FIXME : should be also able to read it by name ? + Integer ordinal = Integer.valueOf(value + ""); + if (ordinal == -1) { + value = null; + } else { + for (E enumValue : enumValues) { + if (ordinal == enumValue.ordinal()) { + value = enumValue; + break; + } + } + } + } + return delegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/GBC.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/GBC.java new file mode 100644 index 0000000..0a530a4 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/GBC.java @@ -0,0 +1,151 @@ +/** + * *##% Lutin I18n Editor + * Copyright (C) 2008 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ +/* +GBC - A convenience class to tame the GridBagLayout + +Copyright (C) 2002 Cay S. Horstmann (http://horstmann.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package jaxx.runtime.swing; + +import java.awt.GridBagConstraints; +import java.awt.Insets; + +/** + * This class simplifies the use of the GridBagConstraints + * class. + */ +public class GBC extends GridBagConstraints { + private static final long serialVersionUID = -3626882543530638704L; + + /** + * Constructs a GBC with a given gridx and gridy position and + * all other grid bag constraint values set to the default. + * + * @param gridx the gridx position + * @param gridy the gridy position + */ + public GBC(int gridx, int gridy) { + this.gridx = gridx; + this.gridy = gridy; + } + + /** + * Constructs a GBC with given gridx, gridy, gridwidth, gridheight + * and all other grid bag constraint values set to the default. + * + * @param gridx the gridx position + * @param gridy the gridy position + * @param gridwidth the cell span in x-direction + * @param gridheight the cell span in y-direction + */ + public GBC(int gridx, int gridy, int gridwidth, int gridheight) { + this.gridx = gridx; + this.gridy = gridy; + this.gridwidth = gridwidth; + this.gridheight = gridheight; + } + + /** + * Sets the anchor. + * + * @param anchor the anchor value + * @return this object for further modification + */ + public GBC setAnchor(int anchor) { + this.anchor = anchor; + return this; + } + + /** + * Sets the fill direction. + * + * @param fill the fill direction + * @return this object for further modification + */ + public GBC setFill(int fill) { + this.fill = fill; + return this; + } + + /** + * Sets the cell weights. + * + * @param weightx the cell weight in x-direction + * @param weighty the cell weight in y-direction + * @return this object for further modification + */ + public GBC setWeight(double weightx, double weighty) { + this.weightx = weightx; + this.weighty = weighty; + return this; + } + + /** + * Sets the insets of this cell. + * + * @param distance the spacing to use in all directions + * @return this object for further modification + */ + public GBC setInsets(int distance) { + this.insets = new Insets(distance, distance, distance, distance); + return this; + } + + /** + * Sets the insets of this cell. + * + * @param top the spacing to use on top + * @param left the spacing to use to the left + * @param bottom the spacing to use on the bottom + * @param right the spacing to use to the right + * @return this object for further modification + */ + public GBC setInsets(int top, int left, int bottom, int right) { + this.insets = new Insets(top, left, bottom, right); + return this; + } + + /** + * Sets the internal padding + * + * @param ipadx the internal padding in x-direction + * @param ipady the internal padding in y-direction + * @return this object for further modification + */ + public GBC setIpad(int ipadx, int ipady) { + this.ipadx = ipadx; + this.ipady = ipady; + return this; + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/HBox.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/HBox.java new file mode 100644 index 0000000..813abcc --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/HBox.java @@ -0,0 +1,94 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.swing; + +import javax.swing.JPanel; +import java.awt.Insets; + +/** + * Panel which uses an {@link HBoxLayout} by default. + * + * @author Ethan Nicholas + */ +public class HBox extends JPanel { + + private static final long serialVersionUID = 1L; + public static final String SPACING_PROPERTY = "spacing"; + public static final String MARGIN_PROPERTY = "margin"; + public static final String HORIZONTAL_ALIGNMENT_PROPERTY = "horizontalAlignment"; + public static final String VERTICAL_ALIGNMENT_PROPERTY = "verticalAlignment"; + private Insets margin; + + public HBox() { + super(new HBoxLayout()); + } + + /** + * Returns the spacing between components, in pixels. Spacing is applied between components only, + * not to the top or bottom of the container. + * + * @return spacing between components + */ + public int getSpacing() { + return ((HBoxLayout) getLayout()).getSpacing(); + } + + /** + * Sets the spacing between components. Spacing is applied between components only, + * not to the top or bottom of the container. + * + * @param spacing new spacing value + */ + public void setSpacing(int spacing) { + int oldValue = getSpacing(); + ((HBoxLayout) getLayout()).setSpacing(spacing); + firePropertyChange(SPACING_PROPERTY, oldValue, spacing); + revalidate(); + } + + public int getHorizontalAlignment() { + return ((HBoxLayout) getLayout()).getHorizontalAlignment(); + } + + public void setHorizontalAlignment(int horizontalAlignment) { + int oldValue = getHorizontalAlignment(); + ((HBoxLayout) getLayout()).setHorizontalAlignment(horizontalAlignment); + firePropertyChange(HORIZONTAL_ALIGNMENT_PROPERTY, oldValue, horizontalAlignment); + revalidate(); + } + + public int getVerticalAlignment() { + return ((HBoxLayout) getLayout()).getVerticalAlignment(); + } + + public void setVerticalAlignment(int verticalAlignment) { + int oldValue = getVerticalAlignment(); + ((HBoxLayout) getLayout()).setVerticalAlignment(verticalAlignment); + firePropertyChange(VERTICAL_ALIGNMENT_PROPERTY, oldValue, verticalAlignment); + revalidate(); + } + + public Insets getMargin() { + return margin; + } + + public void setMargin(Insets margin) { + Insets oldValue = this.margin; + this.margin = (Insets) margin.clone(); + firePropertyChange(MARGIN_PROPERTY, oldValue, margin); + } + + @Override + public Insets getInsets() { + Insets result = super.getInsets(); + if (margin != null) { + result.top += margin.top; + result.left += margin.left; + result.right += margin.right; + result.bottom += margin.bottom; + } + return result; + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/HBoxLayout.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/HBoxLayout.java new file mode 100644 index 0000000..ac22f6e --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/HBoxLayout.java @@ -0,0 +1,127 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.swing; + +import javax.swing.SwingConstants; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Insets; +import java.awt.LayoutManager; + +/** + * Horizontal box layout. The layout rules followed by this class are quite different than the core BoxLayout class, + * and in general represent a more useful algorithm. + * + * @author Ethan Nicholas + */ +public class HBoxLayout implements LayoutManager { + + private int spacing = 6; + private int horizontalAlignment = SwingConstants.LEFT; + private int verticalAlignment = SwingConstants.TOP; + + public int getSpacing() { + return spacing; + } + + public void setSpacing(int spacing) { + this.spacing = spacing; + } + + public int getHorizontalAlignment() { + return horizontalAlignment; + } + + public void setHorizontalAlignment(int horizontalAlignment) { + this.horizontalAlignment = horizontalAlignment; + } + + public int getVerticalAlignment() { + return verticalAlignment; + } + + public void setVerticalAlignment(int verticalAlignment) { + this.verticalAlignment = verticalAlignment; + } + + @Override + public void addLayoutComponent(String name, Component comp) { + } + + @Override + public void layoutContainer(Container parent) { + Insets insets = parent.getInsets(); + int parentHeight = parent.getSize().height - insets.top - insets.bottom; + int count = parent.getComponentCount(); + Dimension preferredSize = parent.getPreferredSize(); + int x; + switch (horizontalAlignment) { + case SwingConstants.LEFT: + x = insets.left; + break; + case SwingConstants.CENTER: + x = insets.left + (parent.getWidth() - preferredSize.width) / 2; + break; + case SwingConstants.RIGHT: + x = insets.left + (parent.getWidth() - preferredSize.width); + break; + default: + throw new IllegalArgumentException("invalid horizontal alignment: " + horizontalAlignment); + } + + for (int i = 0; i < count; i++) { + Component component = parent.getComponent(i); + Dimension childPreferredSize = component.getPreferredSize(); + int height = Math.min(childPreferredSize.height, parentHeight); + int y; + switch (verticalAlignment) { + case SwingConstants.TOP: + y = insets.top; + break; + case SwingConstants.CENTER: + y = insets.top + (parentHeight - childPreferredSize.height) / 2; + break; + case SwingConstants.BOTTOM: + y = insets.top + (parentHeight - childPreferredSize.height); + break; + default: + throw new IllegalArgumentException("invalid vertical alignment: " + verticalAlignment); + } + component.setBounds(x, y, childPreferredSize.width, height); + x += childPreferredSize.width + spacing; + } + } + + @Override + public Dimension minimumLayoutSize(Container parent) { + int width = (parent.getComponentCount() - 1) * spacing; + int height = 0; + for (int i = parent.getComponentCount() - 1; i >= 0; i--) { + Dimension minimumSize = parent.getComponent(i).getMinimumSize(); + width += minimumSize.width; + height = Math.max(height, minimumSize.height); + } + Insets insets = parent.getInsets(); + return new Dimension(width + insets.left + insets.right, height + insets.top + insets.bottom); + } + + @Override + public Dimension preferredLayoutSize(Container parent) { + int width = (parent.getComponentCount() - 1) * spacing; + int height = 0; + for (int i = parent.getComponentCount() - 1; i >= 0; i--) { + Dimension preferredSize = parent.getComponent(i).getPreferredSize(); + width += preferredSize.width; + height = Math.max(height, preferredSize.height); + } + Insets insets = parent.getInsets(); + return new Dimension(width + insets.left + insets.right, height + insets.top + insets.bottom); + } + + @Override + public void removeLayoutComponent(Component comp) { + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/I18nTableCellRenderer.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/I18nTableCellRenderer.java new file mode 100644 index 0000000..3f6fa7a --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/I18nTableCellRenderer.java @@ -0,0 +1,66 @@ +package jaxx.runtime.swing; + +import static org.nuiton.i18n.I18n._; + +import javax.swing.JComponent; +import javax.swing.JTable; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; +import java.awt.Component; + +/** + * A simple TableCellRenderer using a delegate TableCellRenderer to render everything elese thant the text : + * the text is I18nalize. + * + * @author chemit + */ +public class I18nTableCellRenderer implements TableCellRenderer { + + /** i18n keys of libelles to display */ + protected final String[] keys; + + /** i18n keys of toolTipTexts to display */ + protected final String[] tips; + + /** the delegate cell renderer */ + protected TableCellRenderer delegate; + + public I18nTableCellRenderer(TableCellRenderer delegate, String... keysAndTips) { + this.delegate = delegate; + if (keysAndTips.length == 0) { + throw new IllegalArgumentException("can not have empty keysAndTips parameters (means no column ?)"); + } + if (keysAndTips.length % 2 == 1) { + throw new IllegalArgumentException("must have some couple (text,tooltTipText), but had a even number of data in keysAndTips parameter"); + } + int size = keysAndTips.length / 2; + this.keys = new String[size]; + this.tips = new String[size]; + for (int i = 0; i < size; i++) { + this.keys[i] = keysAndTips[2 * i]; + this.tips[i] = keysAndTips[2 * i + 1]; + } + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasfocus, int row, int column) { + if (column > keys.length) { + throw new IndexOutOfBoundsException("colum can not be greater than " + keys.length); + } + TableColumn col = table.getColumn(table.getColumnName(column)); + int index = col.getModelIndex(); + value = _(keys[index]); + JComponent rendererComponent = (JComponent) delegate.getTableCellRendererComponent(table, value, isSelected, hasfocus, row, column); + rendererComponent.setToolTipText(_(tips[index])); + return rendererComponent; + } + + public String[] getKeys() { + return keys; + } + + public String[] getTips() { + return tips; + } + +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/Item.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/Item.java new file mode 100644 index 0000000..15fa3fc --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/Item.java @@ -0,0 +1,192 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.swing; + +import javax.swing.event.SwingPropertyChangeSupport; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.util.ArrayList; +import java.util.List; + +// This needs to be split into two classes, Item and TreeItem +/** + * An item in a component such as <code>JComboBox</code> or <code>JTree</code>. The <code>Item</code> + * class corresponds to the <code><item></code> tag in JAXX source files. + */ +public class Item { + + public static final String LABEL_PROPERTY = "label"; + public static final String VALUE_PROPERTY = "value"; + public static final String SELECTED_PROPERTY = "selected"; + private String id; + private String label; + private Object value; + private boolean selected; + private List<Item> children; + private Item parent; + private PropertyChangeSupport propertyChangeSupport; + + /** + * Creates a new Item. This should only be called from compiled JAXX files. + * + * @param id the item's ID + * @param label the string that should be used to represent the item visually + * @param value the item's actual value + * @param selected <code>true</code> if the item should be selected by default + */ + public Item(String id, String label, Object value, boolean selected) { + this.id = id; + this.label = label; + this.value = value; + this.selected = selected; + } + + /** + * Returns this item's ID. + * + * @return the JAXX ID attribute + */ + public String getId() { + return id; + } + + /** + * Returns the string that should be used to represent the item at display time. If <code>null</code>, + * <code>String.valueOf(getValue())</code> will be used instead. + * + * @return this item's display string + * @see #setLabel + */ + public String getLabel() { + return label; + } + + /** + * Sets the item's display string. If <code>null, String.valueOf(getValue())</code> will be used instead. + * + * @param label the new display string + * @see #getLabel + */ + public void setLabel(String label) { + String oldLabel = this.label; + this.label = label; + firePropertyChange(LABEL_PROPERTY, oldLabel, label); + } + + /** + * Returns the item's actual value as it appears in the component's model. The <code>Item</code> itself is not + * visible from the model, only the value. + * + * @return the item's value + * @see #setValue + */ + public Object getValue() { + return value; + } + + /** + * Sets the item's value as it appears in the component's model. The <code>Item</code> itself is not + * visible from the model, only the value. + * + * @param value the new value + * @see #getValue + */ + public void setValue(Object value) { + Object oldValue = this.value; + this.value = value; + firePropertyChange(VALUE_PROPERTY, oldValue, value); + } + + /** + * Returns <code>true</code> if this item is currently selected. This is a bound property. + * + * @return <code>true</code> if item is selected + * @see #setSelected + */ + public boolean isSelected() { + return selected; + } + + /** + * Sets the item's selection state. This is a bound property. + * + * @param selected the new selection state + * @see #isSelected + */ + public void setSelected(boolean selected) { + boolean oldSelected = this.selected; + this.selected = selected; + firePropertyChange(SELECTED_PROPERTY, oldSelected, selected); + } + + /** + * Adds a new child node (Items can be nested in trees). + * + * @param item the new child item + */ + public void addChild(Item item) { + if (children == null) { + children = new ArrayList<Item>(); + } + children.add(item); + item.parent = this; + } + + /** + * Returns a list of this item's children. + * + * @return a list of all nested child nodes + */ + public List<Item> getChildren() { + if (children == null) { + children = new ArrayList<Item>(); + } + return children; + } + + /** + * Returns the <code>Item</code> containing this <code>Item</code>, or <code>null</code> for a top-level + * <code>Item</code>. + * + * @return the item parent (or null) + */ + public Item getParent() { + return parent; + } + + private PropertyChangeSupport getPropertyChangeSupport() { + if (propertyChangeSupport == null) { + propertyChangeSupport = new SwingPropertyChangeSupport(this); + } + return propertyChangeSupport; + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + getPropertyChangeSupport().addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String property, PropertyChangeListener listener) { + getPropertyChangeSupport().addPropertyChangeListener(property, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + getPropertyChangeSupport().removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String property, PropertyChangeListener listener) { + getPropertyChangeSupport().removePropertyChangeListener(property, listener); + } + + protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { + if (propertyChangeSupport != null) { + getPropertyChangeSupport().firePropertyChange(propertyName, oldValue, newValue); + } + } + + @Override + public String toString() { + return getClass().getName() + "[" + value + "]"; + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/JAXXButtonGroup.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/JAXXButtonGroup.java new file mode 100644 index 0000000..bb36243 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/JAXXButtonGroup.java @@ -0,0 +1,222 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.swing; + +import javax.swing.AbstractButton; +import javax.swing.ButtonGroup; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.EventListenerList; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.util.Enumeration; + +public class JAXXButtonGroup extends ButtonGroup { + + public static final String SELECTED_VALUE_PROPERTY = "selectedValue"; + public static final String BUTTON8GROUP_CLIENT_PROPERTY = "$buttonGroup"; + public static final String VALUE_CLIENT_PROPERTY = "$value"; + public static final String SELECTED_TIP_CLIENT_PROPERTY = "$selected.toolTipText"; + public static final String NOT_SELECTED_TIP_CLIENT_PROPERTY = "$not.selected.toolTipText"; + protected EventListenerList listenerList = new EventListenerList(); + private PropertyChangeSupport propertyChangeSupport; + private transient Object selectedValue; + protected boolean useToolTipText; + protected transient ChangeEvent changeEvent = new ChangeEvent(this); + private transient ChangeListener changeListener = new ChangeListener() { + + @Override + public void stateChanged(ChangeEvent e) { + updateSelectedValue(); + if (useToolTipText) { + updateToolTipText(); + } + } + }; + private static final long serialVersionUID = 1L; + + @Override + public void add(AbstractButton button) { + super.add(button); + button.addChangeListener(changeListener); + updateSelectedValue(); + } + + @Override + public void remove(AbstractButton button) { + super.remove(button); + button.removeChangeListener(changeListener); + updateSelectedValue(); + } + + public void updateSelectedValue() { + Enumeration<AbstractButton> e = getElements(); + while (e.hasMoreElements()) { + AbstractButton button = e.nextElement(); + if (button.isSelected()) { + Object buttonValue = button.getClientProperty(VALUE_CLIENT_PROPERTY); + if (buttonValue != getSelectedValue()) { + setSelectedValue(buttonValue); + } + } + } + } + + public void updateToolTipText() { + Enumeration<AbstractButton> e = getElements(); + while (e.hasMoreElements()) { + AbstractButton button = e.nextElement(); + String key = button.isSelected() ? SELECTED_TIP_CLIENT_PROPERTY : NOT_SELECTED_TIP_CLIENT_PROPERTY; + button.setToolTipText((String) button.getClientProperty(key)); + } + } + + public boolean isUseToolTipText() { + return useToolTipText; + } + + public Object getSelectedValue() { + return selectedValue; + } + + public AbstractButton getSelectedButton() { + Enumeration<AbstractButton> e = getElements(); + while (e.hasMoreElements()) { + AbstractButton button = e.nextElement(); + if (button.isSelected()) { + return button; + } + } + return null; + } + + public AbstractButton getButton(Object value) { + Enumeration<AbstractButton> e = getElements(); + while (e.hasMoreElements()) { + AbstractButton button = e.nextElement(); + Object buttonValue = button.getClientProperty(VALUE_CLIENT_PROPERTY); + if (value.equals(buttonValue)) { + return button; + } + } + return null; + } + + public void setSelectedValue(Object value) { + Object oldValue = getSelectedValue(); + this.selectedValue = value; + firePropertyChange(oldValue); + } + + public void setUseToolTipText(boolean useToolTipText) { + this.useToolTipText = useToolTipText; + } + + public void setSelectedButton(Object value) { + setSelectedValue(value); + if (value == null) { + Enumeration<AbstractButton> e = getElements(); + while (e.hasMoreElements()) { + AbstractButton button = e.nextElement(); + setSelected(button.getModel(), false); + } + return; + } + + Enumeration<AbstractButton> e = getElements(); + while (e.hasMoreElements()) { + AbstractButton button = e.nextElement(); + Object buttonValue = button.getClientProperty(VALUE_CLIENT_PROPERTY); + if (value.equals(buttonValue)) { + button.setSelected(true); + break; + } + } + } + + protected PropertyChangeSupport getPropertyChangeSupport() { + if (propertyChangeSupport == null) { + propertyChangeSupport = new PropertyChangeSupport(this); + } + return propertyChangeSupport; + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + getPropertyChangeSupport().addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String property, PropertyChangeListener listener) { + getPropertyChangeSupport().addPropertyChangeListener(property, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + getPropertyChangeSupport().removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String property, PropertyChangeListener listener) { + getPropertyChangeSupport().removePropertyChangeListener(property, listener); + } + + private void firePropertyChange(Object oldValue) { + if (propertyChangeSupport != null) { + getPropertyChangeSupport().firePropertyChange(SELECTED_VALUE_PROPERTY, + oldValue, getSelectedValue()); + } + fireStateChanged(); + } + + /** + * Adds a <code>ChangeListener</code> to the button. + * + * @param l the listener to be added + */ + public void addChangeListener(ChangeListener l) { + listenerList.add(ChangeListener.class, l); + } + + /** + * Removes a ChangeListener from the button. + * + * @param l the listener to be removed + */ + public void removeChangeListener(ChangeListener l) { + listenerList.remove(ChangeListener.class, l); + } + + /** + * Returns an array of all the <code>ChangeListener</code>s added + * to this AbstractButton with addChangeListener(). + * + * @return all of the <code>ChangeListener</code>s added or an empty + * array if no listeners have been added + * @since 1.4 + */ + public ChangeListener[] getChangeListeners() { + return listenerList.getListeners(ChangeListener.class); + } + + /** + * Notifies all listeners that have registered interest for + * notification on this event type. The event instance + * is lazily created. + * + * @see EventListenerList + */ + protected void fireStateChanged() { + // Guaranteed to return a non-null array + Object[] listeners = listenerList.getListenerList(); + // Process the listeners last to first, notifying + // those that are interested in this event + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == ChangeListener.class) { + // Lazily create the event: + if (changeEvent == null) { + changeEvent = new ChangeEvent(this); + } + ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); + } + } + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/JAXXComboBox.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/JAXXComboBox.java new file mode 100644 index 0000000..a882bd1 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/JAXXComboBox.java @@ -0,0 +1,224 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.swing; + +import javax.swing.AbstractListModel; +import javax.swing.ComboBoxModel; +import javax.swing.DefaultListCellRenderer; +import javax.swing.JComboBox; +import javax.swing.JList; +import javax.swing.ListModel; +import java.awt.Component; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class JAXXComboBox extends JComboBox { + + private static final long serialVersionUID = 1L; + + public class JAXXComboBoxModel extends AbstractListModel implements ComboBoxModel { + + private List<Item> items; + private Object selectedItem; + private static final long serialVersionUID = -8940733376638766414L; + + public JAXXComboBoxModel(List<Item> items) { + this.items = items; + + PropertyChangeListener listener = new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent e) { + if (e.getPropertyName().equals(Item.SELECTED_PROPERTY)) { + Item item = (Item) e.getSource(); + int itemIndex = JAXXComboBoxModel.this.items.indexOf(item); + // TODO: fix cut-and-pasting badness + int[] oldSelection = new int[]{getSelectedIndex()}; + int[] newSelection; + int index = -1; + for (int i = 0; i < oldSelection.length; i++) { + if (oldSelection[i] == itemIndex) { + index = i; + break; + } + } + if (item.isSelected()) { + if (index != -1) // it was already selected + { + return; + } + newSelection = new int[oldSelection.length + 1]; + System.arraycopy(oldSelection, 0, newSelection, 0, oldSelection.length); + newSelection[newSelection.length - 1] = itemIndex; + } else { + if (index == -1) // it already wasn't selected + { + return; + } + newSelection = new int[oldSelection.length - 1]; + System.arraycopy(oldSelection, 0, newSelection, 0, index); + System.arraycopy(oldSelection, index + 1, newSelection, index, oldSelection.length - 1 - index); + } + setSelectedIndex(newSelection[0]); + } else { + // TODO: more cut-and-pasting badness + for (int i = 0; i < getSize(); i++) { + if (getElementAt(i) == ((Item) e.getSource()).getValue()) { + fireContentsChanged(JAXXComboBoxModel.this, i, i); + if (getSelectedIndex() == i) { + fireItemStateChanged(new ItemEvent(JAXXComboBox.this, ItemEvent.ITEM_STATE_CHANGED, getElementAt(i), ItemEvent.DESELECTED)); + } + return; + } + } + } + } + }; + for (Item item : items) { + item.addPropertyChangeListener(listener); + } + } + + @Override + public Object getElementAt(int i) { + return items.get(i).getValue(); + } + + @Override + public int getSize() { + return items.size(); + } + + @Override + public Object getSelectedItem() { + return selectedItem; + } + + @Override + public void setSelectedItem(Object selectedItem) { + if ((this.selectedItem != null && !this.selectedItem.equals(selectedItem)) || + this.selectedItem == null && selectedItem != null) { + this.selectedItem = selectedItem; + fireContentsChanged(this, -1, -1); + } + } + } + + public JAXXComboBox() { + setRenderer(new DefaultListCellRenderer() { + + private static final long serialVersionUID = 1L; + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + ListModel model = list.getModel(); + if (model instanceof JAXXComboBoxModel) { + List/*<Item>*/ items = ((JAXXComboBoxModel) model).items; + Item item = null; + if (index == -1) { + for (Object item1 : items) { + Item testItem = (Item) item1; + if (testItem.getValue() == value) { + item = testItem; + break; + } + } + } else { + item = (Item) items.get(index); + } + + if (item != null) { + String label = item.getLabel(); + if (label != null) { + value = label; + } + } + } + return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + } + }); + + addItemListener(new ItemListener() { + + @Override + public void itemStateChanged(ItemEvent e) { + ListModel model = getModel(); + if (model instanceof JAXXComboBoxModel) { + List<Item> items = ((JAXXComboBoxModel) model).items; + for (int i = items.size() - 1; i >= 0; i--) { + boolean selected = getSelectedIndex() == i; + Item item = items.get(i); + if (selected != item.isSelected()) { + item.setSelected(selected); + } + } + } + } + }); + } + + /** + * Fill a combo box model with some datas, and select after all the given object + * + * @param data data ot inject in combo + * @param select the object to select in combo after reflling his model + * @param methodName method to invoke to display data's name + */ + public void fillComboBox(Collection<?> data, Object select, String methodName) { + // prepare method to use + Method m; + try { + m = select.getClass().getMethod(methodName); + m.setAccessible(true); + } catch (NoSuchMethodException e) { + throw new IllegalArgumentException("could not find method " + methodName + " on " + select.getClass()); + } + + List<Item> items = new ArrayList<Item>(); + for (Object o : data) { + boolean selected = o.equals(select); + try { + items.add(new Item(o.toString(), (String) m.invoke(o), o, selected)); + } catch (IllegalAccessException e) { + // shoudl never happen ? + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + // shoudl never happen ? + throw new RuntimeException(e); + } + } + setItems(items); + } + + // this way we can keep it marked protected and still allow code in this file to call it + @Override + protected void fireItemStateChanged(ItemEvent e) { + super.fireItemStateChanged(e); + } + + public void setItems(List<Item> items) { + setModel(new JAXXComboBoxModel(items)); + List<Integer> selectedIndexList = new ArrayList<Integer>(); + for (int i = 0; i < items.size(); i++) { + if (items.get(i).isSelected()) { + selectedIndexList.add(i); + } + } + int[] selectedIndices = new int[selectedIndexList.size()]; + for (int i = 0; i < selectedIndexList.size(); i++) { + selectedIndices[i] = selectedIndexList.get(i); + } + if (selectedIndices.length > 0) { + setSelectedIndex(selectedIndices[0]); + } + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/JAXXList.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/JAXXList.java new file mode 100644 index 0000000..c802d9b --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/JAXXList.java @@ -0,0 +1,309 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.swing; + +import javax.swing.AbstractListModel; +import javax.swing.DefaultListCellRenderer; +import javax.swing.JList; +import javax.swing.ListModel; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import java.awt.Component; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class JAXXList extends JList { + + private static final long serialVersionUID = 1L; + + public class JAXXListModel extends AbstractListModel { + + private List<Item> items; + private static final long serialVersionUID = -1598924187490122036L; + + public JAXXListModel(List<Item> items) { + this.items = items; + + PropertyChangeListener listener = new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent e) { + if (e.getPropertyName().equals(Item.SELECTED_PROPERTY)) { + Item item = (Item) e.getSource(); + int itemIndex = JAXXListModel.this.items.indexOf(item); + int[] oldSelection = getSelectedIndices(); + int[] newSelection; + int index = -1; + for (int i = 0; i < oldSelection.length; i++) { + if (oldSelection[i] == itemIndex) { + index = i; + break; + } + } + if (item.isSelected()) { + if (index != -1) // it was already selected + { + return; + } + newSelection = new int[oldSelection.length + 1]; + System.arraycopy(oldSelection, 0, newSelection, 0, oldSelection.length); + newSelection[newSelection.length - 1] = itemIndex; + } else { + if (index == -1) // it already wasn't selected + { + return; + } + newSelection = new int[oldSelection.length - 1]; + System.arraycopy(oldSelection, 0, newSelection, 0, index); + System.arraycopy(oldSelection, index + 1, newSelection, index, oldSelection.length - 1 - index); + } + setSelectedIndices(newSelection); + } else { + for (int i = 0; i < getSize(); i++) { + if (getElementAt(i) == ((Item) e.getSource()).getValue()) { + fireContentsChanged(JAXXListModel.this, i, i); + if (isSelectedIndex(i)) { + fireSelectionValueChanged(i, i, false); + } + return; + } + } + } + } + }; + for (Item item : items) { + item.addPropertyChangeListener(listener); + } + } + + @Override + public Object getElementAt(int i) { + return items.get(i).getValue(); + } + + @Override + public int getSize() { + return items.size(); + } + } + + public JAXXList() { + setCellRenderer(new DefaultListCellRenderer() { + + private static final long serialVersionUID = 1L; + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + ListModel model = list.getModel(); + if (model instanceof JAXXListModel) { + Item item = ((JAXXListModel) model).items.get(index); + String label = item.getLabel(); + if (label != null) { + value = label; + } + } + return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + } + }); + + addListSelectionListener(new ListSelectionListener() { + + @Override + public void valueChanged(ListSelectionEvent e) { + ListModel model = getModel(); + if (model instanceof JAXXListModel) { + List<Item> items = ((JAXXListModel) model).items; + for (int i = items.size() - 1; i >= 0; i--) { + boolean selected = isSelectedIndex(i); + Item item = items.get(i); + if (selected != item.isSelected()) { + item.setSelected(selected); + } + } + } + } + }); + } + + // this way we can keep it marked protected and still allow code in this file to call it + @Override + protected void fireSelectionValueChanged(int firstIndex, int lastIndex, boolean isAdjusting) { + super.fireSelectionValueChanged(firstIndex, lastIndex, isAdjusting); + } + + public void setSelectedValue(Object value) { + super.setSelectedValue(value, true); + } + + public void setItems(List<Item> items) { + setModel(new JAXXListModel(items)); + List<Integer> selectedIndexList = new ArrayList<Integer>(); + for (int i = 0; i < items.size(); i++) { + if (items.get(i).isSelected()) { + selectedIndexList.add(i); + } + } + int[] selectedIndices = new int[selectedIndexList.size()]; + for (int i = 0; i < selectedIndexList.size(); i++) { + selectedIndices[i] = selectedIndexList.get(i); + } + setSelectedIndices(selectedIndices); + } + + /** + * Fill a list model with some datas, and select after all the given object + * + * @param data data ot inject in combo + * @param selects the objects to select in list after reflling his model + */ + public void fillList(Collection<?> data, Collection<?> selects) { + if (selects == null) { + selects = java.util.Collections.EMPTY_LIST; + } + List<Item> items = new ArrayList<Item>(); + for (Object o : data) { + boolean selected = false; + for (Object select : selects) { + if (selected = o.equals(select)) { + break; + } + } + items.add(new Item(o.toString(), o.toString(), o, selected)); + } + setItems(items); + } + + /** + * Fill a list model with some datas, and select after all the given object + * + * @param data data ot inject in combo + * @param select object to select in list after reflling his model + */ + public void fillList(Collection<?> data, Object select) { + List<Item> items = new ArrayList<Item>(); + for (Object o : data) { + boolean selected = o.equals(select); + items.add(new Item(o.toString(), o.toString(), o, selected)); + } + setItems(items); + } + + /** + * Fill a list model with some datas, and select after all the given object + * + * @param data data ot inject in combo + * @param select object to select in list after reflling his model + * @param methodName method to invoke to display data's name + */ + public void fillList(Collection<?> data, Object select, String methodName) { + // prepare method to use + Method m = null; + + List<Item> items = new ArrayList<Item>(); + for (Object o : data) { + boolean selected = o.equals(select); + if (m == null) { + try { + m = o.getClass().getMethod(methodName); + m.setAccessible(true); + } catch (NoSuchMethodException e) { + throw new IllegalArgumentException("could not find method " + methodName + " on " + o.getClass()); + } + } + try { + items.add(new Item(o.toString(), (String) m.invoke(o), o, selected)); + } catch (SecurityException e) { + // shoudl never happen ? + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + // shoudl never happen ? + throw new RuntimeException(e); + } catch (IllegalArgumentException e) { + // shoudl never happen ? + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + // shoudl never happen ? + throw new RuntimeException(e); + } + } + setItems(items); + } + + /** + * Fill a list model with some datas, and select after all the given object + * + * @param data data ot inject in combo + * @param selects the objects to select in list after reflling his model + * @param methodName method to invoke to display data's name + */ + public void fillList(Collection<?> data, Collection<?> selects, String methodName) { + // prepare method to use + Method m = null; + + List<Item> items = new ArrayList<Item>(); + for (Object o : data) { + boolean selected = selects.contains(o); + if (m == null) { + try { + m = o.getClass().getMethod(methodName); + m.setAccessible(true); + } catch (NoSuchMethodException e) { + throw new IllegalArgumentException("could not find method " + methodName + " on " + o.getClass()); + } + } + try { + items.add(new Item(o.toString(), (String) m.invoke(o), o, selected)); + } catch (SecurityException e) { + // shoudl never happen ? + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + // shoudl never happen ? + throw new RuntimeException(e); + } catch (IllegalArgumentException e) { + // shoudl never happen ? + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + // shoudl never happen ? + throw new RuntimeException(e); + } + } + setItems(items); + } + + /** + * Set the selected Objects + * + * @param values Objects must be selected in the list + */ + public void setSelectedValues(Object[] values) { + if (values != null){ + List<Integer> selectedIndices = new ArrayList<Integer>(); + ListModel model = getModel(); + for (int i = 0; i < model.getSize(); i++) { + Object o = model.getElementAt(i); + for (Object value : values) { + if (o.equals(value)) { + selectedIndices.add(i); + break; + } + } + } + int[] ints = new int[selectedIndices.size()]; + for (int i = 0; i < ints.length; i++) { + ints[i] = selectedIndices.get(i).intValue(); + } + setSelectedIndices(ints); + } + else{ + // No selection if values is null + setSelectedIndex(-1); + } + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/JAXXTab.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/JAXXTab.java new file mode 100644 index 0000000..803e8d3 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/JAXXTab.java @@ -0,0 +1,25 @@ +/* + * ##% Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 Code Lutin, + * Tony Chemit + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * ##% */ +package jaxx.runtime.swing; + +/** @author chemit */ +public class JAXXTab extends Table { + + private static final long serialVersionUID = 1L; +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/JAXXToggleButton.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/JAXXToggleButton.java new file mode 100644 index 0000000..13c14c6 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/JAXXToggleButton.java @@ -0,0 +1,92 @@ +package jaxx.runtime.swing; + +public class JAXXToggleButton extends javax.swing.JToggleButton { + + private static final long serialVersionUID = 1L; + protected String glueText; + protected String normalText; + protected String glueTooltipText; + protected String normalTooltipText; + protected int normalMnemonic; + protected int glueMnemonic; + protected boolean _init; + + public String getGlueText() { + return glueText; + } + + public String getNormalText() { + return normalText; + } + + public String getGlueTooltipText() { + return glueTooltipText; + } + + public String getNormalTooltipText() { + return normalTooltipText; + } + + public void setGlueText(String glueText) { + this.glueText = glueText; + + } + + public void setNormalText(String normalText) { + this.normalText = normalText; + + } + + public void setGlueTooltipText(String glueTooltipText) { + this.glueTooltipText = glueTooltipText; + } + + public int getNormalMnemonic() { + return normalMnemonic; + } + + public void setNormalMnemonic(int normalMnemonic) { + this.normalMnemonic = normalMnemonic; + } + + public int getGlueMnemonic() { + return glueMnemonic; + } + + public void setGlueMnemonic(int glueMnemonic) { + this.glueMnemonic = glueMnemonic; + } + + public void setNormalTooltipText(String normalTooltipText) { + this.normalTooltipText = normalTooltipText; + if (!_init) { + init(); + _init = true; + } + } + + @Override + public void setSelected(boolean b) { + super.setSelected(b); + if (isSelected()) { + setText(getGlueText()); + setToolTipText(getGlueTooltipText()); + setMnemonic(getGlueMnemonic()); + } else { + setText(getNormalText()); + setToolTipText(getNormalTooltipText()); + setMnemonic(getNormalMnemonic()); + } + revalidate(); + } + + public void init() { + setSelected(false); + } + + /* end raw body code */ + public JAXXToggleButton() { + super(); + _init = false; + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/JAXXTree.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/JAXXTree.java new file mode 100644 index 0000000..a760731 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/JAXXTree.java @@ -0,0 +1,220 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.swing; + +import javax.swing.JTree; +import javax.swing.event.TreeModelEvent; +import javax.swing.event.TreeModelListener; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.TreeModel; +import javax.swing.tree.TreePath; +import java.awt.Component; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.ArrayList; +import java.util.List; + +public class JAXXTree extends JTree { + + private static final long serialVersionUID = 1L; + private static final String SYNTHETIC = "<synthetic root node>"; + + public class JAXXTreeModel implements TreeModel { + + private Item root; + private List<TreeModelListener> listeners = new ArrayList<TreeModelListener>(); + + public JAXXTreeModel(List<Item> items) { + if (items.size() == 1) { + this.root = items.get(0); + } else { + this.root = new Item(null, null, SYNTHETIC, false); + for (Item item : items) { + root.addChild(item); + } + } + + PropertyChangeListener listener = new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent e) { + if (e.getPropertyName().equals(Item.SELECTED_PROPERTY)) { + Item item = (Item) e.getSource(); + if (item.isSelected()) { + addSelectionPath(getTreePath(item)); + } else { + removeSelectionPath(getTreePath(item)); + } + } else { + Item item = (Item) e.getSource(); + boolean root = item.getParent() == null; + TreePath path = !root ? getTreePath(item.getParent()) : null; + fireTreeNodesChanged(new TreeModelEvent(JAXXTreeModel.this, path, + !root ? new int[]{item.getParent().getChildren().indexOf(item)} : null, + new Object[]{item.getValue()})); + } + } + }; + addPropertyChangeListener(root, listener); + } + + private void addPropertyChangeListener(Item item, PropertyChangeListener listener) { + item.addPropertyChangeListener(listener); + List<Item> children = item.getChildren(); + for (Item aChildren : children) { + addPropertyChangeListener(aChildren, listener); + } + } + + @Override + public void addTreeModelListener(TreeModelListener listener) { + listeners.add(listener); + } + + + /* This is an inefficient implementation, but hand-coded tree structures are unlikely to contain + enough nodes for that to really matter. This could be sped up with caching. */ + private Item findItem(Object value) { + return findItem(root, value); + } + + private Item findItem(Item node, Object value) { + if (node.getValue() == value) { + return node; + } else { + List<Item> children = node.getChildren(); + for (Item aChildren : children) { + Item result = findItem(aChildren, value); + if (result != null) { + return result; + } + } + return null; + } + } + + private TreePath getTreePath(Item node) { + List<Object> path = new ArrayList<Object>(); + while (node != null) { + path.add(0, node.getValue()); + node = node.getParent(); + } + return new TreePath(path.toArray()); + } + + @Override + public Object getChild(Object parent, int index) { + Item node = findItem(parent); + return node.getChildren().get(index).getValue(); + } + + @Override + public int getChildCount(Object parent) { + Item node = findItem(parent); + return node.getChildren().size(); + } + + @Override + public int getIndexOfChild(Object parent, Object child) { + Item node = findItem(parent); + List<Item> children = node.getChildren(); + for (int i = 0, j = children.size(); i < j; i++) { + if (children.get(i).getValue() == child) { + return i; + } + } + return -1; + } + + @Override + public Object getRoot() { + return root.getValue(); + } + + @Override + public boolean isLeaf(Object node) { + Item item = findItem(node); + return item != null && item.getChildren().size() == 0; + } + + @Override + public void removeTreeModelListener(TreeModelListener listener) { + listeners.remove(listener); + } + + public void fireTreeNodesChanged(TreeModelEvent e) { + for (TreeModelListener listener : listeners) { + listener.treeNodesChanged(e); + } + } + + @Override + public void valueForPathChanged(TreePath path, Object newValue) { + } + } + + public JAXXTree(TreeModel model) { + super(model); + } + + public JAXXTree() { + setCellRenderer(new DefaultTreeCellRenderer() { + + private static final long serialVersionUID = 1L; + + @Override + public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { + TreeModel model = tree.getModel(); + if (model instanceof JAXXTreeModel) { + Item item = ((JAXXTreeModel) model).findItem(value); + if (item != null) { + String label = item.getLabel(); + if (label != null) { + value = label; + } + } + } + return super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); + } + }); + + addTreeSelectionListener(new TreeSelectionListener() { + + @Override + public void valueChanged(TreeSelectionEvent e) { + TreeModel model = getModel(); + if (model instanceof JAXXTreeModel) { + scan((JAXXTreeModel) model, ((JAXXTreeModel) model).root); + } + } + + private void scan(JAXXTreeModel model, Item item) { + TreePath path = model.getTreePath(item); + if (item.isSelected() != isPathSelected(path)) { + item.setSelected(!item.isSelected()); + } + List<Item> children = item.getChildren(); + for (Item aChildren : children) { + scan(model, aChildren); + } + } + }); + } + + public void setItems(List<Item> items) { + JAXXTreeModel model = new JAXXTreeModel(items); + if (model.getRoot() != null) { + setRootVisible(model.getRoot() != SYNTHETIC); + } + setModel(model); + } + + public Object getSelectionValue() { + TreePath selectionPath = getSelectionPath(); + return selectionPath != null ? selectionPath.getLastPathComponent() : null; + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/JaxxHelpBroker.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/JaxxHelpBroker.java new file mode 100644 index 0000000..59635f7 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/JaxxHelpBroker.java @@ -0,0 +1,500 @@ +package jaxx.runtime.swing; + +import java.applet.Applet; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.net.URL; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; +import java.util.Vector; +import javax.help.CSH; +import javax.help.HelpBroker; +import javax.help.HelpSet; +import javax.swing.AbstractButton; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import jaxx.runtime.JAXXContext; +import jaxx.runtime.JAXXObject; +import jaxx.runtime.SwingUtil; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * La classe pour encapsuler l'aide de l'application. + * + * @param <B> le type de broker + * @author tony + * @since 1.4 + */ +public abstract class JaxxHelpBroker<B extends JaxxHelpBroker<?>> { + + public static final String JAXX_CONTEXT_ENTRY = "jaxxcontext"; + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(JaxxHelpBroker.class); + protected final String helpsetName; + protected final String defaultID; + protected final String helpKey; + // Main HelpSet & Broker + protected final HelpSet helpset; + protected final HelpBroker helpBroker; + protected Hashtable<Component, Cursor> cursors; + protected Cursor onItemCursor; + protected final Map<Component, String> cache; + + protected JaxxHelpBroker(String helpsetName, String helpKey, String defaultID) { + if (helpsetName == null) { + throw new NullPointerException("parameter helpsetName can not be null!"); + } + this.helpsetName = helpsetName; + this.helpKey = helpKey; + this.defaultID = defaultID; + cache = new HashMap<Component, String>(); + try { + ClassLoader cl = getClass().getClassLoader(); + URL url = HelpSet.findHelpSet(cl, helpsetName); + helpset = new HelpSet(cl, url); + helpBroker = helpset.createHelpBroker(); + } catch (Exception ee) { + throw new IllegalStateException("could not find help set " + helpsetName + " for reason " + ee.getMessage(), ee); + } + } + + public void prepareUI(JAXXObject c) { + if (c == null) { + throw new NullPointerException("parameter c can not be null!"); + } + + // l'ui doit avoir un boutton showHelp + AbstractButton help = getShowHelpButton(c); + + if (help == null) { + if (log.isDebugEnabled()) { + log.debug("no showButton detected for " + c.getClass()); + } + } else { + + // attach context to button + help.putClientProperty(JAXX_CONTEXT_ENTRY, c.getDelegateContext()); + + // add tracking action + ActionListener listener = getShowHelpAction(); + if (log.isDebugEnabled()) { + log.debug("adding tracking action " + listener); + } + help.addActionListener(listener); + + } + if (log.isDebugEnabled()) { + log.debug("done for " + c); + } + } + + public HelpBroker getHelpBroker() { + return helpBroker; + } + + public String getHelpKey() { + return helpKey; + } + + public HelpSet getHelpset() { + return helpset; + } + + public String getHelpsetName() { + return helpsetName; + } + + public String getDefaultID() { + return defaultID; + } + + public void showHelpSet() { + if (log.isDebugEnabled()) { + log.debug(this); + } + new CSH.DisplayHelpFromSource(helpBroker); + } + + public void showHelp(JAXXContext context, String helpId) { + } + + public void installUI(Component comp, String helpId) { + CSH.setHelpIDString(comp, helpId); + if (log.isDebugEnabled()) { + log.debug(helpId + " : " + comp.getName()); + } + cache.put(comp, helpId); + } + + public class ShowHelpForTrackedComponentAction implements ActionListener { + + @Override + public void actionPerformed(ActionEvent e) { + AbstractButton source = (AbstractButton) e.getSource(); + + JAXXContext context = (JAXXContext) source.getClientProperty(JAXX_CONTEXT_ENTRY); + + // prepare cursor + onItemCursor = (Cursor) UIManager.get("HelpOnItemCursor"); + Vector<?> topComponents = null; + cursors = null; + + if (onItemCursor != null) { + cursors = new Hashtable<Component, Cursor>(); + topComponents = getTopContainers(source); + Enumeration<?> enums = topComponents.elements(); + while (enums.hasMoreElements()) { + setAndStoreCursors((Container) enums.nextElement(), onItemCursor); + } + } + + // get the tracked component + Component comp = null; + try { + MouseEvent event = getMouseEvent(); + if (event == null) { + // tracking canceled + return; + } + comp = (Component) event.getSource(); + if (log.isDebugEnabled()) { + log.debug("component traking " + comp.getName() + " : " + comp.getClass().getName()); + } + comp = SwingUtil.getDeepestObjectAt(comp, event.getX(), event.getY()); + if (log.isDebugEnabled()) { + log.debug("deepest component " + comp.getName() + " : " + comp.getClass().getName()); + } + } finally { + // restore the old cursors + if (topComponents != null) { + Enumeration<?> containers = topComponents.elements(); + while (containers.hasMoreElements()) { + resetAndRestoreCursors((Container) containers.nextElement()); + } + } + cursors = null; + } + + String helpID = findHelpId(comp); + showHelp(context, helpID); + } + + public String findHelpId(Component comp) { + String helpID = CSH.getHelpIDString(comp); + if (defaultID.equals(helpID)) { + String id = cache.get(comp); + // on verifie qu'on est bien sur sur le bon id + if (helpID.equals(id)) { + // ok + return helpID; + } + if (log.isDebugEnabled()) { + log.debug("will try to find better id for comp : " + comp.getName()); + } + // on est pas sur le bon id + // on recherche parmis les parents + helpID = findExtactHelpId(comp); + } + if (log.isInfoEnabled()) { + log.info("helpID " + helpID + " for comp " + comp.getName() + " : " + comp.getClass().getName()); + } + return helpID; + } + + protected String findExtactHelpId(Component comp) { + Container parent = comp.getParent(); + while (parent != null) { + String id = cache.get(parent); + if (id == null) { + // ce container n'a pas d'id + // on va directement sur le parent + parent = parent.getParent(); + continue; + } + // le parent possède un id + // on utilise cet id + return id; + } + // on a pas trouve d'id + // on retourne l'id par defaut + return defaultID; + } + } + + protected AbstractButton getShowHelpButton(JAXXObject c) { + return (AbstractButton) c.getObjectById("showHelp"); + } + + protected ActionListener getShowHelpAction() { + return new ShowHelpForTrackedComponentAction(); + } + + //------------------------------------------------------------------------- + //--- Copy CSH code but with accessible modifiers and little improvments + //------------------------------------------------------------------------- + /* + * Get all top level containers to change it's cursors + */ + protected Vector<?> getTopContainers(Object source) { + // This method is used to obtain all top level components of application + // for which the changing of cursor to question mark is wanted. + // Method Frame.getFrames() is used to get list of Frames and + // Frame.getOwnedWindows() method on elements of the list + // returns all Windows, Dialogs etc. It works correctly in application. + // Problem is in applets. There is no way how to get reference to applets + // from elsewhere than applet itself. So, if request for CSH (this means + // pressing help button or select help menu item) does't come from component + // in a Applet, cursor for applets is not changed to question mark. Only for + // Frames, Windows and Dialogs is cursor changed properly. + + Vector<Component> containers = new Vector<Component>(); + Component topComponent = null; + topComponent = getRoot(source); + if (topComponent instanceof Applet) { + try { + Enumeration<Applet> applets = ((Applet) topComponent).getAppletContext().getApplets(); + while (applets.hasMoreElements()) { + containers.add(applets.nextElement()); + } + } catch (NullPointerException npe) { + containers.add(topComponent); + } + } + Frame frames[] = Frame.getFrames(); + for (int i = 0; i < frames.length; i++) { + Window[] windows = frames[i].getOwnedWindows(); + for (int j = 0; j < windows.length; j++) { + containers.add(windows[j]); + } + if (!containers.contains(frames[i])) { + containers.add(frames[i]); + } + } + return containers; + } + + protected Component getRoot(Object comp) { + Object parent = comp; + while (parent != null) { + comp = parent; + if (comp instanceof MenuComponent) { + parent = ((MenuComponent) comp).getParent(); + } else if (comp instanceof Component) { + if (comp instanceof Window) { + break; + } + if (comp instanceof Applet) { + break; + } + parent = ((Component) comp).getParent(); + } else { + break; + } + } + if (comp instanceof Component) { + return ((Component) comp); + } + return null; + } + + /* + * Set the cursor for a component and its children. + * Store the old cursors for future resetting + */ + protected void setAndStoreCursors(Component comp, Cursor cursor) { + if (comp == null) { + return; + } + Cursor compCursor = comp.getCursor(); + if (compCursor != cursor) { + cursors.put(comp, compCursor); + log.debug("set cursor on " + comp); + comp.setCursor(cursor); + } + if (comp instanceof Container) { + Component component[] = ((Container) comp).getComponents(); + for (int i = 0; i < component.length; i++) { + setAndStoreCursors(component[i], cursor); + } + } + } + + /* + * Actually restore the cursor for a component and its children + */ + protected void resetAndRestoreCursors(Component comp) { + if (comp == null) { + return; + } + Cursor oldCursor = cursors.get(comp); + if (oldCursor != null) { + log.debug("restored cursor " + oldCursor + " on " + comp); + comp.setCursor(oldCursor); + } + if (comp instanceof Container) { + Component component[] = ((Container) comp).getComponents(); + for (int i = 0; i < component.length; i++) { + resetAndRestoreCursors(component[i]); + } + } + } + + /** + * Context Sensitive Event Tracking + * + * Creates a new EventDispatchThread from which to dispatch events. This + * method returns when stopModal is invoked. + * + * @return MouseEvent The mouse event occurred. Null if + * cancelled on an undetermined object. + */ + public static MouseEvent getMouseEvent() { + // Should the cursor change to a quesiton mark here or + // require the user to change the cursor externally to this method? + // The problem is that each component can have it's own cursor. + // For that reason it might be better to have the user change the + // cusor rather than us. + + // To track context-sensitive events get the event queue and process + // the events the same way EventDispatchThread does. Filter out + // ContextSensitiveEvents SelectObject & Cancel (MouseDown & ???). + // Note: This code only handles mouse events. Accessiblity might + // require additional functionality or event trapping + + // If the eventQueue can't be retrieved, the thread gets interrupted, + // or the thread isn't a instanceof EventDispatchThread then return + // a null as we won't be able to trap events. + try { + if (EventQueue.isDispatchThread()) { + EventQueue eq = null; + + // Find the eventQueue. If we can't get to it then just return + // null since we won't be able to trap any events. + + try { + eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); + } catch (Exception ee) { + log.debug(ee); + } + + // Safe guard + if (eq == null) { + return null; + } + + int eventNumber = -1; + + // Process the events until an object has been selected or + // the context-sensitive search has been canceled. + while (true) { + // This is essentially the body of EventDispatchThread + // modified to trap context-senstive events and act + // appropriately + eventNumber++; + AWTEvent event = eq.getNextEvent(); + Object src = event.getSource(); + // can't call eq.dispatchEvent + // so I pasted it's body here + + if (log.isDebugEnabled()) { + log.debug(event); + } + + // Not sure if I should suppress ActiveEvents or not + // Modal dialogs do. For now we will not suppress the + // ActiveEvent events + + if (event instanceof ActiveEvent) { + ((ActiveEvent) event).dispatch(); + continue; + } + + if (src instanceof Component) { + // Trap the context-sensitive events here + if (event instanceof KeyEvent) { + KeyEvent e = (KeyEvent) event; + // if this is the cancel key then exit + // otherwise pass all other keys up + if (e.getKeyCode() == KeyEvent.VK_CANCEL || + e.getKeyCode() == KeyEvent.VK_ESCAPE) { + e.consume(); + return null; + } else { + e.consume(); + // dispatchEvent(event); + } + } else if (event instanceof MouseEvent) { + MouseEvent e = (MouseEvent) event; + int eID = e.getID(); + + if ((eID == MouseEvent.MOUSE_CLICKED || + eID == MouseEvent.MOUSE_PRESSED || + eID == MouseEvent.MOUSE_RELEASED) && + SwingUtilities.isRightMouseButton(e)) { + // cancel tracking + e.consume(); + if (log.isDebugEnabled()) { + log.debug("tracking canceled!!!"); + } + return null; + } + + if ((eID == MouseEvent.MOUSE_CLICKED || + eID == MouseEvent.MOUSE_PRESSED || + eID == MouseEvent.MOUSE_RELEASED) && + SwingUtilities.isLeftMouseButton(e)) { + if (eID == MouseEvent.MOUSE_CLICKED) { + if (eventNumber == 0) { + dispatchEvent(event); + continue; + } + } + e.consume(); + return e; + } else { + e.consume(); + } + } else { + dispatchEvent(event); + } + } else if (src instanceof MenuComponent) { + if (event instanceof InputEvent) { + ((InputEvent) event).consume(); + } + } else { + log.error("unable to dispatch event: " + event); + } + } + } + } catch (InterruptedException e) { + if (log.isDebugEnabled()) { + log.debug(e); + } + } + if (log.isDebugEnabled()) { + log.debug("Fall Through code"); + } + return null; + } + + private static void dispatchEvent(AWTEvent event) { + Object src = event.getSource(); + if (event instanceof ActiveEvent) { + // This could become the sole method of dispatching in time. + ((ActiveEvent) event).dispatch(); + } else if (src instanceof Component) { + ((Component) src).dispatchEvent(event); + } else if (src instanceof MenuComponent) { + ((MenuComponent) src).dispatchEvent(event); + } else { + log.error("unable to dispatch event: " + event); + } + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/LocaleListCellRenderer.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/LocaleListCellRenderer.java new file mode 100644 index 0000000..5365420 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/LocaleListCellRenderer.java @@ -0,0 +1,114 @@ +package jaxx.runtime.swing; + +import java.awt.Component; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import javax.swing.DefaultListCellRenderer; +import javax.swing.Icon; +import javax.swing.JLabel; +import javax.swing.JList; +import jaxx.runtime.SwingUtil; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * + * @author chemit + */ +public class LocaleListCellRenderer extends DefaultListCellRenderer { + + public static final Log log = LogFactory.getLog(LocaleListCellRenderer.class); + private static final long serialVersionUID = 1L; + protected Map<Locale, Icon> cache = new HashMap<Locale, Icon>(); + protected boolean showIcon; + protected boolean showText; + + public LocaleListCellRenderer() { + this(true, true); + } + + public LocaleListCellRenderer(boolean showIcon, boolean showText) { + this.showIcon = showIcon; + this.showText = showText; + } + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + JLabel comp = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + Locale locale = (Locale) value; + if (locale != null) { + Icon icon = getIcon(locale); + comp.setIcon(icon); + } + String text = getText(locale); + String tip = getToolTipText(locale); + comp.setText(text); + comp.setToolTipText(tip); + return comp; + } + + public String getText(Locale locale) { + String text = null; + if (showText) { + text = locale.getDisplayName(Locale.getDefault()); + } + return text; + } + + public String getToolTipText(Locale locale) { + String tip = locale.getDisplayName(Locale.getDefault()); + return tip; + } + + public boolean isShowText() { + return showText; + } + + public boolean isShowIcon() { + return showIcon; + } + + public void setShowIcon(boolean showIcon) { + boolean old = this.showIcon; + this.showIcon = showIcon; + firePropertyChange("showIcon", old, showIcon); + } + + public void setShowText(boolean showText) { + boolean old = this.showText; + this.showText = showText; + firePropertyChange("showText", old, showText); + } + + public synchronized Icon getIcon(Locale locale) { + if (!showIcon) { + return null; + } + Icon icon = cache.get(locale); + if (icon != null) { + return icon; + } + + icon = SwingUtil.getUIManagerActionIcon("i18n-" + locale.toString()); + + if (icon == null) { + log.warn("could not find icon action.i18n-" + locale.toString()); + if (locale.getCountry() != null) { + icon = SwingUtil.getUIManagerActionIcon("i18n-" + locale.getCountry().toLowerCase()); + if (icon == null) { + log.warn("could not find icon action.i18n-" + locale.getCountry().toLowerCase()); + + icon = SwingUtil.createActionIcon("i18n-" + locale.getCountry().toLowerCase()); + if (icon == null) { + log.warn("could not find icon action.i18n-" + locale.getCountry().toLowerCase()); + } + } + + } + } + + cache.put(locale, icon); + return icon; + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/MyDefaultCellEditor.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/MyDefaultCellEditor.java new file mode 100644 index 0000000..0d909cd --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/MyDefaultCellEditor.java @@ -0,0 +1,104 @@ +package jaxx.runtime.swing; + +import org.nuiton.util.EnumEditor; + +import javax.swing.DefaultCellEditor; +import javax.swing.Icon; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.table.TableCellEditor; +import java.awt.Component; + +/** + * @author chemit + * @since 1.5 + */ +public class MyDefaultCellEditor extends DefaultCellEditor { + + private static final long serialVersionUID = 1L; + + public static TableCellEditor newTextEditor() { + return new MyDefaultCellEditor(new JTextField()); + } + + public static TableCellEditor newBooleanEditor() { + return new MyDefaultCellEditor(new JCheckBox()); + } + + public static TableCellEditor newListEditor() { + return newListEditor(new JComboBox()); + } + + public static TableCellEditor newListEditor(JComboBox editor) { + return new MyDefaultCellEditor(editor); + } + + public static TableCellEditor newEnumEditor(EnumEditor editor) { + return new MyDefaultCellEditor(editor) { + + private static final long serialVersionUID = 1L; + + @Override + public Object getCellEditorValue() { + Object value = super.getCellEditorValue(); + if (value != null) { + value = ((Enum) value).ordinal(); + } else { + value = -1; + } + return value; + } + }; + } + + public static TableCellEditor newBooleanEditor(Icon icon) { + return new MyDefaultCellEditor(new JCheckBox(icon)); + } + + public static TableCellEditor newBooleanEditor(Icon icon, boolean requireSelect) { + TableCellEditor cellEditor = newBooleanEditor(icon); + ((MyDefaultCellEditor) cellEditor).setRequireSelect(requireSelect); + return cellEditor; + } + + public static TableCellEditor newBooleanEditor(boolean requireSelect) { + TableCellEditor cellEditor = newBooleanEditor(); + ((MyDefaultCellEditor) cellEditor).setRequireSelect(requireSelect); + return cellEditor; + } + protected boolean requireSelect = true; + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + if (!isSelected && requireSelect) { + // force to have select the cell before editing, a way to not modify edition for nothing... + return null; + } + return super.getTableCellEditorComponent(table, value, isSelected, row, column); + } + + public boolean isRequireSelect() { + return requireSelect; + } + + public void setRequireSelect(boolean requireSelect) { + this.requireSelect = requireSelect; + } + + protected MyDefaultCellEditor(JTextField textField) { + super(textField); + setClickCountToStart(1); + } + + protected MyDefaultCellEditor(JCheckBox checkBox) { + super(checkBox); + setClickCountToStart(1); + } + + protected MyDefaultCellEditor(JComboBox comboBox) { + super(comboBox); + setClickCountToStart(1); + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/OneClicListSelectionModel.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/OneClicListSelectionModel.java new file mode 100644 index 0000000..ef35d99 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/OneClicListSelectionModel.java @@ -0,0 +1,181 @@ +package jaxx.runtime.swing; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.swing.ListModel; +import javax.swing.ListSelectionModel; +import javax.swing.event.ListSelectionListener; +import java.util.Arrays; + +/** + * @author chemit + * @since 1.5 + */ +public class OneClicListSelectionModel implements ListSelectionModel { + + /** to use log facility, just put in your code: log.info("..."); */ + static private Log log = LogFactory.getLog(OneClicListSelectionModel.class); + protected ListSelectionModel delegate; + protected final ListModel model; + private boolean[] _states; + + public OneClicListSelectionModel(ListSelectionModel delegate, ListModel model) { + this.delegate = delegate; + this.model = model; + delegate.clearSelection(); + } + + protected boolean[] getStates(int selectedIndex) { + int max = model.getSize(); + if (_states == null || _states.length != max) { + _states = new boolean[max]; + } else { + Arrays.fill(_states, false); + } + for (int i = 0; i < max; i++) { + _states[i] = i != selectedIndex && delegate.isSelectedIndex(i); + } + return _states; + } + + @Override + public void setSelectionInterval(int index0, int index1) { + if (index0 != index1) { + // not a single selection (come from a click) + // use default behaviour + delegate.setSelectionInterval(index0, index1); + return; + } + delegate.setValueIsAdjusting(true); + + try { + int max = model.getSize(); + + if (log.isDebugEnabled()) { + log.debug("single [index:" + index0 + "] [selected:" + isSelectedIndex(index0) + "] [size:" + max + "] [anchor:" + delegate.getAnchorSelectionIndex() + "] [lead:" + delegate.getLeadSelectionIndex() + "]"); + } + + if (!isSelectedIndex(index0)) { + // select it + delegate.addSelectionInterval(index0, index1); + return; + } + if (max == index0) { + // last selected index, so can directly remove it + delegate.removeIndexInterval(index0, index0); + return; + } + + // must recompute the selection removing only the index0 item + boolean[] state = getStates(index0); + + if (log.isDebugEnabled()) { + log.debug("state : " + Arrays.toString(state)); + } + delegate.clearSelection(); + for (int i = 0; i < max; i++) { + if (state[i]) { + delegate.addSelectionInterval(i, i); + } + } + } finally { + delegate.setValueIsAdjusting(false); + } + } + + @Override + public void addSelectionInterval(int index0, int index1) { + delegate.addSelectionInterval(index0, index1); + } + + @Override + public void removeSelectionInterval(int index0, int index1) { + delegate.removeSelectionInterval(index0, index1); + } + + @Override + public int getMinSelectionIndex() { + return delegate.getMinSelectionIndex(); + } + + @Override + public int getMaxSelectionIndex() { + return delegate.getMaxSelectionIndex(); + } + + @Override + public boolean isSelectedIndex(int index) { + return delegate.isSelectedIndex(index); + } + + @Override + public int getAnchorSelectionIndex() { + return delegate.getAnchorSelectionIndex(); + } + + @Override + public void setAnchorSelectionIndex(int index) { + delegate.setAnchorSelectionIndex(index); + } + + @Override + public int getLeadSelectionIndex() { + return delegate.getLeadSelectionIndex(); + } + + @Override + public void setLeadSelectionIndex(int index) { + delegate.setLeadSelectionIndex(index); + } + + @Override + public void clearSelection() { + delegate.clearSelection(); + } + + @Override + public boolean isSelectionEmpty() { + return delegate.isSelectionEmpty(); + } + + @Override + public void insertIndexInterval(int index, int length, boolean before) { + delegate.insertIndexInterval(index, length, before); + } + + @Override + public void removeIndexInterval(int index0, int index1) { + delegate.removeIndexInterval(index0, index1); + } + + @Override + public void setValueIsAdjusting(boolean valueIsAdjusting) { + delegate.setValueIsAdjusting(valueIsAdjusting); + } + + @Override + public boolean getValueIsAdjusting() { + return delegate.getValueIsAdjusting(); + } + + @Override + public void setSelectionMode(int selectionMode) { + delegate.setSelectionMode(selectionMode); + } + + @Override + public int getSelectionMode() { + return delegate.getSelectionMode(); + } + + @Override + public void addListSelectionListener(ListSelectionListener x) { + delegate.addListSelectionListener(x); + } + + @Override + public void removeListSelectionListener(ListSelectionListener x) { + delegate.removeListSelectionListener(x); + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/Spacer.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/Spacer.java new file mode 100644 index 0000000..45f9d25 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/Spacer.java @@ -0,0 +1,12 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.swing; + +import javax.swing.JComponent; + +public class Spacer extends JComponent { + + private static final long serialVersionUID = 1L; +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/TabInfo.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/TabInfo.java new file mode 100644 index 0000000..6cacc5a --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/TabInfo.java @@ -0,0 +1,165 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.swing; + +import javax.swing.Icon; +import javax.swing.event.SwingPropertyChangeSupport; +import java.awt.Color; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; + +public class TabInfo { + + public static String BACKGROUND_PROPERTY = "background"; + public static String DISABLED_ICON_PROPERTY = "disabledIcon"; + public static String DISPLAYED_MNEMONIC_INDEX_PROPERTY = "displayedMnemonicIndex"; + public static String ENABLED_PROPERTY = "enabled"; + public static String FOREGROUND_PROPERTY = "foreground"; + public static String ICON_PROPERTY = "icon"; + public static String MNEMONIC_PROPERTY = "mnemonic"; + public static String TITLE_PROPERTY = "title"; + public static String TOOL_TIP_TEXT_PROPERTY = "toolTipText"; + private String id; + private Color background; + private Icon disabledIcon; + private int displayedMnemonicIndex = -1; + private boolean enabled = true; + private Color foreground; + private Icon icon; + private int mnemonic = -1; + private String title; + private String toolTipText; + private PropertyChangeSupport propertyChangeSupport; + + public TabInfo() { + } + + public TabInfo(String id) { + this.id = id; + } + + public String getId() { + return id; + } + + public Color getBackground() { + return background; + } + + public void setBackground(Color background) { + Color oldValue = this.background; + this.background = background; + firePropertyChange(BACKGROUND_PROPERTY, oldValue, background); + } + + public Icon getDisabledIcon() { + return disabledIcon; + } + + public void setDisabledIcon(Icon disabledIcon) { + Icon oldValue = this.disabledIcon; + this.disabledIcon = disabledIcon; + firePropertyChange(DISABLED_ICON_PROPERTY, oldValue, disabledIcon); + } + + public int getDisplayedMnemonicIndex() { + return displayedMnemonicIndex; + } + + public void setDisplayedMnemonicIndex(int displayedMnemonicIndex) { + int oldValue = this.displayedMnemonicIndex; + this.displayedMnemonicIndex = displayedMnemonicIndex; + firePropertyChange(DISPLAYED_MNEMONIC_INDEX_PROPERTY, oldValue, displayedMnemonicIndex); + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + boolean oldValue = this.enabled; + this.enabled = enabled; + firePropertyChange(ENABLED_PROPERTY, oldValue, enabled); + } + + public Color getForeground() { + return foreground; + } + + public void setForeground(Color foreground) { + Color oldValue = this.foreground; + this.foreground = foreground; + firePropertyChange(FOREGROUND_PROPERTY, oldValue, foreground); + } + + public Icon getIcon() { + return icon; + } + + public void setIcon(Icon icon) { + Icon oldValue = this.icon; + this.icon = icon; + firePropertyChange(ICON_PROPERTY, oldValue, icon); + } + + public int getMnemonic() { + return mnemonic; + } + + public void setMnemonic(int mnemonic) { + int oldValue = this.mnemonic; + this.mnemonic = mnemonic; + firePropertyChange(MNEMONIC_PROPERTY, oldValue, mnemonic); + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + String oldValue = this.title; + this.title = title; + firePropertyChange(TITLE_PROPERTY, oldValue, title); + } + + public String getToolTipText() { + return toolTipText; + } + + public void setToolTipText(String toolTipText) { + String oldValue = this.toolTipText; + this.toolTipText = toolTipText; + firePropertyChange(TOOL_TIP_TEXT_PROPERTY, oldValue, toolTipText); + } + + private PropertyChangeSupport getPropertyChangeSupport() { + if (propertyChangeSupport == null) { + propertyChangeSupport = new SwingPropertyChangeSupport(this); + } + return propertyChangeSupport; + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + getPropertyChangeSupport().addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String property, PropertyChangeListener listener) { + getPropertyChangeSupport().addPropertyChangeListener(property, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + getPropertyChangeSupport().removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String property, PropertyChangeListener listener) { + getPropertyChangeSupport().removePropertyChangeListener(property, listener); + } + + protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { + if (propertyChangeSupport != null) { + getPropertyChangeSupport().firePropertyChange(propertyName, oldValue, newValue); + } + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/TabInfoPropertyChangeListener.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/TabInfoPropertyChangeListener.java new file mode 100644 index 0000000..9c0aee2 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/TabInfoPropertyChangeListener.java @@ -0,0 +1,44 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.swing; + +import javax.swing.Icon; +import javax.swing.JTabbedPane; +import java.awt.Color; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +public class TabInfoPropertyChangeListener implements PropertyChangeListener { + + private JTabbedPane tabs; + private int tabIndex; + + public TabInfoPropertyChangeListener(JTabbedPane tabs, int tabIndex) { + this.tabs = tabs; + this.tabIndex = tabIndex; + } + + @Override + public void propertyChange(PropertyChangeEvent e) { + String name = e.getPropertyName(); + if (name.equals(TabInfo.TITLE_PROPERTY)) { + tabs.setTitleAt(tabIndex, (String) e.getNewValue()); + } else if (name.equals(TabInfo.TOOL_TIP_TEXT_PROPERTY)) { + tabs.setToolTipTextAt(tabIndex, (String) e.getNewValue()); + } else if (name.equals(TabInfo.FOREGROUND_PROPERTY)) { + tabs.setForegroundAt(tabIndex, (Color) e.getNewValue()); + } else if (name.equals(TabInfo.BACKGROUND_PROPERTY)) { + tabs.setBackgroundAt(tabIndex, (Color) e.getNewValue()); + } else if (name.equals(TabInfo.MNEMONIC_PROPERTY)) { + tabs.setMnemonicAt(tabIndex, (Integer) e.getNewValue()); + } else if (name.equals(TabInfo.DISPLAYED_MNEMONIC_INDEX_PROPERTY)) { + tabs.setDisplayedMnemonicIndexAt(tabIndex, (Integer) e.getNewValue()); + } else if (name.equals(TabInfo.ICON_PROPERTY)) { + tabs.setIconAt(tabIndex, (Icon) e.getNewValue()); + } else if (name.equals(TabInfo.DISABLED_ICON_PROPERTY)) { + tabs.setDisabledIconAt(tabIndex, (Icon) e.getNewValue()); + } + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/Table.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/Table.java new file mode 100644 index 0000000..dcaf0a9 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/Table.java @@ -0,0 +1,58 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.swing; + +import javax.swing.JPanel; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.LayoutManager; + +/** + * Panel which uses a {@link GridBagLayout} by default. + * + * @author Ethan Nicholas + */ +public class Table extends JPanel { + + private static final long serialVersionUID = 1L; + public static final Insets DEFAULT_INSETS = new Insets(3, 3, 3, 3); + private GridBagConstraints tableConstraints = new GridBagConstraints(); + private GridBagConstraints rowConstraints = null; + private GridBagConstraints cellConstraints = null; + + public Table() { + super.setLayout(new GridBagLayout()); + + tableConstraints.insets = DEFAULT_INSETS; + } + + @Override + public void setLayout(LayoutManager layout) { + // do nothing + } + + public GridBagConstraints getTableConstraints() { + return tableConstraints; + } + + public GridBagConstraints getRowConstraints() { + return rowConstraints; + } + + public GridBagConstraints getCellConstraints() { + return cellConstraints; + } + + public void newRow() { + tableConstraints.gridy++; + rowConstraints = (GridBagConstraints) tableConstraints.clone(); + } + + public void newCell() { + rowConstraints.gridx++; + cellConstraints = (GridBagConstraints) rowConstraints.clone(); + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/VBox.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/VBox.java new file mode 100644 index 0000000..7321e19 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/VBox.java @@ -0,0 +1,94 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.swing; + +import javax.swing.JPanel; +import java.awt.Insets; + +/** + * Panel which uses a {@link VBoxLayout} by default. + * + * @author Ethan Nicholas + */ +public class VBox extends JPanel { + + private static final long serialVersionUID = 1L; + public static final String SPACING_PROPERTY = "spacing"; + public static final String MARGIN_PROPERTY = "margin"; + public static final String HORIZONTAL_ALIGNMENT_PROPERTY = "horizontalAlignment"; + public static final String VERTICAL_ALIGNMENT_PROPERTY = "verticalAlignment"; + private Insets margin; + + public VBox() { + super(new VBoxLayout()); + } + + /** + * Returns the spacing between components, in pixels. Spacing is applied between components only, + * not to the top or bottom of the container. + * + * @return spacing between components + */ + public int getSpacing() { + return ((VBoxLayout) getLayout()).getSpacing(); + } + + /** + * Sets the spacing between components. Spacing is applied between components only, + * not to the top or bottom of the container. + * + * @param spacing new spacing value + */ + public void setSpacing(int spacing) { + int oldValue = getSpacing(); + ((VBoxLayout) getLayout()).setSpacing(spacing); + firePropertyChange(SPACING_PROPERTY, oldValue, spacing); + revalidate(); + } + + public int getHorizontalAlignment() { + return ((VBoxLayout) getLayout()).getHorizontalAlignment(); + } + + public void setHorizontalAlignment(int horizontalAlignment) { + int oldValue = getHorizontalAlignment(); + ((VBoxLayout) getLayout()).setHorizontalAlignment(horizontalAlignment); + firePropertyChange(HORIZONTAL_ALIGNMENT_PROPERTY, oldValue, horizontalAlignment); + revalidate(); + } + + public int getVerticalAlignment() { + return ((VBoxLayout) getLayout()).getVerticalAlignment(); + } + + public void setVerticalAlignment(int verticalAlignment) { + int oldValue = getVerticalAlignment(); + ((VBoxLayout) getLayout()).setVerticalAlignment(verticalAlignment); + firePropertyChange(VERTICAL_ALIGNMENT_PROPERTY, oldValue, verticalAlignment); + revalidate(); + } + + public Insets getMargin() { + return margin; + } + + public void setMargin(Insets margin) { + Insets oldValue = this.margin; + this.margin = (Insets) margin.clone(); + firePropertyChange(MARGIN_PROPERTY, oldValue, margin); + } + + @Override + public Insets getInsets() { + Insets result = super.getInsets(); + if (margin != null) { + result.top += margin.top; + result.left += margin.left; + result.right += margin.right; + result.bottom += margin.bottom; + } + return result; + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/VBoxLayout.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/VBoxLayout.java new file mode 100644 index 0000000..4f1b46c --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/VBoxLayout.java @@ -0,0 +1,127 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.swing; + +import javax.swing.SwingConstants; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Insets; +import java.awt.LayoutManager; + +/** + * Vertical box layout. The layout rules followed by this class are quite different than the core BoxLayout class, + * and in general represent a more useful algorithm. + * + * @author Ethan Nicholas + */ +public class VBoxLayout implements LayoutManager { + + private int spacing = 6; + private int horizontalAlignment = SwingConstants.LEFT; + private int verticalAlignment = SwingConstants.TOP; + + public int getSpacing() { + return spacing; + } + + public void setSpacing(int spacing) { + this.spacing = spacing; + } + + public int getHorizontalAlignment() { + return horizontalAlignment; + } + + public void setHorizontalAlignment(int horizontalAlignment) { + this.horizontalAlignment = horizontalAlignment; + } + + public int getVerticalAlignment() { + return verticalAlignment; + } + + public void setVerticalAlignment(int verticalAlignment) { + this.verticalAlignment = verticalAlignment; + } + + @Override + public void addLayoutComponent(String name, Component comp) { + } + + @Override + public void layoutContainer(Container parent) { + Insets insets = parent.getInsets(); + int parentWidth = parent.getSize().width - insets.left - insets.right; + int count = parent.getComponentCount(); + Dimension preferredSize = parent.getPreferredSize(); + int y; + switch (verticalAlignment) { + case SwingConstants.TOP: + y = insets.top; + break; + case SwingConstants.CENTER: + y = insets.top + (parent.getHeight() - preferredSize.height) / 2; + break; + case SwingConstants.BOTTOM: + y = insets.top + (parent.getHeight() - preferredSize.height); + break; + default: + throw new IllegalArgumentException("invalid vertical alignment: " + verticalAlignment); + } + + for (int i = 0; i < count; i++) { + Component component = parent.getComponent(i); + Dimension childPreferredSize = component.getPreferredSize(); + int width = Math.min(childPreferredSize.width, parentWidth); + int x; + switch (horizontalAlignment) { + case SwingConstants.LEFT: + x = insets.left; + break; + case SwingConstants.CENTER: + x = insets.left + (parentWidth - childPreferredSize.width) / 2; + break; + case SwingConstants.RIGHT: + x = insets.left + (parentWidth - childPreferredSize.width); + break; + default: + throw new IllegalArgumentException("invalid horizontal alignment: " + horizontalAlignment); + } + component.setBounds(x, y, width, childPreferredSize.height); + y += childPreferredSize.height + spacing; + } + } + + @Override + public Dimension minimumLayoutSize(Container parent) { + int width = 0; + int height = (parent.getComponentCount() - 1) * spacing; + for (int i = parent.getComponentCount() - 1; i >= 0; i--) { + Dimension minimumSize = parent.getComponent(i).getMinimumSize(); + width = Math.max(width, minimumSize.width); + height += minimumSize.height; + } + Insets insets = parent.getInsets(); + return new Dimension(width + insets.left + insets.right, height + insets.top + insets.bottom); + } + + @Override + public Dimension preferredLayoutSize(Container parent) { + int width = 0; + int height = (parent.getComponentCount() - 1) * spacing; + for (int i = parent.getComponentCount() - 1; i >= 0; i--) { + Dimension preferredSize = parent.getComponent(i).getPreferredSize(); + width = Math.max(width, preferredSize.width); + height += preferredSize.height; + } + Insets insets = parent.getInsets(); + return new Dimension(width + insets.left + insets.right, height + insets.top + insets.bottom); + } + + @Override + public void removeLayoutComponent(Component comp) { + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/editor/ClassCellEditor.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/editor/ClassCellEditor.java new file mode 100644 index 0000000..8c5e68b --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/editor/ClassCellEditor.java @@ -0,0 +1,119 @@ +/* +* *##% ui + * Copyright (C) 2008 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ +package jaxx.runtime.swing.editor; + +import org.apache.commons.beanutils.Converter; +import org.nuiton.util.ConverterUtil; + +import javax.swing.DefaultCellEditor; +import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.event.CellEditorListener; +import javax.swing.table.TableCellEditor; +import java.awt.Component; +import java.util.EventObject; + +/** + * A class cell editor (fork from comandline project). + * + * @author chemit + */ +public class ClassCellEditor implements TableCellEditor { + + protected TableCellEditor delegate; + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + + String valStr = (value + "").trim(); + if (valStr.equals("null")) { + valStr = ""; + } else if (valStr.startsWith("class ")) { + valStr = valStr.substring(6); + } + Component comp; + comp = getDelegate().getTableCellEditorComponent(table, valStr, isSelected, row, column); + return comp; + } + + @Override + public Object getCellEditorValue() { + Object o = !hasDelegate() ? null : delegate.getCellEditorValue(); + if (o == null) { + return null; + } + Converter converter = ConverterUtil.getConverter(Class.class); + + try { + if (converter != null) { + return converter.convert(Class.class, o); + } + o = Class.forName(o + ""); + } catch (Exception e) { + o = null; + } + return o; + } + + @Override + public boolean isCellEditable(EventObject anEvent) { + return !hasDelegate() || delegate.isCellEditable(anEvent); + } + + @Override + public boolean shouldSelectCell(EventObject anEvent) { + return hasDelegate() && delegate.shouldSelectCell(anEvent); + } + + @Override + public boolean stopCellEditing() { + return !hasDelegate() || delegate.stopCellEditing(); + } + + @Override + public void cancelCellEditing() { + if (hasDelegate()) { + delegate.cancelCellEditing(); + } + } + + @Override + public void addCellEditorListener(CellEditorListener l) { + if (hasDelegate()) { + delegate.addCellEditorListener(l); + } + } + + @Override + public void removeCellEditorListener(CellEditorListener l) { + if (hasDelegate()) { + delegate.removeCellEditorListener(l); + } + } + + protected TableCellEditor getDelegate() { + if (delegate == null) { + delegate = new DefaultCellEditor(new JTextField()); + } + return delegate; + } + + protected boolean hasDelegate() { + return delegate != null; + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/editor/EnumEditor.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/editor/EnumEditor.java new file mode 100644 index 0000000..0bd0b1f --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/editor/EnumEditor.java @@ -0,0 +1,57 @@ +/* + * *##% Lutin utilities library + * Copyright (C) 2004 - 2008 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ +package jaxx.runtime.swing.editor; + +import javax.swing.JComboBox; +import java.util.EnumSet; +import org.nuiton.util.ReflectUtil; + +/** + * Une éditeur d'enum. + * + * @param <E> le type d'enumeration a editer. + * + * @author chemit + * + * @since 1.6.0 + */ +public class EnumEditor<E extends Enum<E>> extends JComboBox { + + /** serialVersionUID */ + private static final long serialVersionUID = 2693771553067104538L; + protected Class<E> type; + + public static <E extends Enum<E>> EnumEditor<E> newEditor(Class<E> type) { + return new EnumEditor<E>(type); + } + + public EnumEditor(Class<E> type) { + super(buildModel(type)); + } + + @Override + public E getSelectedItem() { + return (E) super.getSelectedItem(); + } + + protected static <E extends Enum<E>> Object[] buildModel(Class<E> type) { + Class<E> enumClass = ReflectUtil.getEnumClass(type); + EnumSet<E> result = EnumSet.allOf(enumClass); + return result.toArray(new Object[result.size()]); + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/editor/LocaleEditor.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/editor/LocaleEditor.java new file mode 100644 index 0000000..e6a37da --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/editor/LocaleEditor.java @@ -0,0 +1,64 @@ +/* +* *##% Lutin utilities library + * Copyright (C) 2004 - 2008 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ +package jaxx.runtime.swing.editor; + +import javax.swing.JComboBox; +import java.util.Locale; +import org.nuiton.i18n.I18n; + +/** + * A {@link Locale} editor. + * <p/> + * use the static method to have an instance of editor {@link #newEditor(java.util.Locale[])} + * <p/> + * If no locale is given to this method, it will go and seek via + * {@link org.nuiton.i18n.I18nLoader#getLocales()} all loaded locales in i18n system + * + * @author chemit + * @since 1.6.0 + */ +public class LocaleEditor extends JComboBox { + + /** serialVersionUID */ + private static final long serialVersionUID = -6777873426011538807L; + + protected Locale[] type; + + public static LocaleEditor newEditor(Locale... type) { + return new LocaleEditor(type); + } + + public LocaleEditor(Locale... type) { + super(buildModel(type)); + } + + @Override + public Locale getSelectedItem() { + return (Locale) super.getSelectedItem(); + } + + protected static Locale[] buildModel(Locale... type) { + if (type.length > 0) { + return type; + } + // get availables locales registred in I18n system + type = I18n.getLoader().getLocales(); + return type; + } + +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/navigation/NavigationTreeCellRenderer.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/navigation/NavigationTreeCellRenderer.java new file mode 100644 index 0000000..b353e4b --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/navigation/NavigationTreeCellRenderer.java @@ -0,0 +1,93 @@ +package jaxx.runtime.swing.navigation; + +import jaxx.runtime.JAXXContext; +import jaxx.runtime.swing.navigation.NavigationTreeModel.NavigationTreeNode; +import jaxx.runtime.swing.navigation.NavigationUtil.NodeRenderer; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.util.StringUtil; + +import javax.swing.JTree; +import javax.swing.UIManager; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.TreeCellRenderer; +import javax.swing.tree.TreePath; +import java.awt.Component; + +/** + * A simple cell renderer which use the {@link NavigationTreeNode#renderer} to display node. + * + * @author chemit + */ +public class NavigationTreeCellRenderer implements TreeCellRenderer { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private final Log log = LogFactory.getLog(NavigationTreeCellRenderer.class); + + protected JAXXContext context; + + protected DefaultTreeCellRenderer delegate; + + protected static long t = 0; + + public NavigationTreeCellRenderer(JAXXContext context) { + this.context = context; + UIManager.put("Tree.rendererFillBackground", false); + delegate = new DefaultTreeCellRenderer(); + } + + public NavigationTreeCellRenderer(JAXXContext context, DefaultTreeCellRenderer delegate) { + this.context = context; + this.delegate = delegate; + } + + @Override + public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { + TreePath path = tree.getPathForRow(row); + if (path == null) { + return delegate; + } + + if (value != null) { + long t0 = System.nanoTime(); + NodeRenderer renderer = getNodeRenderer(value); + long t1 = System.nanoTime(); + if (renderer != null) { + value = renderer.toString(context); + long t2 = System.nanoTime(); + if (log.isDebugEnabled()) { + log.debug("use renderer [" + (t++) + "]<" + row + ">" + renderer.decorator + " <" + StringUtil.convertTime(t0, t1) + "/" + StringUtil.convertTime(t1, t2) + ">"); + } + } + } + + return delegate.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); + } + + /** + * @param value the value which should be a node + * @return the nodeRenderer attached to node via the {@link NavigationTreeNode#userObject}, + * or <code>null</code> if value is null, or value is not int good type. + */ + protected NodeRenderer getNodeRenderer(Object value) { + NodeRenderer render = null; + + if (value != null) { + NavigationTreeNode node = getNode(value); + + if (node != null && node.getUserObject() instanceof NodeRenderer) { + render = (NodeRenderer) node.getUserObject(); + } + } + return render; + } + + /** + * @param value the value which should be a node + * @return the cast {@link NavigationTreeNode}, or <code>null</code> if value is null. + */ + protected NavigationTreeNode getNode(Object value) { + return value instanceof NavigationTreeNode ? (NavigationTreeNode) value : null; + } + +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/navigation/NavigationTreeHandler.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/navigation/NavigationTreeHandler.java new file mode 100644 index 0000000..5e26a4e --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/navigation/NavigationTreeHandler.java @@ -0,0 +1,249 @@ +package jaxx.runtime.swing.navigation; + +import java.awt.Component; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.DefaultTreeSelectionModel; +import javax.swing.tree.TreePath; +import jaxx.runtime.JAXXAction; +import jaxx.runtime.JAXXContext; +import jaxx.runtime.JAXXContextEntryDef; +import jaxx.runtime.JAXXObject; +import jaxx.runtime.swing.navigation.NavigationTreeModel.NavigationTreeNode; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * The handler of a navigation tree. + * + * This is also the selection model to use, since we must check before moving + * from a node we can not just listen selection model changed, we must control + * it. + * + * + * @author tony + * @since 1.3 + */ +public abstract class NavigationTreeHandler extends DefaultTreeSelectionModel { + + private static final long serialVersionUID = 1L; + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private final Log log = LogFactory.getLog(NavigationTreeHandler.class); + static public final String NAVIGATION_SELECTED_BEAN = "navigation-selected-bean"; + static public final JAXXContextEntryDef<String> NAVIGATION_SELECTED_PATH_ENTRY_DEF = JAXXContextEntryDef.newDef("navigation-selected-path", String.class); + static public final JAXXContextEntryDef<NavigationTreeNode> NAVIGATION_SELECTED_NODE_ENTRY_DEF = JAXXContextEntryDef.newDef("navigation-selected-node", NavigationTreeNode.class); + + /** defined the stategy of instanciation of ui */ + public enum Strategy { + + /** instanciate a ui for a node */ + PER_NODE, + /** instanciate only one a ui for a type,nodes will share the instanciation */ + PER_UI_TYPE + } + /** la classe d'ui par defaut, associé à un noeud de l'arbe */ + protected Class<? extends JAXXObject> defaultUIClass; + protected Class<? extends JAXXAction> defaultUIHandlerClass; + /** l'ui contenant l'arbre de navigation */ + protected JAXXObject context; + protected Strategy strategy; + + protected NavigationTreeHandler(Class<? extends JAXXObject> defaultUIClass, Class<? extends JAXXAction> defaultUIHandlerClass, JAXXObject context, Strategy strategy) { + this.defaultUIClass = defaultUIClass; + this.defaultUIHandlerClass = defaultUIHandlerClass; + this.context = context; + this.strategy = strategy; + addTreeSelectionListener(new TreeSelectionListener() { + + @Override + public void valueChanged(TreeSelectionEvent event) { + if (event.getOldLeadSelectionPath() != null && event.getOldLeadSelectionPath().equals(event.getPath())) { + // do not treate this if no path changed + return; + } + NavigationTreeNode node = (NavigationTreeNode) event.getPath().getLastPathComponent(); + selectNodeUI(node); + } + }); + } + + protected abstract NavigationTreeModel getNavigationTreeModel(); + + /** + * @return le composent actuellement visible associé au noeud courant ou au noeud précédent + * lors d'un changement de noeud. + */ + protected abstract Component getCurrentUI(); + + /** + * @param node le noeud associé à l'ui à retrouver + * @return l'ui associé au novueau noeud sélectionné + */ + protected abstract Component getUI(NavigationTreeNode node); + + /** + * @param component le composent actuellement visible + * @return <code>true</code> si le composent a bien été fermé, <code>false</code> sinon + * @throws Exception if any + */ + protected abstract boolean closeUI(Component component) throws Exception; + + /** + * Instancie une nouvelle ui associé à un noeud de l'arbre de navigation + * + * @param node le noeud associé à l'ui à créer + * @return la nouvelle ui associée au noeud + * @throws Exception if any + */ + protected abstract Component createUI(NavigationTreeNode node) throws Exception; + + protected abstract JAXXContext createUIContext(NavigationTreeNode node) throws Exception; + + /** + * Ouvre l'ui associée au noeud sélectionné dans l'arbre de navigation. + * + * @param newUI l'ui associé au noeud sélectionné à ouvrir + * @param node le node de l'ui a ouvrir + * @throws Exception if any + */ + protected abstract void openUI(Component newUI, NavigationTreeNode node) throws Exception; + + /** + * Traitement des exceptions. + * + * @param e l'erreur recontrée (ou null si pas d"erreur) + */ + protected abstract void treateError(Exception e); + + /** + * Prepare le nouveau noeud sélectionné. + * + * @param node le noeud a preparer + * @return le noeud selectionné et preparé + */ + protected NavigationTreeNode prepareNode(NavigationTreeNode node) { + + if (node.getJaxxClass() == null) { + // no ui is associated with this node, display a empty content + node.setJaxxClass(defaultUIClass); + } + + if (node.getJaxxActionClass() == null) { + node.setJaxxActionClass(defaultUIHandlerClass); + } + return node; + } + + @Override + public void setSelectionPath(TreePath path) { + if (path.equals(getSelectionPath())) { + // stay on same node, can skip + if (log.isDebugEnabled()) { + log.debug("skip stay on path " + path); + } + return; + } + Component component = getCurrentUI(); + + try { + if (!closeUI(component)) { + if (log.isDebugEnabled()) { + log.debug("changing node canceled!"); + } + // can not changed current node + return; + } + } catch (Exception ex) { + treateError(ex); + return; + } + if (log.isDebugEnabled()) { + log.debug("will select path " + path); + } + // ok can safely select the new path + super.setSelectionPath(path); + } + + public void selectNodeUI(NavigationTreeNode node) { + + try { + + node = prepareNode(node); + + String path = node.getContextPath(); + + if (log.isTraceEnabled()) { + log.trace(path); + } + + Component newUI = getUI(node); + + // now, we are free to open the ui associated with the selected node in navigation + + // always clean cache on the node before all + node.cachedBean = null; + if (node.renderer != null) { + node.renderer.setRendererCachedValue(null); + } + // before all, attach bean in context associated with the selected node in navigation tree + Object data = getNavigationTreeModel().getJAXXContextValue(context, path); + + addSelectedBeanInContext(node, data); + + if (newUI == null) { + // instanciate a new ui associated with the selected node + newUI = createUI(node); + } + + // save in context current node context path + NAVIGATION_SELECTED_PATH_ENTRY_DEF.setContextValue(context, node.getContextPath()); + + // save in context current node + NAVIGATION_SELECTED_NODE_ENTRY_DEF.setContextValue(context, node); + + // really open the ui associated with the selected node + openUI(newUI, node); + + } catch (Exception e) { + // remove data from context + + // if any error, go back to previvous node + treateError(e); + } + } + + protected void addSelectedBeanInContext(NavigationTreeNode node, Object data) { + + if (log.isDebugEnabled()) { + log.debug("find data for contextPath <" + node.getContextPath() + "> : " + (data == null ? null : data.getClass())); + } + + context.removeContextValue(Object.class, NAVIGATION_SELECTED_BEAN); + + if (data != null) { + context.setContextValue(data, NAVIGATION_SELECTED_BEAN); + //todo should we not use this to avoid conflict in context ? + context.setContextValue(data); + } + } + + protected String getNodeConstraints(NavigationTreeNode node) { + String constraints; + switch (strategy) { + case PER_NODE: + constraints = node.getContextPath(); + break; + case PER_UI_TYPE: + constraints = node.getJaxxClass().getName(); + break; + default: + throw new IllegalArgumentException("could not find constraint for node : " + node); + } + return constraints; + } + + protected JAXXAction getJAXXAction(Class<? extends JAXXAction> jaxxActionClass) throws Exception { + JAXXAction action = jaxxActionClass.newInstance(); + return action; + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/navigation/NavigationTreeHandlerWithCardLayout.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/navigation/NavigationTreeHandlerWithCardLayout.java new file mode 100644 index 0000000..5d5c956 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/navigation/NavigationTreeHandlerWithCardLayout.java @@ -0,0 +1,119 @@ +package jaxx.runtime.swing.navigation; + +import jaxx.runtime.JAXXAction; +import jaxx.runtime.JAXXContext; +import jaxx.runtime.JAXXInitialContext; +import jaxx.runtime.JAXXObject; +import jaxx.runtime.swing.CardLayout2; +import jaxx.runtime.swing.navigation.NavigationTreeModel.NavigationTreeNode; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.swing.JPanel; +import java.awt.Component; + +/** + * Simple {@link NavigationTreeSelectionAdapter} implementation with a {@link jaxx.runtime.swing.CardLayout2} to manage components to + * associated with tree's nodes. + * <p/> + * For each node, the ui associated has a constraints in a cardlayout which is the node context path. + * <p/> + * A single container managed by the cardlayout is used to display the components associated with tree's nodes. + * + * @author chemit + */ +public abstract class NavigationTreeHandlerWithCardLayout extends NavigationTreeHandler { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private final Log log = LogFactory.getLog(NavigationTreeHandlerWithCardLayout.class); + + /** + * All components associated with a tree's node is displayed in a single container. + * + * @return the containter of components + */ + protected abstract JPanel getContentContainer(); + + /** + * the cardlayout managing components associated with tree node. The constraints + * of each component is the node contextPath. + * + * @return the layout used to display components associated with tree's nodes. + */ + protected abstract CardLayout2 getContentLayout(); + + public NavigationTreeHandlerWithCardLayout(Class<? extends JAXXObject> defaultUIClass, Class<? extends JAXXAction> defaultUIHandlerClass, JAXXObject context, Strategy strategy) { + super(defaultUIClass, defaultUIHandlerClass, context, strategy); + + if (getContentContainer() == null) { + throw new IllegalArgumentException("could not have a null 'contentContainer' in ui " + context); + } + if (getContentLayout() == null) { + throw new IllegalArgumentException("could not have a null 'contentLayout' in ui " + context); + } + } + + @Override + protected Component getCurrentUI() { + CardLayout2 layout = getContentLayout(); + JPanel container = getContentContainer(); + return layout.getVisibleComponent(container); + } + + @Override + protected Component getUI(NavigationTreeNode node) { + CardLayout2 layout = getContentLayout(); + JPanel container = getContentContainer(); + String path = getNodeConstraints(node); + return layout.contains(path) ? layout.getComponent(container, path) : null; + } + + @Override + protected void openUI(Component newUI, NavigationTreeNode node) throws Exception { + + CardLayout2 layout = getContentLayout(); + JPanel container = getContentContainer(); + // switch layout + layout.show(container, getNodeConstraints(node)); + } + + @Override + protected boolean closeUI(Component component) throws Exception { + // by default, we says that component was succesfull closed + return true; + } + + @Override + protected JAXXContext createUIContext(NavigationTreeNode node) throws Exception { + + if (node.getJaxxActionClass() == null) { + if (log.isWarnEnabled()) { + log.warn("no action associated with ui " + node.getJaxxClass()); + } + // no action associated, just + return context; + } + + JAXXAction action = getJAXXAction(node.getJaxxActionClass()); + + // init context with + JAXXInitialContext uiContext = action.init(this.context); + return uiContext; + } + + @Override + protected Component createUI(NavigationTreeNode node) throws Exception { + + JAXXContext uiContext = createUIContext(node); + + JAXXObject newUI = node.getJaxxClass().getConstructor(JAXXContext.class).newInstance(uiContext); + + if (log.isDebugEnabled()) { + log.debug("instanciate new ui " + newUI); + } + + getContentContainer().add((Component) newUI, getNodeConstraints(node)); + return (Component) newUI; + } +} + diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/navigation/NavigationTreeModel.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/navigation/NavigationTreeModel.java new file mode 100644 index 0000000..39215f1 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/navigation/NavigationTreeModel.java @@ -0,0 +1,589 @@ +package jaxx.runtime.swing.navigation; + + +import jaxx.runtime.JAXXAction; +import jaxx.runtime.JAXXContext; +import jaxx.runtime.JAXXContextEntryDef; +import jaxx.runtime.JAXXObject; +import jaxx.runtime.swing.navigation.NavigationUtil.NodeRenderer; +import org.apache.commons.jxpath.JXPathContext; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeNode; +import java.util.Enumeration; +import java.util.StringTokenizer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Le modele utilisé pour un arbre de navigation. + * <p/> + * Il est composé de {@link NavigationTreeModel.NavigationTreeNode} + * + * @author chemit + */ +public class NavigationTreeModel extends DefaultTreeModel { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private final Log log = LogFactory.getLog(NavigationTreeModel.class); + + static private final long serialVersionUID = 1L; + + /** the separator char used to produce the navigation path of a node. */ + protected final String navigationPathSeparator; + + public NavigationTreeModel(TreeNode root, String navigationPathSeparator) { + super(root); + this.navigationPathSeparator = navigationPathSeparator; + } + + @Override + public NavigationTreeNode getRoot() { + return (NavigationTreeNode) super.getRoot(); + } + + /** + * Search from the root node a node named by his fully path (concatenation of nodes + * {@link NavigationTreeNode#navigationPath} valued separated by dot. + * <p/> + * Example : + * <p/> + * <pre>$root.child1.leaf1</pre> + * + * @param path the fully path of the searched node. + * @return the node matching the fully context from the root node, or <code>null</code> if not find. + */ + public NavigationTreeNode findNode(String path) { + return findNode(getRoot(), path, (Pattern) null); + } + + /** + * Apply first the regex pattern to obtain the searched node fi the given <code>regex</code> is not null. + * <p/> + * Search then from the root node a node named by his fully path (concatenation of nodes + * {@link NavigationTreeNode#navigationPath} valued separated by {@link #navigationPathSeparator}. + * <p/> + * <p/> + * Example : + * <p/> + * <pre>$root.child1.leaf1</pre> + * + * @param path the fully path of the searched node. + * @param regex a optional regex to apply to path before searching + * @return the node matching the fully context from the root node, or <code>null</code> if not found. + */ + public NavigationTreeNode findNode(String path, String regex) { + return findNode(getRoot(), path, regex); + } + + /** + * Apply first the regex pattern to obtain the searched node. + * <p/> + * Search then from the root node a node named by his fully path (concatenation of nodes + * {@link NavigationTreeNode#navigationPath} valued separated by {@link #navigationPathSeparator}. + * <p/> + * Example : + * <p/> + * <pre>$root.child1.leaf1</pre> + * + * @param path the fully path of the searched node. + * @param regex a optional regex to apply to path before searching + * @return the node matching the fully context from the root node, or <code>null</code> if not found. + */ + public NavigationTreeNode findNode(String path, Pattern regex) { + return findNode(getRoot(), path, regex); + } + + + /** + * Search from a given root node a node named by his fully path (concatenation of nodes + * {@link NavigationTreeNode#navigationPath} valued separated by {@link #navigationPathSeparator}. + * + * @param root root node to be used + * @param path the fully path of the searched node. + * @return the node matching the fully context from the given root node, or <code>null</code> if not found. + */ + public NavigationTreeNode findNode(NavigationTreeNode root, String path) { + return findNode(root, path, (Pattern) null); + } + + /** + * Apply first the regex pattern to obtain the searched node. + * <p/> + * Search then from a given root node a node named by his fully path (concatenation of nodes) + * {@link NavigationTreeNode#navigationPath} valued separated by {@link #navigationPathSeparator}. + * + * @param root root node to be used + * @param path the fully path of the searched node. + * @param regex a previous regex to apply to path : must have a matches + * @return the node matching the fully context from the given root node, or <code>null</code> if not found. + */ + public NavigationTreeNode findNode(NavigationTreeNode root, String path, String regex) { + return findNode(root, path, regex == null ? null : Pattern.compile(regex)); + } + + /** + * Apply first the regex pattern to obtain the searched node. + * <p/> + * Search then from a given root node a node named by his fully path (concatenation of nodes + * {@link NavigationTreeNode#navigationPath} valued separated by {@link #navigationPathSeparator}. + * + * @param root root node to be used + * @param path the fully path of the searched node. + * @param regex a previous regex to apply to path : must have a matches + * @return the node matching the fully context from the given root node, or <code>null</code> if not found. + */ + public NavigationTreeNode findNode(NavigationTreeNode root, String path, Pattern regex) { + if (regex != null) { + Matcher matcher = regex.matcher(path); + if (!matcher.matches() || matcher.groupCount() < 1) { + log.warn("no matching regex " + regex + " to " + path); + return null; + } + path = matcher.group(1); + if (log.isDebugEnabled()) { + log.debug("matching regex " + regex + " : " + path); + } + } + StringTokenizer stk = new StringTokenizer(path, navigationPathSeparator); + NavigationTreeNode result = root; + // pas the first token (matches the root node) + if (root.isRoot() && stk.hasMoreTokens()) { + String rootPath = stk.nextToken(); + if (!rootPath.equals(root.getNavigationPath())) { + return null; + } + } + while (stk.hasMoreTokens()) { + result = result.getChild(stk.nextToken()); + } + return result; + } + + + /** + * Obtain the associated bean value from context corresponding to node from given navigation path. + * + * @param context the context where to seek value + * @param navigationPath the current context path of the node + * @return the value associated in context with the given navigation path + */ + public Object getJAXXContextValue(JAXXContext context, String navigationPath) { + Object result; + NavigationTreeNode node = findNode(navigationPath, (Pattern) null); + result = getJAXXContextValue(context, node); + return result; + } + + /** + * Obtain the associated bean value from context corresponding to node + * + * @param context the context where to seek value + * @param node the current node + * @return the value associated in context with the given node. + */ + public Object getJAXXContextValue(JAXXContext context, NavigationTreeNode node) { + if (node == null) { + return null; + //fixme should throw a NPE exception + //throw new NullPointerException("node can not be null"); + } + return node.getJAXXContextValue(context); + } + + + @Override + public void nodeChanged(TreeNode node) { + nodeChanged(node, false); + } + + public void nodeChanged(TreeNode node, boolean deep) { + NavigationTreeNode n = (NavigationTreeNode) node; + n.clearCache(!deep); + super.nodeChanged(node); + if (deep) { + Enumeration<?> childs = node.children(); + while (childs.hasMoreElements()) { + NavigationTreeNode o = (NavigationTreeNode) childs.nextElement(); + nodeChanged(o, true); + } + } + } + + /** + * la représentation d'un noeud dans le modele {@link NavigationTreeModel} + * + * @author chemit + */ + public class NavigationTreeNode extends DefaultMutableTreeNode { + + private static final long serialVersionUID = 1L; + + /** pour representer le context du noeud. */ + protected String navigationPath; + + /** + * the cached complete navigation path from root node + * used for performance issues. + */ + protected String cachedNavigationPath; + + /** the JAXXObject class associated with this node (can be null) */ + protected Class<? extends JAXXObject> jaxxClass; + + /** the JAXXAction class associated with this node and will be put in ui context */ + protected Class<? extends JAXXAction> jaxxActionClass; + + /** the definition of the JAXXContext entry associated to this node, if null will seek in parent */ + protected JAXXContextEntryDef<?> jaxxContextEntryDef; + + /** jxPath to process to obtain real value associated from context with the node (can be null) */ + protected String jaxxContextEntryPath; + + /** cache of bean associated with bean to improve performance */ + protected transient Object cachedBean; + + /** renderer of the node */ + protected NodeRenderer renderer; + + /** + * The type of the related bean associated with the node. + * <p/> + * Note: This type is here to override the NodeRenderer internalClass, since + * we could need to override this data. + * <p/> + * If this property is let to null, then we will use the NodeRenderer one + */ + protected Class<?> internalClass; + + public NavigationTreeNode(Object renderer, + Object jaxxContextEntryDef, + String navigationPath, + Class<? extends JAXXObject> jaxxClass, + Class<? extends JAXXAction> jaxxActionClass) { + super(renderer); + if (renderer instanceof NodeRenderer) { + // the renderer must keep a reference of the node + this.renderer = (NodeRenderer) renderer; + this.renderer.setNode(this); + } else if (renderer instanceof String) { + // nothing special to be done + } else if (renderer != null) { + // wrong renderer type + throw new IllegalArgumentException("to define a renderer, must be a String (simple libelle) or a " + NodeRenderer.class + ", but was " + renderer); + } + this.navigationPath = navigationPath; + this.jaxxClass = jaxxClass; + this.jaxxActionClass = jaxxActionClass; + + if (jaxxContextEntryDef instanceof JAXXContextEntryDef<?>) { + this.jaxxContextEntryDef = ((JAXXContextEntryDef<?>) jaxxContextEntryDef); + } else if (jaxxContextEntryDef instanceof String) { + this.jaxxContextEntryPath = (String) jaxxContextEntryDef; + } else if (jaxxContextEntryDef != null) { + // wrong context definition type + throw new IllegalArgumentException("to define a context link, must be a String (jxpath) or a " + JAXXContextEntryDef.class + ", but was " + jaxxContextEntryDef); + } + } + + public NavigationTreeNode(Object renderer, + JAXXContextEntryDef<?> jaxxContextEntryDef, + String jaxxContextEntryPath, + String navigationPath, + Class<? extends JAXXObject> jaxxClass, + Class<? extends JAXXAction> jaxxActionClass) { + super(renderer); + if (renderer instanceof NodeRenderer) { + // the renderer must keep a reference of the node + this.renderer = (NodeRenderer) renderer; + this.renderer.setNode(this); + } else if (renderer instanceof String) { + // nothing special to be done + } else if (renderer != null) { + // wrong renderer type + throw new IllegalArgumentException("to define a renderer, must be a String (simple libelle) or a " + NodeRenderer.class + ", but was " + renderer); + } + this.navigationPath = navigationPath; + this.jaxxClass = jaxxClass; + this.jaxxActionClass = jaxxActionClass; + this.jaxxContextEntryDef = jaxxContextEntryDef; + this.jaxxContextEntryPath = jaxxContextEntryPath; + } + + public String getNavigationPath() { + return navigationPath; + } + + public void setNavigationPath(String navigationPath) { + this.navigationPath = navigationPath; + } + + public Class<? extends JAXXObject> getJaxxClass() { + return jaxxClass; + } + + public void setJaxxClass(Class<? extends JAXXObject> jaxxClass) { + this.jaxxClass = jaxxClass; + } + + public void setInternalClass(Class<?> internalClass) { + this.internalClass = internalClass; + } + + public Class<? extends JAXXAction> getJaxxActionClass() { + return jaxxActionClass; + } + + public void setJaxxActionClass(Class<? extends JAXXAction> jaxxActionClass) { + this.jaxxActionClass = jaxxActionClass; + } + + public JAXXContextEntryDef<?> getJaxxContextEntryDef() { + return jaxxContextEntryDef; + } + + public void setJaxxContextEntryDef(JAXXContextEntryDef<?> jaxxContextEntryDef) { + this.jaxxContextEntryDef = jaxxContextEntryDef; + } + + public String getJaxxContextEntryPath() { + return jaxxContextEntryPath; + } + + public void setJaxxContextEntryPath(String jaxxContextEntryPath) { + this.jaxxContextEntryPath = jaxxContextEntryPath; + } + + public Class<?> getInternalClass() { + return internalClass == null ? renderer.getInternalClass() : internalClass; + } + + /** @return the fully context pathof the node from the root node to this. */ + public String getContextPath() { + if (cachedNavigationPath == null) { + TreeNode[] path = getPath(); + StringBuilder sb = new StringBuilder(); + for (TreeNode treeNode : path) { + NavigationTreeNode myNode = (NavigationTreeNode) treeNode; + sb.append(navigationPathSeparator).append(myNode.getNavigationPath()); + } + cachedNavigationPath = sb.substring(1); + } + return cachedNavigationPath; + } + + @Override + public NavigationTreeNode getChildAt(int index) { + return (NavigationTreeNode) super.getChildAt(index); + } + + @Override + public NavigationTreeNode getParent() { + return (NavigationTreeNode) super.getParent(); + } + + /** + * @param navigationPath the name of the {@link #navigationPath} to be matched in the cild of this node. + * @return the child of this node with given {@link # navigationPath} value. + */ + public NavigationTreeNode getChild(String navigationPath) { + for (int i = 0, max = getChildCount(); i < max; i++) { + NavigationTreeNode son = getChildAt(i); + if (navigationPath.equals(son.getNavigationPath())) { + return son; + } + } + return null; + } + + /** + * Obtain the associated bean value from context corresponding to node + * + * @param context the context to seek + * @return the value associated in context with the given context path + */ + public Object getJAXXContextValue(JAXXContext context) { + Object result; + + if (cachedBean != null) { + // use cached bean + return cachedBean; + } + + if (getJaxxContextEntryDef() != null && jaxxContextEntryPath == null) { + // the node maps directly a value in context, with no jxpath resolving + result = getJaxxContextEntryDef().getContextValue(context); + // save in cache + setCachedBean(result); + return result; + } + // find the first ancestor node with a context def + NavigationTreeNode parentNode = getFirstAncestorWithDef(); + if (parentNode == null) { + log.warn("could not find a ancestor node with a definition of a context entry from node (" + this + ")"); + // todo must be an error + // no parent found + return null; + } + + Object parentBean = parentNode.getJaxxContextEntryDef().getContextValue(context); + + if (parentBean == null) { + // must be an error no bean found + log.warn("culd not find a bean attached in context from context entry definition " + parentNode.getJaxxContextEntryDef()); + return null; + } + + if (parentNode.jaxxContextEntryPath != null) { + // apply the jxpath on parentBean + JXPathContext jxcontext = JXPathContext.newContext(parentBean); + + parentBean = jxcontext.getValue(parentNode.jaxxContextEntryPath); + } + + // save in cache + parentNode.setCachedBean(parentBean); + + if (this == parentNode) { + // current node is the node matching the context entry value and no jxpath is found + return parentBean; + } + + if (jaxxContextEntryPath == null) { + // todo must be an error + log.warn("must find a jaxxContextEntryPath on node (" + this + ")"); + return null; + } + + String jxpathExpression = computeJXPath(jaxxContextEntryPath, parentNode); + + if (jxpathExpression == null) { + /// todo must be an error + log.warn("could not build jxpath from node " + parentNode + " to " + this); + // could not retreave the jxpath... + return null; + } + if (jxpathExpression.startsWith("[")) { + // special case when we want to access a collection + jxpathExpression = '.' + jxpathExpression; + } + if (log.isDebugEnabled()) { + log.debug("jxpath : " + jxpathExpression); + } + + JXPathContext jxcontext = JXPathContext.newContext(parentBean); + + result = jxcontext.getValue(jxpathExpression); + + // save in cache + setCachedBean(result); + + return result; + } + + /** + * @return the first ancestor with a none null {@link #jaxxContextEntryDef} + * or <code>null</code> if none find.. + */ + protected NavigationTreeNode getFirstAncestorWithDef() { + if (jaxxContextEntryDef != null) { + return this; + } + return getParent() == null ? null : getParent().getFirstAncestorWithDef(); + } + + protected String computeJXPath(String expr, NavigationTreeNode parentNode) { + if (parentNode == this) { + // reach the parent limit node, return the expr computed + return expr; + } + int firstIndex = expr.indexOf(".."); + int lastIndex = expr.lastIndexOf(".."); + + if (firstIndex == -1) { + // this is a error, since current node is not parent limit node, + // we must find somewhere a way to go up in nodes + throw new IllegalArgumentException(expr + " should contains at least one \"..\""); + } + + if (firstIndex != 0) { + // this is a error, the ../ must be at the beginning of the expression + throw new IllegalArgumentException("\"..\" must be at the beginning but was : " + expr); + } + + NavigationTreeNode ancestor = getParent(); + + if (firstIndex == lastIndex) { + // found only one go up, so must be substitute by the parent node context + + String newExpr = expr.substring(2); + //String newExpr = expr.substring(expr.startsWith("../") ? 3 : 2); + + if (getParent().equals(parentNode)) { + + // parent node is the final parent node, so no substitution needed + return newExpr; + //return parentNode.computeJXPath(newExpr, parentNode); + } + + // ancestor must have a jaxxContextEntryPath + if (ancestor.jaxxContextEntryPath == null) { + throw new IllegalArgumentException("with the expression " + expr + ", the ancestor node (" + ancestor + ") must have a jaxxContextEntryPath definition, but was not "); + } + + newExpr = ancestor.jaxxContextEntryPath + newExpr; + + return ancestor.computeJXPath(newExpr, parentNode); + } + + // have more than one go up, so the ancestor node can not have a jaxxContextEntryPath + if (ancestor.jaxxContextEntryPath != null) { + throw new IllegalArgumentException("with the expression " + expr + ", the ancestor node can not have a jaxxContextEntryPath definition"); + } + + // substitute the last ..[/] and delegate to ancestor + String newExpr = expr.substring(0, lastIndex - 1) + expr.substring(lastIndex + (expr.charAt(lastIndex + 3) == '/' ? 3 : 2)); + + return ancestor.computeJXPath(newExpr, parentNode); + } + + public void clearCache() { + clearCache(false); + } + + public void clearCache(boolean deep) { + + // clear bean cache + cachedBean = null; + + // clear context navigation cache + cachedNavigationPath = null; + + // clear render cache + if (renderer != null) { + renderer.setRendererCachedValue(null); + } + + if (deep) { + // clear cache in childs + Enumeration<?> childs = this.children(); + while (childs.hasMoreElements()) { + NavigationTreeNode o = (NavigationTreeNode) childs.nextElement(); + o.clearCache(); + } + } + } + + public Object getCachedBean() { + return cachedBean; + } + + public void setCachedBean(Object cachedBean) { + this.cachedBean = cachedBean; + } + } + +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/navigation/NavigationTreeModelBuilder.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/navigation/NavigationTreeModelBuilder.java new file mode 100644 index 0000000..121b119 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/navigation/NavigationTreeModelBuilder.java @@ -0,0 +1,152 @@ +package jaxx.runtime.swing.navigation; + +import jaxx.runtime.Decorator; +import jaxx.runtime.JAXXAction; +import jaxx.runtime.JAXXContextEntryDef; +import jaxx.runtime.JAXXObject; +import jaxx.runtime.swing.navigation.NavigationTreeModel.NavigationTreeNode; +import jaxx.runtime.swing.navigation.NavigationUtil.NodeRenderer; + +/** @author chemit */ +public class NavigationTreeModelBuilder { + + protected NavigationTreeModel model; + + public NavigationTreeModelBuilder(String navigationSeparator) { + model = new NavigationTreeModel(null, navigationSeparator); + } + + public NavigationTreeModel getModel() { + return model; + } + + public NavigationTreeNode build(NavigationTreeNode parentNode, String libelle, + JAXXContextEntryDef entryDef, + String entryPath, + String contextName, + Class<? extends JAXXObject> uiClass, + Class<? extends JAXXAction> actionClass) { + NavigationTreeNode node = model.new NavigationTreeNode(new NodeRenderer(libelle), entryDef, entryPath, contextName, uiClass, actionClass); + return addChildNode(parentNode, node); + } + + public NavigationTreeNode build(NavigationTreeNode parentNode, String libelle, + JAXXContextEntryDef entryDef, + String contextName, + Class<? extends JAXXObject> uiClass, + Class<? extends JAXXAction> actionClass) { + NavigationTreeNode node = model.new NavigationTreeNode(new NodeRenderer(libelle), entryDef, contextName, uiClass, actionClass); + return addChildNode(parentNode, node); + } + + public NavigationTreeNode build(NavigationTreeNode parentNode, String libelle, + String entryPath, + String contextName, + Class<? extends JAXXObject> uiClass, + Class<? extends JAXXAction> actionClass) { + NavigationTreeNode node = model.new NavigationTreeNode(new NodeRenderer(libelle), entryPath, contextName, uiClass, actionClass); + return addChildNode(parentNode, node); + } + + public NavigationTreeNode build(NavigationTreeNode parentNode, Decorator<?> decorator, + JAXXContextEntryDef entryDef, + String entryPath, + String contextName, + Class<? extends JAXXObject> uiClass, + Class<? extends JAXXAction> actionClass) { + NavigationTreeNode node = model.new NavigationTreeNode(new NodeRenderer(decorator), entryDef, entryPath, contextName, uiClass, actionClass); + return addChildNode(parentNode, node); + } + + public NavigationTreeNode build(NavigationTreeNode parentNode, Decorator<?> decorator, + JAXXContextEntryDef entryDef, + String contextName, + Class<? extends JAXXObject> uiClass, + Class<? extends JAXXAction> actionClass) { + NavigationTreeNode node = model.new NavigationTreeNode(new NodeRenderer(decorator), entryDef, contextName, uiClass, actionClass); + return addChildNode(parentNode, node); + } + + public NavigationTreeNode build(NavigationTreeNode parentNode, Decorator<?> decorator, + String entryPath, + String contextName, + Class<? extends JAXXObject> uiClass, + Class<? extends JAXXAction> actionClass) { + NavigationTreeNode node = model.new NavigationTreeNode(new NodeRenderer(decorator), entryPath, contextName, uiClass, actionClass); + return addChildNode(parentNode, node); + } + + protected NavigationTreeNode addChildNode(NavigationTreeNode parentNode, NavigationTreeNode node) { + if (parentNode == null) { + model.setRoot(node); + } else { + parentNode.add(node); + } + model.nodeStructureChanged(parentNode); + return node; + } + + public NavigationTreeNode removeChildNode(NavigationTreeNode node) { + NavigationTreeNode parentNode = node.getParent(); + model.removeNodeFromParent(node); + return parentNode; + } + + public static abstract class ChildBuilder<O> { + + protected NavigationTreeModelBuilder builder; + + protected ChildBuilder(NavigationTreeModelBuilder builder) { + this.builder = builder; + } + + protected abstract void init(Class<? extends O> klass); + + protected abstract Decorator<? extends O> getDecorator(O child); + + protected abstract String getJXPath(O child); + + protected abstract String getNavigationPath(O child); + + public void build(NavigationTreeNode parent, boolean cacheValues, Class<? extends O> klass, java.util.Collection<? extends O> beans, Class<? extends JAXXObject> ui, Class<? extends JAXXAction> actionClass) { + + if (beans == null || beans.isEmpty()) { + // no bean to treate + return; + } + + init(klass); + + NavigationTreeNode node; + + for (O o : beans) { + node = builder.build(parent, getDecorator(o), getJXPath(o), getNavigationPath(o), ui, actionClass); + if (cacheValues) { + // cache the bean value to improve performance + node.setCachedBean(o); + } + } + } + + public void build(NavigationTreeNode parent, boolean cacheValues, Class<? extends O> klass, O[] beans, Class<? extends JAXXObject> ui, Class<? extends JAXXAction> actionClass) { + + if (beans == null || beans.length == 0) { + // no bean to treate + return; + } + + init(klass); + + NavigationTreeNode node; + + for (O o : beans) { + node = builder.build(parent, getDecorator(o), getJXPath(o), getNavigationPath(o), ui, actionClass); + if (cacheValues) { + // cache the bean value to improve performance + node.setCachedBean(o); + } + } + } + } + +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/navigation/NavigationTreeSelectionAdapter.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/navigation/NavigationTreeSelectionAdapter.java new file mode 100644 index 0000000..f68f372 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/navigation/NavigationTreeSelectionAdapter.java @@ -0,0 +1,243 @@ +package jaxx.runtime.swing.navigation; + +import jaxx.runtime.JAXXAction; +import jaxx.runtime.JAXXContextEntryDef; +import jaxx.runtime.JAXXObject; +import jaxx.runtime.swing.navigation.NavigationTreeModel.NavigationTreeNode; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.swing.JTree; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.TreePath; +import java.awt.Component; + +/** A {@link javax.swing.event.TreeSelectionListener} implementation@author chemit */ +public abstract class NavigationTreeSelectionAdapter implements TreeSelectionListener { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private final Log log = LogFactory.getLog(NavigationTreeSelectionAdapter.class); + + //static public final String NAVIGATION_CONTEXT_PATH = "navigation-context-path"; + + //static public final String NAVIGATION_SELECTED_NODE = "navigation-selected-node"; + + static public final String NAVIGATION_SELECTED_BEAN = "navigation-selected-bean"; + + static public final JAXXContextEntryDef<String> NAVIGATION_SELECTED_PATH_ENTRY_DEF = JAXXContextEntryDef.newDef("navigation-selected-path", String.class); + + static public final JAXXContextEntryDef<NavigationTreeNode> NAVIGATION_SELECTED_NODE_ENTRY_DEF = JAXXContextEntryDef.newDef("navigation-selected-node", NavigationTreeNode.class); + + static public final JAXXContextEntryDef<Boolean> GO_BACK_DEF = JAXXContextEntryDef.newDef("goBack", Boolean.class); + + /** defined the stategy of instanciation of ui */ + public enum Strategy { + /** instanciate a ui for a node */ + PER_NODE, + /** instanciate only one a ui for a type,nodes will share the instanciation */ + PER_UI_TYPE + } + + /** la classe d'ui par defaut, associé à un noeud de l'arbe */ + protected Class<? extends JAXXObject> defaultUIClass; + + protected Class<? extends JAXXAction> defaultUIHandlerClass; + + /** l'ui contenant l'arbre de navigation */ + protected JAXXObject context; + + protected Strategy strategy; + + protected NavigationTreeSelectionAdapter(Class<? extends JAXXObject> defaultUIClass, Class<? extends JAXXAction> defaultUIHandlerClass, JAXXObject context, Strategy strategy) { + this.defaultUIClass = defaultUIClass; + this.defaultUIHandlerClass = defaultUIHandlerClass; + this.context = context; + this.strategy = strategy; + } + + + protected abstract NavigationTreeModel getNavigationTreeModel(); + + /** + * @return le composent actuellement visible associé au noeud courant ou au noeud précédent + * lors d'un changement de noeud. + */ + protected abstract Component getCurrentUI(); + + /** + * @param node le noeud associé à l'ui à retrouver + * @return l'ui associé au novueau noeud sélectionné + */ + protected abstract Component getUI(NavigationTreeNode node); + + /** + * @param event l'evenement de selection de noeud + * @param component le composent actuellement visible + * @return <code>true</code> si le composent a bien été fermé, <code>false</code> sinon + * @throws Exception if any + */ + protected abstract boolean closeUI(TreeSelectionEvent event, Component component) throws Exception; + + /** + * Instancie une nouvelle ui associé à un noeud de l'arbre de navigation + * + * @param node le noeud associé à l'ui à créer + * @return la nouvelle ui associée au noeud + * @throws Exception if any + */ + protected abstract Component createUI(NavigationTreeNode node) throws Exception; + + /** + * Ouvre l'ui associée au noeud sélectionné dans l'arbre de navigation. + * + * @param newUI l'ui associé au noeud sélectionné à ouvrir + * @param node le node de l'ui a ouvrir + * @throws Exception if any + */ + protected abstract void openUI(Component newUI, NavigationTreeNode node) throws Exception; + + /** + * Retourne au noeud précdemment sélectionné dans l'arbre de navigation, avec la possibilité de notifier + * une erreure survenue. + * + * @param event l'évènement de changement de noeud sélectionné. + * @param e l'erreur recontrée (ou null si pas d"erreur) + */ + protected abstract void goBackToPreviousNode(TreeSelectionEvent event, Exception e); + + /** + * Prepare le nouveau noeud sélectionné. + * + * @param event l'évènement de selection du noeud + * @return le noeud selectionné et preparé + */ + protected NavigationTreeNode prepareNode(TreeSelectionEvent event) { + NavigationTreeNode node = (NavigationTreeNode) event.getPath().getLastPathComponent(); + + if (node.getJaxxClass() == null) { + // no ui is associated with this node, display a empty content + node.setJaxxClass(defaultUIClass); + } + + if (node.getJaxxActionClass() == null) { + node.setJaxxActionClass(defaultUIHandlerClass); + } + return node; + } + + @Override + public void valueChanged(TreeSelectionEvent event) { + if (event.getOldLeadSelectionPath() != null && event.getOldLeadSelectionPath().equals(event.getPath())) { + // do not treate this if no path changed + return; + } + + Boolean goBack = GO_BACK_DEF.getContextValue(context); + if (goBack != null && goBack) { + // do not treate this, apsecial flag told us :) + GO_BACK_DEF.removeContextValue(context); + return; + } + + try { + + NavigationTreeNode node = prepareNode(event); + + String path = node.getContextPath(); + + if (log.isTraceEnabled()) { + log.trace(path); + } + + Component newUI = getUI(node); + Component component = getCurrentUI(); + + if (newUI != null && strategy == Strategy.PER_NODE && newUI.equals(component)) { + // call back from goto back to previous node, do nothing + return; + } + + if (!closeUI(event, component)) { + GO_BACK_DEF.setContextValue(context, Boolean.TRUE); + // previous ui was not closed, so reselect the previous node in navigation + goBackToPreviousNode(event, null); + // and quit + return; + } + + // now, we are free to open the ui associated with the selected node in navigation + + // always clean cache on the node before all + node.cachedBean = null; + if (node.renderer != null) { + node.renderer.setRendererCachedValue(null); + } + // before all, attach bean in context associated with the selected node in naivgation tree + Object data = getNavigationTreeModel().getJAXXContextValue(context, path); + + addSelectedBeanInContext(node, data); + + if (newUI == null) { + // instanciate a new ui associated with the selected node + newUI = createUI(node); + } + + // save in context current node context path + NAVIGATION_SELECTED_PATH_ENTRY_DEF.setContextValue(context, node.getContextPath()); + + // save in context current node + NAVIGATION_SELECTED_NODE_ENTRY_DEF.setContextValue(context, node); + + // really open the ui associated with the selected node + openUI(newUI, node); + + } catch (Exception e) { + // remove data from context + + // if any error, go back to previvous node + goBackToPreviousNode(event, e); + } + } + + protected void addSelectedBeanInContext(NavigationTreeNode node, Object data) { + + if (log.isDebugEnabled()) { + log.debug("find data for contextPath <" + node.getContextPath() + "> : " + (data == null ? null : data.getClass())); + } + + context.removeContextValue(Object.class, NAVIGATION_SELECTED_BEAN); + + if (data != null) { + context.setContextValue(data, NAVIGATION_SELECTED_BEAN); + //todo should we not use this to avoid conflict in context ? + context.setContextValue(data); + } + } + + protected String getNodeConstraints(NavigationTreeNode node) { + String constraints; + switch (strategy) { + case PER_NODE: + constraints = node.getContextPath(); + break; + case PER_UI_TYPE: + constraints = node.getJaxxClass().getName(); + break; + default: + throw new IllegalArgumentException("could not find constraint for node : " + node); + } + return constraints; + } + + protected void returnToPreviousNode(JTree tree, TreeSelectionEvent event) { + // go back to previous node + // put in context a tag to not come back again here + TreePath oldPath = event.getOldLeadSelectionPath(); + //NavigationTreeNode oldNode = (NavigationTreeNode) oldPath.getLastPathComponent(); + if (oldPath != null) { + tree.setSelectionPath(oldPath); + } + } + +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/navigation/NavigationTreeSelectionAdapterWithCardLayout.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/navigation/NavigationTreeSelectionAdapterWithCardLayout.java new file mode 100644 index 0000000..283a9f8 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/navigation/NavigationTreeSelectionAdapterWithCardLayout.java @@ -0,0 +1,108 @@ +package jaxx.runtime.swing.navigation; + +import jaxx.runtime.JAXXAction; +import jaxx.runtime.JAXXContext; +import jaxx.runtime.JAXXInitialContext; +import jaxx.runtime.JAXXObject; +import jaxx.runtime.swing.CardLayout2; +import jaxx.runtime.swing.navigation.NavigationTreeModel.NavigationTreeNode; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.swing.JPanel; +import javax.swing.event.TreeSelectionEvent; +import java.awt.Component; + +/** + * Simple {@link NavigationTreeSelectionAdapter} implementation with a {@link jaxx.runtime.swing.CardLayout2} to manage components to + * associated with tree's nodes. + * <p/> + * For each node, the ui associated has a constraints in a cardlayout which is the node context path. + * <p/> + * A single container managed by the cardlayout is used to display the components associated with tree's nodes. + * + * @author chemit + */ +public abstract class NavigationTreeSelectionAdapterWithCardLayout extends NavigationTreeSelectionAdapter { + + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private final Log log = LogFactory.getLog(NavigationTreeSelectionAdapterWithCardLayout.class); + + /** + * All components associated with a tree's node is displayed in a single container. + * + * @return the containter of components + */ + protected abstract JPanel getContentContainer(); + + /** + * the cardlayout managing components associated with tree node. The constraints + * of each component is the node contextPath. + * + * @return the layout used to display components associated with tree's nodes. + */ + protected abstract CardLayout2 getContentLayout(); + + public NavigationTreeSelectionAdapterWithCardLayout(Class<? extends JAXXObject> defaultUIClass, Class<? extends JAXXAction> defaultUIHandlerClass, JAXXObject context, Strategy strategy) { + super(defaultUIClass, defaultUIHandlerClass, context,strategy); + + if (getContentContainer() == null) { + throw new IllegalArgumentException("could not have a null 'contentContainer' in ui " + context); + } + if (getContentLayout() == null) { + throw new IllegalArgumentException("could not have a null 'contentLayout' in ui " + context); + } + } + + protected Component getCurrentUI() { + CardLayout2 layout = getContentLayout(); + JPanel container = getContentContainer(); + return layout.getVisibleComponent(container); + } + + protected Component getUI(NavigationTreeNode node) { + CardLayout2 layout = getContentLayout(); + JPanel container = getContentContainer(); + String path = getNodeConstraints(node); + return layout.contains(path) ? layout.getComponent(container, path) : null; + } + + protected void openUI(Component newUI, NavigationTreeNode node) throws Exception { + + CardLayout2 layout = getContentLayout(); + JPanel container = getContentContainer(); + // switch layout + layout.show(container, getNodeConstraints(node)); + } + + protected boolean closeUI(TreeSelectionEvent event, Component component) throws Exception { + // by default, we says that component was succesfull closed + return true; + } + + protected Component createUI(NavigationTreeNode node) throws Exception { + JAXXObject newUI; + + if (node.getJaxxActionClass() != null) { + JAXXAction action = node.getJaxxActionClass().newInstance(); + // init context with + JAXXInitialContext context = action.init(this.context); + // must instanciate the ui with an JAXXInitialContext + newUI = node.getJaxxClass().getConstructor(JAXXContext.class).newInstance(context); + } else { + if (log.isWarnEnabled()) { + log.warn("no action associated with ui " + node.getJaxxClass()); + } + // no action associated, just + newUI = node.getJaxxClass().getConstructor(JAXXContext.class).newInstance(this.context); + } + if (log.isDebugEnabled()) { + log.debug("instanciate new ui " + newUI); + } + + getContentContainer().add((Component) newUI, getNodeConstraints(node)); + return (Component) newUI; + } +} + diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/navigation/NavigationUtil.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/navigation/NavigationUtil.java new file mode 100644 index 0000000..7f6dded --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/navigation/NavigationUtil.java @@ -0,0 +1,159 @@ +package jaxx.runtime.swing.navigation; + +import jaxx.runtime.Decorator; +import jaxx.runtime.JAXXContext; +import jaxx.runtime.swing.navigation.NavigationTreeModel.NavigationTreeNode; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import static org.nuiton.i18n.I18n._; + +import java.lang.reflect.InvocationTargetException; +import java.util.regex.Pattern; + +/** + * Usefull methods on {@link NavigationTreeModel} and others. + * + * @author chemit + * @see jaxx.runtime.swing.navigation.NavigationTreeModel + * @see jaxx.runtime.swing.navigation.NavigationTreeModel.NavigationTreeNode + */ +public class NavigationUtil { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private final Log log = LogFactory.getLog(NavigationUtil.class); + + public static String getCurrentNavigationNath(JAXXContext context) { + return NavigationTreeSelectionAdapter.NAVIGATION_SELECTED_PATH_ENTRY_DEF.getContextValue(context); + } + + public static NavigationTreeNode getSelectedNode(JAXXContext context) { + return NavigationTreeSelectionAdapter.NAVIGATION_SELECTED_NODE_ENTRY_DEF.getContextValue(context); + } + + public static <O> O getSelectedBean(JAXXContext context, Class<O> clazz) { + return context.getContextValue(clazz, NavigationTreeSelectionAdapter.NAVIGATION_SELECTED_BEAN); + } + + public static Object getContextValue(JAXXContext context, String contextKey, String navigationPath) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { + + NavigationTreeModel navigationModel = context.getContextValue(NavigationTreeModel.class, contextKey); + + return navigationModel.getJAXXContextValue(context, navigationPath); + } + + public static NavigationTreeNode findNode(JAXXContext context, String contextKey, String navigationPath) { + + NavigationTreeModel navigationModel = context.getContextValue(NavigationTreeModel.class, contextKey); + + return navigationModel.findNode(navigationPath); + } + + public static NavigationTreeNode findNode(JAXXContext context, String contextKey, String navigationPath, String regex) { + + NavigationTreeModel navigationModel = context.getContextValue(NavigationTreeModel.class, contextKey); + + return navigationModel.findNode(navigationPath, regex); + } + + + public static NavigationTreeNode findNode(JAXXContext context, String contextKey, String navigationPath, Pattern regex) { + + NavigationTreeModel navigationModel = context.getContextValue(NavigationTreeModel.class, contextKey); + + return navigationModel.findNode(navigationPath, regex); + } + + public static NavigationTreeNode findNode(JAXXContext context, String contextKey, String navigationPath, String regex, String suffix) { + + NavigationTreeModel navigationModel = context.getContextValue(NavigationTreeModel.class, contextKey); + + NavigationTreeNode navigationTreeNode = navigationModel.findNode(navigationPath, regex); + if (navigationTreeNode != null && suffix != null) { + navigationTreeNode = navigationModel.findNode(navigationTreeNode, suffix); + } + return navigationTreeNode; + } + + public static NavigationTreeNode findNode(JAXXContext context, String contextKey, String navigationPath, Pattern regex, String suffix) { + + NavigationTreeModel navigationModel = context.getContextValue(NavigationTreeModel.class, contextKey); + + NavigationTreeNode navigationTreeNode = navigationModel.findNode(navigationPath, regex); + if (navigationTreeNode != null && suffix != null) { + navigationTreeNode = navigationModel.findNode(navigationTreeNode, suffix); + } + return navigationTreeNode; + } + + public static class NodeRenderer implements java.io.Serializable { + + protected String libelle; + + protected Decorator<?> decorator; + + protected NavigationTreeNode node; + + protected Class<?> internalClass; + + protected String rendererCachedValue; + + private static final long serialVersionUID = -1238962588426200861L; + + public NodeRenderer(String libelle) { + this.libelle = libelle; + this.internalClass = String.class; + } + + public NodeRenderer(Decorator<?> decorator) { + this.decorator = decorator; + this.internalClass = decorator.getInternalClass(); + } + + public String toString(JAXXContext context) { + if (rendererCachedValue != null) { + return rendererCachedValue; + } + + String result; + + if (libelle != null) { + // simple libelle renderer + result = _(libelle); + } else { + + // with decorator renderer + + try { + Object bean = node.getJAXXContextValue(context); + result = decorator.toString(bean); + + } catch (Exception e) { + result = ""; + } + } + setRendererCachedValue(result); + return result; + } + + public void setNode(NavigationTreeNode node) { + this.node = node; + } + + public Class<?> getInternalClass() { + return internalClass; + } + + public void setRendererCachedValue(String rendererCachedValue) { + this.rendererCachedValue = rendererCachedValue; + if (log.isDebugEnabled()) { + log.debug(rendererCachedValue); + } + } + + public String getRendererCachedValue() { + return rendererCachedValue; + } + + } + +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardModel.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardModel.java new file mode 100644 index 0000000..f5e9ac7 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardModel.java @@ -0,0 +1,244 @@ +package jaxx.runtime.swing.wizard; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.util.List; + +/** + * Un modèle de wizard. + * + * + * <b>Note:</b> le type des étapes doit être uné énumération qui implante + * {@link WizardStep}. + * + * @param <E> le type des étapes. + * + * @author tony + * @since 1.3 + * @see WizardStep + */ +public class WizardModel<E extends WizardStep> { + + public static final String STEPS_PROPERTY_NAME = "steps"; + public static final String STEP_PROPERTY_NAME = "step"; + public static final String PREVIOUS_STEP_PROPERTY_NAME = "previousStep"; + public static final String NEXT_STEP_PROPERTY_NAME = "nextStep"; + public static final String VALID_STEP_PROPERTY_NAME = "validStep"; + /** + * le type d'une etape du model (doit etre une enumeration) + */ + protected final Class<E> stepClass; + /** + * Toutes les étapes à passer + */ + protected List<E> steps; + /** les etapes a exclure */ + protected List<E> excludeSteps; + /** + * L'étape courante + */ + protected E step; + /** + * drapeau pour valider l'état de l'étape courante + */ + protected boolean validStep; + /** + * drapeau lorsque le modele effectue des operations + * de transformation de modele mais que les écouteurs + * ne devraient pas tenir compte des modifications + */ + protected boolean valueAdjusting; + /** + * pour propager les changements dans le modèle vers l'ui + */ + protected PropertyChangeSupport pcs; + + public WizardModel(Class<E> stepClass, E... steps) { + if (!Enum.class.isAssignableFrom(stepClass)) { + throw new IllegalArgumentException("stepClass must be an Enumeration but was " + stepClass.getName()); + } + this.stepClass = stepClass; + this.pcs = new PropertyChangeSupport(this); + this.steps = new java.util.ArrayList<E>(); + if (steps.length > 0) { + setSteps(steps); + } + } + + public void start() { + if (steps.isEmpty()) { + throw new IllegalStateException("can not start, no step found"); + } + step = null; + E startStep = steps.get(0); + setStep(startStep); + } + + public void gotoNextStep() { + E nextStep = getNextStep(); + if (nextStep == null) { + throw new IllegalStateException("no next step to go"); + } + setStep(nextStep); + } + + public void gotoPreviousStep() { + E previousStep = getPreviousStep(); + if (previousStep == null) { + throw new IllegalStateException("no previous step to go"); + } + setStep(previousStep); + } + + public void gotoStep(E e) { + if (e == null) { + throw new NullPointerException("step can not be null"); + } + if (!steps.contains(e)) { + throw new IllegalStateException("step " + e.toString() + " is not in universe of steps (" + steps + ")"); + } + setStep(e); + } + + public E getStep() { + return step; + } + + public int getStepIndex(E s) { + int index = steps.indexOf(s); + return index; + } + + public boolean isValidStep() { + return validStep; + } + + public E getPreviousStep() { + E e = getPreviousStep(step); + return e; + } + + public E getPreviousStep(E step) { + int index = getStepIndex(step); + if (index < 1) { + // si pas de step ou sur premier step + return null; + } + return steps.get(index - 1); + } + + public E getNextStep(E step) { + int index = getStepIndex(step); + if (index < 1) { + // si pas de step ou sur premier step + return null; + } + return steps.get(index - 1); + } + + public E getNextStep() { + int index = getStepIndex(step); + if (index == -1 || index == steps.size() - 1) { + // si pas de step positionne ou dernier etape + return null; + } + return steps.get(index + 1); + } + + public java.util.List<E> getSteps() { + return steps; + } + + public boolean isValueAdjusting() { + return valueAdjusting; + } + + /** + * Change l'univers des etapes. + * + * Note: on presume ici que l'étape courante est toujours la meme. + * + * @param steps le nouvel univers des etapes + */ + public void setSteps(E... steps) { + java.util.List<E> oldValue = this.steps; + this.steps = java.util.Collections.unmodifiableList(java.util.Arrays.asList(steps)); + firePropertyChange(STEPS_PROPERTY_NAME, oldValue, this.steps); + // la propriete nextStep peut avoir changee + firePropertyChange(NEXT_STEP_PROPERTY_NAME, null, getNextStep()); + } + + public void setValueAdjusting(boolean valueAdjusting) { + this.valueAdjusting = valueAdjusting; + } + + public void setExcludeSteps(List<E> excludeSteps) { + this.excludeSteps = excludeSteps; + } + public boolean validate(E s) { + return step != null; + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + pcs.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + pcs.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.removePropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListeners() { + for (PropertyChangeListener l : pcs.getPropertyChangeListeners()) { + pcs.removePropertyChangeListener(l); + } + } + + public void validate() { + if (step == null) { + // pas de validation quand aucune etape n'est sélectionnée + return; + } + boolean validate = validate(step); + this.validStep = validate; + // toujours forcer la propagation + firePropertyChange(VALID_STEP_PROPERTY_NAME, null, validStep); + } + + protected Class<E> getStepClass() { + return stepClass; + } + + protected void setStep(E step) { + E oldValue = this.step; + this.step = step; + firePropertyChange(STEP_PROPERTY_NAME, oldValue, step); + // la propriete nextStep peut avoir changee + firePropertyChange(NEXT_STEP_PROPERTY_NAME, null, getNextStep()); + // la propriete previousStep peut avoir changee + firePropertyChange(PREVIOUS_STEP_PROPERTY_NAME, null, getPreviousStep()); + validate(); + } + + protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { + pcs.firePropertyChange(propertyName, oldValue, newValue); + } + + protected void fireIndexedPropertyChange(String propertyName, int index, Object oldValue, Object newValue) { + pcs.fireIndexedPropertyChange(propertyName, index, oldValue, newValue); + } + + protected E[] updateStepUniverse() { + return null; + } + + protected void updateUniverse() { + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationAction.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationAction.java new file mode 100644 index 0000000..52d26e7 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationAction.java @@ -0,0 +1,108 @@ +package jaxx.runtime.swing.wizard; + +import javax.swing.SwingWorker; +import jaxx.runtime.JAXXContext; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * La classe de base a implanter pour definir l'action d'une operation + * dans un wizard. + * + * @author tony + * @param <E> le type d'étapes + * @param <M> le type de modèle + * @since 1.3 + */ +public abstract class WizardOperationAction<E extends WizardOperationStep, M extends WizardOperationModel<E>> extends SwingWorker<WizardOperationState, String> { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + private static final Log log = LogFactory.getLog(WizardOperationAction.class); + E operation; + WizardOperationState operationState; + Exception error; + + public WizardOperationAction(E operation) { + super(); + if (!operation.isOperation()) { + throw new IllegalArgumentException("the step " + operation + " has no operation defined"); + } + this.operation = operation; + } + + public E getOperation() { + return operation; + } + + public Exception getError() { + return error; + } + + public void setError(Exception e) { + error = e; + } + + public void sendMessage(String msg) { + firePropertyChange("message", null, msg); + } + + public abstract void start(JAXXContext context); + + public abstract void beforeAction(JAXXContext context, M model) throws Exception; + + public abstract WizardOperationState doAction(M model) throws Exception; + + public abstract WizardOperationState onError(M model, Exception e); + + public abstract WizardOperationState onCancel(M model, Exception e); + + protected abstract M getModel(); + + public WizardOperationState getOperationState() { + return operationState; + } + + protected abstract JAXXContext getContext(); + + @Override + public String toString() { + return super.toString() + " < operation: " + operation + ", state: " + getState() + " >"; + } + + @Override + protected WizardOperationState doInBackground() throws Exception { + log.trace(this); + WizardOperationState result; + M model = getModel(); + try { + beforeAction(getContext(), model); + result = doAction(model); + } catch (Exception e) { + error = e; + result = onError(model, e); + } + return result; + } + + @Override + protected void done() { + log.trace(this); + WizardOperationState result = null; + try { + if (isCancelled()) { + + result = onCancel(getModel(), error); + } else { + result = get(); + } + } catch (Exception e) { + result = WizardOperationState.FAILED; + error = e; + // ne devrait jamais arrivé ? + log.error(e.getMessage(), e); + } finally { + // on enregistre le resultat de l'opération + this.operationState = result; + } + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationActionThread.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationActionThread.java new file mode 100644 index 0000000..eada87e --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationActionThread.java @@ -0,0 +1,204 @@ +package jaxx.runtime.swing.wizard; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.Date; +import javax.swing.SwingWorker.StateValue; +import jaxx.runtime.JAXXContext; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Thread qui réalise les opérations. + * + * Pour exécuter une nouvelle opération, on utilise la méthode + * {@link #launchOperation(SynchroActionWorker)}. + * + * Note: Pour bloquer (ou débloquer) le thread, on utilise la méthode {@link #setWaiting(boolean)} + * + * @param <E> le type des etapes + * @param <M> le type de modele + * @param <A> le type d'action d'operation + * + * @author tony + * @since 1.3 + */ +public abstract class WizardOperationActionThread<E extends WizardOperationStep, M extends WizardOperationModel<E>, A extends WizardOperationAction<E, M>> extends Thread implements PropertyChangeListener { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + private static final Log log = LogFactory.getLog(WizardOperationActionThread.class); + /** + * l'état du thread si annulé + */ + private boolean canceled; + protected Class<M> modelClass; + protected A currentAction; + /** + * un lock pour permettre la suspension et la reprise du thread + * lors du mode interactif. + */ + private final Object LOCK = new Object(); + + protected abstract M getModel(); + + protected abstract JAXXContext getContext(); + + public WizardOperationActionThread(Class<M> modelClass) throws IllegalArgumentException { + super(WizardOperationActionThread.class.getSimpleName() + " " + new Date()); + this.modelClass = modelClass; + } + + public void cancel() { + log.info("cancel " + this); + this.canceled = true; + + // on annule le modele + getModel().cancel(); + + // on rend la main au thread + setWaiting(false); + } + + @SuppressWarnings("unchecked") + public A launchOperation(E operation) { + + if (currentAction != null && (!currentAction.isDone() || currentAction.operationState == WizardOperationState.RUNNING)) { + // on ne peut traiter qu'une seule opération à la fois + throw new IllegalStateException("can not add a operation when thread is busy, or has another operation to be done"); + } + currentAction = (A) getModel().getOperationAction(operation); + + // on libere le thread pour qu'il execute l'opération + setWaiting(false); + + return currentAction; + } + + public A getCurrentAction() { + return currentAction; + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + log.trace(evt.getPropertyName() + " <" + evt.getOldValue() + " - " + evt.getNewValue() + ">"); + if ("state".equals(evt.getPropertyName())) { + StateValue state = (StateValue) evt.getNewValue(); + if (state == StateValue.DONE) { + // on rend la main au thread pour qu'il attende une prochaine operation + setWaiting(false); + } + } + } + + @Override + public void run() { + try { + + // on vérifie que le context contient bien le modèle + if (getModel() == null) { + throw new NullPointerException("could not find model " + modelClass + " for " + this); + } + + while (!canceled) { + + if (canceled) { + // une annulation a été demandé + // donc même si une opération est demandée, on ne la traite + // pas + break; + } + + // en attente qu'une opération + // le block est bloqué jusqu'à arrivée d'une opération + // ou une demande d'annulation + setWaiting(true); + + // le thread a repris la main, donc plus en attente + log.trace("no more waiting " + this); + + if (!canceled) { + // une opération a été demandée + + // le thread écoute les modifications de l'action + currentAction.addPropertyChangeListener(this); + + // l'opération passe en etant en cours + getModel().setOperationState(WizardOperationState.RUNNING); + + // démarrage de l'opération dans un worker + currentAction.start(getContext()); + // le thread est bloqué jusqu'à la fin de l'opération + // ou une demande d'annulation + setWaiting(true); + + // le thread reprend la main des que l'operation + // est terminée ou a été annulée, on passera alors + // dans la méthode onPropertyChanged + + if (canceled) { + getModel().setOperationState(WizardOperationState.CANCELED); + } else { + getModel().setOperationState(currentAction.getOperationState()); + } + + // le thread n'écoute plus l'action car elle est terminée + // ou annulée + currentAction.removePropertyChangeListener(this); + // suppression de l'action + //currentAction = null; + } + + } + + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + unlockThread(); + log.trace(this + " will close..."); + close(); + } + } + + /** + * La méthode pour nettoyer le thread, a la fermeture. + * + */ + protected void close() { + // par defaut, on ne fait rien + log.trace(this); + } + + protected void setWaiting(boolean waiting) { + + if (waiting && !canceled) { + // locking thread + try { + lockThread(); + } catch (InterruptedException ex) { + log.error(ex.getMessage(), ex); + canceled = true; + } + } + + if (!waiting) { + // release lock + unlockThread(); + } + } + + protected void lockThread() throws InterruptedException { + synchronized (LOCK) { + log.trace(this); + // lock + LOCK.wait(); + } + } + + protected void unlockThread() { + synchronized (LOCK) { + log.trace(this); + // unlock + LOCK.notify(); + } + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationModel.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationModel.java new file mode 100644 index 0000000..c71e942 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationModel.java @@ -0,0 +1,269 @@ +package jaxx.runtime.swing.wizard; + +import java.util.Arrays; +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.swing.SwingWorker.StateValue; + +/** + * Un modèle de wizard avec des opérations. + * + * @param <E> le type des étapes. + * @author tony + * @since 1.3 + */ +public class WizardOperationModel<E extends WizardOperationStep> extends WizardModel<E> { + + public static final String OPERATIONS_PROPERTY_NAME = "operations"; + public static final String OPERATION_STATE_PROPERTY_NAME = "operationState"; + public static final String MODEL_STATE_PROPERTY_NAME = "modelState"; + public static final String WAS_STARTED_PROPERTY_NAME = "wasStarted"; + + /** + * La liste des opérations à effectuer + */ + protected Set<E> operations; + /** + * Pour conserver les états des opérations + */ + protected Map<E, WizardOperationState> operationStates; + protected Map<E, WizardOperationAction> operationActions; + /** + * L'état générale du modèle + */ + protected WizardOperationState modelState; + /** + * un drapeau pour savoir siune opération a été lancée + */ + protected boolean wasStarted; + + @SuppressWarnings("unchecked") + public <T extends Enum<T>> WizardOperationModel(Class<E> stepClass, E... steps) { + super(stepClass, steps); + Class<T> k = (Class) stepClass; + this.operationStates = (Map) new EnumMap(k); + this.operations = (Set<E>) EnumSet.noneOf(k); + this.operationActions = (Map) new EnumMap(k); + } + + public Set<E> getOperations() { + return operations; + } + + public WizardOperationState getModelState() { + return modelState; + } + + public boolean isWasStarted() { + return wasStarted; + } + + @SuppressWarnings("unchecked") + public E getOperation() { + return getStep() != null && getStep().isOperation() ? getStep() : null; + } + + public WizardOperationState getOperationState() { + E operation = getOperation(); + return getOperationState(operation); + } + + public WizardOperationState getOperationState(E operation) { + return operationStates.get(operation); + } + + public WizardOperationAction getOperationAction(E operation) { + WizardOperationAction action = operationActions.get(operation); + if (action == null) { + try { + action = operation.getActionClass().newInstance(); + operationActions.put(operation, action); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + return action; + } + + public void setOperationState(WizardOperationState operationState) { + E operation = getOperation(); + setOperationState(operation, operationState); + } + + public void setOperationState(E operation, WizardOperationState operationState) { + WizardOperationState oldValue = getOperationState(operation); + this.operationStates.put(operation, operationState); + fireIndexedPropertyChange(OPERATION_STATE_PROPERTY_NAME, getSteps().indexOf(operation), oldValue, operationState); + updateModelState(operation, operationState); + validate(); + } + + public boolean[] getAccessibleSteps() { + boolean[] result = new boolean[getSteps().size()]; + int index = getSteps().indexOf(getStep()); + if (index != -1) { + + for (int i = 0, j = steps.size(); i < j; i++) { + if (i <= index) { + // tous les onglets inferieur ou egal au courant sont accessibles + result[i] = true; + continue; + } + // les onglets au dela de l'onglet sélectionné sont accessibles + // uniquement si l'onglet precedent est accessible, valide et son etat est a SUCCESSED + E previousStep = steps.get(i - 1); + result[i] = modelState == WizardOperationState.SUCCESSED || + (result[i - 1] && + validate(previousStep) && + (!previousStep.isOperation() || getOperationState(previousStep) == WizardOperationState.SUCCESSED)); + } + } + //System.out.println("accessibles steps -------- " + java.util.Arrays.toString(result)); + return result; + } + + @Override + public void start() { + super.start(); + updateUniverse(); + //setSteps(steps.toArray((E[]) Array.newInstance(stepClass, steps.size()))); + + // le modèle n'est pas démarré + setModelState(WizardOperationState.PENDING); + } + + public void cancel() { + + for (E op : operations) { + if (getOperationState(op) == WizardOperationState.PENDING) { + // on annule l'opération à venir + setOperationState(op, WizardOperationState.CANCELED); + } + } + setModelState(WizardOperationState.CANCELED); + if (getStep() != null && getStep().isOperation()) { + WizardOperationAction action = getOperationAction(getStep()); + if (action != null) { + if (!action.isCancelled() && !action.isDone() && action.getState() == StateValue.STARTED) { + System.out.println("cancel action " + action); + // on annule l'action + action.cancel(true); + } + } + } + } + + public WizardOperationModel<E> addOperation(E operation) { + operations.add(operation); + // mis a jour de l'univers des etapes et operations + updateUniverse(); + // validation + validate(); + return this; + } + + public void removeOperation(E operation) { + operations.remove(operation); + + // mis a jour de l'univers des etapes et operations + updateUniverse(); + // validation + validate(); + } + + @Override + public void setSteps(E... steps) { + super.setSteps(steps); + // on force la propagation de la nouvelle liste + firePropertyChange(OPERATIONS_PROPERTY_NAME, null, operations); + updateOperationStates(Arrays.asList(steps)); + } + + public void updateOperationStates(List<E> steps) { + int index = 0; + for (E e : steps) { + fireIndexedPropertyChange(OPERATION_STATE_PROPERTY_NAME, index++, null, getOperationState(e)); + } + firePropertyChange(MODEL_STATE_PROPERTY_NAME, null, modelState); + } + + public WizardOperationAction reloadOperation(E operation) { + operationActions.remove(operation); + WizardOperationAction newOp = getOperationAction(operation); + return newOp; + } + + protected void setModelState(WizardOperationState modelState) { + WizardOperationState oldValue = this.modelState; + this.modelState = modelState; + firePropertyChange(MODEL_STATE_PROPERTY_NAME, oldValue, modelState); + if (!wasStarted) { + if ((oldValue == null || oldValue == WizardOperationState.PENDING) && modelState == WizardOperationState.RUNNING) { + this.wasStarted = true; + firePropertyChange(WAS_STARTED_PROPERTY_NAME, false, true); + } + } + } + + protected void updateModelState(E operation, WizardOperationState operationState) { + + switch (operationState) { + case RUNNING: + //le modele est occupé + setModelState(WizardOperationState.RUNNING); + break; + case FAILED: + //le modele est en erreur + setModelState(WizardOperationState.FAILED); + break; + case CANCELED: + //le modele devient annulé + setModelState(WizardOperationState.CANCELED); + return; + case PENDING: + //le modele est en attente + setModelState(WizardOperationState.PENDING); + break; + case NEED_FIX: + //le modele est en attente + setModelState(WizardOperationState.PENDING); + break; + case SUCCESSED: + // on regarde si on peut passer le model a l'état success + boolean valid = true; + for (E o : operations) { + if (getOperationState(o) != WizardOperationState.SUCCESSED) { + valid = false; + break; + } + } + if (valid) { + setModelState(WizardOperationState.SUCCESSED); + } else { + setModelState(WizardOperationState.PENDING); + } + break; + } + updateOperationStates(steps); + } + + @Override + protected void updateUniverse() { + E[] newSteps = updateStepUniverse(); + setSteps(newSteps); + } + + protected int getOperationIndex(E operation) { + int index = 0; + for (E o : operations) { + if (operation == o) { + return index; + } + index++; + } + return -1; + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationState.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationState.java new file mode 100644 index 0000000..9e6f9f2 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationState.java @@ -0,0 +1,32 @@ +package jaxx.runtime.swing.wizard; + +/** + * Pour caractériser l'état d'une opération. + */ +public enum WizardOperationState { + + /** + * quand l'opération n'a pas encore été réalisée + */ + PENDING, + /** + * quand l'opération est en cours + */ + RUNNING, + /** + * quand l'opération est annulé en cours d'exécution + */ + CANCELED, + /** + * quand une erreur s'est produite pendant l'exécution + */ + FAILED, + /** + * quand l'exécution s'est terminée mais requière des corrections + */ + NEED_FIX, + /** + * quand l'exécution s'est terminée et ne requière pas de correction + */ + SUCCESSED +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationStep.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationStep.java new file mode 100644 index 0000000..220447f --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationStep.java @@ -0,0 +1,34 @@ +package jaxx.runtime.swing.wizard; + +/** + * + * Le contrat a implanter pour une etapes dans le modèle de wizard avec + * opérations. + * + * @author tony + * @since 1.3 + */ +public interface WizardOperationStep extends WizardStep { + + /** + * @return le label de l'opération + */ + String getOperationLabel(); + + /** + * @return la description de l'opération + */ + String getOperationDescription(); + + /** + * @return le type de l'action associée à l'étape ou <code>null</code> si + * l'étape n'a pas d'opération associée. + */ + Class<? extends WizardOperationAction> getActionClass(); + + /** + * @return <code>true</code> si l'étape a une opération associée, + * <code>false</code> sinon. + */ + boolean isOperation(); +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardStep.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardStep.java new file mode 100644 index 0000000..e5b7478 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardStep.java @@ -0,0 +1,20 @@ +package jaxx.runtime.swing.wizard; + +import java.io.Serializable; + +/** + * le contrat d'une étape d'un wizard. + * + * @author tony + * @since 1.3 + */ +public interface WizardStep extends Serializable { + + String name(); + + int ordinal(); + + String getLabel(); + + String getDescription(); +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardStepUI.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardStepUI.java new file mode 100644 index 0000000..f57388a --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardStepUI.java @@ -0,0 +1,14 @@ +package jaxx.runtime.swing.wizard; + +/** + * Le contrat d'une ui d'étape. + * + * @param <E> le type d'étape + * @param <M> le type de modèle + * @author tony + * @since 1.3 + */ +public interface WizardStepUI<E extends WizardStep, M extends WizardModel<E>> { + + E getStep(); +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardUI.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardUI.java new file mode 100644 index 0000000..3a62b0e --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardUI.java @@ -0,0 +1,94 @@ +package jaxx.runtime.swing.wizard; + +import javax.swing.JTabbedPane; + +/** + * + * Contrat a respecter pour une ui de wizard. + * + * @param <E> le type d'etape + * @param <M> le type de model + * + * @author tony + * @since 1.3 + */ +public interface WizardUI<E extends WizardStep, M extends WizardModel<E>> { + + /** + * @return le modèle de wizard + */ + M getModel(); + + /** + * + * @return l'étape courante + */ + E getSelectedStep(); + + /** + * + * @return l'ui de l'étape courante + */ + WizardStepUI<E, M> getSelectedStepUI(); + + /** + * + * @param step l'étape donnée + * @return l'ui de l'étape donnée + */ + WizardStepUI<E, M> getStepUI(E step); + + /** + * + * @param stepIndex la position de l'étape + * @return l'ui de l'étape donée + */ + WizardStepUI<E, M> getStepUI(int stepIndex); + + /** + * démarre le wizard + */ + void start(); + + /** + * //TODO il faudrait supprimer cette méthode + * @return le conteneur d'ui d'étapes + */ + JTabbedPane getTabs(); + + /** + * Méthode invoqué lorsque la première opération du modèlé a été démarrée. + */ + void onWasStarted(); + + /** + * Méthode invoquée lorsque l'univers des étapes a été modifié dans le + * modèle. + * + * @param steps les nouvelles étapes + */ + void onStepsChanged(E[] steps); + + /** + * Méthode invoquée lorsque l'étape courante a changé dans le modèle. + * + * @param newStep la nouvelle étape courante + */ + void onStepChanged(E newStep); + + /** + * Méthode invoquée lorsque l'état interne du modèle a changé. + * + * @param newState le nouvelle état du modèle de wizard + */ + void onModelStateChanged(WizardOperationState newState); + + /** + * Méthode invoqué lorsque l'état d'une opération a changé. + * + * @param step l'étape dont l'état a changé + * @param newState le nouvel état pour l'étape donné + */ + void onOperationStateChanged(E step,WizardOperationState newState) ; + +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardUILancher.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardUILancher.java new file mode 100644 index 0000000..aaba288 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardUILancher.java @@ -0,0 +1,162 @@ +package jaxx.runtime.swing.wizard; + +import java.awt.Window; +import javax.swing.ImageIcon; +import jaxx.runtime.JAXXContext; +import jaxx.runtime.JAXXInitialContext; +import jaxx.runtime.JAXXObject; +import org.apache.commons.beanutils.ConstructorUtils; + +/** + * + * Une classe pour lancer une ui de wizard. + * + * @param <E> le type des etapes + * @param <M> le type de modele + * @param <UI> le type d'ui + * @author tony + * @since 1.3 + */ +public abstract class WizardUILancher<E extends WizardStep, M extends WizardModel<E>, UI extends WizardUI<E, M>> { + + protected UI ui; + + public WizardUILancher(JAXXContext context, Class<UI> uiClass, Class<M> modelClass, String title, String tip, ImageIcon icon) { + this(context, uiClass, modelClass, null, title, tip, icon); + } + + public WizardUILancher(JAXXContext context, Class<UI> uiClass, Class<M> modelClass, M model, String title, String tip, ImageIcon icon) { + try { + ui = createUI(context, uiClass, modelClass, model, title, tip, icon); + } catch (Exception ex) { + throw new RuntimeException("could not instanciate launcher for reason " + ex.getMessage(), ex); + } + } + + public WizardUILancher(JAXXContext context, Window mainUI, Class<UI> uiClass, Class<M> modelClass, M model) { + try { + ui = createUI(context, mainUI, uiClass, modelClass, model); + } catch (Exception ex) { + throw new RuntimeException("could not instanciate launcher for reason " + ex.getMessage(), ex); + } + } + + public WizardUILancher(JAXXContext context, Window mainUI, Class<UI> uiClass, Class<M> modelClass) { + this(context, mainUI, uiClass, modelClass, null); + } + + public void start() { + init(ui); + start(ui); + } + + protected void start(UI ui) { + ui.start(); + } + + public <T> T getContextValue(Class<T> clazz, String name) { + if (ui == null) { + throw new NullPointerException("ui can not be null"); + } + if (!(ui instanceof JAXXObject)) { + throw new ClassCastException("ui can not be casted to JAXXObject "); + } + + return ((JAXXObject) ui).getContextValue(clazz, name); + } + + public <T> T getContextValue(Class<T> clazz) { + return getContextValue(clazz, null); + } + + protected void init(UI ui) { + } + + protected void doAction(UI ui) { + } + + protected void doCancel(UI ui) { + } + + protected void doClose(UI ui, boolean wasCanceld) { + } + + @SuppressWarnings("unchecked") + protected UI createUI(JAXXContext context, Window mainUI, Class<UI> uiClass, Class<M> modelClass, M model) throws Exception { + JAXXInitialContext uiContext = new JAXXInitialContext(); + uiContext.add(mainUI == null ? context : mainUI); + // parent context model + uiContext.add(modelClass.newInstance()); + if (model != null) { + uiContext.add("incoming", model); + } + // apply action + uiContext.add("apply", new Runnable() { + + @Override + public void run() { + try { + doAction(ui); + } finally { + doClose(ui, false); + } + } + }); + // cancel action + uiContext.add("cancel", new Runnable() { + + @Override + public void run() { + try { + doCancel(ui); + } finally { + doClose(ui, true); + } + } + }); + + // instanciate ui + + UI newUI = (UI) ConstructorUtils.invokeConstructor(uiClass, new Object[]{mainUI, uiContext}, new Class[]{Window.class, JAXXContext.class}); + return newUI; + } + + @SuppressWarnings("unchecked") + protected UI createUI(JAXXContext context, Class<UI> uiClass, Class<M> modelClass, M model, String title, String tip, ImageIcon icon) throws Exception { + JAXXInitialContext uiContext = new JAXXInitialContext(); + uiContext.add(context); + // parent context model + uiContext.add(modelClass.newInstance()); + if (model != null) { + uiContext.add("incoming", model); + } + // apply action + uiContext.add("apply", new Runnable() { + + @Override + public void run() { + try { + doAction(ui); + } finally { + doClose(ui, false); + } + } + }); + // cancel action + uiContext.add("cancel", new Runnable() { + + @Override + public void run() { + try { + doCancel(ui); + } finally { + doClose(ui, true); + } + } + }); + + // instanciate ui + UI newUI = (UI) ConstructorUtils.invokeConstructor(uiClass, new Object[]{uiContext, title, tip, icon}, new Class[]{JAXXContext.class, String.class, String.class, ImageIcon.class}); + return newUI; + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardUtil.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardUtil.java new file mode 100644 index 0000000..4a30ba2 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardUtil.java @@ -0,0 +1,157 @@ +package jaxx.runtime.swing.wizard; + +import java.awt.Component; +import java.beans.IndexedPropertyChangeEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.lang.reflect.Array; +import javax.swing.JTabbedPane; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import static org.nuiton.i18n.I18n._; + +/** + * Classe de méthodes utiles sur les wizard. + * + * @author tony + * @since 1.3 + */ +public class WizardUtil { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(WizardUI.class); + + protected WizardUtil() { + } + + public static boolean acceptStates(WizardOperationState state, WizardOperationState... accepted) { + for (WizardOperationState s : accepted) { + if (s == state) { + return true; + } + } + return false; + } + + public static boolean rejectStates(WizardOperationState state, WizardOperationState... rejected) { + for (WizardOperationState s : rejected) { + if (s == state) { + return false; + } + } + return true; + } + + public static void addDebugLogListener(final Log log, WizardModel<?> model) { + if (log.isDebugEnabled()) { + model.addPropertyChangeListener(new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + log.debug(evt.getPropertyName() + " <" + evt.getOldValue() + " - " + evt.getNewValue() + ">"); + } + }); + } + } + + public static void addTraceLogListener(final Log log, WizardModel<?> model) { + if (log.isTraceEnabled()) { + model.addPropertyChangeListener(new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + log.trace(evt.getPropertyName() + " <" + evt.getOldValue() + " - " + evt.getNewValue() + ">"); + } + }); + } + } + + public static <E extends WizardStep, M extends WizardModel<E>> void installWizardUIListeners(final WizardUI<E, M> ui) { + ui.getModel().addPropertyChangeListener(new PropertyChangeListener() { + + @Override + @SuppressWarnings("unchecked") + public void propertyChange(PropertyChangeEvent evt) { + String propertyName = evt.getPropertyName(); + if (WizardOperationModel.WAS_STARTED_PROPERTY_NAME.equals(propertyName)) { + ui.onWasStarted(); + return; + } + if (WizardModel.STEPS_PROPERTY_NAME.equals(propertyName)) { + java.util.List<E> steps = (java.util.List<E>) evt.getNewValue(); + ui.onStepsChanged(steps.toArray((E[]) Array.newInstance(ui.getModel().stepClass, steps.size()))); + return; + } + if (WizardModel.STEP_PROPERTY_NAME.equals(propertyName)) { + ui.onStepChanged((E) evt.getNewValue()); + return; + } + if (WizardOperationModel.MODEL_STATE_PROPERTY_NAME.equals(propertyName)) { + //TODO should be unicast : only for good stepUI ? + ui.onModelStateChanged((WizardOperationState) evt.getNewValue()); + return; + } + if (WizardOperationModel.OPERATION_STATE_PROPERTY_NAME.equals(propertyName)) { + IndexedPropertyChangeEvent e = (IndexedPropertyChangeEvent) evt; + int stepIndex = e.getIndex(); + E step = ui.getModel().getSteps().get(stepIndex); + ui.onOperationStateChanged(step, (WizardOperationState) evt.getNewValue()); + return; + } + } + }); + } + + /** + * Ajoute un listener sur le modele pour gere la politique d'affichage des + * onglets. + * + * Dans cette implantation, les onglets sont ouverts jusqu'a l'etape courante. + * Lorsque l'on revient en arrière, les onglets d'etapes superieurs sont + * fermes. + * + * @param <E> le type d'un etape de l'assistant + * @param <M> le type du modele de l'assistant + * @param ui l'ui de l'assitant + * @since 1.7.1 + */ + public static <E extends WizardStep, M extends WizardModel<E>> void addTabsDisplayUntilStepListener(final WizardUI<E, M> ui) { + // on écoute les changements d'étapes + ui.getModel().addPropertyChangeListener(WizardModel.STEP_PROPERTY_NAME, new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + M model = (M) evt.getSource(); + E oldStep = (E) evt.getOldValue(); + E newStep = (E) evt.getNewValue(); + log.debug("step has changed <old:" + oldStep + ", new:" + newStep + ">"); + int oldStepIndex = oldStep == null ? -1 : model.getStepIndex(oldStep); + int newStepIndex = model.getStepIndex(newStep); + JTabbedPane tabs = ui.getTabs(); + if (oldStepIndex + 1 == newStepIndex) { + // creation d'un nouvel onglet + WizardStepUI<E, M> c = ui.getStepUI(newStep); + String title = _(newStep.getLabel()); + String tip = _(newStep.getDescription()); + tabs.addTab(title, null, (Component) c, tip); + // selection du nouvel onglet + int index = tabs.indexOfComponent((Component) c); + if (index > -1) { + tabs.setSelectedIndex(index); + } + } else if (oldStepIndex > newStepIndex) { + // il s'agit d'un retour en arrière + // on supprime tous les onglets obsoletes + int index = newStepIndex + 1; + while (tabs.getTabCount() > index) { + log.trace("remove tab : " + index); + tabs.remove(index); + } + } else { + throw new IllegalStateException("can not go from " + oldStep + " to " + newStep); + } + } + }); + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/package.html b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/package.html new file mode 100644 index 0000000..f2b6b69 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/package.html @@ -0,0 +1,9 @@ +<html> + <body> + <h1>JAXX - Wizard framework</h1> + + This package contains all the classes of the wizard framework. + + TODO + </body> +</html> \ No newline at end of file diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/SwingValidator.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/SwingValidator.java new file mode 100644 index 0000000..a01110f --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/SwingValidator.java @@ -0,0 +1,279 @@ +package jaxx.runtime.validator.swing; + +import jaxx.runtime.validator.swing.ui.AbstractBeanValidatorUI; +import jaxx.runtime.validator.swing.ui.IconValidationUI; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.jdesktop.jxlayer.JXLayer; + +import javax.swing.JComponent; +import javax.swing.SwingUtilities; +import java.awt.Container; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import jaxx.runtime.validator.BeanValidator; +import jaxx.runtime.validator.BeanValidatorField; + +/** + * La surcharge de {@link jaxx.runtime.validator.BeanValidator} pour les ui swing + * <p/> + * /** + * <p/> + * Permet d'ajouter facilement le support de la validation des champs d'un + * bean et de le relier a une interface graphique. + * Utilise xwork pour la validation et JXLayer pour la visualisation. + * <p/> + * <p/> + * Le mieux pour son integration dans Jaxx est de faire de la generation pour + * force la compilation du code suivant: + * <p/> + * <pre> + * myValidor.getBean().get<field>(); + * </pre> + * <p/> + * et ceci pour chaque field ajoute a la map fieldRepresentation. De cette + * facon meme si le champs field est en texte on a une verification de son + * existance a la compilation. + * <p/> + * <p/> + * La representation en tag pourrait etre + * <pre> + * <validator id="myValidator" beanClass="{Personne.class}" errorList="$list"> + * <field name="name" component="$name"/> + * <field name="firstName" component="$firstName"/> + * <field name="birthDate" component="$birthDate"/> + * </validator> + * <validator beanClass="{Personne.class}" autoField="true" errorList="$list"> + * <fieldRepresentation name="name" component="$lastName"/> + * </validator> + * </pre> + * <p/> + * dans le premier exemple on fait un mapping explicite des champs, mais on voit + * que le nom du composant graphique est le meme que celui du champs. Pour eviter + * de longue saisie, il est possible d'utiliser le flag <b>autoField</b> + * qui pour chaque champs du ayant une methode get du bean recherche un composant + * avec cet Id. Il est aussi possible de surcharge un champs explicitement + * comme ici name, dans le cas ou le composant qui porterait ce nom serait + * utilise pour autre chose. + * <p/> + * <p/> + * Il faut un handler particulier pour ce composant car les attributs + * <b>beanClass</b> et <b>autoField</b> ne sont present que dans le XML jaxx et + * servent a la generation. Il faut aussi prendre en compte les elements + * fieldRepresentation fils du tag validator. + * <p/> + * <p/> + * Voici ce que pourrait etre le code genere par jaxx + * <pre> + * // declaration du bean + * BeanValidator<beanClass> $myValidator; + * // init du bean + * protected void createMyValidator() { + * $myValidator = new BeanValidator<beanClass>(); + * // genere seulement si autoField = true + * for (Method m : beanClass.getMethod()) { + * if (m.getName().startsWith("get")) { + * String fieldName = m.getName().substring(3).toLowerCase(); + * $myValidator.setFieldRepresentation(fieldName, $objectMap.get(fieldName)); + * } + * } + * // pour chaque tag fieldRepresentation + * myValidator.setFieldRepresentation("name", $lastName); + * // si beanClass est specifie et n'est pas Object, on force l'acces au champs + * // pour validation a la compilation + * $myValidator.getBean().getName(); + * $objectMap.put("myValidator", $myValidator); + * } + * </pre> + * + * @param <B> le type de bean a valider + * @author poussin + * @author chemit + * @version 1.0 + */ +public class SwingValidator<B> extends BeanValidator<B> { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private final Log log = LogFactory.getLog(SwingValidator.class); + static private final Class<? extends AbstractBeanValidatorUI> DEFAULT_UI_CLASS = IconValidationUI.class; + /** permet de faire le lien en un champs du bean et l'objet qui permet de l'editer */ + protected Map<String, JComponent> fieldRepresentation; + /** Object servant a contenir la liste des erreurs */ + protected SwingValidatorMessageListModel errorListModel; + /** Object servant a contenir la liste des erreurs */ + protected SwingValidatorMessageTableModel errorTableModel; + /** ui renderer class */ + protected Class<? extends AbstractBeanValidatorUI> uiClass; + + public SwingValidator(Class<B> beanClass, String contextName) { + super(beanClass, contextName); + fieldRepresentation = new HashMap<String, JComponent>(); + } + + /** + * To reload a bean in the validator. + * + * This method is used to reload ui, since some editors + * could not exist when validator is init, so some messages + * should not be attached to an editor. + */ + public void reloadBean() { + B b = getBean(); + if (b != null) { + setBean(null); + setBean(b); + } + } + + public JComponent getFieldRepresentation(String fieldname) { + return fieldRepresentation.get(fieldname); + } + + public Class<? extends AbstractBeanValidatorUI> getUiClass() { + return uiClass; + } + + public void setErrorListModel(SwingValidatorMessageListModel errorListModel) { + this.errorListModel = errorListModel; + if (errorListModel != null) { + // register the validator in the model list + errorListModel.registerValidator(this); + } + } + + public void setErrorTableModel(SwingValidatorMessageTableModel errorTableModel) { + this.errorTableModel = errorTableModel; + if (errorTableModel != null) { + // register the validator in the model table + errorTableModel.registerValidator(this); + } + } + + public void setUiClass(Class<? extends AbstractBeanValidatorUI> uiClass) { + this.uiClass = uiClass; + } + + @Override + public void setContextName(String contextName) { + /*Map<ValidatorField<B>, List<ValidatorErrorListener>> oldListeners = new HashMap<ValidatorField<B>, List<ValidatorErrorListener>>(); + + for (ValidatorField<B> field : fields) { + ValidatorErrorListener[] listeners = field.getValidatorErrorListeners(); + List<ValidatorErrorListener> toReinject = new ArrayList<ValidatorErrorListener>(); + for (ValidatorErrorListener listener : listeners) { + if (listener instanceof AbstractBeanValidatorUI) { + // this listener will be reinject via installUIs method + continue; + } + toReinject.add(listener); + } + oldListeners.put(field, toReinject); + }*/ + super.setContextName(contextName); + // must reinstall ui + installUIs(); + // reinject none ui listeners + /*for (Entry<ValidatorField<B>, List<ValidatorErrorListener>> entry : oldListeners.entrySet()) { + ValidatorField<B> field = getField(entry.getKey().getName()); + for (ValidatorErrorListener listener : entry.getValue()) { + field.addValidatorErrorListener(listener); + } + } + oldListeners.clear();*/ + } + + /** + * Permet d'indiquer le composant graphique responsable de l'affichage + * d'un attribut du bean + * + * @param fieldname the field name in the bean + * @param c the editor component for the field + */ + public void setFieldRepresentation(String fieldname, JComponent c) { + BeanValidatorField<B> field = getField(fieldname); + if (field == null) { + // no field registred in the validator + log.warn("the field '" + fieldname + "' is not defined in validator (no rules on it)"); + return; + } + fieldRepresentation.put(fieldname, c); + } + + public void setFieldRepresentation(Map<String, JComponent> fieldRepresentation) { + for (Map.Entry<String, JComponent> e : fieldRepresentation.entrySet()) { + setFieldRepresentation(e.getKey(), e.getValue()); + } + } + + @Override + public SwingValidator<?> getParentValidator() { + return (SwingValidator<?>) super.getParentValidator(); + } + + public void setParentValidator(SwingValidator<?> parentValidator) { + super.setParentValidator(parentValidator); + } + + /** install ui on required components */ + public void installUIs() { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + if (uiClass == null) { + // use the default one + uiClass = DEFAULT_UI_CLASS; + } + for (Entry<String, JComponent> entry : fieldRepresentation.entrySet()) { + try { + setMessageRepresentation(entry.getKey(), null, entry.getValue(), uiClass); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + }); + } + + protected void setMessageRepresentation(String fieldname, JComponent old, JComponent c, Class<? extends AbstractBeanValidatorUI> uiClass) + throws InvocationTargetException, IllegalAccessException, InstantiationException, NoSuchMethodException { + if (old == c) { + // same component, nothing to do + return; + } + BeanValidatorField<B> field = getField(fieldname); + + if (field == null) { + // this case should not appear since fieldName has already been check in method addFieldRepresentation + return; + } + if (old != null) { + // suppression du jxlayer sous l'ancien composant + Container container = old.getParent(); + if (container instanceof JXLayer) { + JXLayer<?> jx = (JXLayer<?>) container; + Object ui = jx.getUI(); + if (ui != null && ui instanceof AbstractBeanValidatorUI) { + removeBeanValidatorListener((AbstractBeanValidatorUI) ui); + } + + jx.setUI(null); + } + } + if (c != null) { + // ajout du jxlayer sous ce composant + Container container = c.getParent(); + if (container instanceof JXLayer) { + Constructor<? extends AbstractBeanValidatorUI> cons = uiClass.getConstructor(BeanValidatorField.class); + AbstractBeanValidatorUI ui = cons.newInstance(field); + ui.setEnabled(true); + JXLayer<JComponent> jx = (JXLayer<JComponent>) container; + addBeanValidatorListener(ui); + jx.setUI(ui); + } + } + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/SwingValidatorMessage.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/SwingValidatorMessage.java new file mode 100644 index 0000000..cbb63c3 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/SwingValidatorMessage.java @@ -0,0 +1,66 @@ +package jaxx.runtime.validator.swing; + +import javax.swing.JComponent; +import jaxx.runtime.validator.BeanValidatorField; +import jaxx.runtime.validator.BeanValidatorMessage; +import jaxx.runtime.validator.BeanValidatorScope; + +/** + * The object to box a validation message within an u. + * + * @author chemit + * @since 1.3 + * @see BeanValidatorMessage + */ +public class SwingValidatorMessage extends BeanValidatorMessage<SwingValidatorMessage> { + + /** + * the optional field's editor + */ + protected JComponent editor; + protected String fieldName; + + public SwingValidatorMessage(SwingValidator validator, BeanValidatorField field, String message, BeanValidatorScope scope, JComponent editor) { + super(validator, field, message, scope); + this.fieldName = field.getName(); + this.editor = editor; + } + + public SwingValidatorMessage(SwingValidator validator, String fieldName, String message, BeanValidatorScope scope, JComponent editor) { + super(validator, null, message, scope); + this.fieldName = fieldName; + this.editor = editor; + } + + public JComponent getEditor() { + return editor; + } + + public String getFieldName() { + return fieldName; + } + + @Override + public int compareTo(SwingValidatorMessage o) { + // sort on scope + int result = getScope().compareTo(o.getScope()); + if (result == 0) { + // sort on field name + result = fieldName.compareTo(o.getFieldName()); + if (result == 0) { + // sort on message + result = message.compareTo(o.getMessage()); + } + } + return result; + } + + @Override + public String toString() { + String s = scope + " - " + (field == null ? message : field.getI18nError(message)); + if (editor == null) { + return s; + } + return editor.getName() + " : " + s; + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/SwingValidatorMessageListModel.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/SwingValidatorMessageListModel.java new file mode 100644 index 0000000..a01ecf9 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/SwingValidatorMessageListModel.java @@ -0,0 +1,142 @@ +package jaxx.runtime.validator.swing; + +import jaxx.runtime.validator.BeanValidatorEvent; + +import javax.swing.JComponent; +import java.util.ArrayList; +import java.util.List; +import jaxx.runtime.validator.BeanValidatorField; +import jaxx.runtime.validator.BeanValidatorScope; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * The model of the list of validation's messages + * + * @author chemit + */ +public class SwingValidatorMessageListModel + extends javax.swing.AbstractListModel + implements jaxx.runtime.validator.BeanValidatorListener { + + private static final long serialVersionUID = 1L; + /** to use log facility, just put in your code: log.info(\"...\"); */ + private static Log log = LogFactory.getLog(SwingValidatorMessageListModel.class); + /** list of registred validators */ + protected transient List<SwingValidator<?>> validators; + /** list of messages actual displayed */ + protected List<SwingValidatorMessage> data; + + public SwingValidatorMessageListModel() { + validators = new ArrayList<SwingValidator<?>>(); + data = new java.util.ArrayList<SwingValidatorMessage>(); + } + + public boolean isEmpty() { + return getSize() == 0; + } + + public void registerValidator(SwingValidator<?> validator) { + if (validators.contains(validator)) { + throw new IllegalArgumentException("the validator " + validator + " is already registred in " + this); + } + validators.add(validator); + validator.addBeanValidatorListener(this); + } + + public void clear() { + int i = data.size(); + if (i > 0) { + data.clear(); + fireIntervalRemoved(this, 0, i - 1); + } + } + + @Override + public int getSize() { + return data.size(); + } + + @Override + public Object getElementAt(int index) { + ensureRowIndex(index); + return data.get(index); + } + + @Override + public void onFieldChanged(BeanValidatorEvent event) { + String[] toDelete = event.getMessagesToDelete(); + String[] toAdd = event.getMessagesToAdd(); + BeanValidatorField field = event.getField(); + BeanValidatorScope scope = event.getScope(); + boolean mustAdd = toAdd != null && toAdd.length > 0; + boolean mustDel = toDelete != null && toDelete.length > 0; + + if (log.isTraceEnabled()) { + log.trace("----------------------------------------------------------"); + log.trace(field + " - (" + getSize() + ") toAdd " + mustAdd); + log.trace(field + " - (" + getSize() + ") toDelete " + mustDel); + } + + SwingValidator validator = (SwingValidator) event.getSource(); + + if (mustDel) { + + // removes datas and notify if no messages to add + removeMessages(validator, field, scope, !mustAdd, toDelete); + } + + if (mustAdd) { + + // add new messages, sort datas and notify + addMessages(validator, field, scope, true, toAdd); + } + } + + protected void ensureRowIndex(int index) throws ArrayIndexOutOfBoundsException { + if (index < -1 || index >= getSize()) { + throw new ArrayIndexOutOfBoundsException("the rowIndex was " + index + ", but should be int [0," + (getSize() - 1) + "]"); + } + } + + protected void addMessages(SwingValidator validator, BeanValidatorField field, BeanValidatorScope scope, boolean sort, String... messages) { + + JComponent editor = validator.getFieldRepresentation(field.getName()); + // add new errors + for (String error : messages) { + SwingValidatorMessage row = new SwingValidatorMessage(validator, field, error, scope, editor); + data.add(row); + if (!sort) { + fireIntervalAdded(this, data.size() - 1, data.size() - 1); + } + } + + if (sort) { + + // resort datas + java.util.Collections.sort(data); + + // notify + fireContentsChanged(this, 0, getSize() - 1); + } + } + + protected void removeMessages(SwingValidator validator, BeanValidatorField field, BeanValidatorScope scope, boolean notify, String... messages) { + + List<String> messagesToDel = new java.util.ArrayList<String>(java.util.Arrays.asList(messages)); + + // do it in reverse mode (only one pass in that way since index + // will stay coherent while removing them) + + for (int i = getSize() - 1; i > -1; i--) { + SwingValidatorMessage error = data.get(i); + if (error.getValidator() == validator && error.getScope() == scope && error.getField() == field && messagesToDel.contains(error.getMessage())) { + // remove the message + data.remove(i); + if (notify) { + fireIntervalRemoved(this, i, i); + } + } + } + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/SwingValidatorMessageListMouseListener.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/SwingValidatorMessageListMouseListener.java new file mode 100644 index 0000000..7505620 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/SwingValidatorMessageListMouseListener.java @@ -0,0 +1,60 @@ +package jaxx.runtime.validator.swing; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.swing.JComponent; +import javax.swing.JList; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/** + * A mouse listener to put on a {@link javax.swing.JList} with a {@link SwingValidatorMessageListModel} as a model. + * <p/> + * When a double click occurs, find the selected error in model and then focus to the associated component of error. + * + * @author chemit + */ +public class SwingValidatorMessageListMouseListener extends MouseAdapter { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(SwingValidatorMessageListMouseListener.class); + + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + if (e.getClickCount() == 2) { + + SwingValidatorMessage entry = getSelectedMessage(e); + if (entry == null) { + // no entry found + return; + } + JComponent component = entry.getEditor(); + if (component != null) { + component.requestFocus(); + } + } + } + + protected SwingValidatorMessage getSelectedMessage(MouseEvent e) { + JList list = (JList) e.getSource(); + if (!(list.getModel() instanceof SwingValidatorMessageListModel)) { + log.warn("model must be a " + SwingValidatorMessageListModel.class + ", but was " + list.getModel()); + return null; + } + + SwingValidatorMessageListModel model = (SwingValidatorMessageListModel) list.getModel(); + int index = list.getSelectionModel().getMinSelectionIndex(); + if (index == -1) { + // nothing is selected + return null; + } + SwingValidatorMessage entry = (SwingValidatorMessage) model.getElementAt(index); + if (log.isDebugEnabled()) { + log.debug("selected index: " + index + " : error: " + entry); + } + return entry; + } + +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/SwingValidatorMessageListRenderer.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/SwingValidatorMessageListRenderer.java new file mode 100644 index 0000000..df6fcbd --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/SwingValidatorMessageListRenderer.java @@ -0,0 +1,90 @@ +package jaxx.runtime.validator.swing; + +import javax.swing.ImageIcon; +import javax.swing.JLabel; +import javax.swing.JList; +import java.awt.Component; +import javax.swing.DefaultListCellRenderer; +import jaxx.runtime.validator.BeanValidatorScope; +import jaxx.runtime.SwingValidatorUtil; +import static org.nuiton.i18n.I18n._; + +/** + * A simple render of a table of validator's messages, says a table that use + * a {@link SwingValidatorMessageTableModel} model. + * + * @author chemit + * @since 1.3 + * @see SwingValidatorMessageTableModel + */ +public class SwingValidatorMessageListRenderer extends DefaultListCellRenderer { + + private static final long serialVersionUID = 1L; + protected String format = "%1$-20s - %2$s"; + protected String formatTip = "%1$-20s - %2$-20s : %3$s"; + + public SwingValidatorMessageListRenderer() { + } + + public SwingValidatorMessageListRenderer(String format) { + this.format = format; + } + + public String getFormat() { + return format; + } + + public void setFormat(String format) { + this.format = format; + } + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + + JLabel rendererComponent = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + + SwingValidatorMessage model = (SwingValidatorMessage) value; + + // scope + ImageIcon icon = SwingValidatorUtil.getIcon(model.getScope()); + + // field name + String fieldName = getFieldName(list, model.getField().getName(), index); + + // message + String message = getMessage(model); + + // text to display + String text = String.format(format, fieldName, message); + + String label = _(model.getScope().getLabel()); + String tmp = _("validator.scope.tip", label); + String tmp2 = _("validator.field.tip", fieldName); + + String tooltTipText = String.format(formatTip, tmp, tmp2, message); + + + rendererComponent.setText(text); + rendererComponent.setToolTipText(tooltTipText); + rendererComponent.setIcon(icon); + + return rendererComponent; + } + + public ImageIcon getIcon(BeanValidatorScope scope) { + ImageIcon icon = SwingValidatorUtil.getIcon(scope); + return icon; + } + + public String getMessage(SwingValidatorMessage model) { + String text = SwingValidatorUtil.getMessage(model); + return text; + } + + public String getFieldName(JList list, String value, int row) { + SwingValidatorMessageListModel tableModel = (SwingValidatorMessageListModel) list.getModel(); + SwingValidatorMessage model = (SwingValidatorMessage) tableModel.getElementAt(row); + String fieldName = SwingValidatorUtil.getFieldName(model, value); + return fieldName; + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/SwingValidatorMessageTableModel.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/SwingValidatorMessageTableModel.java new file mode 100644 index 0000000..400adab --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/SwingValidatorMessageTableModel.java @@ -0,0 +1,327 @@ +package jaxx.runtime.validator.swing; + +import jaxx.runtime.validator.BeanValidatorEvent; + +import javax.swing.JComponent; +import java.util.ArrayList; +import java.util.List; +import jaxx.runtime.validator.BeanValidatorField; +import jaxx.runtime.validator.BeanValidatorScope; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * The model of the table of errors. + * + * The model listens validators messages and update his internal model from it. + * + * @author chemit + * @since 1.3 + */ +public class SwingValidatorMessageTableModel + extends javax.swing.table.AbstractTableModel + implements jaxx.runtime.validator.BeanValidatorListener { + + private static final long serialVersionUID = 1L; + /** to use log facility, just put in your code: log.info(\"...\"); */ + private static Log log = LogFactory.getLog(SwingValidatorMessageTableMouseListener.class); + public static final String[] columnNames = {"validator.scope", "validator.field", "validator.message"}; + public static final Class<?>[] columnClasses = {BeanValidatorScope.class, String.class, String.class}; + /** list of registred validators */ + protected transient List<SwingValidator<?>> validators; + /** list of messages actual displayed */ + protected List<SwingValidatorMessage> data; + + public SwingValidatorMessageTableModel() { + super(); + validators = new ArrayList<SwingValidator<?>>(); + data = new java.util.ArrayList<SwingValidatorMessage>(); + } + + /** + * Register a validator for this model. + * + * + * Note: a validator can not be register twice in the same model. + * + * @param validator the validator to register + */ + public void registerValidator(SwingValidator<?> validator) { + if (validators.contains(validator)) { + throw new IllegalArgumentException("the validator " + validator + " is already registred in " + this); + } + validators.add(validator); + validator.addBeanValidatorListener(this); + } + + public void addMessages(SwingValidator validator, String fieldName, BeanValidatorScope scope, String... messages) { + addMessages(validator, fieldName, scope, true, messages); + } + + public void addMessages(JComponent editor, String fieldName, BeanValidatorScope scope, String... messages) { + addMessages(editor, fieldName, scope, true, messages); + } + + public void addMessages(SwingValidator validator, BeanValidatorField field, BeanValidatorScope scope, String... messages) { + addMessages(validator, field, scope, true, messages); + } + + public void removeMessages(JComponent editor, BeanValidatorScope scope) { + + // do it in reverse mode (only one pass in that way since index + // will stay coherent while removing them) + + for (int i = getRowCount() - 1; i > -1; i--) { + SwingValidatorMessage error = data.get(i); + if (error.getEditor() == editor && (scope == null || error.getScope() == scope)) { + // remove the message + data.remove(i); + fireTableRowsDeleted(i, i); + } + } + } + + public void removeMessages(SwingValidator validator, String fieldName, BeanValidatorScope scope, String... messages) { + removeMessages(validator, fieldName, scope, true, messages); + } + + public void removeMessages(JComponent editor, String fieldName, BeanValidatorScope scope) { + removeMessages(editor, fieldName, scope, true); + } + + public void removeMessages(SwingValidator validator, BeanValidatorField field, BeanValidatorScope scope, String... messages) { + removeMessages(validator, field, scope, true, messages); + } + + public void clear() { + int i = data.size(); + if (i > 0) { + data.clear(); + fireTableRowsDeleted(0, i - 1); + } + } + + /** + * Obtain the message for a given row. + * + * @param rowIndex the row index + * @return the message for the given row index + */ + public SwingValidatorMessage getRow(int rowIndex) { + ensureRowIndex(rowIndex); + return data.get(rowIndex); + } + + @Override + public boolean isCellEditable(int row, int column) { + // cells are never editable in this model + return false; + } + + @Override + public Class<?> getColumnClass(int columnIndex) { + ensureColumnIndex(columnIndex); + return columnClasses[columnIndex]; + } + + @Override + public String getColumnName(int column) { + ensureColumnIndex(column); + return columnNames[column]; + } + + @Override + public void onFieldChanged(BeanValidatorEvent event) { + String[] toDelete = event.getMessagesToDelete(); + String[] toAdd = event.getMessagesToAdd(); + BeanValidatorField field = event.getField(); + BeanValidatorScope scope = event.getScope(); + boolean mustAdd = toAdd != null && toAdd.length > 0; + boolean mustDel = toDelete != null && toDelete.length > 0; + + if (log.isTraceEnabled()) { + log.trace("----------------------------------------------------------"); + log.trace(field + " - (" + getRowCount() + ") toAdd " + mustAdd); + log.trace(field + " - (" + getRowCount() + ") toDelete " + mustDel); + } + + SwingValidator validator = (SwingValidator) event.getSource(); + + if (mustDel) { + + // removes datas and notify if no messages to add + removeMessages(validator, field, scope, !mustAdd, toDelete); + } + + if (mustAdd) { + + // add new messages, sort datas and notify + addMessages(validator, field, scope, true, toAdd); + } + } + + @Override + public int getRowCount() { + return data.size(); + } + + @Override + public int getColumnCount() { + return columnNames.length; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + ensureColumnIndex(columnIndex); + ensureRowIndex(rowIndex); + + SwingValidatorMessage row = data.get(rowIndex); + if (columnIndex == 0) { + // the icon + return row.getScope(); + } + if (columnIndex == 1) { + // the field + return row.getFieldName(); + } + if (columnIndex == 2) { + // the message + return row.getMessage(); + } + + // should never come here + return null; + } + + protected void ensureRowIndex(int rowIndex) throws ArrayIndexOutOfBoundsException { + if (rowIndex < -1 || rowIndex >= getRowCount()) { + throw new ArrayIndexOutOfBoundsException("the rowIndex was " + rowIndex + ", but should be int [0," + (getRowCount() - 1) + "]"); + } + } + + protected void ensureColumnIndex(int index) throws ArrayIndexOutOfBoundsException { + if (index < -1 || index >= getColumnCount()) { + throw new ArrayIndexOutOfBoundsException("the columnIndex was " + index + ", but should be int [0," + (getColumnCount() - 1) + "]"); + } + } + + protected void addMessages(SwingValidator validator, BeanValidatorField field, BeanValidatorScope scope, boolean sort, String... messages) { + + JComponent editor = validator == null ? null : validator.getFieldRepresentation(field.getName()); + // add new errors + for (String error : messages) { + SwingValidatorMessage row = new SwingValidatorMessage(validator, field, error, scope, editor); + data.add(row); + if (!sort) { + fireTableRowsInserted(data.size() - 1, data.size() - 1); + } + } + + if (sort) { + + // resort datas + java.util.Collections.sort(data); + + // notify + fireTableDataChanged(); + } + } + + protected void addMessages(SwingValidator validator, String fieldName, BeanValidatorScope scope, boolean sort, String... messages) { + + JComponent editor = validator == null ? null : validator.getFieldRepresentation(fieldName); + // add new errors + for (String error : messages) { + SwingValidatorMessage row = new SwingValidatorMessage(validator, fieldName, error, scope, editor); + data.add(row); + if (!sort) { + fireTableRowsInserted(data.size() - 1, data.size() - 1); + } + } + + if (sort) { + + // resort datas + java.util.Collections.sort(data); + + // notify + fireTableDataChanged(); + } + } + + protected void addMessages(JComponent editor, String fieldName, BeanValidatorScope scope, boolean sort, String... messages) { + + // add new errors + for (String error : messages) { + SwingValidatorMessage row = new SwingValidatorMessage(null, fieldName, error, scope, editor); + data.add(row); + if (!sort) { + fireTableRowsInserted(data.size() - 1, data.size() - 1); + } + } + + if (sort) { + + // resort datas + java.util.Collections.sort(data); + + // notify + fireTableDataChanged(); + } + } + + protected void removeMessages(SwingValidator validator, BeanValidatorField field, BeanValidatorScope scope, boolean notify, String... messages) { + + List<String> messagesToDel = new java.util.ArrayList<String>(java.util.Arrays.asList(messages)); + + // do it in reverse mode (only one pass in that way since index + // will stay coherent while removing them) + + for (int i = getRowCount() - 1; i > -1; i--) { + SwingValidatorMessage error = data.get(i); + if (error.getValidator() == validator && error.getScope() == scope && error.getFieldName().equals(field.getName()) && messagesToDel.contains(error.getMessage())) { + // remove the message + data.remove(i); + if (notify) { + fireTableRowsDeleted(i, i); + } + } + } + } + + protected void removeMessages(SwingValidator validator, String fieldName, BeanValidatorScope scope, boolean notify, String... messages) { + + List<String> messagesToDel = new java.util.ArrayList<String>(java.util.Arrays.asList(messages)); + + // do it in reverse mode (only one pass in that way since index + // will stay coherent while removing them) + + for (int i = getRowCount() - 1; i > -1; i--) { + SwingValidatorMessage error = data.get(i); + if (error.getValidator() == validator && error.getScope() == scope && error.getFieldName().equals(fieldName) && messagesToDel.contains(error.getMessage())) { + // remove the message + data.remove(i); + if (notify) { + fireTableRowsDeleted(i, i); + } + } + } + } + + protected void removeMessages(JComponent editor, String fieldName, BeanValidatorScope scope, boolean notify) { + + // do it in reverse mode (only one pass in that way since index + // will stay coherent while removing them) + + for (int i = getRowCount() - 1; i > -1; i--) { + SwingValidatorMessage error = data.get(i); + if (error.getEditor() == editor && (scope == null || error.getScope() == scope) && error.getFieldName().equals(fieldName)) { + // remove the message + data.remove(i); + if (notify) { + fireTableRowsDeleted(i, i); + } + } + } + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/SwingValidatorMessageTableMouseListener.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/SwingValidatorMessageTableMouseListener.java new file mode 100644 index 0000000..8bb068c --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/SwingValidatorMessageTableMouseListener.java @@ -0,0 +1,94 @@ +package jaxx.runtime.validator.swing; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.swing.JComponent; +import javax.swing.JTable; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; + +/** + * A mouse listener to put on a {@link javax.swing.JList} with a {@link SwingValidatorMessageTableModel} as a model. + * <p/> + * When a double click occurs, find the selected error in model and then focus to the associated component of error. + * + * @author chemit + */ +public class SwingValidatorMessageTableMouseListener extends MouseAdapter { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + private static Log log = LogFactory.getLog(SwingValidatorMessageTableMouseListener.class); + + public static final String HIGHLIGHT_ERROR_PROPERTY = "highlightError"; + + /** delgate property change support */ + protected PropertyChangeSupport pcs; + + public SwingValidatorMessageTableMouseListener() { + pcs = new PropertyChangeSupport(this); + } + + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + if (e.getClickCount() == 2) { + + SwingValidatorMessage entry = getSelectedMessage(e); + if (entry == null) { + // no entry found + return; + } + JComponent component = entry.getEditor(); + if (component != null) { + pcs.firePropertyChange(HIGHLIGHT_ERROR_PROPERTY, null, entry); + if (component.isVisible()) { + component.requestFocus(); + } + } + } + } + + + protected SwingValidatorMessage getSelectedMessage(MouseEvent e) { + JTable table = (JTable) e.getSource(); + if (!(table.getModel() instanceof SwingValidatorMessageTableModel)) { + log.warn("model must be a " + SwingValidatorMessageTableModel.class + ", but was " + table.getModel()); + return null; + } + + SwingValidatorMessageTableModel model = (SwingValidatorMessageTableModel) table.getModel(); + int index = table.getSelectionModel().getMinSelectionIndex(); + if (index == -1) { + // nothing is selected + return null; + } + if (table.getRowSorter() != null) { + index = table.getRowSorter().convertRowIndexToModel(index); + } + SwingValidatorMessage entry = model.getRow(index); + if (log.isDebugEnabled()) { + log.debug("selected index: " + index + " : error: " + entry); + } + return entry; + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + pcs.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + pcs.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.removePropertyChangeListener(propertyName, listener); + } + +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/SwingValidatorMessageTableRenderer.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/SwingValidatorMessageTableRenderer.java new file mode 100644 index 0000000..d4e83bc --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/SwingValidatorMessageTableRenderer.java @@ -0,0 +1,84 @@ +package jaxx.runtime.validator.swing; + +import javax.swing.ImageIcon; +import javax.swing.JLabel; +import javax.swing.JTable; +import javax.swing.table.DefaultTableCellRenderer; +import java.awt.Component; +import jaxx.runtime.validator.BeanValidatorScope; +import jaxx.runtime.SwingValidatorUtil; +import static org.nuiton.i18n.I18n._; + +/** + * A simple render of a table of validator's messages, says a table that use + * a {@link SwingValidatorMessageTableModel} model. + * + * @author chemit + * @since 1.3 + * @see SwingValidatorMessageTableModel + */ +public class SwingValidatorMessageTableRenderer extends DefaultTableCellRenderer { + + private static final long serialVersionUID = 1L; + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + JLabel rendererComponent = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + + ImageIcon icon = null; + String text = null; + String toolTipText = null; + + column = table.convertColumnIndexToModel(column); + if (table.getRowSorter() != null) { + row = table.getRowSorter().convertRowIndexToModel(row); + } + + + switch (column) { + case 0: + // scope + BeanValidatorScope scope = (BeanValidatorScope) value; + icon = SwingValidatorUtil.getIcon(scope); + String label = _(scope.getLabel()); + toolTipText = _("validator.scope.tip", label); + break; + + case 1: + // field name + text = getFieldName(table, (String) value, row); + toolTipText = _("validator.field.tip", text); + break; + + case 2: + // message + text = getMessage(table, (String) value, row); + toolTipText = _("validator.message.tip", text); + break; + } + + rendererComponent.setText(text); + rendererComponent.setToolTipText(toolTipText); + rendererComponent.setIcon(icon); + return rendererComponent; + } + + public ImageIcon getIcon(BeanValidatorScope scope) { + ImageIcon icon = SwingValidatorUtil.getIcon(scope); + return icon; + } + + public String getMessage(JTable table, String value, int row) { + SwingValidatorMessageTableModel tableModel = (SwingValidatorMessageTableModel) table.getModel(); + SwingValidatorMessage model = tableModel.getRow(row); + String text = SwingValidatorUtil.getMessage(model); + return text; + } + + public String getFieldName(JTable table, String value, int row) { + SwingValidatorMessageTableModel tableModel = (SwingValidatorMessageTableModel) table.getModel(); + SwingValidatorMessage model = tableModel.getRow(row); + String fieldName = SwingValidatorUtil.getFieldName(model, value); + return fieldName; + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/ui/AbstractBeanValidatorUI.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/ui/AbstractBeanValidatorUI.java new file mode 100644 index 0000000..38eb670 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/ui/AbstractBeanValidatorUI.java @@ -0,0 +1,37 @@ +package jaxx.runtime.validator.swing.ui; + +import jaxx.runtime.validator.BeanValidatorEvent; +import jaxx.runtime.validator.BeanValidatorField; +import jaxx.runtime.validator.BeanValidatorListener; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.jdesktop.jxlayer.plaf.AbstractLayerUI; + +/** + * Abstract renderer + * + * @author chemit + */ +public abstract class AbstractBeanValidatorUI extends AbstractLayerUI<javax.swing.JComponent> implements BeanValidatorListener { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + private static final Log log = LogFactory.getLog(AbstractBeanValidatorUI.class); + /** the field to render */ + protected BeanValidatorField field; + + public AbstractBeanValidatorUI(BeanValidatorField field) { + this.field = field; + if (log.isDebugEnabled()) { + log.debug("install " + this + "<field:" + field + ">"); + } + } + + @Override + public void onFieldChanged(BeanValidatorEvent event) { + if (field.equals(event.getField())) { + // ask to repaint the layer + setDirty(true); + } + } + +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/ui/IconValidationUI.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/ui/IconValidationUI.java new file mode 100644 index 0000000..1e192ce --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/ui/IconValidationUI.java @@ -0,0 +1,86 @@ +package jaxx.runtime.validator.swing.ui; + +import org.jdesktop.jxlayer.JXLayer; + +import javax.swing.BorderFactory; +import javax.swing.JComponent; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.image.BufferedImage; +import jaxx.runtime.validator.BeanValidatorField; +import jaxx.runtime.validator.BeanValidatorScope; + +/** @author chemit */ +public class IconValidationUI extends AbstractBeanValidatorUI { + + // The icon to be shown at the layer's corner + protected static BufferedImage errorIcon; + protected static BufferedImage warningIcon; + protected static BufferedImage infoIcon; + + public IconValidationUI(BeanValidatorField field) { + super(field); + if (errorIcon == null) { + errorIcon = prepareIcon(Color.RED); + } + if (warningIcon == null) { + warningIcon = prepareIcon(Color.ORANGE); + } + if (infoIcon == null) { + infoIcon = prepareIcon(Color.GREEN); + } + } + + @Override + public void installUI(JComponent c) { + super.installUI(c); + c.setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 3)); + } + + @Override + public void uninstallUI(JComponent c) { + super.uninstallUI(c); + c.setBorder(null); + } + + @Override + protected void paintLayer(Graphics2D g2, JXLayer<JComponent> l) { + super.paintLayer(g2, l); + // There is no need to take insets into account for this painter + BeanValidatorScope scope = field.getScope(); + if (scope != null) { + BufferedImage icon = null; + switch (scope) { + case ERROR: + icon = errorIcon; + break; + case WARNING: + icon = warningIcon; + break; + case INFO: + icon = infoIcon; + break; + } + if (icon != null) { + g2.drawImage(icon, l.getWidth() - icon.getWidth() - 1, 0, null); + } + } + } + + protected static BufferedImage prepareIcon(Color color) { + int width = 7; + int height = 8; + BufferedImage icon = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2 = (Graphics2D) icon.getGraphics(); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); + g2.setColor(color); + g2.fillRect(0, 0, width, height); + g2.setColor(Color.WHITE); + g2.drawLine(0, 0, width, height); + g2.drawLine(0, height, width, 0); + g2.dispose(); + return icon; + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/ui/ImageValidationUI.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/ui/ImageValidationUI.java new file mode 100644 index 0000000..868e09e --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/ui/ImageValidationUI.java @@ -0,0 +1,78 @@ +package jaxx.runtime.validator.swing.ui; + +import org.jdesktop.jxlayer.JXLayer; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.image.BufferedImage; +import jaxx.runtime.validator.BeanValidatorField; +import jaxx.runtime.validator.BeanValidatorScope; + +/** @author chemit */ +public class ImageValidationUI extends AbstractBeanValidatorUI { + + protected static BufferedImage errorIcon; + protected static BufferedImage warningIcon; + protected static BufferedImage infoIcon; + + public ImageValidationUI(BeanValidatorField field) { + super(field); + if (errorIcon == null) { + errorIcon = prepareIcon(jaxx.runtime.Util.createImageIcon("error.png")); + } + if (warningIcon == null) { + warningIcon = prepareIcon(jaxx.runtime.Util.createImageIcon("warning.png")); + } + if (infoIcon == null) { + infoIcon = prepareIcon(jaxx.runtime.Util.createImageIcon("info.png")); + } + } + + protected static BufferedImage prepareIcon(ImageIcon image) { + BufferedImage icon = new BufferedImage(image.getIconWidth(), image.getIconHeight(), BufferedImage.TYPE_INT_ARGB); + Graphics2D g2 = (Graphics2D) icon.getGraphics(); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); + g2.drawImage(image.getImage(), 0, 0, null); + g2.dispose(); + return icon; + } + + @Override + public void installUI(JComponent c) { + super.installUI(c); + c.setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 3)); + } + + @Override + public void uninstallUI(JComponent c) { + super.uninstallUI(c); + c.setBorder(null); + } + + @Override + protected void paintLayer(Graphics2D g2, JXLayer<JComponent> l) { + super.paintLayer(g2, l); + BeanValidatorScope scope = field.getScope(); + if (scope != null) { + BufferedImage icon = null; + switch (scope) { + case ERROR: + icon = errorIcon; + break; + case WARNING: + icon = warningIcon; + break; + case INFO: + icon = infoIcon; + break; + } + if (icon != null) { + g2.drawImage(icon, l.getWidth() - icon.getWidth() - 1, 0, null); + } + } + } +} \ No newline at end of file diff --git a/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/ui/TranslucentValidationUI.java b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/ui/TranslucentValidationUI.java new file mode 100644 index 0000000..ef21595 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/validator/swing/ui/TranslucentValidationUI.java @@ -0,0 +1,65 @@ +package jaxx.runtime.validator.swing.ui; + +import jaxx.runtime.validator.BeanValidatorScope; +import org.jdesktop.jxlayer.JXLayer; + +import javax.swing.JComponent; +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.Rectangle; +import jaxx.runtime.validator.BeanValidatorField; + +/** @author chemit */ +public class TranslucentValidationUI extends AbstractBeanValidatorUI { + + protected Color errorHightlight; + protected Color warningHightlight; + protected Color infoHightlight; + + public TranslucentValidationUI(BeanValidatorField field) { + super(field); + errorHightlight = Color.RED; + warningHightlight = Color.YELLOW; + infoHightlight = Color.GREEN; + } + + @Override + protected void paintLayer(Graphics2D g2, JXLayer<JComponent> l) { + // paints the layer as is + super.paintLayer(g2, l); + + // to be in sync with the view if the layer has a border + Insets layerInsets = l.getInsets(); + g2.translate(layerInsets.left, layerInsets.top); + + JComponent view = l.getView(); + // To prevent painting on view's border + Insets insets = view.getInsets(); + g2.clip(new Rectangle(insets.left, insets.top, + view.getWidth() - insets.left - insets.right, + view.getHeight() - insets.top - insets.bottom)); + + BeanValidatorScope scope = field.getScope(); + + if (scope == null) { + g2.setColor(Color.WHITE); + } else { + switch (scope) { + case ERROR: + g2.setColor(errorHightlight); + break; + case WARNING: + g2.setColor(warningHightlight); + break; + case INFO: + g2.setColor(infoHightlight); + break; + } + } + + g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .2f)); + g2.fillRect(0, 0, l.getWidth(), l.getHeight()); + } +} diff --git a/trunk/jaxx-runtime-swing/src/main/resources/i18n/jaxx-runtime-swing-en_GB.properties b/trunk/jaxx-runtime-swing/src/main/resources/i18n/jaxx-runtime-swing-en_GB.properties new file mode 100644 index 0000000..0374c36 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/resources/i18n/jaxx-runtime-swing-en_GB.properties @@ -0,0 +1,9 @@ +validator.field.header=Property +validator.field.header.tip=Property on which message occurs +validator.field.tip=Property '%1$s' +validator.message.header=Message +validator.message.header.tip=The message text +validator.message.tip=Message \: %1$s +validator.scope.header=... +validator.scope.header.tip=The message scope +validator.scope.tip=Message scope \: '%1$s' diff --git a/trunk/jaxx-runtime-swing/src/main/resources/i18n/jaxx-runtime-swing-fr_FR.properties b/trunk/jaxx-runtime-swing/src/main/resources/i18n/jaxx-runtime-swing-fr_FR.properties new file mode 100644 index 0000000..77a14d0 --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/main/resources/i18n/jaxx-runtime-swing-fr_FR.properties @@ -0,0 +1,9 @@ +validator.field.header=Champ +validator.field.header.tip=Le champ surquel intervient le message +validator.field.tip=Propri\u00E9t\u00E9 '%1$s' +validator.message.header=Message +validator.message.header.tip=Le texte du message +validator.message.tip=Message \: %1$s +validator.scope.header=... +validator.scope.header.tip=Le de type de message +validator.scope.tip=Type de message \: '%1$s' diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-delete.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-delete.png new file mode 100644 index 0000000..184f762 Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-delete.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-config-16.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-config-16.png new file mode 100644 index 0000000..9460dfc Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-config-16.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-config.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-config.png new file mode 100644 index 0000000..8ef7275 Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-config.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-message-16.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-message-16.png new file mode 100644 index 0000000..12cd1ae Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-message-16.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-message.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-message.png new file mode 100644 index 0000000..5aed843 Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-message.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-next-16.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-next-16.png new file mode 100644 index 0000000..6ef8de7 Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-next-16.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-next.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-next.png new file mode 100644 index 0000000..3fe7568 Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-next.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-pause-16.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-pause-16.png new file mode 100644 index 0000000..2d9ce9c Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-pause-16.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-pause.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-pause.png new file mode 100644 index 0000000..76ba422 Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-pause.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-previous-16.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-previous-16.png new file mode 100644 index 0000000..659cd90 Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-previous-16.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-previous.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-previous.png new file mode 100644 index 0000000..9bab29c Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-previous.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-refresh-16.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-refresh-16.png new file mode 100644 index 0000000..0de2656 Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-refresh-16.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-refresh.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-refresh.png new file mode 100644 index 0000000..ae1f596 Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-refresh.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-start-16.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-start-16.png new file mode 100644 index 0000000..0846555 Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-start-16.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-start.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-start.png new file mode 100644 index 0000000..8d36e63 Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-start.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-canceled-16.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-canceled-16.png new file mode 100644 index 0000000..c149c2b Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-canceled-16.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-canceled.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-canceled.png new file mode 100644 index 0000000..296415e Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-canceled.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-failed-16.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-failed-16.png new file mode 100644 index 0000000..c37bd06 Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-failed-16.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-failed.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-failed.png new file mode 100644 index 0000000..bed8b4f Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-failed.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-need_fix-16.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-need_fix-16.png new file mode 100644 index 0000000..628cf2d Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-need_fix-16.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-need_fix.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-need_fix.png new file mode 100644 index 0000000..1c6b8eb Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-need_fix.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-pending-16.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-pending-16.png new file mode 100644 index 0000000..893bb60 Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-pending-16.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-pending.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-pending.png new file mode 100644 index 0000000..2415154 Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-pending.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-running-16.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-running-16.png new file mode 100644 index 0000000..0846555 Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-running-16.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-running.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-running.png new file mode 100644 index 0000000..de1a5f3 Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-running.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-successed-16.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-successed-16.png new file mode 100644 index 0000000..a9925a0 Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-successed-16.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-successed.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-successed.png new file mode 100644 index 0000000..743ef89 Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/action-wizard-state-successed.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/error.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/error.png new file mode 100644 index 0000000..c37bd06 Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/error.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/info.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/info.png new file mode 100644 index 0000000..12cd1ae Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/info.png differ diff --git a/trunk/jaxx-runtime-swing/src/main/resources/icons/warning.png b/trunk/jaxx-runtime-swing/src/main/resources/icons/warning.png new file mode 100644 index 0000000..628cf2d Binary files /dev/null and b/trunk/jaxx-runtime-swing/src/main/resources/icons/warning.png differ diff --git a/trunk/jaxx-runtime-swing/src/site/site.xml b/trunk/jaxx-runtime-swing/src/site/site.xml new file mode 100644 index 0000000..6c8144f --- /dev/null +++ b/trunk/jaxx-runtime-swing/src/site/site.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project name="${project.name}"> + + <bannerLeft> + <name>${project.name}</name> + <src>${site.home.url}/jaxx.png</src> + <href>index.html</href> + </bannerLeft> + + <body> + + <breadcrumbs> + <item name="${project.name}" href="${project.url}" /> + </breadcrumbs> + + <menu ref="parent"/> + + <menu name="Utilisateur" inherited="top"/> + + <menu ref="reports"/> + + <menu ref="modules"/> + + </body> +</project> diff --git a/trunk/jaxx-swing-action/LICENSE.txt b/trunk/jaxx-swing-action/LICENSE.txt new file mode 100644 index 0000000..3f7b8b1 --- /dev/null +++ b/trunk/jaxx-swing-action/LICENSE.txt @@ -0,0 +1,166 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/trunk/jaxx-swing-action/README.txt b/trunk/jaxx-swing-action/README.txt new file mode 100644 index 0000000..d2e50d3 --- /dev/null +++ b/trunk/jaxx-swing-action/README.txt @@ -0,0 +1,2 @@ +To deploy new version of pom: mvn deploy +To install localy: mvn install diff --git a/trunk/jaxx-swing-action/changelog.txt b/trunk/jaxx-swing-action/changelog.txt new file mode 100644 index 0000000..aebecde --- /dev/null +++ b/trunk/jaxx-swing-action/changelog.txt @@ -0,0 +1,10 @@ +1.3 chemit 20090409 + +1.1 chemit 20090220 + * 20090122 [chemit] - refactor poms (sibling dependencies, pluginsManagment,...) + - rename i18n bundles according artifactId + +1.0 chemit 20090111 + +0.7 chemit 200812?? + * 20081207 [chemit] use lutinproject 3.1 \ No newline at end of file diff --git a/trunk/jaxx-swing-action/pom.xml b/trunk/jaxx-swing-action/pom.xml new file mode 100644 index 0000000..e49e6d0 --- /dev/null +++ b/trunk/jaxx-swing-action/pom.xml @@ -0,0 +1,85 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + + <!-- ************************************************************* --> + <!-- *** POM Relationships *************************************** --> + <!-- ************************************************************* --> + + <parent> + <groupId>org.nuiton</groupId> + <artifactId>jaxx</artifactId> + <version>1.7.1</version> + </parent> + + <groupId>org.nuiton.jaxx</groupId> + <artifactId>jaxx-swing-action</artifactId> + + <dependencies> + + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>jaxx-runtime-swing</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>jboss</groupId> + <artifactId>javassist</artifactId> + <version>3.7.ga</version> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </dependency> + + </dependencies> + + <!-- ************************************************************* --> + <!-- *** Project Information ************************************* --> + <!-- ************************************************************* --> + + <name>${project.artifactId}</name> + <description>Jaxx lutin library swing extension (tabs and actions)</description> + + <!-- ************************************************************* --> + <!-- *** Build Settings ****************************************** --> + <!-- ************************************************************* --> + <packaging>jar</packaging> + + <build> + + <pluginManagement> + <plugins> + <plugin> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <!-- the code contains some AnnotationProcessor --> + <compilerArgument>-proc:none</compilerArgument> + </configuration> + </plugin> + </plugins> + </pluginManagement> + + <plugins> + + <plugin> + <groupId>org.nuiton.i18n</groupId> + <artifactId>maven-i18n-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>parserJava</goal> + <goal>gen</goal> + </goals> + </execution> + </executions> + </plugin> + + </plugins> + </build> + +</project> diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/AbstractActionConfigurationResolver.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/AbstractActionConfigurationResolver.java new file mode 100644 index 0000000..14ac574 --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/AbstractActionConfigurationResolver.java @@ -0,0 +1,77 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.action; + +import javax.swing.JComponent; + +/** + * Common abstract class of a resolver of action configuration. + * <p/> + * The class implements the logic of research of the configuration annotation. + * + * @param <A> type of annotation + * @param <C> type of component + * @author chemit + */ +public abstract class AbstractActionConfigurationResolver<A extends java.lang.annotation.Annotation, C extends JComponent> implements ActionConfigurationResolver<A, C> { + + /** the type of configuration's annotation */ + protected final Class<A> annotationImpl; + + /** the type of component that can fire an action */ + protected final Class<C> componentImpl; + + /** + * The typed method (on component) to apply configuration on the action and component. + * + * @param component the component which fires the action + * @param action the given action + * @return the configuration's annotation + */ + protected abstract A applyConfiguration0(C component, MyAbstractAction action); + + protected AbstractActionConfigurationResolver(Class<A> annotationImpl, Class<C> componentImpl) { + this.annotationImpl = annotationImpl; + this.componentImpl = componentImpl; + } + + @Override + public A resolveConfiguration(MyAbstractAction action) { + if (action.hasDelegate()) { + return resolveConfiguration(action.getDelegate()); + } + return action.getClass().getAnnotation(annotationImpl); + } + + @SuppressWarnings({"unchecked"}) + @Override + public A applyConfiguration(JComponent component, MyAbstractAction action) { + if (component != null && componentImpl.isAssignableFrom(component.getClass())) { + return applyConfiguration0((C) component, action); + } + + return null; + } + + @Override + public Class<A> getAnnotationImpl() { + return annotationImpl; + } + + @Override + public Class<C> getComponentImpl() { + return componentImpl; + } +} diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionAnnotationProcessing.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionAnnotationProcessing.java new file mode 100644 index 0000000..343ce49 --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionAnnotationProcessing.java @@ -0,0 +1,398 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ + + +package org.nuiton.jaxx.action; + +import javassist.CannotCompileException; +import javassist.ClassPool; +import javassist.CtClass; +import javassist.CtConstructor; +import javassist.LoaderClassPath; +import javassist.NotFoundException; +import org.nuiton.util.SortedProperties; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedOptions; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.AnnotationValueVisitor; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.SimpleAnnotationValueVisitor6; +import javax.tools.FileObject; +import javax.tools.JavaFileObject; +import javax.tools.StandardLocation; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Map.Entry; +import java.util.Properties; +import java.util.Set; + + +@SupportedAnnotationTypes(value = {"org.nuiton.jaxx.action.*"}) +@SupportedSourceVersion(SourceVersion.RELEASE_6) +@SupportedOptions({"jaxx.verbose"}) +/** + * Annotation processor to compute actions mapping. + * + * @author chemit */ +public class ActionAnnotationProcessing extends AbstractProcessor { + + /** the {@link ActionProvider} service declaration relative path */ + protected String providerDeclarationLocation = "META-INF/services/" + ActionProvider.class.getName(); + + /** the relative path where to store actions mapping, will be complete with the name of base action to use */ + protected String actionsFileLocation = ActionProviderFromProperties.actionsFileLocation; + + /** verbose flag (can be activated by passing an annotation parameter to compiler via <code>-Ai18n.verbose</code>) */ + protected boolean verbose; + + /** the list of class processed by the processor */ + protected java.util.List<String> processedClass; + + /** the map of actions processed, keys are the action commaned and values are fqn of implementations */ + protected Properties actions; + + /** Extractor of values of annotations found */ + protected AnnotationValueVisitor<Object, Void> annotationValueExtractor; + + /** the type element of the base action to be used by {@link ActionProvider} */ + protected TypeElement baseActionElement; + + /** the fqn of the action provider to generate */ + protected String providerFQN; + + /** the fqn of the base action class to be used */ + protected String baseFQN; + + @Override + public synchronized void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + parseOptions(); + printDebug("verbose : " + verbose); + printDebug("FileLocation : " + actionsFileLocation); + processedClass = new ArrayList<String>(); + actions = new SortedProperties(); + } + + @Override + public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { + for (TypeElement annotation : annotations) { + + Set<? extends Element> annotatedWith = roundEnv.getElementsAnnotatedWith(annotation); + + if (annotation.getQualifiedName().toString().equals(ActionProviderAnnotation.class.getName())) { + // init provider + if (annotatedWith.size() != 1) { + throw new IllegalStateException("can have only one provider defined by the annotation " + ActionProviderAnnotation.class); + } + + baseActionElement = (TypeElement) annotatedWith.iterator().next(); + + //fixme it is not possible to know if baseActionElement is assigned from MyAbstractAction, since we + // can NOT garanted at this stage thaht the class was compiled... + + baseFQN = baseActionElement.asType().toString(); + int index = baseFQN.lastIndexOf(".") + 1; + String baseSimpleName = baseFQN.substring(index); + String packageName = baseFQN.substring(0, index); + + providerFQN = packageName + baseSimpleName + "Provider"; + printDebug("providerFQN " + providerFQN); + actionsFileLocation = String.format(actionsFileLocation, baseSimpleName); + continue; + } + + for (Element e : annotatedWith) { + String className = e.toString(); + + if (processedClass.contains(className)) { + printWarning("class already processed " + className); + // do not process class twice + continue; + } + + boolean wasTreated = registerActionsForClass(annotation.asType(), e); + if (wasTreated) { + printDebug("process class " + className); + processedClass.add(className); + } else { + printDebug("class was not processed " + e); + } + } + } + + if ((roundEnv.processingOver())) { + printDebug("round is over " + roundEnv); + try { + if (baseActionElement != null) { + // found the base action class to be compiled, so we have to write provider things... + writeProviderClass(); + writeProviderServiceDeclaration(); + } else { + + // baseActionClass was not compiled at this time, must find it back + // this means they should have an already mapping file written + + actionsFileLocation = findMappingFile(); + + printInfo("reused actionFilesLocation " + actionsFileLocation); + } + + writeActionMapping(); + + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + processedClass.clear(); + actions.clear(); + } + } + + return true; + } + + protected String findMappingFile() throws IOException { + String path = String.format(actionsFileLocation, "dummy_" + System.nanoTime()); + + + FileObject oldFo = processingEnv.getFiler().getResource(StandardLocation.SOURCE_OUTPUT, "", path); + File dummyFile = new File(oldFo.toUri().toString()).getParentFile(); + File[] files = dummyFile.listFiles(new FilenameFilter() { + + public boolean accept(File dir, String name) { + return name.startsWith("jaxx-") && name.endsWith("-actions.properties"); + } + }); + if (files.length < 1) { + // this is not normal, should have exactly one file here + throw new IllegalStateException("no provider name found, you must add on baseaction the annotation " + ActionProviderAnnotation.class); + } + File f = files[0]; + int index = f.getAbsolutePath().indexOf("META-INF"); + + return f.getAbsolutePath().substring(index); + } + + protected boolean registerActionsForClass(TypeMirror annotationType, Element e) { + boolean doTreate = false; + for (AnnotationMirror mirror : e.getAnnotationMirrors()) { + if (!mirror.getAnnotationType().equals(annotationType)) { + // do not treate other annotations + continue; + } + doTreate = true; + printDebug("found a annotation to treate : " + mirror + " for action : " + e.toString()); + for (String name : getActionNames(mirror)) { + actions.put("action." + name, e.toString()); + printDebug("registerActionForClass " + name + " : " + e.toString()); + } + } + return doTreate; + } + + protected void parseOptions() { + java.util.Map options = processingEnv.getOptions(); + verbose = options.containsKey("jaxx.verbose"); + } + + protected void writeProviderClass() throws IOException, NotFoundException, CannotCompileException, ClassNotFoundException { + OutputStream outputStream = null; + try { + + ClassPool pool = ClassPool.getDefault(); + + pool.appendClassPath(new LoaderClassPath(ActionProviderFromProperties.class.getClassLoader())); + + CtClass superClass = pool.get(ActionProviderFromProperties.class.getName()); + CtClass clazz = pool.makeClass(providerFQN); + // define the base action class in javassist pool to make possible compilation + pool.makeClass(baseFQN); + clazz.setSuperclass(superClass); + // add constructor + CtConstructor constructor = new CtConstructor(null, clazz); + constructor.setBody("super( " + baseFQN + ".class);"); + clazz.addConstructor(constructor); + byte[] byteCode = clazz.toBytecode(); + + JavaFileObject fo = processingEnv.getFiler().createClassFile(providerFQN); + printInfo("writing " + fo.toUri()); + outputStream = fo.openOutputStream(); + outputStream.write(byteCode); + + } finally { + if (outputStream != null) { + outputStream.close(); + } + } + } + + protected void writeProviderServiceDeclaration() throws IOException { + BufferedWriter w = null; + try { + FileObject fo = processingEnv.getFiler().createResource(StandardLocation.SOURCE_OUTPUT, "", providerDeclarationLocation); + printInfo("writing " + fo.toUri()); + w = new BufferedWriter(fo.openWriter()); + w.append("# generated by ").append(getClass().getName()).append("\n").toString(); + w.append("#").append(new java.util.Date().toString()).append("\n").toString(); + w.append(providerFQN); + } finally { + if (w != null) { + w.close(); + } + } + } + + protected void writeActionMapping() throws IOException { + if (actions.isEmpty()) { + // nothing to write or overwrite + return; + } + + BufferedWriter w = null; + try { + Properties oldProps = loadOldActionMapping(); + if (oldProps != null) { + oldProps.putAll(actions); + actions = oldProps; + } + // ecriture de toutes les actions trouvees + FileObject fo = processingEnv.getFiler().createResource(StandardLocation.SOURCE_OUTPUT, "", actionsFileLocation); + printInfo("writing " + fo.toUri()); + w = new BufferedWriter(fo.openWriter()); + actions.store(w, "generated by " + getClass().getName()); + } finally { + if (w != null) { + w.close(); + } + } + } + + protected Properties loadOldActionMapping() throws IOException { + // reprise sur une ancienne compilation + FileObject oldFo = processingEnv.getFiler().getResource(StandardLocation.SOURCE_OUTPUT, "", actionsFileLocation); + if (!new File(oldFo.toUri().toString()).exists()) { + return null; + } + Properties oldProps = new SortedProperties(); + InputStream inputStream = null; + try { + inputStream = oldFo.openInputStream(); + if (inputStream != null) { + oldProps.load(inputStream); + } + oldFo.delete(); + } finally { + if (inputStream != null) { + inputStream.close(); + } + } + + return oldProps; + } + + /** + * Obtain the array of names to be used by the annotation + * + * @param element the dictonnary of values found in a annotation + * @return thee array of names detected in the annotation + */ + @SuppressWarnings({"unchecked"}) + protected String[] getActionNames(AnnotationMirror element) { + String[] result = null; + for (Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : element.getElementValues().entrySet()) { + ExecutableElement type = entry.getKey(); + String name = type.getSimpleName().toString(); + + if ("actionCommands".equals(name)) { + List<String> stringList = (List<String>) entry.getValue().accept(getAnnotationValueExtractor(), null); + result = stringList.toArray(new String[stringList.size()]); + // a actionCommands field means + break; + } + if ("actionCommandProvider".equals(name)) { + TypeMirror t = (TypeMirror) entry.getValue().accept(getAnnotationValueExtractor(), null); + String classname = t.toString(); + printDebug("actionCommandProvider = " + classname); + if (classname.equals(ActionNameProvider.class.getName())) { + continue; + } + + // means there is a runtime names provider + result = new String[]{":" + classname}; + break; + } + if ("actionCommand".equals(name)) { + result = new String[]{(String) entry.getValue().accept(getAnnotationValueExtractor(), null)}; + } + } + + return result; + } + + protected AnnotationValueVisitor<Object, Void> getAnnotationValueExtractor() { + if (annotationValueExtractor == null) { + annotationValueExtractor = new SimpleAnnotationValueVisitor6<Object, Void>() { + + @Override + protected Object defaultAction(Object o, Void aVoid) { + return o; + } + + @Override + public Object visitArray(List<? extends AnnotationValue> vals, Void aVoid) { + List<Object> realVals = new java.util.ArrayList<Object>(); + for (AnnotationValue val : vals) { + realVals.add(val.accept(this, aVoid)); + } + return realVals; + } + + public Object visitType(TypeMirror t, Void aVoid) { + return t; + } + }; + } + return annotationValueExtractor; + } + + protected void printWarning(String msg) { + System.out.println("[WARN] " + getClass().getName() + " : " + msg); + } + + protected void printInfo(String msg) { + System.out.println("[INFO] " + getClass().getName() + " : " + msg); + } + + protected void printDebug(String msg) { + if (verbose) { + System.out.println("[DEBUG] " + getClass().getName() + " : " + msg); + } + } +} diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionConfig.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionConfig.java new file mode 100644 index 0000000..40b15bd --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionConfig.java @@ -0,0 +1,122 @@ +/* +* ##% Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 Code Lutin, +* Tony Chemit, Gabriel Landais +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* ##% */ +package org.nuiton.jaxx.action; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Pour enregister une action. + * <p/> + * Placer cette annotation sur la classe implantant l'action, + * <p/> + * les informations décrites seront utilisées pour instancier l'action + * + * @author chemit + */ +@Retention(RetentionPolicy.RUNTIME) + +@Target(ElementType.TYPE) +@Inherited +public @interface ActionConfig { + + /** + * @return la clef de la commande (doit être unique) + * @see javax.swing.Action#ACTION_COMMAND_KEY + */ + String actionCommand(); + + /** @return array of names to be used in actions mapping */ + String[] actionCommands() default {}; + + /** + * @return the class to obtain at runtime the array of names to be used in actions mapping. + * <p/> + * <b>Note : the special value {@link org.nuiton.jaxx.action.ActionNameProvider} is used to says not to used + * œthis mecanism since we can not set a null value in a annotation</b> + */ + Class<? extends ActionNameProvider> actionCommandProvider() default org.nuiton.jaxx.action.ActionNameProvider.class; + + /** + * @return la clef i18n du texte de l'action, si vide ignoré + * @see javax.swing.Action#NAME + */ + String name() default ""; + + /** + * @return la clef i18n du tooltip de l'action, si vide ignoré + * @see javax.swing.Action#SHORT_DESCRIPTION + */ + String shortDescription() default ""; + + /** + * @return la clef i18n du texte de l'action, si vide ignoré + * @see javax.swing.Action#LONG_DESCRIPTION + */ + String longDescription() default ""; + + /** + * @return le nom de l'icone associé, si vide ignoré + * @see javax.swing.Action#SMALL_ICON + */ + String smallIcon() default ""; + + /** + * @return le nom du grande icone associé, si vide ignoré + * @see javax.swing.Action#LARGE_ICON_KEY + */ + String largeIcon() default ""; + + /** + * @return accelerator + * @see javax.swing.Action#ACCELERATOR_KEY + */ + String accelerator() default ""; + + /** + * @return mnemonic key + * @see javax.swing.Action#MNEMONIC_KEY + */ + int mnemonic() default '\0'; + + /** + * @return mnemonic key index + * @see javax.swing.Action#DISPLAYED_MNEMONIC_INDEX_KEY + */ + int displayedMnemonicIndex() default '\0'; + + /** + * @return la valeur par défaut pour les component selectable + * @see javax.swing.Action#SELECTED_KEY + */ + boolean selected() default false; + + /** + * @return enabled state + * @see javax.swing.Action#isEnabled() + */ + boolean enabled() default true; + + /** @return hideActionText state */ + boolean hideActionText() default false; + +} \ No newline at end of file diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionConfigConfigurationResolver.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionConfigConfigurationResolver.java new file mode 100644 index 0000000..828eef4 --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionConfigConfigurationResolver.java @@ -0,0 +1,68 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.action; + +import static org.nuiton.i18n.I18n._; + +import javax.swing.AbstractButton; +import javax.swing.Action; + +/** + * Implementation of configuration's resolver for annotation {@link ActionConfig} + * + * @author chemit + */ +public class ActionConfigConfigurationResolver extends AbstractActionConfigurationResolver<ActionConfig, AbstractButton> { + + public ActionConfigConfigurationResolver() { + super(ActionConfig.class, AbstractButton.class); + } + + @Override + protected ActionConfig applyConfiguration0(AbstractButton component, MyAbstractAction action) { + ActionConfig anno = resolveConfiguration(action); + if (anno == null) { + return null; + } + // inject les données + if (!anno.name().isEmpty()) { + //System.out.println("found action with name : " + anno.name()); + action.putValue(Action.NAME, _(anno.name())); + } + //if (!anno.shortDescription().isEmpty()) { + action.putValue(Action.SHORT_DESCRIPTION, _(anno.shortDescription())); + //} + if (!anno.smallIcon().isEmpty()) { + action.putValue(Action.SMALL_ICON, org.nuiton.jaxx.util.UIHelper.createImageIcon(anno.smallIcon())); + } + if (anno.mnemonic() != '\0') { + action.putValue(Action.MNEMONIC_KEY, anno.mnemonic()); + } else if (component != null) { + action.putValue(Action.MNEMONIC_KEY, component.getMnemonic()); + } + //TODO Convert it from String action.putValue(Action.ACCELERATOR_KEY, anno.accelerator()); + + if (component == null) { + action.putValue("hideActionText", anno.hideActionText()); + } else { + boolean actionText = component.getHideActionText(); + action.putValue("hideActionText", anno.hideActionText() || actionText); + } + action.putValue(Action.SELECTED_KEY, anno.selected()); + action.setEnabled(anno.enabled()); + + return anno; + } +} diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionConfigurationResolver.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionConfigurationResolver.java new file mode 100644 index 0000000..552b59b --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionConfigurationResolver.java @@ -0,0 +1,54 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.action; + +import javax.swing.JComponent; + +/** + * The contract to be realized to resolve an {@link MyAbstractAction} configuration. + * <p/> + * Configuration is done by a Annotation of type {@link A} placed on the action class. + * <p/> + * If the instanciated action box the real action, we should always search on the boxed action. + * <p/> + * Moreover, a action can only be fired by a certain type of component (for example a Button or a ComboBox), the class + * of the component type is given by the {@link C} class. + * + * @param <A> type of annotation for config + * @param <C> type of component + * @author chemit + */ +public interface ActionConfigurationResolver<A extends java.lang.annotation.Annotation, C extends JComponent> { + /** + * Search the annotation that configure the given action (or the boxed action). + * + * @param action current action + * @return the configuration of the action + */ + A resolveConfiguration(MyAbstractAction action); + + /** + * @param component widget that requires the action + * @param action given action + * @return the configuration of the action + */ + A applyConfiguration(JComponent component, MyAbstractAction action); + + /** @return the configuration annotation dealed by this resolver */ + Class<A> getAnnotationImpl(); + + /** @return the class of the component which can fired the action */ + Class<C> getComponentImpl(); +} diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionFactory.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionFactory.java new file mode 100644 index 0000000..22c1f5c --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionFactory.java @@ -0,0 +1,150 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.action; + +import jaxx.runtime.JAXXObject; + +import javax.swing.JComponent; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +/** + * Action factory using the <code>ActionConfig-like</code> annotations to configure actions. + * <p/> + * <p/> + * An {@link ActionFactory} builds actions always on a same type <code>A</code> and obtain them from some + * {@link ActionProvider} via methods {@link #newAction(String, JComponent)} and {@link #newAction(String)} . + * <p/> + * If the action coming from the provider is not on the same type <code>A</code>, then the action is boxed in a * + * action <code>A</code> and use the generic mecanism of delegation provided by {@link MyAbstractAction}. + * <p/> + * Use after the {@link #loadActions(jaxx.runtime.JAXXObject)} to instanciate actions in ui with id equals a known + * action... + * <p/> + * All actions instanciated are stored in a cache that you can request via method {@link #getActionFromCache(String)}, + * {@link #cacheEntrySet()} and {@link #resetCache()}. + * <p/> + * You can also from this factory fires some action via the methods {@link #fireAction(String, Object, JComponent)} , + * {@link #fireAction(String, Object)} , {@link #fireAction0(String, Object, MyAbstractAction)}. + * <p/> + * Finally, a {@link #dispose()} method is there to shut down all instanciated action when you want to dispose all uis. + * + * @param <A> type of boxed action + * @author chemit + * @see ActionProvider + * @see MyAbstractAction + */ +public interface ActionFactory<A extends MyAbstractAction> { + + /** + * Method to init the dictionary of knwon action implementations. + * + * @return the dictionary of known action implementations + */ + Map<String, Class<? extends MyAbstractAction>> init(); + + /** @return the class of the base action of the factory. */ + Class<A> getBaseClass(); + + /** @return the set of all the action's classes known by the factory. */ + Set<Entry<String, Class<? extends MyAbstractAction>>> implsEntrySet(); + + /** @return the array of names of all actions known by the factory */ + String[] getActionNames(); + + /** @return the set of all actions cached in factory indexed by their name */ + Set<Entry<String, A>> cacheEntrySet(); + + /** + * @param actionKey the action's key + * @return the action in cache or <code>null</code> if action is not in cache + */ + MyAbstractAction getActionFromCache(String actionKey); + + /** clear the cache of instanciated actions. */ + void resetCache(); + + /** + * @param actionKey the key of an action + * @return the action with this key from cache, or <code>null</code> if this action is not in cache + */ + + //A get(String actionKey); + + /** + * For a given ui, load all actions registred in factory. + * <p/> + * The id of the widget in ui is directly mapped to a action key. + * + * @param ui the ui to treate + */ + void loadActions(JAXXObject ui); + + /** + * Obtain an action instance given his key and widget + * + * @param actionKey the key of action + * @param component the component using the action + * @return the instanciated action (could come from cache if already instanciated {@link #getActionFromCache(String)} + */ + A newAction(String actionKey, JComponent component); + + /** + * Obtain an action instance given his key (should call {@link #newAction(String, JComponent)} + * <p/> + * This is a convinient method when you want to obtain an action with no attached widget. + * + * @param actionKey the key of action + * @return the instanciated action (could come from cache if already instanciated {@link #getActionFromCache(String)} + */ + A newAction(String actionKey); + + + /** + * Fire an action given his key, his source and tthe widget responsible of action + * + * @param actionKey the action's key + * @param source the object source of action + * @param component the component doing the action + */ + void fireAction(String actionKey, Object source, JComponent component); + + /** + * Fire an action given his key and his source, no widget are involved here + * + * @param actionKey the action's key + * @param source the object source of action + */ + void fireAction(String actionKey, Object source); + + /** + * Fire an action given his action's key, his source and the real action. + * <p/> + * This is a convinient method when you need to modified action before fire it. + * + * @param actionKey action's key + * @param source source of action + * @param action real action + */ + void fireAction0(String actionKey, Object source, A action); + + + /** + * dispose all actions in cache using {@link MyAbstractAction#disposeUI()} on each + * action, then {@link #resetCache()} + */ + void dispose(); +} diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionFactoryFromProvider.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionFactoryFromProvider.java new file mode 100644 index 0000000..d5a386c --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionFactoryFromProvider.java @@ -0,0 +1,470 @@ +/* +* ##% Copyright (C) 2007, 2008 Code Lutin, Tony Chemit +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* ##% */ +package org.nuiton.jaxx.action; + +import jaxx.runtime.JAXXObject; +import jaxx.runtime.swing.JAXXToggleButton; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.util.Resource; + +import javax.swing.AbstractButton; +import javax.swing.Action; +import javax.swing.Icon; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import java.awt.event.ActionEvent; +import java.lang.reflect.InvocationTargetException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.TreeMap; + +/** + * A simple implementation of {@link ActionFactory} using some {@link ActionProvider} to seek actions. + * <p/> + * <p/> + * An entry is in that form : <code>action.actionName=fqn</code> where + * <p/> + * <code>actionName</code> is the key of action used in factory, and + * <code>fqn</code> is the fully qualified name of the implemented action class. + * <p/> + * A special clase is to have for a given entry a key like this : <code>action.:fqn'=fqn</code>, in that case, + * le fqn' is a classe of type {@link org.nuiton.jaxx.action.ActionNameProvider} which gives us at + * runtime the names of each entry to put in cache for the givne action fqn. + * + * @param <A> the type of action + * @author chemit + */ +public class ActionFactoryFromProvider<A extends MyAbstractAction> implements ActionFactory<A> { + + protected static Log log = LogFactory.getLog(ActionFactoryFromProvider.class); + + public static <A extends MyAbstractAction> ActionFactory<A> newInstance(Class<A> klazz) { + return new ActionFactoryFromProvider<A>(klazz); + } + + /** class of encapsuling action */ + protected Class<A> baseImpl; + + /** dictionary of known actions implementations */ + private Map<String, Class<? extends MyAbstractAction>> impls; + + /** dictionary of instanciated actions */ + private Map<String, A> cache; + + protected final ActionConfigConfigurationResolver actionConfigInitializer; + protected final ToggleActionConfigConfigurationResolver toggleActionConfigInitializer; + protected final SelectActionConfigConfigurationResolver selectActionConfigInitializer; + + protected List<AbstractActionConfigurationResolver> configurationResolvers; + + protected ActionFactoryFromProvider(Class<A> baseImpl) { + this.baseImpl = baseImpl; + this.impls = init(); + this.cache = new TreeMap<String, A>(); + this.configurationResolvers = new java.util.ArrayList<AbstractActionConfigurationResolver>(); + + this.toggleActionConfigInitializer = registerInitializer(ToggleActionConfigConfigurationResolver.class); + this.actionConfigInitializer = registerInitializer(ActionConfigConfigurationResolver.class); + this.selectActionConfigInitializer = registerInitializer(SelectActionConfigConfigurationResolver.class); + } + + @Override + public Class<A> getBaseClass() { + return baseImpl; + } + + @Override + public void resetCache() { + cache.clear(); + } + + /*public A get(String actionKey) { + return cache.get(actionKey); + }*/ + + @Override + public void loadActions(JAXXObject ui) { + if (log.isDebugEnabled()) { + log.debug("for ui " + ui.getClass()); + } + for (Map.Entry<String, Class<? extends MyAbstractAction>> entry : implsEntrySet()) { + String actionKey = entry.getKey(); + Object comp = ui.getObjectById(actionKey); + if (comp == null || !(comp instanceof AbstractButton || comp instanceof JComboBox)) { + // nothing to do + continue; + } + if (log.isTraceEnabled()) { + log.trace("detect action " + actionKey); + } + if (comp instanceof AbstractButton) { + AbstractButton component = (AbstractButton) comp; + A action = newAction(actionKey, component); + + component.setAction(action); + + if (component instanceof JAXXToggleButton) { + JAXXToggleButton glueComponent = (JAXXToggleButton) component; + glueComponent.setIcon((Icon) action.getValue(Action.SMALL_ICON)); + Integer integer = (Integer) action.getValue(Action.MNEMONIC_KEY); + if (integer != null) { + glueComponent.setNormalMnemonic(integer); + } + glueComponent.setSelectedIcon((Icon) action.getValue(Action.SMALL_ICON + 2)); + integer = (Integer) action.getValue(Action.MNEMONIC_KEY + 2); + if (integer != null) { + glueComponent.setGlueMnemonic(integer); + } + glueComponent.setGlueText((String) action.getValue(Action.NAME + 2)); + glueComponent.setGlueTooltipText((String) action.getValue(Action.SHORT_DESCRIPTION + 2)); + + glueComponent.setNormalText((String) action.getValue(Action.NAME)); + glueComponent.setNormalTooltipText((String) action.getValue(Action.SHORT_DESCRIPTION)); + } + + Boolean value = (Boolean) action.getValue("hideActionText"); + component.setHideActionText(value != null && value); + action.setEnabled(true); + continue; + } + // is JComboBox + JComboBox component = (JComboBox) comp; + A action = newAction(actionKey, component); + + component.setAction(action); + Integer val = (Integer) action.getValue("selectedIndex"); + if (val != null && val != -1 && val < component.getItemCount() && val != component.getSelectedIndex()) { + component.setSelectedIndex(val); + } + } + } + + /** + * @param actionKey le nom de l'action tel que définie dans le fichier + * de mapping (sans le prefix action.) + * @param component le button où rattacher l'action + * @return une nouvelle instance de l'action associée à sa clef. + */ + @Override + public A newAction(String actionKey, JComponent component) { + // try first in cache + A result = getActionFromCache(actionKey); + if (result != null) { + return result; + } + + try { + result = newActionInstance(actionKey); + } catch (Exception e) { + throw new RuntimeException(e); + } + + if (log.isDebugEnabled()) { + log.debug("create <" + actionKey + " : " + result + ">"); + } + + // recherche de l'annotation de configuration + ActionConfigurationResolver<?, ?> configurationResolver = resolveActionConfiguration(result); + + if (configurationResolver != null) { + configurationResolver.applyConfiguration(component, result); + } + + try { + + if (configurationResolver != null) { + if (AbstractButton.class.isAssignableFrom(configurationResolver.getComponentImpl())) { + finalizeNewAction((AbstractButton) component, result, configurationResolver); + } + + if (JComboBox.class.isAssignableFrom(configurationResolver.getComponentImpl())) { + finalizeNewAction((JComboBox) component, result, configurationResolver); + } + + return result; + } + + if (component == null || component instanceof AbstractButton) { + finalizeNewAction((AbstractButton) component, result, configurationResolver); + return result; + } + + if (component instanceof JComboBox) { + finalizeNewAction((JComboBox) component, result, configurationResolver); + } + } finally { + // save result in cache + cache.put(actionKey, result); + } + + return result; + } + + @Override + public A newAction(String actionKey) { + return newAction(actionKey, null); + } + + @Override + public String[] getActionNames() { + return impls.keySet().toArray(new String[impls.size()]); + } + + @Override + public Set<Entry<String, Class<? extends MyAbstractAction>>> implsEntrySet() { + return impls.entrySet(); + } + + @Override + public Set<Entry<String, A>> cacheEntrySet() { + return cache.entrySet(); + } + + @Override + public void fireAction(String actionKey, Object source, JComponent component) { + A action = newAction(actionKey, component); + fireAction0(actionKey, source, action); + } + + @Override + public void fireAction(String actionKey, Object source) { + fireAction(actionKey, source, null); + } + + /** + * @param actionKey la clef de l'action + * @return l'action deja stockee dans le cache d'action, ou <code>null</code> si non trouvée. + */ + @Override + public A getActionFromCache(String actionKey) { + // on vérifie que l'action existe bien + checkRegistredAction(actionKey); + + A action = null; + // try in cache + if (cache.containsKey(actionKey)) { + // use cached action + action = cache.get(actionKey); + if (log.isDebugEnabled()) { + log.debug("use cache action " + action); + } + } + return action; + } + + @Override + public void dispose() { + if (log.isInfoEnabled()) { + log.info(this); + } + for (String actionKey : getActionNames()) { + MyAbstractAction action = getActionFromCache(actionKey); + if (action != null) { + action.disposeUI(); + } + } + resetCache(); + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + resetCache(); + impls.clear(); + } + + /** + * @param component le button où rattacher l'action + * @param action action + * @param configurationResolver initializer + */ + protected void finalizeNewAction(AbstractButton component, MyAbstractAction action, ActionConfigurationResolver<?, ?> configurationResolver) { + + if (configurationResolver == null) { + // no configurationResolver matching, + if (component != null) { + action.putValue(Action.ACTION_COMMAND_KEY, component.getName()); + action.putValue(Action.SHORT_DESCRIPTION, component.getToolTipText()); + action.putValue(Action.SMALL_ICON, component.getIcon()); + action.putValue(Action.NAME, component.getText()); + action.putValue(Action.MNEMONIC_KEY, component.getMnemonic()); + action.putValue("hideActionText", component.getHideActionText()); + if (component instanceof JAXXToggleButton) { + JAXXToggleButton glueComponent = (JAXXToggleButton) component; + action.putValue(Action.SHORT_DESCRIPTION, glueComponent.getNormalTooltipText()); + action.putValue(Action.NAME, glueComponent.getNormalText()); + action.putValue(Action.SMALL_ICON, glueComponent.getIcon()); + action.putValue(Action.MNEMONIC_KEY, glueComponent.getNormalMnemonic()); + action.putValue(Action.SHORT_DESCRIPTION + 2, glueComponent.getGlueTooltipText()); + action.putValue(Action.NAME + 2, glueComponent.getGlueText()); + action.putValue(Action.SMALL_ICON + 2, glueComponent.getSelectedIcon()); + action.putValue(Action.MNEMONIC_KEY + 2, glueComponent.getGlueMnemonic()); + } + } + + } + + String text = (String) action.getValue(Action.NAME); + Integer mnemo = (Integer) action.getValue(Action.MNEMONIC_KEY); + if (mnemo != null && mnemo != '\0') { + int pos = text.indexOf((char) mnemo.intValue()); + if (pos == -1) { + pos = text.indexOf(Character.toLowerCase((char) mnemo.intValue())); + } + action.putValue(Action.DISPLAYED_MNEMONIC_INDEX_KEY, pos); + } + + } + + /** + * @param component le select box où rattacher l'action + * @param action action + * @param configurationResolver initializer + */ + protected void finalizeNewAction(JComboBox component, MyAbstractAction action, ActionConfigurationResolver<?, ?> configurationResolver) { + + if (configurationResolver == null) { + action.putValue(Action.ACTION_COMMAND_KEY, component.getName()); + action.putValue(Action.SHORT_DESCRIPTION, component.getToolTipText()); + //result.putValue("selectedIndex", component.getSelectedIndex()); + } + + } + + protected ActionConfigurationResolver resolveActionConfiguration(MyAbstractAction action) { + for (ActionConfigurationResolver resolver : configurationResolvers) { + if (resolver.resolveConfiguration(action) != null) { + return resolver; + } + } + return null; + } + + protected <I extends AbstractActionConfigurationResolver> I registerInitializer(Class<I> initizalizer) { + try { + I instance = initizalizer.newInstance(); + configurationResolvers.add(instance); + return instance; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public void fireAction0(String actionKey, Object source, A action) { + if (action == null) { + log.warn("could not find action " + actionKey); + return; + } + ActionEvent event = new ActionEvent(source, ActionEvent.ACTION_FIRST, actionKey); + action.actionPerformed(event); + } + + protected void checkRegistredAction(String actionKey) { + if (!impls.containsKey(actionKey)) { + throw new IllegalStateException("can not find a registered action for key " + actionKey); + } + } + + + @SuppressWarnings({"unchecked"}) + protected A newActionInstance(String actionKey) throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { + Class<? extends MyAbstractAction> klazz = impls.get(actionKey); + MyAbstractAction result; + result = klazz.getConstructor(String.class).newInstance(actionKey); + result.putValue(Action.ACTION_COMMAND_KEY, actionKey); + if (!getBaseClass().isAssignableFrom(klazz)) { + // the instanciated action must be boxed in the base Action of the factory + result = getBaseClass().getConstructor(MyAbstractAction.class).newInstance(result); + } + return (A) result; + } + + + public Map<String, Class<? extends MyAbstractAction>> init() { + if (log.isDebugEnabled()) { + log.debug("start loading " + this); + } + URLClassLoader newCL = fixClassLoader(getClass()); + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + if (newCL != null) { + // replace current cl by our fiexed cl + Thread.currentThread().setContextClassLoader(newCL); + } + // obtain a ServiceLoader on ActionProvider + ServiceLoader<ActionProvider> loader = ServiceLoader.load(ActionProvider.class); + Map<String, Class<? extends MyAbstractAction>> cache = new TreeMap<String, Class<? extends MyAbstractAction>>(); + + for (ActionProvider<?> actionProvider : loader) { + if (log.isDebugEnabled()) { + log.debug("found " + actionProvider); + } + cache.putAll(actionProvider.getClasses()); + } + if (newCL != null) { + // to avoid side effects, push back old cl + Thread.currentThread().setContextClassLoader(cl); + } + return cache; + } + + /** + * Fix the class loader when application is launched from a java -jar + * The ServiceLoader seems not to find services from jar manifest... + * <p/> + * Our solution is to get all jar from the jar manifest and create a URLClassLoader, this is not perfect but works. + * <p/> + * TODO Put this nice code in a ServiceLoaderUtil in lutinutil... + * + * @param klass class to use to obtain classloader + * @return the fixed classloader + */ + public static URLClassLoader fixClassLoader(Class<?> klass) { + ClassLoader l = klass.getClassLoader(); + URLClassLoader cl; + if (!(l instanceof URLClassLoader)) { + log.warn("using cl is not a URL classloader " + l); + cl = new URLClassLoader(new URL[0], l); + } else { + cl = (URLClassLoader) l; + } + if (cl.getURLs().length == 1) { + // come from a java -jar, must expand all jar to make possible ServiceLoader to work + try { + //todo put this in lutinutil ServiceLoaderUtil + URL[] urls = Resource.getClassPathURLsFromJarManifest(cl.getURLs()[0]); + URLClassLoader newCL = new URLClassLoader(urls); + if (log.isTraceEnabled()) { + for (URL url : newCL.getURLs()) { + log.trace(url); + } + } + return newCL; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + return null; + } + +} \ No newline at end of file diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionNameProvider.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionNameProvider.java new file mode 100644 index 0000000..ec1745a --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionNameProvider.java @@ -0,0 +1,34 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.action; + +/** + * Contrat pour obtenir les noms d'une action de maniere dynamique. + * <p/> + * Cette méthode sera appelee par un {@link ActionProvider} lorsque la clef dans le + * fichier de mapping est <code>:fqn</code> (où fqn correspond à une implantation de ce contrat). + * <p/> + * Ainsi on peut associer à une action donnee plusieurs instances avec des noms différents mais de le meme comportement. + * <p/> + * Par exemple, une changement de locale ou seule la locale varie (et elle sera retrouvee a partir du nom de l'action). + * + * @author chemit + */ +public interface ActionNameProvider { + + /** @return la liste des noms à utiliser par la classe d'action. */ + String[] getActionCommands(); + +} diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionProvider.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionProvider.java new file mode 100644 index 0000000..cca7195 --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionProvider.java @@ -0,0 +1,36 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.action; + +/** + * Contract to be realized by a provider of Actions. + * <p/> + * A provider of actions is based on a certain type of {@link MyAbstractAction} (<code>A</code>) with an accessor + * {@link #getBaseClass()} and deliver some implementations of such actions indexed by their logical names via the + * method {#link #getClasses()}. + * + * @param <A> type of action boxed + * @author chemit + * @see MyAbstractAction + */ +public interface ActionProvider<A extends MyAbstractAction> { + + /** @return the base classe of provided actions */ + Class<A> getBaseClass(); + + /** @return the provided actions classes */ + java.util.Map<String, Class<? extends A>> getClasses(); + +} diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionProviderAnnotation.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionProviderAnnotation.java new file mode 100644 index 0000000..a881fe3 --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionProviderAnnotation.java @@ -0,0 +1,34 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.action; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Pour enregister un provider d'action. + * <p/> + * Placer cette annotation sur la classe de base d'action, + * <p/> + * + * @author chemit + */ +@Retention(RetentionPolicy.RUNTIME) + +@Target(ElementType.TYPE) +public @interface ActionProviderAnnotation { +} diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionProviderFromProperties.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionProviderFromProperties.java new file mode 100644 index 0000000..7cf9179 --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ActionProviderFromProperties.java @@ -0,0 +1,135 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.action; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import static org.nuiton.i18n.I18n._; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; +import java.util.Properties; +import java.util.TreeMap; + +/** @author chemit */ +public class ActionProviderFromProperties<A extends MyAbstractAction> implements ActionProvider<A> { + + /** default prefix for an entryin mapping file. */ + protected static final String ACTION_KEY_PREFIX = "action."; + + protected static final String actionsFileLocation = "META-INF/jaxx-%1$s-actions.properties"; + + protected String propertiesPath; + + protected static Log log = LogFactory.getLog(ActionProviderFromProperties.class); + + protected Class<A> baseClass; + + protected Map<String, Class<? extends A>> actions; + + + protected ActionProviderFromProperties(Class<A> baseClass) { + + this.baseClass = baseClass; + this.propertiesPath = "/" + String.format(actionsFileLocation, baseClass.getSimpleName()); + this.actions = initCache(); + } + + public Class<A> getBaseClass() { + return baseClass; + } + + public Map<String, Class<? extends A>> getClasses() { + return actions; + } + + @Override + public String toString() { + return super.toString() + "<baseClass:" + baseClass.getSimpleName() + ">"; + } + + protected void clearCache() { + if (actions != null) { + actions.clear(); + actions = null; + } + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + clearCache(); + } + + @SuppressWarnings({"unchecked"}) + protected Map<String, Class<? extends A>> initCache() { + + InputStream inputStream = null; + + Properties properties = new Properties(); + + try { + inputStream = getClass().getResourceAsStream(propertiesPath); + if (inputStream == null) { + //throw new NullPointerException("could not find action file " + propertiesPath); + // actually, there is nothing to load, this is not an error + } else { + log.info("load " + propertiesPath); + properties.load(inputStream); + } + } catch (IOException e) { + String message = _("jaxx.error.load.actions.file", e.getMessage()); + log.warn(message); + throw new RuntimeException(message); + } finally { + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + log.warn(_("jaxx.error.close.actions.file", e.getMessage())); + //throw new RuntimeException(_("jaxx.error.load.actions.file", e.getMessage())); + } + } + } + + Map<String, Class<? extends A>> cache = new TreeMap<String, Class<? extends A>>(); + int prefix = ACTION_KEY_PREFIX.length(); + for (Map.Entry<Object, Object> entry : properties.entrySet()) { + String key = entry.getKey() + ""; + String qfn = entry.getValue() + ""; + try { + Class<? extends A> implCass; + implCass = (Class<? extends A>) Class.forName(qfn); + String actionKey = key.substring(prefix); + if (actionKey.startsWith(":")) { + // this is a RuntimeActionNameProvider + Class<ActionNameProvider> klazz = (Class<ActionNameProvider>) Class.forName(actionKey.substring(1)); + for (String s : klazz.newInstance().getActionCommands()) { + log.debug("found action <" + s + " : " + implCass + ">"); + cache.put(s, implCass); + } + continue; + } + log.debug("found action <" + actionKey + " : " + implCass + ">"); + cache.put(actionKey, implCass); + } catch (Exception e) { + throw new RuntimeException(_("jaxx.error.load.actions.class", key, qfn), e); + } + } + + return cache; + } +} diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/MyAbstractAction.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/MyAbstractAction.java new file mode 100644 index 0000000..1440ca4 --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/MyAbstractAction.java @@ -0,0 +1,260 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.action; + +import jaxx.runtime.JAXXObject; +import org.apache.commons.logging.LogFactory; +import static org.nuiton.i18n.I18n._; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JComponent; +import java.awt.event.ActionEvent; +import java.beans.PropertyChangeListener; + +/** + * Action de base à utiliser pour encapsuler toutes les actions du système. + * <p/> + * Ces actions seront chargées par des {@link ActionProvider} et des {@link ActionFactory}. + * + * @author chemit + */ +public abstract class MyAbstractAction extends AbstractAction { + + protected static org.apache.commons.logging.Log log = LogFactory.getLog(MyAbstractAction.class); + + private static final long serialVersionUID = -810023044364620841L; + + protected ActionEvent e; + + protected MyAbstractAction delegate; + + protected abstract String getPrefix(); + + protected MyAbstractAction(String name) { + super(name); + } + + protected MyAbstractAction(MyAbstractAction delegate) { + super((String) delegate.getValue(Action.NAME)); + this.delegate = delegate; + } + + @Override + public void actionPerformed(java.awt.event.ActionEvent e) { + if (hasDelegate()) { + // delegate to real action + delegate.actionPerformed(e); + return; + } + log.debug("------------------------------------------------------------"); + log.debug("event : " + e); + log.debug("source : " + e.getSource()); + this.e = e; + try { + boolean accepted = beforeAction(e); + log.debug("action : " + this); + if (accepted) { + log.info(getActionName() + " (treate:" + accepted + ") : " + this); + } else { + log.debug(getActionName() + " (treate:" + accepted + ") : " + this); + } + if (accepted) { + doAction(e); + setStatus(_("jaxx.action.done", getName())); + updateUI(); + } + } catch (Exception e1) { + showError(e1); + } finally { + this.e = null; + // always clear action after use : actions are staless + clear(); + } + } + + public String getI18nToolTipText() { + if (hasDelegate()) { + return delegate.getI18nToolTipText(); + } + return getPrefix() + ".action." + getActionName() + ".tooltip"; + } + + public void updateUI() { + if (hasDelegate()) { + delegate.updateUI(); + } + // nothing by default + } + + public void disposeUI() { + if (hasDelegate()) { + delegate.disposeUI(); + } + // nothing by default + } + + public MyAbstractAction getDelegate() { + return delegate; + } + + public boolean hasDelegate() { + return delegate != null; + } + + protected String getName() { + return (String) getValue(NAME); + } + + protected String getActionName() { + return (String) getValue(ACTION_COMMAND_KEY); + } + + protected void setStatus(String status) { + // do nothing from here + if (log.isDebugEnabled()) { + log.debug(status); + } + } + + protected boolean beforeAction(ActionEvent evt) throws Exception { + boolean canContinue = isEnabled(); + if (canContinue && hasDelegate()) { + return delegate.beforeAction(evt); + } + return canContinue; + } + + protected void doAction(ActionEvent evt) throws Exception { + if (hasDelegate()) { + delegate.doAction(evt); + } + // nothing by default + } + + protected JComponent getUIObject(String name, JAXXObject container) { + if (container == null) { + return null; + } + return (JComponent) container.getObjectById(name); + } + + protected void clear() { + if (hasDelegate()) { + delegate.clear(); + } + // nothing by default + } + + protected void showError(Exception e) { + log.error(e); + } + + // ----------------------------------------------------------------------------- + // --- super class delegate methods ------------------------------------------- + // ----------------------------------------------------------------------------- + + @Override + public Object getValue(String key) { + if (hasDelegate()) { + return delegate.getValue(key); + } + return super.getValue(key); + } + + @Override + public void putValue(String key, Object newValue) { + if (hasDelegate()) { + delegate.putValue(key, newValue); + } + super.putValue(key, newValue); + } + + @Override + public boolean isEnabled() { + if (hasDelegate()) { + return delegate.isEnabled(); + } + return super.isEnabled(); + } + + @Override + public void setEnabled(boolean newValue) { + if (hasDelegate()) { + delegate.setEnabled(newValue); + } + super.setEnabled(newValue); + } + + @Override + public Object[] getKeys() { + if (hasDelegate()) { + return getKeys(); + } + return super.getKeys(); + } + + @Override + protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { + if (hasDelegate()) { + delegate.firePropertyChange(propertyName, oldValue, newValue); + } + super.firePropertyChange(propertyName, oldValue, newValue); + } + + @Override + public synchronized void addPropertyChangeListener(PropertyChangeListener listener) { + if (hasDelegate()) { + delegate.addPropertyChangeListener(listener); + } + super.addPropertyChangeListener(listener); + } + + @Override + public synchronized void removePropertyChangeListener(PropertyChangeListener listener) { + if (hasDelegate()) { + delegate.removePropertyChangeListener(listener); + } + super.removePropertyChangeListener(listener); + } + + @Override + public synchronized PropertyChangeListener[] getPropertyChangeListeners() { + if (hasDelegate()) { + return delegate.getPropertyChangeListeners(); + } + return super.getPropertyChangeListeners(); + } + + @Override + protected Object clone() throws CloneNotSupportedException { + if (hasDelegate()) { + return clone(); + } + return super.clone(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(super.toString()); + if (hasDelegate()) { + sb.append("[delegate: ").append(delegate.toString()).append("]"); + } else { + sb.append("<key:").append(getActionName()).append(">"); + } + return sb.toString(); + } +} diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/SelectActionConfig.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/SelectActionConfig.java new file mode 100644 index 0000000..ca0ad0c --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/SelectActionConfig.java @@ -0,0 +1,95 @@ +/* +* ##% Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 Code Lutin, +* Tony Chemit, Gabriel Landais +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* ##% */ +package org.nuiton.jaxx.action; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Pour enregister une action. + * <p/> + * Placer cette annotation sur la classe implantant l'action, + * <p/> + * les informations décrites seront utilisées pour instancier l'action + * + * @author chemit + */ +@Retention(RetentionPolicy.RUNTIME) + +@Target(ElementType.TYPE) +@Inherited +public @interface SelectActionConfig { + + /** + * @return la clef de la commande (doit être unique) + * @see javax.swing.Action#ACTION_COMMAND_KEY + */ + String actionCommand(); + + /** @return array of names to be used in actions mapping */ + String[] actionCommands() default {}; + + /** + * @return the class to obtain at runtime the array of names to be used in actions mapping. + * <p/> + * <b>Note : the special value {@link org.nuiton.jaxx.action.ActionNameProvider} is used to says not to used + * œthis mecanism since we can not set a null value in a annotation</b> + */ + Class<? extends ActionNameProvider> actionCommandProvider() default org.nuiton.jaxx.action.ActionNameProvider.class; + + /** + * @return la clef i18n du texte de l'action, si vide ignoré + * @see javax.swing.Action#NAME + */ + String name() default ""; + + /** + * @return la clef i18n du tooltip de l'action, si vide ignoré + * @see javax.swing.Action#SHORT_DESCRIPTION + */ + String shortDescription() default ""; + + /** + * @return la clef i18n du texte de l'action, si vide ignoré + * @see javax.swing.Action#LONG_DESCRIPTION + */ + String longDescription() default ""; + + /** + * @return accelerator key + * @see javax.swing.Action#ACCELERATOR_KEY + */ + String accelerator() default ""; + + /** + * @return la valeur par défaut pour les component selectable + * @see javax.swing.Action#SELECTED_KEY + */ + int selectedIndex() default 0; + + /** + * @return enabled state + * @see javax.swing.Action#isEnabled() + */ + boolean enabled() default true; + +} \ No newline at end of file diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/SelectActionConfigConfigurationResolver.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/SelectActionConfigConfigurationResolver.java new file mode 100644 index 0000000..d50803c --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/SelectActionConfigConfigurationResolver.java @@ -0,0 +1,54 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.action; + +import static org.nuiton.i18n.I18n._; + +import javax.swing.Action; +import javax.swing.JComboBox; + +/** + * Implementation of configuration's resolver for annotation {@link SelectActionConfig} + * + * @author chemit + */ +public class SelectActionConfigConfigurationResolver extends AbstractActionConfigurationResolver<SelectActionConfig, JComboBox> { + + public SelectActionConfigConfigurationResolver() { + super(SelectActionConfig.class, JComboBox.class); + } + + @Override + protected SelectActionConfig applyConfiguration0(JComboBox component, MyAbstractAction action) { + SelectActionConfig anno = resolveConfiguration(action); + if (anno == null) { + return null; + } + // inject les données + if (!anno.name().isEmpty()) { + action.putValue(Action.NAME, _(anno.name())); + } + if (!anno.shortDescription().isEmpty()) { + action.putValue(Action.SHORT_DESCRIPTION, _(anno.shortDescription())); + } else { + action.putValue(Action.SHORT_DESCRIPTION, _(component.getToolTipText())); + } + action.putValue("selectedIndex", anno.selectedIndex()); + //TODO Convert it from String action.putValue(Action.ACCELERATOR_KEY, anno.accelerator()); + action.setEnabled(anno.enabled()); + + return anno; + } +} \ No newline at end of file diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ToggleActionConfig.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ToggleActionConfig.java new file mode 100644 index 0000000..339d2fe --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ToggleActionConfig.java @@ -0,0 +1,156 @@ +/* +* ##% Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 Code Lutin, +* Tony Chemit, Gabriel Landais +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* ##% */ +package org.nuiton.jaxx.action; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Pour enregister une action de type Toggle (ToggleButton). + * <p/> + * Placer cette annotation sur la classe implantant l'action, + * <p/> + * les informations décrites seront utilisées pour instancier l'action + * + * @author chemit + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Inherited +public @interface ToggleActionConfig { + /** + * @return la clef de la commande (doit être unique) + * @see javax.swing.Action#ACTION_COMMAND_KEY + */ + String actionCommand(); + + /** @return array of names to be used in actions mapping */ + String[] actionCommands() default {}; + + /** + * @return the class to obtain at runtime the array of names to be used in actions mapping. + * <p/> + * <b>Note : the special value {@link org.nuiton.jaxx.action.ActionNameProvider} is used to says not to used + * œthis mecanism since we can not set a null value in a annotation</b> + */ + Class<? extends ActionNameProvider> actionCommandProvider() default org.nuiton.jaxx.action.ActionNameProvider.class; + + /** + * @return la clef i18n du texte de l'action, si vide ignoré + * @see javax.swing.Action#NAME + */ + String name() default ""; + + /** + * @return la clef i18n du tooltip de l'action, si vide ignoré + * @see javax.swing.Action#SHORT_DESCRIPTION + */ + String shortDescription() default ""; + + /** + * @return la clef i18n du texte de l'action, si vide ignoré + * @see javax.swing.Action#LONG_DESCRIPTION + */ + String longDescription() default ""; + + /** + * @return le nom de l'icone associé, si vide ignoré + * @see javax.swing.Action#SMALL_ICON + */ + String smallIcon() default ""; + + /** + * @return le nom du grande icone associé, si vide ignoré + * @see javax.swing.Action#LARGE_ICON_KEY + */ + String largeIcon() default ""; + + /** + * @return accelerator key of default state + * @see javax.swing.Action#ACCELERATOR_KEY + */ + String accelerator() default ""; + + /** + * @return mnemonic key of default state + * @see javax.swing.Action#MNEMONIC_KEY + */ + int mnemonic() default '\0'; + + /** + * @return la clef i18n du texte de l'action, si vide ignoré + * @see javax.swing.Action#NAME + */ + String name2() default ""; + + /** + * @return la clef i18n du tooltip de l'action, si vide ignoré + * @see javax.swing.Action#SHORT_DESCRIPTION + */ + String shortDescription2() default ""; + + /** + * @return la clef i18n du texte de l'action, si vide ignoré + * @see javax.swing.Action#LONG_DESCRIPTION + */ + String longDescription2() default ""; + + /** + * @return le nom de l'icone associé, si vide ignoré + * @see javax.swing.Action#SMALL_ICON + */ + String smallIcon2() default ""; + + /** + * @return le nom du grande icone associé, si vide ignoré + * @see javax.swing.Action#LARGE_ICON_KEY + */ + String largeIcon2() default ""; + + /** + * @return accelerator key of default state + * @see javax.swing.Action#ACCELERATOR_KEY + */ + String accelerator2() default ""; + + /** + * @return mnemonic key of second state + * @see javax.swing.Action#MNEMONIC_KEY + */ + int mnemonic2() default '\0'; + + /** + * @return la valeur par défaut pour les component selectable + * @see javax.swing.Action#SELECTED_KEY + */ + boolean selected() default false; + + /** + * @return enaled state + * @see javax.swing.Action#isEnabled() + */ + boolean enabled() default true; + + /** @return hideActionText state */ + boolean hideActionText() default false; + +} \ No newline at end of file diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ToggleActionConfigConfigurationResolver.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ToggleActionConfigConfigurationResolver.java new file mode 100644 index 0000000..6351b3c --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/action/ToggleActionConfigConfigurationResolver.java @@ -0,0 +1,79 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.action; + +import static org.nuiton.i18n.I18n._; + +import javax.swing.AbstractButton; +import javax.swing.Action; + +/** + * Implementation of configuration's resolver for annotation {@link ToggleActionConfig} + * + * @author chemit + */ +public class ToggleActionConfigConfigurationResolver extends AbstractActionConfigurationResolver<ToggleActionConfig, AbstractButton> { + + public ToggleActionConfigConfigurationResolver() { + super(ToggleActionConfig.class, AbstractButton.class); + } + + protected ToggleActionConfig applyConfiguration0(AbstractButton component, MyAbstractAction action) { + ToggleActionConfig anno = resolveConfiguration(action); + if (anno == null) { + return null; + } + // inject les données + if (!anno.name().isEmpty()) { + //System.out.println("found action with name : " + anno.name()); + action.putValue(Action.NAME, _(anno.name())); + } + if (!anno.name2().isEmpty()) { + //System.out.println("found action with name2 : " + anno.name2()); + action.putValue(Action.NAME + "2", _(anno.name2())); + } + + if (!anno.shortDescription().isEmpty()) { + action.putValue(Action.SHORT_DESCRIPTION, _(anno.shortDescription())); + } + if (!anno.shortDescription2().isEmpty()) { + action.putValue(Action.SHORT_DESCRIPTION + "2", _(anno.shortDescription2())); + } + + if (!anno.smallIcon().isEmpty()) { + action.putValue(Action.SMALL_ICON, org.nuiton.jaxx.util.UIHelper.createImageIcon(anno.smallIcon())); + } + if (!anno.smallIcon2().isEmpty()) { + action.putValue(Action.SMALL_ICON + "2", org.nuiton.jaxx.util.UIHelper.createImageIcon(anno.smallIcon2())); + } + + if (anno.mnemonic() != '\0') { + action.putValue(Action.MNEMONIC_KEY, anno.mnemonic()); + } else if (component != null) { + action.putValue(Action.MNEMONIC_KEY, component.getMnemonic()); + } + if (anno.mnemonic2() != '\0') { + action.putValue(Action.MNEMONIC_KEY + "2", anno.mnemonic2()); + } + //TODO Convert it from String action.putValue(Action.ACCELERATOR_KEY, anno.accelerator()); + + + action.putValue("hideActionText", anno.hideActionText()); + action.putValue(Action.SELECTED_KEY, anno.selected()); + action.setEnabled(anno.enabled()); + + return anno; + } +} \ No newline at end of file diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/tab/TabContentConfig.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/tab/TabContentConfig.java new file mode 100644 index 0000000..1fada8e --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/tab/TabContentConfig.java @@ -0,0 +1,54 @@ +/* +* ##% Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 Code Lutin, +* Tony Chemit, Gabriel Landais +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* ##% */ +package org.nuiton.jaxx.tab; + +import jaxx.runtime.swing.JAXXTab; + +import javax.swing.JTabbedPane; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Pour enregister un tab + * + * @author chemit + */ +@Retention(RetentionPolicy.RUNTIME) + +@Target(ElementType.FIELD) + +public @interface TabContentConfig { + + Class<? extends TabModel> model(); + + Class<? extends JAXXTab> impl(); + + Class<? extends JTabbedPane> parentImpl(); + + boolean useToogle() default false; + + String name(); + + String shortDescription(); + + String[] dynamicFields() default {}; + +} diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/tab/TabFactory.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/tab/TabFactory.java new file mode 100644 index 0000000..16e45cb --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/tab/TabFactory.java @@ -0,0 +1,219 @@ +/* +* \#\#% Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 Code Lutin, +* Tony Chemit +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* \#\#% */ +package org.nuiton.jaxx.tab; + +import jaxx.runtime.JAXXObject; +import jaxx.runtime.swing.JAXXTab; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.swing.JComponent; +import javax.swing.JTabbedPane; +import java.awt.Component; +import java.lang.reflect.Field; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +/** + * Une usine pour les Tabs, leur configs et leur modèles + * + * @author tony + * @see TabContentConfig + * @see TabModel + */ + +public abstract class TabFactory { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + protected static Log log = LogFactory.getLog(TabFactory.class); + + /** dictionary of configs */ + protected Map<String, TabContentConfig> configs; + + /** dictionary of instanciated actions */ + protected Map<String, JAXXTab> cache; + + /** dictionary of instanciated models */ + protected Map<String, TabModel> models; + + protected abstract Map<String, TabContentConfig> initFactory(); + + protected abstract void initTab(JAXXTab tab, String tabName, TabContentConfig config); + + protected JAXXTab newTab(String tabName) { + + checkRegistredConfig(tabName); + + // try in cache + if (cache.containsKey(tabName)) { + // use cached tab + return cache.get(tabName); + } + + TabContentConfig config = configs.get(tabName); + + JAXXTab instance; + try { + instance = config.impl().newInstance(); + if (log.isDebugEnabled()) { + log.debug("new tab : " + instance); + } + + cache.put(tabName, instance); + + initJAXXTab(config, instance); + initTab(instance, tabName, config); + + return instance; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public Set<String> keySet() { + return cache.keySet(); + } + + public TabContentConfig getConfig(String tabName) { + checkRegistredConfig(tabName); + return configs.get(tabName); + } + + public JAXXTab getUI(String tabName) { + return cache.get(tabName); + } + + public TabModel getModel(String tabName, Object... params) { + + if (models.containsKey(tabName)) { + return models.get(tabName); + } + TabContentConfig config = getConfig(tabName); + TabModel tabModel; + try { + tabModel = initTabModel(config, params); + if (log.isDebugEnabled()) { + log.debug("new tab model : " + tabModel); + } + models.put(tabName, tabModel); + } catch (Exception e) { + throw new RuntimeException(e); + } + return tabModel; + } + + protected TabModel initTabModel(TabContentConfig config, Object... params) throws InstantiationException, IllegalAccessException { + TabModel tabModel; + tabModel = config.model().newInstance(); + return tabModel; + } + + public void showTab(final JTabbedPane container, String tabName) { + + TabContentConfig config = getConfig(tabName); + + JAXXTab comp = newTab(tabName); + + int index = getTabIndex(container, comp); + if (index == -1) { + registerTab(container, tabName, config, comp); + } + + container.setSelectedComponent(comp); + } + + public void closeTab(JTabbedPane container, String tabName) { + + TabContentConfig config = getConfig(tabName); + + final JComponent comp = cache.get(tabName); + + int index = getTabIndex(container, comp); + if (index != -1) { + container.removeTabAt(index); + if (log.isDebugEnabled()) { + log.debug(config + " index " + index); + } + } + } + + public int getTabIndex(final JTabbedPane container, JComponent comp) { + if (container != null && comp != null) { + for (int i = 0; i < container.getTabCount(); i++) { + Component o = container.getComponentAt(i); + if (o.equals(comp)) { + return i; + } + } + } + return -1; + } + + public void resetCache() { + cache.clear(); + models.clear(); + } + + + protected TabFactory() { + configs = initFactory(); + cache = new TreeMap<String, JAXXTab>(); + models = new TreeMap<String, TabModel>(); + } + + protected JComponent addTabHeader(final JTabbedPane container, final String tabName, final TabContentConfig config, final JAXXTab comp) { + // by default, no tab header + return null; + } + + protected void registerTab(final JTabbedPane container, final String tabName, final TabContentConfig config, final JAXXTab comp) { + + container.addTab(tabName, comp); + + JComponent header = addTabHeader(container, tabName, config, comp); + + if (header != null) { + + container.setTabComponentAt(container.getTabCount() - 1, header); + } + } + + @SuppressWarnings({"unchecked"}) + protected void initJAXXTab(TabContentConfig config, JAXXTab instance) throws NoSuchFieldException, IllegalAccessException { + if (instance instanceof JAXXObject) { + JAXXObject ui = (JAXXObject) instance; + for (String dynamicField : config.dynamicFields()) { + String dynamciName = dynamicField + '_' + config.name(); + Object obj = ui.getObjectById(dynamicField); + Field m = ui.getClass().getDeclaredField("$objectMap"); + m.setAccessible(true); + Map<Object, Object> map = (Map<Object, Object>) m.get(ui); + map.put(dynamciName, obj); + } + } + } + + protected void checkRegistredConfig(String tabName) { + if (!configs.containsKey(tabName)) { + throw new IllegalStateException("can not find a registered TabContentConfig for tab name " + tabName); + } + } + +} \ No newline at end of file diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/tab/TabModel.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/tab/TabModel.java new file mode 100644 index 0000000..5c762b2 --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/tab/TabModel.java @@ -0,0 +1,30 @@ +/* +* ##% Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 Code Lutin, +* Tony Chemit +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* ##% */ +package org.nuiton.jaxx.tab; + +import java.io.Serializable; + +/** @author chemit */ +public interface TabModel extends Serializable { + + String getName(); + + void setName(String name); + +} diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/AbstractUIAction.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/AbstractUIAction.java new file mode 100644 index 0000000..ab18764 --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/AbstractUIAction.java @@ -0,0 +1,55 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * @param <H> type of handler + * @author chemit */ +public abstract class AbstractUIAction<H extends DialogUIHandler<?, ?>> extends javax.swing.AbstractAction { + + protected static Log log = LogFactory.getLog(AbstractUIAction.class); + + protected transient DialogUI<? extends H> ui; + + private static final long serialVersionUID = 1L; + + protected AbstractUIAction(String name, javax.swing.Icon icon, DialogUI<? extends H> ui) { + super(name, icon); + this.ui = ui; + } + + protected H getHandler() { + checkInit(); + return ui.getHandler(); + } + + protected void setUi(DialogUI<? extends H> ui) { + this.ui = ui; + } + + public DialogUI<? extends H> getUi() { + return ui; + } + + protected void checkInit() throws IllegalStateException { + /*if (ui == null) { + throw new IllegalStateException("no handler, nor ui referenced in " + this); + } */ + } + +} diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/DialogUI.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/DialogUI.java new file mode 100644 index 0000000..5ec07ea --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/DialogUI.java @@ -0,0 +1,137 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.swing.AbstractAction; +import javax.swing.AbstractButton; +import javax.swing.ImageIcon; +import javax.swing.JDialog; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.lang.reflect.Constructor; + +/** + * A abstract dialog contract to be realised by a dialogUI (WindowEvent adapter) + * <p/> + * TODO : make jaxx authorized implementing interface for root tag :) + * + * @param <H> type of handler + * @author chemit + */ +public abstract class DialogUI<H extends DialogUIHandler<?,?>> extends JDialog implements WindowListener { + + protected static Log log = LogFactory.getLog(DialogUI.class); + + public javax.swing.AbstractAction newAction(Class<?> actionClass, Object... params) { + Constructor<?> constructor = null; + for (Constructor<?> cons : actionClass.getConstructors()) { + Class<?>[] prototype = cons.getParameterTypes(); + if (prototype.length > 0 && DialogUI.class.isAssignableFrom(prototype[0])) { + // use this constructor + constructor = cons; + break; + } + } + if (constructor == null) { + throw new IllegalStateException("could not find a matching constructor for " + actionClass); + } + + // wrap params + Object[] parameters = new Object[1 + params.length]; + parameters[0] = this; + System.arraycopy(params, 0, parameters, 1, params.length); + try { + AbstractAction action = (AbstractAction) constructor.newInstance(parameters); + if (log.isInfoEnabled()) { + log.info(action); + } + return action; + } catch (Exception e) { + throw new IllegalStateException("could not init the action " + actionClass + " for reason : " + e.getMessage()); + } + } + + private H handler; + + public abstract AbstractButton getHelp(); + + public abstract Object getObjectById(java.lang.String s); + + protected DialogUI() { + UIHelper.setQuitAction(this); + addWindowListener(this); + //TODO will be handled by jaxx with javax.help... + //getHelp().setAction(newAction(HelpAction.class)); + } + + public H getHandler() { + return handler; + } + + public void setHandler(H handler) { + this.handler = handler; + } + + protected ImageIcon createActionIcon(String name) { + return UIHelper.createActionIcon(name); + } + + @Override + public void windowOpened(WindowEvent e) { + } + + @Override + public void windowClosed(WindowEvent e) { + } + + @Override + public void windowClosing(WindowEvent e) { + } + + @Override + public void windowIconified(WindowEvent e) { + } + + @Override + public void windowDeiconified(WindowEvent e) { + } + + @Override + public void windowActivated(WindowEvent e) { + } + + @Override + public void windowDeactivated(WindowEvent e) { + } + + @Override + public synchronized void addWindowListener(WindowListener l) { + super.addWindowListener(l); + if (log.isDebugEnabled()) { + log.debug("after added (" + getWindowListeners().length + ") : " + l); + } + } + + @Override + public synchronized void removeWindowListener(WindowListener l) { + super.removeWindowListener(l); + if (log.isDebugEnabled()) { + log.debug("after removed (" + getWindowListeners().length + ") : " + l); + } + } +} \ No newline at end of file diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/DialogUIDef.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/DialogUIDef.java new file mode 100644 index 0000000..cd92124 --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/DialogUIDef.java @@ -0,0 +1,238 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.util; + +import static org.nuiton.i18n.I18n._; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.swing.ImageIcon; +import java.lang.reflect.Constructor; + +/** + * Definition of an ui, with his model, handler and ui class definitions. + * <p/> + * The class contains also a shared instace of concrete ui. + * + * @param <M> type of model + * @param <U> type of ui + * @param <H> type of handler + * @author chemit + */ +public class DialogUIDef<M extends DialogUIModel, U extends DialogUI<H>, H extends DialogUIHandler<M, U>> implements java.io.Serializable { + + static protected final Log log = LogFactory.getLog(DialogUIDef.class); + + public static <M extends DialogUIModel, U extends DialogUI<H>, H extends DialogUIHandler<M, U>> DialogUIDef<M, U, H> newDef(Class<H> handlerClass, Class<U> uiClass, Class<M> modelClass, String showActionLibelle, String showActionTip, String uiTitle) { + DialogUIDef<M, U, H> result; + result = new DialogUIDef<M, U, H>(handlerClass, uiClass, modelClass, showActionLibelle, showActionTip, uiTitle); + return result; + } + + /** + * model class + */ + private final Class<M> modelClass; + + /** + * handler class + */ + private final Class<H> handlerClass; + + /** + * abstract ui class + */ + private final Class<U> uiClass; + + /** + * concrete lookup ui class + */ + private Class<? extends U> uiImplClass; + + /** + * shared instance of ui + */ + protected U uiInstance; + + /** + * unique name of ui def + */ + protected final String name; + + protected final String uiTitle; + protected final String showActionLibelle; + protected final String showActionTip; + + protected ImageIcon showUIActionIcon; + + + private static final long serialVersionUID = 1L; + + private DialogUIDef(Class<H> handlerClass, Class<U> uiClass, Class<M> modelClass, + String showActionLibelle, String showActionTip, String uiTitle) { + this.handlerClass = handlerClass; + this.uiClass = uiClass; + this.modelClass = modelClass; + this.showActionLibelle = showActionLibelle; + this.name = uiClass.getSimpleName().toLowerCase(); + this.showActionTip = showActionTip; + this.uiTitle = uiTitle; + } + + public Class<U> getUiClass() { + return uiClass; + } + + public Class<H> getHandlerClass() { + return handlerClass; + } + + public Class<M> getModelClass() { + return modelClass; + } + + public Class<? extends U> getUiImplClass() { + return uiImplClass; + } + + public String getUiTitle() { + return _(uiTitle); + } + + public String getShowActionLibelle() { + return _(showActionLibelle); + } + + public String getShowActionTip() { + return _(showActionTip); + } + + public ImageIcon getShowUIActionIcon() { + if (showUIActionIcon == null) { + showUIActionIcon = UIHelper.createActionIcon("show-" + name); + } + return showUIActionIcon; + } + + @SuppressWarnings({"unchecked"}) + public void setUiImplClass(Class<?> uiImplClass) { + this.uiImplClass = (Class<? extends U>) uiImplClass; + } + + @Override + public boolean equals(Object o) { + return this == o || o instanceof DialogUIDef<?,?,?> && uiClass.equals(((DialogUIDef<?,?,?>) o).uiClass); + } + + @Override + public int hashCode() { + return uiClass.hashCode(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(super.toString()).append('<'); + sb.append(printClass("handler", handlerClass, true)); + sb.append(printClass("model", modelClass, true)); + sb.append(printClass("ui", uiClass, true)); + sb.append(printClass("uiImpl", uiImplClass, false)); + return sb.toString(); + } + + protected U getUiInstance() { + // no lazy instanciation, to control ui instanciation... + /*if (uiInstance == null) { + if (uiImplClass == null) { + throw new IllegalStateException("no concrete ui impl found in " + this); + } + synchronized (this) { + try { + uiInstance = uiImplClass.newInstance(); + } catch (Exception e) { + throw new IllegalStateException("could not instanciate ui " + this,e); + } + } + }*/ + return uiInstance; + } + + protected void setUiInstance(U uiInstance) { + this.uiInstance = uiInstance; + } + + protected U newUI() { + if (uiImplClass == null) { + throw new IllegalStateException("no concrete ui impl found in " + this); + } + try { + U result = uiImplClass.newInstance(); + log.info(result); + return result; + } catch (Exception e) { + throw new IllegalStateException("could not instanciate ui " + this, e); + } + } + + protected M newModel() { + if (modelClass == null) { + throw new IllegalStateException("no model impl found in " + this); + } + try { + M model = modelClass.newInstance(); + log.info(model); + return model; + } catch (Exception e) { + throw new IllegalStateException("could not instanciate ui " + this, e); + } + } + + protected H newHandler(U ui, M model, Object... params) { + if (handlerClass == null) { + throw new IllegalStateException("no handler impl found in " + this); + } + try { + Class<?>[] prototype = getHandlerPrototype(params); + Object[] parameters = getHandlerParameters(ui, model, params); + H result = handlerClass.getConstructor(prototype).newInstance(parameters); + log.info(result); + return result; + } catch (Exception e) { + throw new IllegalStateException("could not instanciate ui " + this, e); + } + } + + protected Object[] getHandlerParameters(U ui, M model, Object[] params) { + Object[] result = new Object[2 + params.length]; + result[0] = ui; + result[1] = model; + System.arraycopy(params, 0, result, 2, params.length); + return result; + } + + protected Class<?>[] getHandlerPrototype(Object[] params) { + int length = params.length; + for (Constructor<?> constructor : handlerClass.getConstructors()) { + Class<?>[] prototype = constructor.getParameterTypes(); + if (prototype.length == 2 + length && prototype[0] == uiClass && prototype[1] == modelClass) { + return prototype; + } + } + throw new IllegalStateException("could not find a matching constructor in " + handlerClass); + } + + protected String printClass(String s, Class<?> aClass, boolean notLast) { + return s + ':' + (aClass == null ? null : aClass.getSimpleName()) + (notLast ? ", " : ">"); + } +} diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/DialogUIHandler.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/DialogUIHandler.java new file mode 100644 index 0000000..cb5fdf8 --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/DialogUIHandler.java @@ -0,0 +1,72 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.awt.event.WindowListener; +import java.beans.PropertyChangeListener; + +/** + * DialogUI handler + * + * @param <M> type of model + * @param <U> type of ui + * @author chemit + */ +public abstract class DialogUIHandler<M extends DialogUIModel, U extends DialogUI<? extends DialogUIHandler<?,?>>> implements PropertyChangeListener { + + protected static Log log = LogFactory.getLog(DialogUIHandler.class); + + /** ui handled */ + private U ui; + + /** model handled */ + private M model; + + protected DialogUIHandler(U ui, M model) { + this.ui = ui; + this.model = model; + } + + public U getUi() { + return ui; + } + + public M getModel() { + return model; + } + + public void init() { + if (model == null) { + throw new IllegalStateException("no model was defined for " + this); + } + model.addPropertyChangeListener(this); + } + + public void dispose() { + model.dispose(); + for (WindowListener windowListener : getUi().getWindowListeners()) { + getUi().removeWindowListener(windowListener); + } + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + dispose(); + } +} \ No newline at end of file diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/DialogUIModel.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/DialogUIModel.java new file mode 100644 index 0000000..96a06f5 --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/DialogUIModel.java @@ -0,0 +1,97 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; + +/** + * Abstract ui model, with property change support. + * + * @author chemit + */ +public abstract class DialogUIModel { + + static protected final Log log = LogFactory.getLog(DialogUIModel.class); + + /** support for change properties support */ + protected PropertyChangeSupport changeSupport; + + public synchronized void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + if (listener == null) { + return; + } + if (changeSupport == null) { + changeSupport = new PropertyChangeSupport(this); + } + changeSupport.addPropertyChangeListener(propertyName, listener); + } + + public synchronized void addPropertyChangeListener(PropertyChangeListener listener) { + if (listener == null) { + return; + } + if (changeSupport == null) { + changeSupport = new PropertyChangeSupport(this); + } + changeSupport.addPropertyChangeListener(listener); + } + + public synchronized void removePropertyChangeListener(PropertyChangeListener listener) { + if (listener == null || changeSupport == null) { + return; + } + changeSupport.removePropertyChangeListener(listener); + } + + public synchronized void removePropertyChangeListeners() { + if (changeSupport == null) { + return; + } + for (PropertyChangeListener listener : getPropertyChangeListeners()) { + changeSupport.removePropertyChangeListener(listener); + } + } + + public synchronized PropertyChangeListener[] getPropertyChangeListeners() { + if (changeSupport == null) { + return new PropertyChangeListener[0]; + } + return changeSupport.getPropertyChangeListeners(); + } + + public void firePropertyChange(String propertyName, Object oldValue, Object newValue) { + if (changeSupport == null || (oldValue == null && newValue == null) || + (oldValue != null && oldValue.equals(newValue))) { + return; + } + changeSupport.firePropertyChange(propertyName, oldValue, newValue); + } + + public void dispose() { + for (PropertyChangeListener listener : changeSupport.getPropertyChangeListeners()) { + changeSupport.removePropertyChangeListener(listener); + } + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + dispose(); + } +} \ No newline at end of file diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/FactoryWindowListener.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/FactoryWindowListener.java new file mode 100644 index 0000000..8ffe6e2 --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/FactoryWindowListener.java @@ -0,0 +1,84 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.util; + +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +/** + * A windowListenr for ui managed by {@link org.nuiton.jaxx.util.UIFactory}. + * <p/> + * To be used when all ui from factory are closed, via {@link #allWindowsClosed(java.awt.event.WindowEvent)} method. + * + * @author chemit + */ +public abstract class FactoryWindowListener extends WindowAdapter { + + /** + * method to be invoked when all ui registred in factory are really disposed. + * + * @param e event + */ + public abstract void allWindowsClosed(WindowEvent e); + + /** underlying factory of ui */ + private UIFactory factory; + + /** flag to make sure {@link #allWindowsClosed(java.awt.event.WindowEvent)} is called only once. */ + private boolean wasClosed; + + @Override + public void windowClosed(WindowEvent e) { + if (UIFactory.log.isDebugEnabled()) { + UIFactory.log.debug(this + " : " + e); + } + if (e.getWindow().isVisible()) { + // only deal with real closed and none visible windows... + return; + } + for (DialogUIDef<?,?,?> def : factory.getDefs()) { + DialogUI<?> ui = def.uiInstance; + if (ui != null && ui.isVisible()) { + // at least one ui visible, do not close all + return; + } + } + + if (wasClosed) { + // make sure to process only once + return; + } + if (UIFactory.log.isInfoEnabled()) { + UIFactory.log.info("closing factory listener " + this); + } + + synchronized (this) { + try { + allWindowsClosed(e); + } finally { + wasClosed = true; + factory.removeFactoryWindowListener(this); + } + } + } + + protected UIFactory getFactory() { + return factory; + } + + protected void setFactory(UIFactory factory) { + this.factory = factory; + } +} diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/FormElement.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/FormElement.java new file mode 100644 index 0000000..ff54c85 --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/FormElement.java @@ -0,0 +1,31 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.util; + +/** + * @param <U> type of dialog + * @author chemit */ +public interface FormElement<U extends DialogUI<?>> { + + String name(); + + int ordinal(); + + Object getValue(U ui); + + void setValue(U ui, String value); + + javax.swing.JLabel getLabel(U ui); +} diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/ShowUIAction.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/ShowUIAction.java new file mode 100644 index 0000000..d659e36 --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/ShowUIAction.java @@ -0,0 +1,140 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.awt.Dimension; +import java.awt.Point; +import java.awt.event.ActionEvent; + +/** + * @param <M> type of model + * @param <U> type of ui + * @param <H> type of handler + * @author chemit */ +public abstract class ShowUIAction<M extends DialogUIModel, U extends DialogUI<H>, H extends DialogUIHandler<M, U>> extends javax.swing.AbstractAction { + + protected static Log log = LogFactory.getLog(AbstractUIAction.class); + + protected transient DialogUI<?> ui; + + private static final long serialVersionUID = 1L; + + protected DialogUIDef<M, U, H> uiDef; + + protected transient UIFactory factory; + + protected String position; + + protected boolean undecorated = true; + + protected U initUI(ActionEvent e) { + return getFactory().getUI(uiDef); + } + + public ShowUIAction(DialogUI<?> ui, DialogUIDef<M, U, H> uiDef, UIFactory factory, boolean showText) { + super(uiDef.getShowActionLibelle(), uiDef.getShowUIActionIcon()); + this.ui = ui; + this.uiDef = uiDef; + String name = (String) getValue(NAME); + putValue(DISPLAYED_MNEMONIC_INDEX_KEY, name.length() - 1); + putValue(ACCELERATOR_KEY, (int) name.charAt(name.length() - 1)); + if (!showText) { + putValue(NAME, null); + } + putValue(SHORT_DESCRIPTION, uiDef.getShowActionTip()); + this.factory = factory; + } + + public DialogUI<?> getUi() { + return ui; + } + + public DialogUIDef<M, U, H> getUiDef() { + return uiDef; + } + + public UIFactory getFactory() { + return factory; + } + + public void setUiDef(DialogUIDef<M, U, H> uiDef) { + this.uiDef = uiDef; + } + + public void setPosition(String position) { + this.position = position; + } + + public void setUndecorated(boolean undecorated) { + this.undecorated = undecorated; + } + + @Override + public void actionPerformed(java.awt.event.ActionEvent e) { + checkInit(); + U gui = initUI(e); + gui.setTitle(uiDef.getUiTitle()); + log.info(gui.getTitle()); + //TODO ui.setUndecorated(undecorated); + setPosition(this.getUi(), gui, position); + + gui.setVisible(true); + } + + protected void setPosition(javax.swing.JDialog parentUI, javax.swing.JDialog ui, String position) { + if (position == null || parentUI == null) { + return; + } + Point parentLocation = parentUI.getLocationOnScreen(); + Dimension parentSize = parentUI.getSize(); + + if (position.equals("bottom-left")) { + int top = (int) (parentLocation.getY() + parentSize.getHeight()); + int left = (int) (parentLocation.getX()); + Point newLocation = new Point(left, top); + newLocation.setLocation(left, top); + ui.setLocation(newLocation); + return; + } + if (position.equals("top-left")) { + int top = (int) (parentLocation.getY()); + int left = (int) (parentLocation.getX()); + Point newLocation = new Point(left, top); + newLocation.setLocation(left, top); + ui.setLocation(newLocation); + return; + } + if (position.equals("top-right")) { + int top = (int) (parentLocation.getY()); + int left = (int) (parentLocation.getX() + parentSize.getWidth()); + Point newLocation = new Point(left, top); + newLocation.setLocation(left, top); + ui.setLocation(newLocation); + return; + } + if (position.equals(("center"))) { + //TODO + } + } + + protected void checkInit() throws IllegalStateException { + if (factory == null) { + throw new IllegalStateException("no factory found in " + this); + } + } +} \ No newline at end of file diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/UIFactory.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/UIFactory.java new file mode 100644 index 0000000..a5001ac --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/UIFactory.java @@ -0,0 +1,184 @@ +/** +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.util.StringUtil; + +import javax.swing.event.EventListenerList; +import java.util.ArrayList; +import java.util.List; +import java.util.ServiceLoader; + +/** + * Factory for UI, using a cache and a provider to find ui implementations. + * + * @author chemit + */ +public class UIFactory { + + static protected final Log log = LogFactory.getLog(UIFactory.class); + + private final String applicationName; + + private final DialogUIDef<?,?,?>[] defs; + + private final EventListenerList listeners; + + public UIFactory(String applicationName, DialogUIDef<?,?,?>[] defs, FactoryWindowListener... listeners) { + this.applicationName = applicationName; + this.listeners = new EventListenerList(); + for (FactoryWindowListener listener : listeners) { + listener.setFactory(this); + addFactoryWindowListener(listener); + } + this.defs = defs; + long t0 = System.nanoTime(); + if (log.isDebugEnabled()) { + log.debug("start at " + new java.util.Date()); + } + try { + init(); + } catch (Exception e) { + log.error(e); + throw new RuntimeException(e); + } finally { + if (log.isDebugEnabled()) { + log.info("end in " + StringUtil.convertTime(t0, System.nanoTime())); + } + } + } + + public void addFactoryWindowListener(FactoryWindowListener l) { + listeners.add(FactoryWindowListener.class, l); + if (log.isDebugEnabled()) { + log.debug("after added (" + listeners.getListenerCount() + ") : " + l); + } + } + + public void removeFactoryWindowListener(FactoryWindowListener l) { + listeners.remove(FactoryWindowListener.class, l); + for (DialogUIDef<?,?,?> def : getDefs()) { + if (def.uiInstance != null) { + def.uiInstance.removeWindowListener(l); + } + } + if (log.isDebugEnabled()) { + log.debug(" after removed (" + listeners.getListenerCount() + ") : " + l); + } + if (listeners.getListenerCount(FactoryWindowListener.class) == 0) { + // close for real factory + close(); + } + } + + public void close() { + log.info(this + " at " + new java.util.Date()); + for (DialogUIDef<?, ?, ?> def : defs) { + DialogUI<?> ui = def.uiInstance; + if (ui != null) { + ui.getHandler().dispose(); + def.uiInstance = null; + } + } + if (listeners.getListenerCount(FactoryWindowListener.class) > 0) { + log.warn("some listeners where not properly removed, force deletion..."); + for (FactoryWindowListener listener : listeners.getListeners(FactoryWindowListener.class)) { + removeFactoryWindowListener(listener); + } + } + + } + + protected void init() { + + UIProvider[] providers = detectProviders(); + + for (DialogUIDef<?, ?, ?> def : defs) { + initDef(providers, def); + if (def.getUiImplClass() == null) { + throw new IllegalStateException("could not find implementation for ui def " + def); + } + } + } + + protected void initDef(UIProvider[] providers, DialogUIDef<?, ?, ?> def) { + for (UIProvider provider : providers) { + Class<?> uiImplClass = provider.findUIImplementation(def); + if (uiImplClass != null) { + if (log.isDebugEnabled()) { + log.debug("init done for " + def); + } + // ui implementation was found + break; + } + } + } + + protected UIProvider[] detectProviders() { + long t0 = System.nanoTime(); + List<UIProvider> providers = new ArrayList<UIProvider>(); + for (UIProvider provider : ServiceLoader.load(UIProvider.class)) { + if (applicationName.equals(provider.getApplicationName())) { + if (log.isDebugEnabled()) { + log.debug("provider detected [" + provider + ']'); + } + providers.add(provider); + } + } + log.info("found " + providers.size() + " ui provider(s) in " + StringUtil.convertTime(t0, System.nanoTime()) + " : " + providers); + return providers.toArray(new UIProvider[providers.size()]); + } + + protected DialogUIDef<?,?,?>[] getDefs() { + return defs; + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + close(); + } + + public <M extends DialogUIModel, U extends DialogUI<H>, H extends DialogUIHandler<M, U>> U getUI(DialogUIDef<M, U, H> uiType, Object... params) { + U ui = uiType.uiInstance; + if (ui == null) { + try { + ui = uiType.newUI(); + M model = uiType.newModel(); + H handler = uiType.newHandler(ui, model, params); + registerUI(uiType, ui, handler); + } catch (Exception e) { + throw new IllegalStateException("could not instanciate ui handler " + uiType + " for reason : " + e.getMessage(), e); + } + } + return ui; + } + + protected <M extends DialogUIModel, U extends DialogUI<H>, H extends DialogUIHandler<M, U>> void registerUI(DialogUIDef<M, U, H> uiType, U ui, H handler) { + ui.setHandler(handler); + handler.init(); + uiType.setUiInstance(ui); + for (FactoryWindowListener listener : listeners.getListeners(FactoryWindowListener.class)) { + if (log.isDebugEnabled()) { + log.debug("----- addFactoryWindowListener " + listener + " to " + ui); + } + ui.addWindowListener(listener); + } + } + +} \ No newline at end of file diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/UIHelper.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/UIHelper.java new file mode 100644 index 0000000..9cb2136 --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/UIHelper.java @@ -0,0 +1,71 @@ +/* +* ##% Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 Code Lutin, +* Tony Chemit +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* ##% */ +package org.nuiton.jaxx.util; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JRootPane; +import javax.swing.KeyStroke; +import java.awt.event.ActionEvent; + +/** + * Ui helper class. + * + * @author tony + */ +public class UIHelper { + + public static ImageIcon createImageIcon(String path) { + java.net.URL imgURL = UIHelper.class.getResource("/icons/" + path); + if (imgURL != null) { + return new ImageIcon(imgURL); + } else { + throw new IllegalArgumentException("could not find icon " + path); + } + } + + /** + * Attach to <code>ui</code> an abort action,accessible by <code>ESC</code> key. + * + * @param ui ui + */ + public static void setQuitAction(final JDialog ui) { + JRootPane rootPane = ui.getRootPane(); + + Action quitAction = new AbstractAction("quit") { + private static final long serialVersionUID = -869095664995763057L; + + @Override + public void actionPerformed(ActionEvent e) { + ui.dispose(); + } + }; + rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("ESCAPE"), "quit"); + rootPane.getActionMap().put("quit", quitAction); + ui.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + } + + public static ImageIcon createActionIcon(String name) { + return createImageIcon("action-" + name + ".png"); + } + +} diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/UIProvider.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/UIProvider.java new file mode 100644 index 0000000..629bc87 --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/UIProvider.java @@ -0,0 +1,86 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.util; + +/** @author chemit */ +public abstract class UIProvider { + + /** the name of application using this provider */ + protected String applicationName; + + /** the name of ui implementation used by this provider */ + protected String providerName; + + /** array of ui implementations */ + protected Class<?>[] implementations; + + protected UIProvider(String applicationName, String providerName, Class<?>... implementations) { + this.applicationName = applicationName; + this.providerName = providerName; + this.implementations = implementations; + } + + public String getProviderName() { + return providerName; + } + + public String getApplicationName() { + return applicationName; + } + + public Class<?>[] getImplementations() { + return implementations; + } + + public Class<?> findUIImplementation(DialogUIDef<?, ?, ?> def) { + Class<? extends DialogUI<?>> uiClass = def.getUiClass(); + for (Class<?> klass : implementations) { + if (uiClass.isAssignableFrom(klass)) { + def.setUiImplClass(klass); + return klass; + } + } + return null; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(super.toString()).append('<'); + sb.append(printClass("application", applicationName, true)); + sb.append(printClass("provider", providerName, true)); + sb.append(printClass("uis", implementations.length, false)); + return sb.toString(); + } + + protected String printClass(String s, Object aClass, boolean notLast) { + return s + ':' + (aClass == null ? null : aClass) + (notLast ? ", " : ">"); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof UIProvider)) return false; + + UIProvider that = (UIProvider) o; + return applicationName.equals(that.applicationName) && providerName.equals(that.providerName); + + } + + @Override + public int hashCode() { + return (31 * applicationName.hashCode()) + providerName.hashCode(); + } + +} \ No newline at end of file diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/config/CancelAction.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/config/CancelAction.java new file mode 100644 index 0000000..6e58346 --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/config/CancelAction.java @@ -0,0 +1,43 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.util.config; + +import org.nuiton.jaxx.util.AbstractUIAction; +import org.nuiton.jaxx.util.DialogUI; +import org.nuiton.jaxx.util.UIHelper; + +import java.awt.event.ActionEvent; + +/** @author chemit */ +public class CancelAction<E extends Enum<E>, H extends DialogConfigUIHandler<E, ?, ?>> extends AbstractUIAction<H> { + private static final long serialVersionUID = 1L; + + public CancelAction(DialogUI<? extends H> dialogUI, boolean showLabel) { + super(null, UIHelper.createActionIcon("cancel-config"), dialogUI); + if (showLabel) { + String text = org.nuiton.i18n.I18n._("lutinui.config.cancel"); + putValue(NAME, text); + putValue(DISPLAYED_MNEMONIC_INDEX_KEY, 0); + putValue(MNEMONIC_KEY, (int) text.charAt(0)); + } + String libelle = org.nuiton.i18n.I18n._("lutinui.config.cancel.tooltip"); + putValue(SHORT_DESCRIPTION, libelle); + + } + + public void actionPerformed(ActionEvent e) { + getUi().dispose(); + } +} \ No newline at end of file diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/config/DialogConfigUI.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/config/DialogConfigUI.java new file mode 100644 index 0000000..d39efa3 --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/config/DialogConfigUI.java @@ -0,0 +1,105 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.util.config; + +import org.nuiton.jaxx.util.DialogUI; + +import javax.swing.AbstractButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPasswordField; +import javax.swing.JRadioButton; +import javax.swing.JTextField; + +/** + * A abstract dialog contract to be realised by a dialogUI (WindowEvent adapter) + * <p/> + * TODO : make jaxx authorized implementing interface for root tag :) + * + * @author chemit + */ +public abstract class DialogConfigUI<E extends Enum<E>, H extends DialogConfigUIHandler<E, ?, ?>> extends DialogUI<H> { + + public abstract AbstractButton getOk(); + + public abstract AbstractButton getReset(); + + public abstract AbstractButton getCancel(); + + public JComponent getElement(E key) { + Object id = getObjectById(key.name()); + if (id == null) { + log.error(new NullPointerException("no widget for key "+key)); + return null; + } + if (!(id instanceof JComponent)) { + throw new IllegalArgumentException(id + " is not a JComponent"); + } + return (JComponent) id; + } + + public Object getElementValue(E key) { + JComponent o = getElement(key); + if (o instanceof JPasswordField) { + return new String(((JPasswordField) o).getPassword()); + } + if (o instanceof JTextField) { + return ((JTextField) o).getText(); + } + if (o instanceof JRadioButton) { + return ((JRadioButton) o).isSelected(); + } + if (o instanceof JCheckBox) { + return ((JCheckBox) o).isSelected(); + } + + if (o instanceof JComboBox) { + return ((JComboBox) o).getSelectedItem(); + } + return ""; + } + + public void setElementValue(E key, Object value) { + JComponent o = getElement(key); + + String strValue = value == null ? "" : String.valueOf(value); + if (o instanceof JPasswordField) { + ((JPasswordField) o).setText(strValue); + } + if (o instanceof JTextField) { + ((JTextField) o).setText(strValue); + } + if (o instanceof JRadioButton) { + ((JRadioButton) o).setSelected(Boolean.valueOf(strValue.isEmpty() ? "false" : strValue)); + } + if (o instanceof JCheckBox) { + ((JCheckBox) o).setSelected(Boolean.valueOf(strValue.isEmpty() ? "false" : strValue)); + } + if (o instanceof JComboBox) { + ((JComboBox) o).setSelectedItem(value); + } + } + + public JLabel getElementLabel(E key) { + return (JLabel) getObjectById(key.name() + "Label"); + } + + public void doCheck(E key) { + getHandler().doCheck(key); + } + +} \ No newline at end of file diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/config/DialogConfigUIHandler.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/config/DialogConfigUIHandler.java new file mode 100644 index 0000000..b91baed --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/config/DialogConfigUIHandler.java @@ -0,0 +1,156 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.util.config; + +import org.nuiton.jaxx.util.DialogUIHandler; +import org.nuiton.util.ConverterUtil; +import org.nuiton.util.config.Config; +import org.nuiton.util.config.Property; + +import javax.swing.JComponent; +import java.awt.Color; +import java.beans.PropertyChangeEvent; +import java.util.EnumMap; +import java.util.EnumSet; + +/** + * DialogUI handler + * + * @author chemit + */ +public abstract class DialogConfigUIHandler<E extends Enum<E>, M extends DialogConfigUIModel<E, ?>, U extends DialogConfigUI<E, ?>> extends DialogUIHandler<M, U> { + + protected DialogConfigUIHandler(U ui, M model) { + super(ui, model); + } + + public void propertyChange(PropertyChangeEvent evt) { + if (log.isDebugEnabled()) { + log.debug(evt.getPropertyName() + " old:" + evt.getOldValue() + ", new:" + evt.getNewValue()); + } + String action = evt.getPropertyName(); + + if (DialogConfigUIModel.CONFIG_PROPERTY_CHANGED.equals(action)) { + // update ui with model values, + populateUI(); + // revalidate form + doCheckAll(); + return; + } + + if (DialogConfigUIModel.MODIFIED_PROPERTY_CHANGED.equals(action)) { + Boolean newValue = (Boolean) evt.getNewValue(); + boolean modified = newValue != null && newValue; + getUi().getReset().setEnabled(modified); + getUi().getOk().setEnabled(modified && getModel().isConfigValid()); + return; + } + + if (DialogConfigUIModel.UNVALID_PROPERTY_CHANGED.equals(action)) { + updateUI(); + return; + } + + throw new IllegalStateException("unimplemented property changed : " + evt + " for " + this); + } + + public void doCheck(E key) { + Object uiValue = getUi().getElementValue(key); + DialogConfigUIModel<E, ?> model = getModel(); + Object currentValue = model.getCurrent().getProperty(key); + if (currentValue == null) { + currentValue = ""; + } else { + currentValue = String.valueOf(currentValue); + } + + model.validateProperty(key, uiValue); + model.changeModifiedState(key, uiValue, currentValue); + } + + public void doCheckAll() { + DialogConfigUIModel<E, ?> model = getModel(); + EnumSet<E> unvalids = EnumSet.noneOf(model.klass); + for (E e : model.getCheckedKeysSet()) { + Object uiValue = getUi().getElementValue(e); + if (!model.isValid(e, uiValue)) { + unvalids.add(e); + } + } + model.setUnvalids(unvalids); + unvalids.clear(); + } + + protected boolean prepareSave() { + DialogConfigUI<E, ?> ui = getUi(); + DialogConfigUIModel<E, ?> model = getModel(); + + Config<E> current = model.getCurrent(); + + if (!model.isConfigValid()) { + log.warn("do not save a unvalid config : " + model.getUnvalids()); + return false; + } + + if (!model.isModified()) { + log.warn("nothing to save"); + return false; + } + EnumSet<E> toTreate = model.getCheckedKeysSet(); + // transfert checkable values from ui to model + for (E key : model.getModifieds()) { + if (!toTreate.contains(key)) { + continue; + } + Object value = ui.getElementValue(key); + Class<?> type = ((Property) key).getType(); + Object newValue = ConverterUtil.convert(type, value); + current.setProperty(key, newValue); + } + + return true; + } + + protected void populateUI() { + U ui = getUi(); + EnumMap<E, Object> map = getModel().getCurrent().getProperties(); + for (E e : getModel().getCheckedKeysSet()) { + Object value = map.get(e); + populateUI(ui, e, value); + } + } + + protected void populateUI(U ui, E key, Object value) { + ui.setElementValue(key, value); + } + + protected void updateUI() { + EnumSet<E> unvalids = getModel().getUnvalids(); + for (E key : unvalids) { + setLabelColor(key, false); + } + for (E key : EnumSet.complementOf(unvalids)) { + setLabelColor(key, true); + } + } + + protected void setLabelColor(E key, boolean valid) { + JComponent component = getUi().getElementLabel(key); + if (component != null && component.isVisible()) { + component.setForeground(valid ? Color.black : Color.red); + } + } + +} \ No newline at end of file diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/config/DialogConfigUIModel.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/config/DialogConfigUIModel.java new file mode 100644 index 0000000..fe9b373 --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/config/DialogConfigUIModel.java @@ -0,0 +1,220 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.util.config; + +import org.nuiton.jaxx.util.DialogUIModel; +import org.nuiton.util.config.Config; + +import java.util.EnumSet; + +/** + * Abstract config ui model. + * + * @author chemit + */ +public abstract class DialogConfigUIModel<E extends Enum<E>, C extends Config<E>> extends DialogUIModel { + + public static final String CONFIG_PROPERTY_CHANGED = "config"; + public static final String MODIFIED_PROPERTY_CHANGED = "modify"; + public static final String UNVALID_PROPERTY_CHANGED = "unvalid"; + + /** @return a empty config */ + protected abstract C newConfig(); + + /** + * @param key property key + * @param value value to validate + * @return <code>true</code> if given value is valid for property, <code>false>/code> otherwise + */ + protected abstract boolean isValid(E key, Object value); + + /** + * object used to init model and save model, this is an external object. + * <p/> + * The object must have bean read-write properties for each value of E + */ + protected Object src; + + /** current config used in model */ + protected C current; + + /** set of modified properties */ + protected EnumSet<E> modifieds; + + /** set of unvalid properties */ + protected EnumSet<E> unvalids; + + /** enum class */ + protected Class<E> klass; + + /** set of key not to check */ + protected EnumSet<E> uncheckedKeys; + + /** set of all keys checkable */ + protected EnumSet<E> checkedKeysSet; + + protected DialogConfigUIModel(Class<E> klass) { + this.klass = klass; + this.current = newConfig(); + this.modifieds = EnumSet.noneOf(klass); + this.unvalids = EnumSet.noneOf(klass); + } + + public EnumSet<E> getCheckedKeysSet() { + if (checkedKeysSet == null) { + if (uncheckedKeys != null) { + checkedKeysSet = EnumSet.complementOf(uncheckedKeys); + } else { + checkedKeysSet = EnumSet.allOf(klass); + } + } + return checkedKeysSet; + } + + public Object getSrc() { + return src; + } + + public C getCurrent() { + return current; + } + + public EnumSet<E> getUnivserse() { + return getCurrent().getUniverse(); + } + + public EnumSet<E> getModifieds() { + return modifieds; + } + + public EnumSet<E> getUnvalids() { + return unvalids; + } + + public boolean isModified() { + return !modifieds.isEmpty(); + } + + public boolean isConfigValid() { + return unvalids.isEmpty(); + } + + public void populate(Object src) { + this.src = src; + this.current = newConfig(); + if (src != null) { + this.current.copyFrom(src); + } + this.modifieds.clear(); + this.unvalids.clear(); + setModified(false); + firePropertyChange(CONFIG_PROPERTY_CHANGED, null, this); + } + + public void reset() { + populate(src); + } + + public void setModified(boolean modified) { + firePropertyChange(MODIFIED_PROPERTY_CHANGED, null, modified); + } + + public void setUnvalid(boolean unvalid) { + firePropertyChange(UNVALID_PROPERTY_CHANGED, null, unvalid); + } + + public void addModified(E key) { + if (!modifieds.contains(key)) { + modifieds.add(key); + log.debug(key); + } + setModified(!modifieds.isEmpty()); + } + + public void removeModified(E key) { + + if (modifieds.contains(key)) { + modifieds.remove(key); + } + setModified(!modifieds.isEmpty()); + } + + public void removeModified(EnumSet<E> keys) { + for (E key : keys) { + if (modifieds.contains(key)) { + modifieds.remove(key); + } + } + setModified(!modifieds.isEmpty()); + } + + public void setUnvalids(EnumSet<E> keys) { + for (E key : keys) { + if (!unvalids.contains(key)) { + unvalids.add(key); + } + } + for (E key : EnumSet.complementOf(keys)) { + if (unvalids.contains(key)) { + unvalids.remove(key); + } + } + setUnvalid(!unvalids.isEmpty()); + } + + + public void addUnvalid(E key) { + if (!unvalids.contains(key)) { + unvalids.add(key); + } + setUnvalid(!unvalids.isEmpty()); + } + + public void removeUnvalid(E key) { + if (unvalids.contains(key)) { + unvalids.remove(key); + } + setUnvalid(!unvalids.isEmpty()); + } + + public void save() { + current.copyTo(src, modifieds); + modifieds.clear(); + // redisplay config + firePropertyChange(CONFIG_PROPERTY_CHANGED, null, this); + } + + public void changeModifiedState(E key, Object uiValue, Object currentValue) { + if (uiValue!=null && uiValue.equals(currentValue)) { + removeModified(key); + } else { + addModified(key); + } + } + + public void clear(E key) { + log.info(key); + modifieds.remove(key); + unvalids.remove(key); + } + + protected void validateProperty(E key, Object uiValue) { + if (isValid(key, uiValue)) { + removeUnvalid(key); + } else { + addUnvalid(key); + } + } +} \ No newline at end of file diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/config/ResetAction.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/config/ResetAction.java new file mode 100644 index 0000000..8a9d30c --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/config/ResetAction.java @@ -0,0 +1,43 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.util.config; + +import org.nuiton.jaxx.util.AbstractUIAction; +import org.nuiton.jaxx.util.DialogUI; +import org.nuiton.jaxx.util.UIHelper; + +import java.awt.event.ActionEvent; + +/** @author chemit */ +public class ResetAction<E extends Enum<E>, H extends DialogConfigUIHandler<E, ?, ?>> extends AbstractUIAction<H> { + private static final long serialVersionUID = 1L; + + public ResetAction(DialogUI<? extends H> dialogUI, boolean showLabel) { + super(null, UIHelper.createActionIcon("reset-config"), dialogUI); + if (showLabel) { + String text = org.nuiton.i18n.I18n._("lutinui.config.reset"); + putValue(NAME, text); + putValue(DISPLAYED_MNEMONIC_INDEX_KEY, 0); + putValue(MNEMONIC_KEY, (int) text.charAt(0)); + } + String libelle = org.nuiton.i18n.I18n._("lutinui.config.reset.tooltip"); + putValue(SHORT_DESCRIPTION, libelle); + + } + + public void actionPerformed(ActionEvent e) { + getHandler().getModel().reset(); + } +} \ No newline at end of file diff --git a/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/config/SaveAction.java b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/config/SaveAction.java new file mode 100644 index 0000000..b4f994c --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/java/org/nuiton/jaxx/util/config/SaveAction.java @@ -0,0 +1,50 @@ +/** + * ##% Copyright (C) 2008 Code Lutin, Tony Chemit + * This program is free software; you + * can redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. You + * should have received a copy of the GNU General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place + * - Suite 330, Boston, MA 02111-1307, USA. + * ##% + */ +package org.nuiton.jaxx.util.config; + +import org.nuiton.jaxx.util.AbstractUIAction; +import org.nuiton.jaxx.util.DialogUI; +import org.nuiton.jaxx.util.UIHelper; + +import java.awt.event.ActionEvent; + +/** @author chemit */ +public class SaveAction<E extends Enum<E>, H extends DialogConfigUIHandler<E, ?, ?>> extends AbstractUIAction<H> { + private static final long serialVersionUID = 1L; + + public SaveAction(DialogUI<? extends H> dialogUI, boolean showLabel) { + super(null, UIHelper.createActionIcon("save-config"), dialogUI); + if (showLabel) { + String text = org.nuiton.i18n.I18n._("lutinui.config.save"); + putValue(NAME, text); + putValue(DISPLAYED_MNEMONIC_INDEX_KEY, 0); + putValue(MNEMONIC_KEY, (int) text.charAt(0)); + } + String libelle = org.nuiton.i18n.I18n._("lutinui.config.save.tooltip"); + putValue(SHORT_DESCRIPTION, libelle); + } + + public void actionPerformed(ActionEvent e) { + + if (getHandler().prepareSave()) { + + // save model to src + getHandler().getModel().save(); + + // close ui + getUi().dispose(); + } + } +} diff --git a/trunk/jaxx-swing-action/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/trunk/jaxx-swing-action/src/main/resources/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 0000000..1b41cf0 --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1 @@ +org.nuiton.jaxx.action.ActionAnnotationProcessing \ No newline at end of file diff --git a/trunk/jaxx-swing-action/src/main/resources/i18n/jaxx-swing-action-en_GB.properties b/trunk/jaxx-swing-action/src/main/resources/i18n/jaxx-swing-action-en_GB.properties new file mode 100644 index 0000000..4c960a0 --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/resources/i18n/jaxx-swing-action-en_GB.properties @@ -0,0 +1,10 @@ +jaxx.action.done=Action '%1$s' done. +jaxx.error.close.actions.file=Error while closing file of actions +jaxx.error.load.actions.class=Error while loading actions +jaxx.error.load.actions.file=Error while loading file of actions +lutinui.config.cancel=Cancel +lutinui.config.cancel.tooltip=Cancel and quit +lutinui.config.reset=Reset +lutinui.config.reset.tooltip=Reset configuration +lutinui.config.save=Save +lutinui.config.save.tooltip=Save configuration and quit diff --git a/trunk/jaxx-swing-action/src/main/resources/i18n/jaxx-swing-action-fr_FR.properties b/trunk/jaxx-swing-action/src/main/resources/i18n/jaxx-swing-action-fr_FR.properties new file mode 100644 index 0000000..fa697e6 --- /dev/null +++ b/trunk/jaxx-swing-action/src/main/resources/i18n/jaxx-swing-action-fr_FR.properties @@ -0,0 +1,10 @@ +jaxx.action.done=Action '%1$s' termin\u00E9e. +jaxx.error.close.actions.file=Erreur lors de la fermeture du fichier d'actions +jaxx.error.load.actions.class=Erreur lors du chargement des actions +jaxx.error.load.actions.file=Erreur lors du chargement du fchier d'actions +lutinui.config.cancel=Annuler +lutinui.config.cancel.tooltip=Annuler les modification et quitter +lutinui.config.reset=R\u00E9initialiser +lutinui.config.reset.tooltip=R\u00E9initialiser la configuration +lutinui.config.save=Sauver +lutinui.config.save.tooltip=Sauver la configuration et quitter diff --git a/trunk/jaxx-swing-action/src/site/rst/Todo.rst b/trunk/jaxx-swing-action/src/site/rst/Todo.rst new file mode 100644 index 0000000..d7aabf6 --- /dev/null +++ b/trunk/jaxx-swing-action/src/site/rst/Todo.rst @@ -0,0 +1,4 @@ +TODO +==== + +a faire \ No newline at end of file diff --git a/trunk/jaxx-swing-action/src/site/rst/index.rst b/trunk/jaxx-swing-action/src/site/rst/index.rst new file mode 100644 index 0000000..0c9d288 --- /dev/null +++ b/trunk/jaxx-swing-action/src/site/rst/index.rst @@ -0,0 +1,13 @@ +jaxx-swing-action +================= + +.. contents:: + + +Présentation +------------ + +Framework de gestion des actions et onglets TODO + +**Veuillez consulter la JavaDoc pour de plus ample détails sur les différentes +librairies.** diff --git a/trunk/jaxx-swing-action/src/site/site.xml b/trunk/jaxx-swing-action/src/site/site.xml new file mode 100644 index 0000000..6c8144f --- /dev/null +++ b/trunk/jaxx-swing-action/src/site/site.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project name="${project.name}"> + + <bannerLeft> + <name>${project.name}</name> + <src>${site.home.url}/jaxx.png</src> + <href>index.html</href> + </bannerLeft> + + <body> + + <breadcrumbs> + <item name="${project.name}" href="${project.url}" /> + </breadcrumbs> + + <menu ref="parent"/> + + <menu name="Utilisateur" inherited="top"/> + + <menu ref="reports"/> + + <menu ref="modules"/> + + </body> +</project> diff --git a/trunk/maven-jaxx-plugin/LICENSE.txt b/trunk/maven-jaxx-plugin/LICENSE.txt new file mode 100644 index 0000000..3f7b8b1 --- /dev/null +++ b/trunk/maven-jaxx-plugin/LICENSE.txt @@ -0,0 +1,166 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/trunk/maven-jaxx-plugin/README.txt b/trunk/maven-jaxx-plugin/README.txt new file mode 100644 index 0000000..d2e50d3 --- /dev/null +++ b/trunk/maven-jaxx-plugin/README.txt @@ -0,0 +1,2 @@ +To deploy new version of pom: mvn deploy +To install localy: mvn install diff --git a/trunk/maven-jaxx-plugin/changelog.txt b/trunk/maven-jaxx-plugin/changelog.txt new file mode 100644 index 0000000..a177b80 --- /dev/null +++ b/trunk/maven-jaxx-plugin/changelog.txt @@ -0,0 +1,37 @@ +1.3 chemit 20090409 + * 20090327 [chemit] - add javax help mecanism + * 20090301 [chemit] - add a profile mode (-Djaxx.profile) + +1.2 letelier 2009022? + +1.1 chemit 20090220 + * 20090203 [chemit] - mojo's property src is now by default in src/main/java + * 20090202 [chemit] - introduce a property validatorClass to specify the validator implementation + * 20090124 [chemit] - introduce a flag useUIManagerForIcon to retreave icons from UIManager + - clean mojo getter and setter (not used here) + * 20090123 [chemit] - add tests for icon improvment + * 20090122 [chemit] - refactor poms (sibling dependencies, pluginsManagment,...) + - rename i18n bundles according artifactId + * 20090113 [chemit] - fix bug : when using addProjectClassPath property, sometimes does not retreave + dependancies, force it to work whatever is the phase :) + +1.0 chemit 20090111 + +0.8 chemit 200812?? + * 20081219 [chemit] - add addProjectClassPath property to add project compile class-path in plugin class-path + * 20081214 [chemit] - add addSourcesToClassPath property to add sources directories in class-path + +0.7 chemit 20081210 + * 20081208 [chemit] - javabBean attribute use to initialize bean + * 20081207 [chemit] use lutinproject 3.1 + +0.6 chemit 200811?? + * 20081108 [chemit] can add extra imports in JaxxGeneratorMojo (will be added to all generated java files). + * 20081104 [chemit] can add extra beanInfoSearchPath in JaxxGeneratorMojo + +0.5 chemit 20081002 + * 20081013 [chemit] can generate logger on jaxx files + * 20081011 [chemit] improve site + * 20081011 [chemit] refactor tests of the plugin using maven-plugin-testing-harness plugin + * 20081002 [chemit] Using lutinpluginproject 3.0, changing groupId to org.codelutin + * 20081002 [chemit] Make nearly all tests works again... diff --git a/trunk/maven-jaxx-plugin/pom.xml b/trunk/maven-jaxx-plugin/pom.xml new file mode 100644 index 0000000..e2964d7 --- /dev/null +++ b/trunk/maven-jaxx-plugin/pom.xml @@ -0,0 +1,143 @@ + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <!-- ************************************************************* --> + <!-- *** POM Relationships *************************************** --> + <!-- ************************************************************* --> + + <parent> + <groupId>org.nuiton</groupId> + <artifactId>jaxx</artifactId> + <version>1.7.1</version> + </parent> + + <groupId>org.nuiton.jaxx</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + + <dependencies> + + <!-- sibling dependencies --> + + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>jaxx-compiler</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>jaxx-swing-action</artifactId> + <version>${project.version}</version> + </dependency> + + <!-- maven plugin project dependencies --> + + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-plugin-api</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-project</artifactId> + </dependency> + + <!-- other dependencies --> + + <dependency> + <groupId>org.nuiton</groupId> + <artifactId>maven-helper-plugin</artifactId> + </dependency> + + <!-- pour acceder aux BeansInfos swing via Introspector --> + <dependency> + <groupId>com.sun</groupId> + <artifactId>dt</artifactId> + <!--version>${java.version}</version--> + <scope>system</scope> + <systemPath>/${java.home}/../lib/dt.jar</systemPath> + </dependency> + + <!-- tests dependencies --> + + <dependency> + <groupId>org.apache.maven.shared</groupId> + <artifactId>maven-plugin-testing-harness</artifactId> + <version>1.1</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.apache.maven.shared</groupId> + <artifactId>maven-verifier</artifactId> + <version>1.0</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.apache.velocity</groupId> + <artifactId>velocity</artifactId> + <version>1.5</version> + </dependency> + <dependency> + <groupId>commons-lang</groupId> + <artifactId>commons-lang</artifactId> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </dependency> + + <dependency> + <groupId>org.nuiton</groupId> + <artifactId>maven-helper-plugin</artifactId> + <classifier>tests</classifier> + </dependency> + + </dependencies> + + <!-- ************************************************************* --> + <!-- *** Project Information ************************************* --> + <!-- ************************************************************* --> + + <name>${project.artifactId}</name> + <description> + Maven 2 plugin to generate java source from ui interface definitions + in jaxx format. + </description> + + <!-- ************************************************************* --> + <!-- *** Build Settings ****************************************** --> + <!-- ************************************************************* --> + + <packaging>maven-plugin</packaging> + + <build> + <plugins> + + <plugin> + <artifactId>maven-plugin-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>helpmojo</goal> + </goals> + </execution> + </executions> + </plugin> + + </plugins> + </build> + + <reporting> + <plugins> + <plugin> + <artifactId>maven-plugin-plugin</artifactId> + </plugin> + </plugins> + </reporting> + +</project> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/main/java/org/nuiton/jaxx/AbstractJaxxMojo.java b/trunk/maven-jaxx-plugin/src/main/java/org/nuiton/jaxx/AbstractJaxxMojo.java new file mode 100644 index 0000000..fd4112c --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/main/java/org/nuiton/jaxx/AbstractJaxxMojo.java @@ -0,0 +1,170 @@ +/* *##% + * Copyright (C) 2007 + * JaxxPlugin, Code Lutin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *##%*/ +package org.nuiton.jaxx; + +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.project.MavenProject; + +import java.io.File; + +/** + * Abract Jaxx Mojo. + * + * @author chemit + * + * @since 1.3 + */ +public abstract class AbstractJaxxMojo extends AbstractMojo { + + /** + * Dépendance du projet. + * + * @parameter default-value="${project}" + * @required + * @readonly + */ + protected MavenProject project; + /** + * Repertoire de destination des fichiers java a generer. + * + * @parameter expression="${jaxx.outJava}" default-value="${basedir}/target/generated-sources/java" + */ + protected File outJava; + /** + * verbose flag + * + * @parameter expression="${jaxx.verbose}" default-value="false" + * + * @since 1.3 + */ + protected boolean verbose; + /** + * to make compiler i18nable, says add the {@link org.nuiton.i18n.I18n#_(String, Object[])} method + * invocation on {@link jaxx.compiler.I18nHelper#I18N_ATTRIBUTES} attributes. + * + * @parameter expression="${jaxx.i18nable}" default-value="true" + * @see jaxx.compiler.I18nHelper + */ + protected boolean i18nable; + /** + * The store of helpIds generated by {@link JaxxGeneratorMojo}. + * <p/> + * + * @parameter expression="${jaxx.helpIdStore}" default-value="target/helpIds.properties" + * @required + * + * @since 1.3 + */ + protected File helpIdStore; + /** + * The name of the helpset to generate. + * + * @parameter expression="${jaxx.helpSetName}" default-value="${project.artifactId}" + * @required + * + * @since 1.3 + */ + protected String helpSetName; + /** + * The prefix to add to i18n key for any help i18n key. + * + * @parameter expression="${jaxx.helpsetI18nPrefix}" default-value="${jaxx.helpSetName}.help." + * @required + * + * @since 1.3 + */ + protected String helpsetI18nPrefix; + /** + * The suffix to add to i18n key for an help Id. + * + * @parameter expression="${jaxx.helpsetTitleI18nSuffix}" default-value=".title" + * @required + * + * @since 1.3 + */ + protected String helpsetTitleI18nSuffix; + /** + * The suffix to add to i18n key for an toc Id. + * + * @parameter expression="${jaxx.helpsetTocI18nSuffix}" default-value=".toc" + * @required + * + * @since 1.3 + */ + protected String helpsetTocI18nSuffix; + /** + * The suffix to add to i18n key for an toc Id. + * + * @parameter expression="${jaxx.helpsetIndexI18nSuffix}" default-value=".index" + * @required + * + * @since 1.3 + */ + protected String helpsetIndexI18nSuffix; + protected boolean skip = true; + protected ClassLoader cl; + + public abstract void init() throws Exception; + + public abstract void doAction() throws Exception; + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + + try { + init(); + } catch (Exception e) { + if (e instanceof MojoFailureException) { + throw (MojoFailureException) e; + } + if (e instanceof MojoExecutionException) { + throw (MojoExecutionException) e; + } + throw new MojoExecutionException("error in init : " + e.getMessage(), e); + } + + if (skip) { + if (verbose) { + getLog().info("jaxx - skip!"); + } + return; + } + + try { + + doAction(); + + } catch (Exception e) { + //getLog().error(e); + Throwable e2 = e; + while (e2.getCause() != null) { + e2 = e.getCause(); + } + getLog().error(e2); + + throw new MojoExecutionException(e2.getMessage(), e2); + } finally { + System.gc(); + } + + } + +} \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/main/java/org/nuiton/jaxx/JaxxGeneratorMojo.java b/trunk/maven-jaxx-plugin/src/main/java/org/nuiton/jaxx/JaxxGeneratorMojo.java new file mode 100644 index 0000000..b837178 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/main/java/org/nuiton/jaxx/JaxxGeneratorMojo.java @@ -0,0 +1,652 @@ +/* *##% + * Copyright (C) 2007 + * JaxxPlugin, Code Lutin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *##%*/ +package org.nuiton.jaxx; + +import jaxx.beaninfos.BeanInfoUtil; +import jaxx.compiler.CompilerOptions; +import jaxx.compiler.JAXXCompiler; +import jaxx.compiler.JAXXCompilerLaunchor; +import jaxx.runtime.JAXXContext; +import jaxx.tags.TagManager; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.codehaus.plexus.util.DirectoryScanner; +import org.nuiton.util.FileUpdaterHelper; +import org.nuiton.util.MirroredFileUpdater; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; +import java.util.Set; +import jaxx.compiler.CompiledObjectDecorator; +import jaxx.compiler.HelpRootCompiledObjectDecorator; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.model.Resource; +import org.apache.maven.project.MavenProject; + +/** + * Classe permettant de transformer des sources jaxx vers du source java. + * + * @author chemit + * @goal generate + * @phase process-sources + * @requiresDependencyResolution compile + * @requiresProject + */ +public class JaxxGeneratorMojo extends AbstractJaxxMojo { + + /** + * Le compilateur à utiliser (par défaut celui de Swing) + * + * @parameter expression="${jaxx.compilerFQN}" default-value="jaxx.compiler.SwingCompiler" + */ + protected String compilerFQN; + /** + * Le compilateur à utiliser (par défaut celui de Swing) + * + * @parameter expression="${jaxx.validatorFQN}" default-value="jaxx.runtime.validator.swing.SwingValidator" + */ + protected String validatorFQN; + /** + * chemin du repertoire de generation des resources. + * + * @parameter expression="${jaxx.outResource}" default-value="${basedir}/target/generated-sources/resources" + */ + protected File outResource; + /** + * chemin du repertoire de compilation des resources. + * + * @parameter expression="${jaxx.outClass}" default-value="${basedir}/target/classes" + */ + protected File outClass; + /** + * Repertoire sources des fichiers jaxx a generer. + * + * @parameter expression="${jaxx.src}" default-value="${maven.src.dir}/main/java" + */ + protected File src; + /** + * pour optimizer le code compile ou genere ? + * + * @parameter expression="${jaxx.optimize}" default-value="false" + */ + protected boolean optimize; + /** + * les options de la compilation + * + * @parameter expression="${jaxx.javaOpts}" + */ + protected String javaOpts = null; + /** + * pour filter les fichiers a traiter + * + * @parameter expression="${jaxx.includes}" + */ + protected String[] includes; + /** + * pour filter les fichiers a ne pas traiter + * + * @parameter expression="${jaxx.excludes}" + */ + protected String[] excludes; + /** + * flag to include in compiler classpath the java sources directories (src and outJava). + * <p/> + * By default, false. + * + * @parameter expression="${jaxx.addSourcesToClassPath}" default-value="false" + */ + protected boolean addSourcesToClassPath; + /** + * flag to include in compiler classpath the java resources directories (src and outJava). + * <p/> + * By default, false. + * + * @parameter expression="${jaxx.addResourcesToClassPath}" default-value="false" + * @since 1.6.0 + */ + protected boolean addResourcesToClassPath; + /** + * flag to include in compiler classpath the compile class-path (can only be used in a test phase). + * <p/> + * By default, false. + * + * @parameter expression="${jaxx.addCompileClassPath}" default-value="false" + * @since 1.6.0 + */ + protected boolean addCompileClassPath; + /** + * flag to include in compiler classpath the project compile classpath. + * <p/> + * By default, false. + * + * @parameter expression="${jaxx.addProjectClassPath}" default-value="false" + */ + protected boolean addProjectClassPath; + /** + * to force generation of java source for any jaxx files with no timestamp checking. + * <p/> + * By default, never force generation. + * + * @parameter expression="${jaxx.force}" default-value="false" + */ + protected boolean force; + /** + * flag to add logger to each generated jaxx file. + * <p/> + * By default, always add it. + * + * @parameter expression="${jaxx.addLogger}" default-value="true" + */ + protected boolean addLogger; + /** + * flag to keep compilers after the generate operation (usefull for tests. + * <p/> + * By default, always reset. + * + * @parameter expression="${jaxx.resetAfterCompile}" default-value="true" + */ + protected boolean resetAfterCompile; + /** + * the name of implementation of {@link jaxx.runtime.JAXXContext} + * to be used on {@link jaxx.runtime.JAXXObject}. + * <p/> + * Must not be abstract. + * + * @parameter expression="${jaxx.jaxxContextImplementorClass}" default-value="jaxx.runtime.DefaultJAXXContext" + * @required + */ + protected String jaxxContextImplementorClass; + /** + * extra path to be added in {@link java.beans.Introspector#setBeanInfoSearchPath(String[])}. + * <p/> + * add beanInfoSearchPath to be registred by {@link BeanInfoUtil#addJaxxBeanInfoPath(String[])} + * <p/> + * and then will be use by {@link jaxx.tags.swing.SwingInitializer#initialize()}. + * <p/> + * <p/> + * This permit to use real beanInfo of imported graphic libraries. + * + * @parameter expression="${jaxx.beanInfoSearchPath}" + */ + protected String[] beanInfoSearchPath; + /** + * list of fqn of class toimport for all generated jaxx files + * + * @parameter expression="${jaxx.extraImports}" + * + * @deprecated Prefer use of extraImportList as a string, so + * could be use in properties section. + */ + protected String[] extraImports; + /** + * list of fqn of class toimport for all generated jaxx files + * + * @parameter expression="${jaxx.extraImportList}" + */ + protected String extraImportList; + /** + * the FQN of the ui to use for error notification. + * <p/> + * If not given, will use the one defined in validator + * + * @parameter expression="${jaxx.defaultErrorUIFQN}" + * @see jaxx.runtime.validator.swing.SwingValidator#DEFAULT_UI_CLASS + */ + protected String defaultErrorUIFQN; + /** + * the FQN of the ui to use for error notification. + * <p/> + * If not given, will use the one defined in validator + * + * @parameter expression="${jaxx.defaultDecorator}" default-value="jaxx.compiler.DefaultCompiledObjectDecorator" + * + * @see jaxx.compiler.CompiledObjectDecorator + */ + protected String defaultDecoratorFQN; + /** + * a flag to use UIManager to retreave icons. + * + * @parameter expression="${jaxx.useUIManagerForIcon}" default-value="false" + */ + protected boolean useUIManagerForIcon; + /** + * flag to activate profile mode. + * <p/> + * By default, not active. + * + * @parameter expression="${jaxx.profile}" default-value="false" + */ + protected boolean profile; + /** + * flag to activate help generation process. + * <p/> + * By default, not active. + * + * @parameter expression="${jaxx.generateHelp}" default-value="false" + * + * @since 1.3 + */ + protected boolean generateHelp; + /** + * the FQN of help broker + * <p/> + * By default, none. + * + * @parameter expression="${jaxx.helpBrokerFQN}" + * + * @since 1.3 + */ + protected String helpBrokerFQN; + /** + * A flag to mark themojo to be used in a test phase. This will permits to add generated sources in test compile roots. + * + * @parameter expression="${jaxx.testPhase}" default-value="false" + * @since 1.6.0 + */ + protected boolean testPhase; + protected String[] files; + private static final String[] INCLUDES = {"**\\/*.jaxx"}; + protected CompilerOptions options; + protected MirroredFileUpdater updater; + private Class<?> defaultErrorUIClass; + private Class<?> validatorClass; + private Class<? extends CompiledObjectDecorator> defaultDecoratorClass; + private Class<? extends JAXXCompiler> compilerClass; + + @SuppressWarnings("unchecked") + @Override + public void init() throws Exception { + + if (project != null && ("pom".equals(project.getPackaging()) || "site".equals(project.getPackaging()))) { + // nothing to be done for this type of packaging + skip = true; + getLog().info("skip generate goal for packaging " + project.getPackaging()); + return; + } + + if (generateHelp) { + // check there is some bundle + if (helpIdStore == null) { + throw new MojoFailureException("you must set the helpIdStore property."); + } + } + skip = false; + + checkJaxxContextImplementorClass(); + + if (beanInfoSearchPath != null && beanInfoSearchPath.length > 0) { + // register extra path + BeanInfoUtil.addJaxxBeanInfoPath(beanInfoSearchPath); + } + if (!outResource.exists()) { + outResource.mkdirs(); + } + + if (!outJava.exists()) { + outJava.mkdirs(); + } + + fixCompileSourceRoots(); + + if (addSourcesToClassPath || addProjectClassPath) { + cl = initClassLoader(project, getLog()); + Thread.currentThread().setContextClassLoader(cl); + } else { + cl = getClass().getClassLoader(); + //cl = Thread.currentThread().getContextClassLoader(); + } + + + compilerClass = (Class<? extends JAXXCompiler>) Class.forName(compilerFQN, false, cl); + defaultDecoratorClass = (Class<? extends CompiledObjectDecorator>) Class.forName(defaultDecoratorFQN, false, cl); + + // check the validator class is correct + validatorClass = Class.forName(validatorFQN, false, cl); + + if (defaultErrorUIFQN != null && !defaultErrorUIFQN.trim().isEmpty()) { + defaultErrorUIClass = Class.forName(defaultErrorUIFQN, false, cl); + } + + DirectoryScanner ds; + ds = new DirectoryScanner(); + ds.setBasedir(src); + boolean noIncludes = includes == null || includes.length == 0; + ds.setIncludes(noIncludes ? INCLUDES : includes); + + if (excludes != null && excludes.length > 0) { + ds.setExcludes(excludes); + } + + ds.scan(); + String[] filesFind = ds.getIncludedFiles(); + if (verbose) { + getLog().info("jaxx - discover " + filesFind.length + " jaxx file(s). "); + } + + updater = FileUpdaterHelper.newJaxxFileUpdater(src, outJava); + + if (force) { + // we will regenerate all files + this.files = filesFind; + } else { + // filter files + List<String> listFiles = new ArrayList<String>(); + + for (String file : filesFind) { + if (updater.isFileUpToDate(new File(src, file))) { + if (verbose) { + getLog().info("jaxx - skip file [" + file + "]."); + } + } else { + if (verbose) { + getLog().info("jaxx - detect modify file [" + file + "]."); + } + listFiles.add(file); + } + } + this.files = listFiles.toArray(new String[listFiles.size()]); + } + + if (extraImportList != null && !extraImportList.isEmpty()) { + String[] imports = extraImportList.split(","); + int i = 0; + for (String importS : imports) { + imports[i++] = importS.trim(); + } + if (verbose) { + getLog().info("extra imports " + java.util.Arrays.toString(imports)); + } + extraImports = imports; + + } + options = toCompilerOptions(); + + if (verbose) { + printInit(); + } + + } + + @Override + public void doAction() throws MojoExecutionException { + getLog().info("jaxx - detects " + this.files.length + " modify jaxx file(s). "); + + try { + + // force compiler init from here, not in a static block + TagManager.reset(verbose); + + JAXXCompilerLaunchor launchor = JAXXCompilerLaunchor.newLaunchor(src, files, options); + boolean success = launchor.compile(); + getLog().info("jaxx - generate " + launchor.getCompilerCount() + " file(s). "); + + if (!success) { + throw new MojoExecutionException("Aborting due to errors reported by jaxxc"); + } + + if (generateHelp) { + // generate help + generateHelp(); + } + + } catch (MojoExecutionException e) { + getLog().error(e); + throw e; + } catch (Exception e) { + //getLog().error(e); + Throwable e2 = e; + while (e2.getCause() != null) { + e2 = e.getCause(); + } + getLog().error(e2); + + throw new MojoExecutionException(e2.getMessage(), e2); + } + } + + public CompilerOptions toCompilerOptions() { + CompilerOptions result = new CompilerOptions(); + result.setClassPath(src.getPath()); + if (javaOpts != null && !"".equals(javaOpts)) { + result.setJavacOpts(javaOpts); + } + result.setCompilerClass(compilerClass); + result.setValidatorFQN(validatorFQN); + result.setValidatorClass(validatorClass); + result.setKeepJavaFiles(true); + result.setOptimize(optimize); + result.setJavacTargetDirectory(outClass); + result.setTargetDirectory(outJava); + result.setVerbose(verbose); + result.setI18nable(i18nable); + result.setAddLogger(addLogger); + result.setProfile(profile); + result.setResetAfterCompile(resetAfterCompile); + result.setJaxxContextImplementorClass(jaxxContextImplementorClass); + result.setExtraImports(extraImports); + result.setDefaultErrorUI(defaultErrorUIClass); + result.setUseUIManagerForIcon(useUIManagerForIcon); + result.setDefaultDecoratorClass(defaultDecoratorClass); + result.setGenerateHelp(generateHelp); + result.setHelpBrokerFQN(helpBrokerFQN); + result.setHelpsetTitleI18nSuffix(helpsetTitleI18nSuffix); + result.setHelpsetIndexI18nSuffix(helpsetIndexI18nSuffix); + result.setHelpsetTocI18nSuffix(helpsetTocI18nSuffix); + result.setHelpSetName(helpSetName); + result.setHelpsetI18nPrefix(helpsetI18nPrefix); + + if (cl != null) { + result.setClassLoader(cl); + } + return result; + } + + protected void fixCompileSourceRoots() { +// //fixme should remove this silly test when we will make real maven plugin tests :) +// if (project != null) { +// if (!project.getCompileSourceRoots().contains(outJava.getPath())) { +// project.addCompileSourceRoot(outJava.getPath()); +// } +// } + if (project == null) { + // no project defined, can not fix anything + // this case could appears if we wanted to do some tests of the plugin + return; + } + + if (testPhase) { + if (!project.getTestCompileSourceRoots().contains( + outJava.getPath())) { + getLog().info("Add test compile source root : " + outJava); + project.addTestCompileSourceRoot(outJava.getPath()); + } + } else { + if (!project.getCompileSourceRoots().contains(outJava.getPath())) { + getLog().info("Add compile source root : " + outJava); + project.addCompileSourceRoot(outJava.getPath()); + } + } + } + + protected void printInit() { + getLog().info(options.toString()); + getLog().info("includes : " + Arrays.toString(includes)); + for (String file : files) { + getLog().info("will generate " + file); + } + + ClassLoader threadLoader = Thread.currentThread().getContextClassLoader(); + getLog().info(threadLoader.toString()); + if (threadLoader.getClass().getSimpleName().equals("RealmClassLoader")) { + try { + java.lang.reflect.Method m = threadLoader.getClass().getDeclaredMethod("getURLs"); + m.setAccessible(true); + URL[] urls = (URL[]) m.invoke(threadLoader); + + for (URL url : urls) { + getLog().info("url in class loader " + url); + } + } catch (Exception e) { + getLog().warn("??? : " + e.getMessage(), e); + } + } + + //fixme should remove this silly test when we will make real maven plugin tests :) + if (getPluginContext() != null) { + for (Object e : getPluginContext().keySet()) { + getLog().info("pluginContext " + e + " : " + getPluginContext().get(e)); + } + } + } + + protected void checkJaxxContextImplementorClass() { + if (jaxxContextImplementorClass == null) { + throw new IllegalArgumentException("jaxxContextImplementor can not be null"); + } + try { + Class<?> jaxxContextImplementor = Class.forName(jaxxContextImplementorClass); + if (!JAXXContext.class.isAssignableFrom(jaxxContextImplementor)) { + throw new IllegalArgumentException("jaxxContextImplementor '" + jaxxContextImplementor + "' does not implements " + JAXXContext.class); + } + if (Modifier.isAbstract(jaxxContextImplementor.getModifiers())) { + throw new IllegalArgumentException("jaxxContextImplementor '" + jaxxContextImplementor + "' can not be abstract."); + + } + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("could not find jaxxContextImplementor class : " + jaxxContextImplementorClass); + } + } + + protected void generateHelp() throws IOException { + Set<String> helpIds = HelpRootCompiledObjectDecorator.getHelpIds(); + if (helpIds.isEmpty()) { + if (verbose) { + // no ids detected in this compilation round + getLog().info("no helpIds detected."); + } + return; + } + + if (!helpIdStore.getParentFile().exists()) { + helpIdStore.getParentFile().mkdirs(); + } + + Properties p = new Properties(); + + for (String helpId : helpIds) { + String path = helpId.replaceAll("\\.", File.separator); + path = removeQuote(path) + ".html"; + p.put(removeQuote(helpId), path); + } + + FileOutputStream w = new FileOutputStream(helpIdStore); + + try { + p.store(w, null); + } finally { + w.close(); + } + + getLog().info("helpIdStore generated in " + helpIdStore); + + helpIds.clear(); + } + + @SuppressWarnings({"unchecked"}) + protected URLClassLoader initClassLoader(MavenProject project, org.apache.maven.plugin.logging.Log log) throws MalformedURLException { + URLClassLoader loader = null; + if (project != null) { + + URLClassLoader result; + try { + + List<URL> lUrls = new ArrayList<URL>(); + List<String> sources = project.getCompileSourceRoots(); + + if (addSourcesToClassPath) { + for (String source : sources) { + lUrls.add(new File(source).toURI().toURL()); + } + if (testPhase) { + for (Object source : project.getTestCompileSourceRoots()) { + lUrls.add(new File(source.toString()).toURI().toURL()); + } + } + } + if (addResourcesToClassPath) { + for (Object source : project.getResources()) { + Resource r = (Resource) source; + lUrls.add(new File(r.getDirectory()).toURI().toURL()); + } + } + if (testPhase && addCompileClassPath) { + if (project != null) { + lUrls.add(new File(project.getBuild().getOutputDirectory()).toURI().toURL()); + } + } + if (addProjectClassPath) { + getLog().info("use project compile scope class-path"); + // add also all dependencies of the project in compile scope + Set<?> artifacts = project.getArtifacts(); + for (Object o : artifacts) { + Artifact a = (Artifact) o; + lUrls.add(a.getFile().toURI().toURL()); + } + } + + result = new URLClassLoader(lUrls.toArray(new URL[lUrls.size()]), getClass().getClassLoader()); + + } catch (IOException e) { + throw new RuntimeException("Can't create ClassLoader for reason " + e.getMessage(), e); + } + loader = result; + } else { + List<URL> lUrls = new ArrayList<URL>(); + if (addSourcesToClassPath) { + lUrls.add(src.toURI().toURL()); + } + loader = new URLClassLoader(lUrls.toArray(new URL[lUrls.size()]), getClass().getClassLoader()); + } + if (verbose) { + for (URL entry : loader.getURLs()) { + log.info("classpath : " + entry); + } + } + return loader; + } + + protected String removeQuote(String txt) { + if (txt.startsWith("\"")) { + txt = txt.substring(1); + } + if (txt.endsWith("\"")) { + txt = txt.substring(0, txt.length() - 1); + } + return txt; + } +} diff --git a/trunk/maven-jaxx-plugin/src/main/java/org/nuiton/jaxx/JaxxHelpGeneratorMojo.java b/trunk/maven-jaxx-plugin/src/main/java/org/nuiton/jaxx/JaxxHelpGeneratorMojo.java new file mode 100644 index 0000000..490ed65 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/main/java/org/nuiton/jaxx/JaxxHelpGeneratorMojo.java @@ -0,0 +1,792 @@ +/* *##% + * Copyright (C) 2007 + * JaxxPlugin, Code Lutin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *##%*/ +package org.nuiton.jaxx; + +import org.apache.maven.plugin.MojoFailureException; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Enumeration; +import java.util.List; +import java.util.Properties; +import java.util.Set; +import java.util.Stack; +import org.apache.maven.model.Resource; +import org.nuiton.i18n.I18n; +import org.nuiton.util.FileUtil; +import org.nuiton.util.SortedProperties; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLReaderFactory; +import static org.nuiton.i18n.I18n._; + +/** + * Mojo to generate javax help stuff for your project. + * + * HelpIds should have been discovered by the JaxxMojo. + * + * @author chemit + * @goal generate-help + * @phase process-sources + * + * @requiresProject + * @requiresDependencyResolution compile + * @since 1.3 + */ +public class JaxxHelpGeneratorMojo extends AbstractJaxxMojo { + + /** + * The directory where to generate javaHelp skeleton files. + * <p/> + * Is required if generateHelp is on. + * + * @parameter expression="${jaxx.helpTarget}" alias="target" default-value="${maven.src.dir}/main/help" + * @required + * + * @since 1.3 + */ + protected File target; + /** + * The locale to generate for help. + * + * By default, stay in France. + * + * @parameter expression="${jaxx.locale}" default-value="fr" + * @required + * + * @since 1.3 + */ + protected String locale; + /** + * The package where to generate i18n java file. + * + * @parameter expression="${jaxx.packageName}" default-value="${project.groupId}" + * @required + * + * @since 1.3 + */ + protected String packageName; + /** + * The file name of the helpset to generate. + * + * @parameter expression="${jaxx.helpSetFileName}" default-value="${jaxx.helpSetName}.hs" + * @required + * + * @since 1.3 + */ + protected String helpsetFileName; + /** + * The file name of the helpset map to generate. + * + * @parameter expression="${jaxx.mapFileName}" default-value="${jaxx.helpSetName}Map.jhm" + * @required + * + * @since 1.3 + */ + protected String mapFileName; + /** + * The file name of the helpset index to generate. + * + * @parameter expression="${jaxx.indexFileName}" default-value="${jaxx.helpSetName}Index.xml" + * @required + * + * @since 1.3 + */ + protected String indexFileName; + /** + * The file name of the helpset toc to generate. + * + * @parameter expression="${jaxx.tocFileName}" default-value="${jaxx.helpSetName}TOC.xml" + * @required + * + * @since 1.3 + */ + protected String tocFileName; + /** + * The file name of the i18n java file to generate. + * + * @parameter expression="${jaxx.i8nFileName}" default-value="${jaxx.helpSetName}I18n.java" + * @required + * + * @since 1.3 + */ + protected String i8nFileName; + /** + * The template used to generate helpset file. + * + * Must be an existing file or a ressource in classp-ath + * + * @parameter expression="${jaxx.helpSetTemplate}" default-value="/defaultHelpSet.hs.vm" + * @required + * + * @since 1.3 + */ + protected File helpSetTemplate; + /** + * The template used to generate helpset map file. + * + * Must be an existing file or a ressource in classp-ath + * + * @parameter expression="${jaxx.mapTemplate}" default-value="/defaultMap.jhm.vm" + * @required + * + * @since 1.3 + */ + protected File mapTemplate; + /** + * The template used to generate helpset index file. + * + * Must be an existing file or a ressource in classp-ath + * + * @parameter expression="${jaxx.indexTemplate}" default-value="/defaultIndex.xml.vm" + * @required + * + * @since 1.3 + */ + protected File indexTemplate; + /** + * The template used to generate helpset toc file. + * + * Must be an existing file or a ressource in classp-ath + * + * @parameter expression="${jaxx.tocTemplate}" default-value="/defaultToc.xml.vm" + * @required + * + * @since 1.3 + */ + protected File tocTemplate; + /** + * The template used to generate helpset content file. + * + * Must be an existing file or a ressource in classp-ath + * + * @parameter expression="${jaxx.contentTemplate}" default-value="/defaultContent.html.vm" + * @required + * + * @since 1.3 + */ + protected File contentTemplate; + /** + * The template used to generate helpset content file. + * + * Must be an existing file or a ressource in classp-ath + * + * @parameter expression="${jaxx.i18nTemplate}" default-value="/defaultI18n.java.vm" + * @required + * + * @since 1.3 + */ + protected File i18nTemplate; + /** + * The help ids discovered by Jaxx compilation + */ + protected Properties helpIds; + private static final String AUTOREMOVE_LINE = "REMOVE THS LINE TO DISABLE AUTO-REGENERATE THE FILE"; + + @Override + public void init() throws Exception { + + if (project != null && ("pom".equals(project.getPackaging()) || "site".equals(project.getPackaging()))) { + // nothing to be done for this type of packaging + skip = true; + getLog().info("skip generate goal for packaging " + project.getPackaging()); + return; + } + + if (!helpIdStore.exists()) { + skip = true; + getLog().info("no helpIdStore to react at " + helpIdStore); + return; + } + + // check there is some bundle + if (locale == null) { + throw new MojoFailureException("you must set the bundles property."); + } + // check there is some bundle + if (target == null) { + throw new MojoFailureException("you must set the target property."); + } + // check ressources + checkResource(helpSetTemplate); + checkResource(mapTemplate); + checkResource(indexTemplate); + checkResource(tocTemplate); + checkResource(contentTemplate); + + if (!target.exists()) { + getLog().info("mkdir " + target); + target.mkdirs(); + } + + + helpIds = new SortedProperties(); + + InputStream stream = new FileInputStream(helpIdStore); + + helpIds.load(stream); + + stream.close(); + + if (helpIds.isEmpty()) { + + // no ids detected + getLog().warn("no helpIds detected, will skip."); + skip = true; + return; + } + + skip = false; + } + + @Override + public void doAction() throws Exception { + + if (i18nable) { + + List<URL> lUrls = new java.util.ArrayList<URL>(); + List resources = project.getResources(); + for (Object o : resources) { + Resource resource = (Resource) o; + lUrls.add(new File(resource.getDirectory()).toURI().toURL()); + } + I18n.setExtraURL(lUrls.toArray(new URL[lUrls.size()])); + I18n.init(locale, null); + } + + File file; + + Properties env = new Properties(); + + env.put("helpSetName", helpSetName); + env.put("helpSetFileName", helpsetFileName); + env.put("mapFileName", mapFileName); + env.put("indexFileName", indexFileName); + env.put("tocFileName", tocFileName); + env.put("separator", " "); + env.put("autoremoveLine", AUTOREMOVE_LINE); + + + int touchedFiles = 0; + + // --------------------------------------------------------------- + // --- main helpset file ----------------------------------------- + // --------------------------------------------------------------- + + + file = new File(target, helpsetFileName); + + boolean doCreate = generateHelSetFile(file, env); + + if (doCreate) { + touchedFiles++; + } + + // --------------------------------------------------------------- + // --- helpset map file ------------------------------------------ + // --------------------------------------------------------------- + + file = new File(target, mapFileName); + + Properties mergedHelpIds = generateMapFile(file, env); + touchedFiles++; + + // --------------------------------------------------------------- + // --- helpset index file ---------------------------------------- + // --------------------------------------------------------------- + + file = new File(target, indexFileName); + + NodeItem indexRootItem = generateIndexFile(file, env); + touchedFiles++; + + // --------------------------------------------------------------- + // --- helpset toc file ------------------------------------------ + // --------------------------------------------------------------- + + file = new File(target, tocFileName); + + NodeItem tocRootItem = generateTocFile(file, env); + touchedFiles++; + + // --------------------------------------------------------------- + // --- helpset content files ------------------------------------- + // --------------------------------------------------------------- + + TemplateGenerator gen = prepareGenerator(contentTemplate); + + Enumeration keys = helpIds.keys(); + + while (keys.hasMoreElements()) { + String key = (String) keys.nextElement(); + String url = (String) helpIds.get(key); + url = helpSetName + File.separator + url; + + File f = new File(target, url); + + boolean exist = f.exists(); + + if (exist) { + // check if there is a autoremoveLine in content + String content = FileUtil.readAsString(f); + if (!content.contains(AUTOREMOVE_LINE)) { + // no regenerate marker detected, so skip this file + if (verbose) { + getLog().debug("skip existing file " + f); + } + continue; + } + } + + f.getParentFile().mkdirs(); + + if (verbose) { + if (exist) { + getLog().info("regenerate content file " + f); + } else { + getLog().info("generate content file " + f); + } + } + + env.put("helpId", key); + String i18n = helpsetI18nPrefix + key + helpsetTitleI18nSuffix; + env.put("helpIdTitle", _(i18n)); + env.put("helpIdUrl", url); + + gen.generate(env, f); + touchedFiles++; + } + + // --------------------------------------------------------------- + // --- i18n file ------------------------------------------------- + // --------------------------------------------------------------- + + String path = packageName.replaceAll("\\.", File.separator); + path += File.separator + i8nFileName; + file = new File(outJava, path); + generateI18nFile(file, env, mergedHelpIds, indexRootItem, tocRootItem); + touchedFiles++; + + getLog().info(touchedFiles + " file(s) treated."); + } + + protected void generateI18nFile(File file, Properties env, Properties mergedHelpIds, NodeItem indexRootItem, NodeItem tocRootItem) throws Exception { + + boolean create = !file.exists(); + + if (!file.getParentFile().exists()) { + file.getParentFile().mkdirs(); + } + + Set<String> keys = new java.util.HashSet<String>(); + + for (Object k : mergedHelpIds.keySet()) { + String key = helpsetI18nPrefix + k + helpsetTitleI18nSuffix; + keys.add(key); + } + indexRootItem.extractI18n(keys, helpsetI18nPrefix, helpsetIndexI18nSuffix); + tocRootItem.extractI18n(keys, helpsetI18nPrefix, helpsetTocI18nSuffix); + + env.put("keys", keys); + env.put("packageName", packageName); + String className = file.getName(); + int index = className.lastIndexOf("."); + className = className.substring(0, index); + env.put("className", className); + + if (verbose) { + if (create) { + getLog().info("generate i18n java file " + file); + } else { + getLog().info("udpate i18n java file " + file); + } + } + + doGen(i18nTemplate, file, env); + + } + + protected boolean generateHelSetFile(File file, Properties env) throws Exception { + + if (file.exists()) { + // check the auto removeline presence + String content = FileUtil.readAsString(file); + if (!content.contains(AUTOREMOVE_LINE)) { + // no regenerate marker detected, so skip this file + if (verbose) { + getLog().info("skip existing helpset main file " + file); + } + return false; + } + } + + if (verbose) { + if (file.exists()) { + getLog().info("regenerate helpset main file " + file); + } else { + getLog().info("generate helpset main file " + file); + } + } + doGen(helpSetTemplate, file, env); + return true; + } + + protected Properties generateMapFile(File file, Properties env) throws Exception { + + boolean create; + + Properties mergedHelpIds = null; + if (file.exists()) { + + // get back the exisiting data and merge it with incoming ones + + if (verbose) { + getLog().info("loading existing helpset map file " + file); + } + + mergedHelpIds = getExistingHelpIds(file); + create = false; + + } else { + + mergedHelpIds = new SortedProperties(); + create = true; + } + + // inject new helpIds + + for (Object k : helpIds.keySet()) { + mergedHelpIds.put(k, helpSetName + "/" + helpIds.get(k)); + } + + if (!mergedHelpIds.contains("top")) { + // on ajoute une entree vers le root du helpset + + String topUrl = helpSetName + ".html"; + helpIds.put("top", topUrl); + mergedHelpIds.put("top", helpSetName + "/" + topUrl); + if (verbose) { + getLog().debug("add top entry with url " + topUrl); + } + } + + if (verbose) { + if (create) { + getLog().info("generate helpset map file " + file); + } else { + getLog().info("udpate helpset map file " + file); + } + } + + env.put("helpIds", mergedHelpIds); + doGen(mapTemplate, file, env); + env.remove("helpIds"); + return mergedHelpIds; + } + + protected NodeItem generateIndexFile(File file, Properties env) throws Exception { + NodeItem rootItem = null; + + boolean create; + + if (file.exists()) { + + create = false; + + rootItem = getExistingItems("indexitem", file); + } else { + create = true; + } + + if (rootItem == null) { + rootItem = new NodeItem("top", helpSetName); + } + + // inject new index entries + + for (Object k : helpIds.keySet()) { + NodeItem toc = rootItem.findChild(k + ""); + if (verbose) { + getLog().debug("index " + k + " : " + toc); + } + } + + //String prefix = helpsetI18nPrefix; + //String prefix = helpsetI18nPrefix + helpSetName + "."; + rootItem.applyI18n(helpsetI18nPrefix, helpsetIndexI18nSuffix); + + if (verbose) { + if (create) { + getLog().info("generate helpset index file " + file); + } else { + getLog().info("udpate helpset index file " + file); + } + } + + env.put("rootItem", rootItem); + doGen(indexTemplate, file, env); + env.remove("rootItem"); + return rootItem; + } + + protected NodeItem generateTocFile(File file, Properties env) throws Exception { + NodeItem rootItem = null; + + boolean create; + + if (file.exists()) { + + create = false; + + rootItem = getExistingItems("tocitem", file); + } else { + create = true; + } + + if (rootItem == null) { + rootItem = new NodeItem("top", helpSetName); + } + // inject new toc entries + + for (Object k : helpIds.keySet()) { + NodeItem toc = rootItem.findChild(k + ""); + if (verbose) { + getLog().debug("toc " + k + " : " + toc); + } + } + + //String prefix = helpsetI18nPrefix + helpSetName + "."; + rootItem.applyI18n(helpsetI18nPrefix, helpsetTocI18nSuffix); + + if (verbose) { + if (create) { + getLog().info("generate helpset toc file " + file); + } else { + getLog().info("udpate helpset toc file " + file); + } + } + + env.put("rootItem", rootItem); + doGen(tocTemplate, file, env); + env.remove("rootItem"); + return rootItem; + } + + protected void doGen(File template, File f, Properties env) throws Exception { + TemplateGenerator gen = prepareGenerator(template); + gen.generate(env, f); + } + + protected TemplateGenerator prepareGenerator(File template) throws Exception { + URL templateURL = getTemplate(template); + + if (verbose) { + getLog().info("using template " + templateURL); + } + TemplateGenerator gen = new TemplateGenerator(project, templateURL); + return gen; + } + + protected URL getTemplate(File f) throws IOException { + URL r = null; + InputStream s = null; + if (f.exists()) { + r = f.toURI().toURL(); + } else { + r = getClass().getResource(f.toString()); + } + return r; + } + + protected void checkResource(File f) throws MojoFailureException { + if (!f.exists()) { + // test in classPath + InputStream r = getClass().getResourceAsStream(f.toString()); + if (r == null) { + throw new MojoFailureException("could not find ressource " + f); + } + } + } + + protected Properties getExistingHelpIds(File file) throws SAXException, IOException { + + final Properties result = new SortedProperties(); + + XMLReader parser = XMLReaderFactory.createXMLReader(); + + parser.setContentHandler(new ContentHandlerAdapter() { + + String target; + String url; + + @Override + public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { + if ("mapID".equals(localName)) { + target = atts.getValue("target"); + url = atts.getValue("url"); + if (verbose) { + getLog().debug("detect map entry : " + target + " : " + url); + } + result.put(target, url); + } + } + }); + + InputStream s = new FileInputStream(file); + try { + parser.parse(new InputSource(s)); + } finally { + s.close(); + } + return result; + } + + protected NodeItem getExistingItems(String tagName, File file) throws SAXException, IOException { + + XMLReader parser = XMLReaderFactory.createXMLReader(); + NodeItemHandler handler = new NodeItemHandler(tagName); + + parser.setContentHandler(handler); + + NodeItem rootItem = null; + InputStream s = new FileInputStream(file); + try { + parser.parse(new InputSource(s)); + rootItem = handler.rootItem; + } finally { + s.close(); + } + return rootItem; + } + + static class NodeItemHandler extends ContentHandlerAdapter { + + NodeItem rootItem; + NodeItem currentItem; + final Stack<NodeItem> stack; + final String tagName; + + public NodeItemHandler(String tagName) { + this.tagName = tagName; + this.stack = new Stack<NodeItem>(); + } + + @Override + public void startDocument() throws SAXException { + rootItem = new NodeItem("top", null); + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { + if (tagName.equals(localName)) { + + String target = atts.getValue("target"); + String text = atts.getValue("text"); + + // debut d'un item + if (currentItem == null) { + // premier item + if (rootItem.getTarget().equals(target)) { + // le premier item est bien top + //rootItem.setText(text); + currentItem = rootItem; + } else { + // le premier noeud n'est pas top + // en l'encapsule + stack.push(rootItem); + currentItem = new NodeItem(target, text); + rootItem.addChild(currentItem); + } + } else { + NodeItem newItem = new NodeItem(target, text); + currentItem.addChild(newItem); + currentItem = newItem; + } + currentItem.adjustTarget(); + stack.push(currentItem); + + } + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + if (tagName.equals(localName)) { + // fin d'un item + stack.pop(); + if (!stack.isEmpty()) { + currentItem = stack.peek(); + } + } + } + } + + static class ContentHandlerAdapter implements ContentHandler { + + @Override + public void setDocumentLocator(Locator locator) { + } + + @Override + public void startDocument() throws SAXException { + } + + @Override + public void endDocument() throws SAXException { + } + + @Override + public void startPrefixMapping(String prefix, String uri) throws SAXException { + } + + @Override + public void endPrefixMapping(String prefix) throws SAXException { + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + } + + @Override + public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { + } + + @Override + public void processingInstruction(String target, String data) throws SAXException { + } + + @Override + public void skippedEntity(String name) throws SAXException { + } + } +} \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/main/java/org/nuiton/jaxx/NodeItem.java b/trunk/maven-jaxx-plugin/src/main/java/org/nuiton/jaxx/NodeItem.java new file mode 100644 index 0000000..0ccb694 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/main/java/org/nuiton/jaxx/NodeItem.java @@ -0,0 +1,137 @@ +package org.nuiton.jaxx; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import static org.nuiton.i18n.I18n._; + +public class NodeItem { + + String absoluteTarget; + private String target; + private String text; + private List<NodeItem> childs; + + public NodeItem(String target, String text) { + this.target = target; + this.absoluteTarget = target; + + this.text = text; + } + + public String getTarget() { + return target; + } + + public String getAbsoluteTarget() { + return absoluteTarget; + } + + public String getText() { + return text; + } + + public List<NodeItem> getChilds() { + return childs; + } + + public NodeItem findChild(String path) { + NodeItem result = null; + String[] paths = path.split("\\."); + for (int i = 0, j = paths.length; i < j; i++) { + String p = paths[i]; + if (result == null) { + + // first node + if (target.equals(p)) { + result = this; + continue; + } + result = getChild(p); + if (result == null) { + result = new NodeItem(p, null); + addChild(result); + adjutsAbsoluteTarget(result); + } + continue; + } + NodeItem child = result.getChild(p); + if (child == null) { + child = new NodeItem(p, null); + result.addChild(child); + result.adjutsAbsoluteTarget(child); + result = child; + } else { + result = child; + } + } + return result; + } + + public NodeItem getChild(int index) { + return childs.get(index); + } + + public NodeItem getChild(String target) { + if (isLeaf()) { + return null; + } + for (NodeItem i : childs) { + if (i.target.equals(target)) { + return i; + } + } + return null; + } + + public void addChild(NodeItem child) { + if (childs == null) { + childs = new ArrayList<NodeItem>(); + } + + childs.add(child); + } + + public void adjutsAbsoluteTarget(NodeItem child) { + if (!"top".equals(target)) { + // on ne prefixe pas les fils direct du root + child.absoluteTarget = absoluteTarget + "." + child.target; + } + } + + public void adjustTarget() { + int index = target.lastIndexOf("."); + if (index > -1) { + target = target.substring(index + 1); + } + } + + public boolean isLeaf() { + return childs == null || childs.isEmpty(); + } + + public void applyI18n(String prefix, String suffix) { + String key = prefix + getAbsoluteTarget() + suffix; + text = _(key); + if (!isLeaf()) { + for (NodeItem i : getChilds()) { + i.applyI18n(prefix, suffix); + } + } + } + + public void extractI18n(Set<String> keys, String prefix, String suffix) { + String key = prefix + getAbsoluteTarget() + suffix; + keys.add(key); + if (!isLeaf()) { + for (NodeItem i : getChilds()) { + i.extractI18n(keys, prefix, suffix); + } + } + } + + @Override + public String toString() { + return super.toString() + "<target:" + target + ", text:" + text + ", nbChilds:" + (isLeaf() ? 0 : childs.size()) + ">"; + } +} diff --git a/trunk/maven-jaxx-plugin/src/main/java/org/nuiton/jaxx/TemplateGenerator.java b/trunk/maven-jaxx-plugin/src/main/java/org/nuiton/jaxx/TemplateGenerator.java new file mode 100644 index 0000000..cd954c0 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/main/java/org/nuiton/jaxx/TemplateGenerator.java @@ -0,0 +1,142 @@ +/* + * Copyright 2001-2005 The Apache Software Foundation. + * + * 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. + */ +package org.nuiton.jaxx; + +import java.io.File; +import java.io.FileWriter; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Iterator; +import java.util.Properties; + +import org.apache.maven.project.MavenProject; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; + +/** + * Generator of template base on velocity. + * + * @author chemit + * @since 1.3 + * + */ +public class TemplateGenerator { + + protected VelocityEngine engine; + protected final MavenProject mavenProject; + protected Template velocityTemplate; + + protected TemplateGenerator(MavenProject mavenProject, URL template) throws URISyntaxException { + + if (mavenProject == null) { + throw new IllegalArgumentException("mavenProject must not be null"); + } + + if (template == null) { + throw new IllegalArgumentException("template must not be null"); + } + + this.mavenProject = mavenProject; + + Properties props = new Properties(); + + String templateName; + + if (template.toURI().isOpaque()) { + + // template is in a jar + + props = new Properties(); + props.setProperty("resource.loader", "jar"); + props.setProperty("jar.resource.loader.description", "Jar resource loader for default webstart templates"); + props.setProperty("jar.resource.loader.class", "org.apache.velocity.runtime.resource.loader.JarResourceLoader"); + + // obtain the jar url + + String url = template.toString(); + int i = url.indexOf("!"); + templateName = url.substring(i + 2); + + props.setProperty("jar.resource.loader.path", url.substring(0, i + 2)); + + } else { + + + templateName = new File(template.getFile()).getName(); + + //props.setProperty(VelocityEngine.RUNTIME_LOG_LOGSYSTEM_CLASS, "org.apache.velocity.runtime.log.NullLogSystem"); + props.setProperty("file.resource.loader.path", template.getFile()); + + } + + try { + engine = new VelocityEngine(); + //engine.setProperty("runtime.log.logsystem", new NullLogSystem()); + engine.init(props); + } catch (Exception e) { + IllegalArgumentException iae = new IllegalArgumentException("Could not initialise Velocity"); + iae.initCause(e); + throw iae; + } + + try { + this.velocityTemplate = engine.getTemplate(templateName); + } catch (Exception e) { + IllegalArgumentException iae = + new IllegalArgumentException("Could not load the template file from '" + template + "'"); + iae.initCause(e); + throw iae; + } + } + + public void generate(Properties context, File outputFile) throws Exception { + + + VelocityContext vcontext = new VelocityContext(); + + // Note: properties that contain dots will not be properly parsed by Velocity. Should we replace dots with underscores ? + addPropertiesToContext(System.getProperties(), vcontext); + + addPropertiesToContext(mavenProject.getProperties(), vcontext); + addPropertiesToContext(context, vcontext); + + vcontext.put("project", mavenProject.getModel()); + + vcontext.put("outputFile", outputFile.getName()); + + FileWriter writer = new FileWriter(outputFile); + + try { + velocityTemplate.merge(vcontext, writer); + writer.flush(); + } catch (Exception e) { + throw new Exception("Could not generate the template " + velocityTemplate.getName() + ": " + e.getMessage(), e); + } finally { + writer.close(); + } + } + + protected void addPropertiesToContext(Properties properties, VelocityContext context) { + + for (Iterator iter = properties.keySet().iterator(); iter.hasNext();) { + String key = (String) iter.next(); + Object value = properties.get(key); + context.put(key, value); + } + + } +} diff --git a/trunk/maven-jaxx-plugin/src/main/resources/defaultContent.html.vm b/trunk/maven-jaxx-plugin/src/main/resources/defaultContent.html.vm new file mode 100644 index 0000000..584c595 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/main/resources/defaultContent.html.vm @@ -0,0 +1,14 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"> +<HTML> +<HEAD> +<TITLE> +$helpIdTitle +</TITLE> +</HEAD> +<BODY BGCOLOR="#ffffff"> +<H1>$helpIdTitle</H1> + +<!-- $autoremoveLine --> + +</BODY> +</HTML> diff --git a/trunk/maven-jaxx-plugin/src/main/resources/defaultHelpSet.hs.vm b/trunk/maven-jaxx-plugin/src/main/resources/defaultHelpSet.hs.vm new file mode 100644 index 0000000..582797c --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/main/resources/defaultHelpSet.hs.vm @@ -0,0 +1,44 @@ +<?xml version='1.0' encoding='UTF-8' ?> +<!DOCTYPE helpset + PUBLIC "-//Sun Microsystems Inc.//DTD JavaHelp HelpSet Version 1.0//EN" + "http://java.sun.com/products/javahelp/helpset_1_0.dtd"> + +<helpset version="1.0"> + + <!-- $autoremoveLine --> + + <!-- title --> + <title>${helpSetTitle}</title> + + <!-- maps --> + <maps> + <homeID>top</homeID> + <mapref location="$mapFileName"/> + </maps> + + <!-- views --> + <view> + <name>TOC</name> + <label>Table Of Contents</label> + <type>javax.help.TOCView</type> + <data>$tocFileName</data> + </view> + + <view> + <name>Index</name> + <label>Index</label> + <type>javax.help.IndexView</type> + <data>$indexFileName</data> + </view> + +#if ( $!searchData != "" ) + <view> + <name>Search</name> + <label>Search</label> + <type>javax.help.SearchView</type> + <data engine="com.sun.java.help.search.DefaultSearchEngine"> + $searchData + </data> + </view> +#end +</helpset> diff --git a/trunk/maven-jaxx-plugin/src/main/resources/defaultI18n.java.vm b/trunk/maven-jaxx-plugin/src/main/resources/defaultI18n.java.vm new file mode 100644 index 0000000..b11615e --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/main/resources/defaultI18n.java.vm @@ -0,0 +1,16 @@ +package $packageName; + +$!commentaire +public class $className { // $className + +{ +// BEGIN DO NOT REMOVE : used to detect helper i18n keys +// +#foreach( $key in $keys ) +// _("$key"); +#end +// +// END DO NOT REMOVE : used to detect helper i18n keys +} + +} // $className \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/main/resources/defaultIndex.xml.vm b/trunk/maven-jaxx-plugin/src/main/resources/defaultIndex.xml.vm new file mode 100644 index 0000000..e880e18 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/main/resources/defaultIndex.xml.vm @@ -0,0 +1,21 @@ +<?xml version='1.0' encoding='UTF-8' ?> +<!DOCTYPE index + PUBLIC "-//Sun Microsystems Inc.//DTD JavaHelp Index Version 1.0//EN" + "http://buix.labs.libre-entreprise.org/javahelp/index_1_0.dtd"> + +## pour afficher un org.nuiton.jaxx.NodeItem +#macro ( renderItem $item $prefix ) +#if ( $item.isLeaf() ) +$prefix<indexitem target="$item.absoluteTarget" text="$!item.text"/> +#else +$prefix<indexitem target="$item.absoluteTarget" text="$!item.text"> +#foreach( $child in $item.getChilds() ) +#renderItem( $child "$prefix$separator" ) +#end +$prefix</indexitem> +#end +#end + +<index version="1.0"> +#renderItem( $rootItem $separator ) +</index> diff --git a/trunk/maven-jaxx-plugin/src/main/resources/defaultMap.jhm.vm b/trunk/maven-jaxx-plugin/src/main/resources/defaultMap.jhm.vm new file mode 100644 index 0000000..83fe6ee --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/main/resources/defaultMap.jhm.vm @@ -0,0 +1,16 @@ +<?xml version='1.0' encoding='UTF-8' ?> +<!DOCTYPE map + PUBLIC "-//Sun Microsystems Inc.//DTD JavaHelp Map Version 1.0//EN" + "http://java.sun.com/products/javahelp/map_1_0.dtd"> +<map version="1.0"> + +#if ( !$helpIds.get("toplevelfolder")) + <!-- use this entry to go up in navigation --> + <!--mapID target="toplevelfolder" url="images/toplevel.gif" /--> +#end + +#foreach( $key in $helpIds.keys() ) + <mapID target="$key" url="$helpIds.get($key)" /> +#end + +</map> diff --git a/trunk/maven-jaxx-plugin/src/main/resources/defaultToc.xml.vm b/trunk/maven-jaxx-plugin/src/main/resources/defaultToc.xml.vm new file mode 100644 index 0000000..d3e5e57 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/main/resources/defaultToc.xml.vm @@ -0,0 +1,20 @@ +<?xml version='1.0' encoding='UTF-8' ?> +<!DOCTYPE toc + PUBLIC "-//Sun Microsystems Inc.//DTD JavaHelp TOC Version 1.0//EN" + "http://buix.labs.libre-entreprise.org/javahelp/toc_1_0.dtd"> + +## pour afficher un org.nuiton.jaxx.NodeItem +#macro ( renderItem $item $prefix ) +#if ( $item.isLeaf() ) +$prefix<tocitem target="$item.absoluteTarget" text="$!item.text"/> +#else +$prefix<tocitem target="$item.absoluteTarget" text="$!item.text"> +#foreach( $child in $item.getChilds() ) +#renderItem( $child "$prefix$separator" ) +#end +$prefix</tocitem> +#end +#end +<toc version="1.0"> +#renderItem( $rootItem $separator ) +</toc> diff --git a/trunk/maven-jaxx-plugin/src/main/resources/log4j.properties b/trunk/maven-jaxx-plugin/src/main/resources/log4j.properties new file mode 100644 index 0000000..5e2fe11 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/main/resources/log4j.properties @@ -0,0 +1,9 @@ +# Global logging configuration +log4j.rootLogger=INFO, stdout +# Console output... +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) %M - %m%n + +log4j.logger.org.nuiton.i18n=ERROR +#log4j.logger.jaxx=DEBUG diff --git a/trunk/maven-jaxx-plugin/src/site/rst/Todo.rst b/trunk/maven-jaxx-plugin/src/site/rst/Todo.rst new file mode 100644 index 0000000..d7aabf6 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/site/rst/Todo.rst @@ -0,0 +1,4 @@ +TODO +==== + +a faire \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/site/rst/index.rst b/trunk/maven-jaxx-plugin/src/site/rst/index.rst new file mode 100644 index 0000000..a12f742 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/site/rst/index.rst @@ -0,0 +1,13 @@ +maven-jaxx-plugin +================= + +.. contents:: + + +Présentation +------------ + +Le plugin maven pour lancer le compilateur jaxx dans un projet maven TODO + +**Veuillez consulter la JavaDoc pour de plus ample détails sur les différentes +librairies.** diff --git a/trunk/maven-jaxx-plugin/src/site/site.xml b/trunk/maven-jaxx-plugin/src/site/site.xml new file mode 100644 index 0000000..b50ff43 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/site/site.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project name="${project.name}"> + + <bannerLeft> + <name>${project.name}</name> + <src>${site.home.url}/jaxx.png</src> + <href>index.html</href> + </bannerLeft> + + <body> + + <breadcrumbs> + <item name="${project.name}" href="${project.url}" /> + </breadcrumbs> + + <menu ref="parent"/> + + <menu name="Utilisateur" inherited="top"> + <item name="Accueil" href="index.html"/> + <item name="Détail goals" href="plugin-info.html"> + <item name="generate" href="generate-mojo.html"/> + <item name="help" href="help-mojo.html"/> + </item> + </menu> + + <menu name="Téléchargement" inherit="top"> + <item href="${labs.builder.url}/org/codelutin/jaxx/${project.artifactId}/${project.version}" + name="Télécharger la dernière version"/> + <item href="${labs.builder.url}/org/codelutin/jaxx/${project.artifactId}" + name="Voir toutes les versions"/> + </menu> + + <menu name="Développeur" inherit="top"> + <item name="A faire" href="Todo.html"/> + </menu> + + <menu ref="reports"/> + + <menu ref="modules"/> + </body> +</project> diff --git a/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/Bug1722Test.java b/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/Bug1722Test.java new file mode 100644 index 0000000..8351b69 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/Bug1722Test.java @@ -0,0 +1,12 @@ +package org.nuiton.jaxx; + +/** @author chemit */ +public class Bug1722Test extends JaxxBaseTest { + + public void testBug_1722() throws Exception { + mojo.execute(); + assertNumberJaxxFiles(2); + } + + +} diff --git a/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/Bug1750Test.java b/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/Bug1750Test.java new file mode 100644 index 0000000..3bd9401 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/Bug1750Test.java @@ -0,0 +1,44 @@ +package org.nuiton.jaxx; + +import jaxx.Base64Coder; +import jaxx.compiler.JAXXCompiler; +import jaxx.compiler.JAXXCompilerLaunchor; +import jaxx.runtime.JAXXObjectDescriptor; +import jaxx.runtime.Util; + +/** @author chemit */ +public class Bug1750Test extends JaxxBaseTest { + + public void testBug_1750() throws Exception { + mojo.execute(); + assertNumberJaxxFiles(1); + + JAXXCompiler compiler = JAXXCompilerLaunchor.get().getJAXXCompiler("testcases.bug_1750.ComboBox"); + assertNotNull(compiler); + + JAXXObjectDescriptor descriptor = compiler.getJAXXObjectDescriptor(); + assertNotNull(descriptor); + + String data = Base64Coder.serialize(descriptor, false); + + JAXXObjectDescriptor descriptor2 = (JAXXObjectDescriptor) Base64Coder.deserialize(data, false); + assertNotNull(descriptor2); + assertEquals(descriptor.toString(), descriptor2.toString()); + + descriptor2 = Util.decodeJAXXObjectDescriptor(data); + assertNotNull(descriptor2); + assertEquals(descriptor.toString(), descriptor2.toString()); + + data = Base64Coder.serialize(descriptor, true); + + descriptor2 = (JAXXObjectDescriptor) Base64Coder.deserialize(data, true); + assertNotNull(descriptor2); + assertEquals(descriptor.toString(), descriptor2.toString()); + + descriptor2 = Util.decodeCompressedJAXXObjectDescriptor(data); + assertNotNull(descriptor2); + assertEquals(descriptor.toString(), descriptor2.toString()); + + } + +} \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/Bug1751Test.java b/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/Bug1751Test.java new file mode 100644 index 0000000..bc674ea --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/Bug1751Test.java @@ -0,0 +1,14 @@ +package org.nuiton.jaxx; + +/** @author chemit */ +public class Bug1751Test extends JaxxBaseTest { + + public void testBug_1751() throws Exception { + mojo.execute(); + assertNumberJaxxFiles(3); + + checkPattern(mojo, "implements java.io.Serializable", true); + checkPattern(mojo, "label.setText(_(\"test\"))", true); + } + +} \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/CompilerTest.java b/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/CompilerTest.java new file mode 100644 index 0000000..4995a6a --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/CompilerTest.java @@ -0,0 +1,227 @@ +package org.nuiton.jaxx; + +import jaxx.compiler.JAXXCompiler; +import jaxx.compiler.JAXXCompilerLaunchor; +import jaxx.runtime.DefaultJAXXContext; +import jaxx.runtime.JAXXContext; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.logging.SystemStreamLog; + +import java.io.File; +import java.lang.reflect.Field; +import java.util.Map; + +public class CompilerTest extends JaxxBaseTest { + + public void testInnerClasses() throws Exception { + mojo.execute(); + assertNumberJaxxFiles(1); + } + + public void testIcon() throws Exception { + mojo.execute(); + checkPattern(mojo, ".createImageIcon(\"myIcon.png\")", true); + checkPattern(mojo, ".createActionIcon(\"myActionIcon.png\")", true); + checkPattern(mojo, ".getUIManagerIcon(\"myIcon.png\")", false); + checkPattern(mojo, ".getUIManagerActionIcon(\"myActionIcon.png\")", false); + assertNumberJaxxFiles(1); + mojo.useUIManagerForIcon = true; + mojo.execute(); + checkPattern(mojo, ".createImageIcon(\"myIcon.png\")", false); + checkPattern(mojo, ".createActionIcon(\"myActionIcon.png\")", false); + checkPattern(mojo, ".getUIManagerIcon(\"myIcon.png\")", true); + checkPattern(mojo, ".getUIManagerActionIcon(\"myActionIcon.png\")", true); + } + + public void testClientProperty() throws Exception { + mojo.execute(); + checkPattern(mojo, ".putClientProperty(\"testOne\", \"oneTest\")", true); + checkPattern(mojo, ".putClientProperty(\"testTwo\", \"anotherTest\")", true); + } + + public void testSpecialSubclassing() throws Exception { + mojo.execute(); + assertNumberJaxxFiles(7); + } + + public void testCSSTests() throws Exception { + mojo.execute(); + assertNumberJaxxFiles(7); + } + + public void testWithLog() throws Exception { + mojo.execute(); + String[] files = mojo.files; + assertNumberJaxxFiles(2); + + String withLogFile; + String withnoLogFile; + if (files[0].endsWith("WithLog.jaxx")) { + withLogFile = files[0]; + withnoLogFile = files[1]; + } else { + withLogFile = files[1]; + withnoLogFile = files[0]; + } + checkPattern(mojo, "Log log = LogFactory.getLog(", true, withLogFile); + checkPattern(mojo, "import org.apache.commons.logging.Log;", true, withLogFile); + checkPattern(mojo, "import org.apache.commons.logging.LogFactory;", true, withLogFile); + + checkPattern(mojo, "Log log = LogFactory.getLog(", false, withnoLogFile); + checkPattern(mojo, "import org.apache.commons.logging.Log;", false, withnoLogFile); + checkPattern(mojo, "import org.apache.commons.logging.LogFactory;", false, withnoLogFile); + } + + public void testNoLog() throws Exception { + mojo.execute(); + assertNumberJaxxFiles(2); + checkPattern(mojo, "Log log = LogFactory.getLog(", false); + checkPattern(mojo, "import org.apache.commons.logging.Log;", false); + checkPattern(mojo, "import org.apache.commons.logging.LogFactory;", false); + } + + @SuppressWarnings({"unchecked"}) + public void testErrors() throws Exception { + // init mojo to get alls files to treate + mojo.init(); + + assertNumberJaxxFiles(34); + mojo.setLog(new SystemStreamLog() { + + @Override + public boolean isErrorEnabled() { + return false; + } + + @Override + public void error(Throwable error) { + //do nothing + } + + @Override + public void error(CharSequence content) { + //do nothing + } + + @Override + public void error(CharSequence content, Throwable error) { + //do nothing + } + }); + Field fieldCompilers = JAXXCompilerLaunchor.class.getDeclaredField("compilers"); + Field fieldErrorCount = JAXXCompilerLaunchor.class.getDeclaredField("errorCount"); + + fieldCompilers.setAccessible(true); + fieldErrorCount.setAccessible(true); + + // execute mjo on each jaxx file to produce the error + for (String file : mojo.files) { + getLog().info("test bad file " + file); + mojo.files = new String[]{file}; + try { + mojo.doAction(); + // should never pass + fail(); + } catch (MojoExecutionException e) { + // ok jaxx compiler failed + assertTrue(true); + + JAXXCompilerLaunchor launchor = JAXXCompilerLaunchor.get(); + Map<String, JAXXCompiler> compilers = (Map<String, JAXXCompiler>) fieldCompilers.get(launchor); + assertEquals(1, compilers.size()); + //JAXXCompiler compiler; + //compiler = compilers.values().iterator().next(); + Integer nberrors = (Integer) fieldErrorCount.get(launchor); + assertTrue(nberrors != null && nberrors > 0); + } + } + } + + public void testInitializers() throws Exception { + mojo.execute(); + assertNumberJaxxFiles(1); + } + + public void testErrorJaxxContextImplementorClass() throws Exception { + mojo.jaxxContextImplementorClass = null; + try { + mojo.init(); + fail(); + } catch (IllegalArgumentException e) { + assertTrue(true); + } + + mojo.jaxxContextImplementorClass = String.class.getName(); + try { + mojo.init(); + fail(); + } catch (IllegalArgumentException e) { + assertTrue(true); + } + + mojo.jaxxContextImplementorClass = JAXXContext.class.getName(); + try { + mojo.init(); + fail(); + } catch (IllegalArgumentException e) { + assertTrue(true); + } + + mojo.jaxxContextImplementorClass = DefaultJAXXContext.class.getName(); + mojo.init(); + assertTrue(true); + + } + + public void testScript() throws Exception { + mojo.execute(); + assertNumberJaxxFiles(1); + } + + public void testOverridingDataBindings() throws Exception { + mojo.execute(); + assertNumberJaxxFiles(3); + } + + public void testClassReferences() throws Exception { + mojo.execute(); + assertNumberJaxxFiles(6); + } + + public void testForce() throws Exception { + + // first round, with force option so will generate theonly JButton.jaxx file + mojo.execute(); + String[] files = mojo.files; + assertNumberJaxxFiles(1); + + File srcFile = new File(mojo.src, files[0]); + + File dstFile = mojo.updater.getMirrorFile(srcFile); + + long oldTime = dstFile.lastModified(); + // second round, no force so will not the file + mojo.force = false; + mojo.execute(); + assertNumberJaxxFiles(0); + + Thread.sleep(1000); + + assertEquals(oldTime, mojo.updater.getMirrorFile(srcFile).lastModified()); + + // three round : modify a source with no force option + if (!srcFile.setLastModified(System.currentTimeMillis())) { + log.warn("failed to set LastModified for file " + srcFile); + } + + mojo.execute(); + assertNumberJaxxFiles(1); + assertTrue(mojo.updater.getMirrorFile(srcFile).lastModified() > oldTime); + + // last round, reforce file generation for an no modify source + mojo.force = true; + mojo.execute(); + assertNumberJaxxFiles(1); + assertTrue(mojo.updater.getMirrorFile(srcFile).lastModified() > oldTime); + } +} \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/CompilerValidatorTest.java b/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/CompilerValidatorTest.java new file mode 100644 index 0000000..61d1259 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/CompilerValidatorTest.java @@ -0,0 +1,72 @@ +package org.nuiton.jaxx; + +import jaxx.compiler.JAXXCompilerLaunchor; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.logging.SystemStreamLog; + +import java.lang.reflect.Field; +import java.util.Map; + +public class CompilerValidatorTest extends JaxxBaseTest { + + public void testValidatorOk() throws Exception { + mojo.execute(); + assertNumberJaxxFiles(2); + + } + + @SuppressWarnings({"unchecked"}) + public void testValidatorErrors() throws Exception { + // init mojo to get alls files to treate + mojo.init(); + String[] files = mojo.files; + assertNumberJaxxFiles(19); + mojo.setLog(new SystemStreamLog() { + @Override + public boolean isErrorEnabled() { + return false; + } + + @Override + public void error(Throwable error) { + //do nothing + } + + @Override + public void error(CharSequence content) { + //do nothing + } + + @Override + public void error(CharSequence content, Throwable error) { + //do nothing + } + }); + Field fieldCompilers = JAXXCompilerLaunchor.class.getDeclaredField("compilers"); + Field fieldErrorCount = JAXXCompilerLaunchor.class.getDeclaredField("errorCount"); + + fieldCompilers.setAccessible(true); + fieldErrorCount.setAccessible(true); + + // execute mjo on each jaxx file to produce the error + for (String file : files) { + getLog().info("test bad file " + file); + mojo.files = new String[]{file}; + try { + mojo.doAction(); + // should never pass + fail("for file " + file); + } catch (MojoExecutionException e) { + // ok jaxx compiler failed + assertTrue(true); + JAXXCompilerLaunchor launchor = JAXXCompilerLaunchor.get(); + Map<String, Compiler> compilers = (Map<String, Compiler>) fieldCompilers.get(launchor); + assertEquals(1, compilers.size()); + //Compiler compiler = compilers.values().iterator().next(); + Integer nberrors = (Integer) fieldErrorCount.get(launchor); + assertEquals(1, nberrors.intValue()); + } + } + } + +} \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/DecoratorTest.java b/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/DecoratorTest.java new file mode 100644 index 0000000..ec18b7f --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/DecoratorTest.java @@ -0,0 +1,11 @@ +package org.nuiton.jaxx; + +public class DecoratorTest extends JaxxBaseTest { + + public void testDecorator() throws Exception { + mojo.execute(); + assertNumberJaxxFiles(1); + checkPattern(mojo, "root.add(jaxx.runtime.SwingUtil.boxComponentWithJxLayer(boxedButton))", true); + } + +} \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/I18nTest.java b/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/I18nTest.java new file mode 100644 index 0000000..be821e6 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/I18nTest.java @@ -0,0 +1,39 @@ +package org.nuiton.jaxx; + +public class I18nTest extends JaxxBaseTest { + + public void testI18nText() throws Exception { + mojo.i18nable = false; + mojo.execute(); + checkPattern(mojo, "testId.setText(_(\"test.text\"));", false); + + mojo.i18nable = true; + mojo.execute(); + checkPattern(mojo, "testId.setText(_(\"test.text\"));", true); + checkPattern(mojo, "\"_(\\\"test.text\\\")\"", false); + } + + public void testI18nTitle() throws Exception { + mojo.i18nable = false; + mojo.execute(); + checkPattern(mojo, "testId.setTitle(_(\"test.title\"));", false); + + mojo.i18nable = true; + mojo.execute(); + checkPattern(mojo, "testId.setTitle(_(\"test.title\"));", true); + checkPattern(mojo, "\"_(\\\"test.title\\\")\"", false); + } + + public void testI18nToolTipText() throws Exception { + mojo.i18nable = false; + mojo.execute(); + checkPattern(mojo, "testId.setToolTipText(_(\"test.toolTipText\"));", false); + + mojo.i18nable = true; + mojo.execute(); + checkPattern(mojo, "testId.setToolTipText(_(\"test.toolTipText\"));", true); + checkPattern(mojo, "\"_(\\\"test.toolTipText\\\")\"", false); + } + + +} \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/JaxxBaseTest.java b/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/JaxxBaseTest.java new file mode 100644 index 0000000..7e8221d --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/JaxxBaseTest.java @@ -0,0 +1,85 @@ +package org.nuiton.jaxx; + +import jaxx.runtime.DefaultJAXXContext; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.maven.plugin.testing.AbstractMojoTestCase; +import org.nuiton.util.FileUtil; + +import java.io.File; +import java.io.IOException; + +/** @author chemit */ +public abstract class JaxxBaseTest extends AbstractMojoTestCase { + + protected static final String DEFALUT_PREFIX = "src" + File.separator + "test" + File.separator + "resources" + File.separator + "testcases" + File.separator; + + /** log */ + protected Log log; + + protected JaxxGeneratorMojo mojo; + + protected File pomFile; + + public String getPrefix() { + return DEFALUT_PREFIX; + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + getLog().info(getName()); + pomFile = getPomFile(); + mojo = (JaxxGeneratorMojo) lookupMojo("generate", pomFile); + mojo.jaxxContextImplementorClass = DefaultJAXXContext.class.getName(); + mojo.compilerFQN = jaxx.compiler.SwingCompiler.class.getName(); + mojo.validatorFQN = jaxx.runtime.validator.swing.SwingValidator.class.getName(); + mojo.defaultDecoratorFQN = jaxx.compiler.DefaultCompiledObjectDecorator.class.getName(); + assertNotNull(mojo); + } + + protected File getPomFile() { + return new File(getBasedir(), getPrefix() + getName().substring(4) + ".xml"); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + if (mojo != null) { + mojo = null; + } + if (pomFile != null) { + pomFile = null; + } + } + + protected void checkPattern(JaxxGeneratorMojo mojo, String pattern, boolean required, String... files) throws IOException { + if (files.length == 0) { + files = mojo.files; + } + for (String file : files) { + // check we have a the required/forbidden pattern + File f = new File(mojo.outJava, file.substring(0, file.length() - 4) + "java"); + if (mojo.verbose) { + getLog().info("check generated file " + f); + } + + assertTrue("generated file " + f + " was not found...", f.exists()); + String content = FileUtil.readAsString(f); + + String errorMessage = required ? "could not find the pattern : " : "should not have found pattern :"; + assertEquals(errorMessage + pattern + " in file " + f, required, content.contains(pattern)); + } + } + + protected Log getLog() { + if (log == null) { + log = LogFactory.getLog(getClass()); + } + return log; + } + + protected void assertNumberJaxxFiles(int expectedNbFiles) { + assertEquals(expectedNbFiles, mojo.files.length); + } +} diff --git a/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/NodeItemTest.java b/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/NodeItemTest.java new file mode 100644 index 0000000..83459d6 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/NodeItemTest.java @@ -0,0 +1,54 @@ +package org.nuiton.jaxx; + +import org.junit.Assert; +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * + * @author tony + */ +public class NodeItemTest { + + @Test + public void testFindChild() { + System.out.println("findChild"); + String path = "a"; + NodeItem instance = new NodeItem("a", "rootItem text"); + NodeItem expResult = new NodeItem("a", "rootItem text"); + NodeItem result = instance.findChild(path); + assertTocItemEquals(expResult, result); + + path = "a.b"; + expResult = new NodeItem("b", null); + result = instance.findChild(path); + assertTocItemEquals(expResult, result); + assertTrue(instance.getChild("b") == result); + assertTrue(instance.findChild("b") == result); + + NodeItem b = result; + + path = "ab"; + expResult = new NodeItem("ab", null); + result = instance.findChild(path); + assertTocItemEquals(expResult, result); + assertTrue(instance.getChild("ab") == result); + assertTrue(instance.findChild("ab") == result); + + path = "a.b.cd"; + expResult = new NodeItem("cd", null); + result = instance.findChild(path); + assertTocItemEquals(expResult, result); + assertTrue(b.getChild("cd") == result); + assertTrue(b.findChild("b.cd") == result); + assertTrue(b.findChild("cd") == result); + assertTrue(instance.findChild("b.cd") == result); + assertTrue(instance.findChild("a.b.cd") == result); + } + + protected void assertTocItemEquals(NodeItem t, NodeItem t2) { + Assert.assertEquals(t.getTarget(), t2.getTarget()); + Assert.assertEquals(t.getText(), t2.getText()); + + } +} \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/Bug_1722.xml b/trunk/maven-jaxx-plugin/src/test/resources/testcases/Bug_1722.xml new file mode 100644 index 0000000..486471a --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/Bug_1722.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <build> + <plugins> + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <configuration> + <src>${basedir}/src/test/resources</src> + <outJava>${basedir}/target/it-generated-sources/java</outJava> + <outResource>${basedir}/target/it-generated-sources/resources</outResource> + <force>true</force> + <verbose>true</verbose> + <includes> + <value>**/bug_1722/*.jaxx</value> + </includes> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/Bug_1750.xml b/trunk/maven-jaxx-plugin/src/test/resources/testcases/Bug_1750.xml new file mode 100644 index 0000000..cfed647 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/Bug_1750.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <build> + <plugins> + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <configuration> + <src>${basedir}/src/test/resources</src> + <outJava>${basedir}/target/it-generated-sources/java</outJava> + <outResource>${basedir}/target/it-generated-sources/resources</outResource> + <force>true</force> + <verbose>true</verbose> + <resetAfterCompile>false</resetAfterCompile> + <includes> + <value>**/bug_1750/*.jaxx</value> + </includes> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/Bug_1751.xml b/trunk/maven-jaxx-plugin/src/test/resources/testcases/Bug_1751.xml new file mode 100644 index 0000000..9f59194 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/Bug_1751.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <build> + <plugins> + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <configuration> + <src>${basedir}/src/test/resources</src> + <outJava>${basedir}/target/it-generated-sources/java</outJava> + <outResource>${basedir}/target/it-generated-sources/resources</outResource> + <i18nable>true</i18nable> + <force>true</force> + <verbose>true</verbose> + <resetAfterCompile>false</resetAfterCompile> + <includes> + <value>**/bug_1751/*.jaxx</value> + </includes> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/CSSTests.xml b/trunk/maven-jaxx-plugin/src/test/resources/testcases/CSSTests.xml new file mode 100644 index 0000000..98950a9 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/CSSTests.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <build> + <plugins> + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <configuration> + <src>${basedir}/src/test/resources</src> + <outJava>${basedir}/target/it-generated-sources/java</outJava> + <outResource>${basedir}/target/it-generated-sources/resources</outResource> + <force>true</force> + <i18nable>false</i18nable> + <includes> + <value>**/CSSTests/*.jaxx</value> + </includes> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/CSSTests/CSSTests.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/CSSTests/CSSTests.jaxx new file mode 100644 index 0000000..9dacdff --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/CSSTests/CSSTests.jaxx @@ -0,0 +1,24 @@ +<Application title='CSSTests'> + <style> + Application { lookAndFeel: {lookAndFeel.getSelectedValue()}; } + </style> + + <JMenuBar> + <JMenu text='View'> + <JMenu text='Look and Feel'> + <JRadioButtonMenuItem text='Ocean' value='cross_platform' buttonGroup='lookAndFeel' selected='true'/> + <JRadioButtonMenuItem text='System' value='system' buttonGroup='lookAndFeel'/> + </JMenu> + </JMenu> + </JMenuBar> + + <JTabbedPane> + <tab title='Simple Tests'> + <SimpleCSS/> + </tab> + + <tab title='Pseudoclasses'> + <Pseudoclasses/> + </tab> + </JTabbedPane> +</Application> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/CSSTests/Child.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/CSSTests/Child.jaxx new file mode 100644 index 0000000..e026860 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/CSSTests/Child.jaxx @@ -0,0 +1 @@ +<JButton styleClass='yellow' id='child'/> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/CSSTests/Child2.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/CSSTests/Child2.jaxx new file mode 100644 index 0000000..cbd83b5 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/CSSTests/Child2.jaxx @@ -0,0 +1 @@ +<JButton foreground='#ffcccc'/> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/CSSTests/GrandChild.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/CSSTests/GrandChild.jaxx new file mode 100644 index 0000000..c50845c --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/CSSTests/GrandChild.jaxx @@ -0,0 +1,28 @@ +<JPanel layout='{new BorderLayout()}'> + <script> + public String getText() { + return grandChild.getText(); + } + + + public void setText(String Text) { + grandChild.setText(Text); + } + + + public Color getForeground() { + if (grandChild != null) + return grandChild.getForeground(); + else + return Color.BLACK; + } + + + public void setForeground(Color foreground) { + if (grandChild != null) + grandChild.setForeground(foreground); + } + </script> + + <GrandChildButton id='grandChild'/> +</JPanel> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/CSSTests/GrandChildButton.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/CSSTests/GrandChildButton.jaxx new file mode 100644 index 0000000..db4c74a --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/CSSTests/GrandChildButton.jaxx @@ -0,0 +1 @@ +<JButton/> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/CSSTests/Pseudoclasses.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/CSSTests/Pseudoclasses.jaxx new file mode 100644 index 0000000..22db348 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/CSSTests/Pseudoclasses.jaxx @@ -0,0 +1,99 @@ +<JPanel layout='{new GridLayout(0, 2, 6, 6)}'> + <!-- each checkbox has both its own test and all of the ones that came before in order + to make sure that all of the pseudoclass overrides works properly - only the last + pair should have any effect --> + <style> + #test1:enabled { text: "Enabled"; } + #test1:disabled { text: "Disabled"; } + + #test2:enabled { text: "Enabled"; } + #test2:disabled { text: "Disabled"; } + #test2:focused { text: "Focused"; } + #test2:unfocused { text: "Unfocused"; } + + #test3:enabled { text: "Enabled"; } + #test3:disabled { text: "Disabled"; } + #test3:focused { text: "Focused"; } + #test3:unfocused { text: "Unfocused"; } + #test3:selected { text: "Selected"; } + #test3:deselected { text: "Deselected"; } + + #test4:enabled { text: "Enabled"; } + #test4:disabled { text: "Disabled"; } + #test4:focused { text: "Focused"; } + #test4:unfocused { text: "Unfocused"; } + #test4:selected { text: "Selected"; } + #test4:deselected { text: "Deselected"; } + #test4:mouseover { text: "Mouseover"; } + #test4:mouseout { text: "Mouseout"; } + + #test5:enabled { text: "Enabled"; } + #test5:disabled { text: "Disabled"; } + #test5:focused { text: "Focused"; } + #test5:unfocused { text: "Unfocused"; } + #test5:selected { text: "Selected"; } + #test5:deselected { text: "Deselected"; } + #test5:mouseover { text: "Mouseover"; } + #test5:mouseout { text: "Mouseout"; } + #test5:mousedown { text: "Mousedown"; } + #test5:mouseup { text: "Mouseup"; } + + #test6:{object.isSelected()} { text: "Selected"; } + + #test7:selected { text: { "you shouldn't see this".toUpperCase() } } + #test7:selected { text: { currentTime }; } + + #test8:mouseover { text: { test8Field.getText() }; } + </style> + + <script> + import java.text.*; + import javax.swing.Timer; + + DateFormat dateFormat = DateFormat.getTimeInstance(); + String currentTime = dateFormat.format(new Date()); + + Timer timer = new Timer(1000, new ActionListener() { + public void actionPerformed(ActionEvent e) { + currentTime = dateFormat.format(new Date()); + } + }); + + timer.start(); + </script> + + <JPanel border='{BorderFactory.createTitledBorder("Enabled/Disabled")}'> + <JCheckBox text="You shouldn't see this" enabled='{enabledCB.isSelected()}' id='test1'/> + </JPanel> + + <JPanel border='{BorderFactory.createTitledBorder("Focused/Unfocused")}'> + <JCheckBox text="You shouldn't see this" enabled='{enabledCB.isSelected()}' id='test2'/> + </JPanel> + + <JPanel border='{BorderFactory.createTitledBorder("Selected/Deselected")}'> + <JCheckBox text="You shouldn't see this" enabled='{enabledCB.isSelected()}' id='test3'/> + </JPanel> + + <JPanel border='{BorderFactory.createTitledBorder("Mouseover/Mouseout")}'> + <JCheckBox text="You shouldn't see this" enabled='{enabledCB.isSelected()}' id='test4'/> + </JPanel> + + <JPanel border='{BorderFactory.createTitledBorder("Mouseup/Mousedown")}'> + <JCheckBox text="You shouldn't see this" enabled='{enabledCB.isSelected()}' id='test5'/> + </JPanel> + + <JPanel border='{BorderFactory.createTitledBorder("Programmatic Selected")}'> + <JCheckBox text='Unselected' enabled='{enabledCB.isSelected()}' id='test6'/> + </JPanel> + + <JPanel border='{BorderFactory.createTitledBorder("Pseudoclass Data Binding")}'> + <JCheckBox text='Select to see current time' enabled='{enabledCB.isSelected()}' id='test7'/> + </JPanel> + + <VBox border='{BorderFactory.createTitledBorder("Pseudoclass Proxy Data Binding")}'> + <JCheckBox text='Mouse over to see the below text' enabled='{enabledCB.isSelected()}' id='test8'/> + <JTextField id='test8Field'/> + </VBox> + + <JCheckBox text='Enable checkboxes' id='enabledCB' selected='true'/> +</JPanel> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/CSSTests/SimpleCSS.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/CSSTests/SimpleCSS.jaxx new file mode 100644 index 0000000..93befeb --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/CSSTests/SimpleCSS.jaxx @@ -0,0 +1,29 @@ +<VBox> + <JPanel layout='{new GridLayout(0, 1, 6, 6)}'> + <style> + JPanel { border: {null}; font-size: 18; } + + JButton { foreground: red } + JButton.green { foreground: green; } + AbstractButton.blue { foreground: blue } + .blue { foreground: white; } + #B4:enabled { foreground: { Color.orange } } + .yellow { foreground: yellow; } + #child.idTest { foreground: white } + #B7:{true} { foreground: cyan; } + #B8 { foreground: black } + #B8.yellow { foreground: { new Color(0, 0, 0) } } + </style> + + <JButton id='B1' text='Red'/> + <JButton id='B2' text='Green' styleClass='green'/> + <JButton id='B3' text='Blue' styleClass='blue'/> + <GrandChild id='B4' text='Orange'/> + <Child id='B5' text='Yellow'/> + <Child id='B6' text='White' styleClass='idTest'/> + <Child id='B7' text='Cyan'/> + <Child2 id='B8' text='Pink' styleClass='yellow'/> + <Child2 id='B9' text='Purple' foreground='#aa20ff'/> + <GrandChild text='Red'/> + </JPanel> +</VBox> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClassReferences.xml b/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClassReferences.xml new file mode 100644 index 0000000..db6bd9d --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClassReferences.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <build> + <plugins> + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <configuration> + <src>${basedir}/src/test/resources</src> + <outJava>${basedir}/target/it-generated-sources/java</outJava> + <outResource>${basedir}/target/it-generated-sources/resources</outResource> + <force>true</force> + <includes> + <value>**/ClassReferences/*.jaxx</value> + </includes> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClassReferences/ClassReferences.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClassReferences/ClassReferences.jaxx new file mode 100644 index 0000000..6d69218 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClassReferences/ClassReferences.jaxx @@ -0,0 +1,18 @@ +<Application> + <script> + Object ref1 = new ConstructorReferenceTest(); + box.add(new JLabel(ref1.toString())); + + TypeReference ref2; // this line only compiles if TypeReference.jaxx gets compiled due to this reference + box.add(new JLabel("Type reference worked")); + + box.add(new JLabel(StaticMethodTest.getText())); + </script> + + <VBox id='box'> + <!-- TODO Ce cas ne fonctionne plus (il faut posséder cette classe compilée ? --> + <!--ClassTest customProperty='Compiled class file worked'/--> + <JAXXTest customProperty='Uncompiled JAXX file worked'/> + <JavaTaist customProperty='Uncompiled Java file worked'/> + </VBox> +</Application> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClassReferences/ConstructorReferenceTest.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClassReferences/ConstructorReferenceTest.jaxx new file mode 100644 index 0000000..7746296 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClassReferences/ConstructorReferenceTest.jaxx @@ -0,0 +1,7 @@ +<Object> + <script> + public String toString() { + return "Constructor reference worked"; + } + </script> +</Object> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClassReferences/JAXXReferenceTest.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClassReferences/JAXXReferenceTest.jaxx new file mode 100644 index 0000000..12efc17 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClassReferences/JAXXReferenceTest.jaxx @@ -0,0 +1,7 @@ +<JLabel> + <script> + public void setCustomProperty(String label) { + setText(label); + } + </script> +</JLabel> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClassReferences/JAXXTest.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClassReferences/JAXXTest.jaxx new file mode 100644 index 0000000..12efc17 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClassReferences/JAXXTest.jaxx @@ -0,0 +1,7 @@ +<JLabel> + <script> + public void setCustomProperty(String label) { + setText(label); + } + </script> +</JLabel> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClassReferences/JavaTaist.java b/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClassReferences/JavaTaist.java new file mode 100644 index 0000000..e15c38b --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClassReferences/JavaTaist.java @@ -0,0 +1,9 @@ +package testcases.ClassReferences; + +import javax.swing.*; + +public class JavaTaist extends JLabel { + public void setCustomProperty(String label) { + setText(label); + } +} \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClassReferences/StaticMethodTest.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClassReferences/StaticMethodTest.jaxx new file mode 100644 index 0000000..682c427 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClassReferences/StaticMethodTest.jaxx @@ -0,0 +1,7 @@ +<Object> + <script> + public static String getText() { + return "Static method reference worked"; + } + </script> +</Object> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClassReferences/TypeReference.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClassReferences/TypeReference.jaxx new file mode 100644 index 0000000..57514ce --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClassReferences/TypeReference.jaxx @@ -0,0 +1 @@ +<Object/> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClientProperty.xml b/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClientProperty.xml new file mode 100644 index 0000000..68b6822 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/ClientProperty.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <build> + <plugins> + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <configuration> + <src>${basedir}/src/test/resources</src> + <outJava>${basedir}/target/it-generated-sources/java</outJava> + <outResource>${basedir}/target/it-generated-sources/resources</outResource> + <force>true</force> + <addLogger>false</addLogger> + <includes> + <value>**/clientProperty/*.jaxx</value> + </includes> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/Decorator.xml b/trunk/maven-jaxx-plugin/src/test/resources/testcases/Decorator.xml new file mode 100644 index 0000000..2b156ba --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/Decorator.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <build> + <plugins> + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <configuration> + <src>${basedir}/src/test/resources</src> + <outJava>${basedir}/target/it-generated-sources/java</outJava> + <outResource>${basedir}/target/it-generated-sources/resources</outResource> + <force>true</force> + <addLogger>false</addLogger> + <includes> + <value>**/decorator/*.jaxx</value> + </includes> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/ErrorJaxxContextImplementorClass.xml b/trunk/maven-jaxx-plugin/src/test/resources/testcases/ErrorJaxxContextImplementorClass.xml new file mode 100644 index 0000000..d2f3b1a --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/ErrorJaxxContextImplementorClass.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <build> + <plugins> + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <configuration> + <src>${basedir}/src/test/resources</src> + <outJava>${basedir}/target/it-generated-sources/java</outJava> + <outResource>${basedir}/target/it-generated-sources/resources</outResource> + <jaxxContextImplementorClass>java.lang.String</jaxxContextImplementorClass> + <force>true</force> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/Errors.xml b/trunk/maven-jaxx-plugin/src/test/resources/testcases/Errors.xml new file mode 100644 index 0000000..d76fd22 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/Errors.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <build> + <plugins> + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <configuration> + <src>${basedir}/src/test/resources</src> + <outJava>${basedir}/target/it-generated-sources/java</outJava> + <outResource>${basedir}/target/it-generated-sources/resources</outResource> + <force>true</force> + <includes> + <value>**/errors/*.jaxx</value> + </includes> + <excludes> + <value>**/validator/errors/*.jaxx</value> + </excludes> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/Force.xml b/trunk/maven-jaxx-plugin/src/test/resources/testcases/Force.xml new file mode 100644 index 0000000..91ca6e5 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/Force.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <build> + <plugins> + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <configuration> + <src>${basedir}/src/test/resources</src> + <outJava>${basedir}/target/it-generated-sources/java</outJava> + <outResource>${basedir}/target/it-generated-sources/resources</outResource> + <force>true</force> + <includes> + <value>**/force/*.jaxx</value> + </includes> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/I18nText.xml b/trunk/maven-jaxx-plugin/src/test/resources/testcases/I18nText.xml new file mode 100644 index 0000000..f71004b --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/I18nText.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <build> + <plugins> + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <configuration> + <src>${basedir}/src/test/resources</src> + <outJava>${basedir}/target/it-generated-sources/java</outJava> + <outResource>${basedir}/target/it-generated-sources/resources</outResource> + <force>true</force> + <i18nable>true</i18nable> + <includes> + <value>**/i18n/text/*.jaxx</value> + </includes> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/I18nTitle.xml b/trunk/maven-jaxx-plugin/src/test/resources/testcases/I18nTitle.xml new file mode 100644 index 0000000..a7dc68b --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/I18nTitle.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <build> + <plugins> + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <configuration> + <src>${basedir}/src/test/resources</src> + <outJava>${basedir}/target/it-generated-sources/java</outJava> + <outResource>${basedir}/target/it-generated-sources/resources</outResource> + <force>true</force> + <i18nable>true</i18nable> + <includes> + <value>**/i18n/title/*.jaxx</value> + </includes> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/I18nToolTipText.xml b/trunk/maven-jaxx-plugin/src/test/resources/testcases/I18nToolTipText.xml new file mode 100644 index 0000000..3338f22 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/I18nToolTipText.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <build> + <plugins> + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <configuration> + <src>${basedir}/src/test/resources</src> + <outJava>${basedir}/target/it-generated-sources/java</outJava> + <outResource>${basedir}/target/it-generated-sources/resources</outResource> + <force>true</force> + <i18nable>true</i18nable> + <includes> + <value>**/i18n/tooltiptext/*.jaxx</value> + </includes> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/Icon.xml b/trunk/maven-jaxx-plugin/src/test/resources/testcases/Icon.xml new file mode 100644 index 0000000..1e75f16 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/Icon.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <build> + <plugins> + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <configuration> + <src>${basedir}/src/test/resources</src> + <outJava>${basedir}/target/it-generated-sources/java</outJava> + <outResource>${basedir}/target/it-generated-sources/resources</outResource> + <i18nable>false</i18nable> + <force>true</force> + <verbose>true</verbose> + <resetAfterCompile>true</resetAfterCompile> + <includes> + <value>**/icon/*.jaxx</value> + </includes> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/Initializers.xml b/trunk/maven-jaxx-plugin/src/test/resources/testcases/Initializers.xml new file mode 100644 index 0000000..813aa13 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/Initializers.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <build> + <plugins> + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <configuration> + <src>${basedir}/src/test/resources</src> + <outJava>${basedir}/target/it-generated-sources/java</outJava> + <outResource>${basedir}/target/it-generated-sources/resources</outResource> + <force>true</force> + <includes> + <value>**/Initializers/*.jaxx</value> + </includes> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/Initializers/Initializers.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/Initializers/Initializers.jaxx new file mode 100644 index 0000000..a62805b --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/Initializers/Initializers.jaxx @@ -0,0 +1,37 @@ +<Application> + <script> + private static String staticInitializerText = "Static initializer FAILED"; + + static { + staticInitializerText = "Static initializer worked!"; + } + + { initializerTest.setText("Initializer worked!"); } + + public Initializers(String label) { + this(1, "Custom constructor test 2 worked!"); + constructorTest1.setText(label); + } + + + public Initializers(int dummy, String label) { + super("Test 3 worked! "+dummy); + constructorTest2.setText(label); + } + + + public static void main(String[] arg) { // test custom main method + Initializers test = new Initializers("Custom constructor test 1 worked!"); + test.mainTest.setText("Custom main method worked!"); + test.setVisible(true); + } + </script> + + <VBox> + <JLabel id='mainTest' text='Custom main method FAILED'/> + <JLabel id='constructorTest1' text='Custom constructor TEST 1 FAILED'/> + <JLabel id='constructorTest2' text='Custom constructor TEST 2 FAILED'/> + <JLabel id='initializerTest' text='Initializer FAILED'/> + <JLabel id='staticInitializerTest' text='{Initializers.staticInitializerText}'/> + </VBox> +</Application> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/InnerClasses.xml b/trunk/maven-jaxx-plugin/src/test/resources/testcases/InnerClasses.xml new file mode 100644 index 0000000..9e36fb0 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/InnerClasses.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <build> + <plugins> + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <configuration> + <src>${basedir}/src/test/resources</src> + <outJava>${basedir}/target/it-generated-sources/java</outJava> + <outResource>${basedir}/target/it-generated-sources/resources</outResource> + <force>true</force> + <includes> + <value>**/InnerClasses/*.jaxx</value> + </includes> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/InnerClasses/InnerClasses.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/InnerClasses/InnerClasses.jaxx new file mode 100644 index 0000000..335f9c1 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/InnerClasses/InnerClasses.jaxx @@ -0,0 +1,17 @@ +<Application> + <JMenuBar> + <JMenu text='Test'> + <JMenuItem text='1'/> + <JPopupMenu.Separator/> + <JMenuItem text='2'/> + <javax.swing.JPopupMenu.Separator/> + <JMenuItem text='3'/> + <JPopupMenu.Separator xmlns="javax.swing.*"/> + <JMenuItem text='4'/> + <swing:JPopupMenu.Separator xmlns:swing="javax.swing.*"/> + <JMenuItem text='5'/> + <swing:javax.swing.JPopupMenu.Separator xmlns:swing="javax.swing.*"/> + <JMenuItem text='6'/> + </JMenu> + </JMenuBar> +</Application> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/NoLog.xml b/trunk/maven-jaxx-plugin/src/test/resources/testcases/NoLog.xml new file mode 100644 index 0000000..2cb70a3 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/NoLog.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <build> + <plugins> + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <configuration> + <src>${basedir}/src/test/resources</src> + <outJava>${basedir}/target/it-generated-sources/java</outJava> + <outResource>${basedir}/target/it-generated-sources/resources</outResource> + <force>true</force> + <addLogger>false</addLogger> + <includes> + <value>**/log/nolog/*.jaxx</value> + </includes> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/OverridingDataBindings.xml b/trunk/maven-jaxx-plugin/src/test/resources/testcases/OverridingDataBindings.xml new file mode 100644 index 0000000..8a3a1e3 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/OverridingDataBindings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <build> + <plugins> + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <configuration> + <src>${basedir}/src/test/resources</src> + <outJava>${basedir}/target/it-generated-sources/java</outJava> + <outResource>${basedir}/target/it-generated-sources/resources</outResource> + <force>true</force> + <includes> + <value>**/OverridingDataBindings/*.jaxx</value> + </includes> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/OverridingDataBindings/CurrentTime.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/OverridingDataBindings/CurrentTime.jaxx new file mode 100644 index 0000000..ae7ce83 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/OverridingDataBindings/CurrentTime.jaxx @@ -0,0 +1,17 @@ +<JLabel text='{currentTime}' foreground='blue'> + <script> + import java.text.*; + import javax.swing.Timer; + + DateFormat dateFormat = DateFormat.getTimeInstance(); + String currentTime = dateFormat.format(new Date()); + + Timer timer = new Timer(1000, new ActionListener() { + public void actionPerformed(ActionEvent e) { + currentTime = dateFormat.format(new Date()); + } + }); + + timer.start(); + </script> +</JLabel> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/OverridingDataBindings/OverriddenCurrentTime.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/OverridingDataBindings/OverriddenCurrentTime.jaxx new file mode 100644 index 0000000..e7816cb --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/OverridingDataBindings/OverriddenCurrentTime.jaxx @@ -0,0 +1 @@ +<CurrentTime text='Parent Working'/> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/OverridingDataBindings/OverridingDataBindings.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/OverridingDataBindings/OverridingDataBindings.jaxx new file mode 100644 index 0000000..4d9433a --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/OverridingDataBindings/OverridingDataBindings.jaxx @@ -0,0 +1,12 @@ +<Application> + <VBox> + <JLabel text='The text below should display the time'/> + <CurrentTime/> + + <JLabel text='The text below should read "Child Working"'/> + <CurrentTime text='Child Working'/> + + <JLabel text='The text below should read "Parent Working"'/> + <OverriddenCurrentTime/> + </VBox> +</Application> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/Script.xml b/trunk/maven-jaxx-plugin/src/test/resources/testcases/Script.xml new file mode 100644 index 0000000..2cd9355 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/Script.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <build> + <plugins> + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <configuration> + <src>${basedir}/src/test/resources</src> + <outJava>${basedir}/target/it-generated-sources/java</outJava> + <outResource>${basedir}/target/it-generated-sources/resources</outResource> + <force>true</force> + <includes> + <value>**/Script/*.jaxx</value> + </includes> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/Script/JScriptInitializer.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/Script/JScriptInitializer.jaxx new file mode 100644 index 0000000..57d0a98 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/Script/JScriptInitializer.jaxx @@ -0,0 +1,19 @@ +<JDialog> + <script> + protected boolean value + </script> + <script> + value=false + </script> + + <script> + value=getOk(); + + public boolean getOk() { + return true; + } + </script> + <VBox> + <JButton text='close' onActionPerformed="dispose()"/> + </VBox> +</JDialog> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/SpecialSubclassing.xml b/trunk/maven-jaxx-plugin/src/test/resources/testcases/SpecialSubclassing.xml new file mode 100644 index 0000000..0630dcb --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/SpecialSubclassing.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <build> + <plugins> + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <configuration> + <src>${basedir}/src/test/resources</src> + <outJava>${basedir}/target/it-generated-sources/java</outJava> + <outResource>${basedir}/target/it-generated-sources/resources</outResource> + <force>true</force> + <includes> + <value>**/SpecialSubclassing/*.jaxx</value> + </includes> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/SpecialSubclassing/JComboBoxTest1.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/SpecialSubclassing/JComboBoxTest1.jaxx new file mode 100644 index 0000000..7a3d535 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/SpecialSubclassing/JComboBoxTest1.jaxx @@ -0,0 +1,3 @@ +<JComboBox> + <item value='Working' selected='true'/> +</JComboBox> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/SpecialSubclassing/JComboBoxTest2.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/SpecialSubclassing/JComboBoxTest2.jaxx new file mode 100644 index 0000000..e522ac0 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/SpecialSubclassing/JComboBoxTest2.jaxx @@ -0,0 +1,3 @@ +<JComboBox> + <item value='Failed!'/> +</JComboBox> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/SpecialSubclassing/JListTest1.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/SpecialSubclassing/JListTest1.jaxx new file mode 100644 index 0000000..f49ad85 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/SpecialSubclassing/JListTest1.jaxx @@ -0,0 +1,3 @@ +<JList> + <item value='Working' selected='true'/> +</JList> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/SpecialSubclassing/JListTest2.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/SpecialSubclassing/JListTest2.jaxx new file mode 100644 index 0000000..10a6c79 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/SpecialSubclassing/JListTest2.jaxx @@ -0,0 +1,3 @@ +<JList> + <item value='Failed!'/> +</JList> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/SpecialSubclassing/JTreeTest1.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/SpecialSubclassing/JTreeTest1.jaxx new file mode 100644 index 0000000..1dcc3a1 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/SpecialSubclassing/JTreeTest1.jaxx @@ -0,0 +1,3 @@ +<JTree> + <item value='Working' selected='true'/> +</JTree> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/SpecialSubclassing/JTreeTest2.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/SpecialSubclassing/JTreeTest2.jaxx new file mode 100644 index 0000000..a9e3f3a --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/SpecialSubclassing/JTreeTest2.jaxx @@ -0,0 +1,3 @@ +<JTree> + <item value='Failed!'/> +</JTree> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/SpecialSubclassing/SpecialSubclassing.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/SpecialSubclassing/SpecialSubclassing.jaxx new file mode 100644 index 0000000..51b0fe2 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/SpecialSubclassing/SpecialSubclassing.jaxx @@ -0,0 +1,26 @@ +<Application title='Special Subclassing'> + <VBox> + <JComboBoxTest1/> + <JComboBoxTest2> + <item value='Working' selected='true'/> + </JComboBoxTest2> + + <JScrollPane> + <JListTest1/> + </JScrollPane> + <JScrollPane> + <JListTest2> + <item value='Working' selected='true'/> + </JListTest2> + </JScrollPane> + + <JScrollPane width='80' height='80'> + <JTreeTest1/> + </JScrollPane> + <JScrollPane width='80' height='80'> + <JTreeTest2> + <item value='Working' selected='true'/> + </JTreeTest2> + </JScrollPane> + </VBox> +</Application> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/ValidatorErrors.xml b/trunk/maven-jaxx-plugin/src/test/resources/testcases/ValidatorErrors.xml new file mode 100644 index 0000000..cc63435 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/ValidatorErrors.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <build> + <plugins> + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <configuration> + <src>${basedir}/src/test/resources</src> + <outJava>${basedir}/target/it-generated-sources/java</outJava> + <outResource>${basedir}/target/it-generated-sources/resources</outResource> + <force>true</force> + <includes> + <value>**/validator/errors/*.jaxx</value> + </includes> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/ValidatorOk.xml b/trunk/maven-jaxx-plugin/src/test/resources/testcases/ValidatorOk.xml new file mode 100644 index 0000000..f5c2fa8 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/ValidatorOk.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <build> + <plugins> + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <configuration> + <src>${basedir}/src/test/resources</src> + <outJava>${basedir}/target/it-generated-sources/java</outJava> + <outResource>${basedir}/target/it-generated-sources/resources</outResource> + <force>true</force> + <includes> + <value>**/validator/ok/*.jaxx</value> + </includes> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/WithLog.xml b/trunk/maven-jaxx-plugin/src/test/resources/testcases/WithLog.xml new file mode 100644 index 0000000..4d7bc48 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/WithLog.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <build> + <plugins> + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <configuration> + <src>${basedir}/src/test/resources</src> + <outJava>${basedir}/target/it-generated-sources/java</outJava> + <outResource>${basedir}/target/it-generated-sources/resources</outResource> + <force>true</force> + <addLogger>true</addLogger> + <includes> + <value>**/log/withlog/*.jaxx</value> + </includes> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/bug_1722/DemoPanel.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/bug_1722/DemoPanel.jaxx new file mode 100644 index 0000000..fa1b802 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/bug_1722/DemoPanel.jaxx @@ -0,0 +1,7 @@ +<JTabbedPane id='top'> + <tab title='Title'> + <JPanel id='demoPanel'> + <JLabel text='override'/> + </JPanel> + </tab> +</JTabbedPane> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/bug_1722/JButtonDemo.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/bug_1722/JButtonDemo.jaxx new file mode 100644 index 0000000..3fdd447 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/bug_1722/JButtonDemo.jaxx @@ -0,0 +1,5 @@ +<DemoPanel> + <JPanel id='demoPanel'> + <JLabel text='override'/> + </JPanel> +</DemoPanel> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/bug_1750/ComboBox.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/bug_1750/ComboBox.jaxx new file mode 100644 index 0000000..4f19d1b --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/bug_1750/ComboBox.jaxx @@ -0,0 +1,18 @@ +<Table> + + <!-- selectedItem state --> + <Object id='selectedItem' javaBean=''/> + + <!-- check state --> + <Boolean id='check' constructorParams='false' javaBean=''/> + + <row> + <cell> + <JComboBox id='combobox' selectedItem='{getSelectedItem()}' + onItemStateChanged='setSelectedItem(combobox.getSelectedItem())'/> + </cell> + <cell> + <JCheckBox id='checkbox' selected='{isCheck()}' onActionPerformed='setCheck(checkbox.isSelected())'/> + </cell> + </row> +</Table> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/bug_1751/Test1.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/bug_1751/Test1.jaxx new file mode 100644 index 0000000..516f523 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/bug_1751/Test1.jaxx @@ -0,0 +1 @@ +<JLabel id='label' implements="java.io.Serializable" text='test'/> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/bug_1751/Test2.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/bug_1751/Test2.jaxx new file mode 100644 index 0000000..ee048c4 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/bug_1751/Test2.jaxx @@ -0,0 +1 @@ +<JLabel id='label' text='test' implements="java.io.Serializable"/> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/bug_1751/Test3.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/bug_1751/Test3.jaxx new file mode 100644 index 0000000..47a5c50 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/bug_1751/Test3.jaxx @@ -0,0 +1 @@ +<JLabel implements="java.io.Serializable" text='test' id='label'/> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/clientProperty/TestOne.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/clientProperty/TestOne.jaxx new file mode 100644 index 0000000..789849e --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/clientProperty/TestOne.jaxx @@ -0,0 +1,3 @@ +<JPanel id='root'> + <JButton id='boxedButton' _testOne='"oneTest"' _testTwo='{"anotherTest"}'/> +</JPanel> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/decorator/BoxedDecorator.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/decorator/BoxedDecorator.jaxx new file mode 100644 index 0000000..ae341b8 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/decorator/BoxedDecorator.jaxx @@ -0,0 +1,3 @@ +<JPanel id='root'> + <JButton id='boxedButton' decorator='boxed'/> +</JPanel> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/AmbiguousName.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/AmbiguousName.jaxx new file mode 100644 index 0000000..cc340b9 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/AmbiguousName.jaxx @@ -0,0 +1,10 @@ +<JPanel> + <script> + import java.awt.*; + import java.sql.*; + import java.util.*; + </script> + + <List/> + <Date/> +</JPanel> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/BadTypeConversions.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/BadTypeConversions.jaxx new file mode 100644 index 0000000..18fb9a0 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/BadTypeConversions.jaxx @@ -0,0 +1,4 @@ +<JButton opaque='yellow' + margin='42, 1, 7' + mnemonic='AX' + border='true'/> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/CellOutsideOfRow.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/CellOutsideOfRow.jaxx new file mode 100644 index 0000000..c3a530a --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/CellOutsideOfRow.jaxx @@ -0,0 +1,5 @@ +<JPanel> + <cell><JButton/></cell> + + <cell><JLabel/></cell> +</JPanel> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ChildrenInNonContainer.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ChildrenInNonContainer.jaxx new file mode 100644 index 0000000..636a6d0 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ChildrenInNonContainer.jaxx @@ -0,0 +1,4 @@ +<JButton> + <JPanel/> + <JMenuBar/> +</JButton> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ClassNotFound.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ClassNotFound.jaxx new file mode 100644 index 0000000..a65b576 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ClassNotFound.jaxx @@ -0,0 +1,3 @@ +<Frame> + <Glob/> +</Frame> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ConflictingPackages.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ConflictingPackages.jaxx new file mode 100644 index 0000000..56bd2c0 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ConflictingPackages.jaxx @@ -0,0 +1 @@ +<awt:javax.swing.JFrame xmlns:awt='java.awt.*'/> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ConstraintsParseError.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ConstraintsParseError.jaxx new file mode 100644 index 0000000..54c80c5 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ConstraintsParseError.jaxx @@ -0,0 +1,5 @@ +<Application> + <JLabel constraints='BorderLayout*%NORTH'/> + <JButton constraints='BorderLayout.SOUTH'/> + <JTabbedPane constraints='BorderLayout(CENTER'/> +</Application> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/DataBindingParseError.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/DataBindingParseError.jaxx new file mode 100644 index 0000000..a9fe864 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/DataBindingParseError.jaxx @@ -0,0 +1,6 @@ +<JPanel> + <JButton text='{"Missing right brace"'/> + <JLabel text='{Math.PI + Math.E ~= Math.PIE}'/> + <JToolBar visible='{I like pie}'/> + <JButton text='{"This should compile"}}'/> +</JPanel> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/DuplicateIDs.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/DuplicateIDs.jaxx new file mode 100644 index 0000000..6f6ccfd --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/DuplicateIDs.jaxx @@ -0,0 +1,4 @@ +<JPanel id='duplicate'> + <JPanel id='duplicate'/> + <JColorChooser id='duplicate'/> +</JPanel> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/EventHandlerParseError.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/EventHandlerParseError.jaxx new file mode 100644 index 0000000..43a872d --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/EventHandlerParseError.jaxx @@ -0,0 +1,4 @@ +<JPanel> + <JButton onActionPerformed='!*'/> + <JPanel onMouseEntered='{System.out.println("Remember kids, only use curly braces where appropriate!")}'/> +</JPanel> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/InvalidID.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/InvalidID.jaxx new file mode 100644 index 0000000..397a774 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/InvalidID.jaxx @@ -0,0 +1,3 @@ +<Application id='1'> + <JButton id='Hello-'/> +</Application> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/InvalidRootTag.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/InvalidRootTag.jaxx new file mode 100644 index 0000000..737b3e6 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/InvalidRootTag.jaxx @@ -0,0 +1 @@ +<style source='test.css'/> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/InvalidXML.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/InvalidXML.jaxx new file mode 100644 index 0000000..c040eb7 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/InvalidXML.jaxx @@ -0,0 +1,4 @@ +<begin> + <valid/> + <so.is.this/> +</end> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ItemDuplicateValues.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ItemDuplicateValues.jaxx new file mode 100644 index 0000000..27e0397 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ItemDuplicateValues.jaxx @@ -0,0 +1,8 @@ +<JList> + <item value='1'/> + <item value='2'/> + <item value='2'/> + <item value='3'/> + <item value='3'/> + <item value='3'/> +</JList> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ItemNoValue.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ItemNoValue.jaxx new file mode 100644 index 0000000..ca70ebd --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ItemNoValue.jaxx @@ -0,0 +1,4 @@ +<JList> + <item label='This item doesn&t have a value'/> + <item label='Neither does this one'/> +</JList> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/MixedContent.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/MixedContent.jaxx new file mode 100644 index 0000000..c4bc217 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/MixedContent.jaxx @@ -0,0 +1,19 @@ +<JPanel> + mixed1 + + <Table> + <row> + mixed2 + + <cell>mixed3</cell> + </row> + </Table> + + <JList> + <item>mixed4</item> + </JList> + + <JTabbedPane> + <tab>mixed5</tab> + </JTabbedPane> +</JPanel> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/RowOutsideOfTable.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/RowOutsideOfTable.jaxx new file mode 100644 index 0000000..5d82261 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/RowOutsideOfTable.jaxx @@ -0,0 +1,9 @@ +<JPanel> + <row> + <cell><JButton/></cell> + </row> + + <row> + <cell><JLabel/></cell> + </row> +</JPanel> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/RowWrongChild.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/RowWrongChild.jaxx new file mode 100644 index 0000000..6841aaa --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/RowWrongChild.jaxx @@ -0,0 +1,9 @@ +<Table> + <row> + <JPanel/> + </row> + + <row> + <JScrollPane/> + </row> +</Table> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ScriptNotFound.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ScriptNotFound.jaxx new file mode 100644 index 0000000..6d5aadb --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ScriptNotFound.jaxx @@ -0,0 +1 @@ +<script source='notfound.script'/> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ScriptParseError.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ScriptParseError.jaxx new file mode 100644 index 0000000..76068ca --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ScriptParseError.jaxx @@ -0,0 +1,6 @@ +<JFileChooser> + <script> + System.err.println("this is a valid line"); + System.err.println("this is an unclosed string literal); + </script> +</JFileChooser> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ScriptSourceAndInline.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ScriptSourceAndInline.jaxx new file mode 100644 index 0000000..3ef95ea --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/ScriptSourceAndInline.jaxx @@ -0,0 +1,3 @@ +<script source='dependencies/test.script'> + System.err.println("This should not compile"); +</script> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/StyleNotFound.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/StyleNotFound.jaxx new file mode 100644 index 0000000..b8de60c --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/StyleNotFound.jaxx @@ -0,0 +1 @@ +<style source='notfound.css'/> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/StyleParseError.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/StyleParseError.jaxx new file mode 100644 index 0000000..915b9f9 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/StyleParseError.jaxx @@ -0,0 +1,9 @@ +<JFileChooser> + <style> + JButton { + foreground: blue; + label: "Parse error on next line"; + *: false; + } + </style> +</JFileChooser> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/StyleSourceAndInline.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/StyleSourceAndInline.jaxx new file mode 100644 index 0000000..d1f054c --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/StyleSourceAndInline.jaxx @@ -0,0 +1,3 @@ +<style source='dependencies/test.css'> + JLabel { text: "this should not compile" } +</style> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/TabOutsideOfTabbedPane.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/TabOutsideOfTabbedPane.jaxx new file mode 100644 index 0000000..155482c --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/TabOutsideOfTabbedPane.jaxx @@ -0,0 +1,9 @@ +<JPanel> + <tab> + <JButton/> + </tab> + + <tab> + <JLabel/> + </tab> +</JPanel> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/TabbedPaneWrongChild.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/TabbedPaneWrongChild.jaxx new file mode 100644 index 0000000..b40b314 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/TabbedPaneWrongChild.jaxx @@ -0,0 +1,6 @@ +<Application> + <JTabbedPane> + <JPanel/> + <JScrollPane/> + </JTabbedPane> +</Application> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/TableWrongChild.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/TableWrongChild.jaxx new file mode 100644 index 0000000..5799da5 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/TableWrongChild.jaxx @@ -0,0 +1,6 @@ +<Application> + <Table> + <JPanel/> + <JScrollPane/> + </Table> +</Application> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/TooManyCellChildren.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/TooManyCellChildren.jaxx new file mode 100644 index 0000000..00c0a20 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/TooManyCellChildren.jaxx @@ -0,0 +1,15 @@ +<Application> + <Table> + <row> + <cell> + <JButton/> + <JButton/> + </cell> + + <cell> + <JPanel/> + <JToolBar/> + </cell> + </row> + </Table> +</Application> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/TooManyScrollPaneChildren.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/TooManyScrollPaneChildren.jaxx new file mode 100644 index 0000000..7a777aa --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/TooManyScrollPaneChildren.jaxx @@ -0,0 +1,5 @@ +<JScrollPane> + <JButton/> + <JToolBar/> + <JPanel/> +</JScrollPane> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/TooManySplitPaneChildren.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/TooManySplitPaneChildren.jaxx new file mode 100644 index 0000000..907b2a9 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/TooManySplitPaneChildren.jaxx @@ -0,0 +1,7 @@ +<Application> + <JSplitPane> + <JButton text='one'/> + <JButton text='two'/> + <JButton text='three'/> + </JSplitPane> +</Application> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/TooManyTabChildren.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/TooManyTabChildren.jaxx new file mode 100644 index 0000000..edcdf62 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/TooManyTabChildren.jaxx @@ -0,0 +1,13 @@ +<Application> + <JTabbedPane> + <tab> + <JButton/> + <JButton/> + </tab> + + <tab> + <JPanel/> + <JToolBar/> + </tab> + </JTabbedPane> +</Application> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/UnsupportedAttribute.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/UnsupportedAttribute.jaxx new file mode 100644 index 0000000..9f51932 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/UnsupportedAttribute.jaxx @@ -0,0 +1,3 @@ +<JPanel widgetCount='7'> + <JLabel mnemonic='A'/> +</JPanel> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/UnsupportedEvent.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/UnsupportedEvent.jaxx new file mode 100644 index 0000000..9082bc7 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/UnsupportedEvent.jaxx @@ -0,0 +1,3 @@ +<JPanel onWink='7'> + <JLabel onWonLottery='A'/> +</JPanel> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/UnsupportedPseudoclass.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/UnsupportedPseudoclass.jaxx new file mode 100644 index 0000000..f1a1a69 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/UnsupportedPseudoclass.jaxx @@ -0,0 +1,5 @@ +<JButton> + <style> + :opaque { enabled: false; } + </style> +</JButton> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/dependencies/test.css b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/dependencies/test.css new file mode 100644 index 0000000..1758539 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/dependencies/test.css @@ -0,0 +1 @@ +JLabel { text: "This should not compile" } \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/dependencies/test.script b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/dependencies/test.script new file mode 100644 index 0000000..6b1b25c --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/errors/dependencies/test.script @@ -0,0 +1 @@ +System.err.println("This should not compile."); \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/force/JButton.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/force/JButton.jaxx new file mode 100644 index 0000000..722fe25 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/force/JButton.jaxx @@ -0,0 +1 @@ +<javax.swing.JButton id='testId' text='test.text'/> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/i18n/text/JButton.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/i18n/text/JButton.jaxx new file mode 100644 index 0000000..722fe25 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/i18n/text/JButton.jaxx @@ -0,0 +1 @@ +<javax.swing.JButton id='testId' text='test.text'/> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/i18n/title/JDialog.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/i18n/title/JDialog.jaxx new file mode 100644 index 0000000..46aa29f --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/i18n/title/JDialog.jaxx @@ -0,0 +1 @@ +<JDialog id='testId' title='test.title'/> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/i18n/title/JTabbedPane.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/i18n/title/JTabbedPane.jaxx new file mode 100644 index 0000000..afbd648 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/i18n/title/JTabbedPane.jaxx @@ -0,0 +1,3 @@ + <JTabbedPane> + <tab id="testId" title='test.title'/> +</JTabbedPane> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/i18n/title/JTabbedPane2.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/i18n/title/JTabbedPane2.jaxx new file mode 100644 index 0000000..97d0f77 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/i18n/title/JTabbedPane2.jaxx @@ -0,0 +1,5 @@ +<JTabbedPane> + <tab id="testId" title='test.title'> + <JLabel text='testLabel'/> + </tab> +</JTabbedPane> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/i18n/tooltiptext/JButton.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/i18n/tooltiptext/JButton.jaxx new file mode 100644 index 0000000..1bbef52 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/i18n/tooltiptext/JButton.jaxx @@ -0,0 +1 @@ +<javax.swing.JButton id='testId' toolTipText='test.toolTipText'/> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/i18n/tooltiptext/JTabbedPane.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/i18n/tooltiptext/JTabbedPane.jaxx new file mode 100644 index 0000000..ae54930 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/i18n/tooltiptext/JTabbedPane.jaxx @@ -0,0 +1,3 @@ + <JTabbedPane id="testId" toolTipText='test.toolTipText'> + <tab title="text"/> +</JTabbedPane> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/i18n/tooltiptext/JTabbedPane2.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/i18n/tooltiptext/JTabbedPane2.jaxx new file mode 100644 index 0000000..ed2ae79 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/i18n/tooltiptext/JTabbedPane2.jaxx @@ -0,0 +1,3 @@ + <JTabbedPane> + <tab id="testId" toolTipText='test.toolTipText'/> +</JTabbedPane> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/i18n/tooltiptext/JTabbedPane3.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/i18n/tooltiptext/JTabbedPane3.jaxx new file mode 100644 index 0000000..43dda47 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/i18n/tooltiptext/JTabbedPane3.jaxx @@ -0,0 +1,5 @@ +<JTabbedPane> + <tab id="testId" toolTipText='test.toolTipText'> + <JLabel text='yo'/> + </tab> +</JTabbedPane> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/icon/Test1.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/icon/Test1.jaxx new file mode 100644 index 0000000..a3c6005 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/icon/Test1.jaxx @@ -0,0 +1,4 @@ +<JPanel> + <JLabel icon='myIcon.png'/> + <JLabel actionIcon='myActionIcon.png'/> +</JPanel> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/log/nolog/NoLog.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/log/nolog/NoLog.jaxx new file mode 100644 index 0000000..71a00b1 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/log/nolog/NoLog.jaxx @@ -0,0 +1 @@ +<JButton id='testId' text='test.text'/> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/log/nolog/NoLogSon.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/log/nolog/NoLogSon.jaxx new file mode 100644 index 0000000..77eed15 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/log/nolog/NoLogSon.jaxx @@ -0,0 +1 @@ +<NoLog id='testId' text='test.text'/> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/log/withlog/NoLog.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/log/withlog/NoLog.jaxx new file mode 100644 index 0000000..2e72314 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/log/withlog/NoLog.jaxx @@ -0,0 +1 @@ +<WithLog id='testId' text='test.text'/> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/log/withlog/WithLog.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/log/withlog/WithLog.jaxx new file mode 100644 index 0000000..71a00b1 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/log/withlog/WithLog.jaxx @@ -0,0 +1 @@ +<JButton id='testId' text='test.text'/> \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/AutoFieldComponentNotFound.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/AutoFieldComponentNotFound.jaxx new file mode 100644 index 0000000..8fcda77 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/AutoFieldComponentNotFound.jaxx @@ -0,0 +1,5 @@ +<Application> + <BeanValidator beanClass="testcases.validator.errors.Model" autoField='true' strictMode='true'/> + <JTextField id='text'/> + <JTextField id='text2'/> +</Application> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/DuplicatedBean.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/DuplicatedBean.jaxx new file mode 100644 index 0000000..a367e31 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/DuplicatedBean.jaxx @@ -0,0 +1,3 @@ +<Application> + <BeanValidator bean='model' errorListModel='errors' bean='yo'/> +</Application> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/DuplicatedBean2.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/DuplicatedBean2.jaxx new file mode 100644 index 0000000..4a762fc --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/DuplicatedBean2.jaxx @@ -0,0 +1,5 @@ +<Application> + <Model id='model'/> + <BeanValidator bean='model'/> + <BeanValidator bean='model'/> +</Application> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/DuplicatedErrorListModel.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/DuplicatedErrorListModel.jaxx new file mode 100644 index 0000000..f0a53ce --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/DuplicatedErrorListModel.jaxx @@ -0,0 +1,4 @@ +<Application> + <jaxx.runtime.validator.swing.SwingValidatorMessageListModel id='errors'/> + <BeanValidator beanClass='testcases.validator.errors.Model' errorListModel='errors' errorListModel='fake'/> +</Application> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/DuplicatedErrorTableModel.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/DuplicatedErrorTableModel.jaxx new file mode 100644 index 0000000..9025657 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/DuplicatedErrorTableModel.jaxx @@ -0,0 +1,4 @@ +<Application> + <jaxx.runtime.validator.swing.SwingValidatorMessageListModel id='errors'/> + <BeanValidator beanClass='testcases.validator.errors.Model' errorTableModel='errors' errorTableModel='fake'/> +</Application> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/DuplicatedFieldInSameValidator.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/DuplicatedFieldInSameValidator.jaxx new file mode 100644 index 0000000..210aa68 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/DuplicatedFieldInSameValidator.jaxx @@ -0,0 +1,7 @@ +<Application> + <BeanValidator beanClass="testcases.validator.errors.Model"> + <field name="text"/> + <field name="text"/> + </BeanValidator> + <JTextField id='text'/> +</Application> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/FieldBeanPropertyNotFound.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/FieldBeanPropertyNotFound.jaxx new file mode 100644 index 0000000..97e0318 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/FieldBeanPropertyNotFound.jaxx @@ -0,0 +1,5 @@ +<Application> + <BeanValidator beanClass="testcases.validator.errors.Model"> + <field name="fake"/> + </BeanValidator> +</Application> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/FieldComponentDuplicated.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/FieldComponentDuplicated.jaxx new file mode 100644 index 0000000..176e944 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/FieldComponentDuplicated.jaxx @@ -0,0 +1,7 @@ +<Application> + <BeanValidator beanClass="testcases.validator.errors.Model"> + <field name="text2" component="text"/> + <field name="text" component="text"/> + </BeanValidator> + <JTextField id='text'/> +</Application> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/FieldComponentNotFound.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/FieldComponentNotFound.jaxx new file mode 100644 index 0000000..18e9f6d --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/FieldComponentNotFound.jaxx @@ -0,0 +1,5 @@ +<Application> + <BeanValidator beanClass="testcases.validator.errors.Model"> + <field name="text" component="fake"/> + </BeanValidator> +</Application> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/FieldComponentNotFound2.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/FieldComponentNotFound2.jaxx new file mode 100644 index 0000000..97e0318 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/FieldComponentNotFound2.jaxx @@ -0,0 +1,5 @@ +<Application> + <BeanValidator beanClass="testcases.validator.errors.Model"> + <field name="fake"/> + </BeanValidator> +</Application> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/FieldNoName.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/FieldNoName.jaxx new file mode 100644 index 0000000..ef57d93 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/FieldNoName.jaxx @@ -0,0 +1,5 @@ +<Application> + <BeanValidator beanClass="testcases.validator.errors.Model"> + <field/> + </BeanValidator> +</Application> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/FieldNoName2.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/FieldNoName2.jaxx new file mode 100644 index 0000000..9cab45f --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/FieldNoName2.jaxx @@ -0,0 +1,5 @@ +<Application> + <BeanValidator beanClass="testcases.validator.errors.Model"> + <field component="text"/> + </BeanValidator> +</Application> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/Model.java b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/Model.java new file mode 100644 index 0000000..4dba232 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/Model.java @@ -0,0 +1,66 @@ +package testcases.validator.errors; + +import java.beans.*; + +public class Model { + + protected String text = "text"; + + protected String text2 = "text2"; + + protected int ratio = 51; + + + PropertyChangeSupport p; + + public Model() { + p = new PropertyChangeSupport(this); + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + p.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + p.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + p.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + p.removePropertyChangeListener(propertyName, listener); + } + + + public String getText() { + return text; + } + + public String getText2() { + return text2; + } + + public int getRatio() { + return ratio; + } + + public void setText(String text) { + String oldText = this.text; + this.text = text; + p.firePropertyChange("text", oldText, text); + } + + public void setText2(String text2) { + String oldText2 = this.text2; + this.text2 = text2; + p.firePropertyChange("text2", oldText2, text2); + } + + public void setRatio(int ratio) { + int oldRatio = this.ratio; + this.ratio = ratio; + p.firePropertyChange("ratio",oldRatio, ratio); + } +} \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/NoBean.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/NoBean.jaxx new file mode 100644 index 0000000..315617d --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/NoBean.jaxx @@ -0,0 +1,5 @@ +<Application> + + <BeanValidator id='validator'/> + +</Application> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/UnfoundBean.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/UnfoundBean.jaxx new file mode 100644 index 0000000..8ca870f --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/UnfoundBean.jaxx @@ -0,0 +1,3 @@ +<Application> + <BeanValidator bean='fake'/> +</Application> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/UnfoundErrorList.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/UnfoundErrorList.jaxx new file mode 100644 index 0000000..6dcfc87 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/UnfoundErrorList.jaxx @@ -0,0 +1,3 @@ +<Application> + <BeanValidator beanClass='testcases.validator.errors.Model' errorList='fake'/> +</Application> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/UnfoundErrorListModel.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/UnfoundErrorListModel.jaxx new file mode 100644 index 0000000..3642ab0 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/UnfoundErrorListModel.jaxx @@ -0,0 +1,3 @@ +<Application> + <BeanValidator beanClass='testcases.validator.errors.Model' errorListModel='fake'/> +</Application> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/UnfoundErrorTable.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/UnfoundErrorTable.jaxx new file mode 100644 index 0000000..e9e715e --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/UnfoundErrorTable.jaxx @@ -0,0 +1,3 @@ +<Application> + <BeanValidator beanClass='testcases.validator.errors.Model' errorTable='fake'/> +</Application> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/UnfoundErrorTableModel.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/UnfoundErrorTableModel.jaxx new file mode 100644 index 0000000..50f8b54 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/UnfoundErrorTableModel.jaxx @@ -0,0 +1,3 @@ +<Application> + <BeanValidator bean='testcases.validator.errors.Model' errorTableModel='fake'/> +</Application> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/UnfoundParentValidator.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/UnfoundParentValidator.jaxx new file mode 100644 index 0000000..445168b --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/errors/UnfoundParentValidator.jaxx @@ -0,0 +1,3 @@ +<Application> + <BeanValidator beanClass='testcases.validator.errors.Model' parentValidator='fake'/> +</Application> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/ok/Identity.java b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/ok/Identity.java new file mode 100644 index 0000000..9fd2502 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/ok/Identity.java @@ -0,0 +1,79 @@ +package testcases.validator.ok; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; + +public class Identity { + + protected String firstName = ""; + + protected String lastName = ""; + + protected String email = "dummy@codelutin.com"; + + protected int age = 51; + + + PropertyChangeSupport p; + + public Identity() { + p = new PropertyChangeSupport(this); + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + p.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + p.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + p.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + p.removePropertyChangeListener(propertyName, listener); + } + + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public String getEmail() { + return email; + } + + public int getAge() { + return age; + } + + public void setFirstName(String firstName) { + String oldFirstName = this.firstName; + this.firstName = firstName; + p.firePropertyChange("firstName", oldFirstName, firstName); + } + + public void setLastName(String lastName) { + String oldLastName = this.lastName; + this.lastName = lastName; + p.firePropertyChange("lastName", oldLastName, lastName); + } + + public void setEmail(String email) { + String oldEmail =this.email; + this.email = email; + p.firePropertyChange("email", oldEmail, email); + } + + public void setAge(int age) { + int oldAge = this.age; + this.age = age; + p.firePropertyChange("age", oldAge, age); + } +} \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/ok/Model.java b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/ok/Model.java new file mode 100644 index 0000000..5135d7b --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/ok/Model.java @@ -0,0 +1,66 @@ +package testcases.validator.ok; + +import java.beans.*; + +public class Model { + + protected String text = "text"; + + protected String text2 = "text2"; + + protected int ratio = 51; + + + PropertyChangeSupport p; + + public Model() { + p = new PropertyChangeSupport(this); + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + p.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + p.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + p.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + p.removePropertyChangeListener(propertyName, listener); + } + + + public String getText() { + return text; + } + + public String getText2() { + return text2; + } + + public int getRatio() { + return ratio; + } + + public void setText(String text) { + String oldText = this.text; + this.text = text; + p.firePropertyChange("text", oldText, text); + } + + public void setText2(String text2) { + String oldText2 = this.text2; + this.text2 = text2; + p.firePropertyChange("text2", oldText2, text2); + } + + public void setRatio(int ratio) { + int oldRatio = this.ratio; + this.ratio = ratio; + p.firePropertyChange("ratio",oldRatio, ratio); + } +} \ No newline at end of file diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/ok/Validation.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/ok/Validation.jaxx new file mode 100644 index 0000000..1469d97 --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/ok/Validation.jaxx @@ -0,0 +1,274 @@ +<Application title="Validation.jaxx"> + + <!-- models --> + <Model id='model'/> + <Model id='model2'/> + <Identity id='identity'/> + + <!-- errors model --> + <jaxx.runtime.validator.swing.SwingValidatorMessageListModel id='errors' + onContentsChanged='ok.setEnabled(errors.size()==0)'/> + + <!-- validators --> + <BeanValidator id='validator' bean='model' errorListModel='errors'> + <field name="text"/> + <field name="text2"/> + <field name="ratio"/> + </BeanValidator> + <BeanValidator id='validator2' bean='model2' errorListModel='errors' + uiClass="jaxx.runtime.validator.swing.ui.IconValidationUI"> + <field name="text" component="_text"/> + <field name="text2" component="_text2"/> + <field name="ratio" component="_ratio"/> + </BeanValidator> + <BeanValidator id='validator3' autoField='true' bean='identity' errorListModel='errors' + uiClass="jaxx.runtime.validator.swing.ui.TranslucentValidationUI"> + <field name="email" component="email2"/> + </BeanValidator> + + <Table fill='both'> + <row> + <cell weightx='1' weighty='1' insets='6, 3, 0, 0'> + <JPanel border='{BorderFactory.createTitledBorder("Form")}' + layout='{new GridLayout()}' width='250' height='120'> + <Table anchor='west' fill='both'> + <row> + <cell> + <JLabel text='Text:'/> + </cell> + <cell weightx='1'> + <JTextField id='text' text='{model.getText()}' + onKeyReleased='model.setText(text.getText())'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Text2:'/> + </cell> + <cell weightx='1'> + <JTextField id='text2' text='{model.getText2()}' + onKeyReleased='model.setText2(text2.getText())'/> + </cell> + </row> + + <row> + <cell> + <JLabel text='Ratio:'/> + </cell> + <cell> + <JSlider id='ratio' minimum='0' maximum='100' value='{model.getRatio()}' + onStateChanged='model.setRatio(ratio.getValue())'/> + </cell> + </row> + </Table> + </JPanel> + </cell> + <cell weightx='1' weighty='1' insets='6, 3, 0, 0'> + <JPanel border='{BorderFactory.createTitledBorder("Model")}' + layout='{new GridLayout()}' width='250' height='120'> + <Table anchor='west' fill='both'> + <row> + <cell> + <JLabel text='Text:'/> + </cell> + <cell weightx='1'> + <JLabel text='{model.getText()}'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Text2:'/> + </cell> + <cell weightx='1'> + <JLabel text='{model.getText2()}'/> + </cell> + </row> + + <row> + <cell> + <JLabel text='Ratio:'/> + </cell> + <cell> + <JLabel text='{model.getRatio()}'/> + </cell> + </row> + </Table> + </JPanel> + </cell> + </row> + <row> + <cell weightx='1' weighty='1' insets='6, 3, 0, 0'> + <JPanel border='{BorderFactory.createTitledBorder("Form2")}' + layout='{new GridLayout()}' width='250' height='120'> + <Table anchor='west' fill='both'> + <row> + <cell> + <JLabel text='Text:'/> + </cell> + <cell weightx='1'> + <JTextField id='_text' text='{model2.getText()}' + onKeyReleased='model2.setText(_text.getText())'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Text2:'/> + </cell> + <cell weightx='1'> + <JTextField id='_text2' text='{model2.getText2()}' + onKeyReleased='model2.setText2(_text2.getText())'/> + </cell> + </row> + + <row> + <cell> + <JLabel text='Ratio:'/> + </cell> + <cell> + <JSlider id='_ratio' minimum='0' maximum='100' value='{model2.getRatio()}' + onStateChanged='model2.setRatio(_ratio.getValue())'/> + </cell> + </row> + </Table> + </JPanel> + </cell> + <cell weightx='1' weighty='1' insets='6, 3, 0, 0'> + <JPanel border='{BorderFactory.createTitledBorder("Model2")}' + layout='{new GridLayout()}' width='250' height='120'> + <Table anchor='west' fill='both'> + <row> + <cell> + <JLabel text='Text:'/> + </cell> + <cell weightx='1'> + <JLabel text='{model2.getText()}'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Text2:'/> + </cell> + <cell weightx='1'> + <JLabel text='{model2.getText2()}'/> + </cell> + </row> + + <row> + <cell> + <JLabel text='Ratio:'/> + </cell> + <cell> + <JLabel text='{model2.getRatio()}'/> + </cell> + </row> + </Table> + </JPanel> + </cell> + </row> + <row> + <cell weightx='1' weighty='1' insets='6, 3, 0, 0'> + <JPanel border='{BorderFactory.createTitledBorder("Identify Form")}' + layout='{new GridLayout()}' width='250' height='140'> + <Table anchor='west' fill='both'> + <row> + <cell> + <JLabel text='FirstName:'/> + </cell> + <cell weightx='1'> + <JTextField id='firstName' text='{identity.getFirstName()}' + onKeyReleased='identity.setFirstName(firstName.getText())'/> + </cell> + </row> + <row> + <cell> + <JLabel text='LastName:'/> + </cell> + <cell weightx='1'> + <JTextField id='lastName' text='{identity.getLastName()}' + onKeyReleased='identity.setLastName(lastName.getText())'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Email:'/> + </cell> + <cell weightx='1'> + <JTextField id='email2' text='{identity.getEmail()}' + onKeyReleased='identity.setEmail(email2.getText())'/> + </cell> + </row> + + <row> + <cell> + <JLabel text='Age:'/> + </cell> + <cell> + <JSlider id='age' minimum='0' maximum='100' value='{identity.getAge()}' + onStateChanged='identity.setAge(age.getValue())'/> + </cell> + </row> + </Table> + </JPanel> + </cell> + <cell weightx='1' weighty='1' insets='6, 3, 0, 0'> + <JPanel border='{BorderFactory.createTitledBorder("Identity Model")}' + layout='{new GridLayout()}' width='250' height='120'> + <Table anchor='west' fill='both'> + <row> + <cell> + <JLabel text='FirstName:'/> + </cell> + <cell weightx='1'> + <JLabel text='{identity.getFirstName()}'/> + </cell> + </row> + <row> + <cell> + <JLabel text='LastName:'/> + </cell> + <cell weightx='1'> + <JLabel text='{identity.getLastName()}'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Email:'/> + </cell> + <cell weightx='1'> + <JLabel text='{identity.getEmail()}'/> + </cell> + </row> + + <row> + <cell> + <JLabel text='Age:'/> + </cell> + <cell> + <JLabel text='{identity.getAge()}'/> + </cell> + </row> + </Table> + </JPanel> + </cell> + </row> + <row> + <cell columns='2' fill="both"> + <JPanel border='{BorderFactory.createTitledBorder("Errors")}' layout='{new GridLayout()}' height='200' + width='500'> + <JScrollPane> + <JList model='{errors}'/> + </JScrollPane> + </JPanel> + </cell> + </row> + <row> + <cell columns='2' fill="both"> + <JPanel layout='{new GridLayout(1,2,0,0)}'> + <JButton text='cancel' onActionPerformed='dispose()'/> + <JButton id='ok' text='valid' onActionPerformed='dispose()'/> + </JPanel> + </cell> + </row> + + </Table> +</Application> diff --git a/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/ok/ValidationBeanClass.jaxx b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/ok/ValidationBeanClass.jaxx new file mode 100644 index 0000000..0e37fba --- /dev/null +++ b/trunk/maven-jaxx-plugin/src/test/resources/testcases/validator/ok/ValidationBeanClass.jaxx @@ -0,0 +1,112 @@ +<Application title="Validation.jaxx"> + + <!-- models --> + <Identity id='identity'/> + + <!-- errors model --> + <jaxx.runtime.validator.swing.SwingValidatorMessageListModel id='errors'/> + + <!-- validators --> + <BeanValidator id='validator3' autoField='true' beanClass='testcases.validator.ok.Identity' errorListModel='errors'> + <field name="email" component="email2"/> + </BeanValidator> + + <Table fill='both'> + <row> + <cell weightx='1' weighty='1' insets='6, 3, 0, 0'> + <JPanel border='{BorderFactory.createTitledBorder("Identify Form")}' + layout='{new GridLayout()}' width='250' height='140'> + <Table anchor='west' fill='both'> + <row> + <cell> + <JLabel text='FirstName:'/> + </cell> + <cell weightx='1'> + <JTextField id='firstName' text='{identity.getFirstName()}' + onKeyReleased='identity.setFirstName(firstName.getText())'/> + </cell> + </row> + <row> + <cell> + <JLabel text='LastName:'/> + </cell> + <cell weightx='1'> + <JTextField id='lastName' text='{identity.getLastName()}' + onKeyReleased='identity.setLastName(lastName.getText())'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Email:'/> + </cell> + <cell weightx='1'> + <JTextField id='email2' text='{identity.getEmail()}' + onKeyReleased='identity.setEmail(email2.getText())'/> + </cell> + </row> + + <row> + <cell> + <JLabel text='Age:'/> + </cell> + <cell> + <JSlider id='age' minimum='0' maximum='100' value='{identity.getAge()}' + onStateChanged='identity.setAge(age.getValue())'/> + </cell> + </row> + </Table> + </JPanel> + </cell> + <cell weightx='1' weighty='1' insets='6, 3, 0, 0'> + <JPanel border='{BorderFactory.createTitledBorder("Identity Model")}' + layout='{new GridLayout()}' width='250' height='120'> + <Table anchor='west' fill='both'> + <row> + <cell> + <JLabel text='FirstName:'/> + </cell> + <cell weightx='1'> + <JLabel text='{identity.getFirstName()}'/> + </cell> + </row> + <row> + <cell> + <JLabel text='LastName:'/> + </cell> + <cell weightx='1'> + <JLabel text='{identity.getLastName()}'/> + </cell> + </row> + <row> + <cell> + <JLabel text='Email:'/> + </cell> + <cell weightx='1'> + <JLabel text='{identity.getEmail()}'/> + </cell> + </row> + + <row> + <cell> + <JLabel text='Age:'/> + </cell> + <cell> + <JLabel text='{identity.getAge()}'/> + </cell> + </row> + </Table> + </JPanel> + </cell> + </row> + <row> + <cell columns='2' fill="both"> + <JPanel border='{BorderFactory.createTitledBorder("Errors")}' layout='{new GridLayout()}' height='200' + width='500'> + <JScrollPane> + <JList model='{errors}'/> + </JScrollPane> + </JPanel> + </cell> + </row> + </Table> +</Application> diff --git a/trunk/pom.xml b/trunk/pom.xml new file mode 100644 index 0000000..6d0dbf7 --- /dev/null +++ b/trunk/pom.xml @@ -0,0 +1,219 @@ + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <!-- ************************************************************* --> + <!-- *** POM Relationships *************************************** --> + <!-- ************************************************************* --> + + <parent> + <groupId>org.nuiton</groupId> + <artifactId>mavenpom</artifactId> + <version>1.0.0</version> + </parent> + + <artifactId>jaxx</artifactId> + <version>1.7.1</version> + + <modules> + <module>jaxx-runtime-api</module> + <module>jaxx-runtime-swing</module> + + <module>jaxx-compiler</module> + + <module>jaxx-swing-action</module> + <module>maven-jaxx-plugin</module> + + <module>jaxx-runtime-swing-widget</module> + + <module>jaxx-example</module> + </modules> + + <dependencyManagement> + <dependencies> + + <!-- lutin dependencies --> + + <dependency> + <groupId>org.nuiton</groupId> + <artifactId>nuiton-utils</artifactId> + <version>${lutinutil.version}</version> + </dependency> + + <dependency> + <groupId>org.nuiton</groupId> + <artifactId>maven-helper-plugin</artifactId> + <version>${helper.version}</version> + <scope>compile</scope> + </dependency> + + <dependency> + <groupId>org.nuiton</groupId> + <artifactId>maven-helper-plugin</artifactId> + <version>${helper.version}</version> + <scope>test</scope> + <classifier>tests</classifier> + </dependency> + + <!-- common dependencies --> + + <dependency> + <groupId>commons-jxpath</groupId> + <artifactId>commons-jxpath</artifactId> + <version>1.3</version> + </dependency> + + <dependency> + <groupId>commons-lang</groupId> + <artifactId>commons-lang</artifactId> + <version>2.4</version> + </dependency> + + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>1.4</version> + </dependency> + + <!-- sun dependencies --> + + <dependency> + <groupId>com.sun</groupId> + <artifactId>dt</artifactId> + <version>${java.version}</version> + <scope>system</scope> + <systemPath>/${java.home}/../lib/dt.jar</systemPath> + </dependency> + + <dependency> + <groupId>javax.help</groupId> + <artifactId>javahelp</artifactId> + <version>2.0.02</version> + </dependency> + + <!-- maven dependencies --> + + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-plugin-api</artifactId> + <version>${maven.version}</version> + <scope>compile</scope> + </dependency> + + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-project</artifactId> + <version>${maven.version}</version> + <scope>compile</scope> + </dependency> + + <!-- xworks dependencies --> + + <dependency> + <groupId>com.opensymphony</groupId> + <artifactId>xwork</artifactId> + <version>2.1.3</version> + <exclusions> + <exclusion> + <groupId>org.springframework</groupId> + <artifactId>spring-test</artifactId> + </exclusion> + </exclusions> + </dependency> + + <!-- swinglabs dependencies --> + + <dependency> + <groupId>org.swinglabs</groupId> + <artifactId>jxlayer</artifactId> + <version>3.0.3</version> + </dependency> + + <dependency> + <groupId>org.swinglabs</groupId> + <artifactId>swingx</artifactId> + <version>1.0</version> + </dependency> + + <dependency> + <groupId>org.swinglabs</groupId> + <artifactId>swing-worker</artifactId> + <version>1.1</version> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.6</version> + <scope>test</scope> + </dependency> + + </dependencies> + </dependencyManagement> + + <!-- ************************************************************* --> + <!-- *** Project Information ************************************* --> + <!-- ************************************************************* --> + + <name>${project.artifactId}</name> + <description>Jaxx library parent pom</description> + <inceptionYear>2008</inceptionYear> + <url>http://maven-site.nuiton.org/jaxx</url> + + <!-- ************************************************************* --> + <!-- *** Build Settings ****************************************** --> + <!-- ************************************************************* --> + + <packaging>pom</packaging> + + <properties> + + <!-- pour un muli module on doit fixer le projectId --> + <projectId>jaxx</projectId> + + <lutinutil.version>1.1.0</lutinutil.version> + <i18n.version>1.0.0</i18n.version> + + </properties> + + <build> + + <pluginManagement> + <plugins> + + <!-- plugin i18n --> + <plugin> + <groupId>org.nuiton.i18n</groupId> + <artifactId>maven-i18n-plugin</artifactId> + <version>${i18n.version}</version> + </plugin> + + <plugin> + <artifactId>maven-site-plugin</artifactId> + <dependencies> + <dependency> + <groupId>org.nuiton.jrst</groupId> + <artifactId>doxia-module-jrst</artifactId> + <version>1.0.0</version> + </dependency> + </dependencies> + </plugin> + + </plugins> + </pluginManagement> + + </build> + + <!-- ************************************************************* --> + <!-- *** Build Environment ************************************** --> + <!-- ************************************************************* --> + + <!-- Source control management. --> + <scm> + <connection>scm:svn:http://svn.nuiton.org/svn/jaxx/tags/jaxx-1.7.1</connection> + <developerConnection>scm:svn:http://svn.nuiton.org/svn/jaxx/tags/jaxx-1.7.1</developerConnection> + <url>http://www.nuiton.org/repositories/browse/jaxx/tags/jaxx-1.7.1</url> + </scm> + +</project> diff --git a/trunk/src/site/resources/images/jrst-logo.png b/trunk/src/site/resources/images/jrst-logo.png new file mode 100644 index 0000000..8c87f9a Binary files /dev/null and b/trunk/src/site/resources/images/jrst-logo.png differ diff --git a/trunk/src/site/resources/jaxx.png b/trunk/src/site/resources/jaxx.png new file mode 100644 index 0000000..c3d68c9 Binary files /dev/null and b/trunk/src/site/resources/jaxx.png differ diff --git a/trunk/src/site/rst/BeanValidator.rst b/trunk/src/site/rst/BeanValidator.rst new file mode 100644 index 0000000..5c5c149 --- /dev/null +++ b/trunk/src/site/rst/BeanValidator.rst @@ -0,0 +1,181 @@ +------------- +BeanValidator +------------- + +.. contents:: + + +**WARNING : documentation non à jour...** + +Présentation +============ + +Ajout du support de validation dans JAXX. + +La techonologie utilisée est celle de Struts 2 (XWorks 2). + + +Configuration +============= + +La configuration des validateurs se font via des fichier xml (on peut aussi utiliser des annotations,...). + +Ajout d'un validateur +********************* + +Pour enregister un nouveau validateur sur un bean, il suffit de placer dans le même paquetage que le bean un fichier *XXX-validation.xml* où XXX est le nom non qualifié du bean. + +On peut de plus affecter un context de validation, dans ce cas le fichier doit s'appeler *XXX-YYY-validation.xml*, où YYY est le nom du context de validation. + +Ainsi on peut valider de différentes manières un bean (par exemple selon son cycle de vie :création, modification, ...). + +Ajout d'un nouveau type de validateur +************************************* + +Il est aussi possible de définir de nouveau type de validateurs : + + * créer une classe qui étend FieldValidator + * ajouter un fichier validators.xml (ou ajouter dans un tel fichier la définition du nouveau validator) à la racine du class-path. + +I18n +**** + +Afin de rendre le mécanisme multi-langue, on propose dans les fichiers de validations d'utiliser des clef i18n pour les messages. + +Un nouveau parseur dans notre plugin i18n a été ajouté pour détecter ces clefs. (*maven-i18n-plugin:0.7:parserValidation*) + + +Intégration dans JAXX +===================== + +Deux nouveaux tags ont été conçus pour pouvoir décrire un validateur dans les fichiers JAXX. + +Ce développement est dans le paquetage *jaxx.tags.validator*. + +tag BeanValidator +***************** + +Permet de définir un nouveau validateur dans une classe JAXX. + +Les attributs autorisés sont les suivants : + + * *id* : le nom du validateur + + * *bean* : l'id d'un bean connu par la classe JAXX. On ne peut pas utiliser ici une expression car on n'est pas sûr de pouvoir déterminer le type de cette expression pendant le parsing ? (a verifier). + + * *beanClass* : le FQN de classe du bean à valider. Peut-être non présent si l'attribut *bean* est renseigné. + + * *beanInitializer* : une expression pour initialiser le bean à valider. TODO a revoir : on devrait utiliser uniquement un seul attribut *bean*... + + * *contextName* : le nom du contexte de validation. + + * *autoField* : flag pour indiquer l'inscription implicite des validateurs de champs du bean. Pour ce faire on parcourt l'ensemble des champs du bean et on ne considère uniquement ceux dont on connait dans la classe JAXX un composent d'édition du champ (id=nom du champ). Il est possible de surcharger ce configuration implicite en rajoutant explicitement des champs (voir le tag *field*). + + * *errorList* : le composant graphique pour afficher la liste des erreurs, doit étendre *javax.swing.JList*. Si non présent, on essayera le component d'id *errorList*. + + * *errorListModel* : le modèle qui contient la liste des erreurs (et est liée au composant *errorList*), doit étendre *jaxx.runtime.validator.swing.SwingValidatorErrorListModel*. Si non présent on essayera le composent d'id *errorListModel*. + + * *uiClass* : le FQN de la classe utilisé pour le rendu des erreurs sur les wigets d'édition. La classe doit étendre *jaxx.runtime.validator.swing.ui.AbstractBeanValidatorUI*. Si non présent, on utilise par défaut le render *jaxx.runtime.validator.swing.ui.IconValidationUI*. + + +Le tag supporte aussi l'ajout de tag *field* comme fils pour définir explicitement des champs à validater. + +tag field +********* + +Le tag *field* définit une entrée dans le validateur, on définit une correspondance entre le champ à valider et le composant d'édition de ce champ. + +Le tag supporte les attributs suivants : + + * *name* : le nom de la propriété du bean associée. + Cet attribut est obligatoire. + + * *component* : l'id du composant graphique d'édition associé à la propriété du bean. + Cet attribut peut être omis si le nom de la propriété du bean est identique à celui du composent graphique d'édition. + + +Les classes du runtime +====================== + +Ce développement est dans le paquetage *jaxx.runtime.validator* (sauf pour l'interface *jaxx.runtime.JAXXValidator*). + +Il s'agit de l'ensemble des classes ajoutées dans le module *jaxx-core* pour encapsuler la validation dans les fichiers java générés à partir des fichiers JAXX. + + +interface jaxx.runtime.JAXXValidator +************************************ + +Ce contrat a été ajouté à tous les objets JAXX générés (donc l'interface JAXXObject étend JAXXValidator). + +On définit ici uniquement des méthodes d'accès aux validateurs enregistrés dans le JAXXObject. + +TODO on pourrait ajouter des méthodes pour savoir l'état de validation d'un validateur ? + + +classe jaxx.runtime.validator.swing.SwingValidator +************************************************** + +Il s'agit de la classe principale d'encapsulation d'un validateur XWorks 2. + +Le principe est simple : le validateur écoute les modifications sur le bean associé et revalide le bean à chaque modification. La validation met à jour la liste des erreurs asociées. + +On se base sur les PropertyChangeListener pour écouter les modification des beans. Il faut donc que les beans supporte ces listeners. + +Pour les entités de ToPIA, il suffit de positionner un contexte (topia) au bean pour profiter des listeners liés. + +Pour les DTO de ToPIA, les générateurs ont été modifiés pour gérer ce support. + +Les méthodes à retenir sont : + + * *setBean* pour affecter un bean au validateur (pour déasactiver passer null). Lors de la désactivation d'un bean, les erreurs associés sont retirées de la liste des erreurs. + + * *setContextName* pour affecter un nouveau nom de context de validation (par défaut on utilise pas de context de validation). + + * *validate* pour lancer une validation sur le bean liée (ne sera opérant uniquement si un bean est liée et qu'une liste d'erreur est liée). + + * *isValid* pour connaitre l'état du validateur à un moment donné. + +Normalement la méthode *validate* ne devrait pas être appelée directement. : elle est automatiquement invoquée lorsqu'une propriété du bean est modifiée. + +classe jaxx.runtime.validator.swing.SwingValidatorErrorModel +************************************************************ + +Modélisation d'une erreur renvoyé par le validateur, on conserve ici : + + * le validateur qui a provoqué l'erreur + + * la propriété du bean en faute + + * le composent graphique d'édtion de la propriété + +classe jaxx.runtime.validator.swing.SwingValidatorErrorListModel +**************************************************************** + +Le modèle de la liste des erreurs renvoyées par le validateur. Il s'agit d'une extension d'un *javax.swing.DefaultListModel* qui permet de gérer une liste d'erreurs provenant de plusieurs validateurs en même temps. + +classe jaxx.runtime.validator.swing.SwingValidatorErrorListMouseListener +************************************************************************ + +Un listener écoutant les double clics sur une liste d'erreurs et qui donne le focus au composent graphique d'édition associée à la propriété dont l'erreur est sélectionné. + + +Les conversions +=============== + +Pour l'édition de proriétés qui ne sont pas des chaines de caractères, des erreurs de conversions peuvent survenir (conversion de la valeur de l'édtieur graphique vers le bean), avant que l'on utilise +réellement la mécanique de la validation. + +Pour palier à ce problème on a intégré la gestion des erreurs de conversion dans le validateur. +Pour ce faire, il suffit de faire appel à la méthode suivante pour injecter dans un bean une propriété : + + :: + + jaxx.runtime.Util.convert(validator,"nomDeLaPropriété",widget.getText(),TypeDeLaProriete.class); + + +On obtiendra si une erreur de conversion intervient, une erreur dont le libellé est de la forme *error.convertor.XXX* +où XXX est nom simple en minuscule du type de la propruité. (par exemple : *error.convertor.integer*). + + + + diff --git a/trunk/src/site/rst/Core.rst b/trunk/src/site/rst/Core.rst new file mode 100644 index 0000000..44e6322 --- /dev/null +++ b/trunk/src/site/rst/Core.rst @@ -0,0 +1,154 @@ +++++ +Core +++++ + +.. contents:: + +Nouvelles fonctionnalités apportées sur les classes générées. + +--------- +Interface +--------- + +Présentation +============ + +Ajout de contrats sur le code généré dans JAXX. + +Mécanisme +========= + +Le compilateur JAXX génère des classes à partir de fichiers JAXX mais n'est pas capable d'ajouter des contrats sur +les objets générés, donc interdit en quelque sorte la programmation par contrat. + +Pour palier à cette limitation, on a ajouté un attribut spécial *implements*. + +Cette attribut ne doit être placé que sur le tag racine d'un fichier JAXX et son contenu est le nom qualifié d'un ou +plusieurs contrats séparaés par des virgules. + +:: + + <JPanel implements='java.lang.Comparable'> + + <script>public int compareTo(JPanel o) { return getName().compareTo(o.getName()); }</script> + + </JPanel> + +La classe générée aura bien le contrat *java.lang.Comparable*. + +-------- +Abstract +-------- + +Présentation +============ + +Ajout de la possibilité de générer des classes abstraites. + +Mécanisme +========= + +Ajout d'un attribut *abstract*. + +:: + + <JPanel abstract='true'/> + +La classe générée sera abstraite. + +-------- +Generics +-------- + +Présentation +============ + +Ajout de possible de type generique sur les inferfaces et superclass. + +Mécanisme +========= + +Ajout d'un attribut genericType et superGenericType. + +Exemple : (fichier Parent.jaxx) +:: + + <JPanel genericType='E' + implements='java.lang.Comparable<E>' + abstract='true' /> + +La classe générée sera de la forme : + +:: + + public abstract Parent<E> implements java.lang.Comparable<E> { + ... + } + +Pour surcharger une telle classe (fichier Son.jaxx) : + +:: + + <Parent superGenericType='String' + abstract='true'/> + +La classe générée sera de la forme : + +:: + + public Son extends Parent<String> { + ... + } + + +TODO +==== + +Permettre l'utilisation des types génériques dans les scripts. + +-------- +JavaBean +-------- + +Présentation +============ + +Ajout du support complêt des javaBean dans JAXX. + +Mécanisme +========= + +Il est possible dans JAXX de rajouter des objets quelconques via leur nom qualifié de classe : + +:: + + <JPanel> + <java.lang.Boolean id='myState' constructorParams='true'/> + <JLabel text='text' visible='{isMySate()}'/> + </JPanel> + +Avant l'ajout de la fonctionnalité, le code généré possèdait : + + * une propriété en lecture seul nommé *myState*. + +Aucun support javaBean n'était présent et le databinding sur la propriété *visible* du label n'est pas créé. Cela veut +dire que le label sera initialisé avec la valeur initiale du boolean et c'est tout... + +Avec l'ajout du support javaBean, on peut maintenant faire ces bindings, pour ce faire il suffit d'ajouter un attribut +*javaBean* sur l'objet : + +:: + + <JPanel> + <java.lang.Boolean id='myState' javaBean='true'/> + <JLabel text='text' visible='{isMySate()}'/> + </JPanel> + +On aura donc en plus : + + * un mutateur sur la propriété *myState* qui déclanchera l'envoie d'un *PropertyChange* sur la propriété lors de modification de valeur. + +Ainsi le compilateur JAXX sera capable d'enregistrer un novueau dataBindig sur la propriété *visible* du label et la +modification de l'état *myState* sera automatiquement répercuté sur la propriété. + +Note: le contenu de l'attribut *javaBean* est l'initialiteur de la propriété. \ No newline at end of file diff --git a/trunk/src/site/rst/I18n.rst b/trunk/src/site/rst/I18n.rst new file mode 100644 index 0000000..8ddfc0f --- /dev/null +++ b/trunk/src/site/rst/I18n.rst @@ -0,0 +1,56 @@ +---- +I18n +---- + +.. contents:: + + +Présentation +============ + +Ajout du support i18n dans JAXX. + +On utilise la système i18n développé dans la librairie des lutins (*lutinlib*). + +Configuration +============= + +Une option a été ajoutée dans le plugin maven de JAXX : *i18nable* pour permettre ou non l'utilisation de ce système. + +Par défaut, l'option est active (donc aucune configuration supplémentaire n'est nécessaire pour utiliser i18n dans JAXX). + + +Fonctionnement +============== + +Le fonctionnement est simple : lors de la compilation JAXX, lorsque l'on rencontre certains attributs on encapsule la +valeur de l'attribution par un appel à la méthode + +:: + + org.nuiton.i18n.I18n._(String) + + +La liste des attributs en question sont les suivants : + + - title + - text + - toolTipText + + +Ensuite l'utilisation du *parserJava* du plugin i18n permet la détection des clefs i18n. + + +Pourquoi ne plus utiliser l'ancien parserJaxx du plugin i18n +============================================================ + +Un parseur avait été développé initialement pour détecter dans les fichiers JAXX (*parserJaxx*), les appels à la méthode de traduction +i18n dans les attributs. + +Ce parseur n'est plus d'actualité car on ne doit plus avoir d'appel explicite à cette méthode dans les fichiers JAXX. + +De plus, même sans avoir mis en place le mécanisme i18n dans JAXX, ce parseur n'était plus d'actualité : il se base +sur une liste prédéfinie d'attributs xml à scanner pour détecter des appels i18n; ce qui n'était pas acceptable à terme +car si on ajoute un nouveau composent dans JAXX, le plugin i18n n'est pas capable de détecter les nouvelles clefs. + +Donc on préconise l'utilisation du *parserJava* du plugin i18n qui lui est capable de détecter tous les appels i18n. diff --git a/trunk/src/site/rst/JAXXContext.rst b/trunk/src/site/rst/JAXXContext.rst new file mode 100644 index 0000000..465f8fd --- /dev/null +++ b/trunk/src/site/rst/JAXXContext.rst @@ -0,0 +1,161 @@ +----------- +JAXXContext +----------- + +.. contents:: + + +Présentation +============ + +Ajout d'un context applicatif dans JAXX. + +Le besoin initial de ce développement est de pouvoir facilement intégrer un context applicatif dans JAXX et de pouvoir +l'utiliser dans les fichiers JAXX pour injecter par exemple des données dans les widgets. + +jaxx.runtime.JAXXContext +======================== + +Il s'agit du contrat de base du context applicatif. + +Les entrées dans le context +*************************** + +Chaque donnée utilisable dans le context est caractérisée par deux propriétés : + + * la type de l'objet + + * un nom (facultatif) associé à la donnée + +Le type de l'objet correspondant en fait à la classe de la donnée. + +Le nom qui est facultatif permet de pouvoir distinguer plusieurs données d'un même type dans le context. Si le nom +n'est pas utilisé pour caractériser une données on fixera alors sa valeur à *null*. + +Afin de pouvoir caractériser les entrées dans le context, une classe a été définie *jaxx.runtime.JAXXContextEntryDef*. + +Les méthodes de lecture +*********************** + +On a définit deux méthodes de lecture de données dans le context : + + * *getContextValue(Class)* récupère la donnée *non nommée* dont le type correspond à celui passé. + + * *getContextValue(Class,String)* récupère la donnée nommé dont le type correspond à celui passé. + +Les méthodes d'écriture +*********************** + +On a définit quatre méthodes d'écriture de données dans le context : + + * *setContextValue(Object)* enregistre dans le context la donnée *non nommée*. + + * *setContextValue(Object,String)* enregistre dans le context la donnée *nommée*. + + * *removeContextValue(Class)* supprime du context, la donnée *non nommée* dont le type est passé. + + * *removeContextValue(Class, String)* supprime du context, la donnée *nommée* dont le type est passé. + +Afin de pouvoir assurer une cohérence dans le context, chaque injection de donnée, sera toujours précédée par une +suppression d'un éventuellement ancienne valeur qui aurait la même définition d'entrée. + +L'héritage +********** + +Il est possible d'avoir une hériarchie de context qui s'enchaînent. Ce mécanisme a été mis en place pour répondre à un +besion précis : chaque fichier JAXX donne lieu à une nouvelle classe qui possède son propre context. + +On peut avoir des fichiers JAXX qui utilisent d'autres fichiers JAXX, il faut donc être capable de lier le context du +composent parent avec ses fils. + +La mise en place de l'héritage est transparente pour l'utilisateur : aucune méthode supplémentaire n'est requise. + +Les implantations de context +============================ + +jaxx.runtime.DefaultJAXXContext +******************************* + +Il s'agit de l'implantation par défaut utilisée par les objects *JAXXObject* (objets générés). + +A noter que pour les opérations d'injection ou de suppression, on effectuera les opérations sur le context qui contient +réellement la donnée, ce qui est important pour conserver la cohérence des contexts dans les contexts chaînés. + +Pour traiter le context parent, aucune méthode publique supplémentaire n'a été rajoutée, il suffit d'injecter un objet +de type *JAXXContext* *non nommé* qui le context courant qui sera détecté comme une entrée de type context. + +Cette entrée spéciale ne sera pas stockée avec les autres entrées afin d'optimiser les algorithmes d'injection et de +restitution. + +jaxx.runtime.JAXXInitialContext +******************************* + +On a implanté un second type de context qui lui peut servir à l'initialisation des JAXXObject. + +Ce second type de context ajoute des méthodes pour préparer le context avant l'instanciation des JAXXObject. + +Ce context admet certaine limitation (pas de suppression dans le context), et apporte trois nouvelles méthodes : + + * add(Object) : injecte dans le context une entrée non nommée et retourne l'instance du context. + + * add(String,Object) : injecte dans le context une entrée nommé et retourne l'instance du context. + + * to(JAXXContext) : injecte dans le context passé toutes les entrée du context. + +Les méthodes *add* peuvent être chaînées comme dans l'exemple suivant : + +:: + + JAXXInitialContext context = new JAXXInitialContext().add("string").add(0).add("currentDate",new Date()); + + +Intégration dans les JAXXObject +=============================== + +Le traitement d'un fichier JAXX donne lieu à une classe qui possède le contrat *jaxx.runtime.JAXXObject*. + +Ce contrat hérite donc du contrat *JAXXContext* (afin de pouvoir l'utiliser de manière transparente dans les fichiers JAXX). + +Afin de simplifier la génération et les évolutions du context indépendemment des évolutions des JAXXObject, on utilise +un pattern de délégation au sein des object générés. + +Paramétrage de l'implantation du context +**************************************** + +Une propriété a été rajoutée sur le plugin JAXX, afin de pouvoir préciser l'implantation de context à utiliser : + +:: + + jaxx.jaxxContextImplementorClass + +Il s'agit du nom qualifié de la classe d'implantation à utiliser. + +Par défaut, si rien n'est renseigné, on utilisera un *jaxx.runtime.DefaultJAXXContext*. + + +Initialisation d'un JAXXObject +****************************** + +Un nouveau constructeur a été ajouté dans les JAXXObjet générés afin de pouvoir facilement initialisé un tel objet à +partir d'un context parent, son unique paramètre est le context parent. Ce constructeur est capable de différencer le +type de context passé : + + * s'il s'agit d'un *JAXXInitialContext*, on recopie alors dans le context réel de l'objet toutes les entrées du context passé. + + * sinon le context passé est simplement injecté dans le context de l'objet (et donc sera utilisé comme le context parent de celui de l'objet). + +Voici un exemple d'initialisation d'un JAXXObject : + +:: + + java.util.Date currentDate = new java.util.Date(); + JAXXInitialContext context = new JAXXInitialContext().add("string").add(0).add("currentDate",currentDate); + JAXXObject ui = new MyUI(context); + + assert "string".equals(myUI.getContextValue(String.class)); + assert 0 == myUI.getContextValue(Integer.class); + assert currentDate.equals(myUI.getContextValue(java.util.Date.class,"currentDate")); + +A noter, que l'initialisation du context d'un *JAXXObject* sera toujours effectuée avant la méthode *$initialize* générée +par le compilateur JAXX, ce qui permet de pouvoir utiliser le context pour l'initialisation des widgets dans les fichiers JAXX. + diff --git a/trunk/src/site/rst/NavigationTreeModel.rst b/trunk/src/site/rst/NavigationTreeModel.rst new file mode 100644 index 0000000..efeee0e --- /dev/null +++ b/trunk/src/site/rst/NavigationTreeModel.rst @@ -0,0 +1,169 @@ +------------------- +NavigationTreeModel +------------------- + +.. contents:: + +**WARNING : documentation non à jour...** + +Présentation +============ + +Ajout d'un modèle d'arbre de navigation. + +Le but de cette fonctionnalité est de pouvoir créer un arbre de navigation lié au context de JAXX, de définir des UI +rattachés à chaque noeud. + +Le développement est effectué dans le paquetage *jaxx.runtime.swing.navigation*. + +jaxx.runtime.swing.navigation.NavigationTreeModel +================================================= + +Il s'agit du modèle de l'arbre utilisé, c'est une extension d'un *javax.swing.tree.DefaultTreeModel*. + +Les noeuds présents dans ce modèle sont aussi typés en *jaxx.runtime.swing.navigation.NavigationTreeModel.NavigationTreeNode*. + +L'idée principale est de pouvoir associer à un noeud précis un chemin depuis la racine, ce que l'on appele *chemin de navigation*. + +Pour obtenir le chemin de navigation d'un noeud donné, on récupère l'enmseble des neoud depuis la racine vers ce noeud +et les concatène en suffixant par le caractère séparateur défini. + +Définition d'un noeud +===================== + +Le noeud (*jaxx.runtime.swing.navigation.NavigationTreeModel.NavigationTreeNode*) est une extension d'un *javax.swing.tree.DefaultMutableTreeNode*. + +Il apporte les nouvelles propriétés suivantes : + + * *navigationPAth* : nom de chemin de navigation de ce noeud. + + * *jaxxClass* : nom qualifié de la classe d'ui associé à ce noeud (doit être obligatoirement un *JAXXObject*) + + * *jaxxActionClass* : nom qualifié de la classe d'handler d'ui associé à ce noeud (doit être obligatoirement un *JAXXAction*). + + * *jaxxContextEntryDef* : définition de l'entrée dans le context JAXX associé à ce noeud. + + * *jaxxContextEntryJXPath* : définition d'une expression JXPath à appliquer sur le bean associé au noeud. + + +Retrouver un noeud à partir du chemin de navigation +*************************************************** + +Il est possible en connaissant le chemin de navigation d'un noued de récupérer le noeud dans l'arbre via la méthode + +:: + + model.findNode("chemin.de.navigation") + +Trouver la valeur associée dans le context JAXX à partir du chemin de navigation +******************************************************************************** + +Il est possible en connaissant le chemin de navigation d'un noued de récupérer la valeur associée dans le context JAXX. + +:: + + model.getJAXXContextValue(myJAXXContext, "chemin.de.navigation")* . + +L'algrotihme est le suivant : + + * récupération du noeud associé au chemin de navigation + + * recherche du premier noeud (dans les noeuds qui remontent vers la racine de l'arbre) dont la propriété *jaxxContextEntry* est non nulle, il s'agit du point d'entré dans le context JAXX. + + * redescendre à partir de ce noeud vers le noeud d'origine (si ce noeud était différent) et en descendant conjointement dans l'objet du context JAXX : + + - on utilise l'expression JXPath pour obtenir l'objet associé au noeud + +Exemple : + +:: + + "$root" + <-- la racine de l'abre + | + + "string" <-- attaché au context JAXX <java.lang.String,"string"> + | + + "liste" + <-- attaché au context JAXX <java.util.List.class,"liste"> + | | + | + "0" <-- le premier élément de la liste + | | + | + "1" <-- le second élément de la liste + | | + | + "2" <-- le troisième élément de la liste + | + + "locale" + <-- attaché au context JAXX <java.util.Locale> + | + + country + | + + language + + // preparation du context + java.util.List myList = java.util.Arrays.asList("one","two","three"); + java.util.Locale myLocale = java.util.Locale.FRENCH; + context.setContextValue(myList, "liste"); + context.setContextValue("stringValue","string"); + context.setContextValue(myLocale); + + + // récupération des valeurs dans le context à partir de chemin de navigation + assert model.getJAXXContextValue(context, "$root") == null; + assert model.getJAXXContextValue(context, "$root.string") == "stringValue"; + assert model.getJAXXContextValue(context, "$root.liste") == myList; + assert model.getJAXXContextValue(context, "$root.liste.0") == "one"; + assert model.getJAXXContextValue(context, "$root.liste.1") == "two"; + assert model.getJAXXContextValue(context, "$root.liste.2") == "three"; + assert model.getJAXXContextValue(context, "$root.locale") == myLocale; + assert model.getJAXXContextValue(context, "$root.locale.country") == myLocale.getCountry(); + assert model.getJAXXContextValue(context, "$root.locale.language") == myLocale.getLanguage(); + +TODO mettre à jour cet exemple suite à l'utilisation de JXPath pour naviguer dans les objets. + +A noter qu'une seconde méthode de récupération de valeur du context JAXX est disponible pour pouvoir récupérer cette +valeur en connaissant le noeud : + +:: + + model.getJAXXContextValue(context, myNode); + +jaxx.runtime.swing.navigation.NavigationTreeSelectionAdapter +============================================================ + +Il s'agit d'un listener sur la sélection d'un noeud dans l'arbre de navigation basé sur notre modèle de navigation. Il +étend *javax.swing.event.TreeSelectionListener*. + +Ce listener contient la gestion de passage d'un noeud à un autre avec interaction avec le context JAXX et affichage automatique de l'ui associé au noeud sélectionné. + +**Attention : la mécanique ne fonctionne que pour un arbre à selection unique.** + +Algorithme +********** + +Voici l'algorithme utilisé lors de la sélection d'un nouveau noeud : + + * *closeUI* : tentative de fermeture de l'ui lié au noeud précédemment selectionné, si cela n'aboutit pas on retourne sur le noeud précédent. + + * *attachBeanFromNodeToContext* : injection dans le context JAXX de la valeur associée au nouveau noeud + + * *createUI* : création de la nouvelle ui (si elle n'existe pas) + + * *openUI* : ouverture de la nouvelle ui + +Si une erreur survient lors de ces opérations, on entre dans la méthode *goBackToPreviousNode* qui est abstraite et permet de notifier les erreur de retourner au noeud précdent. + +jaxx.runtime.swing.navigation.NavigationTreeSelectionAdapterWithCardLayout +************************************************************************** + +Il s'agit d'une implantation du listener précédent qui suppose que les uis associées aux noeuds sont affichées dans un +unique container en utilisant le layout *jaxx.runtime.swing.CardLayout2*. + +La contrainte de chaque ui sera extactement le chemin de navigation du noeud associé. + +Il possède deux méthodes abstraites : + + * *getContentContainer* : qui indique le container d'ui. + + * *getContentLayout* : qui indique le layout utilisé. + +Pour pouvoir utilisé cet *adapter*, il vous suffit de définir la méthode suivante (en plus des deux méthodes abstraites) : + + * *goBackToPreviousNode* : comment gérer les erreurs et retourner au noeud précedent. + diff --git a/trunk/src/site/rst/Todo.rst b/trunk/src/site/rst/Todo.rst new file mode 100644 index 0000000..58db111 --- /dev/null +++ b/trunk/src/site/rst/Todo.rst @@ -0,0 +1,8 @@ +==== +TODO +==== + + - mettre à jour les documentations techniques et utilisateur. + + - enrichir les démos. + \ No newline at end of file diff --git a/trunk/src/site/rst/index.rst b/trunk/src/site/rst/index.rst new file mode 100644 index 0000000..b942a10 --- /dev/null +++ b/trunk/src/site/rst/index.rst @@ -0,0 +1,46 @@ +jaxx-core +========= + +.. contents:: + + +Présentation +------------ + +Le projet Jaxx. + +Depuis la version 1.0, et en prévision de nouveaux générateurs s'appuyant sur Jaxx,on a revu l'architecture du projet. + +Désormais, une séparation a été effectuée entre le code de compilation et le code d'exécution. + +Tout le code de compilation est en dépendance du plugin maven et vous ne devriez pas à avoir à vous en servir. + +Ce dont vous avez besoin dans vos dépendances sont uniquement les modules jaxx-runtime-xxx. + +TODO A finir la présentation de la nouvelle architecture (dans la version 1.2). + +**Veuillez consulter la JavaDoc pour de plus ample détails sur les différentes +librairies.** + +Nouvelles fonctionnalités +------------------------- + + * Core_ + + * I18n_ + + * JAXXContext_ + + * BeanValidator_ + + * NavigationTreeModel_ + +.. _Core: Core.html + +.. _I18n: I18n.html + +.. _JAXXContext: JAXXContext.html + +.. _BeanValidator: BeanValidator.html + +.. _NavigationTreeModel: NavigationTreeModel.html diff --git a/trunk/src/site/site.xml b/trunk/src/site/site.xml new file mode 100644 index 0000000..1e28d41 --- /dev/null +++ b/trunk/src/site/site.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project name="${project.name}"> + + <bannerLeft> + <name>${project.name}</name> + <src>${site.home.url}/jaxx.png</src> + <href>index.html</href> + </bannerLeft> + + <poweredBy> + <logo href="http://maven.apache.org" name="Maven" img="${project.url}/images/logos/maven-feather.png"/> + <logo href="http://jrst.labs.libre-entreprise.org" name="JRst" img="${project.url}/images/jrst-logo.png"/> + <logo href="http://docutils.sourceforge.net/rst.html" name="ReStructuredText" img="${project.url}/images/restructuredtext-logo.png"/> + </poweredBy> + + <body> + <links> + <item name="original JAXX" href="http://buix.labs.libre-entreprise.org/original-jaxx"/> + </links> + + <breadcrumbs> + <item name="${project.name}" href="${project.url}" /> + </breadcrumbs> + + <menu name="Utilisateur"> + <item name="Accueil" href="index.html"/> + </menu> + + <menu name="Développeur"> + <item name="A faire" href="Todo.html"/> + </menu> + + <menu ref="modules"/> + + <menu ref="reports"/> + </body> +</project> -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.
This is an automated email from the git hooks/post-receive script. New commit to annotated tag v1.7.1 in repository jaxx. See https://gitlab.nuiton.org/nuiton/jaxx.git commit ef6ee08492e8bdc2a9e78b29af34ec15efe54197 Author: Tony Chemit <chemit@codelutin.com> Date: Mon Aug 24 10:03:02 2009 +0000 fix mavenpom... --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0fa460e..920a9f6 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ <parent> <groupId>org.nuiton</groupId> <artifactId>mavenpom</artifactId> - <version>1.0.0-rc-4</version> + <version>1.0.0</version> </parent> <artifactId>jaxx</artifactId> -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.
This is an automated email from the git hooks/post-receive script. New commit to annotated tag v1.7.1 in repository jaxx. See https://gitlab.nuiton.org/nuiton/jaxx.git commit afc92c822c3fffed8a4e929f725351b523a5a9af Author: Tony Chemit <chemit@codelutin.com> Date: Mon Aug 24 10:21:25 2009 +0000 fix pom... --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 920a9f6..594615b 100644 --- a/pom.xml +++ b/pom.xml @@ -172,8 +172,8 @@ <!-- pour un muli module on doit fixer le projectId --> <projectId>jaxx</projectId> - <lutinutil.version>1.1.0-rc-8</lutinutil.version> - <i18n.version>1.0.0-rc-4</i18n.version> + <lutinutil.version>1.1.0</lutinutil.version> + <i18n.version>1.0.0</i18n.version> </properties> -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.
This is an automated email from the git hooks/post-receive script. New commit to annotated tag v1.7.1 in repository jaxx. See https://gitlab.nuiton.org/nuiton/jaxx.git commit dd03db66a2bd680fa71f3dc97aed37a17f109b20 Merge: afc92c8 de1aac7 Author: Tony Chemit <chemit@codelutin.com> Date: Tue Aug 25 20:12:25 2009 +0000 [maven-scm] copy for tag jaxx-1.7.1 jaxx-compiler/src/main/java/jaxx/ClassMap.java | 1 + jaxx-compiler/src/site/site.xml | 13 - jaxx-example/pom.xml | 11 +- jaxx-example/src/site/site.xml | 17 +- jaxx-runtime-api/src/site/site.xml | 13 - jaxx-runtime-swing-widget/pom.xml | 2 + .../main/java/jaxx/runtime/swing/AboutPanel.jaxx | 32 +- .../main/java/jaxx/runtime/swing/ClockWidget.jaxx | 24 +- .../java/jaxx/runtime/swing/EntityComboBox.jaxx | 25 +- .../jaxx/runtime/swing/EntityComboBoxHandler.java | 20 +- .../java/jaxx/runtime/swing/ErrorDialogUI.jaxx | 22 + .../jaxx/runtime/swing/MemoryStatusWidget.jaxx | 26 +- .../jaxx/runtime/swing/StatusMessagePanel.jaxx | 22 + .../runtime/swing/StatusMessagePanelHandler.java | 18 + .../jaxx/runtime/swing/editor/ColumnSelector.jaxx | 0 .../java/jaxx/runtime/swing/editor/I18nEditor.jaxx | 24 +- .../jaxx/runtime/swing/editor/NumberEditor.jaxx | 53 +- .../runtime/swing/editor/NumberEditorHandler.java | 18 + .../runtime/swing/editor/NumberEditorPopup.css | 18 + .../java/jaxx/runtime/swing/editor/TimeEditor.css | 20 +- .../java/jaxx/runtime/swing/editor/TimeEditor.jaxx | 22 + .../runtime/swing/editor/TimeEditorHandler.java | 18 + .../swing/editor/config/ConfigCategoryUI.css | 0 .../swing/editor/config/ConfigCategoryUI.jaxx | 0 .../swing/editor/config/ConfigTableEditor.java | 0 .../swing/editor/config/ConfigTableRenderer.java | 0 .../jaxx/runtime/swing/editor/config/ConfigUI.css | 0 .../jaxx/runtime/swing/editor/config/ConfigUI.jaxx | 0 .../swing/editor/config/ConfigUIBuilder.java | 0 .../swing/editor/config/model/CategoryModel.java | 0 .../editor/config/model/ConfigTableModel.java | 0 .../swing/editor/config/model/ConfigUIModel.java | 0 .../swing/editor/config/model/OptionModel.java | 0 .../jaxx-runtime-swing-widget-en_GB.properties | 69 +- .../jaxx-runtime-swing-widget-fr_FR.properties | 70 +- .../main/resources/icons/action-config-quit.png | Bin .../main/resources/icons/action-config-reset.png | Bin .../main/resources/icons/action-config-save.png | Bin jaxx-runtime-swing-widget/src/site/site.xml | 13 - .../src/main/java/jaxx/runtime/SwingUtil.java | 22 + .../jaxx/runtime/swing/I18nTableCellRenderer.java | 10 + .../jaxx/runtime/swing/editor/ClassCellEditor.java | 0 .../jaxx/runtime/swing/editor/LocaleEditor.java | 1 - .../jaxx/runtime/swing/wizard/WizardModel.java | 8 +- .../jaxx/runtime/swing/wizard/WizardUILancher.java | 8 +- .../java/jaxx/runtime/swing/wizard/WizardUtil.java | 64 +- jaxx-runtime-swing/src/site/site.xml | 13 - jaxx-swing-action/src/site/site.xml | 13 - maven-jaxx-plugin/pom.xml | 12 - maven-jaxx-plugin/src/site/site.xml | 17 +- pom.xml | 13 +- src/site/site.xml | 17 +- trunk/LICENSE.txt | 166 - trunk/README.txt | 2 - trunk/changelog.txt | 41 - trunk/jaxx-compiler/LICENSE.txt | 166 - trunk/jaxx-compiler/README.txt | 2 - trunk/jaxx-compiler/changelog.txt | 120 - trunk/jaxx-compiler/pom.xml | 54 - .../jaxx-compiler/src/main/java/jaxx/ClassMap.java | 96 - .../src/main/java/jaxx/CompilerException.java | 52 - .../src/main/java/jaxx/DefaultInitializer.java | 52 - .../src/main/java/jaxx/PrintTagInfo.java | 118 - .../src/main/java/jaxx/ScriptException.java | 45 - .../src/main/java/jaxx/SwingInitializer.java | 127 - .../java/jaxx/UnsupportedAttributeException.java | 49 - .../main/java/jaxx/UnsupportedTagException.java | 45 - .../src/main/java/jaxx/beaninfos/BeanInfoUtil.java | 36 - .../compiler/BoxedCompiledObjectDecorator.java | 27 - .../main/java/jaxx/compiler/CompiledObject.java | 638 -- .../jaxx/compiler/CompiledObjectDecorator.java | 76 - .../main/java/jaxx/compiler/CompilerOptions.java | 406 - .../src/main/java/jaxx/compiler/DataBinding.java | 92 - .../src/main/java/jaxx/compiler/DataSource.java | 454 - .../compiler/DefaultCompiledObjectDecorator.java | 128 - .../src/main/java/jaxx/compiler/EventHandler.java | 61 - .../src/main/java/jaxx/compiler/Generator.java | 14 - .../compiler/HelpRootCompiledObjectDecorator.java | 93 - .../src/main/java/jaxx/compiler/I18nHelper.java | 70 - .../src/main/java/jaxx/compiler/JAXXCompiler.java | 1550 --- .../java/jaxx/compiler/JAXXCompilerLaunchor.java | 451 - .../java/jaxx/compiler/JAXXObjectGenerator.java | 598 -- .../src/main/java/jaxx/compiler/JAXXProfile.java | 240 - .../src/main/java/jaxx/compiler/JavaArgument.java | 86 - .../src/main/java/jaxx/compiler/JavaField.java | 187 - .../src/main/java/jaxx/compiler/JavaFile.java | 344 - .../src/main/java/jaxx/compiler/JavaMethod.java | 499 - .../main/java/jaxx/compiler/ScriptInitializer.java | 20 - .../src/main/java/jaxx/compiler/ScriptManager.java | 336 - .../src/main/java/jaxx/compiler/SwingCompiler.java | 73 - .../main/java/jaxx/compiler/SwingGenerator.java | 26 - .../src/main/java/jaxx/compiler/SymbolTable.java | 56 - .../java/jaxx/compiler/ValidatorGenerator.java | 89 - trunk/jaxx-compiler/src/main/java/jaxx/css/CSS.jj | 587 -- trunk/jaxx-compiler/src/main/java/jaxx/css/CSS.jjt | 256 - .../src/main/java/jaxx/css/CSSParser.java | 799 -- .../src/main/java/jaxx/css/CSSParserConstants.java | 72 - .../main/java/jaxx/css/CSSParserTokenManager.java | 1152 --- .../main/java/jaxx/css/CSSParserTreeConstants.java | 40 - .../src/main/java/jaxx/css/JJTCSSParserState.java | 123 - .../jaxx-compiler/src/main/java/jaxx/css/Node.java | 51 - .../src/main/java/jaxx/css/ParseException.java | 20 - .../src/main/java/jaxx/css/SimpleCharStream.java | 398 - .../src/main/java/jaxx/css/SimpleNode.java | 122 - .../src/main/java/jaxx/css/StylesheetHelper.java | 563 -- .../src/main/java/jaxx/css/Token.java | 76 - .../src/main/java/jaxx/css/TokenMgrError.java | 126 - .../jaxx/introspection/JAXXBeanDescriptor.java | 14 - .../main/java/jaxx/introspection/JAXXBeanInfo.java | 36 - .../jaxx/introspection/JAXXEventSetDescriptor.java | 39 - .../jaxx/introspection/JAXXFeatureDescriptor.java | 55 - .../java/jaxx/introspection/JAXXIntrospector.java | 176 - .../jaxx/introspection/JAXXPropertyDescriptor.java | 96 - .../main/java/jaxx/parser/JJTJavaParserState.java | 123 - .../src/main/java/jaxx/parser/Java1.5.jj | 5125 ---------- .../src/main/java/jaxx/parser/Java1.5.jjt | 2150 ---- .../src/main/java/jaxx/parser/JavaCharStream.java | 530 - .../src/main/java/jaxx/parser/JavaParser.java | 10048 ------------------- .../main/java/jaxx/parser/JavaParserConstants.java | 260 - .../java/jaxx/parser/JavaParserTokenManager.java | 2072 ---- .../java/jaxx/parser/JavaParserTreeConstants.java | 230 - .../src/main/java/jaxx/parser/Node.java | 51 - .../src/main/java/jaxx/parser/ParseException.java | 214 - .../src/main/java/jaxx/parser/SimpleNode.java | 135 - .../src/main/java/jaxx/parser/Token.java | 79 - .../src/main/java/jaxx/parser/TokenMgrError.java | 126 - .../main/java/jaxx/reflect/ClassDescriptor.java | 166 - .../java/jaxx/reflect/ClassDescriptorLoader.java | 431 - .../main/java/jaxx/reflect/FieldDescriptor.java | 27 - .../src/main/java/jaxx/reflect/JavaFileParser.java | 230 - .../main/java/jaxx/reflect/MemberDescriptor.java | 40 - .../main/java/jaxx/reflect/MethodDescriptor.java | 54 - .../src/main/java/jaxx/spi/Initializer.java | 15 - .../java/jaxx/tags/DefaultComponentHandler.java | 322 - .../main/java/jaxx/tags/DefaultObjectHandler.java | 1184 --- .../src/main/java/jaxx/tags/ScriptHandler.java | 81 - .../src/main/java/jaxx/tags/StyleHandler.java | 180 - .../src/main/java/jaxx/tags/TagHandler.java | 46 - .../src/main/java/jaxx/tags/TagManager.java | 479 - .../java/jaxx/tags/swing/ApplicationHandler.java | 41 - .../src/main/java/jaxx/tags/swing/CellHandler.java | 154 - .../jaxx/tags/swing/CompiledItemContainer.java | 53 - .../java/jaxx/tags/swing/EnumEditorHandler.java | 56 - .../src/main/java/jaxx/tags/swing/ItemHandler.java | 144 - .../main/java/jaxx/tags/swing/JAXXTabHandler.java | 28 - .../java/jaxx/tags/swing/JCheckBoxHandler.java | 25 - .../java/jaxx/tags/swing/JComboBoxHandler.java | 62 - .../jaxx/tags/swing/JInternalFrameHandler.java | 54 - .../main/java/jaxx/tags/swing/JListHandler.java | 64 - .../main/java/jaxx/tags/swing/JMenuHandler.java | 26 - .../jaxx/tags/swing/JPasswordFieldHandler.java | 25 - .../java/jaxx/tags/swing/JPopupMenuHandler.java | 31 - .../java/jaxx/tags/swing/JProgressBarHandler.java | 26 - .../java/jaxx/tags/swing/JRadioButtonHandler.java | 81 - .../java/jaxx/tags/swing/JScrollPaneHandler.java | 41 - .../main/java/jaxx/tags/swing/JSliderHandler.java | 45 - .../main/java/jaxx/tags/swing/JSpinnerHandler.java | 92 - .../java/jaxx/tags/swing/JSplitPaneHandler.java | 69 - .../java/jaxx/tags/swing/JTabbedPaneHandler.java | 135 - .../jaxx/tags/swing/JTextComponentHandler.java | 70 - .../main/java/jaxx/tags/swing/JToolBarHandler.java | 38 - .../main/java/jaxx/tags/swing/JTreeHandler.java | 69 - .../main/java/jaxx/tags/swing/JWindowHandler.java | 61 - .../java/jaxx/tags/swing/LocaleEditorHandler.java | 56 - .../src/main/java/jaxx/tags/swing/RowHandler.java | 85 - .../src/main/java/jaxx/tags/swing/TabHandler.java | 175 - .../main/java/jaxx/tags/swing/TableHandler.java | 124 - .../jaxx/tags/validator/BeanValidatorHandler.java | 734 -- .../validator/ExcludeFieldValidatorHandler.java | 85 - .../jaxx/tags/validator/FieldValidatorHandler.java | 78 - .../jaxx/tags/validator/ValidatorInitializer.java | 22 - .../tools/jaxxcapture/AbstractContextNode.java | 17 - .../jaxx/tools/jaxxcapture/CapturedObject.java | 146 - .../java/jaxx/tools/jaxxcapture/ContextNode.java | 7 - .../java/jaxx/tools/jaxxcapture/JAXXCapture.java | 404 - .../java/jaxx/tools/jaxxcapture/LiteralNode.java | 20 - .../java/jaxx/tools/jaxxcapture/MethodNode.java | 19 - .../java/jaxx/tools/jaxxcapture/PropertyNode.java | 19 - .../java/jaxx/tools/jaxxcapture/ValueNode.java | 14 - .../jaxxcapture/handlers/JTabbedPaneHandler.java | 25 - .../tools/jaxxcapture/handlers/ObjectHandler.java | 323 - .../tools/jaxxcapture/handlers/TableHandler.java | 12 - .../src/main/java/jaxx/types/ColorConverter.java | 35 - .../jaxx/types/GridBagConstraintsConverter.java | 22 - .../src/main/java/jaxx/types/InsetsConverter.java | 37 - .../main/java/jaxx/types/KeyStrokeConverter.java | 22 - .../main/java/jaxx/types/PrimitiveConverter.java | 78 - .../src/main/java/jaxx/types/TypeConverter.java | 11 - .../src/main/java/jaxx/types/TypeManager.java | 45 - .../META-INF/services/jaxx.compiler.Generator | 3 - .../META-INF/services/jaxx.spi.Initializer | 3 - trunk/jaxx-compiler/src/site/rst/BeanValidator.rst | 181 - trunk/jaxx-compiler/src/site/rst/I18n.rst | 56 - trunk/jaxx-compiler/src/site/rst/Interface.rst | 38 - trunk/jaxx-compiler/src/site/rst/JAXXContext.rst | 161 - trunk/jaxx-compiler/src/site/rst/JavaBean.rst | 50 - .../src/site/rst/NavigationTreeModel.rst | 168 - trunk/jaxx-compiler/src/site/rst/Todo.rst | 15 - trunk/jaxx-compiler/src/site/rst/index.rst | 41 - trunk/jaxx-compiler/src/site/site.xml | 25 - .../test/java/jaxx/beaninfos/BeanIntoUtilTest.java | 34 - .../test/java/jaxx/junit/ClassDescriptorTest.java | 63 - .../test/java/jaxx/junit/ColorConverterTest.java | 51 - .../test/java/jaxx/junit/InsetsConverterTest.java | 50 - .../test/java/jaxx/junit/JavaFileParserTest.java | 57 - .../src/test/java/jaxx/junit/JavaMethodTest.java | 52 - .../java/jaxx/junit/PrimitiveConverterTest.java | 113 - .../src/test/java/jaxx/junit/TagManagerTest.java | 143 - .../swing/navigation/NavigationTreeModelTest.java | 394 - .../src/test/resources/log4j.properties | 8 - trunk/jaxx-example/LICENSE.txt | 166 - trunk/jaxx-example/README.txt | 2 - trunk/jaxx-example/changelog.txt | 18 - trunk/jaxx-example/pom.xml | 294 - .../main/java/jaxx/demo/BaseBeanDataBinding.jaxx | 21 - .../main/java/jaxx/demo/BeanDataBindingDemo.jaxx | 47 - .../main/java/jaxx/demo/BoxedDecoratorDemo.jaxx | 91 - .../src/main/java/jaxx/demo/Calculator.css | 68 - .../src/main/java/jaxx/demo/CalculatorDemo.jaxx | 89 - .../src/main/java/jaxx/demo/CalculatorEngine.java | 177 - .../src/main/java/jaxx/demo/ComboEditorDemo.jaxx | 35 - .../src/main/java/jaxx/demo/CounterDemo.jaxx | 12 - .../src/main/java/jaxx/demo/DemoPanel.jaxx | 45 - .../src/main/java/jaxx/demo/EmptyDemo.jaxx | 5 - .../src/main/java/jaxx/demo/I18nEditorDemo.jaxx | 46 - .../src/main/java/jaxx/demo/Identity.java | 103 - .../src/main/java/jaxx/demo/JAXXDemo.jaxx | 132 - .../src/main/java/jaxx/demo/JButtonDemo.jaxx | 29 - .../src/main/java/jaxx/demo/JCheckBoxDemo.jaxx | 38 - .../main/java/jaxx/demo/JCheckBoxMenuItemDemo.jaxx | 59 - .../src/main/java/jaxx/demo/JComboBoxDemo.jaxx | 22 - .../src/main/java/jaxx/demo/JDialogDemo.jaxx | 79 - .../src/main/java/jaxx/demo/JListDemo.jaxx | 59 - .../src/main/java/jaxx/demo/JMenuItemDemo.jaxx | 23 - .../main/java/jaxx/demo/JPasswordFieldDemo.jaxx | 10 - .../src/main/java/jaxx/demo/JProgressBarDemo.jaxx | 77 - .../src/main/java/jaxx/demo/JRadioButtonDemo.jaxx | 11 - .../java/jaxx/demo/JRadioButtonMenuItemDemo.jaxx | 14 - .../src/main/java/jaxx/demo/JSliderDemo.jaxx | 12 - .../src/main/java/jaxx/demo/JSpinnerDemo.jaxx | 13 - .../src/main/java/jaxx/demo/JSplitPaneDemo.jaxx | 13 - .../src/main/java/jaxx/demo/JTextAreaDemo.jaxx | 33 - .../src/main/java/jaxx/demo/JTextFieldDemo.jaxx | 22 - .../src/main/java/jaxx/demo/JToggleButtonDemo.jaxx | 9 - .../src/main/java/jaxx/demo/LabelStyle.css | 43 - .../src/main/java/jaxx/demo/LabelStyleDemo.jaxx | 85 - .../src/main/java/jaxx/demo/Model.java | 66 - .../src/main/java/jaxx/demo/NumberEditorDemo.jaxx | 132 - .../main/java/jaxx/demo/NumberEditorDemoModel.java | 78 - .../java/jaxx/demo/StatusMessagePanelDemo.jaxx | 11 - .../src/main/java/jaxx/demo/Validation.css | 5 - .../main/java/jaxx/demo/ValidationListDemo.jaxx | 325 - .../main/java/jaxx/demo/ValidationTableDemo.jaxx | 331 - trunk/jaxx-example/src/main/jnlp/jxlayer.jnlp | 12 - trunk/jaxx-example/src/main/jnlp/sun.jnlp | 12 - .../resources/i18n/jaxx-example-en_GB.properties | 142 - .../resources/i18n/jaxx-example-fr_FR.properties | 134 - .../src/main/resources/icons/action-accept.png | Bin 781 -> 0 bytes .../src/main/resources/icons/action-block.png | Bin 576 -> 0 bytes .../jaxx/demo/Identity-error-validation.xml | 49 - .../jaxx/demo/Identity-info-validation.xml | 49 - .../jaxx/demo/Identity-warning-validation.xml | 49 - .../resources/jaxx/demo/Model-error-validation.xml | 35 - .../resources/jaxx/demo/Model-info-validation.xml | 13 - .../jaxx/demo/Model-warning-validation.xml | 18 - .../main/resources/jaxx/demo/images/Amethyst.jpg | Bin 24619 -> 0 bytes .../src/main/resources/jaxx/demo/images/Lynx.jpg | Bin 40463 -> 0 bytes .../src/main/resources/jaxx/demo/images/Tomato.jpg | Bin 22862 -> 0 bytes .../resources/jaxx/demo/images/pencil_black.gif | Bin 190 -> 0 bytes .../src/main/resources/log4j.properties | 10 - .../src/site/rst/images/Components-screenshot.gif | Bin 46663 -> 0 bytes .../jaxx-example/src/site/rst/images/webstart.gif | Bin 1806 -> 0 bytes trunk/jaxx-example/src/site/rst/index.rst | 40 - trunk/jaxx-example/src/site/site.xml | 27 - .../java/jaxx/demo/BeanValidatorDetectorTest.java | 34 - trunk/jaxx-runtime-api/LICENSE.txt | 166 - trunk/jaxx-runtime-api/README.txt | 2 - trunk/jaxx-runtime-api/changelog.txt | 109 - trunk/jaxx-runtime-api/pom.xml | 138 - .../src/main/java/jaxx/Base64Coder.java | 240 - .../src/main/java/jaxx/css/Rule.java | 54 - .../src/main/java/jaxx/css/Selector.java | 99 - .../src/main/java/jaxx/css/Stylesheet.java | 45 - .../main/java/jaxx/runtime/BeanValidatorUtil.java | 176 - .../java/jaxx/runtime/ComponentDescriptor.java | 49 - .../java/jaxx/runtime/DataBindingListener.java | 46 - .../jaxx/runtime/DataBindingUpdateListener.java | 46 - .../src/main/java/jaxx/runtime/DataContext.java | 400 - .../src/main/java/jaxx/runtime/Decorator.java | 36 - .../src/main/java/jaxx/runtime/DecoratorUtils.java | 111 - .../jaxx/runtime/DefaultApplicationContext.java | 281 - .../main/java/jaxx/runtime/DefaultJAXXContext.java | 214 - .../src/main/java/jaxx/runtime/JAXXAction.java | 19 - .../src/main/java/jaxx/runtime/JAXXContext.java | 99 - .../java/jaxx/runtime/JAXXContextEntryDef.java | 118 - .../main/java/jaxx/runtime/JAXXInitialContext.java | 93 - .../src/main/java/jaxx/runtime/JAXXObject.java | 52 - .../java/jaxx/runtime/JAXXObjectDescriptor.java | 42 - .../src/main/java/jaxx/runtime/JAXXValidator.java | 25 - .../main/java/jaxx/runtime/JXPathDecorator.java | 278 - .../java/jaxx/runtime/MultiJXPathDecorator.java | 129 - .../main/java/jaxx/runtime/PropertyDecorator.java | 94 - .../src/main/java/jaxx/runtime/Util.java | 465 - .../main/java/jaxx/runtime/css/DataBinding.java | 31 - .../main/java/jaxx/runtime/css/Pseudoclasses.java | 176 - .../java/jaxx/runtime/validator/BeanValidator.java | 490 - .../runtime/validator/BeanValidatorDetector.java | 208 - .../jaxx/runtime/validator/BeanValidatorEvent.java | 52 - .../jaxx/runtime/validator/BeanValidatorField.java | 239 - .../runtime/validator/BeanValidatorListener.java | 17 - .../runtime/validator/BeanValidatorMessage.java | 72 - .../jaxx/runtime/validator/BeanValidatorScope.java | 46 - .../jaxx/runtime/validator/XWorkBeanValidator.java | 252 - .../field/CollectionFieldExpressionValidator.java | 448 - .../field/CollectionUniqueKeyValidator.java | 208 - .../field/ExistingDirectoryFieldValidator.java | 72 - .../field/ExistingFileFieldValidator.java | 72 - .../field/FieldExpressionWithParamsValidator.java | 175 - .../field/NotExistingDirectoryFieldValidator.java | 72 - .../field/NotExistingFileFieldValidator.java | 73 - .../field/RequiredFileFieldValidator.java | 72 - .../i18n/jaxx-runtime-api-en_GB.properties | 3 - .../i18n/jaxx-runtime-api-fr_FR.properties | 3 - .../src/main/resources/validators.xml | 18 - trunk/jaxx-runtime-api/src/site/site.xml | 25 - .../runtime/DefaultApplicationContextTest.java | 117 - .../java/jaxx/runtime/DefaultJAXXContextTest.java | 299 - .../java/jaxx/runtime/JXPathDecoratorTest.java | 163 - .../jaxx/runtime/MultiJXPathDecoratorTest.java | 184 - .../src/test/java/jaxx/runtime/UtilTest.java | 29 - .../AbstractBeanValidatorDetectorTest.java | 108 - .../validator/BeanValidatorDetectorTest.java | 101 - .../jaxx/runtime/validator/BeanValidatorTest.java | 198 - .../java/jaxx/runtime/validator/SimpleBean.java | 51 - .../runtime/validator/XWorkBeanValidatorTest.java | 156 - .../field/AbstractFieldValidatorTest.java | 97 - .../AbstractValidatorBeanFieldValidatorTest.java | 14 - .../CollectionFieldExpressionValidatorTest.java | 234 - .../field/CollectionUniqueKeyValidatorTest.java | 86 - .../field/ExistingDirectoryFieldValidatorTest.java | 30 - .../field/ExistingFileFieldValidatorTest.java | 30 - .../validator/field/FieldExpressionBean.java | 103 - .../FieldExpressionWithParamsValidatorTest.java | 116 - .../NotExistingDirectoryFieldValidatorTest.java | 33 - .../field/NotExistingFileFieldValidatorTest.java | 37 - .../field/RequiredFileFieldValidatorTest.java | 29 - .../runtime/validator/field/ValidatorBean.java | 149 - .../validator/SimpleBean-error-validation.xml | 19 - .../validator/SimpleBean-info-validation.xml | 13 - .../validator/SimpleBean-simple-validation.xml | 19 - .../validator/SimpleBean-warning-validation.xml | 13 - .../field/FieldExpressionBean-error-validation.xml | 99 - .../field/ValidatorBean-error-validation.xml | 155 - .../src/test/resources/log4j.properties | 8 - .../src/test/resources/validators.xml | 36 - trunk/jaxx-runtime-swing-widget/LICENSE.txt | 166 - trunk/jaxx-runtime-swing-widget/README.txt | 2 - trunk/jaxx-runtime-swing-widget/changelog.txt | 5 - trunk/jaxx-runtime-swing-widget/pom.xml | 123 - .../main/java/jaxx/runtime/swing/AboutPanel.jaxx | 224 - .../main/java/jaxx/runtime/swing/ClockWidget.jaxx | 55 - .../java/jaxx/runtime/swing/EntityComboBox.jaxx | 131 - .../jaxx/runtime/swing/EntityComboBoxHandler.java | 470 - .../java/jaxx/runtime/swing/ErrorDialogUI.jaxx | 88 - .../jaxx/runtime/swing/MemoryStatusWidget.jaxx | 113 - .../jaxx/runtime/swing/StatusMessagePanel.jaxx | 84 - .../runtime/swing/StatusMessagePanelHandler.java | 75 - .../java/jaxx/runtime/swing/editor/I18nEditor.jaxx | 211 - .../jaxx/runtime/swing/editor/NumberEditor.jaxx | 167 - .../runtime/swing/editor/NumberEditorHandler.java | 468 - .../runtime/swing/editor/NumberEditorPopup.css | 43 - .../java/jaxx/runtime/swing/editor/TimeEditor.css | 49 - .../java/jaxx/runtime/swing/editor/TimeEditor.jaxx | 78 - .../runtime/swing/editor/TimeEditorHandler.java | 222 - .../jaxx-runtime-swing-widget-en_GB.properties | 71 - .../jaxx-runtime-swing-widget-fr_FR.properties | 72 - .../src/main/resources/icons/action-i18n-be.png | Bin 449 -> 0 bytes .../src/main/resources/icons/action-i18n-ca.png | Bin 628 -> 0 bytes .../src/main/resources/icons/action-i18n-ch.png | Bin 367 -> 0 bytes .../src/main/resources/icons/action-i18n-de.png | Bin 545 -> 0 bytes .../src/main/resources/icons/action-i18n-dk.png | Bin 495 -> 0 bytes .../src/main/resources/icons/action-i18n-es.png | Bin 469 -> 0 bytes .../src/main/resources/icons/action-i18n-fi.png | Bin 489 -> 0 bytes .../src/main/resources/icons/action-i18n-fr.png | Bin 545 -> 0 bytes .../src/main/resources/icons/action-i18n-gb.png | Bin 599 -> 0 bytes .../src/main/resources/icons/action-i18n-it.png | Bin 420 -> 0 bytes .../src/main/resources/icons/action-i18n-nl.png | Bin 453 -> 0 bytes .../src/main/resources/icons/action-i18n-no.png | Bin 512 -> 0 bytes .../src/main/resources/icons/action-i18n-se.png | Bin 542 -> 0 bytes .../src/main/resources/icons/action-i18n-us.png | Bin 609 -> 0 bytes .../icons/action-numbereditor-calculator.png | Bin 543 -> 0 bytes .../resources/icons/action-numbereditor-reset.png | Bin 396 -> 0 bytes .../icons/action-numbereditor-validate.png | Bin 537 -> 0 bytes .../src/site/rst/images/Components-screenshot.gif | Bin 46663 -> 0 bytes .../src/site/rst/images/webstart.gif | Bin 1806 -> 0 bytes .../src/site/rst/index.rst | 40 - trunk/jaxx-runtime-swing-widget/src/site/site.xml | 25 - trunk/jaxx-runtime-swing/LICENSE.txt | 166 - trunk/jaxx-runtime-swing/README.txt | 2 - trunk/jaxx-runtime-swing/changelog.txt | 114 - trunk/jaxx-runtime-swing/pom.xml | 53 - .../src/main/java/jaxx/beaninfos/HBoxBeanInfo.java | 58 - .../src/main/java/jaxx/beaninfos/VBoxBeanInfo.java | 58 - .../src/main/java/jaxx/runtime/JaxxHelpUI.java | 23 - .../src/main/java/jaxx/runtime/SwingUtil.java | 739 -- .../main/java/jaxx/runtime/SwingValidatorUtil.java | 200 - .../main/java/jaxx/runtime/swing/Application.java | 56 - .../java/jaxx/runtime/swing/BlockingLayerUI.java | 259 - .../java/jaxx/runtime/swing/BlockingLayerUI2.java | 217 - .../jaxx/runtime/swing/BooleanCellRenderer.java | 61 - .../main/java/jaxx/runtime/swing/CardLayout2.java | 221 - .../java/jaxx/runtime/swing/CardLayout2Ext.java | 99 - .../runtime/swing/DecoratorTableCellRenderer.java | 33 - .../swing/EmptyNumberTableCellRenderer.java | 37 - .../jaxx/runtime/swing/EnumTableCellRenderer.java | 47 - .../src/main/java/jaxx/runtime/swing/GBC.java | 151 - .../src/main/java/jaxx/runtime/swing/HBox.java | 94 - .../main/java/jaxx/runtime/swing/HBoxLayout.java | 127 - .../jaxx/runtime/swing/I18nTableCellRenderer.java | 66 - .../src/main/java/jaxx/runtime/swing/Item.java | 192 - .../java/jaxx/runtime/swing/JAXXButtonGroup.java | 222 - .../main/java/jaxx/runtime/swing/JAXXComboBox.java | 224 - .../src/main/java/jaxx/runtime/swing/JAXXList.java | 309 - .../src/main/java/jaxx/runtime/swing/JAXXTab.java | 25 - .../java/jaxx/runtime/swing/JAXXToggleButton.java | 92 - .../src/main/java/jaxx/runtime/swing/JAXXTree.java | 220 - .../java/jaxx/runtime/swing/JaxxHelpBroker.java | 500 - .../jaxx/runtime/swing/LocaleListCellRenderer.java | 114 - .../jaxx/runtime/swing/MyDefaultCellEditor.java | 104 - .../runtime/swing/OneClicListSelectionModel.java | 181 - .../src/main/java/jaxx/runtime/swing/Spacer.java | 12 - .../src/main/java/jaxx/runtime/swing/TabInfo.java | 165 - .../swing/TabInfoPropertyChangeListener.java | 44 - .../src/main/java/jaxx/runtime/swing/Table.java | 58 - .../src/main/java/jaxx/runtime/swing/VBox.java | 94 - .../main/java/jaxx/runtime/swing/VBoxLayout.java | 127 - .../java/jaxx/runtime/swing/editor/EnumEditor.java | 57 - .../jaxx/runtime/swing/editor/LocaleEditor.java | 64 - .../navigation/NavigationTreeCellRenderer.java | 93 - .../swing/navigation/NavigationTreeHandler.java | 249 - .../NavigationTreeHandlerWithCardLayout.java | 119 - .../swing/navigation/NavigationTreeModel.java | 589 -- .../navigation/NavigationTreeModelBuilder.java | 152 - .../navigation/NavigationTreeSelectionAdapter.java | 243 - ...vigationTreeSelectionAdapterWithCardLayout.java | 108 - .../runtime/swing/navigation/NavigationUtil.java | 159 - .../jaxx/runtime/swing/wizard/WizardModel.java | 244 - .../swing/wizard/WizardOperationAction.java | 108 - .../swing/wizard/WizardOperationActionThread.java | 204 - .../runtime/swing/wizard/WizardOperationModel.java | 269 - .../runtime/swing/wizard/WizardOperationState.java | 32 - .../runtime/swing/wizard/WizardOperationStep.java | 34 - .../java/jaxx/runtime/swing/wizard/WizardStep.java | 20 - .../jaxx/runtime/swing/wizard/WizardStepUI.java | 14 - .../java/jaxx/runtime/swing/wizard/WizardUI.java | 94 - .../jaxx/runtime/swing/wizard/WizardUILancher.java | 162 - .../java/jaxx/runtime/swing/wizard/WizardUtil.java | 157 - .../java/jaxx/runtime/swing/wizard/package.html | 9 - .../runtime/validator/swing/SwingValidator.java | 279 - .../validator/swing/SwingValidatorMessage.java | 66 - .../swing/SwingValidatorMessageListModel.java | 142 - .../SwingValidatorMessageListMouseListener.java | 60 - .../swing/SwingValidatorMessageListRenderer.java | 90 - .../swing/SwingValidatorMessageTableModel.java | 327 - .../SwingValidatorMessageTableMouseListener.java | 94 - .../swing/SwingValidatorMessageTableRenderer.java | 84 - .../swing/ui/AbstractBeanValidatorUI.java | 37 - .../validator/swing/ui/IconValidationUI.java | 86 - .../validator/swing/ui/ImageValidationUI.java | 78 - .../swing/ui/TranslucentValidationUI.java | 65 - .../i18n/jaxx-runtime-swing-en_GB.properties | 9 - .../i18n/jaxx-runtime-swing-fr_FR.properties | 9 - .../src/main/resources/icons/action-delete.png | Bin 783 -> 0 bytes .../resources/icons/action-wizard-config-16.png | Bin 611 -> 0 bytes .../main/resources/icons/action-wizard-config.png | Bin 4639 -> 0 bytes .../resources/icons/action-wizard-message-16.png | Bin 778 -> 0 bytes .../main/resources/icons/action-wizard-message.png | Bin 4433 -> 0 bytes .../main/resources/icons/action-wizard-next-16.png | Bin 676 -> 0 bytes .../main/resources/icons/action-wizard-next.png | Bin 4458 -> 0 bytes .../resources/icons/action-wizard-pause-16.png | Bin 598 -> 0 bytes .../main/resources/icons/action-wizard-pause.png | Bin 4323 -> 0 bytes .../resources/icons/action-wizard-previous-16.png | Bin 655 -> 0 bytes .../resources/icons/action-wizard-previous.png | Bin 4449 -> 0 bytes .../resources/icons/action-wizard-refresh-16.png | Bin 685 -> 0 bytes .../main/resources/icons/action-wizard-refresh.png | Bin 4761 -> 0 bytes .../resources/icons/action-wizard-start-16.png | Bin 592 -> 0 bytes .../main/resources/icons/action-wizard-start.png | Bin 4469 -> 0 bytes .../icons/action-wizard-state-canceled-16.png | Bin 587 -> 0 bytes .../icons/action-wizard-state-canceled.png | Bin 4340 -> 0 bytes .../icons/action-wizard-state-failed-16.png | Bin 701 -> 0 bytes .../resources/icons/action-wizard-state-failed.png | Bin 4197 -> 0 bytes .../icons/action-wizard-state-need_fix-16.png | Bin 666 -> 0 bytes .../icons/action-wizard-state-need_fix.png | Bin 4567 -> 0 bytes .../icons/action-wizard-state-pending-16.png | Bin 403 -> 0 bytes .../icons/action-wizard-state-pending.png | Bin 4284 -> 0 bytes .../icons/action-wizard-state-running-16.png | Bin 592 -> 0 bytes .../icons/action-wizard-state-running.png | Bin 4483 -> 0 bytes .../icons/action-wizard-state-successed-16.png | Bin 537 -> 0 bytes .../icons/action-wizard-state-successed.png | Bin 4447 -> 0 bytes .../src/main/resources/icons/error.png | Bin 701 -> 0 bytes .../src/main/resources/icons/info.png | Bin 778 -> 0 bytes .../src/main/resources/icons/warning.png | Bin 666 -> 0 bytes trunk/jaxx-runtime-swing/src/site/site.xml | 25 - trunk/jaxx-swing-action/LICENSE.txt | 166 - trunk/jaxx-swing-action/README.txt | 2 - trunk/jaxx-swing-action/changelog.txt | 10 - trunk/jaxx-swing-action/pom.xml | 85 - .../AbstractActionConfigurationResolver.java | 77 - .../jaxx/action/ActionAnnotationProcessing.java | 398 - .../java/org/nuiton/jaxx/action/ActionConfig.java | 122 - .../action/ActionConfigConfigurationResolver.java | 68 - .../jaxx/action/ActionConfigurationResolver.java | 54 - .../java/org/nuiton/jaxx/action/ActionFactory.java | 150 - .../jaxx/action/ActionFactoryFromProvider.java | 470 - .../org/nuiton/jaxx/action/ActionNameProvider.java | 34 - .../org/nuiton/jaxx/action/ActionProvider.java | 36 - .../jaxx/action/ActionProviderAnnotation.java | 34 - .../jaxx/action/ActionProviderFromProperties.java | 135 - .../org/nuiton/jaxx/action/MyAbstractAction.java | 260 - .../org/nuiton/jaxx/action/SelectActionConfig.java | 95 - .../SelectActionConfigConfigurationResolver.java | 54 - .../org/nuiton/jaxx/action/ToggleActionConfig.java | 156 - .../ToggleActionConfigConfigurationResolver.java | 79 - .../java/org/nuiton/jaxx/tab/TabContentConfig.java | 54 - .../main/java/org/nuiton/jaxx/tab/TabFactory.java | 219 - .../main/java/org/nuiton/jaxx/tab/TabModel.java | 30 - .../org/nuiton/jaxx/util/AbstractUIAction.java | 55 - .../main/java/org/nuiton/jaxx/util/DialogUI.java | 137 - .../java/org/nuiton/jaxx/util/DialogUIDef.java | 238 - .../java/org/nuiton/jaxx/util/DialogUIHandler.java | 72 - .../java/org/nuiton/jaxx/util/DialogUIModel.java | 97 - .../nuiton/jaxx/util/FactoryWindowListener.java | 84 - .../java/org/nuiton/jaxx/util/FormElement.java | 31 - .../java/org/nuiton/jaxx/util/ShowUIAction.java | 140 - .../main/java/org/nuiton/jaxx/util/UIFactory.java | 184 - .../main/java/org/nuiton/jaxx/util/UIHelper.java | 71 - .../main/java/org/nuiton/jaxx/util/UIProvider.java | 86 - .../org/nuiton/jaxx/util/config/CancelAction.java | 43 - .../nuiton/jaxx/util/config/DialogConfigUI.java | 105 - .../jaxx/util/config/DialogConfigUIHandler.java | 156 - .../jaxx/util/config/DialogConfigUIModel.java | 220 - .../org/nuiton/jaxx/util/config/ResetAction.java | 43 - .../org/nuiton/jaxx/util/config/SaveAction.java | 50 - .../services/javax.annotation.processing.Processor | 1 - .../i18n/jaxx-swing-action-en_GB.properties | 10 - .../i18n/jaxx-swing-action-fr_FR.properties | 10 - trunk/jaxx-swing-action/src/site/rst/Todo.rst | 4 - trunk/jaxx-swing-action/src/site/rst/index.rst | 13 - trunk/jaxx-swing-action/src/site/site.xml | 25 - trunk/maven-jaxx-plugin/LICENSE.txt | 166 - trunk/maven-jaxx-plugin/README.txt | 2 - trunk/maven-jaxx-plugin/changelog.txt | 37 - trunk/maven-jaxx-plugin/pom.xml | 143 - .../java/org/nuiton/jaxx/AbstractJaxxMojo.java | 170 - .../java/org/nuiton/jaxx/JaxxGeneratorMojo.java | 652 -- .../org/nuiton/jaxx/JaxxHelpGeneratorMojo.java | 792 -- .../src/main/java/org/nuiton/jaxx/NodeItem.java | 137 - .../java/org/nuiton/jaxx/TemplateGenerator.java | 142 - .../src/main/resources/defaultContent.html.vm | 14 - .../src/main/resources/defaultHelpSet.hs.vm | 44 - .../src/main/resources/defaultI18n.java.vm | 16 - .../src/main/resources/defaultIndex.xml.vm | 21 - .../src/main/resources/defaultMap.jhm.vm | 16 - .../src/main/resources/defaultToc.xml.vm | 20 - .../src/main/resources/log4j.properties | 9 - trunk/maven-jaxx-plugin/src/site/rst/Todo.rst | 4 - trunk/maven-jaxx-plugin/src/site/rst/index.rst | 13 - trunk/maven-jaxx-plugin/src/site/site.xml | 41 - .../src/test/java/org/nuiton/jaxx/Bug1722Test.java | 12 - .../src/test/java/org/nuiton/jaxx/Bug1750Test.java | 44 - .../src/test/java/org/nuiton/jaxx/Bug1751Test.java | 14 - .../test/java/org/nuiton/jaxx/CompilerTest.java | 227 - .../org/nuiton/jaxx/CompilerValidatorTest.java | 72 - .../test/java/org/nuiton/jaxx/DecoratorTest.java | 11 - .../src/test/java/org/nuiton/jaxx/I18nTest.java | 39 - .../test/java/org/nuiton/jaxx/JaxxBaseTest.java | 85 - .../test/java/org/nuiton/jaxx/NodeItemTest.java | 54 - .../src/test/resources/testcases/Bug_1722.xml | 23 - .../src/test/resources/testcases/Bug_1750.xml | 24 - .../src/test/resources/testcases/Bug_1751.xml | 25 - .../src/test/resources/testcases/CSSTests.xml | 23 - .../resources/testcases/CSSTests/CSSTests.jaxx | 24 - .../test/resources/testcases/CSSTests/Child.jaxx | 1 - .../test/resources/testcases/CSSTests/Child2.jaxx | 1 - .../resources/testcases/CSSTests/GrandChild.jaxx | 28 - .../testcases/CSSTests/GrandChildButton.jaxx | 1 - .../testcases/CSSTests/Pseudoclasses.jaxx | 99 - .../resources/testcases/CSSTests/SimpleCSS.jaxx | 29 - .../test/resources/testcases/ClassReferences.xml | 22 - .../testcases/ClassReferences/ClassReferences.jaxx | 18 - .../ClassReferences/ConstructorReferenceTest.jaxx | 7 - .../ClassReferences/JAXXReferenceTest.jaxx | 7 - .../testcases/ClassReferences/JAXXTest.jaxx | 7 - .../testcases/ClassReferences/JavaTaist.java | 9 - .../ClassReferences/StaticMethodTest.jaxx | 7 - .../testcases/ClassReferences/TypeReference.jaxx | 1 - .../test/resources/testcases/ClientProperty.xml | 23 - .../src/test/resources/testcases/Decorator.xml | 23 - .../testcases/ErrorJaxxContextImplementorClass.xml | 20 - .../src/test/resources/testcases/Errors.xml | 25 - .../src/test/resources/testcases/Force.xml | 22 - .../src/test/resources/testcases/I18nText.xml | 23 - .../src/test/resources/testcases/I18nTitle.xml | 23 - .../test/resources/testcases/I18nToolTipText.xml | 23 - .../src/test/resources/testcases/Icon.xml | 25 - .../src/test/resources/testcases/Initializers.xml | 22 - .../testcases/Initializers/Initializers.jaxx | 37 - .../src/test/resources/testcases/InnerClasses.xml | 22 - .../testcases/InnerClasses/InnerClasses.jaxx | 17 - .../src/test/resources/testcases/NoLog.xml | 23 - .../resources/testcases/OverridingDataBindings.xml | 22 - .../OverridingDataBindings/CurrentTime.jaxx | 17 - .../OverriddenCurrentTime.jaxx | 1 - .../OverridingDataBindings.jaxx | 12 - .../src/test/resources/testcases/Script.xml | 22 - .../testcases/Script/JScriptInitializer.jaxx | 19 - .../resources/testcases/SpecialSubclassing.xml | 22 - .../SpecialSubclassing/JComboBoxTest1.jaxx | 3 - .../SpecialSubclassing/JComboBoxTest2.jaxx | 3 - .../testcases/SpecialSubclassing/JListTest1.jaxx | 3 - .../testcases/SpecialSubclassing/JListTest2.jaxx | 3 - .../testcases/SpecialSubclassing/JTreeTest1.jaxx | 3 - .../testcases/SpecialSubclassing/JTreeTest2.jaxx | 3 - .../SpecialSubclassing/SpecialSubclassing.jaxx | 26 - .../test/resources/testcases/ValidatorErrors.xml | 22 - .../src/test/resources/testcases/ValidatorOk.xml | 22 - .../src/test/resources/testcases/WithLog.xml | 23 - .../resources/testcases/bug_1722/DemoPanel.jaxx | 7 - .../resources/testcases/bug_1722/JButtonDemo.jaxx | 5 - .../resources/testcases/bug_1750/ComboBox.jaxx | 18 - .../test/resources/testcases/bug_1751/Test1.jaxx | 1 - .../test/resources/testcases/bug_1751/Test2.jaxx | 1 - .../test/resources/testcases/bug_1751/Test3.jaxx | 1 - .../testcases/clientProperty/TestOne.jaxx | 3 - .../testcases/decorator/BoxedDecorator.jaxx | 3 - .../resources/testcases/errors/AmbiguousName.jaxx | 10 - .../testcases/errors/BadTypeConversions.jaxx | 4 - .../testcases/errors/CellOutsideOfRow.jaxx | 5 - .../testcases/errors/ChildrenInNonContainer.jaxx | 4 - .../resources/testcases/errors/ClassNotFound.jaxx | 3 - .../testcases/errors/ConflictingPackages.jaxx | 1 - .../testcases/errors/ConstraintsParseError.jaxx | 5 - .../testcases/errors/DataBindingParseError.jaxx | 6 - .../resources/testcases/errors/DuplicateIDs.jaxx | 4 - .../testcases/errors/EventHandlerParseError.jaxx | 4 - .../test/resources/testcases/errors/InvalidID.jaxx | 3 - .../resources/testcases/errors/InvalidRootTag.jaxx | 1 - .../resources/testcases/errors/InvalidXML.jaxx | 4 - .../testcases/errors/ItemDuplicateValues.jaxx | 8 - .../resources/testcases/errors/ItemNoValue.jaxx | 4 - .../resources/testcases/errors/MixedContent.jaxx | 19 - .../testcases/errors/RowOutsideOfTable.jaxx | 9 - .../resources/testcases/errors/RowWrongChild.jaxx | 9 - .../resources/testcases/errors/ScriptNotFound.jaxx | 1 - .../testcases/errors/ScriptParseError.jaxx | 6 - .../testcases/errors/ScriptSourceAndInline.jaxx | 3 - .../resources/testcases/errors/StyleNotFound.jaxx | 1 - .../testcases/errors/StyleParseError.jaxx | 9 - .../testcases/errors/StyleSourceAndInline.jaxx | 3 - .../testcases/errors/TabOutsideOfTabbedPane.jaxx | 9 - .../testcases/errors/TabbedPaneWrongChild.jaxx | 6 - .../testcases/errors/TableWrongChild.jaxx | 6 - .../testcases/errors/TooManyCellChildren.jaxx | 15 - .../errors/TooManyScrollPaneChildren.jaxx | 5 - .../testcases/errors/TooManySplitPaneChildren.jaxx | 7 - .../testcases/errors/TooManyTabChildren.jaxx | 13 - .../testcases/errors/UnsupportedAttribute.jaxx | 3 - .../testcases/errors/UnsupportedEvent.jaxx | 3 - .../testcases/errors/UnsupportedPseudoclass.jaxx | 5 - .../testcases/errors/dependencies/test.css | 1 - .../testcases/errors/dependencies/test.script | 1 - .../test/resources/testcases/force/JButton.jaxx | 1 - .../resources/testcases/i18n/text/JButton.jaxx | 1 - .../resources/testcases/i18n/title/JDialog.jaxx | 1 - .../testcases/i18n/title/JTabbedPane.jaxx | 3 - .../testcases/i18n/title/JTabbedPane2.jaxx | 5 - .../testcases/i18n/tooltiptext/JButton.jaxx | 1 - .../testcases/i18n/tooltiptext/JTabbedPane.jaxx | 3 - .../testcases/i18n/tooltiptext/JTabbedPane2.jaxx | 3 - .../testcases/i18n/tooltiptext/JTabbedPane3.jaxx | 5 - .../src/test/resources/testcases/icon/Test1.jaxx | 4 - .../test/resources/testcases/log/nolog/NoLog.jaxx | 1 - .../resources/testcases/log/nolog/NoLogSon.jaxx | 1 - .../resources/testcases/log/withlog/NoLog.jaxx | 1 - .../resources/testcases/log/withlog/WithLog.jaxx | 1 - .../errors/AutoFieldComponentNotFound.jaxx | 5 - .../testcases/validator/errors/DuplicatedBean.jaxx | 3 - .../validator/errors/DuplicatedBean2.jaxx | 5 - .../validator/errors/DuplicatedErrorListModel.jaxx | 4 - .../errors/DuplicatedErrorTableModel.jaxx | 4 - .../errors/DuplicatedFieldInSameValidator.jaxx | 7 - .../errors/FieldBeanPropertyNotFound.jaxx | 5 - .../validator/errors/FieldComponentDuplicated.jaxx | 7 - .../validator/errors/FieldComponentNotFound.jaxx | 5 - .../validator/errors/FieldComponentNotFound2.jaxx | 5 - .../testcases/validator/errors/FieldNoName.jaxx | 5 - .../testcases/validator/errors/FieldNoName2.jaxx | 5 - .../testcases/validator/errors/Model.java | 66 - .../testcases/validator/errors/NoBean.jaxx | 5 - .../testcases/validator/errors/UnfoundBean.jaxx | 3 - .../validator/errors/UnfoundErrorList.jaxx | 3 - .../validator/errors/UnfoundErrorListModel.jaxx | 3 - .../validator/errors/UnfoundErrorTable.jaxx | 3 - .../validator/errors/UnfoundErrorTableModel.jaxx | 3 - .../validator/errors/UnfoundParentValidator.jaxx | 3 - .../resources/testcases/validator/ok/Identity.java | 79 - .../resources/testcases/validator/ok/Model.java | 66 - .../testcases/validator/ok/Validation.jaxx | 274 - .../validator/ok/ValidationBeanClass.jaxx | 112 - trunk/pom.xml | 219 - trunk/src/site/resources/images/jrst-logo.png | Bin 608 -> 0 bytes trunk/src/site/resources/jaxx.png | Bin 9503 -> 0 bytes trunk/src/site/rst/BeanValidator.rst | 181 - trunk/src/site/rst/Core.rst | 154 - trunk/src/site/rst/I18n.rst | 56 - trunk/src/site/rst/JAXXContext.rst | 161 - trunk/src/site/rst/NavigationTreeModel.rst | 169 - trunk/src/site/rst/Todo.rst | 8 - trunk/src/site/rst/index.rst | 46 - trunk/src/site/site.xml | 37 - 720 files changed, 564 insertions(+), 79478 deletions(-) -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.
participants (1)
-
nuiton.org scm