r1286 - in jaxx/trunk: . jaxx-compiler-gwt jaxx-compiler-gwt/.settings jaxx-compiler-gwt/src jaxx-compiler-gwt/src/main jaxx-compiler-gwt/src/main/java jaxx-compiler-gwt/src/main/java/jaxx jaxx-compiler-gwt/src/main/java/jaxx/compiler jaxx-compiler-gwt/src/main/java/jaxx/tags jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt jaxx-compiler-gwt/src/main/java/jaxx/types jaxx-compiler-gwt/src/main/resources jaxx-compiler-gwt/src/main/resources/META-INF jaxx-compiler-gwt/src/main/resources/META-INF/se
Author: kmorin Date: 2009-04-02 12:38:08 +0000 (Thu, 02 Apr 2009) New Revision: 1286 Added: jaxx/trunk/jaxx-compiler-gwt/ jaxx/trunk/jaxx-compiler-gwt/.classpath jaxx/trunk/jaxx-compiler-gwt/.project jaxx/trunk/jaxx-compiler-gwt/.settings/ jaxx/trunk/jaxx-compiler-gwt/.settings/org.eclipse.jdt.core.prefs jaxx/trunk/jaxx-compiler-gwt/LICENSE.txt jaxx/trunk/jaxx-compiler-gwt/README.txt jaxx/trunk/jaxx-compiler-gwt/changelog.txt jaxx/trunk/jaxx-compiler-gwt/pom.xml jaxx/trunk/jaxx-compiler-gwt/src/ jaxx/trunk/jaxx-compiler-gwt/src/main/ jaxx/trunk/jaxx-compiler-gwt/src/main/java/ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/GWTInitializer.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/compiler/ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/compiler/BoxedCompiledObjectDecorator.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/compiler/GWTCompiler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/compiler/GWTGenerator.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/compiler/HelpRootCompiledObjectDecorator.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/ApplicationHandler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/CellHandler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/CheckBoxHandler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/ComboBoxHandler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/CompiledItemContainer.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/ItemHandler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JAXXTabHandler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JInternalFrameHandler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JPopupMenuHandler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JProgressBarHandler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JScrollPaneHandler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JSliderHandler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JSpinnerHandler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JSplitPaneHandler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JTabbedPaneHandler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JTextComponentHandler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JToolBarHandler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JWindowHandler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/ListHandler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/MenuHandler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/PasswordFieldHandler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/RadioButtonHandler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/RowHandler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/TabHandler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/TableHandler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/TreeHandler.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/types/ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/types/ColorConverter.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/types/GridBagConstraintsConverter.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/types/InsetsConverter.java jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/types/KeyStrokeConverter.java jaxx/trunk/jaxx-compiler-gwt/src/main/resources/ jaxx/trunk/jaxx-compiler-gwt/src/main/resources/META-INF/ jaxx/trunk/jaxx-compiler-gwt/src/main/resources/META-INF/services/ jaxx/trunk/jaxx-compiler-gwt/src/main/resources/META-INF/services/jaxx.compiler.Generator jaxx/trunk/jaxx-compiler-gwt/src/main/resources/META-INF/services/jaxx.spi.Initializer jaxx/trunk/jaxx-compiler-gwt/src/site/ jaxx/trunk/jaxx-compiler-gwt/src/site/fr/ jaxx/trunk/jaxx-compiler-gwt/src/site/fr/rst/ jaxx/trunk/jaxx-compiler-gwt/src/test/ jaxx/trunk/jaxx-compiler-gwt/src/test/java/ jaxx/trunk/jaxx-compiler-gwt/src/test/java/jaxx/ jaxx/trunk/jaxx-compiler-gwt/src/test/java/jaxx/junit/ jaxx/trunk/jaxx-compiler-gwt/src/test/java/jaxx/junit/ColorConverterTest.java jaxx/trunk/jaxx-compiler-gwt/src/test/java/jaxx/junit/InsetsConverterTest.java jaxx/trunk/jaxx-compiler-gwt/src/test/java/jaxx/junit/TagManagerTest.java jaxx/trunk/jaxx-compiler-gwt/src/test/java/jaxx/runtime/ jaxx/trunk/jaxx-compiler-gwt/src/test/java/jaxx/runtime/swing/ jaxx/trunk/jaxx-compiler-gwt/src/test/java/jaxx/runtime/swing/navigation/ jaxx/trunk/jaxx-compiler-gwt/src/test/java/jaxx/runtime/swing/navigation/NavigationTreeModelTest.java jaxx/trunk/jaxx-compiler-gwt/src/test/resources/ jaxx/trunk/jaxx-compiler-gwt/src/test/resources/log4j.properties jaxx/trunk/jaxx-gwt-action/ jaxx/trunk/jaxx-gwt-action/.classpath jaxx/trunk/jaxx-gwt-action/.project jaxx/trunk/jaxx-gwt-action/.settings/ jaxx/trunk/jaxx-gwt-action/.settings/org.eclipse.jdt.core.prefs jaxx/trunk/jaxx-gwt-action/LICENSE.txt jaxx/trunk/jaxx-gwt-action/README.txt jaxx/trunk/jaxx-gwt-action/changelog.txt jaxx/trunk/jaxx-gwt-action/pom.xml jaxx/trunk/jaxx-gwt-action/src/ jaxx/trunk/jaxx-gwt-action/src/main/ jaxx/trunk/jaxx-gwt-action/src/main/java/ jaxx/trunk/jaxx-gwt-action/src/main/java/org/ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/AbstractActionConfigurationResolver.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionAnnotationProcessing.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionConfig.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionConfigConfigurationResolver.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionConfigurationResolver.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionFactory.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionFactoryFromProvider.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionNameProvider.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionProvider.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionProviderAnnotation.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionProviderFromProperties.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/MyAbstractAction.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/SelectActionConfig.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/SelectActionConfigConfigurationResolver.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ToggleActionConfig.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ToggleActionConfigConfigurationResolver.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/tab/ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/tab/TabContentConfig.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/tab/TabFactory.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/tab/TabModel.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/AbstractUIAction.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/DialogUI.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/DialogUIDef.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/DialogUIHandler.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/DialogUIModel.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/FactoryWindowListener.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/FormElement.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/ShowUIAction.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/UIFactory.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/UIHelper.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/UIProvider.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/config/ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/config/CancelAction.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/config/DialogConfigUI.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/config/DialogConfigUIHandler.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/config/DialogConfigUIModel.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/config/ResetAction.java jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/config/SaveAction.java jaxx/trunk/jaxx-gwt-action/src/main/resources/ jaxx/trunk/jaxx-gwt-action/src/main/resources/META-INF/ jaxx/trunk/jaxx-gwt-action/src/main/resources/META-INF/services/ jaxx/trunk/jaxx-gwt-action/src/main/resources/META-INF/services/javax.annotation.processing.Processor jaxx/trunk/jaxx-gwt-action/src/main/resources/i18n/ jaxx/trunk/jaxx-gwt-action/src/main/resources/i18n/jaxx-gwt-action-en_GB.properties jaxx/trunk/jaxx-gwt-action/src/main/resources/i18n/jaxx-gwt-action-fr_FR.properties jaxx/trunk/jaxx-gwt-action/src/main/resources/i18n/jaxx-swing-action-en_GB.properties jaxx/trunk/jaxx-gwt-action/src/main/resources/i18n/jaxx-swing-action-fr_FR.properties jaxx/trunk/jaxx-gwt-action/src/site/ jaxx/trunk/jaxx-gwt-action/src/site/fr/ jaxx/trunk/jaxx-gwt-action/src/site/fr/rst/ jaxx/trunk/jaxx-gwt-action/src/site/fr/rst/Todo.rst jaxx/trunk/jaxx-gwt-action/src/site/fr/rst/index.rst jaxx/trunk/jaxx-gwt-action/src/test/ jaxx/trunk/jaxx-gwt-action/src/test/java/ jaxx/trunk/jaxx-gwt-action/src/test/java/jaxx/ jaxx/trunk/jaxx-gwt-action/src/test/java/jaxx/runtime/ jaxx/trunk/jaxx-gwt-action/src/test/java/jaxx/runtime/UtilTest.java jaxx/trunk/jaxx-gwt-action/src/test/resources/ jaxx/trunk/jaxx-runtime-gwt/ jaxx/trunk/jaxx-runtime-gwt/.classpath jaxx/trunk/jaxx-runtime-gwt/.project jaxx/trunk/jaxx-runtime-gwt/.settings/ jaxx/trunk/jaxx-runtime-gwt/.settings/org.eclipse.jdt.core.prefs jaxx/trunk/jaxx-runtime-gwt/LICENSE.txt jaxx/trunk/jaxx-runtime-gwt/README.txt jaxx/trunk/jaxx-runtime-gwt/changelog.txt jaxx/trunk/jaxx-runtime-gwt/pom.xml jaxx/trunk/jaxx-runtime-gwt/src/ jaxx/trunk/jaxx-runtime-gwt/src/main/ jaxx/trunk/jaxx-runtime-gwt/src/main/java/ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/beaninfos/ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/beaninfos/HBoxBeanInfo.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/beaninfos/VBoxBeanInfo.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/GWTUtil.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/JaxxHelpUI.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/Application.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/BlockingLayerUI.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/BlockingLayerUI2.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/CardLayout2.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/CardLayout2Ext.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/DecoratorTableCellRenderer.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/HBox.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/HBoxLayout.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/I18nTableCellRenderer.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/Item.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JAXXButtonGroup.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JAXXComboBox.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JAXXList.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JAXXTab.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JAXXToggleButton.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JAXXTree.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JaxxHelpBroker.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/Spacer.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/TabInfo.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/TabInfoPropertyChangeListener.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/Table.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/VBox.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/VBoxLayout.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/navigation/ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/navigation/NavigationTreeCellRenderer.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/navigation/NavigationTreeModel.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/navigation/NavigationTreeModelBuilder.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/navigation/NavigationTreeSelectionAdapter.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/navigation/NavigationTreeSelectionAdapterWithCardLayout.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/navigation/NavigationUtil.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardModel.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardOperationAction.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardOperationActionThread.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardOperationModel.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardOperationState.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardOperationStep.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardStep.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardStepUI.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardUI.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardUILancher.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardUtil.java jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/package.html jaxx/trunk/jaxx-runtime-gwt/src/main/resources/ jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/ jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-config-16.png jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-config.png jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-message-16.png jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-message.png jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-next-16.png jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-next.png jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-pause-16.png jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-pause.png jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-previous-16.png jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-previous.png jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-refresh-16.png jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-refresh.png jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-start-16.png jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-start.png jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-canceled-16.png jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-canceled.png jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-failed-16.png jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-failed.png jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-need_fix-16.png jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-need_fix.png jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-pending-16.png jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-pending.png jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-running-16.png jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-running.png jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-successed-16.png jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-successed.png jaxx/trunk/jaxx-runtime-gwt/src/site/ jaxx/trunk/jaxx-runtime-gwt/src/site/fr/ jaxx/trunk/jaxx-runtime-gwt/src/site/fr/rst/ jaxx/trunk/jaxx-runtime-gwt/src/test/ jaxx/trunk/jaxx-runtime-gwt/src/test/java/ jaxx/trunk/jaxx-runtime-gwt/src/test/java/jaxx/ jaxx/trunk/jaxx-runtime-gwt/src/test/java/jaxx/junit/ jaxx/trunk/jaxx-runtime-gwt/src/test/java/jaxx/runtime/ jaxx/trunk/jaxx-runtime-gwt/src/test/resources/ jaxx/trunk/jaxx-runtime-gwt/src/test/resources/jaxx/ jaxx/trunk/jaxx-runtime-gwt/src/test/resources/jaxx/junit/ jaxx/trunk/jaxx-runtime-validator-gwt/ jaxx/trunk/jaxx-runtime-validator-gwt/.classpath jaxx/trunk/jaxx-runtime-validator-gwt/.project jaxx/trunk/jaxx-runtime-validator-gwt/.settings/ jaxx/trunk/jaxx-runtime-validator-gwt/.settings/org.eclipse.jdt.core.prefs jaxx/trunk/jaxx-runtime-validator-gwt/LICENSE.txt jaxx/trunk/jaxx-runtime-validator-gwt/README.txt jaxx/trunk/jaxx-runtime-validator-gwt/changelog.txt jaxx/trunk/jaxx-runtime-validator-gwt/pom.xml jaxx/trunk/jaxx-runtime-validator-gwt/src/ jaxx/trunk/jaxx-runtime-validator-gwt/src/main/ jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/ jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/ jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/ jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/GWTValidatorUtil.java jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/ jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/ jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidator.java jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessage.java jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessageListModel.java jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessageListMouseListener.java jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessageListRenderer.java jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessageTableModel.java jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessageTableMouseListener.java jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessageTableRenderer.java jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/ui/ jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/ui/AbstractBeanValidatorUI.java jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/ui/IconValidationUI.java jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/ui/ImageValidationUI.java jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/ui/TranslucentValidationUI.java jaxx/trunk/jaxx-runtime-validator-gwt/src/main/resources/ jaxx/trunk/jaxx-runtime-validator-gwt/src/main/resources/icons/ jaxx/trunk/jaxx-runtime-validator-gwt/src/main/resources/icons/error.png jaxx/trunk/jaxx-runtime-validator-gwt/src/main/resources/icons/info.png jaxx/trunk/jaxx-runtime-validator-gwt/src/main/resources/icons/warning.png jaxx/trunk/jaxx-runtime-validator-gwt/src/site/ jaxx/trunk/jaxx-runtime-validator-gwt/src/site/fr/ jaxx/trunk/jaxx-runtime-validator-gwt/src/site/fr/rst/ jaxx/trunk/jaxx-runtime-validator-gwt/src/test/ jaxx/trunk/jaxx-runtime-validator-gwt/src/test/java/ jaxx/trunk/jaxx-runtime-validator-gwt/src/test/resources/ Log: Added: jaxx/trunk/jaxx-compiler-gwt/.classpath =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/.classpath (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/.classpath 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,22 @@ +<classpath> + <classpathentry kind="src" path="src/main/java"/> + <classpathentry kind="src" path="src/main/resources" including="**/*" excluding="**/*~|**/*.java"/> + <classpathentry kind="src" path="src/test/java" output="target/test-classes"/> + <classpathentry kind="src" path="src/test/resources" output="target/test-classes" excluding="**/*.java"/> + <classpathentry kind="output" path="target/classes"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry kind="var" path="M2_REPO/commons-beanutils/commons-beanutils/1.8.0/commons-beanutils-1.8.0.jar"/> + <classpathentry kind="var" path="M2_REPO/commons-collections/commons-collections/3.2.1/commons-collections-3.2.1.jar"/> + <classpathentry kind="var" path="M2_REPO/commons-jxpath/commons-jxpath/1.3/commons-jxpath-1.3.jar"/> + <classpathentry kind="var" path="M2_REPO/commons-lang/commons-lang/2.4/commons-lang-2.4.jar"/> + <classpathentry kind="var" path="M2_REPO/commons-logging/commons-logging/1.1.1/commons-logging-1.1.1.jar"/> + <classpathentry kind="var" path="M2_REPO/commons-primitives/commons-primitives/1.0/commons-primitives-1.0.jar"/> + <classpathentry kind="var" path="M2_REPO/javax/help/javahelp/2.0.02/javahelp-2.0.02.jar"/> + <classpathentry kind="src" path="/jaxx-compiler-api"/> + <classpathentry kind="src" path="/jaxx-runtime-api"/> + <classpathentry kind="src" path="/jaxx-runtime-gwt"/> + <classpathentry kind="var" path="M2_REPO/junit/junit/4.5/junit-4.5.jar"/> + <classpathentry kind="var" path="M2_REPO/org/swinglabs/jxlayer/3.0.1/jxlayer-3.0.1.jar"/> + <classpathentry kind="var" path="M2_REPO/log4j/log4j/1.2.14/log4j-1.2.14.jar"/> + <classpathentry kind="var" path="M2_REPO/org/codelutin/lutinutil/1.0.3/lutinutil-1.0.3.jar"/> +</classpath> \ No newline at end of file Added: jaxx/trunk/jaxx-compiler-gwt/.project =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/.project (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/.project 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,17 @@ +<projectDescription> + <name>jaxx-compiler-gwt</name> + <comment>Jaxx compiler gwt extension</comment> + <projects> + <project>jaxx-compiler-api</project> + <project>jaxx-runtime-api</project> + <project>jaxx-runtime-gwt</project> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> \ No newline at end of file Added: jaxx/trunk/jaxx-compiler-gwt/.settings/org.eclipse.jdt.core.prefs =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/.settings/org.eclipse.jdt.core.prefs (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/.settings/org.eclipse.jdt.core.prefs 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,5 @@ +#Mon Mar 30 12:41:56 CEST 2009 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 Added: jaxx/trunk/jaxx-compiler-gwt/LICENSE.txt =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/LICENSE.txt (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/LICENSE.txt 2009-04-02 12:38:08 UTC (rev 1286) @@ -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. + Added: jaxx/trunk/jaxx-compiler-gwt/README.txt =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/README.txt (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/README.txt 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,2 @@ +To deploy new version of pom: mvn deploy +To install localy: mvn install Added: jaxx/trunk/jaxx-compiler-gwt/changelog.txt =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/changelog.txt (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/changelog.txt 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,96 @@ +1.3 chemit 20090320 + * 20090327 [chemit] - introduce javax help decorator + +1.1 chemit 20090220 + * 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) Added: jaxx/trunk/jaxx-compiler-gwt/pom.xml =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/pom.xml (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/pom.xml 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,113 @@ +<?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/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <!-- ************************************************************* --> + <!-- *** POM Relationships *************************************** --> + <!-- ************************************************************* --> + + <parent> + <groupId>org.codelutin</groupId> + <artifactId>jaxx</artifactId> + <version>1.3-SNAPSHOT</version> + </parent> + + <groupId>org.codelutin.jaxx</groupId> + <artifactId>jaxx-compiler-gwt</artifactId> + + <repositories> + <repository> + <id>gwt-maven</id> + <url>http://gwt-maven.googlecode.com/svn/trunk/mavenrepo/</url> + </repository> + </repositories> + + <dependencies> + + <!-- sibling dependencies --> + + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>jaxx-runtime-gwt</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>jaxx-compiler-api</artifactId> + <version>${project.version}</version> + </dependency> + + <!-- GWT Dependencies --> + <dependency> + <groupId>com.google.gwt</groupId> + <artifactId>gwt-servlet</artifactId> + <version>${gwtVersion}</version> + <scope>runtime</scope> + </dependency> + <dependency> + <groupId>com.google.gwt</groupId> + <artifactId>gwt-user</artifactId> + <version>${gwtVersion}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>com.google.gwt</groupId> + <artifactId>gwt-dev</artifactId> + <version>${gwtVersion}</version> + <classifier>${platform}-libs</classifier> + <type>zip</type> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>com.google.gwt</groupId> + <artifactId>gwt-dev</artifactId> + <version>${gwtVersion}</version> + <classifier>${platform}</classifier> + <scope>provided</scope> + </dependency> + + </dependencies> + + <!-- ************************************************************* --> + <!-- *** Project Information ************************************* --> + <!-- ************************************************************* --> + + <name>${project.artifactId}</name> + <description>Jaxx compiler gwt extension</description> + + <!-- ************************************************************* --> + <!-- *** Build Settings ****************************************** --> + <!-- ************************************************************* --> + <packaging>jar</packaging> + + <properties> + + <gwtVersion>1.5.3</gwtVersion> + + </properties> + + <!-- ************************************************************* --> + <!-- *** Build Environment ************************************** --> + <!-- ************************************************************* --> + <scm> + <url>http://labs.libre-entreprise.org/plugins/scmsvn/viewcvs.php/jaxx/trunk/jaxx-compiler-swing/?root=buix</url> + <connection>scm:svn:svn://anonymous@labs.libre-entreprise.org/svnroot/buix/jaxx/trunk/jaxx-compiler-gwt</connection> + <developerConnection>scm:svn:svn+ssh://sletellier@labs.libre-entreprise.org/svnroot/buix/jaxx/trunk/jaxx-compiler-gwt</developerConnection> + </scm> + + <profiles> + <profile> + <id>gwt-dev-linux</id> + <properties> + <platform>linux</platform> + </properties> + <activation> + <os> + <name>Linux</name> + </os> + </activation> + </profile> + </profiles> +</project> Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/GWTInitializer.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/GWTInitializer.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/GWTInitializer.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,97 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx; + +import jaxx.tags.gwt.*; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.runtime.gwt.Application; +import jaxx.runtime.gwt.JAXXButtonGroup; +import jaxx.runtime.gwt.JAXXComboBox; +import jaxx.runtime.gwt.JAXXList; +import jaxx.runtime.gwt.JAXXTab; +import jaxx.runtime.gwt.JAXXTree; +import jaxx.runtime.gwt.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 com.google.gwt.user.client.ui.*; + +public class GWTInitializer implements Initializer { + + 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), CheckBoxHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JCheckBoxMenuItem.class), CheckBoxHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JAXXComboBox.class), ComboBoxHandler.class); + TagManager.registerTag("javax.swing.*", "JComboBox", new ComboBoxHandler(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), ListHandler.class); + TagManager.registerTag("javax.swing.*", "JList", new ListHandler(ClassDescriptorLoader.getClassDescriptor(JAXXList.class))); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JMenu.class), MenuHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JPasswordField.class), PasswordFieldHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JPopupMenu.class), JPopupMenuHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JProgressBar.class), JProgressBarHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JRadioButton.class), RadioButtonHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JRadioButtonMenuItem.class), RadioButtonHandler.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), RadioButtonHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JToolBar.class), JToolBarHandler.class); + TagManager.registerBean(ClassDescriptorLoader.getClassDescriptor(JAXXTree.class), TreeHandler.class); + TagManager.registerTag("javax.swing.*", "JTree", new TreeHandler(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); + } +} \ No newline at end of file Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/compiler/BoxedCompiledObjectDecorator.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/compiler/BoxedCompiledObjectDecorator.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/compiler/BoxedCompiledObjectDecorator.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,27 @@ +package jaxx.compiler; + +import jaxx.compiler.CompiledObject.ChildRef; +import jaxx.runtime.GWTUtil; + +/** + * 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(GWTUtil.class.getName()+".boxComponentWithJxLayer(" + javaCode + ")"); + break; + } + } + super.finalizeCompiler(compiler, root, object, javaFile, packageName, className, fullClassName); + } +} Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/compiler/GWTCompiler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/compiler/GWTCompiler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/compiler/GWTCompiler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,75 @@ +/* + * 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 GWTCompiler extends JAXXCompiler { + + /*---------------------------------------------------------------------------------*/ + /*-- Constructor methods ----------------------------------------------------------*/ + /*---------------------------------------------------------------------------------*/ + + public GWTCompiler(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.gwt.JAXXButtonGroup", + "jaxx.runtime.gwt.HBox", + "jaxx.runtime.gwt.VBox", + "jaxx.runtime.gwt.Table", + "static org.codelutin.i18n.I18n._", + "static jaxx.runtime.Util.createImageIcon", + "com.google.gwt.user.client.ui.*"); + + + } + + /** + * 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 GWTCompiler(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.gwt.JAXXButtonGroup", + "jaxx.runtime.gwt.HBox", + "jaxx.runtime.gwt.VBox", + "jaxx.runtime.gwt.Table", + "static org.codelutin.i18n.I18n._", + "static jaxx.runtime.Util.createImageIcon", + "com.google.gwt.user.client.ui.*"); + } + +} \ No newline at end of file Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/compiler/GWTGenerator.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/compiler/GWTGenerator.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/compiler/GWTGenerator.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,27 @@ +package jaxx.compiler; + +import jaxx.reflect.ClassDescriptorLoader; + +import java.lang.reflect.Modifier; + +/** @author chemit */ +public class GWTGenerator 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.addInterface("com.google.gwt.core.client.EntryPoint"); + javaFile.addMethod(JavaMethod.newMethod(Modifier.PUBLIC, "void", "onModuleLoad", + "SwingUtilities.invokeLater(new Runnable() { public void run() { new " + className + "().setVisible(true); } });") + ); + System.out.println(javaFile.getMethods()[javaFile.getMethods().length-1].getName()); + } + } +} Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/compiler/HelpRootCompiledObjectDecorator.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/compiler/HelpRootCompiledObjectDecorator.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/compiler/HelpRootCompiledObjectDecorator.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -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; + } +} Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/ApplicationHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/ApplicationHandler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/ApplicationHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,36 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.gwt; + +import jaxx.CompilerException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.runtime.gwt.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 { + super.setAttribute(object, propertyName, stringValue, inline, compiler); + } + + + @Override + protected void setDefaults(CompiledObject object, Element tag, JAXXCompiler compiler) throws CompilerException { + super.setDefaults(object, tag, compiler); + } +} \ No newline at end of file Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/CellHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/CellHandler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/CellHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,154 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.gwt; + +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 Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/CheckBoxHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/CheckBoxHandler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/CheckBoxHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,25 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.gwt; + +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.tags.DefaultComponentHandler; + +import javax.swing.AbstractButton; +import javax.swing.event.ChangeListener; + +public class CheckBoxHandler extends DefaultComponentHandler { + public CheckBoxHandler(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 Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/ComboBoxHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/ComboBoxHandler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/ComboBoxHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,65 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.gwt; + +import jaxx.CompilerException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.runtime.gwt.Item; +import jaxx.runtime.gwt.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 ComboBoxHandler extends DefaultComponentHandler { + + public ComboBoxHandler(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.gwt.Item> " + listName + " = new java.util.ArrayList<jaxx.runtime.gwt.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 + ");"); + } + } +} + + + Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/CompiledItemContainer.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/CompiledItemContainer.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/CompiledItemContainer.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,53 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.gwt; + +import jaxx.CompilerException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.runtime.gwt.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 Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/ItemHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/ItemHandler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/ItemHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,144 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.gwt; + +import jaxx.CompilerException; +import jaxx.UnsupportedAttributeException; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.runtime.gwt.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 Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JAXXTabHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JAXXTabHandler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JAXXTabHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -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.gwt; + +import jaxx.reflect.ClassDescriptor; + +/** @author chemit */ +public class JAXXTabHandler extends TableHandler { + public JAXXTabHandler(ClassDescriptor beanClass) { + super(beanClass); + } +} Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JInternalFrameHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JInternalFrameHandler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JInternalFrameHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,54 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.gwt; + +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 Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JPopupMenuHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JPopupMenuHandler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JPopupMenuHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,31 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.gwt; + +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 Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JProgressBarHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JProgressBarHandler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JProgressBarHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,26 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.gwt; + +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 Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JScrollPaneHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JScrollPaneHandler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JScrollPaneHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,41 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.gwt; + +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 Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JSliderHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JSliderHandler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JSliderHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,45 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.gwt; + +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 Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JSpinnerHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JSpinnerHandler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JSpinnerHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,92 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.gwt; + +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 Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JSplitPaneHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JSplitPaneHandler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JSplitPaneHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,69 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.gwt; + +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 Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JTabbedPaneHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JTabbedPaneHandler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JTabbedPaneHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,135 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.gwt; + +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.gwt.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 Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JTextComponentHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JTextComponentHandler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JTextComponentHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,70 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.gwt; + +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.GWTUtil; + +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 GWTUtil.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 Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JToolBarHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JToolBarHandler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JToolBarHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,38 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.gwt; + +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 Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JWindowHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JWindowHandler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/JWindowHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,61 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.gwt; + +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 Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/ListHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/ListHandler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/ListHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,64 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.gwt; + +import jaxx.CompilerException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.runtime.gwt.Item; +import jaxx.runtime.gwt.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 ListHandler extends DefaultComponentHandler { + public ListHandler(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 + ");"); + } + } +} + + + Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/MenuHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/MenuHandler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/MenuHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,26 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.gwt; + +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.tags.DefaultComponentHandler; + +import javax.swing.JMenu; +import javax.swing.event.MenuListener; + +public class MenuHandler extends DefaultComponentHandler { + + public MenuHandler(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 Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/PasswordFieldHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/PasswordFieldHandler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/PasswordFieldHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,25 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.gwt; + +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; + +import javax.swing.JPasswordField; +import javax.swing.event.DocumentListener; + +public class PasswordFieldHandler extends JTextComponentHandler { + + public PasswordFieldHandler(ClassDescriptor beanClass) { + super(beanClass); + ClassDescriptorLoader.checkSupportClass(getClass(), beanClass, JPasswordField.class); + } + + @Override + protected void configureProxyEventInfo() { + super.configureProxyEventInfo(); + addProxyEventInfo("getPassword", DocumentListener.class, "document"); + } +} \ No newline at end of file Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/RadioButtonHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/RadioButtonHandler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/RadioButtonHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,81 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.gwt; + +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.gwt.JAXXButtonGroup; +import jaxx.tags.DefaultComponentHandler; +import jaxx.types.TypeManager; + +import javax.swing.AbstractButton; +import javax.swing.event.ChangeListener; + +public class RadioButtonHandler 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 RadioButtonHandler(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 Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/RowHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/RowHandler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/RowHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,85 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.gwt; + +import jaxx.CompilerException; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.runtime.gwt.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 Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/TabHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/TabHandler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/TabHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,175 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.gwt; + +import jaxx.CompilerException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.I18nHelper; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.runtime.gwt.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 Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/TableHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/TableHandler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/TableHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,124 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.gwt; + +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.gwt.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 Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/TreeHandler.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/TreeHandler.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/tags/gwt/TreeHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,69 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.tags.gwt; + +import jaxx.CompilerException; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.JAXXCompiler; +import jaxx.reflect.ClassDescriptor; +import jaxx.reflect.ClassDescriptorLoader; +import jaxx.runtime.gwt.Item; +import jaxx.runtime.gwt.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 TreeHandler extends DefaultComponentHandler { + public TreeHandler(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 + ");"); + } + } +} + + + Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/types/ColorConverter.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/types/ColorConverter.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/types/ColorConverter.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,34 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package 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 Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/types/GridBagConstraintsConverter.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/types/GridBagConstraintsConverter.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/types/GridBagConstraintsConverter.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,21 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package 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 Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/types/InsetsConverter.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/types/InsetsConverter.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/types/InsetsConverter.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,36 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package 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 Added: jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/types/KeyStrokeConverter.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/types/KeyStrokeConverter.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/java/jaxx/types/KeyStrokeConverter.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,21 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package 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 Added: jaxx/trunk/jaxx-compiler-gwt/src/main/resources/META-INF/services/jaxx.compiler.Generator =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/resources/META-INF/services/jaxx.compiler.Generator (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/resources/META-INF/services/jaxx.compiler.Generator 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1 @@ +jaxx.compiler.GWTGenerator Added: jaxx/trunk/jaxx-compiler-gwt/src/main/resources/META-INF/services/jaxx.spi.Initializer =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/main/resources/META-INF/services/jaxx.spi.Initializer (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/main/resources/META-INF/services/jaxx.spi.Initializer 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1 @@ +jaxx.GWTInitializer \ No newline at end of file Added: jaxx/trunk/jaxx-compiler-gwt/src/test/java/jaxx/junit/ColorConverterTest.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/test/java/jaxx/junit/ColorConverterTest.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/test/java/jaxx/junit/ColorConverterTest.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -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 Added: jaxx/trunk/jaxx-compiler-gwt/src/test/java/jaxx/junit/InsetsConverterTest.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/test/java/jaxx/junit/InsetsConverterTest.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/test/java/jaxx/junit/InsetsConverterTest.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -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 Added: jaxx/trunk/jaxx-compiler-gwt/src/test/java/jaxx/junit/TagManagerTest.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/test/java/jaxx/junit/TagManagerTest.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/test/java/jaxx/junit/TagManagerTest.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,143 @@ +package jaxx.junit; + +import jaxx.compiler.JAXXCompiler; +import jaxx.compiler.JAXXCompilerLaunchor; +import jaxx.compiler.GWTCompiler; +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 GWTCompiler(GWTCompiler.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 Added: jaxx/trunk/jaxx-compiler-gwt/src/test/java/jaxx/runtime/swing/navigation/NavigationTreeModelTest.java =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/test/java/jaxx/runtime/swing/navigation/NavigationTreeModelTest.java (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/test/java/jaxx/runtime/swing/navigation/NavigationTreeModelTest.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,396 @@ +package jaxx.runtime.swing.navigation; + +import jaxx.runtime.DefaultJAXXContext; +import jaxx.runtime.JAXXContext; +import jaxx.runtime.JAXXContextEntryDef; +import jaxx.runtime.gwt.navigation.NavigationTreeModel; +import jaxx.runtime.gwt.navigation.NavigationTreeModelBuilder; +import jaxx.runtime.gwt.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 + ">"; + } + } + +} Added: jaxx/trunk/jaxx-compiler-gwt/src/test/resources/log4j.properties =================================================================== --- jaxx/trunk/jaxx-compiler-gwt/src/test/resources/log4j.properties (rev 0) +++ jaxx/trunk/jaxx-compiler-gwt/src/test/resources/log4j.properties 2009-04-02 12:38:08 UTC (rev 1286) @@ -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 Added: jaxx/trunk/jaxx-gwt-action/.classpath =================================================================== --- jaxx/trunk/jaxx-gwt-action/.classpath (rev 0) +++ jaxx/trunk/jaxx-gwt-action/.classpath 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,22 @@ +<classpath> + <classpathentry kind="src" path="src/main/java"/> + <classpathentry kind="src" path="src/main/resources" including="**/*" excluding="**/*~|**/*.java"/> + <classpathentry kind="src" path="src/test/java" output="target/test-classes"/> + <classpathentry kind="src" path="src/test/resources" output="target/test-classes" excluding="**/*.java"/> + <classpathentry kind="output" path="target/classes"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry kind="var" path="M2_REPO/commons-beanutils/commons-beanutils/1.8.0/commons-beanutils-1.8.0.jar"/> + <classpathentry kind="var" path="M2_REPO/commons-collections/commons-collections/3.2.1/commons-collections-3.2.1.jar"/> + <classpathentry kind="var" path="M2_REPO/commons-jxpath/commons-jxpath/1.3/commons-jxpath-1.3.jar"/> + <classpathentry kind="var" path="M2_REPO/commons-lang/commons-lang/2.4/commons-lang-2.4.jar"/> + <classpathentry kind="var" path="M2_REPO/commons-logging/commons-logging/1.1.1/commons-logging-1.1.1.jar"/> + <classpathentry kind="var" path="M2_REPO/commons-primitives/commons-primitives/1.0/commons-primitives-1.0.jar"/> + <classpathentry kind="var" path="M2_REPO/javax/help/javahelp/2.0.02/javahelp-2.0.02.jar"/> + <classpathentry kind="var" path="M2_REPO/jboss/javassist/3.7.ga/javassist-3.7.ga.jar"/> + <classpathentry kind="src" path="/jaxx-runtime-api"/> + <classpathentry kind="src" path="/jaxx-runtime-gwt"/> + <classpathentry kind="var" path="M2_REPO/junit/junit/4.5/junit-4.5.jar"/> + <classpathentry kind="var" path="M2_REPO/org/swinglabs/jxlayer/3.0.1/jxlayer-3.0.1.jar"/> + <classpathentry kind="var" path="M2_REPO/log4j/log4j/1.2.14/log4j-1.2.14.jar"/> + <classpathentry kind="var" path="M2_REPO/org/codelutin/lutinutil/1.0.3/lutinutil-1.0.3.jar"/> +</classpath> \ No newline at end of file Added: jaxx/trunk/jaxx-gwt-action/.project =================================================================== --- jaxx/trunk/jaxx-gwt-action/.project (rev 0) +++ jaxx/trunk/jaxx-gwt-action/.project 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,16 @@ +<projectDescription> + <name>jaxx-gwt-action</name> + <comment>Jaxx lutin library gwt extension (tabs and actions)</comment> + <projects> + <project>jaxx-runtime-api</project> + <project>jaxx-runtime-gwt</project> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> \ No newline at end of file Added: jaxx/trunk/jaxx-gwt-action/.settings/org.eclipse.jdt.core.prefs =================================================================== --- jaxx/trunk/jaxx-gwt-action/.settings/org.eclipse.jdt.core.prefs (rev 0) +++ jaxx/trunk/jaxx-gwt-action/.settings/org.eclipse.jdt.core.prefs 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,5 @@ +#Mon Mar 30 12:41:57 CEST 2009 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 Added: jaxx/trunk/jaxx-gwt-action/LICENSE.txt =================================================================== --- jaxx/trunk/jaxx-gwt-action/LICENSE.txt (rev 0) +++ jaxx/trunk/jaxx-gwt-action/LICENSE.txt 2009-04-02 12:38:08 UTC (rev 1286) @@ -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. + Added: jaxx/trunk/jaxx-gwt-action/README.txt =================================================================== --- jaxx/trunk/jaxx-gwt-action/README.txt (rev 0) +++ jaxx/trunk/jaxx-gwt-action/README.txt 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,2 @@ +To deploy new version of pom: mvn deploy +To install localy: mvn install Added: jaxx/trunk/jaxx-gwt-action/changelog.txt =================================================================== --- jaxx/trunk/jaxx-gwt-action/changelog.txt (rev 0) +++ jaxx/trunk/jaxx-gwt-action/changelog.txt 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,10 @@ +1.3 chemit 20090320 + +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 Added: jaxx/trunk/jaxx-gwt-action/pom.xml =================================================================== --- jaxx/trunk/jaxx-gwt-action/pom.xml (rev 0) +++ jaxx/trunk/jaxx-gwt-action/pom.xml 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,145 @@ +<?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/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + + <!-- ************************************************************* --> + <!-- *** POM Relationships *************************************** --> + <!-- ************************************************************* --> + + <parent> + <groupId>org.codelutin</groupId> + <artifactId>jaxx</artifactId> + <version>1.3-SNAPSHOT</version> + </parent> + + <groupId>org.codelutin.jaxx</groupId> + <artifactId>jaxx-gwt-action</artifactId> + + <repositories> + <repository> + <id>gwt-maven</id> + <url>http://gwt-maven.googlecode.com/svn/trunk/mavenrepo/</url> + </repository> + </repositories> + + <dependencies> + + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>jaxx-runtime-gwt</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>jboss</groupId> + <artifactId>javassist</artifactId> + <version>3.7.ga</version> + </dependency> + + <!-- GWT Dependencies --> + <dependency> + <groupId>com.google.gwt</groupId> + <artifactId>gwt-servlet</artifactId> + <version>${gwtVersion}</version> + <scope>runtime</scope> + </dependency> + <dependency> + <groupId>com.google.gwt</groupId> + <artifactId>gwt-user</artifactId> + <version>${gwtVersion}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>com.google.gwt</groupId> + <artifactId>gwt-dev</artifactId> + <version>${gwtVersion}</version> + <classifier>${platform}-libs</classifier> + <type>zip</type> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>com.google.gwt</groupId> + <artifactId>gwt-dev</artifactId> + <version>${gwtVersion}</version> + <classifier>${platform}</classifier> + <scope>provided</scope> + </dependency> + + </dependencies> + + <!-- ************************************************************* --> + <!-- *** Project Information ************************************* --> + <!-- ************************************************************* --> + + <name>${project.artifactId}</name> + <description>Jaxx lutin library gwt extension (tabs and actions)</description> + + <!-- ************************************************************* --> + <!-- *** Build Settings ****************************************** --> + <!-- ************************************************************* --> + <packaging>jar</packaging> + + <properties> + + <gwtVersion>1.5.3</gwtVersion> + + </properties> + + <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.codelutin</groupId> + <artifactId>maven-i18n-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>parserJava</goal> + <goal>gen</goal> + </goals> + </execution> + </executions> + </plugin> + + </plugins> + </build> + + <!-- ************************************************************* --> + <!-- *** Build Environment ************************************** --> + <!-- ************************************************************* --> + <scm> + <url>http://labs.libre-entreprise.org/plugins/scmsvn/viewcvs.php/jaxx/trunk/jaxx-gwt-action/?root=buix</url> + <connection>scm:svn:svn://anonymous@labs.libre-entreprise.org/svnroot/buix/jaxx/trunk/jaxx-gwt-action</connection> + <developerConnection>scm:svn:svn+ssh://sletellier@labs.libre-entreprise.org/svnroot/buix/jaxx/trunk/jaxx-gwt-action</developerConnection> + </scm> + + <profiles> + <profile> + <id>gwt-dev-linux</id> + <properties> + <platform>linux</platform> + </properties> + <activation> + <os> + <name>Linux</name> + </os> + </activation> + </profile> + </profiles> + +</project> Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/AbstractActionConfigurationResolver.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/AbstractActionConfigurationResolver.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/AbstractActionConfigurationResolver.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,70 @@ +/** + * ##% 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.codelutin.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. + * + * @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; + } + + public A resolveConfiguration(MyAbstractAction action) { + if (action.hasDelegate()) { + return resolveConfiguration(action.getDelegate()); + } + return action.getClass().getAnnotation(annotationImpl); + } + + @SuppressWarnings({"unchecked"}) + public A applyConfiguration(JComponent component, MyAbstractAction action) { + if (component != null && componentImpl.isAssignableFrom(component.getClass())) + return applyConfiguration0((C) component, action); + + return null; + } + + public Class<A> getAnnotationImpl() { + return annotationImpl; + } + + public Class<C> getComponentImpl() { + return componentImpl; + } +} Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionAnnotationProcessing.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionAnnotationProcessing.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionAnnotationProcessing.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,395 @@ +/** + * ##% 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.codelutin.jaxx.action; + +import javassist.CannotCompileException; +import javassist.ClassPool; +import javassist.CtClass; +import javassist.CtConstructor; +import javassist.LoaderClassPath; +import javassist.NotFoundException; +import org.codelutin.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.codelutin.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); + } + } +} Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionConfig.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionConfig.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionConfig.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -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.codelutin.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.codelutin.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.codelutin.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 Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionConfigConfigurationResolver.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionConfigConfigurationResolver.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionConfigConfigurationResolver.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,67 @@ +/** + * ##% 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.codelutin.jaxx.action; + +import static org.codelutin.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); + } + + 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.codelutin.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; + } +} Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionConfigurationResolver.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionConfigurationResolver.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionConfigurationResolver.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,52 @@ +/** + * ##% 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.codelutin.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. + * + * @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(); +} Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionFactory.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionFactory.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionFactory.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,149 @@ +/** + * ##% 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.codelutin.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. + * + * @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(); +} Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionFactoryFromProvider.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionFactoryFromProvider.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionFactoryFromProvider.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,457 @@ +/* +* ##% 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.codelutin.jaxx.action; + +import jaxx.runtime.JAXXObject; +import jaxx.runtime.gwt.JAXXToggleButton; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.codelutin.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.codelutin.jaxx.action.ActionNameProvider} which gives us at + * runtime the names of each entry to put in cache for the givne action fqn. + * + * @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); + } + + public Class<A> getBaseClass() { + return baseImpl; + } + + public void resetCache() { + cache.clear(); + } + + /*public A get(String actionKey) { + return cache.get(actionKey); + }*/ + + 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. + */ + 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; + } + + public A newAction(String actionKey) { + return newAction(actionKey, null); + } + + public String[] getActionNames() { + return impls.keySet().toArray(new String[impls.size()]); + } + + public Set<Entry<String, Class<? extends MyAbstractAction>>> implsEntrySet() { + return impls.entrySet(); + } + + public Set<Entry<String, A>> cacheEntrySet() { + return cache.entrySet(); + } + + public void fireAction(String actionKey, Object source, JComponent component) { + A action = newAction(actionKey, component); + fireAction0(actionKey, source, action); + } + + 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. + */ + 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; + } + + 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 Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionNameProvider.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionNameProvider.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionNameProvider.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -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.codelutin.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(); + +} Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionProvider.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionProvider.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionProvider.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,35 @@ +/** + * ##% 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.codelutin.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()}. + * + * @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(); + +} Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionProviderAnnotation.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionProviderAnnotation.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionProviderAnnotation.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -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.codelutin.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 { +} Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionProviderFromProperties.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionProviderFromProperties.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ActionProviderFromProperties.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -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.codelutin.jaxx.action; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import static org.codelutin.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; + } +} Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/MyAbstractAction.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/MyAbstractAction.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/MyAbstractAction.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,259 @@ +/** + * ##% 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.codelutin.jaxx.action; + +import jaxx.runtime.JAXXObject; +import org.apache.commons.logging.LogFactory; +import static org.codelutin.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; + } + + 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 enabled = isEnabled(); + if (enabled && hasDelegate()) { + return delegate.beforeAction(evt); + } + return enabled; + } + + 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(); + } +} Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/SelectActionConfig.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/SelectActionConfig.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/SelectActionConfig.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -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.codelutin.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.codelutin.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.codelutin.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 Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/SelectActionConfigConfigurationResolver.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/SelectActionConfigConfigurationResolver.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/SelectActionConfigConfigurationResolver.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,53 @@ +/** + * ##% 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.codelutin.jaxx.action; + +import static org.codelutin.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); + } + + 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 Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ToggleActionConfig.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ToggleActionConfig.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ToggleActionConfig.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -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.codelutin.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.codelutin.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.codelutin.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 Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ToggleActionConfigConfigurationResolver.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ToggleActionConfigConfigurationResolver.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/action/ToggleActionConfigConfigurationResolver.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -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.codelutin.jaxx.action; + +import static org.codelutin.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.codelutin.jaxx.util.UIHelper.createImageIcon(anno.smallIcon())); + } + if (!anno.smallIcon2().isEmpty()) { + action.putValue(Action.SMALL_ICON + "2", org.codelutin.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 Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/tab/TabContentConfig.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/tab/TabContentConfig.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/tab/TabContentConfig.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -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.codelutin.jaxx.tab; + +import jaxx.runtime.gwt.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 {}; + +} Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/tab/TabFactory.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/tab/TabFactory.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/tab/TabFactory.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -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.codelutin.jaxx.tab; + +import jaxx.runtime.JAXXObject; +import jaxx.runtime.gwt.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 Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/tab/TabModel.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/tab/TabModel.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/tab/TabModel.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -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.codelutin.jaxx.tab; + +import java.io.Serializable; + +/** @author chemit */ +public interface TabModel extends Serializable { + + String getName(); + + void setName(String name); + +} Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/AbstractUIAction.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/AbstractUIAction.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/AbstractUIAction.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,53 @@ +/** + * ##% 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.codelutin.jaxx.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** @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); + } */ + } + +} Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/DialogUI.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/DialogUI.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/DialogUI.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,129 @@ +/** + * ##% 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.codelutin.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 :) + * + * @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); + } + + public void windowOpened(WindowEvent e) { + } + + public void windowClosed(WindowEvent e) { + } + + public void windowClosing(WindowEvent e) { + } + + public void windowIconified(WindowEvent e) { + } + + public void windowDeiconified(WindowEvent e) { + } + + public void windowActivated(WindowEvent e) { + } + + 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 Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/DialogUIDef.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/DialogUIDef.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/DialogUIDef.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,235 @@ +/** + * ##% 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.codelutin.jaxx.util; + +import static org.codelutin.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. + * + * @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 ? ", " : ">"); + } +} Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/DialogUIHandler.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/DialogUIHandler.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/DialogUIHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,70 @@ +/** + * ##% 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.codelutin.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 + * + * @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 Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/DialogUIModel.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/DialogUIModel.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/DialogUIModel.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -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.codelutin.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 Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/FactoryWindowListener.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/FactoryWindowListener.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/FactoryWindowListener.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -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.codelutin.jaxx.util; + +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +/** + * A windowListenr for ui managed by {@link org.codelutin.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; + } +} Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/FormElement.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/FormElement.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/FormElement.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,29 @@ +/** + * ##% 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.codelutin.jaxx.util; + +/** @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); +} Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/ShowUIAction.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/ShowUIAction.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/ShowUIAction.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -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.codelutin.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; + +/** @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; + } + + public void actionPerformed(java.awt.event.ActionEvent e) { + checkInit(); + U ui = initUI(e); + ui.setTitle(uiDef.getUiTitle()); + log.info(ui.getTitle()); + //TODO ui.setUndecorated(undecorated); + setPosition(this.getUi(), ui, position); + + ui.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 Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/UIFactory.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/UIFactory.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/UIFactory.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -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.codelutin.jaxx.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.codelutin.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 Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/UIHelper.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/UIHelper.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/UIHelper.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,70 @@ +/* +* ##% 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.codelutin.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; + + 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"); + } + +} Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/UIProvider.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/UIProvider.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/UIProvider.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -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.codelutin.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 Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/config/CancelAction.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/config/CancelAction.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/config/CancelAction.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -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.codelutin.jaxx.util.config; + +import org.codelutin.jaxx.util.AbstractUIAction; +import org.codelutin.jaxx.util.DialogUI; +import org.codelutin.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.codelutin.i18n.I18n._("lutinui.config.cancel"); + putValue(NAME, text); + putValue(DISPLAYED_MNEMONIC_INDEX_KEY, 0); + putValue(MNEMONIC_KEY, (int) text.charAt(0)); + } + String libelle = org.codelutin.i18n.I18n._("lutinui.config.cancel.tooltip"); + putValue(SHORT_DESCRIPTION, libelle); + + } + + public void actionPerformed(ActionEvent e) { + getUi().dispose(); + } +} \ No newline at end of file Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/config/DialogConfigUI.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/config/DialogConfigUI.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/config/DialogConfigUI.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -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.codelutin.jaxx.util.config; + +import org.codelutin.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 Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/config/DialogConfigUIHandler.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/config/DialogConfigUIHandler.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/config/DialogConfigUIHandler.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -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.codelutin.jaxx.util.config; + +import org.codelutin.jaxx.util.DialogUIHandler; +import org.codelutin.util.ConverterUtil; +import org.codelutin.util.config.Config; +import org.codelutin.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 Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/config/DialogConfigUIModel.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/config/DialogConfigUIModel.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/config/DialogConfigUIModel.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -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.codelutin.jaxx.util.config; + +import org.codelutin.jaxx.util.DialogUIModel; +import org.codelutin.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 Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/config/ResetAction.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/config/ResetAction.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/config/ResetAction.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -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.codelutin.jaxx.util.config; + +import org.codelutin.jaxx.util.AbstractUIAction; +import org.codelutin.jaxx.util.DialogUI; +import org.codelutin.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.codelutin.i18n.I18n._("lutinui.config.reset"); + putValue(NAME, text); + putValue(DISPLAYED_MNEMONIC_INDEX_KEY, 0); + putValue(MNEMONIC_KEY, (int) text.charAt(0)); + } + String libelle = org.codelutin.i18n.I18n._("lutinui.config.reset.tooltip"); + putValue(SHORT_DESCRIPTION, libelle); + + } + + public void actionPerformed(ActionEvent e) { + getHandler().getModel().reset(); + } +} \ No newline at end of file Added: jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/config/SaveAction.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/config/SaveAction.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/java/org/codelutin/jaxx/util/config/SaveAction.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -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.codelutin.jaxx.util.config; + +import org.codelutin.jaxx.util.AbstractUIAction; +import org.codelutin.jaxx.util.DialogUI; +import org.codelutin.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.codelutin.i18n.I18n._("lutinui.config.save"); + putValue(NAME, text); + putValue(DISPLAYED_MNEMONIC_INDEX_KEY, 0); + putValue(MNEMONIC_KEY, (int) text.charAt(0)); + } + String libelle = org.codelutin.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(); + } + } +} Added: jaxx/trunk/jaxx-gwt-action/src/main/resources/META-INF/services/javax.annotation.processing.Processor =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/resources/META-INF/services/javax.annotation.processing.Processor (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/resources/META-INF/services/javax.annotation.processing.Processor 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1 @@ +org.codelutin.jaxx.action.ActionAnnotationProcessing \ No newline at end of file Added: jaxx/trunk/jaxx-gwt-action/src/main/resources/i18n/jaxx-gwt-action-en_GB.properties =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/resources/i18n/jaxx-gwt-action-en_GB.properties (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/resources/i18n/jaxx-gwt-action-en_GB.properties 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,10 @@ +jaxx.action.done=jaxx.action.done +jaxx.error.close.actions.file=jaxx.error.close.actions.file +jaxx.error.load.actions.class=jaxx.error.load.actions.class +jaxx.error.load.actions.file=jaxx.error.load.actions.file +lutinui.config.cancel=lutinui.config.cancel +lutinui.config.cancel.tooltip=lutinui.config.cancel.tooltip +lutinui.config.reset=lutinui.config.reset +lutinui.config.reset.tooltip=lutinui.config.reset.tooltip +lutinui.config.save=lutinui.config.save +lutinui.config.save.tooltip=lutinui.config.save.tooltip Added: jaxx/trunk/jaxx-gwt-action/src/main/resources/i18n/jaxx-gwt-action-fr_FR.properties =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/resources/i18n/jaxx-gwt-action-fr_FR.properties (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/resources/i18n/jaxx-gwt-action-fr_FR.properties 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,10 @@ +jaxx.action.done= +jaxx.error.close.actions.file= +jaxx.error.load.actions.class= +jaxx.error.load.actions.file= +lutinui.config.cancel= +lutinui.config.cancel.tooltip= +lutinui.config.reset= +lutinui.config.reset.tooltip= +lutinui.config.save= +lutinui.config.save.tooltip= Added: jaxx/trunk/jaxx-gwt-action/src/main/resources/i18n/jaxx-swing-action-en_GB.properties =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/resources/i18n/jaxx-swing-action-en_GB.properties (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/resources/i18n/jaxx-swing-action-en_GB.properties 2009-04-02 12:38:08 UTC (rev 1286) @@ -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 Added: jaxx/trunk/jaxx-gwt-action/src/main/resources/i18n/jaxx-swing-action-fr_FR.properties =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/main/resources/i18n/jaxx-swing-action-fr_FR.properties (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/main/resources/i18n/jaxx-swing-action-fr_FR.properties 2009-04-02 12:38:08 UTC (rev 1286) @@ -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 Added: jaxx/trunk/jaxx-gwt-action/src/site/fr/rst/Todo.rst =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/site/fr/rst/Todo.rst (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/site/fr/rst/Todo.rst 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,4 @@ +TODO +==== + +a faire \ No newline at end of file Added: jaxx/trunk/jaxx-gwt-action/src/site/fr/rst/index.rst =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/site/fr/rst/index.rst (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/site/fr/rst/index.rst 2009-04-02 12:38:08 UTC (rev 1286) @@ -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.** Added: jaxx/trunk/jaxx-gwt-action/src/test/java/jaxx/runtime/UtilTest.java =================================================================== --- jaxx/trunk/jaxx-gwt-action/src/test/java/jaxx/runtime/UtilTest.java (rev 0) +++ jaxx/trunk/jaxx-gwt-action/src/test/java/jaxx/runtime/UtilTest.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,25 @@ +package jaxx.runtime; + +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + +public class UtilTest extends junit.framework.TestCase { + private int count; + + + public void testGetEventListener() { + count = 0; + DocumentListener listener = (DocumentListener) jaxx.runtime.Util.getEventListener(javax.swing.event.DocumentListener.class, this, "incCount"); + listener.insertUpdate(null); + assertEquals(count, 1); + DocumentListener listener2 = (DocumentListener) jaxx.runtime.Util.getEventListener(javax.swing.event.DocumentListener.class, this, "incCount"); + listener2.removeUpdate(null); + 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 Added: jaxx/trunk/jaxx-runtime-gwt/.classpath =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/.classpath (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/.classpath 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,20 @@ +<classpath> + <classpathentry kind="src" path="src/main/java"/> + <classpathentry kind="src" path="src/main/resources" including="**/*" excluding="**/*~|**/*.java"/> + <classpathentry kind="src" path="src/test/java" output="target/test-classes"/> + <classpathentry kind="src" path="src/test/resources" output="target/test-classes" excluding="**/*.java"/> + <classpathentry kind="output" path="target/classes"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry kind="var" path="M2_REPO/commons-beanutils/commons-beanutils/1.8.0/commons-beanutils-1.8.0.jar"/> + <classpathentry kind="var" path="M2_REPO/commons-collections/commons-collections/3.2.1/commons-collections-3.2.1.jar"/> + <classpathentry kind="var" path="M2_REPO/commons-jxpath/commons-jxpath/1.3/commons-jxpath-1.3.jar"/> + <classpathentry kind="var" path="M2_REPO/commons-lang/commons-lang/2.4/commons-lang-2.4.jar"/> + <classpathentry kind="var" path="M2_REPO/commons-logging/commons-logging/1.1.1/commons-logging-1.1.1.jar"/> + <classpathentry kind="var" path="M2_REPO/commons-primitives/commons-primitives/1.0/commons-primitives-1.0.jar"/> + <classpathentry kind="var" path="M2_REPO/javax/help/javahelp/2.0.02/javahelp-2.0.02.jar"/> + <classpathentry kind="src" path="/jaxx-runtime-api"/> + <classpathentry kind="var" path="M2_REPO/junit/junit/4.5/junit-4.5.jar"/> + <classpathentry kind="var" path="M2_REPO/org/swinglabs/jxlayer/3.0.1/jxlayer-3.0.1.jar"/> + <classpathentry kind="var" path="M2_REPO/log4j/log4j/1.2.14/log4j-1.2.14.jar"/> + <classpathentry kind="var" path="M2_REPO/org/codelutin/lutinutil/1.0.3/lutinutil-1.0.3.jar"/> +</classpath> \ No newline at end of file Added: jaxx/trunk/jaxx-runtime-gwt/.project =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/.project (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/.project 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,15 @@ +<projectDescription> + <name>jaxx-runtime-gwt</name> + <comment>Jaxx runtime gwt extension</comment> + <projects> + <project>jaxx-runtime-api</project> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> \ No newline at end of file Added: jaxx/trunk/jaxx-runtime-gwt/.settings/org.eclipse.jdt.core.prefs =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/.settings/org.eclipse.jdt.core.prefs (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/.settings/org.eclipse.jdt.core.prefs 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,5 @@ +#Mon Mar 30 12:41:55 CEST 2009 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 Added: jaxx/trunk/jaxx-runtime-gwt/LICENSE.txt =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/LICENSE.txt (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/LICENSE.txt 2009-04-02 12:38:08 UTC (rev 1286) @@ -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. + Added: jaxx/trunk/jaxx-runtime-gwt/README.txt =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/README.txt (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/README.txt 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,2 @@ +To deploy new version of pom: mvn deploy +To install localy: mvn install Added: jaxx/trunk/jaxx-runtime-gwt/changelog.txt =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/changelog.txt (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/changelog.txt 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,110 @@ +1.3 chemit 20090321 + * 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) Added: jaxx/trunk/jaxx-runtime-gwt/pom.xml =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/pom.xml (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/pom.xml 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,108 @@ +<?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/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <!-- ************************************************************* --> + <!-- *** POM Relationships *************************************** --> + <!-- ************************************************************* --> + + <parent> + <groupId>org.codelutin</groupId> + <artifactId>jaxx</artifactId> + <version>1.3-SNAPSHOT</version> + </parent> + + <groupId>org.codelutin.jaxx</groupId> + <artifactId>jaxx-runtime-gwt</artifactId> + + <repositories> + <repository> + <id>gwt-maven</id> + <url>http://gwt-maven.googlecode.com/svn/trunk/mavenrepo/</url> + </repository> + </repositories> + + <dependencies> + + <!-- sibling dependencies --> + + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>jaxx-runtime-api</artifactId> + <version>${project.version}</version> + </dependency> + + <!-- GWT Dependencies --> + <dependency> + <groupId>com.google.gwt</groupId> + <artifactId>gwt-servlet</artifactId> + <version>${gwtVersion}</version> + <scope>runtime</scope> + </dependency> + <dependency> + <groupId>com.google.gwt</groupId> + <artifactId>gwt-user</artifactId> + <version>${gwtVersion}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>com.google.gwt</groupId> + <artifactId>gwt-dev</artifactId> + <version>${gwtVersion}</version> + <classifier>${platform}-libs</classifier> + <type>zip</type> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>com.google.gwt</groupId> + <artifactId>gwt-dev</artifactId> + <version>${gwtVersion}</version> + <classifier>${platform}</classifier> + <scope>provided</scope> + </dependency> + + + </dependencies> + + <!-- ************************************************************* --> + <!-- *** Project Information ************************************* --> + <!-- ************************************************************* --> + + <name>${project.artifactId}</name> + <description>Jaxx runtime gwt extension</description> + + <!-- ************************************************************* --> + <!-- *** Build Settings ****************************************** --> + <!-- ************************************************************* --> + <packaging>jar</packaging> + + <properties> + + <gwtVersion>1.5.3</gwtVersion> + + </properties> + + <!-- ************************************************************* --> + <!-- *** Build Environment ************************************** --> + <!-- ************************************************************* --> + <scm> + <url>http://labs.libre-entreprise.org/plugins/scmsvn/viewcvs.php/jaxx/trunk/jaxx-runtime-gwt/?root=buix</url> + <connection>scm:svn:svn://anonymous@labs.libre-entreprise.org/svnroot/buix/jaxx/trunk/jaxx-runtime-gwt</connection> + <developerConnection>scm:svn:svn+ssh://sletellier@labs.libre-entreprise.org/svnroot/buix/jaxx/trunk/jaxx-runtime-gwt</developerConnection> + </scm> + + <profiles> + <profile> + <id>gwt-dev-linux</id> + <properties> + <platform>linux</platform> + </properties> + <activation> + <os> + <name>Linux</name> + </os> + </activation> + </profile> + </profiles> +</project> Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/beaninfos/HBoxBeanInfo.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/beaninfos/HBoxBeanInfo.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/beaninfos/HBoxBeanInfo.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,58 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.beaninfos; + +import jaxx.runtime.gwt.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); + } + } +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/beaninfos/VBoxBeanInfo.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/beaninfos/VBoxBeanInfo.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/beaninfos/VBoxBeanInfo.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,58 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.beaninfos; + +import jaxx.runtime.gwt.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); + } + } +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/GWTUtil.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/GWTUtil.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/GWTUtil.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,484 @@ +package jaxx.runtime; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +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.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.Icon; +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JTabbedPane; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + +import jaxx.runtime.gwt.I18nTableCellRenderer; +import jaxx.runtime.gwt.Item; +import jaxx.runtime.gwt.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 GWTUtil extends Util { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private final Log log = LogFactory.getLog(GWTUtil.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 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(); + 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)); + } + for (Object d : data) { + items.add(new Item(d.toString(), d.toString(), d, d.equals(select))); + } + combo.setItems(items); + } + + 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)); + } + + /** + * 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(); + 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; + } + + 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(GWTUtil.class.getResourceAsStream(defaultUIConfig)); + if (log.isDebugEnabled()) { + log.debug(p.toString()); + } + if (extraUIConfig != null) { + InputStream extraStream = GWTUtil.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; + } +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/JaxxHelpUI.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/JaxxHelpUI.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/JaxxHelpUI.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,24 @@ +package jaxx.runtime; + +import java.awt.Component; + +import jaxx.runtime.gwt.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); +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/Application.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/Application.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/Application.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,56 @@ +package jaxx.runtime.gwt; + +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 Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/BlockingLayerUI.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/BlockingLayerUI.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/BlockingLayerUI.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,259 @@ +package jaxx.runtime.gwt; + +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); + } +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/BlockingLayerUI2.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/BlockingLayerUI2.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/BlockingLayerUI2.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,206 @@ +package jaxx.runtime.gwt; + +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; + /** + * 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 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.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); + + // 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)); + */ + + 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); + } +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/CardLayout2.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/CardLayout2.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/CardLayout2.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,221 @@ +package jaxx.runtime.gwt; + +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(); + + } + +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/CardLayout2Ext.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/CardLayout2Ext.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/CardLayout2Ext.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,99 @@ +package jaxx.runtime.gwt; + +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); + } + } +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/DecoratorTableCellRenderer.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/DecoratorTableCellRenderer.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/DecoratorTableCellRenderer.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,33 @@ +package jaxx.runtime.gwt; + +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 Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/HBox.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/HBox.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/HBox.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,102 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.gwt; + +import javax.swing.JPanel; +import java.awt.Insets; + +/** + * Panel which uses an {@link HBoxLayout} by default. + * + * @author Ethan Nicholas + */ +public class HBox extends JPanel { + 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; + } +} \ No newline at end of file Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/HBoxLayout.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/HBoxLayout.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/HBoxLayout.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,132 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.gwt; + +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; + } + + + public void addLayoutComponent(String name, Component comp) { + } + + + 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; + } + } + + + 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); + } + + + 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); + } + + + public void removeLayoutComponent(Component comp) { + } +} \ No newline at end of file Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/I18nTableCellRenderer.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/I18nTableCellRenderer.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/I18nTableCellRenderer.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,56 @@ +package jaxx.runtime.gwt; + +import static org.codelutin.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]; + } + } + + 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; + } +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/Item.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/Item.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/Item.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,192 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.gwt; + +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 + "]"; + } +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JAXXButtonGroup.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JAXXButtonGroup.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JAXXButtonGroup.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,239 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.gwt; + +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); + } + } + } + + +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JAXXComboBox.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JAXXComboBox.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JAXXComboBox.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,213 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.gwt; + +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 { + 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() { + 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); + } + } + + + public Object getElementAt(int i) { + return items.get(i).getValue(); + } + + + public int getSize() { + return items.size(); + } + + + public Object getSelectedItem() { + return selectedItem; + } + + + 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() { + 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() { + 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]); + } + } +} \ No newline at end of file Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JAXXList.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JAXXList.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JAXXList.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,295 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.gwt; + +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 { + 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() { + 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); + } + } + + + public Object getElementAt(int i) { + return items.get(i).getValue(); + } + + + public int getSize() { + return items.size(); + } + } + + public JAXXList() { + setCellRenderer(new DefaultListCellRenderer() { + @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() { + 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){ + 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]=((Integer)selectedIndices.get(i)).intValue(); + } + setSelectedIndices(ints); + } +} \ No newline at end of file Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JAXXTab.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JAXXTab.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JAXXTab.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,23 @@ +/* +* ##% 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.gwt; + +/** @author chemit */ +public class JAXXTab extends Table { +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JAXXToggleButton.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JAXXToggleButton.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JAXXToggleButton.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,94 @@ +package jaxx.runtime.gwt; + +public class JAXXToggleButton extends javax.swing.JToggleButton { + + 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; + } + +} \ No newline at end of file Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JAXXTree.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JAXXTree.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JAXXTree.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,213 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.gwt; + +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 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() { + 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); + } + } + + + 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()); + } + + + public Object getChild(Object parent, int index) { + Item node = findItem(parent); + return node.getChildren().get(index).getValue(); + } + + + public int getChildCount(Object parent) { + Item node = findItem(parent); + return node.getChildren().size(); + } + + + 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; + } + + + public Object getRoot() { + return root.getValue(); + } + + + public boolean isLeaf(Object node) { + Item item = findItem(node); + return item != null && item.getChildren().size() == 0; + } + + + public void removeTreeModelListener(TreeModelListener listener) { + listeners.remove(listener); + } + + + public void fireTreeNodesChanged(TreeModelEvent e) { + for (TreeModelListener listener : listeners) { + listener.treeNodesChanged(e); + } + } + + + public void valueForPathChanged(TreePath path, Object newValue) { + } + } + + public JAXXTree() { + setCellRenderer(new DefaultTreeCellRenderer() { + @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() { + 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; + } +} \ No newline at end of file Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JaxxHelpBroker.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JaxxHelpBroker.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/JaxxHelpBroker.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,510 @@ +package jaxx.runtime.gwt; + +import java.applet.Applet; +import java.awt.*; +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.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Vector; +import javax.help.CSH; +import javax.help.CSH.DisplayHelpFromSource; +import javax.help.HelpBroker; +import javax.help.HelpSet; +import javax.swing.AbstractButton; +import javax.swing.JComponent; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import jaxx.runtime.JAXXContext; +import jaxx.runtime.JAXXObject; +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 ActionListener showHelpAction; + protected Hashtable<Component, Cursor> cursors; + protected Cursor onItemCursor; + + 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; + 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 AbstractButton getShowHelperButton(JAXXObject c) { + return (AbstractButton) c.getObjectById("showHelp"); + } + + 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 = getShowHelperButton(c); + + if (help == null) { + log.warn("no showButton detected for " + c.getClass()); + } else { + boolean needListener = true; + for (ActionListener a : help.getActionListeners()) { + if (a instanceof DisplayHelpFromSource) { + needListener = false; + break; + } + } + if (needListener) { + // attach context to button + help.putClientProperty(JAXX_CONTEXT_ENTRY, c.getDelegateContext()); + help.addActionListener(getShowHelpAction(c)); + } + + } + if (log.isDebugEnabled()) { + log.debug("for " + c); + } + + //installUI(c, new java.util.ArrayList<String>()); + } + + 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() { + log.info(this); + new CSH.DisplayHelpFromSource(helpBroker); + } + + public void showHelp(JAXXContext context, String helpId) { + } + + public void installUI(Component comp, String helpId) { + CSH.setHelpIDString(comp, helpId); + } + + protected void installUI(Object comp, List<String> scanned) { + //log.info(comp); + if (comp instanceof JComponent) { + JComponent c = (JComponent) comp; + if (scanned.contains(c.getName())) { + return; + } else { + scanned.add(c.getName()); + } + Object id = c.getClientProperty(helpKey); + if (id != null && id instanceof String) { + String helpId = (String) id; + + CSH.setHelpIDString(c, helpId); + + log.info(c.getName() + " : " + helpId); + + if (log.isDebugEnabled()) { + log.debug(c.getName() + " : " + helpId); + + } + } + } + + if (comp instanceof JAXXObject) { + JAXXObject jo = (JAXXObject) comp; + + + Map<String, Object> $objectMap = jo.get$objectMap(); + for (String key : $objectMap.keySet()) { + + if (scanned.contains(key)) { + continue; + } + + Object o = $objectMap.get(key); + + if (o == comp) { + continue; + } + + if (o instanceof JAXXObject) { + installUI(o, scanned); + scanned.add(key); + continue; + } + if (o instanceof JComponent) { + installUI(o, scanned); + continue; + } + } + } + } + + protected ActionListener getShowHelpAction(JAXXContext context) { + if (showHelpAction == null) { + showHelpAction = addShowHelpAction(context); + } + return showHelpAction; + } + + protected ActionListener addShowHelpAction(JAXXContext context) { + return new CSH.DisplayHelpAfterTracking(helpBroker); + } + + protected String getHelpID(Component source) { + String helpID = null; + + // It is necessery for UIManager.get("HelpOnItemCursor"); + + // Get the onItemCursor + onItemCursor = (Cursor) UIManager.get("HelpOnItemCursor"); + if (onItemCursor == null) { + return null; + } + + // change all the cursors on all windows + 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); + } + } + /*MouseEvent event = getMouseEvent(); + + if (event != null) { + Component comp = (Component)event.getSource(); + log.info("component traking!!!!!!!! " + comp.getName()+" : "+comp.getClass().getName()); + }*/ + + + Object o = CSH.trackCSEvents(); + + if (o instanceof Component) { + + helpID = CSH.getHelpIDString((Component) o); + + log.info("component traking " + ((Component) o).getName() + " : " + helpID); + + if (log.isDebugEnabled()) { + log.debug("component traking " + ((Component) o).getName() + " : " + helpID); + } + } + + /*HelpSet objHS = getHelpset(); + try { + ID id = ID.create(helpID, objHS); + if (id == null) { + id = objHS.getHomeID(); + } + + } catch (Exception e2) { + e2.printStackTrace(); + } + if (helpID == null) { + helpID = getDefaultID(); + }*/ + + // restore the old cursors + if (topComponents != null) { + Enumeration containers = topComponents.elements(); + while (containers.hasMoreElements()) { + resetAndRestoreCursors((Container) containers.nextElement()); + } + } + cursors = null; + + return helpID; + } + + /* + * 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 + + // 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.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 { + System.err.println("unable to dispatch event: " + event); + } + } + } + } catch (InterruptedException e) { + log.debug(e); + } + 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 { + System.err.println("unable to dispatch event: " + event); + } + } +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/Spacer.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/Spacer.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/Spacer.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,10 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.gwt; + +import javax.swing.JComponent; + +public class Spacer extends JComponent { +} \ No newline at end of file Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/TabInfo.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/TabInfo.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/TabInfo.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,165 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.gwt; + +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); + } +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/TabInfoPropertyChangeListener.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/TabInfoPropertyChangeListener.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/TabInfoPropertyChangeListener.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,41 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.gwt; + +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; + } + + 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()); + } +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/Table.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/Table.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/Table.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,63 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.gwt; + +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 { + 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; + } + + + 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(); + } +} \ No newline at end of file Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/VBox.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/VBox.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/VBox.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,101 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.gwt; + +import javax.swing.JPanel; +import java.awt.Insets; + +/** + * Panel which uses a {@link VBoxLayout} by default. + * + * @author Ethan Nicholas + */ +public class VBox extends JPanel { + 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); + } + + + 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; + } +} \ No newline at end of file Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/VBoxLayout.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/VBoxLayout.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/VBoxLayout.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,132 @@ +/* + * Copyright 2006 Ethan Nicholas. All rights reserved. + * Use is subject to license terms. + */ +package jaxx.runtime.gwt; + +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; + } + + + public void addLayoutComponent(String name, Component comp) { + } + + + 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; + } + } + + + 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); + } + + + 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); + } + + + public void removeLayoutComponent(Component comp) { + } +} \ No newline at end of file Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/navigation/NavigationTreeCellRenderer.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/navigation/NavigationTreeCellRenderer.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/navigation/NavigationTreeCellRenderer.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,94 @@ +package jaxx.runtime.gwt.navigation; + +import jaxx.runtime.JAXXContext; +import jaxx.runtime.gwt.navigation.NavigationTreeModel.NavigationTreeNode; +import jaxx.runtime.gwt.navigation.NavigationUtil.NodeRenderer; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.codelutin.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; + } + +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/navigation/NavigationTreeModel.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/navigation/NavigationTreeModel.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/navigation/NavigationTreeModel.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,590 @@ +package jaxx.runtime.gwt.navigation; + + +import jaxx.runtime.JAXXAction; +import jaxx.runtime.JAXXContext; +import jaxx.runtime.JAXXContextEntryDef; +import jaxx.runtime.JAXXObject; +import jaxx.runtime.gwt.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; + } + } + +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/navigation/NavigationTreeModelBuilder.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/navigation/NavigationTreeModelBuilder.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/navigation/NavigationTreeModelBuilder.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,152 @@ +package jaxx.runtime.gwt.navigation; + +import jaxx.runtime.Decorator; +import jaxx.runtime.JAXXAction; +import jaxx.runtime.JAXXContextEntryDef; +import jaxx.runtime.JAXXObject; +import jaxx.runtime.gwt.navigation.NavigationTreeModel.NavigationTreeNode; +import jaxx.runtime.gwt.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); + } + } + } + } + +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/navigation/NavigationTreeSelectionAdapter.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/navigation/NavigationTreeSelectionAdapter.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/navigation/NavigationTreeSelectionAdapter.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,243 @@ +package jaxx.runtime.gwt.navigation; + +import jaxx.runtime.JAXXAction; +import jaxx.runtime.JAXXContextEntryDef; +import jaxx.runtime.JAXXObject; +import jaxx.runtime.gwt.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; + } + + 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 Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/navigation/NavigationTreeSelectionAdapterWithCardLayout.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/navigation/NavigationTreeSelectionAdapterWithCardLayout.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/navigation/NavigationTreeSelectionAdapterWithCardLayout.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,109 @@ +package jaxx.runtime.gwt.navigation; + +import jaxx.runtime.JAXXAction; +import jaxx.runtime.JAXXContext; +import jaxx.runtime.JAXXInitialContext; +import jaxx.runtime.JAXXObject; +import jaxx.runtime.gwt.CardLayout2; +import jaxx.runtime.gwt.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.gwt.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; + } +} + Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/navigation/NavigationUtil.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/navigation/NavigationUtil.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/navigation/NavigationUtil.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,155 @@ +package jaxx.runtime.gwt.navigation; + +import jaxx.runtime.Decorator; +import jaxx.runtime.JAXXContext; +import jaxx.runtime.gwt.navigation.NavigationTreeModel.NavigationTreeNode; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import static org.codelutin.i18n.I18n._; + +import java.lang.reflect.InvocationTargetException; +import java.util.regex.Pattern; + +/** + * Usefull methods on {@link NavigationTreeModel} and others. + * + * @author chemit + * @see jaxx.runtime.gwt.navigation.NavigationTreeModel + * @see jaxx.runtime.gwt.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); + } + } + } + +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardModel.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardModel.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardModel.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,238 @@ +package jaxx.runtime.gwt.wizard; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; + +/** + * 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 java.util.List<E> steps; + /** + * 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 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() { + } +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardOperationAction.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardOperationAction.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardOperationAction.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,108 @@ +package jaxx.runtime.gwt.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; + } + } +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardOperationActionThread.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardOperationActionThread.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardOperationActionThread.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,204 @@ +package jaxx.runtime.gwt.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(); + } + } +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardOperationModel.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardOperationModel.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardOperationModel.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,263 @@ +package jaxx.runtime.gwt.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); + } + + 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; + } +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardOperationState.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardOperationState.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardOperationState.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,32 @@ +package jaxx.runtime.gwt.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 +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardOperationStep.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardOperationStep.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardOperationStep.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,34 @@ +package jaxx.runtime.gwt.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(); +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardStep.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardStep.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardStep.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,20 @@ +package jaxx.runtime.gwt.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(); +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardStepUI.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardStepUI.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardStepUI.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,14 @@ +package jaxx.runtime.gwt.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(); +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardUI.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardUI.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardUI.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,94 @@ +package jaxx.runtime.gwt.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) ; + +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardUILancher.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardUILancher.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardUILancher.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,162 @@ +package jaxx.runtime.gwt.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; + } +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardUtil.java =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardUtil.java (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/WizardUtil.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,97 @@ +package jaxx.runtime.gwt.wizard; + +import java.beans.IndexedPropertyChangeEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.lang.reflect.Array; +import org.apache.commons.logging.Log; + +/** + * Classe de méthodes utiles sur les wizard. + * + * @author tony + * @since 1.3 + */ +public class WizardUtil { + + 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; + } + } + }); + } +} Added: jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/package.html =================================================================== --- jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/package.html (rev 0) +++ jaxx/trunk/jaxx-runtime-gwt/src/main/java/jaxx/runtime/gwt/wizard/package.html 2009-04-02 12:38:08 UTC (rev 1286) @@ -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 Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-config-16.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-config-16.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-config.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-config.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-message-16.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-message-16.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-message.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-message.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-next-16.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-next-16.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-next.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-next.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-pause-16.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-pause-16.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-pause.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-pause.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-previous-16.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-previous-16.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-previous.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-previous.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-refresh-16.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-refresh-16.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-refresh.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-refresh.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-start-16.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-start-16.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-start.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-start.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-canceled-16.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-canceled-16.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-canceled.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-canceled.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-failed-16.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-failed-16.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-failed.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-failed.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-need_fix-16.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-need_fix-16.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-need_fix.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-need_fix.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-pending-16.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-pending-16.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-pending.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-pending.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-running-16.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-running-16.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-running.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-running.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-successed-16.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-successed-16.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-successed.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-gwt/src/main/resources/icons/action-wizard-state-successed.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-validator-gwt/.classpath =================================================================== --- jaxx/trunk/jaxx-runtime-validator-gwt/.classpath (rev 0) +++ jaxx/trunk/jaxx-runtime-validator-gwt/.classpath 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,24 @@ +<classpath> + <classpathentry kind="src" path="src/main/java"/> + <classpathentry kind="src" path="src/main/resources" including="**/*" excluding="**/*~|**/*.java"/> + <classpathentry kind="src" path="src/test/java" output="target/test-classes"/> + <classpathentry kind="src" path="src/test/resources" output="target/test-classes" excluding="**/*.java"/> + <classpathentry kind="output" path="target/classes"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry kind="var" path="M2_REPO/commons-beanutils/commons-beanutils/1.8.0/commons-beanutils-1.8.0.jar"/> + <classpathentry kind="var" path="M2_REPO/commons-collections/commons-collections/3.2.1/commons-collections-3.2.1.jar"/> + <classpathentry kind="var" path="M2_REPO/commons-jxpath/commons-jxpath/1.3/commons-jxpath-1.3.jar"/> + <classpathentry kind="var" path="M2_REPO/commons-lang/commons-lang/2.4/commons-lang-2.4.jar"/> + <classpathentry kind="var" path="M2_REPO/commons-logging/commons-logging/1.1.1/commons-logging-1.1.1.jar"/> + <classpathentry kind="var" path="M2_REPO/commons-primitives/commons-primitives/1.0/commons-primitives-1.0.jar"/> + <classpathentry kind="var" path="M2_REPO/javax/help/javahelp/2.0.02/javahelp-2.0.02.jar"/> + <classpathentry kind="src" path="/jaxx-runtime-api"/> + <classpathentry kind="src" path="/jaxx-runtime-gwt"/> + <classpathentry kind="src" path="/jaxx-runtime-validator"/> + <classpathentry kind="var" path="M2_REPO/junit/junit/4.5/junit-4.5.jar"/> + <classpathentry kind="var" path="M2_REPO/org/swinglabs/jxlayer/3.0.1/jxlayer-3.0.1.jar"/> + <classpathentry kind="var" path="M2_REPO/log4j/log4j/1.2.14/log4j-1.2.14.jar"/> + <classpathentry kind="var" path="M2_REPO/org/codelutin/lutinutil/1.0.3/lutinutil-1.0.3.jar"/> + <classpathentry kind="var" path="M2_REPO/opensymphony/ognl/2.6.11/ognl-2.6.11.jar"/> + <classpathentry kind="var" path="M2_REPO/com/opensymphony/xwork/2.1.1-cl_20090130/xwork-2.1.1-cl_20090130.jar"/> +</classpath> \ No newline at end of file Added: jaxx/trunk/jaxx-runtime-validator-gwt/.project =================================================================== --- jaxx/trunk/jaxx-runtime-validator-gwt/.project (rev 0) +++ jaxx/trunk/jaxx-runtime-validator-gwt/.project 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,17 @@ +<projectDescription> + <name>jaxx-runtime-validator-gwt</name> + <comment>Jaxx validation swing extension</comment> + <projects> + <project>jaxx-runtime-api</project> + <project>jaxx-runtime-gwt</project> + <project>jaxx-runtime-validator</project> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> \ No newline at end of file Added: jaxx/trunk/jaxx-runtime-validator-gwt/.settings/org.eclipse.jdt.core.prefs =================================================================== --- jaxx/trunk/jaxx-runtime-validator-gwt/.settings/org.eclipse.jdt.core.prefs (rev 0) +++ jaxx/trunk/jaxx-runtime-validator-gwt/.settings/org.eclipse.jdt.core.prefs 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,5 @@ +#Mon Mar 30 12:41:56 CEST 2009 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 Added: jaxx/trunk/jaxx-runtime-validator-gwt/LICENSE.txt =================================================================== --- jaxx/trunk/jaxx-runtime-validator-gwt/LICENSE.txt (rev 0) +++ jaxx/trunk/jaxx-runtime-validator-gwt/LICENSE.txt 2009-04-02 12:38:08 UTC (rev 1286) @@ -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. + Added: jaxx/trunk/jaxx-runtime-validator-gwt/README.txt =================================================================== --- jaxx/trunk/jaxx-runtime-validator-gwt/README.txt (rev 0) +++ jaxx/trunk/jaxx-runtime-validator-gwt/README.txt 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,2 @@ +To deploy new version of pom: mvn deploy +To install localy: mvn install Added: jaxx/trunk/jaxx-runtime-validator-gwt/changelog.txt =================================================================== --- jaxx/trunk/jaxx-runtime-validator-gwt/changelog.txt (rev 0) +++ jaxx/trunk/jaxx-runtime-validator-gwt/changelog.txt 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,6 @@ +1.3 chemit 20090321 + * 20090320 [chemit] - rename and move SwingValidationUtil to jaxx.runtime.SwingValidatorUtil + * 20090319 [chemit] - refactor Validator : now can deal with scopes, improve design + +1.1 chemit 20090220 + * 20090203 [chemit] - introduce this module specific to swing \ No newline at end of file Added: jaxx/trunk/jaxx-runtime-validator-gwt/pom.xml =================================================================== --- jaxx/trunk/jaxx-runtime-validator-gwt/pom.xml (rev 0) +++ jaxx/trunk/jaxx-runtime-validator-gwt/pom.xml 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,112 @@ +<?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/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <!-- ************************************************************* --> + <!-- *** POM Relationships *************************************** --> + <!-- ************************************************************* --> + + <parent> + <groupId>org.codelutin</groupId> + <artifactId>jaxx</artifactId> + <version>1.3-SNAPSHOT</version> + </parent> + + <groupId>org.codelutin.jaxx</groupId> + <artifactId>jaxx-runtime-validator-gwt</artifactId> + + <repositories> + <repository> + <id>gwt-maven</id> + <url>http://gwt-maven.googlecode.com/svn/trunk/mavenrepo/</url> + </repository> + </repositories> + + <dependencies> + + <!-- sibling dependencies --> + + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>jaxx-runtime-validator</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>jaxx-runtime-gwt</artifactId> + <version>${project.version}</version> + </dependency> + + <!-- GWT Dependencies --> + <dependency> + <groupId>com.google.gwt</groupId> + <artifactId>gwt-servlet</artifactId> + <version>${gwtVersion}</version> + <scope>runtime</scope> + </dependency> + <dependency> + <groupId>com.google.gwt</groupId> + <artifactId>gwt-user</artifactId> + <version>${gwtVersion}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>com.google.gwt</groupId> + <artifactId>gwt-dev</artifactId> + <version>${gwtVersion}</version> + <classifier>${platform}-libs</classifier> + <type>zip</type> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>com.google.gwt</groupId> + <artifactId>gwt-dev</artifactId> + <version>${gwtVersion}</version> + <classifier>${platform}</classifier> + <scope>provided</scope> + </dependency> + + </dependencies> + + <!-- ************************************************************* --> + <!-- *** Project Information ************************************* --> + <!-- ************************************************************* --> + + <name>${project.artifactId}</name> + <description>Jaxx validation gwt extension</description> + + <!-- ************************************************************* --> + <!-- *** Build Settings ****************************************** --> + <!-- ************************************************************* --> + <packaging>jar</packaging> + + <properties> + + <gwtVersion>1.5.3</gwtVersion> + + </properties> + + <!-- ************************************************************* --> + <!-- *** Build Environment ************************************** --> + <!-- ************************************************************* --> + <scm> + <url>http://labs.libre-entreprise.org/plugins/scmsvn/viewcvs.php/jaxx/trunk/jaxx-runtime-validator-gwt/?root=buix</url> + <connection>scm:svn:svn://anonymous@labs.libre-entreprise.org/svnroot/buix/jaxx/trunk/jaxx-runtime-validator-gwt</connection> + <developerConnection>scm:svn:svn+ssh://sletellier@labs.libre-entreprise.org/svnroot/buix/jaxx/trunk/jaxx-runtime-validator-gwt</developerConnection> + </scm> + + <profiles> + <profile> + <id>gwt-dev-linux</id> + <properties> + <platform>linux</platform> + </properties> + <activation> + <os> + <name>Linux</name> + </os> + </activation> + </profile> + </profiles> +</project> Added: jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/GWTValidatorUtil.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/GWTValidatorUtil.java (rev 0) +++ jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/GWTValidatorUtil.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,177 @@ +package jaxx.runtime; + +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 jaxx.runtime.validator.gwt.GWTValidatorMessage; +import jaxx.runtime.validator.gwt.GWTValidatorMessageListMouseListener; +import jaxx.runtime.validator.gwt.GWTValidatorMessageTableMouseListener; + +import org.codelutin.i18n.I18n; + +/** + * The helper class for validation module. + * + * @author chemit + */ +public class GWTValidatorUtil 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(GWTValidatorUtil.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 GWTValidatorUtil() { + // no instance + } + + /** + * 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 GWTValidatorMessageListMouseListener + */ + public static GWTValidatorMessageListMouseListener registerErrorListMouseListener(JList list) { + GWTValidatorMessageListMouseListener listener = getErrorListMouseListener(list); + + if (listener != null) { + return listener; + } + listener = new GWTValidatorMessageListMouseListener(); + 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 GWTValidatorMessageTableMouseListener + */ + public static GWTValidatorMessageTableMouseListener registerErrorTableMouseListener(JTable table) { + GWTValidatorMessageTableMouseListener listener = getErrorTableMouseListener(table); + + if (listener != null) { + return listener; + } + listener = new GWTValidatorMessageTableMouseListener(); + 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 GWTValidatorMessageListMouseListener + */ + public static GWTValidatorMessageListMouseListener getErrorListMouseListener(JList list) { + if (list != null) { + for (MouseListener listener : list.getMouseListeners()) { + if (listener instanceof GWTValidatorMessageTableMouseListener) { + return (GWTValidatorMessageListMouseListener) listener; + } + } + } + return null; + } + + /** + * @param table the validator table ui + * @return the validator table mouse listener, or <code>null</code> if not found + * @see GWTValidatorMessageTableMouseListener + */ + public static GWTValidatorMessageTableMouseListener getErrorTableMouseListener(JTable table) { + if (table != null) { + for (MouseListener listener : table.getMouseListeners()) { + if (listener instanceof GWTValidatorMessageTableMouseListener) { + return (GWTValidatorMessageTableMouseListener) listener; + } + } + } + return null; + } + + public static String getMessage(GWTValidatorMessage model) { + String text = model.getMessage(); + if (model.getField() != null) { + text = model.getField().getI18nError(text); + } + return text; + } + + public static String getFieldName(GWTValidatorMessage 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 Added: jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidator.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidator.java (rev 0) +++ jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidator.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,280 @@ +package jaxx.runtime.validator.gwt; + +import jaxx.runtime.validator.gwt.ui.AbstractBeanValidatorUI; +import jaxx.runtime.validator.gwt.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 GWTValidator<B> extends BeanValidator<B> { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private final Log log = LogFactory.getLog(GWTValidator.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 GWTValidatorMessageListModel errorListModel; + /** Object servant a contenir la liste des erreurs */ + protected GWTValidatorMessageTableModel errorTableModel; + /** ui renderer class */ + protected Class<? extends AbstractBeanValidatorUI> uiClass; + + public GWTValidator(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(GWTValidatorMessageListModel errorListModel) { + this.errorListModel = errorListModel; + if (errorListModel != null) { + // register the validator in the model list + errorListModel.registerValidator(this); + } + } + + public void setErrorTableModel(GWTValidatorMessageTableModel 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 GWTValidator<?> getParentValidator() { + return (GWTValidator<?>) super.getParentValidator(); + } + + public void setParentValidator(GWTValidator<?> 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); + } + } + } +} Added: jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessage.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessage.java (rev 0) +++ jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessage.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,66 @@ +package jaxx.runtime.validator.gwt; + +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 GWTValidatorMessage extends BeanValidatorMessage<GWTValidatorMessage> { + + /** + * the optional field's editor + */ + protected JComponent editor; + protected String fieldName; + + public GWTValidatorMessage(GWTValidator validator, BeanValidatorField field, String message, BeanValidatorScope scope, JComponent editor) { + super(validator, field, message, scope); + this.fieldName = field.getName(); + this.editor = editor; + } + + public GWTValidatorMessage(GWTValidator 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(GWTValidatorMessage 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; + } +} Added: jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessageListModel.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessageListModel.java (rev 0) +++ jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessageListModel.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,142 @@ +package jaxx.runtime.validator.gwt; + +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 GWTValidatorMessageListModel + 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(GWTValidatorMessageListModel.class); + /** list of registred validators */ + protected transient List<GWTValidator<?>> validators; + /** list of messages actual displayed */ + protected List<GWTValidatorMessage> data; + + public GWTValidatorMessageListModel() { + validators = new ArrayList<GWTValidator<?>>(); + data = new java.util.ArrayList<GWTValidatorMessage>(); + } + + public boolean isEmpty() { + return getSize() == 0; + } + + public void registerValidator(GWTValidator<?> 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); + } + + GWTValidator validator = (GWTValidator) 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(GWTValidator validator, BeanValidatorField field, BeanValidatorScope scope, boolean sort, String... messages) { + + JComponent editor = validator.getFieldRepresentation(field.getName()); + // add new errors + for (String error : messages) { + GWTValidatorMessage row = new GWTValidatorMessage(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(GWTValidator 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--) { + GWTValidatorMessage 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); + } + } + } + } +} Added: jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessageListMouseListener.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessageListMouseListener.java (rev 0) +++ jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessageListMouseListener.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,60 @@ +package jaxx.runtime.validator.gwt; + +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 GWTValidatorMessageListModel} 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 GWTValidatorMessageListMouseListener extends MouseAdapter { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(GWTValidatorMessageListMouseListener.class); + + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + if (e.getClickCount() == 2) { + + GWTValidatorMessage entry = getSelectedMessage(e); + if (entry == null) { + // no entry found + return; + } + JComponent component = entry.getEditor(); + if (component != null) { + component.requestFocus(); + } + } + } + + protected GWTValidatorMessage getSelectedMessage(MouseEvent e) { + JList list = (JList) e.getSource(); + if (!(list.getModel() instanceof GWTValidatorMessageListModel)) { + log.warn("model must be a " + GWTValidatorMessageListModel.class + ", but was " + list.getModel()); + return null; + } + + GWTValidatorMessageListModel model = (GWTValidatorMessageListModel) list.getModel(); + int index = list.getSelectionModel().getMinSelectionIndex(); + if (index == -1) { + // nothing is selected + return null; + } + GWTValidatorMessage entry = (GWTValidatorMessage) model.getElementAt(index); + if (log.isDebugEnabled()) { + log.debug("selected index: " + index + " : error: " + entry); + } + return entry; + } + +} \ No newline at end of file Added: jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessageListRenderer.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessageListRenderer.java (rev 0) +++ jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessageListRenderer.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,80 @@ +package jaxx.runtime.validator.gwt; + +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.GWTValidatorUtil; + +/** + * A simple render of a table of validator's messages, says a table that use + * a {@link GWTValidatorMessageTableModel} model. + * + * @author chemit + * @since 1.3 + * @see GWTValidatorMessageTableModel + */ +public class GWTValidatorMessageListRenderer extends DefaultListCellRenderer { + + private static final long serialVersionUID = 1L; + protected String format = "%1$-20s - %2$s"; + + public GWTValidatorMessageListRenderer() { + } + + public GWTValidatorMessageListRenderer(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); + + GWTValidatorMessage model = (GWTValidatorMessage) value; + + // scope + ImageIcon icon = GWTValidatorUtil.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); + + rendererComponent.setText(text); + rendererComponent.setIcon(icon); + + return rendererComponent; + } + + public ImageIcon getIcon(BeanValidatorScope scope) { + ImageIcon icon = GWTValidatorUtil.getIcon(scope); + return icon; + } + + public String getMessage(GWTValidatorMessage model) { + String text = GWTValidatorUtil.getMessage(model); + return text; + } + + public String getFieldName(JList list, String value, int row) { + GWTValidatorMessageListModel tableModel = (GWTValidatorMessageListModel) list.getModel(); + GWTValidatorMessage model = (GWTValidatorMessage) tableModel.getElementAt(row); + String fieldName = GWTValidatorUtil.getFieldName(model, value); + return fieldName; + } +} \ No newline at end of file Added: jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessageTableModel.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessageTableModel.java (rev 0) +++ jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessageTableModel.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,327 @@ +package jaxx.runtime.validator.gwt; + +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 GWTValidatorMessageTableModel + 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(GWTValidatorMessageTableMouseListener.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<GWTValidator<?>> validators; + /** list of messages actual displayed */ + protected List<GWTValidatorMessage> data; + + public GWTValidatorMessageTableModel() { + super(); + validators = new ArrayList<GWTValidator<?>>(); + data = new java.util.ArrayList<GWTValidatorMessage>(); + } + + /** + * 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(GWTValidator<?> 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(GWTValidator 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(GWTValidator 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--) { + GWTValidatorMessage 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(GWTValidator 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(GWTValidator 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 GWTValidatorMessage 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); + } + + GWTValidator validator = (GWTValidator) 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); + + GWTValidatorMessage 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(GWTValidator 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) { + GWTValidatorMessage row = new GWTValidatorMessage(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(GWTValidator validator, String fieldName, BeanValidatorScope scope, boolean sort, String... messages) { + + JComponent editor = validator == null ? null : validator.getFieldRepresentation(fieldName); + // add new errors + for (String error : messages) { + GWTValidatorMessage row = new GWTValidatorMessage(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) { + GWTValidatorMessage row = new GWTValidatorMessage(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(GWTValidator 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--) { + GWTValidatorMessage 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(GWTValidator 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--) { + GWTValidatorMessage 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--) { + GWTValidatorMessage 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 Added: jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessageTableMouseListener.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessageTableMouseListener.java (rev 0) +++ jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessageTableMouseListener.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,94 @@ +package jaxx.runtime.validator.gwt; + +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 GWTValidatorMessageTableModel} 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 GWTValidatorMessageTableMouseListener extends MouseAdapter { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + private static Log log = LogFactory.getLog(GWTValidatorMessageTableMouseListener.class); + + public static final String HIGHLIGHT_ERROR_PROPERTY = "highlightError"; + + /** delgate property change support */ + protected PropertyChangeSupport pcs; + + public GWTValidatorMessageTableMouseListener() { + pcs = new PropertyChangeSupport(this); + } + + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + if (e.getClickCount() == 2) { + + GWTValidatorMessage 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 GWTValidatorMessage getSelectedMessage(MouseEvent e) { + JTable table = (JTable) e.getSource(); + if (!(table.getModel() instanceof GWTValidatorMessageTableModel)) { + log.warn("model must be a " + GWTValidatorMessageTableModel.class + ", but was " + table.getModel()); + return null; + } + + GWTValidatorMessageTableModel model = (GWTValidatorMessageTableModel) table.getModel(); + int index = table.getSelectionModel().getMinSelectionIndex(); + if (index == -1) { + // nothing is selected + return null; + } + if (table.getRowSorter() != null) { + index = table.getRowSorter().convertRowIndexToModel(index); + } + GWTValidatorMessage 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 Added: jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessageTableRenderer.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessageTableRenderer.java (rev 0) +++ jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/GWTValidatorMessageTableRenderer.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,75 @@ +package jaxx.runtime.validator.gwt; + +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.GWTValidatorUtil; + +/** + * A simple render of a table of validator's messages, says a table that use + * a {@link GWTValidatorMessageTableModel} model. + * + * @author chemit + * @since 1.3 + * @see GWTValidatorMessageTableModel + */ +public class GWTValidatorMessageTableRenderer 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; + + column = table.convertColumnIndexToModel(column); + if (table.getRowSorter() != null) { + row = table.getRowSorter().convertRowIndexToModel(row); + } + + switch (column) { + case 0: + // scope + icon = GWTValidatorUtil.getIcon((BeanValidatorScope) value); + break; + + case 1: + // field name + text = getFieldName(table, (String) value, row); + break; + + case 2: + // message + text = getMessage(table, (String) value, row); + break; + } + + rendererComponent.setText(text); + rendererComponent.setIcon(icon); + return rendererComponent; + } + + public ImageIcon getIcon(BeanValidatorScope scope) { + ImageIcon icon = GWTValidatorUtil.getIcon(scope); + return icon; + } + + public String getMessage(JTable table, String value, int row) { + GWTValidatorMessageTableModel tableModel = (GWTValidatorMessageTableModel) table.getModel(); + GWTValidatorMessage model = tableModel.getRow(row); + String text = GWTValidatorUtil.getMessage(model); + return text; + } + + public String getFieldName(JTable table, String value, int row) { + GWTValidatorMessageTableModel tableModel = (GWTValidatorMessageTableModel) table.getModel(); + GWTValidatorMessage model = tableModel.getRow(row); + String fieldName = GWTValidatorUtil.getFieldName(model, value); + return fieldName; + } +} \ No newline at end of file Added: jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/ui/AbstractBeanValidatorUI.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/ui/AbstractBeanValidatorUI.java (rev 0) +++ jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/ui/AbstractBeanValidatorUI.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,37 @@ +package jaxx.runtime.validator.gwt.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); + } + } + +} Added: jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/ui/IconValidationUI.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/ui/IconValidationUI.java (rev 0) +++ jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/ui/IconValidationUI.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,86 @@ +package jaxx.runtime.validator.gwt.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; + } +} Added: jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/ui/ImageValidationUI.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/ui/ImageValidationUI.java (rev 0) +++ jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/ui/ImageValidationUI.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,78 @@ +package jaxx.runtime.validator.gwt.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 Added: jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/ui/TranslucentValidationUI.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/ui/TranslucentValidationUI.java (rev 0) +++ jaxx/trunk/jaxx-runtime-validator-gwt/src/main/java/jaxx/runtime/validator/gwt/ui/TranslucentValidationUI.java 2009-04-02 12:38:08 UTC (rev 1286) @@ -0,0 +1,65 @@ +package jaxx.runtime.validator.gwt.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()); + } +} Added: jaxx/trunk/jaxx-runtime-validator-gwt/src/main/resources/icons/error.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-validator-gwt/src/main/resources/icons/error.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-validator-gwt/src/main/resources/icons/info.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-validator-gwt/src/main/resources/icons/info.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jaxx/trunk/jaxx-runtime-validator-gwt/src/main/resources/icons/warning.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-validator-gwt/src/main/resources/icons/warning.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream
participants (1)
-
kmorin@users.labs.libre-entreprise.org