Author: tchemit Date: 2009-07-27 22:27:58 +0200 (Mon, 27 Jul 2009) New Revision: 1511 Added: trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/ColumnSelector.jaxx trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigCategoryUI.css trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigCategoryUI.jaxx trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigTableEditor.java trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigTableRenderer.java trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigUI.css trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigUI.jaxx trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigUIBuilder.java trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/ trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/CategoryModel.java trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/ConfigTableModel.java trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/ConfigUIModel.java trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/OptionModel.java trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-config-quit.png trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-config-reset.png trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-config-save.png Log: normalize i18n keys in widgets, add ApplicationConfig ui to change preferences, degin of a ColumnSelector (should have a look in swingx...) Added: trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/ColumnSelector.jaxx =================================================================== --- trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/ColumnSelector.jaxx (rev 0) +++ trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/ColumnSelector.jaxx 2009-07-27 20:27:58 UTC (rev 1511) @@ -0,0 +1,152 @@ +<!-- + +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ + +--> +<JPanel implements='PropertyChangeListener, ActionListener' + layout='{new BorderLayout()}' + onFocusGained='button.requestFocus()' + onFocusLost='setPopupVisible(false)'> + + <!-- table to works with --> + <Object id='myTable' javaBean='null'/> + + <!-- internal state --> + <Boolean id='popupVisible' javaBean='false'/> + + <!-- ui handler --> + <!--ColumnSelectorHandler id='handler' constructorParams='this'/--> + + <JPopupMenu id='popup' + border='{new TitledBorder(_("i18neditor.popup.title"))}' + onPopupMenuWillBecomeInvisible='button.setSelected(false)' + onPopupMenuCanceled='button.setSelected(false)'> + <JLabel id='popupLabel' enabled='false' text='i18neditor.empty.locales'/> + </JPopupMenu> + + <script><![CDATA[ +import javax.swing.table.TableColumn; +import javax.swing.table.TableCellRenderer; +import jaxx.runtime.swing.I18nTableCellRenderer; + +public static final String TABLE_PROPERTY = "myTable"; +public static final String POPUP_VISIBLE_PROPERTY = "popupVisible"; + +@Override +public void propertyChange(PropertyChangeEvent evt) { + String name = evt.getPropertyName(); + if (log.isDebugEnabled()) { + log.debug(name+" <old:"+evt.getOldValue()+" - new:"+evt.getNewValue()+">"); + } + //log.info(name+" <old:"+evt.getOldValue()+" - new:"+evt.getNewValue()+">"); + if (TABLE_PROPERTY.equals(name)) { + // table has changed, rebuild the popup + try { + + popup.removeAll(); + JTable t = (JTable) evt.getNewValue(); + if (t != null) { + log.info("table has changed ! " + t.getName()); + for (int i = 0, columnCount = t.getColumnCount(); i < columnCount; i++) { + TableColumn column = t.getColumnModel().getColumn(i); + TableCellRenderer defaultRenderer = t.getTableHeader().getDefaultRenderer(); + String columnName = column.getHeaderValue() + ""; + if (defaultRenderer instanceof I18nTableCellRenderer) { + I18nTableCellRenderer renderer = (I18nTableCellRenderer) defaultRenderer; + columnName = _(renderer.getKeys()[i]); + } + JRadioButtonMenuItem b = new JRadioButtonMenuItem(columnName, null, true); + popup.add(b); + b.addActionListener(this); + b.putClientProperty("columnIndex", i); + b.putClientProperty("columnName", columnName); + b.putClientProperty("column", column); + } + } + } finally { + popup.invalidate(); + } + return; + } + if (POPUP_VISIBLE_PROPERTY.equals(name)) { + Boolean newValue = (Boolean) evt.getNewValue(); + if (newValue == null || !newValue) { + if (getPopup() != null && getPopup().isVisible()) { + getPopup().setVisible(false); + } + return; + } + if (!getPopup().isVisible()) { + SwingUtilities.invokeLater(showPopupRunnable); + } + return; + } + +} + +@Override +public void actionPerformed(ActionEvent event) { + JRadioButtonMenuItem source = (JRadioButtonMenuItem) event.getSource(); + boolean selected = source.isSelected(); + TableColumn column = (TableColumn) source.getClientProperty("column"); + Integer columnIndex = (Integer) source.getClientProperty("columnIndex"); + String columnName = (String) source.getClientProperty("columnName"); + log.info(columnName + ", selected : " + selected); + JTable t = (JTable) myTable; + if (selected) { + // reinject the column in table + t.getColumnModel().addColumn(column); + } else { + // remove column from table + t.getColumnModel().removeColumn(column); + } +} + +protected Runnable showPopupRunnable = new Runnable() { + @Override + public void run() { + getPopup().pack(); + Dimension dim = getPopup().getPreferredSize(); + JToggleButton invoker = getButton(); + getPopup().show(invoker, (int) (invoker.getPreferredSize().getWidth() - dim.getWidth()), invoker.getHeight()); + } +}; + + +addPropertyChangeListener(TABLE_PROPERTY,this); +addPropertyChangeListener(POPUP_VISIBLE_PROPERTY,this); +]]> + </script> + <JToolBar floatable='false' + opaque='false' + borderPainted='false'> + <JToggleButton + id='button' + toolTipText='columnselector.action.tip' + actionIcon='numbereditor-calculator' + constraints='BorderLayout.CENTER' + selected='{popup.isVisible()}' + focusable='true' + focusPainted='false' + borderPainted='false' + rolloverEnabled='false' + onItemStateChanged='if (event.getStateChange() == ItemEvent.SELECTED) { setPopupVisible(true); } else { popupVisible = false; }'/> + </JToolBar> +</JPanel> \ No newline at end of file Added: trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigCategoryUI.css =================================================================== --- trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigCategoryUI.css (rev 0) +++ trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigCategoryUI.css 2009-07-27 20:27:58 UTC (rev 1511) @@ -0,0 +1,60 @@ +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* +*/ + +#categoryLabelPanel { + background:{Color.WHITE}; +} + +#descriptionPane { + columnHeaderView:{new JLabel(_("config.descrition"), jaxx.runtime.Util.getUIManagerActionIcon("information"), 10)}; +} + +#description { + rows:3; + editable:false; + focusable:false; + font-size:10; + text:{_("config.no.option.selected")}; +} + +#tablePane { + columnHeaderView:{table.getTableHeader()}; + verticalScrollBarPolicy:{ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS}; +horizontalScrollBarPolicy:{ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER}; +} + +#table { + rowSelectionAllowed:false; + autoCreateRowSorter:true; + autoResizeMode:{JTable.AUTO_RESIZE_ALL_COLUMNS}; +} + +#reset{ + text:"config.action.reset"; + toolTipText:"config.action.reset.tip"; + actionIcon:"config-reset"; + enabled:{getCategoryModel().isModified()}; +} + +#save{ + text:"config.action.save"; + toolTipText:"config.action.save.tip"; + actionIcon:"config-save"; + enabled:{getCategoryModel().isModified() && getCategoryModel().isValid()}; +} Added: trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigCategoryUI.jaxx =================================================================== --- trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigCategoryUI.jaxx (rev 0) +++ trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigCategoryUI.jaxx 2009-07-27 20:27:58 UTC (rev 1511) @@ -0,0 +1,120 @@ +<!-- + +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ + +--> + +<JPanel layout='{new BorderLayout()}'> + + <style source='ConfigCategoryUI.css'/> + + <script><![CDATA[ +import jaxx.runtime.SwingUtil; +import jaxx.runtime.swing.editor.config.model.*; +import jaxx.runtime.swing.editor.ColumnSelector; +import static org.nuiton.i18n.I18n.n_; + +void $afterCompleteSetup() { + // prepare table + SwingUtil.setI18nTableHeaderRenderer(table, + n_("config.key"), + n_("config.key.tip"), + n_("config.value"), + n_("config.value.tip"), + n_("config.defaultValue"), + n_("config.defaultValue.tip")); + + ConfigTableRenderer renderer = new ConfigTableRenderer(); + SwingUtil.setTableColumnRenderer(table, 0, renderer); + SwingUtil.setTableColumnRenderer(table, 1, renderer); + SwingUtil.setTableColumnRenderer(table, 2, renderer); + Font f = table.getFont().deriveFont(Font.ITALIC | Font.BOLD); + int width = SwingUtil.computeTableColumnWidth(table, f, 0, "___*"); + SwingUtil.fixTableColumnWidth(table, 0, width); + SwingUtil.setTableColumnEditor(table, 1, new ConfigTableEditor((ConfigTableModel) table.getModel())); + //TODO to be continued... + //columnSelector.setMyTable(table); + //tablePane.setCorner(ScrollPaneConstants.UPPER_RIGHT_CORNER, columnSelector); +} + +protected void updateDescriptionText() { + OptionModel option; + if (selectionModel.isSelectionEmpty()) { + option = null; + } else { + int row = selectionModel.getAnchorSelectionIndex(); + ConfigTableModel m = (ConfigTableModel) table.getModel(); + option = m.getEntry(row); + if (log.isDebugEnabled()) { + log.debug(row + " : " + option); + } + } + StringBuilder buffer = new StringBuilder(); + if (option == null) { + buffer.append(_("config.no.option.selected")); + } else { + buffer.append(_("config.option.label", option.getKey(), _(option.getDescription()))).append('\n'); + if (option.isModified()) { + buffer.append(_("config.option.modified", option.getOriginalValue(), option.getValue())).append('\n'); + } + if (option.isFinal()) { + buffer.append(_("config.option.final")).append('\n'); + } + } + description.setText(buffer.toString()); +} +]]> + </script> + + <CategoryModel id='categoryModel' javaBean='getContextValue(CategoryModel.class)'/> + + <ConfigTableModel id='tableModel' constructorParams='categoryModel' + onTableChanged='updateDescriptionText()'/> + + <ListSelectionModel id='selectionModel' javaBean='new DefaultListSelectionModel()' + onValueChanged='if (!event.getValueIsAdjusting()) { updateDescriptionText(); }'/> + + <!--<ColumnSelector id='columnSelector' />--> + + <!-- categorie label --> + <JPanel id="categoryLabelPanel" constraints='BorderLayout.NORTH'> + <JLabel id='categoryLabel'/> + </JPanel> + + <!-- table of options --> + <JScrollPane id='tablePane' constraints='BorderLayout.CENTER'> + <JTable id="table" constructorParams='tableModel' + selectionModel='{selectionModel}'/> + </JScrollPane> + + <JPanel layout='{new BorderLayout()}' constraints='BorderLayout.SOUTH'> + + <!-- description of selected option in table --> + <JScrollPane id="descriptionPane" constraints='BorderLayout.CENTER'> + <JTextArea id='description'/> + </JScrollPane> + + <!-- actions of the category --> + <JPanel layout='{new GridLayout(1,0)}' constraints='BorderLayout.SOUTH'> + <JButton id='reset' onActionPerformed='getContextValue(ConfigUIModel.class).reset()'/> + <JButton id='save' onActionPerformed='getContextValue(ConfigUIModel.class).saveModified()'/> + </JPanel> + </JPanel> +</JPanel> Added: trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigTableEditor.java =================================================================== --- trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigTableEditor.java (rev 0) +++ trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigTableEditor.java 2009-07-27 20:27:58 UTC (rev 1511) @@ -0,0 +1,125 @@ +/* +* *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ +package jaxx.runtime.swing.editor.config; + +import jaxx.runtime.swing.editor.config.model.ConfigTableModel; +import javax.swing.DefaultCellEditor; +import javax.swing.JTable; +import javax.swing.event.CellEditorListener; +import javax.swing.table.TableCellEditor; +import java.awt.Component; +import java.util.EventObject; +import java.util.Locale; +import jaxx.runtime.swing.editor.ClassCellEditor; +import jaxx.runtime.swing.editor.EnumEditor; +import jaxx.runtime.swing.editor.LocaleEditor; + +/** + * L'éditeur des valeurs des propriétés d'une configuration + * + * @author chemit + */ +public class ConfigTableEditor implements TableCellEditor { + + protected TableCellEditor delegate; + protected ConfigTableModel model; + + public ConfigTableEditor(ConfigTableModel model) { + this.model = model; + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + delegate = findDelegate(table, model.getEntry(row).getType()); + return delegate.getTableCellEditorComponent(table, value, isSelected, row, column); + } + + @Override + public Object getCellEditorValue() { + return !hasDelegate() ? null : delegate.getCellEditorValue(); + } + + @Override + public boolean isCellEditable(EventObject anEvent) { + return !hasDelegate() || delegate.isCellEditable(anEvent); + } + + @Override + public boolean shouldSelectCell(EventObject anEvent) { + return hasDelegate() && delegate.shouldSelectCell(anEvent); + } + + @Override + public boolean stopCellEditing() { + return !hasDelegate() || delegate.stopCellEditing(); + } + + @Override + public void cancelCellEditing() { + if (hasDelegate()) { + delegate.cancelCellEditing(); + } + } + + @Override + public void addCellEditorListener(CellEditorListener l) { + if (hasDelegate()) { + delegate.addCellEditorListener(l); + } + } + + @Override + public void removeCellEditorListener(CellEditorListener l) { + if (hasDelegate()) { + delegate.removeCellEditorListener(l); + } + } + + protected TableCellEditor findDelegate(JTable table, Class<?> type) { + TableCellEditor editor = table.getDefaultEditor(type); + TableCellEditor defaultEditor = table.getDefaultEditor(Object.class); + if (editor == defaultEditor) { + // find not a specialized editor for the type + if (type.isEnum()) { + // add a EnumEditor to table + editor = new DefaultCellEditor(EnumEditor.newEditor((Class<Enum>) type)); + table.setDefaultEditor(type, editor); + } else if (type == Class.class) { + editor = new ClassCellEditor(); + table.setDefaultEditor(type, editor); + } //else if (type == File.class){ + // TODO a FileEditor + // table.setDefaultEditor(type, delegate); + //} + else if (type.equals(Locale.class)) { + editor = new DefaultCellEditor(LocaleEditor.newEditor()); + table.setDefaultEditor(Locale.class, editor); + } else { + editor = table.getDefaultEditor(String.class); + } + } + if (editor == null) { + throw new IllegalStateException("could not find a editor for type +" + type); + } + return editor; + } + + protected boolean hasDelegate() { + return delegate != null; + } +} Added: trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigTableRenderer.java =================================================================== --- trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigTableRenderer.java (rev 0) +++ trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigTableRenderer.java 2009-07-27 20:27:58 UTC (rev 1511) @@ -0,0 +1,112 @@ +/* + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ +package jaxx.runtime.swing.editor.config; + +import static org.nuiton.i18n.I18n._; + +import javax.swing.JComponent; +import javax.swing.JTable; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableCellRenderer; +import java.awt.Color; +import java.awt.Component; +import java.awt.Font; +import jaxx.runtime.swing.editor.config.model.ConfigTableModel; +import jaxx.runtime.swing.editor.config.model.OptionModel; + +/** + * Pour le rendu du tableau des options d'une categorie + * + * @author chemit + * @see ConfigTableModel + */ +public class ConfigTableRenderer extends DefaultTableCellRenderer { + + private static final long serialVersionUID = 1L; + protected static Color col; + protected static Font font; + protected static Font font2; + + public ConfigTableRenderer() { + col = getForeground(); + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + int modelRow = table.convertRowIndexToModel(row); + int modelColumn = table.convertColumnIndexToModel(column); + ConfigTableModel model = (ConfigTableModel) table.getModel(); + OptionModel key = model.getEntry(modelRow); + boolean isModified = key.isModified(); + + boolean isValid = key.isValid(); + + if (font == null) { + font = getFont(); + font2 = font.deriveFont(Font.ITALIC | Font.BOLD); + } + Component cellRenderer = null; + switch (modelColumn) { + case 0: + cellRenderer = getKeyCellRenderer(table, value, isSelected, hasFocus, modelRow, modelColumn, key, isValid, isModified); + break; + case 1: + cellRenderer = getValueCellRenderer(table, value, isSelected, hasFocus, modelRow, modelColumn, key, isValid, isModified); + break; + case 2: + cellRenderer = getValueCellRenderer(table, value, isSelected, hasFocus, modelRow, modelColumn, key, isValid, isModified); + break; + default: + throw new IllegalStateException("no renderer find for column " + modelColumn); + } + return cellRenderer; + } + + protected Component getKeyCellRenderer(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column, OptionModel key, boolean isValid, boolean isModified) { + String tooltip = _(key.getDescription()); + Object originalValue = key.getOriginalValue(); + boolean isFinal = key.isFinal(); + if (isFinal) { + tooltip += " [" + _("config.unmodifiable") + ']'; + } + if (isModified) { + String s = _("config.modified", originalValue); + value = value + " *"; + tooltip += " [" + s + ']'; + } + if (!isValid) { + String s2 = _("config.unvalid", originalValue, key.getType()); + tooltip += " (" + s2 + ")"; + value = value + " !"; + } + JComponent result = (JComponent) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + result.setToolTipText(tooltip); + result.setForeground(isValid ? col : Color.RED); + result.setFont(isModified || !isValid ? font2 : font); + result.setEnabled(!isFinal); + return result; + } + + protected Component getValueCellRenderer(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column, OptionModel key, boolean isValid, boolean isModified) { + TableCellRenderer defaultRenderer = table.getDefaultRenderer(key.getType()); + + Component result; + result = defaultRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + return result; + } +} Added: trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigUI.css =================================================================== --- trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigUI.css (rev 0) +++ trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigUI.css 2009-07-27 20:27:58 UTC (rev 1511) @@ -0,0 +1,27 @@ +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* +*/ +#quit{ + text:"config.action.quit"; + toolTipText:"config.action.quit.tip"; + actionIcon:"config-quit"; +} + +#categories{ + tabPlacement:{JTabbedPane.LEFT}; +} Added: trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigUI.jaxx =================================================================== --- trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigUI.jaxx (rev 0) +++ trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigUI.jaxx 2009-07-27 20:27:58 UTC (rev 1511) @@ -0,0 +1,72 @@ +<!-- + +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ + +--> + +<JPanel layout='{new BorderLayout()}'> + + <style source='ConfigUI.css'/> + + <script><![CDATA[ + import jaxx.runtime.swing.editor.config.model.ConfigUIModel; + + categories.setModel(new DefaultSingleSelectionModel() { + + private static final long serialVersionUID = 1L; + + @Override + public void setSelectedIndex(int index) { + // check if catgeory can be quit + boolean canContinue = !isSelected() || ConfigUIBuilder.canQuitCategory(ConfigUI.this); + if (canContinue) { + if (log.isDebugEnabled()) { + log.debug("new index : " + index); + } + // was authorized to continue + super.setSelectedIndex(index); + } + } + }); + + protected void changeCategory(ChangeEvent e) { + JPanel p = (JPanel) getCategories().getSelectedComponent(); + if (p == null) { + // pas de selection + return; + } + getModel().setCategory(p.getName()); + getCategories().invalidate(); + } + ]]> + </script> + + <!-- le modele de l'ui --> + <ConfigUIModel id='model' javaBean='getContextValue(ConfigUIModel.class)'/> + + <!-- les differentes categories de la configuration --> + <JTabbedPane id='categories' constraints='BorderLayout.CENTER' + onStateChanged='changeCategory(event)' /> + + <!-- pour quitter l'ui --> + <JPanel layout='{new GridLayout(1,0)}' constraints='BorderLayout.SOUTH'> + <JButton id='quit'/> + </JPanel> +</JPanel> Added: trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigUIBuilder.java =================================================================== --- trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigUIBuilder.java (rev 0) +++ trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/ConfigUIBuilder.java 2009-07-27 20:27:58 UTC (rev 1511) @@ -0,0 +1,220 @@ +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ +package jaxx.runtime.swing.editor.config; + +import java.awt.Frame; +import java.awt.event.ActionEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JOptionPane; +import javax.swing.JRootPane; +import javax.swing.KeyStroke; +import jaxx.runtime.JAXXContext; +import jaxx.runtime.JAXXInitialContext; +import jaxx.runtime.SwingUtil; + +import jaxx.runtime.swing.editor.config.model.CategoryModel; +import jaxx.runtime.swing.editor.config.model.ConfigUIModel; +import jaxx.runtime.swing.editor.config.model.OptionModel; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import static org.nuiton.i18n.I18n._; + +/** + * La classe pour construire l'ui + * @author chemit + */ +public class ConfigUIBuilder { + + public static final Log log = LogFactory.getLog(ConfigUIBuilder.class); + + /** + * Construire l'ui de configuration (sous forme de panel) + * + * @param parentContext le context applicatif + * @param model le modele de l'ui de configuration + * @param defaultCategory la categorie a selectionner + * @return l'ui instanciate + */ + public static ConfigUI newConfigUI(jaxx.runtime.JAXXContext parentContext, final ConfigUIModel model, String defaultCategory) { + JAXXContext tx = new JAXXInitialContext().add(parentContext).add(model); + + final ConfigUI ui = new ConfigUI(tx); + JButton quitButton = ui.getQuit(); + + // prepare quit action + Action quitAction = new AbstractAction(quitButton.getText(), quitButton.getIcon()) { + + private static final long serialVersionUID = 1L; + + @Override + public void actionPerformed(ActionEvent e) { + if (canQuitCategory(ui)) { + ui.getParentContainer(JDialog.class).dispose(); + } + } + }; + String tip = quitButton.getToolTipText(); + quitButton.setAction(quitAction); + quitButton.setToolTipText(tip); + + // build categories tabs + for (CategoryModel categoryModel : model) { + String category = categoryModel.getCategory(); + String categoryLabel = _(categoryModel.getCategoryLabel()); + ConfigCategoryUI p = new ConfigCategoryUI(new JAXXInitialContext().add(ui).add(categoryModel)); + p.getCategoryLabel().setText(categoryLabel); + p.setName(category); + ui.getCategories().addTab(_(category), null, p, categoryLabel); + } + + model.setCategory(defaultCategory); + int categoryIndex = model.getCategoryIndex(defaultCategory); + if (log.isDebugEnabled()) { + log.debug("index of default category (" + defaultCategory + ") : " + categoryIndex); + } + ui.getCategories().setSelectedIndex(categoryIndex); + return ui; + } + + /** + * Affiche l'ui de configuration dans un boite de dialogue. + * + * @param configUI l'ui de configuration + * @param ui l'ui parent de la boite de dialogue a afficher (peut etre nulle) + * @param undecorated un drapeau pour savoir si on affiche les decorations de fenetre + */ + public static void showConfigUI(final ConfigUI configUI, Frame ui, boolean undecorated) { + JDialog f = new JDialog(ui, true); + f.setTitle(_("config.title")); + f.add(configUI); + if (ui != null) { + f.setIconImage(ui.getIconImage()); + } + // pour savoir si l'ui est autonome + configUI.putClientProperty("standalone", ui == null); + + f.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); + f.addWindowListener(new WindowAdapter() { + + @Override + public void windowClosing(WindowEvent e) { + + if (canQuitCategory(configUI)) { + e.getWindow().dispose(); + } + } + }); + f.setUndecorated(undecorated); + JRootPane rootPane = f.getRootPane(); + rootPane.setDefaultButton(configUI.getQuit()); + rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("ESCAPE"), "quit"); + rootPane.getActionMap().put("quit", configUI.getQuit().getAction()); + f.pack(); + SwingUtil.center(ui, f); + f.setVisible(true); + } + + protected static boolean canQuitCategory(ConfigUI ui) { + boolean canContinue = true; + ConfigUIModel model = ui.getModel(); + CategoryModel categoryModel = model.getCategoryModel(); + String categoryName = _(categoryModel.getCategory()); + if (!categoryModel.isValid()) { + + // the category is not valid + // get all the invalid options + + StringBuilder buffer = new StringBuilder(); + buffer.append(_("config.message.quit.invalid.category", categoryName)).append('\n'); + for (OptionModel m : categoryModel.getInvalidOptions()) { + buffer.append("\n- ").append(m.getKey()); + } + buffer.append('\n'); + int reponse = askUser(ui, + _("config.title.need.confirm"), + buffer.toString(), + JOptionPane.ERROR_MESSAGE, + new Object[]{ + _("config.choice.continue"), + _("config.choice.cancel")}, + 0); + + switch (reponse) { + case JOptionPane.CLOSED_OPTION: + case 1: + canContinue = false; + break; + case 0: + if (categoryModel.isModified()) { + // wil reset category + model.reset(); + } + break; + } + } else if (categoryModel.isModified()) { + + // category was modified, ask user if wants to save + + StringBuilder buffer = new StringBuilder(); + buffer.append(_("config.message.quit.valid.and.modified.category", categoryName)).append('\n'); + for (OptionModel m : categoryModel.getModifiedOptions()) { + buffer.append("\n- ").append(m.getKey()); + } + buffer.append('\n'); + + int reponse = askUser(ui, + _("config.title.need.confirm"), buffer.toString(), + JOptionPane.WARNING_MESSAGE, + new Object[]{ + _("config.choice.save"), + _("config.choice.doNotSave"), + _("config.choice.cancel")}, + 0); + + switch (reponse) { + case JOptionPane.CLOSED_OPTION: + case 2: + canContinue = false; + break; + case 0: + // will save ui + model.saveModified(); + break; + case 1: + // wil reset ui + model.reset(); + break; + } + + } + return canContinue; + } + + public static int askUser(ConfigUI parent, String title, String message, int typeMessage, Object[] options, int defaultOption) { + + int response = JOptionPane.showOptionDialog(parent, message, title, JOptionPane.DEFAULT_OPTION, typeMessage, null, options, options[defaultOption]); + return response; + } +} Added: trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/CategoryModel.java =================================================================== --- trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/CategoryModel.java (rev 0) +++ trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/CategoryModel.java 2009-07-27 20:27:58 UTC (rev 1511) @@ -0,0 +1,165 @@ +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ +package jaxx.runtime.swing.editor.config.model; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +/** + * le modele d'une categorie d'options. + * + * Une categorie est un ensemble d'options. + * + * @author tchemit + */ +public class CategoryModel implements Iterable<OptionModel> { + + public static final String RELOAD_PROPERTY_NAME = "reload"; + public static final String MODIFIED_PROPERTY_NAME = "modified"; + public static final String VALID_PROPERTY_NAME = "valid"; + /** category short name (i18n key) */ + protected String category; + /** category long name (i18n key) */ + protected String categoryLabel; + /** options of the category */ + protected List<OptionModel> entries; + /** suport of modification */ + protected PropertyChangeSupport pcs = new PropertyChangeSupport(this); + + public CategoryModel(String category, String categoryLabel, OptionModel[] entries) { + super(); + this.category = category; + this.categoryLabel = categoryLabel; + this.entries = Collections.unmodifiableList(Arrays.asList(entries)); + } + + public String getCategory() { + return category; + } + + public String getCategoryLabel() { + return categoryLabel; + } + + public List<OptionModel> getEntries() { + return entries; + } + + public boolean isModified() { + boolean modified = false; + for (OptionModel m : this) { + if (m.isModified()) { + modified = true; + break; + } + } + return modified; + } + + public boolean isValid() { + boolean valid = true; + for (OptionModel m : this) { + if (!m.isValid()) { + valid = false; + break; + } + } + return valid; + } + + public void setValue(OptionModel key, Object val) { + boolean wasModified = isModified(); + boolean wasValid = isValid(); + key.setValue(val); + boolean modified = isModified(); + boolean valid = isValid(); + if (wasModified != modified) { + // change modified state + firePropertyChange(MODIFIED_PROPERTY_NAME, wasModified, modified); + } + if (wasValid != valid) { + // change valid state + firePropertyChange(VALID_PROPERTY_NAME, wasValid, valid); + } + } + + @Override + public Iterator<OptionModel> iterator() { + return entries.iterator(); + } + + public List<OptionModel> getInvalidOptions() { + + List<OptionModel> result = new ArrayList<OptionModel>(); + for (OptionModel m : this) { + if (!m.isValid()) { + result.add(m); + } + } + return result; + } + + public List<OptionModel> getModifiedOptions() { + + List<OptionModel> result = new ArrayList<OptionModel>(); + for (OptionModel m : this) { + if (m.isModified()) { + result.add(m); + } + } + return result; + } + + public void firePropertyChange(String propertyName, Object oldValue, Object newValue) { + pcs.firePropertyChange(propertyName, oldValue, newValue); + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + pcs.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + pcs.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.removePropertyChangeListener(propertyName, listener); + } + + public synchronized boolean hasListeners(String propertyName) { + return pcs.hasListeners(propertyName); + } + + public synchronized PropertyChangeListener[] getPropertyChangeListeners(String propertyName) { + return pcs.getPropertyChangeListeners(propertyName); + } + + public synchronized PropertyChangeListener[] getPropertyChangeListeners() { + return pcs.getPropertyChangeListeners(); + } +} Added: trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/ConfigTableModel.java =================================================================== --- trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/ConfigTableModel.java (rev 0) +++ trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/ConfigTableModel.java 2009-07-27 20:27:58 UTC (rev 1511) @@ -0,0 +1,134 @@ +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ +package jaxx.runtime.swing.editor.config.model; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import javax.swing.table.AbstractTableModel; +import org.nuiton.util.ConverterUtil; + +/** + * le modele du tableau d'options pour une categorie donnee. + * + * Le modele se base sur le modele d'une categorie d'option. + * + * @author tchemit + * + * @see CategoryModel + */ +public class ConfigTableModel extends AbstractTableModel { + + private static final long serialVersionUID = 1L; + private static final Class<?>[] columnClass = {String.class, Object.class, String.class}; + /** le modele d'une categorie */ + protected final CategoryModel categoryModel; + + public ConfigTableModel(CategoryModel categoryModel) { + this.categoryModel = categoryModel; + // listen of property reload of the category model + // to known when to refresh table + this.categoryModel.addPropertyChangeListener(CategoryModel.RELOAD_PROPERTY_NAME, new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + fireTableDataChanged(); + } + }); + } + + public CategoryModel getCategoryModel() { + return categoryModel; + } + + public OptionModel getEntry(int rowIndex) { + return categoryModel.getEntries().get(rowIndex); + } + + @Override + public int getRowCount() { + return categoryModel.getEntries().size(); + } + + @Override + public int getColumnCount() { + return columnClass.length; + } + + @Override + public Class<?> getColumnClass(int columnIndex) { + return columnClass[columnIndex]; + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return columnIndex == 1 && !getEntry(rowIndex).isFinal(); + } + + @Override + public Object getValueAt(int row, int column) { + OptionModel key = getEntry(row); + Object value = null; + switch (column) { + case 0: + value = key.getKey(); + break; + case 1: + value = key.getValue(); + break; + case 2: + value = key.getDefaultValue(); + if (value != null) { + value = ConverterUtil.convert(key.getType(), value); + } + break; + } + return value; +// if (column == 0) { +// return key.getKey(); +// } +// return key.getValue(); + } + + @Override + public void setValueAt(Object aValue, int row, int column) { + if (column != 1) { + // seul la colonne 1 est editable (valeur de l'option) + throw new IllegalArgumentException("can not edit column " + column); + } + OptionModel key = getEntry(row); + Object val; + if (aValue == null || key.getType() == aValue.getClass()) { + val = aValue; + } else { + String valStr = String.valueOf(aValue).trim(); + try { + val = ConverterUtil.convert(key.getType(), valStr); + if (val != null && val instanceof Integer) { + if (new Integer(0).equals(val) && !valStr.equals("0")) { + val = null; + } + } + } catch (Exception e) { + val = null; + } + } + categoryModel.setValue(key, val); + fireTableRowsUpdated(row, row); + } +} Added: trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/ConfigUIModel.java =================================================================== --- trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/ConfigUIModel.java (rev 0) +++ trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/ConfigUIModel.java 2009-07-27 20:27:58 UTC (rev 1511) @@ -0,0 +1,189 @@ +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ +package jaxx.runtime.swing.editor.config.model; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.nuiton.util.ApplicationConfig; +import org.nuiton.util.ApplicationConfig.OptionDef; +import static org.nuiton.i18n.I18n._; + +/** + * Le modele de l'ui des preferences. + * + * Ce modele contient les catégories des options. + * + * @author chemit + */ +public class ConfigUIModel implements Iterable<CategoryModel> { + + public static final String CATEGORY_MODEL_PROPERTY_NAME = "categoryModel"; + /** le dictionnaire des options disponibles par categorie */ + protected final Map<String, CategoryModel> categories; + /** La configuration de l'application */ + protected final ApplicationConfig config; + /** la cateogrie en cours d'utilisation */ + protected CategoryModel categoryModel; + /** suport of modification */ + protected final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + + public ConfigUIModel(ApplicationConfig config) { + this.config = config; + this.categories = new LinkedHashMap<String, CategoryModel>(); + } + + /** + * Ajoute une categorie dans le modele. + * + * @param category l'id de la categorie (la clef de traduction du nom de la categorie) + * @param categoryLabel la clef de traduction de la description de la categorie + * @param keys les options de la categorie + */ + public void addCategory(String category, String categoryLabel, OptionDef... keys) { + if (categories.containsKey(category)) { + throw new IllegalArgumentException(_("config.error.category.already.exists", category)); + } + OptionModel[] entries = new OptionModel[keys.length]; + int index = 0; + for (OptionDef d : keys) { + Object value = config.getOption(d); + OptionModel e = new OptionModel(d, value); + entries[index++] = e; + } + CategoryModel m = new CategoryModel(category, categoryLabel, entries); + categories.put(category, m); + } + + /** + * Change la categorie en cours d'édition. + * + * @param category l'id de la categorie courante + */ + public void setCategory(String category) { + if (!categories.containsKey(category)) { + throw new IllegalArgumentException(_("config.error.category.not.found", category)); + } + CategoryModel newCategoryModel = categories.get(category); + setCategoryModel(newCategoryModel); + newCategoryModel.firePropertyChange(CategoryModel.MODIFIED_PROPERTY_NAME, false, getCategoryModel().isModified()); + newCategoryModel.firePropertyChange(CategoryModel.VALID_PROPERTY_NAME, false, getCategoryModel().isValid()); + } + + @Override + public Iterator<CategoryModel> iterator() { + return categories.values().iterator(); + } + + public CategoryModel getCategoryModel() { + return categoryModel; + } + + public void setCategoryModel(CategoryModel categoryModel) { + CategoryModel old = this.categoryModel; + this.categoryModel = categoryModel; + firePropertyChange(CATEGORY_MODEL_PROPERTY_NAME, old, categoryModel); + } + + public void saveModified() { + // compute transients keys (to never be saved) + List<String> transients = new ArrayList<String>(); + + for (OptionModel option : categoryModel) { + if (option.isModified()) { + Object value = option.getValue(); + //TODO TC-20090245 : should try to seek for a mutator, since + // mutator could have extra code to be done when modify an option + config.setOption(option.getKey(), value == null ? null : value.toString()); + // this is the new original value + option.initValue(value); + } + if (option.isTransient()) { + transients.add(option.getKey()); + } + } + // save config + config.saveForUser(transients.toArray(new String[transients.size()])); + // notify data has changed + categoryModel.firePropertyChange(CategoryModel.MODIFIED_PROPERTY_NAME, categoryModel.isModified(), true); + categoryModel.firePropertyChange(CategoryModel.VALID_PROPERTY_NAME, false, categoryModel.isValid()); + categoryModel.firePropertyChange(CategoryModel.RELOAD_PROPERTY_NAME, false, true); + } + + public void reset() { + // reset all modified options of the current category + for (OptionModel key : categoryModel) { + if (key.isModified()) { + key.initValue(key.getOriginalValue()); + } + } + // notify data has changed + categoryModel.firePropertyChange(CategoryModel.MODIFIED_PROPERTY_NAME, categoryModel.isModified(), true); + categoryModel.firePropertyChange(CategoryModel.VALID_PROPERTY_NAME, false, categoryModel.isValid()); + categoryModel.firePropertyChange(CategoryModel.RELOAD_PROPERTY_NAME, false, true); + } + + public int getCategoryIndex(String category) { + int i = 0; + for (CategoryModel m : this) { + if (category.equals(m.getCategory())) { + return i; + } + i++; + } + // not found + return -1; + } + + public void firePropertyChange(String propertyName, Object oldValue, Object newValue) { + pcs.firePropertyChange(propertyName, oldValue, newValue); + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + pcs.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + pcs.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.removePropertyChangeListener(propertyName, listener); + } + + public synchronized boolean hasListeners(String propertyName) { + return pcs.hasListeners(propertyName); + } + + public synchronized PropertyChangeListener[] getPropertyChangeListeners(String propertyName) { + return pcs.getPropertyChangeListeners(propertyName); + } + + public synchronized PropertyChangeListener[] getPropertyChangeListeners() { + return pcs.getPropertyChangeListeners(); + } +} Added: trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/OptionModel.java =================================================================== --- trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/OptionModel.java (rev 0) +++ trunk/jaxx-runtime-swing-widget/src/main/java/jaxx/runtime/swing/editor/config/model/OptionModel.java 2009-07-27 20:27:58 UTC (rev 1511) @@ -0,0 +1,98 @@ +/** + * *##% jaxx-runtime-swing-widget + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ +package jaxx.runtime.swing.editor.config.model; + +import org.nuiton.util.ApplicationConfig.OptionDef; + +/** + * le modele d'une option de la configuration a editer. + * + * @author tchemit + */ +public class OptionModel implements OptionDef { + + protected final OptionDef def; + protected boolean valid = true; + protected Object originalValue; + protected Object value; + + protected OptionModel(OptionDef def, Object value) { + this.def = def; + initValue(value); + } + + @Override + public String getKey() { + return def.getKey(); + } + + @Override + public Class<?> getType() { + return def.getType(); + } + + @Override + public String getDescription() { + return def.getDescription(); + } + + @Override + public String getDefaultValue() { + return def.getDefaultValue(); + } + + @Override + public boolean isTransient() { + return def.isTransient(); + } + + @Override + public boolean isFinal() { + return def.isFinal(); + } + + public Object getOriginalValue() { + return originalValue; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } + + public boolean isModified() { + return !originalValue.equals(value); + } + + public boolean isValid() { + return valid; + } + + public void setValid(boolean valid) { + this.valid = valid; + } + + public void initValue(Object originalValue) { + this.originalValue = originalValue; + this.value = originalValue; + } +} Added: trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-config-quit.png =================================================================== (Binary files differ) Property changes on: trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-config-quit.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Added: trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-config-reset.png =================================================================== (Binary files differ) Property changes on: trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-config-reset.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Added: trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-config-save.png =================================================================== (Binary files differ) Property changes on: trunk/jaxx-runtime-swing-widget/src/main/resources/icons/action-config-save.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream