r2794 - in trunk/jaxx-widgets/src/main: java/jaxx/runtime/swing/editor resources/i18n
Author: tchemit Date: 2014-02-12 15:36:52 +0100 (Wed, 12 Feb 2014) New Revision: 2794 Url: http://nuiton.org/projects/jaxx/repository/revisions/2794 Log: refs #3074: Introduce a new NumberEditor (begin of story...) Added: trunk/jaxx-widgets/src/main/java/jaxx/runtime/swing/editor/NumberEditor2.css trunk/jaxx-widgets/src/main/java/jaxx/runtime/swing/editor/NumberEditor2.jaxx trunk/jaxx-widgets/src/main/java/jaxx/runtime/swing/editor/NumberEditor2Handler.java trunk/jaxx-widgets/src/main/java/jaxx/runtime/swing/editor/NumberEditor2Model.java Modified: trunk/jaxx-widgets/src/main/resources/i18n/jaxx-widgets_en_GB.properties trunk/jaxx-widgets/src/main/resources/i18n/jaxx-widgets_es_ES.properties trunk/jaxx-widgets/src/main/resources/i18n/jaxx-widgets_fr_FR.properties Added: trunk/jaxx-widgets/src/main/java/jaxx/runtime/swing/editor/NumberEditor2.css =================================================================== --- trunk/jaxx-widgets/src/main/java/jaxx/runtime/swing/editor/NumberEditor2.css (rev 0) +++ trunk/jaxx-widgets/src/main/java/jaxx/runtime/swing/editor/NumberEditor2.css 2014-02-12 14:36:52 UTC (rev 2794) @@ -0,0 +1,128 @@ +JToolBar { + floatable: false; + borderPainted: false; + opaque: false; +} + +#toolbarLeft { + visible: {model.isShowReset()}; +} + +#resetButton { + actionIcon: "numbereditor-reset"; + toolTipText: "numbereditor.action.reset.tip"; + toolTipText: {model.getShowResetTip()}; + focusable: false; + focusPainted: false; + enabled: {isEnabled()}; +} + +#editor { + enabled:{isEnabled()}; +} + +#toolbarRight { + maximumSize: {new Dimension(24,24)}; +} + +#showPopUpButton { + actionIcon: "numbereditor-calculator"; + toolTipText: "numbereditor.action.show.tip"; + enabled: {isEnabled()}; + visible: {model.isShowPopup()}; +} + +JButton { + font-size: 14; + focusPainted: false; + focusable: false; +} + +JButton.digit { + foreground: blue; +} + +JButton.operator { + foreground: #009900; +} + +JButton.clear { + foreground: red; +} + +JButton:mouseover { + font-weight: bold; +} + +JButton.operator:mouseover { + font-weight: normal; +} + +#popupPanel { + border: {BorderFactory.createEmptyBorder(4, 4, 4, 4)}; + background: {Color.WHITE}; +} + +#padTouch0 { + text: "numbereditor.0"; + /*enabled: {!getEditor().getModelText().equals("0")};*/ +} + +#padTouch1 { + text: "numbereditor.1"; +} + +#padTouch2 { + text: "numbereditor.2"; +} + +#padTouch3 { + text: "numbereditor.3"; +} + +#padTouch4 { + text: "numbereditor.4"; +} + +#padTouch5 { + text: "numbereditor.5"; +} + +#padTouch6 { + text: "numbereditor.6"; +} + +#padTouch7 { + text: "numbereditor.7"; +} + +#padTouch8 { + text: "numbereditor.8"; +} + +#padTouch9 { + text: "numbereditor.9"; +} + +#padTouchDot { + text: "numbereditor.dot"; +} + +#padTouchSign { + text: "numbereditor.sign"; + enabled: {model.isUseSign()}; +} + +#padTouchClearOne { + text: "numbereditor.cleanOne"; + /*enabled: {!(getModelText().isEmpty() || textField.getCaretPosition() ==0 )};*/ +} + +#padTouchClearAll { + text: "numbereditor.cleanAll"; + /*enabled: {!getModelText().isEmpty()}:*/ +} + +#padValidate { + actionIcon: "numbereditor-validate"; +} Property changes on: trunk/jaxx-widgets/src/main/java/jaxx/runtime/swing/editor/NumberEditor2.css ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision Added: svn:eol-style + native Added: trunk/jaxx-widgets/src/main/java/jaxx/runtime/swing/editor/NumberEditor2.jaxx =================================================================== --- trunk/jaxx-widgets/src/main/java/jaxx/runtime/swing/editor/NumberEditor2.jaxx (rev 0) +++ trunk/jaxx-widgets/src/main/java/jaxx/runtime/swing/editor/NumberEditor2.jaxx 2014-02-12 14:36:52 UTC (rev 2794) @@ -0,0 +1,73 @@ +<JPanel id='editorPanel' layout='{new BorderLayout()}' + onFocusGained='editor.requestFocus()' + onFocusLost='handler.setPopupVisible(false);popup.setVisible(false);' + onMouseExited='handler.setPopupVisible(false);popup.setVisible(false);'> + <import> + java.io.Serializable + java.awt.BorderLayout + java.awt.Color + java.awt.BorderLayout + java.awt.GridLayout + java.awt.Dimension + + javax.swing.JFormattedTextField + javax.swing.BorderFactory + </import> + + <!-- show reset property --> + <Boolean id='showReset' javaBean='false'/> + + <!-- show reset tip --> + <String id='showResetTip' javaBean=''/> + + <!-- model --> + <NumberEditor2Model id='model'/> + + <script><![CDATA[ +public void init() { handler.init(); } +public void setBean(Serializable bean) { model.setBean(bean); } +public void setBeanProperty(String beanProperty) { model.setBeanProperty(beanProperty); } +public void setValue(Number value) { handler.setValue(value, true); } +]]> + </script> + + <!-- popup digital number editor --> + <JPopupMenu id='popup' + onPopupMenuWillBecomeVisible='showPopUpButton.setSelected(true)' + onPopupMenuWillBecomeInvisible='showPopUpButton.setSelected(false)' + onPopupMenuCanceled='showPopUpButton.setSelected(false)'> + <JPanel id='popupPanel' layout='{new GridLayout(4,4)}'> + + <JButton id='padTouch7' styleClass='digit' onActionPerformed='handler.addChar(event)'/> + <JButton id='padTouch8' styleClass='digit' onActionPerformed='handler.addChar(event)'/> + <JButton id='padTouch9' styleClass='digit' onActionPerformed='handler.addChar(event)'/> + <JButton id='padTouchClearAll' styleClass='clear' onActionPerformed='handler.setModel(null)'/> + + <JButton id='padTouch4' styleClass='digit' onActionPerformed='handler.addChar(event)'/> + <JButton id='padTouch5' styleClass='digit' onActionPerformed='handler.addChar(event)'/> + <JButton id='padTouch6' styleClass='digit' onActionPerformed='handler.addChar(event)'/> + <JButton id='padTouchClearOne' styleClass='clear' onActionPerformed='handler.removeChar()' /> + + <JButton id='padTouch1' styleClass='digit' onActionPerformed='handler.addChar(event)'/> + <JButton id='padTouch2' styleClass='digit' onActionPerformed='handler.addChar(event)'/> + <JButton id='padTouch3' styleClass='digit' onActionPerformed='handler.addChar(event)'/> + <JButton enabled="false"/> + + <JButton id='padTouch0' styleClass='digit' onActionPerformed='handler.addChar(event)'/> + <JButton id='padTouchSign' styleClass='operator' onActionPerformed='handler.toggleSign()'/> + <JButton id='padTouchDot' styleClass='operator' onActionPerformed='handler.addChar(event)'/> + <JButton id='padValidate' onActionPerformed="handler.validate()"/> + </JPanel> + </JPopupMenu> + + <JToolBar id='toolbarLeft' constraints='BorderLayout.WEST'> + <JButton id='resetButton' onActionPerformed='handler.resetEditor()'/> + </JToolBar> + <JFormattedTextField id='editor' constraints='BorderLayout.CENTER' + onKeyReleased='handler.onKeyReleased(event)'/> + + <JToolBar id='toolbarRight' constraints='BorderLayout.EAST'> + <JToggleButton id='showPopUpButton' + onActionPerformed='handler.setPopupVisible(!popup.isVisible())'/> + </JToolBar> +</JPanel> \ No newline at end of file Added: trunk/jaxx-widgets/src/main/java/jaxx/runtime/swing/editor/NumberEditor2Handler.java =================================================================== --- trunk/jaxx-widgets/src/main/java/jaxx/runtime/swing/editor/NumberEditor2Handler.java (rev 0) +++ trunk/jaxx-widgets/src/main/java/jaxx/runtime/swing/editor/NumberEditor2Handler.java 2014-02-12 14:36:52 UTC (rev 2794) @@ -0,0 +1,301 @@ +package jaxx.runtime.swing.editor; + +import com.google.common.base.Preconditions; +import jaxx.runtime.spi.UIHandler; +import jaxx.runtime.swing.editor.bean.BeanUIUtil; +import jaxx.runtime.swing.editor.gis.DmdCoordinate; +import jaxx.runtime.swing.editor.gis.DmdCoordinateConverter; +import jaxx.runtime.swing.editor.gis.MaskFormatterFromConverter; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JFormattedTextField; +import javax.swing.SwingUtilities; +import javax.swing.text.BadLocationException; +import javax.swing.text.DefaultFormatterFactory; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.lang.reflect.Method; +import java.text.ParseException; + +/** + * Created on 2/11/14. + * + * @author Tony Chemit <chemit@codelutin.com> + * @since 2.8.1 + */ +public class NumberEditor2Handler implements UIHandler<NumberEditor2> { + + /** Logger. */ + private static final Log log = LogFactory.getLog(NumberEditor2Handler.class); + + protected NumberEditor2 ui; + + protected JFormattedTextField editor; + + protected DmdCoordinateConverter signedConverter; + + protected DmdCoordinateConverter unsignedConverter; + + protected DefaultFormatterFactory signedFormatterFactory; + + protected DefaultFormatterFactory unsignedFormatterFactory; + + /** the mutator method on the property of boxed bean in the editor */ + protected Method mutator; + + /** the getter method on the property */ + protected Method getter; + + /** a flag to known if mutator accept null value */ + protected Boolean acceptNull; + + protected NumberEditor2Model model; + + protected String lastValidText; + + @Override + public void beforeInit(NumberEditor2 ui) { + this.ui = ui; + } + + @Override + public void afterInit(NumberEditor2 ui) { + this.model = ui.getModel(); + this.editor = ui.getEditor(); + + } + + public void init() { + + Preconditions.checkNotNull(model.getBean(), "could not find bean in " + model); + Preconditions.checkNotNull(model.getBeanProperty(), "could not find beanProperty in " + model); + Preconditions.checkNotNull(model.getNumberType(), "could not find numberType in " + model); + + Object bean = model.getBean(); + mutator = BeanUIUtil.getMutator(bean, model.getBeanProperty()); + Preconditions.checkNotNull(mutator, "could not find mutator for " + model.getBeanProperty()); + + { + // prepare unsigned formatter factory + String pattern = getMaskFormatterPattern(false); + MaskFormatterFromConverter<DmdCoordinate> maskFormatter; + try { + maskFormatter = MaskFormatterFromConverter.newFormatter( + DmdCoordinate.class, + pattern, unsignedConverter); + maskFormatter.setValidCharacters(" 01234567890."); + maskFormatter.setCommitsOnValidEdit(true); + unsignedFormatterFactory = new DefaultFormatterFactory(maskFormatter); + } catch (ParseException e) { + // can't happen here + throw new RuntimeException(e); + } + } + { + // prepare signed formatter factory + String pattern = getMaskFormatterPattern(true); + MaskFormatterFromConverter<DmdCoordinate> maskFormatter; + try { + maskFormatter = MaskFormatterFromConverter.newFormatter( + DmdCoordinate.class, + pattern, signedConverter); + maskFormatter.setValidCharacters(" 01234567890."); + maskFormatter.setCommitsOnValidEdit(true); + signedFormatterFactory = new DefaultFormatterFactory(maskFormatter); + } catch (ParseException e) { + // can't happen here + throw new RuntimeException(e); + } + } + +// JFormattedTextField editor = ui.getEditor(); +// editor.setFormatterFactory(model.isSign() ? +// signedFormatterFactory : +// unsignedFormatterFactory); +// editor.setFocusLostBehavior(JFormattedTextField.COMMIT); +// +// // When editor changes his value, propagate it to model +// editor.addPropertyChangeListener("value", new PropertyChangeListener() { +// @Override +// public void propertyChange(PropertyChangeEvent evt) { +// DmdCoordinate newValue = (DmdCoordinate) evt.getNewValue(); +// if (log.isDebugEnabled()) { +// log.debug("Value has changed: " + newValue); +// } +// model.setValue(newValue); +// } +// }); + } + + public void setModel(Object model) { + + } + + /** + * Ajoute le caractère donné à l'endroit où est le curseur dans la zone de + * saisie et met à jour le modèle. + * + * @param s le caractère à ajouter. + */ + void addChar(String s) { + char c = s.charAt(0); + try { + editor.getDocument().insertString(editor.getCaretPosition(), c + "", null); +// setModel(editor.getText()); + //setModel(editor.getModelText() + c); + + } catch (BadLocationException e) { + log.warn(e); + } + } + + /** + * Supprime le caractère juste avant le curseur du modèle (textuel) et + * met à jour la zone de saisie. + */ + public void removeChar() { +// String s = editor.getModelText(); +// int position = editor.getCaretPosition(); +// if (position < 1 || s.isEmpty()) { +// if (log.isDebugEnabled()) { +// log.debug("cannot remove when caret on first position or text empty"); +// } +// // on est au debut du doc, donc rien a faire +// return; +// } +// try { +// editor.getDocument().remove(position - 1, 1); +// } catch (BadLocationException ex) { +// // ne devrait jamais arrive vu qu'on a fait le controle... +// log.debug(ex); +// return; +// } +// String newText = editor.getText(); +// if (log.isDebugEnabled()) { +// log.debug("text updated : " + newText); +// } +// position--; +// editor.setCaretPosition(position); +// setModel(newText); + } + + /** + * Permute le signe dans la zone de saisie et + * dans le modèle. + */ + public void toggleSign() { +// // change sign +// String newValue = editor.getModelText(); +// +// if (newValue.startsWith("-")) { +// setModel(newValue.substring(1)); +// } else { +// setModel("-" + newValue); +// } + } + + void addChar(ActionEvent event) { + String text = ((JButton) event.getSource()).getText(); + addChar(text); + } + + /** + * Affiche ou cache la popup. + * + * @param newValue la nouvelle valeur de visibilité de la popup. + */ + public void setPopupVisible(Boolean newValue) { + + if (log.isTraceEnabled()) { + log.trace(newValue); + } + + if (newValue == null || !newValue) { + ui.getPopup().setVisible(false); + return; + } + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + JComponent invoker = + model.isShowPopup() ? + ui.getShowPopUpButton() : + ui; + Dimension dim = ui.getPopup().getPreferredSize(); + int x = (int) (invoker.getPreferredSize().getWidth() - dim.getWidth()); + ui.getPopup().show(invoker, x, invoker.getHeight()); + ui.getEditor().requestFocus(); + } + }); + } + + protected String getMaskFormatterPattern(boolean useSign) { + String pattern = "############"; + if (useSign) { + pattern = "-" + pattern; + } + return pattern; + } + + public void validate() { + //TODO + } + + public void resetEditor() { + //TODO + } + + public void onKeyReleased(KeyEvent event) { + //TODO + } + + public void setValue(Number value, boolean b) { + //TODO + } + + protected class PopupListener extends MouseAdapter { + + @Override + public void mousePressed(MouseEvent e) { + maybeShowPopup(e); + } + + @Override + public void mouseReleased(MouseEvent e) { + maybeShowPopup(e); + } + + protected void maybeShowPopup(MouseEvent e) { + if (!e.isPopupTrigger()) { + return; + } + if (model.isAutoPopup()) { + if (model.isPopupVisible()) { + if (!ui.getPopup().isVisible()) { + setPopupVisible(true); + } + // popup already visible + + } else { + // set popup auto + model.setPopupVisible(true); + + } + } else { + if (model.isPopupVisible()) { + setPopupVisible(true); + } + } + } + + } +} Property changes on: trunk/jaxx-widgets/src/main/java/jaxx/runtime/swing/editor/NumberEditor2Handler.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision Added: svn:eol-style + native Added: trunk/jaxx-widgets/src/main/java/jaxx/runtime/swing/editor/NumberEditor2Model.java =================================================================== --- trunk/jaxx-widgets/src/main/java/jaxx/runtime/swing/editor/NumberEditor2Model.java (rev 0) +++ trunk/jaxx-widgets/src/main/java/jaxx/runtime/swing/editor/NumberEditor2Model.java 2014-02-12 14:36:52 UTC (rev 2794) @@ -0,0 +1,174 @@ +package jaxx.runtime.swing.editor; + +import org.jdesktop.beans.AbstractSerializableBean; + +import java.util.regex.Pattern; + +/** + * Created on 2/11/14. + * + * @author Tony Chemit <chemit@codelutin.com> + * @since 2.8.1 + */ +public class NumberEditor2Model extends AbstractSerializableBean { + + public static final String PROPERTY_BEAN = "bean"; + + public static final String PROPERTY_BEAN_PROPERTY = "beanProperty"; + + public static final String PROPERTY_NUMBER_TYPE = "numberType"; + + public static final String PROPERTY_NUMBER_PATTERN = "numberPattern"; + + public static final String PROPERTY_USE_SIGN = "useSign"; + + public static final String PROPERTY_SHOW_RESET = "showReset"; + + public static final String PROPERTY_SHOW_POPUP = "showPopup"; + + public static final String PROPERTY_AUTO_POPUP = "autoPopup"; + + public static final String PROPERTY_MODEL = "model"; + + public static final String PROPERTY_MODEL_TEXT = "modelText"; + + public static final String PROPERTY_POPUP_VISIBLE = "popupVisible"; + + public static final String PROPERTY_SELECT_ALL_TEXT_ON_ERROR = "selectAllTextOnError"; + + public static final String PROPERTY_SHOW_RESET_TIP = "showResetTip"; + + private static final long serialVersionUID = 1L; + + protected Object bean; + + protected String beanProperty; + + protected Class<? extends Number> numberType; + + protected Pattern numberPattern; + + protected boolean useSign; + + protected boolean showReset; + + protected boolean showPopup; + + protected boolean autoPopup; + + protected boolean selectAllTextOnError; + + protected boolean popupVisible; + + private String showResetTip; + + public Object getBean() { + return bean; + } + + public String getBeanProperty() { + return beanProperty; + } + + public Class<? extends Number> getNumberType() { + return numberType; + } + + public Pattern getNumberPattern() { + return numberPattern; + } + + public boolean isUseSign() { + return useSign; + } + + public boolean isShowReset() { + return showReset; + } + + public boolean isShowPopup() { + return showPopup; + } + + public boolean isAutoPopup() { + return autoPopup; + } + + public boolean isSelectAllTextOnError() { + return selectAllTextOnError; + } + + public boolean isPopupVisible() { + return popupVisible; + } + + public String getShowResetTip() { + return showResetTip; + } + + public void setBean(Object bean) { + Object oldValue = getBean(); + this.bean = bean; + firePropertyChange(PROPERTY_BEAN, oldValue, bean); + } + + public void setBeanProperty(String beanProperty) { + Object oldValue = getBeanProperty(); + this.beanProperty = beanProperty; + firePropertyChange(PROPERTY_BEAN_PROPERTY, oldValue, beanProperty); + } + + public void setNumberType(Class<? extends Number> numberType) { + Object oldValue = getNumberType(); + this.numberType = numberType; + firePropertyChange(PROPERTY_NUMBER_TYPE, oldValue, numberType); + } + + public void setNumberPattern(Pattern numberPattern) { + Object oldValue = getNumberPattern(); + this.numberPattern = numberPattern; + firePropertyChange(PROPERTY_NUMBER_PATTERN, oldValue, numberPattern); + } + + public void setUseSign(boolean useSign) { + Object oldValue = isUseSign(); + this.useSign = useSign; + firePropertyChange(PROPERTY_USE_SIGN, oldValue, useSign); + } + + public void setShowReset(boolean showReset) { + Object oldValue = isShowReset(); + this.showReset = showReset; + firePropertyChange(PROPERTY_SHOW_RESET, oldValue, showReset); + } + + public void setShowPopup(boolean showPopup) { + Object oldValue = isShowPopup(); + this.showPopup = showPopup; + firePropertyChange(PROPERTY_SHOW_POPUP, oldValue, showPopup); + } + + public void setAutoPopup(boolean autoPopup) { + Object oldValue = isAutoPopup(); + this.autoPopup = autoPopup; + firePropertyChange(PROPERTY_AUTO_POPUP, oldValue, autoPopup); + } + + public void setSelectAllTextOnError(boolean selectAllTextOnError) { + Object oldValue = isSelectAllTextOnError(); + this.selectAllTextOnError = selectAllTextOnError; + firePropertyChange(PROPERTY_SELECT_ALL_TEXT_ON_ERROR, oldValue, selectAllTextOnError); + } + + public void setPopupVisible(boolean popupVisible) { + Object oldValue = isPopupVisible(); + this.popupVisible = popupVisible; + firePropertyChange(PROPERTY_POPUP_VISIBLE, oldValue, popupVisible); + } + + public void setShowResetTip(String showResetTip) { + Object oldValue = getShowResetTip(); + this.showResetTip = showResetTip; + firePropertyChange(PROPERTY_SHOW_RESET_TIP, oldValue, showResetTip); + } +} Property changes on: trunk/jaxx-widgets/src/main/java/jaxx/runtime/swing/editor/NumberEditor2Model.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision Added: svn:eol-style + native Modified: trunk/jaxx-widgets/src/main/resources/i18n/jaxx-widgets_en_GB.properties =================================================================== --- trunk/jaxx-widgets/src/main/resources/i18n/jaxx-widgets_en_GB.properties 2014-02-12 14:36:31 UTC (rev 2793) +++ trunk/jaxx-widgets/src/main/resources/i18n/jaxx-widgets_en_GB.properties 2014-02-12 14:36:52 UTC (rev 2794) @@ -94,7 +94,11 @@ numbereditor.9=9 numbereditor.action.reset.tip=Reset numbereditor.action.show.tip=Show numeric panel +numbereditor.cleanAll= +numbereditor.cleanOne= numbereditor.clearAll=C numbereditor.clearOne=CE +numbereditor.dot= +numbereditor.sign= numbereditor.toggleSign=+/- timeeditor.H=H Modified: trunk/jaxx-widgets/src/main/resources/i18n/jaxx-widgets_es_ES.properties =================================================================== --- trunk/jaxx-widgets/src/main/resources/i18n/jaxx-widgets_es_ES.properties 2014-02-12 14:36:31 UTC (rev 2793) +++ trunk/jaxx-widgets/src/main/resources/i18n/jaxx-widgets_es_ES.properties 2014-02-12 14:36:52 UTC (rev 2794) @@ -94,7 +94,11 @@ numbereditor.9=9 numbereditor.action.reset.tip=Reinicializar numbereditor.action.show.tip=Mostar el teclado numérico +numbereditor.cleanAll= +numbereditor.cleanOne= numbereditor.clearAll=C numbereditor.clearOne=CE +numbereditor.dot= +numbereditor.sign= numbereditor.toggleSign=+/- timeeditor.H=H Modified: trunk/jaxx-widgets/src/main/resources/i18n/jaxx-widgets_fr_FR.properties =================================================================== --- trunk/jaxx-widgets/src/main/resources/i18n/jaxx-widgets_fr_FR.properties 2014-02-12 14:36:31 UTC (rev 2793) +++ trunk/jaxx-widgets/src/main/resources/i18n/jaxx-widgets_fr_FR.properties 2014-02-12 14:36:52 UTC (rev 2794) @@ -94,7 +94,11 @@ numbereditor.9=9 numbereditor.action.reset.tip=Réinitialiser numbereditor.action.show.tip=Afficher le pavé numérique +numbereditor.cleanAll= +numbereditor.cleanOne= numbereditor.clearAll=C numbereditor.clearOne=CE +numbereditor.dot= +numbereditor.sign= numbereditor.toggleSign=+/- timeeditor.H=H
participants (1)
-
tchemit@users.nuiton.org