r1386 - in jaxx/trunk: . jaxx-runtime-api jaxx-runtime-swing jaxx-runtime-swing/src/main/java/jaxx/runtime jaxx-runtime-swing/src/main/java/jaxx/runtime/swing jaxx-runtime-swing/src/main/resources/icons jaxx-runtime-swing-widget jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor jaxx-runtime-swing-widget/src/main/resources/i18n jaxx-runtime-validator jaxx-runtime-validator/src/main/java/jaxx/runtime/validator
Author: tchemit Date: 2009-05-06 05:44:44 +0000 (Wed, 06 May 2009) New Revision: 1386 Added: jaxx/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/EntityComboBox.jaxx jaxx/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/EntityComboBoxHandler.java jaxx/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/ErrorDialogUI.jaxx jaxx/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/TimeEditor.css jaxx/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/TimeEditor.jaxx jaxx/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/TimeEditorHandler.java jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/BooleanCellRenderer.java jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/EmptyNumberTableCellRenderer.java jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/EnumTableCellRenderer.java jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/MyDefaultCellEditor.java jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/OneClicListSelectionModel.java jaxx/trunk/jaxx-runtime-swing/src/main/resources/icons/action-delete.png Modified: jaxx/trunk/changelog.txt jaxx/trunk/jaxx-runtime-api/changelog.txt jaxx/trunk/jaxx-runtime-api/pom.xml jaxx/trunk/jaxx-runtime-swing-widget/pom.xml jaxx/trunk/jaxx-runtime-swing-widget/src/main/resources/i18n/jaxx-runtime-swing-widget-en_GB.properties jaxx/trunk/jaxx-runtime-swing-widget/src/main/resources/i18n/jaxx-runtime-swing-widget-fr_FR.properties jaxx/trunk/jaxx-runtime-swing/changelog.txt jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/SwingUtil.java jaxx/trunk/jaxx-runtime-validator/changelog.txt jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/BeanValidator.java jaxx/trunk/pom.xml Log: add some stuff from ObServe + more (see in changelogs...) TODO : make an example for new editors Modified: jaxx/trunk/changelog.txt =================================================================== --- jaxx/trunk/changelog.txt 2009-05-05 00:02:46 UTC (rev 1385) +++ jaxx/trunk/changelog.txt 2009-05-06 05:44:44 UTC (rev 1386) @@ -1,4 +1,5 @@ 1.5 + * 20090506 [chemit] - super-pom has no dependencies, use lutinutil 1.0.5 * 20090404 [chemit] - introduce module jaxx-runtime-swing-widget for swing widgets designed with jaxx. 1.4 Modified: jaxx/trunk/jaxx-runtime-api/changelog.txt =================================================================== --- jaxx/trunk/jaxx-runtime-api/changelog.txt 2009-05-05 00:02:46 UTC (rev 1385) +++ jaxx/trunk/jaxx-runtime-api/changelog.txt 2009-05-06 05:44:44 UTC (rev 1386) @@ -1,3 +1,6 @@ +1.5 + * 20090506 [chemit] - super-pom has no dependencies + 1.3 chemit 20090409 * 20090404 [chemit] - introduce DataContext class * 20090331 [chemit] - introduce DecoratorUtils class Modified: jaxx/trunk/jaxx-runtime-api/pom.xml =================================================================== --- jaxx/trunk/jaxx-runtime-api/pom.xml 2009-05-05 00:02:46 UTC (rev 1385) +++ jaxx/trunk/jaxx-runtime-api/pom.xml 2009-05-06 05:44:44 UTC (rev 1386) @@ -19,6 +19,11 @@ <dependencies> <dependency> + <groupId>org.codelutin</groupId> + <artifactId>lutinutil</artifactId> + </dependency> + + <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> </dependency> Modified: jaxx/trunk/jaxx-runtime-swing/changelog.txt =================================================================== --- jaxx/trunk/jaxx-runtime-swing/changelog.txt 2009-05-05 00:02:46 UTC (rev 1385) +++ jaxx/trunk/jaxx-runtime-swing/changelog.txt 2009-05-06 05:44:44 UTC (rev 1386) @@ -1,3 +1,6 @@ +1.5 + * 20090506 [chemit] - add some usefull renderer and other stuffs + 1.3 chemit 20090409 * 20090404 [chemit] - introduce dimension factory in SwingUtil for min and max dimensions * 20090327 [chemit] - add javax help mecanism Modified: jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/SwingUtil.java =================================================================== --- jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/SwingUtil.java 2009-05-05 00:02:46 UTC (rev 1385) +++ jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/SwingUtil.java 2009-05-06 05:44:44 UTC (rev 1386) @@ -32,15 +32,22 @@ import java.util.Map.Entry; import java.util.NoSuchElementException; import java.util.Properties; +import javax.swing.DefaultListCellRenderer; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JLayeredPane; +import javax.swing.JList; import javax.swing.JRootPane; import javax.swing.JTabbedPane; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; +import javax.swing.table.DefaultTableCellRenderer; +import jaxx.runtime.swing.BooleanCellRenderer; +import jaxx.runtime.swing.DecoratorTableCellRenderer; +import jaxx.runtime.swing.EmptyNumberTableCellRenderer; +import jaxx.runtime.swing.EnumTableCellRenderer; import jaxx.runtime.swing.I18nTableCellRenderer; import jaxx.runtime.swing.Item; import jaxx.runtime.swing.JAXXComboBox; @@ -197,12 +204,12 @@ * @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); + public static JXLayer<?> boxComponentWithJxLayer(JComponent component) { + JXLayer<?> layer = getLayer(component); if (layer != null) { return layer; } - layer = new org.jdesktop.jxlayer.JXLayer(); + layer = new org.jdesktop.jxlayer.JXLayer<JComponent>(); layer.add(component); return layer; } @@ -234,7 +241,7 @@ public static boolean isLayered(JComponent comp) { Container parent = comp.getParent(); - return parent != null && parent instanceof JXLayer; + return parent != null && parent instanceof JXLayer<?>; } /** @@ -250,7 +257,7 @@ * @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) { + 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 @@ -552,8 +559,8 @@ if (rect == null || rect.width == 0 || rect.height == 0) { rect = comp.getBounds(); } - if (comp instanceof JXLayer) { - JXLayer layer = (JXLayer) comp; + if (comp instanceof JXLayer<?>) { + JXLayer<?> layer = (JXLayer<?>) comp; comp = layer.getView(); } if (comp instanceof Container) { @@ -575,8 +582,8 @@ if (rect == null || rect.width == 0 || rect.height == 0) { rect = comp.getBounds(); } - if (comp instanceof JXLayer) { - JXLayer layer = (JXLayer) comp; + if (comp instanceof JXLayer<?>) { + JXLayer<?> layer = (JXLayer<?>) comp; comp = layer.getView(); } if (comp instanceof Container) { @@ -592,4 +599,56 @@ return cont; } } + + /** + * Génère un renderer de liste graphique basée sur un décorateur donné. + * + * @param <O> le type des données gérées par le décorateur + * @param decorator le décorateur à encapsuler + * @return le nouveau renderer + * @see Decorator + */ + public static <O> DefaultListCellRenderer newDecoratedListCellRenderer(final Decorator<O> decorator) { + return new DefaultListCellRenderer() { + + private static final long serialVersionUID = 1L; + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + String decorated; + if (value instanceof String) { + decorated = (String) value; + } else { + decorated = decorator.toString(value); + } + JComponent component = (JComponent) super.getListCellRendererComponent(list, decorated, index, isSelected, cellHasFocus); + return component; + } + }; + } + + public static TableCellRenderer newDeleteCellRenderer(DefaultTableCellRenderer renderer) { + Icon icon = UIManager.getIcon("Table.removeIcon"); + if (icon == null) { + // try with default icon + icon = createActionIcon("delete"); + } + return new BooleanCellRenderer(renderer, icon); + } + + public static TableCellRenderer newBooleanTableCellRenderer(DefaultTableCellRenderer renderer) { + return new BooleanCellRenderer(renderer); + } + + public static DecoratorTableCellRenderer newDecorateTableCellRenderer(TableCellRenderer renderer, Decorator<?> decorator) { + return new DecoratorTableCellRenderer(renderer, decorator); + } + + public static EmptyNumberTableCellRenderer newEmptyNumberTableCellRenderer(TableCellRenderer renderer) { + return new EmptyNumberTableCellRenderer(renderer); + } + + public static <E extends Enum<E>> EnumTableCellRenderer<E> newEnumTableCellRenderer(TableCellRenderer renderer,Class<E> enumClass) { + return new EnumTableCellRenderer<E>(renderer,enumClass); + } } Added: jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/BooleanCellRenderer.java =================================================================== --- jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/BooleanCellRenderer.java (rev 0) +++ jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/BooleanCellRenderer.java 2009-05-06 05:44:44 UTC (rev 1386) @@ -0,0 +1,61 @@ +package jaxx.runtime.swing; + +import javax.swing.Icon; +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTable; +import javax.swing.table.TableCellRenderer; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; + +/** @author chemit + * @since 1.5 + */ +public class BooleanCellRenderer extends JPanel implements TableCellRenderer { + + private static final long serialVersionUID = 1L; + protected TableCellRenderer defaultDelegate; + protected JCheckBox checkBox; + + public BooleanCellRenderer(TableCellRenderer delegate) { + //super(new BorderLayout()); + this.checkBox = new JCheckBox(); + add(checkBox, BorderLayout.CENTER); + checkBox.setHorizontalAlignment(JLabel.CENTER); + checkBox.setBorderPainted(true); + this.defaultDelegate = delegate; + } + + public BooleanCellRenderer(TableCellRenderer delegate, Icon icon) { + //super(new BorderLayout()); + this.checkBox = new JCheckBox(icon); + add(checkBox, BorderLayout.NORTH); + checkBox.setHorizontalAlignment(JLabel.CENTER); + checkBox.setVerticalTextPosition(JLabel.TOP); + checkBox.setBorderPainted(true); + this.defaultDelegate = delegate; + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + ((JComponent) defaultDelegate).setBackground(null); + JComponent render = (JComponent) defaultDelegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if (isSelected) { + setForeground(table.getSelectionForeground()); + setBackground(table.getSelectionBackground()); + } else { + setForeground(render.getForeground()); + setBackground(render.getBackground()); + //fixme make this works... and remove the test + if (row % 2 == 1) { + setBackground(Color.WHITE); + } + } + checkBox.setSelected((value != null && (Boolean) value)); + setBorder(render.getBorder()); + return this; + } +} Added: jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/EmptyNumberTableCellRenderer.java =================================================================== --- jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/EmptyNumberTableCellRenderer.java (rev 0) +++ jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/EmptyNumberTableCellRenderer.java 2009-05-06 05:44:44 UTC (rev 1386) @@ -0,0 +1,37 @@ +package jaxx.runtime.swing; + +import javax.swing.JTable; +import javax.swing.table.TableCellRenderer; +import java.awt.Component; +import javax.swing.table.DefaultTableCellRenderer; + +/** + * A {@link TableCellRenderer} which does not display numbers when they are + * equals to 0. + * + * @author chemit + * @since 1.5 + */ +public class EmptyNumberTableCellRenderer implements TableCellRenderer { + + protected final Integer ZERO = 0; + protected final Float ZEROF = 0F; + protected final Double ZEROD = 0D; + private TableCellRenderer delegate; + + public EmptyNumberTableCellRenderer() { + this(new DefaultTableCellRenderer()); + } + + public EmptyNumberTableCellRenderer(TableCellRenderer delegate) { + this.delegate = delegate; + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + if (value == null || ZERO.equals(value) || ZEROF.equals(value) || ZEROD.equals(value)) { + value = null; + } + return delegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + } +} Added: jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/EnumTableCellRenderer.java =================================================================== --- jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/EnumTableCellRenderer.java (rev 0) +++ jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/EnumTableCellRenderer.java 2009-05-06 05:44:44 UTC (rev 1386) @@ -0,0 +1,47 @@ +package jaxx.runtime.swing; + +import javax.swing.JTable; +import javax.swing.table.TableCellRenderer; +import java.awt.Component; +import java.util.EnumSet; + +/** + * + * + * A {@link TableCellRenderer} which displays enum values from their ordinal value. + * + * @param <E> le type de l'énumération. + * + * @author chemit + * @since 1.5 + */ +public class EnumTableCellRenderer<E extends Enum<E>> implements TableCellRenderer { + + private TableCellRenderer delegate; + private EnumSet<E> enumValues; + + public EnumTableCellRenderer(TableCellRenderer delegate, Class<E> enumClass) { + this.delegate = delegate; + this.enumValues = EnumSet.allOf(enumClass); + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + + if (value != null) { + //FIXME : should be also able to read it by name ? + Integer ordinal = Integer.valueOf(value + ""); + if (ordinal == -1) { + value = null; + } else { + for (E enumValue : enumValues) { + if (ordinal == enumValue.ordinal()) { + value = enumValue; + break; + } + } + } + } + return delegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + } +} \ No newline at end of file Added: jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/MyDefaultCellEditor.java =================================================================== --- jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/MyDefaultCellEditor.java (rev 0) +++ jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/MyDefaultCellEditor.java 2009-05-06 05:44:44 UTC (rev 1386) @@ -0,0 +1,104 @@ +package jaxx.runtime.swing; + +import org.codelutin.util.EnumEditor; + +import javax.swing.DefaultCellEditor; +import javax.swing.Icon; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.table.TableCellEditor; +import java.awt.Component; + +/** + * @author chemit + * @since 1.5 + */ +public class MyDefaultCellEditor extends DefaultCellEditor { + + private static final long serialVersionUID = 1L; + + public static TableCellEditor newTextEditor() { + return new MyDefaultCellEditor(new JTextField()); + } + + public static TableCellEditor newBooleanEditor() { + return new MyDefaultCellEditor(new JCheckBox()); + } + + public static TableCellEditor newListEditor() { + return newListEditor(new JComboBox()); + } + + public static TableCellEditor newListEditor(JComboBox editor) { + return new MyDefaultCellEditor(editor); + } + + public static TableCellEditor newEnumEditor(EnumEditor editor) { + return new MyDefaultCellEditor(editor) { + + private static final long serialVersionUID = 1L; + + @Override + public Object getCellEditorValue() { + Object value = super.getCellEditorValue(); + if (value != null) { + value = ((Enum) value).ordinal(); + } else { + value = -1; + } + return value; + } + }; + } + + public static TableCellEditor newBooleanEditor(Icon icon) { + return new MyDefaultCellEditor(new JCheckBox(icon)); + } + + public static TableCellEditor newBooleanEditor(Icon icon, boolean requireSelect) { + TableCellEditor cellEditor = newBooleanEditor(icon); + ((MyDefaultCellEditor) cellEditor).setRequireSelect(requireSelect); + return cellEditor; + } + + public static TableCellEditor newBooleanEditor(boolean requireSelect) { + TableCellEditor cellEditor = newBooleanEditor(); + ((MyDefaultCellEditor) cellEditor).setRequireSelect(requireSelect); + return cellEditor; + } + protected boolean requireSelect = true; + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + if (!isSelected && requireSelect) { + // force to have select the cell before editing, a way to not modify edition for nothing... + return null; + } + return super.getTableCellEditorComponent(table, value, isSelected, row, column); + } + + public boolean isRequireSelect() { + return requireSelect; + } + + public void setRequireSelect(boolean requireSelect) { + this.requireSelect = requireSelect; + } + + protected MyDefaultCellEditor(JTextField textField) { + super(textField); + setClickCountToStart(1); + } + + protected MyDefaultCellEditor(JCheckBox checkBox) { + super(checkBox); + setClickCountToStart(1); + } + + protected MyDefaultCellEditor(JComboBox comboBox) { + super(comboBox); + setClickCountToStart(1); + } +} Added: jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/OneClicListSelectionModel.java =================================================================== --- jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/OneClicListSelectionModel.java (rev 0) +++ jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/OneClicListSelectionModel.java 2009-05-06 05:44:44 UTC (rev 1386) @@ -0,0 +1,181 @@ +package jaxx.runtime.swing; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.swing.ListModel; +import javax.swing.ListSelectionModel; +import javax.swing.event.ListSelectionListener; +import java.util.Arrays; + +/** + * @author chemit + * @since 1.5 + */ +public class OneClicListSelectionModel implements ListSelectionModel { + + /** to use log facility, just put in your code: log.info("..."); */ + static private Log log = LogFactory.getLog(OneClicListSelectionModel.class); + protected ListSelectionModel delegate; + protected final ListModel model; + private boolean[] _states; + + public OneClicListSelectionModel(ListSelectionModel delegate, ListModel model) { + this.delegate = delegate; + this.model = model; + delegate.clearSelection(); + } + + protected boolean[] getStates(int selectedIndex) { + int max = model.getSize(); + if (_states == null || _states.length != max) { + _states = new boolean[max]; + } else { + Arrays.fill(_states, false); + } + for (int i = 0; i < max; i++) { + _states[i] = i != selectedIndex && delegate.isSelectedIndex(i); + } + return _states; + } + + @Override + public void setSelectionInterval(int index0, int index1) { + if (index0 != index1) { + // not a single selection (come from a click) + // use default behaviour + delegate.setSelectionInterval(index0, index1); + return; + } + delegate.setValueIsAdjusting(true); + + try { + int max = model.getSize(); + + if (log.isDebugEnabled()) { + log.debug("single [index:" + index0 + "] [selected:" + isSelectedIndex(index0) + "] [size:" + max + "] [anchor:" + delegate.getAnchorSelectionIndex() + "] [lead:" + delegate.getLeadSelectionIndex() + "]"); + } + + if (!isSelectedIndex(index0)) { + // select it + delegate.addSelectionInterval(index0, index1); + return; + } + if (max == index0) { + // last selected index, so can directly remove it + delegate.removeIndexInterval(index0, index0); + return; + } + + // must recompute the selection removing only the index0 item + boolean[] state = getStates(index0); + + if (log.isDebugEnabled()) { + log.debug("state : " + Arrays.toString(state)); + } + delegate.clearSelection(); + for (int i = 0; i < max; i++) { + if (state[i]) { + delegate.addSelectionInterval(i, i); + } + } + } finally { + delegate.setValueIsAdjusting(false); + } + } + + @Override + public void addSelectionInterval(int index0, int index1) { + delegate.addSelectionInterval(index0, index1); + } + + @Override + public void removeSelectionInterval(int index0, int index1) { + delegate.removeSelectionInterval(index0, index1); + } + + @Override + public int getMinSelectionIndex() { + return delegate.getMinSelectionIndex(); + } + + @Override + public int getMaxSelectionIndex() { + return delegate.getMaxSelectionIndex(); + } + + @Override + public boolean isSelectedIndex(int index) { + return delegate.isSelectedIndex(index); + } + + @Override + public int getAnchorSelectionIndex() { + return delegate.getAnchorSelectionIndex(); + } + + @Override + public void setAnchorSelectionIndex(int index) { + delegate.setAnchorSelectionIndex(index); + } + + @Override + public int getLeadSelectionIndex() { + return delegate.getLeadSelectionIndex(); + } + + @Override + public void setLeadSelectionIndex(int index) { + delegate.setLeadSelectionIndex(index); + } + + @Override + public void clearSelection() { + delegate.clearSelection(); + } + + @Override + public boolean isSelectionEmpty() { + return delegate.isSelectionEmpty(); + } + + @Override + public void insertIndexInterval(int index, int length, boolean before) { + delegate.insertIndexInterval(index, length, before); + } + + @Override + public void removeIndexInterval(int index0, int index1) { + delegate.removeIndexInterval(index0, index1); + } + + @Override + public void setValueIsAdjusting(boolean valueIsAdjusting) { + delegate.setValueIsAdjusting(valueIsAdjusting); + } + + @Override + public boolean getValueIsAdjusting() { + return delegate.getValueIsAdjusting(); + } + + @Override + public void setSelectionMode(int selectionMode) { + delegate.setSelectionMode(selectionMode); + } + + @Override + public int getSelectionMode() { + return delegate.getSelectionMode(); + } + + @Override + public void addListSelectionListener(ListSelectionListener x) { + delegate.addListSelectionListener(x); + } + + @Override + public void removeListSelectionListener(ListSelectionListener x) { + delegate.removeListSelectionListener(x); + } +} Added: jaxx/trunk/jaxx-runtime-swing/src/main/resources/icons/action-delete.png =================================================================== (Binary files differ) Property changes on: jaxx/trunk/jaxx-runtime-swing/src/main/resources/icons/action-delete.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Modified: jaxx/trunk/jaxx-runtime-swing-widget/pom.xml =================================================================== --- jaxx/trunk/jaxx-runtime-swing-widget/pom.xml 2009-05-05 00:02:46 UTC (rev 1385) +++ jaxx/trunk/jaxx-runtime-swing-widget/pom.xml 2009-05-06 05:44:44 UTC (rev 1386) @@ -1,3 +1,4 @@ + <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> @@ -25,6 +26,16 @@ <version>${project.version}</version> </dependency> + <dependency> + <groupId>org.swinglabs</groupId> + <artifactId>swingx</artifactId> + </dependency> + + <dependency> + <groupId>org.swinglabs</groupId> + <artifactId>swing-worker</artifactId> + </dependency> + </dependencies> <!-- ************************************************************* --> @@ -93,7 +104,7 @@ </goals> </execution> </executions> - </plugin> + </plugin> </plugins> </build> Added: jaxx/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/EntityComboBox.jaxx =================================================================== --- jaxx/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/EntityComboBox.jaxx (rev 0) +++ jaxx/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/EntityComboBox.jaxx 2009-05-06 05:44:44 UTC (rev 1386) @@ -0,0 +1,110 @@ +<Table fill='both' insets='0' + onFocusGained='combobox.requestFocus()' + onFocusLost='hidePopup()'> + +<!--fill='both' insets='0'--> + <!-- auto complete property --> + <Boolean id='autoComplete' javaBean='false'/> + + <!-- show reset property --> + <Boolean id='showReset' javaBean='false'/> + + <!-- show decorator property --> + <Boolean id='showDecorator' javaBean='true'/> + + <Boolean id='editable' javaBean='true'/> + + <!-- bean property linked state --> + <String id='property' javaBean='""'/> + + <!-- bean property --> + <Object id='bean' javaBean='null'/> + + <!-- selectedItem property --> + <Object id='selectedItem' javaBean='null'/> + + <!-- sort index property --> + <Integer id='index' javaBean='0'/> + + <!-- datas of the combo-box --> + <java.util.List id='data' javaBean='null'/> + + <!-- model of sorted property --> + <ButtonGroup id='indexes' useToolTipText='true' + onStateChanged='setIndex((Integer)indexes.getSelectedValue())'/> + + <!-- ui handler --> + <EntityComboBoxHandler id='handler' constructorParams='this'/> + + <String id='selectedToolTipText' javaBean='null'/> + + <String id='notSelectedToolTipText' javaBean='null'/> + + <String id='popupTitleText' javaBean='null'/> + + <String id='i18nPrefix' javaBean='"observe.common."'/> + + <!-- popup to change sorted property--> + <JPopupMenu id='popup' + border='{new TitledBorder(_("entitycombobox.popup.title"))}' + onPopupMenuWillBecomeInvisible='getChangeDecorator().setSelected(false)' + onPopupMenuCanceled='getChangeDecorator().setSelected(false)'> + <JLabel id='popupLabel'/> + <JSeparator/> + </JPopupMenu> + + <script><![CDATA[ +import static org.codelutin.i18n.I18n.n_; + +public static final String DEFAULT_POPUP_LABEL = n_("entitycombobox.popup.label"); + +public static final String DEFAULT_SELECTED_TOOLTIP = n_("entitycombobox.sort.on"); + +public static final String DEFAULT_NOT_SELECTED_TOOLTIP = n_("entitycombobox.sort.off"); + +public <O> void init(jaxx.runtime.JXPathDecorator<O> decorator, java.util.List<O> data) { + handler.init(decorator, data); +} + +protected void hidePopup() { + if (popup.isVisible()) { + popup.setVisible(false); + } +} +]]> + </script> + <row> + <cell anchor='west'> + <!-- le boutton pour reinitialiser la valeur sélectionnée --> + <JToolBar floatable='false' borderPainted='false' visible='{isShowReset()}'> + <JButton actionIcon='combobox-reset' + toolTipText='entitycombobox.action.reset.tip' + focusable='false' + focusPainted='false' + enabled='{isEnabled()}' + onActionPerformed='setSelectedItem(null)'/> + </JToolBar> + + </cell> + <cell weightx='1'> + <!-- la liste déroulante --> + <JComboBox id='combobox' + selectedItem='{getSelectedItem()}' + enabled='{isEnabled()}' + editable='{isEditable()}' + onFocusGained='hidePopup()' + onItemStateChanged='setSelectedItem(combobox.getSelectedItem())'/> + </cell> + <cell anchor='east' fill='both' insets='0'> + <!-- le boutton pour changer le tri --> + <JToolBar floatable='false' borderPainted='false' visible='{isShowDecorator()}'> + <JToggleButton id='changeDecorator' + actionIcon='combobox-sort' + toolTipText='entitycombobox.action.sort.tip' + focusable='false' + focusPainted='false' + onActionPerformed='getHandler().togglePopup()'/> + </JToolBar> + </cell> + </row> +</Table> Added: jaxx/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/EntityComboBoxHandler.java =================================================================== --- jaxx/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/EntityComboBoxHandler.java (rev 0) +++ jaxx/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/EntityComboBoxHandler.java 2009-05-06 05:44:44 UTC (rev 1386) @@ -0,0 +1,454 @@ +package jaxx.runtime.swing; + +import java.awt.Component; +import jaxx.runtime.JXPathDecorator; +import jaxx.runtime.MultiJXPathDecorator; +import jaxx.runtime.Util; +import jaxx.runtime.SwingUtil; +import org.apache.commons.beanutils.PropertyUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import static org.codelutin.i18n.I18n._; +import static org.codelutin.i18n.I18n.n_; +import org.jdesktop.swingx.autocomplete.ObjectToStringConverter; + +import javax.swing.JPopupMenu; +import javax.swing.JRadioButtonMenuItem; +import javax.swing.JToggleButton; +import javax.swing.SwingUtilities; +import javax.swing.text.Document; +import javax.swing.text.JTextComponent; +import java.awt.Dimension; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.beans.Introspector; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; +import java.util.List; +import javax.swing.JComboBox; +import jaxx.runtime.Decorator; +import org.jdesktop.swingx.autocomplete.AutoCompletePropertyChangeListener; + +/** + * Le handler d'un {@link EntityComboBox}. + * <p/> + * Note: ce handler n'est pas staeless et n'est donc pas partageable entre plusieurs ui. + * + * @param <O> le type des objet contenus dans le modèle du composant. + * + * @author chemit + * @see EntityComboBox + */ +public class EntityComboBoxHandler<O> implements PropertyChangeListener { + + public static final Log log = LogFactory.getLog(EntityComboBoxHandler.class); + public static final String SELECTED_ITEM_PROPERTY = "selectedItem"; + public static final String INDEX_PROPERTY = "index"; + public static final String AUTO_COMPLETE_PROPERTY = "autoComplete"; + public static final String DATA_PROPERTY = "data"; + /** ui if the handler */ + protected EntityComboBox ui; + /** the mutator method on the property of boxed bean in the ui */ + protected Method mutator; + /** the original document of the combbo box editor (keep it to make possible undecorate) */ + protected Document originalDocument; + /** the convertor used to auto-complete */ + protected ObjectToStringConverter convertor; + /** the decorator of data */ + protected MultiJXPathDecorator<O> decorator; + protected boolean init; + + public EntityComboBoxHandler(EntityComboBox ui) { + this.ui = ui; + } + protected final FocusListener EDITOR_TEXT_COMP0NENT_FOCUSLISTENER = new FocusListener() { + + @Override + public void focusGained(FocusEvent e) { + if (log.isDebugEnabled()) { + log.debug("close popup from " + e); + } + ui.getPopup().setVisible(false); + } + + @Override + public void focusLost(FocusEvent e) { + } + }; + + /** + * Initialise le handler de l'ui + * + * @param decorator le decorateur a utiliser + * @param data la liste des données a gérer + */ + public void init(JXPathDecorator<O> decorator, List<O> data) { + + if (init) { + throw new IllegalStateException("can not init the handler twice"); + } + init = true; + if (decorator == null) { + throw new NullPointerException("can not have a null decorator as parameter"); + } + + JAXXButtonGroup indexes = ui.getIndexes(); + + MultiJXPathDecorator<O> d; + if (decorator instanceof MultiJXPathDecorator<?>) { + // should clone decorator ? + d = (MultiJXPathDecorator<O>) decorator; + } else { + d = MultiJXPathDecorator.newDecorator(decorator.getInternalClass(), decorator.getInitialExpression(), " - "); + } + this.decorator = d; + + // init combobox renderer base on given decorator + ui.getCombobox().setRenderer(Util.newDecoratedListCellRenderer(d)); + + this.convertor = newDecoratedObjectToStringConverter(d); + + // keep a trace of original document (to make possible reverse autom-complete) + JTextComponent editorComponent = (JTextComponent) ui.getCombobox().getEditor().getEditorComponent(); + this.originalDocument = editorComponent.getDocument(); + + // build popup + preparePopup(d); + + ui.autoComplete = true; + + ui.addPropertyChangeListener(this); + + // set datas + ui.setData(data); + + // select sort button + indexes.setSelectedButton(ui.getIndex()); + } + + /** Toggle the popup visible state. */ + public void togglePopup() { + boolean newValue = !ui.getPopup().isVisible(); + + if (log.isTraceEnabled()) { + log.trace(newValue); + } + + if (!newValue) { + if (ui.getPopup() != null) { + ui.getPopup().setVisible(false); + } + return; + } + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + ui.getPopup().pack(); + Dimension dim = ui.getPopup().getPreferredSize(); + JToggleButton invoker = ui.getChangeDecorator(); + ui.getPopup().show(invoker, (int) (invoker.getPreferredSize().getWidth() - dim.getWidth()), invoker.getHeight()); + } + }); + } + + /** + * Modifie l'état autoComplete de l'ui. + * + * @param oldValue l'ancienne valeur + * @param newValue la nouvelle valeur + */ + protected void setAutoComplete(Boolean oldValue, Boolean newValue) { + oldValue = oldValue != null && oldValue; + newValue = newValue != null && newValue; + if (oldValue == newValue) { + return; + } + if (log.isDebugEnabled()) { + log.debug("autocomplete state : <" + oldValue + " to " + newValue + ">"); + } + if (!newValue) { + JTextComponent editorComponent = (JTextComponent) ui.getCombobox().getEditor().getEditorComponent(); + editorComponent.removeFocusListener(EDITOR_TEXT_COMP0NENT_FOCUSLISTENER); + undecorate(ui.getCombobox(), originalDocument); + } else { + decorate(ui.getCombobox(), convertor); + JTextComponent editorComponent = (JTextComponent) ui.getCombobox().getEditor().getEditorComponent(); + editorComponent.addFocusListener(EDITOR_TEXT_COMP0NENT_FOCUSLISTENER); + } + } + + /** + * Modifie l'index du décorateur + * + * @param oldValue l'ancienne valeur + * @param newValue la nouvelle valeur + */ + @SuppressWarnings({"unchecked"}) + protected void setIndex(Integer oldValue, Integer newValue) { + if (newValue.equals(oldValue)) { + return; + } + if (log.isDebugEnabled()) { + log.debug("check state : <" + oldValue + " to " + newValue + ">"); + } + + // change decorator context + decorator.setContextIndex(newValue); + + // keep selected item + Object previousSelectedItem = ui.getSelectedItem(); + Boolean wasAutoComplete = ui.isAutoComplete(); + + if (wasAutoComplete) { + ui.setAutoComplete(false); + } + + // remove autocomplete + if (previousSelectedItem != null) { + ui.getCombobox().setSelectedItem(null); + ui.selectedItem = null; + } + + + try { + // Sort data with the decorator jxpath tokens. + JXPathDecorator.sort(decorator, ui.getData(), newValue); + } catch (Exception e) { + log.warn(e.getMessage(), e); + //System.out.println("newValue :: "+decorator+" : "+newValue); + //System.out.println("datas :: "+ui.getData()); + } + + // reload the model + SwingUtil.fillComboBox(ui.getCombobox(), ui.getData(), null); + + if (wasAutoComplete) { + ui.setAutoComplete(true); + } + + if (previousSelectedItem != null) { + ui.setSelectedItem(previousSelectedItem); + } + + ui.getCombobox().requestFocus(); + } + + /** + * Modifie la valeur sélectionnée dans la liste déroulante. + * + * @param oldValue l'ancienne valeur + * @param newValue la nouvelle valeur + */ + protected void setSelectedItem(Object oldValue, Object newValue) { + if (ui.getBean() == null) { + return; + } + + if (newValue == null) { + if (ui.getCombobox().getSelectedItem() == null) { + return; + } + ui.getCombobox().setSelectedItem(null); + + if (ui.isAutoComplete()) { + ui.setAutoComplete(false); + ui.setAutoComplete(true); + } + + if (oldValue == null) { + return; + } + } + if (log.isDebugEnabled()) { + log.debug(ui.getProperty() + " on " + ui.getBean().getClass() + " :: " + oldValue + " to " + newValue); + } + + try { + Method mut = getMutator(); + if (mut != null) { + mut.invoke(ui.getBean(), newValue); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** @return le document de l'éditeur avant complétion. */ + public Document getOriginalDocument() { + return originalDocument; + } + + public MultiJXPathDecorator<O> getDecorator() { + return decorator; + } + + /** + * Creation de l'ui pour modifier le décorateur. + * + * @param decorator le decorateur a utiliser + */ + protected void preparePopup(MultiJXPathDecorator<?> decorator) { + String selectedTip = ui.getSelectedToolTipText(); + if (selectedTip == null) { + // use default selected tip text + selectedTip = EntityComboBox.DEFAULT_SELECTED_TOOLTIP; + } + String notSelectedTip = ui.getNotSelectedToolTipText(); + if (notSelectedTip == null) { + // use default selected tip text + notSelectedTip = EntityComboBox.DEFAULT_NOT_SELECTED_TOOLTIP; + } + JPopupMenu popup = ui.getPopup(); + + //Container container = ui.getIndexesContainer(); + for (int i = 0, max = decorator.getNbContext(); i < max; i++) { + String property = ui.getI18nPrefix() + decorator.getProperty(i); +// String property = "observe.common." + decorator.getProperty(i); + String propertyI18n = _(property); + JRadioButtonMenuItem button = new JRadioButtonMenuItem(propertyI18n); + button.putClientProperty(JAXXButtonGroup.BUTTON8GROUP_CLIENT_PROPERTY, ui.getIndexes()); + button.putClientProperty(JAXXButtonGroup.VALUE_CLIENT_PROPERTY, i); + popup.add(button); + if (selectedTip != null) { + button.putClientProperty(JAXXButtonGroup.SELECTED_TIP_CLIENT_PROPERTY, _(selectedTip, propertyI18n)); + } + if (notSelectedTip != null) { + button.putClientProperty(JAXXButtonGroup.NOT_SELECTED_TIP_CLIENT_PROPERTY, _(notSelectedTip, propertyI18n)); + } + button.setSelected(false); + ui.getIndexes().add(button); + } + String title = ui.getPopupTitleText(); + if (title == null) { + // use default popup title + title = EntityComboBox.DEFAULT_POPUP_LABEL; + + Class<?> internalClass = decorator.getInternalClass(); + String beanI18nKey; + if (internalClass == null) { + beanI18nKey = n_("entitycombobox.unknown.type"); + } else { + beanI18nKey = ui.getI18nPrefix() + Introspector.decapitalize(internalClass.getSimpleName()); + //beanI18nKey = "observe.common." + Introspector.decapitalize(internalClass.getSimpleName()); + } + String beanI18n = _(beanI18nKey); + title = _(title, beanI18n); + } else { + title = _(title); + } + ui.getPopupLabel().setText(title); + ui.getPopup().setLabel(title); + ui.getPopup().invalidate(); + } + + public Class<?> getTargetClass() { + Method m = getMutator(); + return m == null ? null : m.getParameterTypes()[0]; + } + + /** @return le mutateur a utiliser pour modifier le bean associé. */ + protected Method getMutator() { + if (mutator == null) { + Object bean = ui.getBean(); + if (bean == null) { + throw new NullPointerException("could not find bean in " + ui); + } + String property = ui.getProperty(); + if (property == null) { + throw new NullPointerException("could not find property in " + ui); + } + + try { + PropertyDescriptor descriptor = PropertyUtils.getPropertyDescriptor(bean, property); + if (descriptor != null) { + mutator = descriptor.getWriteMethod(); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + return mutator; + } + + /** + * Encapsule un {@link Decorator} dans un {@link ObjectToStringConverter}. + * + * @param decorator le decorateur a encapsuler. + * @return le converter encapsule dans un {@link ObjectToStringConverter} + */ + public static ObjectToStringConverter newDecoratedObjectToStringConverter(final Decorator<?> decorator) { + + return new ObjectToStringConverter() { + + @Override + public String getPreferredStringForItem(Object item) { + return item instanceof String ? (String) item : (item == null ? "" : decorator.toString(item)); + } + }; + } + + /** + * Ajout l'auto-complétion sur une liste déroulante, en utilisant le + * converteur donné pour afficher les données. + * + * @param combo la combo à décorer + * @param convertor le converter utilisé pour afficher les données. + */ + public static void decorate(JComboBox combo, ObjectToStringConverter convertor) { + + org.jdesktop.swingx.autocomplete.AutoCompleteDecorator.decorate(combo, convertor); + } + + /** + * Désactive l'aut-complétion sur une liste déroulante, en y repositionnant + * le modèle du document d'édition d'avant auto-complétion. + * + * @param combo la liste déroulante à décorer + * @param originalDocument le document original de l'édtieur de la + * liste déroulante. + */ + public static void undecorate(JComboBox combo, Document originalDocument) { + + // has not to be editable + combo.setEditable(false); + + // configure the text component=editor component + Component c = combo.getEditor().getEditorComponent(); + JTextComponent editorComponent = (JTextComponent) c; + editorComponent.setDocument(originalDocument); + editorComponent.setText(null); + //remove old property change listener + for (PropertyChangeListener l : c.getPropertyChangeListeners("editor")) { + if (l instanceof AutoCompletePropertyChangeListener) { + c.removePropertyChangeListener("editor", l); + } + } + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + String propertyName = evt.getPropertyName(); + + if (SELECTED_ITEM_PROPERTY.equals(propertyName)) { + setSelectedItem(evt.getOldValue(), evt.getNewValue()); + return; + } + + if (INDEX_PROPERTY.equals(propertyName)) { + setIndex((Integer) evt.getOldValue(), (Integer) evt.getNewValue()); + return; + } + if (AUTO_COMPLETE_PROPERTY.equals(propertyName)) { + setAutoComplete((Boolean) evt.getOldValue(), (Boolean) evt.getNewValue()); + return; + } + if (DATA_PROPERTY.equals(propertyName)) { + // list has changed, force reload of index + setIndex(-1, ui.getIndex()); + } + + } +} Added: jaxx/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/ErrorDialogUI.jaxx =================================================================== --- jaxx/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/ErrorDialogUI.jaxx (rev 0) +++ jaxx/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/ErrorDialogUI.jaxx 2009-05-06 05:44:44 UTC (rev 1386) @@ -0,0 +1,66 @@ +<JDialog title='errorUI.title' modal='true'> + <script><![CDATA[ +protected static ErrorDialogUI instance; +public static void init(Frame frame) { + disposeUI(); + instance = new ErrorDialogUI(frame); + instance.setModalityType(ModalityType.TOOLKIT_MODAL); +} +public static void showError(Exception e) { + if (instance == null) { + instance = new ErrorDialogUI(); + } + instance.getErrorMessage().setText(e.getMessage()); + StringWriter w = new StringWriter(); + e.printStackTrace(new PrintWriter(w)); + instance.getErrorStack().setText(w.toString()); + instance.getErrorStack().setCaretPosition(0); + instance.pack(); + jaxx.runtime.SwingUtil.center(instance.getContextValue(JFrame.class,"parent"), instance); + instance.setVisible(true); +} +public static void disposeUI() { + instance=null; +} + +public ErrorDialogUI(Frame frame) { + super(frame); + if (frame!=null) { + setContextValue(frame); + setContextValue(frame,"parent"); + } + +} + +JRootPane rootPane = getRootPane(); +rootPane.setDefaultButton(close); +rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("ESCAPE"), "close"); +rootPane.getActionMap().put("close", close.getAction()); + ]]></script> + <Table> + <row fill='both'> + <cell> + <JPanel> + <JLabel text='errorUI.message'/> + </JPanel> + </cell> + </row> + <row fill='both'> + <cell> + <JLabel id='errorMessage'/> + </cell> + </row> + <row fill='both' weightx='1' weighty='1'> + <cell> + <JScrollPane width='600' height='200'> + <JTextArea id='errorStack' editable='false' font-size='9'/> + </JScrollPane> + </cell> + </row> + <row fill='horizontal'> + <cell> + <JButton id='close' text='errorUI.action.close' onActionPerformed='dispose()'/> + </cell> + </row> + </Table> +</JDialog> Added: jaxx/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/TimeEditor.css =================================================================== --- jaxx/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/TimeEditor.css (rev 0) +++ jaxx/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/TimeEditor.css 2009-05-06 05:44:44 UTC (rev 1386) @@ -0,0 +1,31 @@ +#title{ + text:{getLabel()}; + horizontalAlignment:center; +} + +#hour{ + value:{getTimeModel()/60}; + enabled:{isEnabled()}; + model:{new SpinnerNumberModel(0,0,23,1)}; +} + +#labelH { + text:"H"; + horizontalAlignment:center; +} +#minute{ + value:{getTimeModel()%60}; + enabled:{isEnabled()}; + model:{new SpinnerNumberModel(0,0,59,1)}; +} + +#slider{ + font-size: 11; + paintTicks:true; + paintLabels:true; + majorTickSpacing:60; + minorTickSpacing:30; + value:{getTimeModel()}; + enabled:{isEnabled()}; + model:{new DefaultBoundedRangeModel(0,1,0,60*24)}; +} Added: jaxx/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/TimeEditor.jaxx =================================================================== --- jaxx/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/TimeEditor.jaxx (rev 0) +++ jaxx/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/TimeEditor.jaxx 2009-05-06 05:44:44 UTC (rev 1386) @@ -0,0 +1,56 @@ + +<JPanel layout='{new BorderLayout()}'> + + <style source='TimeEditor.css'/> + + <!-- bean property --> + <String id='property' javaBean='""'/> + + <!-- title --> + <String id='label' javaBean='""'/> + + <!-- bean --> + <Object id='bean' javaBean='null'/> + + <!-- time model --> + <Integer id="timeModel" javaBean='0'/> + + <!-- the real date --> + <java.util.Date id="date" javaBean='null'/> + + <!-- ui handler --> + <TimeEditorHandler id='handler' constructorParams='this'/> + + <script><![CDATA[ +public void init() { + handler.init(); +} +]]> + </script> + + <Table constraints='BorderLayout.NORTH' fill='horizontal' insets='0'> + <row> + <cell> + <JLabel id='title'/> + </cell> + <cell weightx='1'> + <JLabel/> + </cell> + <cell> + <JSpinner id='hour' + onStateChanged='setTimeModel((Integer)hour.getValue()* 60 + timeModel % 60)'/> + </cell> + <cell> + <JLabel id='labelH'/> + </cell> + <cell> + <JSpinner id='minute' + onStateChanged='setTimeModel((timeModel / 60) * 60 + (Integer) minute.getValue())'/> + </cell> + </row> + </Table> + + <JSlider id='slider' constraints='BorderLayout.SOUTH' + onStateChanged='if (!slider.getValueIsAdjusting()) setTimeModel(slider.getValue());'/> + +</JPanel> Added: jaxx/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/TimeEditorHandler.java =================================================================== --- jaxx/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/TimeEditorHandler.java (rev 0) +++ jaxx/trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/TimeEditorHandler.java 2009-05-06 05:44:44 UTC (rev 1386) @@ -0,0 +1,204 @@ +package jaxx.runtime.swing.editor; + +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import org.apache.commons.beanutils.PropertyUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.swing.JLabel; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; +import java.util.Calendar; +import java.util.Date; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.Map; +import javax.swing.JSlider; +import javax.swing.plaf.basic.BasicSliderUI; + +/** @author chemit */ +public class TimeEditorHandler { + + public static final Log log = LogFactory.getLog(TimeEditorHandler.class); + public static final String BEAN_PROPERTY = "bean"; + public static final String PROPERTY_PROPERTY = "property"; + public static final String DATE_PROPERTY = "date"; + public static final String TIME_MODEL_PROPERTY = "timeModel"; + /** editor ui */ + protected TimeEditor editor; + /** the mutator method on the property of boxed bean in the editor */ + protected Method mutator; + protected Calendar calendar; + + public TimeEditorHandler(TimeEditor ui) { + this.editor = ui; + this.calendar = Calendar.getInstance(); + } + + public void init() { + + if (editor.getBean() == null) { + throw new NullPointerException("can not have a null bean in ui " + editor); + } + + // create slider labels + Map<Integer, JLabel> labelTable = new Hashtable<Integer, JLabel>(); + for (int i = 0; i < 25; i += 2) { + labelTable.put(i * 60, new JLabel(i + "")); + } + JSlider slider = editor.getSlider(); + slider.setLabelTable((Dictionary<?,?>) labelTable); + + MouseAdapter m = new MouseAdapter() { + + @Override + public void mouseClicked(MouseEvent e) { + // set the value + int value = getSliderValue(e); + JSlider slider = (JSlider) e.getComponent(); + slider.setValueIsAdjusting(true); + slider.setValue(value); + slider.setValueIsAdjusting(false); + showToolTip(e); + e.consume(); + } + + @Override + public void mouseDragged(MouseEvent e) { + showToolTip(e); + } + + @Override + public void mouseEntered(MouseEvent e) { + showToolTip(e); + } + + @Override + public void mouseMoved(MouseEvent e) { + showToolTip(e); + } + + @Override + public void mouseReleased(MouseEvent e) { + showToolTip(e); + } + + int getSliderValue(MouseEvent e) { + JSlider slider = (JSlider) e.getSource(); + int value = -1; + if (slider.getUI() instanceof BasicSliderUI) { + BasicSliderUI ui = (BasicSliderUI) slider.getUI(); + value = slider.getOrientation() == JSlider.HORIZONTAL + ? ui.valueForXPosition(e.getX()) + : ui.valueForYPosition(e.getY()); + } + return value; + } + + void showToolTip(MouseEvent e) { + + int value = getSliderValue(e); + if (value == -1) { + return; + } + int h = value / 60; + int m = value % 60; + + String text = ""; + if (h < 10) { + text = "0"; + } + text += h + " : "; + if (m < 10) { + text += "0"; + } + text += m; + + JSlider slider = (JSlider) e.getSource(); + slider.setToolTipText(text); + + } + }; + slider.addMouseListener(m); + slider.addMouseMotionListener(m); + + // listen when date changes (should come from outside) + editor.addPropertyChangeListener(DATE_PROPERTY, new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + Date date = (Date) evt.getNewValue(); + + if (date == null) { + return; + } + calendar.setTime(date); + int hours = calendar.get(Calendar.HOUR_OF_DAY); + int minutes = calendar.get(Calendar.MINUTE); + if (log.isDebugEnabled()) { + log.debug("date changed : new value " + hours + ":" + minutes); + } + getEditor().setTimeModel((hours * 60) + minutes); + } + }); + + // listen when time model changes (should come from editor) + editor.addPropertyChangeListener(TIME_MODEL_PROPERTY, new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + Integer time = (Integer) evt.getNewValue(); + int hours = time / 60; + int minutes = time % 60; + calendar.set(Calendar.HOUR_OF_DAY, hours); + calendar.set(Calendar.MINUTE, minutes); + setDate(null, calendar.getTime()); + } + }); + } + + public TimeEditor getEditor() { + return editor; + } + + protected void setDate(Date oldValue, Date newValue) { + if (editor.getBean() == null) { + return; + } + + if (log.isDebugEnabled()) { + log.debug(editor.getProperty() + " on " + editor.getBean().getClass() + " :: " + oldValue + " to " + newValue); + } + + try { + getMutator().invoke(editor.getBean(), newValue); + + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + protected Method getMutator() { + if (mutator == null) { + Object bean = editor.getBean(); + if (bean == null) { + throw new NullPointerException("could not find bean in " + editor); + } + String property = editor.getProperty(); + if (property == null) { + throw new NullPointerException("could not find property in " + editor); + } + + try { + PropertyDescriptor descriptor = PropertyUtils.getPropertyDescriptor(bean, property); + mutator = descriptor.getWriteMethod(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + return mutator; + } +} \ No newline at end of file Modified: jaxx/trunk/jaxx-runtime-swing-widget/src/main/resources/i18n/jaxx-runtime-swing-widget-en_GB.properties =================================================================== --- jaxx/trunk/jaxx-runtime-swing-widget/src/main/resources/i18n/jaxx-runtime-swing-widget-en_GB.properties 2009-05-05 00:02:46 UTC (rev 1385) +++ jaxx/trunk/jaxx-runtime-swing-widget/src/main/resources/i18n/jaxx-runtime-swing-widget-en_GB.properties 2009-05-06 05:44:44 UTC (rev 1386) @@ -10,8 +10,21 @@ 8= 9= H= +entitycombobox.action.reset.tip= +entitycombobox.action.sort.tip= +entitycombobox.popup.label= +entitycombobox.popup.title= +entitycombobox.sort.off= +entitycombobox.sort.on= +entitycombobox.unknown.type= +errorUI.action.close= +errorUI.message= +errorUI.title= numbereditor.action.reset.tip=Reset numbereditor.action.show.tip=Show numeric panel numbereditor.clearAll=C numbereditor.clearOne=CE numbereditor.toggleSign=+/- +observe.action.close= +observe.message.error.dialog= +observe.title.error.dialog= Modified: jaxx/trunk/jaxx-runtime-swing-widget/src/main/resources/i18n/jaxx-runtime-swing-widget-fr_FR.properties =================================================================== --- jaxx/trunk/jaxx-runtime-swing-widget/src/main/resources/i18n/jaxx-runtime-swing-widget-fr_FR.properties 2009-05-05 00:02:46 UTC (rev 1385) +++ jaxx/trunk/jaxx-runtime-swing-widget/src/main/resources/i18n/jaxx-runtime-swing-widget-fr_FR.properties 2009-05-06 05:44:44 UTC (rev 1386) @@ -10,6 +10,16 @@ 8= 9= H= +entitycombobox.action.reset.tip=R\u00E9initialiser la valeur de la liste d\u00E9roulante +entitycombobox.action.sort.tip=Modifier le tri de la liste d\u00E9roulante +entitycombobox.popup.label=Objet '%1$s' +entitycombobox.popup.title=Modifier le tri +entitycombobox.sort.off=Cliquer pour activer le tri sur la propri\u00E9t\u00E9 '%1$s' +entitycombobox.sort.on=Le tri est effectu\u00E9 sur la propri\u00E9t\u00E9 '%1$s' +entitycombobox.unknown.type=Objet de type inconnu +errorUI.action.close=Fermer +errorUI.message=Une erreur est survenue \! +errorUI.title=Erreur... numbereditor.action.reset.tip=R\u00E9initialiser numbereditor.action.show.tip=Afficher le pav\u00E9 num\u00E9rique numbereditor.clearAll=C Modified: jaxx/trunk/jaxx-runtime-validator/changelog.txt =================================================================== --- jaxx/trunk/jaxx-runtime-validator/changelog.txt 2009-05-05 00:02:46 UTC (rev 1385) +++ jaxx/trunk/jaxx-runtime-validator/changelog.txt 2009-05-06 05:44:44 UTC (rev 1386) @@ -1,4 +1,5 @@ 1.5 + * 20090506 [chemit] - on chained validation, do not changed parentValidator changed state * 20090503 [chemit] - add a new property collectionFieldName on CollectionFieldExpression validator to be able to validate a collection but not for a collection field - add doRevalidate on BeanValidator to validate and update internal states (validate method does not update internal state and should be used in outside...) Modified: jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/BeanValidator.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/BeanValidator.java 2009-05-05 00:02:46 UTC (rev 1385) +++ jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/BeanValidator.java 2009-05-06 05:44:44 UTC (rev 1386) @@ -380,7 +380,13 @@ if (parentValidator != null) { // chained validation - parentValidator.l.propertyChange(null); + // the parent validator should not be changed from this validation + boolean wasModified = parentValidator.isChanged(); + parentValidator.doValidate(); + if (!wasModified) { + // push back old state + parentValidator.setChanged(false); + } } } Modified: jaxx/trunk/pom.xml =================================================================== --- jaxx/trunk/pom.xml 2009-05-05 00:02:46 UTC (rev 1385) +++ jaxx/trunk/pom.xml 2009-05-06 05:44:44 UTC (rev 1386) @@ -34,12 +34,12 @@ <module>jaxx-example</module> </modules> - <dependencies> + <!--dependencies> <dependency> <groupId>org.codelutin</groupId> <artifactId>lutinutil</artifactId> </dependency> - </dependencies> + </dependencies--> <dependencyManagement> <dependencies> @@ -121,6 +121,18 @@ <version>3.0.1</version> </dependency> + <dependency> + <groupId>org.swinglabs</groupId> + <artifactId>swingx</artifactId> + <version>${swingx.version}</version> + </dependency> + + <dependency> + <groupId>org.swinglabs</groupId> + <artifactId>swing-worker</artifactId> + <version>1.1</version> + </dependency> + </dependencies> </dependencyManagement> @@ -147,10 +159,11 @@ <labs.project>buix</labs.project> <!-- libs version --> - <lutinutil.version>1.0.3</lutinutil.version> + <lutinutil.version>1.0.5</lutinutil.version> <jaxx.version>${project.version}</jaxx.version> <i18n.version>0.11</i18n.version> <lutinpluginutil.version>0.4</lutinpluginutil.version> + <swingx.version>0.9.6</swingx.version> <maven.version>2.0.10</maven.version> </properties>
participants (1)
-
tchemit@users.labs.libre-entreprise.org