Tony CHEMIT pushed to branch develop at ultreiaio / ird-observe Commits: 45aa53d8 by Tony CHEMIT at 2017-08-05T12:36:08+02:00 Review log level - - - - - dbd5e228 by Tony CHEMIT at 2017-08-05T19:27:48+02:00 Mise en place la validation sur les FOB (See #830) - - - - - 29 changed files: - client-validation/src/main/resources/fr/ird/observe/services/dto/seine/FloatingObjectDto-create-error-validation.xml - client-validation/src/main/resources/fr/ird/observe/services/dto/seine/FloatingObjectDto-update-error-validation.xml - client-validation/src/main/resources/i18n/client-validation_en_GB.properties - client-validation/src/main/resources/i18n/client-validation_es_ES.properties - client-validation/src/main/resources/i18n/client-validation_fr_FR.properties - client/pom.xml - client/src/main/java/fr/ird/observe/client/ui/actions/content/CopyFloatingObjectPartToLeftAction.java - client/src/main/java/fr/ird/observe/client/ui/actions/content/CopyFloatingObjectPartToRightAction.java - client/src/main/java/fr/ird/observe/client/ui/content/ContentUIHandler.java - − client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/FloatingObjectPartsTreeNode.java - client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/FloatingObjectUI.jaxx - client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/FloatingObjectUI.jcss - client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/FloatingObjectUIHandler.java - client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/FloatingObjectUIModel.java - + client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/dcp/FloatingObjectPartLegendTreeCellRenderer.java - + client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/dcp/FloatingObjectPartsTableCellEditor.java - + client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/dcp/FloatingObjectPartsTableCellRenderer.java - + client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/dcp/FloatingObjectPartsTreeNode.java - + client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/dcp/FloatingObjectPartsTreeTableModel.java - + client/src/main/java/fr/ird/observe/client/ui/util/treetable/JRadioButtonCellEditor.java - + client/src/main/java/fr/ird/observe/client/ui/util/treetable/JRadioButtonProvider.java - + client/src/main/java/fr/ird/observe/client/ui/util/treetable/JRendererRadioButton.java - persistence/src/main/java/fr/ird/observe/persistence/ObserveTopiaPersistenceContext.java - services/src/main/java/fr/ird/observe/services/decoration/ObserveI18nDecoratorHelper.java - + services/src/main/java/fr/ird/observe/services/dto/referential/seine/ObjectMaterialDto.java - services/src/main/models/Observe.model - services/src/main/resources/i18n/services_en_GB.properties - services/src/main/resources/i18n/services_es_ES.properties - services/src/main/resources/i18n/services_fr_FR.properties Changes: ===================================== client-validation/src/main/resources/fr/ird/observe/services/dto/seine/FloatingObjectDto-create-error-validation.xml ===================================== --- a/client-validation/src/main/resources/fr/ird/observe/services/dto/seine/FloatingObjectDto-create-error-validation.xml +++ b/client-validation/src/main/resources/fr/ird/observe/services/dto/seine/FloatingObjectDto-create-error-validation.xml @@ -82,4 +82,16 @@ </field> + <field name="materialsValid"> + + <!-- erreurs sur les materiaux --> + <field-validator type="fieldexpression"> + <param name="expression"> + <![CDATA[ materialsValid ]]> + </param> + <message>observe.validation.floatingObject.invalid.parts</message> + </field-validator> + + </field> + </validators> ===================================== client-validation/src/main/resources/fr/ird/observe/services/dto/seine/FloatingObjectDto-update-error-validation.xml ===================================== --- a/client-validation/src/main/resources/fr/ird/observe/services/dto/seine/FloatingObjectDto-update-error-validation.xml +++ b/client-validation/src/main/resources/fr/ird/observe/services/dto/seine/FloatingObjectDto-update-error-validation.xml @@ -81,4 +81,16 @@ </field-validator> </field> + <field name="materialsValid"> + + <!-- erreurs sur les materiaux --> + <field-validator type="fieldexpression"> + <param name="expression"> + <![CDATA[ materialsValid ]]> + </param> + <message>observe.validation.floatingObject.invalid.parts</message> + </field-validator> + + </field> + </validators> ===================================== client-validation/src/main/resources/i18n/client-validation_en_GB.properties ===================================== --- a/client-validation/src/main/resources/i18n/client-validation_en_GB.properties +++ b/client-validation/src/main/resources/i18n/client-validation_en_GB.properties @@ -102,6 +102,7 @@ observe.validation.encounter.required.species=Species must be filled. observe.validation.floatingObject.comment.tobig=Comment size can not exceed 1024 characters. observe.validation.floatingObject.desactivated.objectOperation=Selected operation is disabled. observe.validation.floatingObject.desactivated.type=Selected type is disabled. +observe.validation.floatingObject.invalid.parts=There is some errors in materials table. observe.validation.floatingObject.required.comment.for.balise1=A comment is required for the selected buoy. observe.validation.floatingObject.required.comment.for.balise2=A comment is required for the selected buoy. observe.validation.floatingObject.required.comment.for.objectFate=A comment is required for the selected object fate. ===================================== client-validation/src/main/resources/i18n/client-validation_es_ES.properties ===================================== --- a/client-validation/src/main/resources/i18n/client-validation_es_ES.properties +++ b/client-validation/src/main/resources/i18n/client-validation_es_ES.properties @@ -102,6 +102,7 @@ observe.validation.encounter.required.species=La selección de una especie es ma observe.validation.floatingObject.comment.tobig=La longitud del campo de comentarios está limitada a 1024 carácteres. observe.validation.floatingObject.desactivated.objectOperation=Al menos una de las operaciones seleccionadas está desactivada. observe.validation.floatingObject.desactivated.type=El tipo de objeto seleccionado está desactivado. +observe.validation.floatingObject.invalid.parts=There is some errors in materials table. \#TODO observe.validation.floatingObject.required.comment.for.balise1=Se requiere un comentario para la primera baliza (étant donné son type). observe.validation.floatingObject.required.comment.for.balise2=Se requiere un comentario para la segunda baliza (étant donné son type). observe.validation.floatingObject.required.comment.for.objectFate=Se requiere un comentario para el devenir. ===================================== client-validation/src/main/resources/i18n/client-validation_fr_FR.properties ===================================== --- a/client-validation/src/main/resources/i18n/client-validation_fr_FR.properties +++ b/client-validation/src/main/resources/i18n/client-validation_fr_FR.properties @@ -102,6 +102,7 @@ observe.validation.encounter.required.species=La sélection d'une espèce est ob observe.validation.floatingObject.comment.tobig=La taille du commentaire est limitée à 1024 caractères. observe.validation.floatingObject.desactivated.objectOperation=Au moins une des opérations sélectionnée est désactivée. observe.validation.floatingObject.desactivated.type=Le type d'objet sélectionné est désactivé. +observe.validation.floatingObject.invalid.parts=Erreurs détectées sur le tableau des matériaux. observe.validation.floatingObject.required.comment.for.balise1=Un commentaire est requis pour la première balise (étant donné son type). observe.validation.floatingObject.required.comment.for.balise2=Un commentaire est requis pour la seconde balise (étant donné son type). observe.validation.floatingObject.required.comment.for.objectFate=Un commentaire est requis pour le devenir objet. ===================================== client/pom.xml ===================================== --- a/client/pom.xml +++ b/client/pom.xml @@ -588,6 +588,11 @@ <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> + <dependency> + <groupId>org.jetbrains</groupId> + <artifactId>annotations</artifactId> + <version>RELEASE</version> + </dependency> </dependencies> ===================================== client/src/main/java/fr/ird/observe/client/ui/actions/content/CopyFloatingObjectPartToLeftAction.java ===================================== --- a/client/src/main/java/fr/ird/observe/client/ui/actions/content/CopyFloatingObjectPartToLeftAction.java +++ b/client/src/main/java/fr/ird/observe/client/ui/actions/content/CopyFloatingObjectPartToLeftAction.java @@ -25,7 +25,7 @@ package fr.ird.observe.client.ui.actions.content; import fr.ird.observe.client.ui.ObserveKeyStrokes; import fr.ird.observe.client.ui.ObserveMainUI; import fr.ird.observe.client.ui.content.ContentUI; -import fr.ird.observe.client.ui.content.impl.seine.FloatingObjectPartsTreeNode; +import fr.ird.observe.client.ui.content.impl.seine.dcp.FloatingObjectPartsTreeNode; import fr.ird.observe.client.ui.content.impl.seine.FloatingObjectUI; import java.util.Enumeration; import org.apache.commons.logging.Log; ===================================== client/src/main/java/fr/ird/observe/client/ui/actions/content/CopyFloatingObjectPartToRightAction.java ===================================== --- a/client/src/main/java/fr/ird/observe/client/ui/actions/content/CopyFloatingObjectPartToRightAction.java +++ b/client/src/main/java/fr/ird/observe/client/ui/actions/content/CopyFloatingObjectPartToRightAction.java @@ -25,7 +25,7 @@ package fr.ird.observe.client.ui.actions.content; import fr.ird.observe.client.ui.ObserveKeyStrokes; import fr.ird.observe.client.ui.ObserveMainUI; import fr.ird.observe.client.ui.content.ContentUI; -import fr.ird.observe.client.ui.content.impl.seine.FloatingObjectPartsTreeNode; +import fr.ird.observe.client.ui.content.impl.seine.dcp.FloatingObjectPartsTreeNode; import fr.ird.observe.client.ui.content.impl.seine.FloatingObjectUI; import java.util.Enumeration; import org.apache.commons.logging.Log; ===================================== client/src/main/java/fr/ird/observe/client/ui/content/ContentUIHandler.java ===================================== --- a/client/src/main/java/fr/ird/observe/client/ui/content/ContentUIHandler.java +++ b/client/src/main/java/fr/ird/observe/client/ui/content/ContentUIHandler.java @@ -563,9 +563,7 @@ public abstract class ContentUIHandler<E extends IdDto, U extends ContentUI<E, U NavigationTreeNodeSupport parentNode = treeHelper.getSelectedNode(); String id = entity.getId(); NavigationTreeNodeSupport node = treeHelper.getChild(parentNode, id); - if (log.isInfoEnabled()) { - log.info("will go to node " + node + " for " + id); - } + log.debug("will go to node " + node + " for " + id); treeHelper.selectNode(node); } @@ -602,7 +600,7 @@ public abstract class ContentUIHandler<E extends IdDto, U extends ContentUI<E, U ImmutableMap.Builder<String, ReferentialReferenceSet<?>> modelReferentialReferenceSets = ImmutableMap.builder(); - log.info("Update referential reference sets for: " + requestName); + log.debug("Update referential reference sets for: " + requestName); // mettre à jour le cache de référentiel ImmutableMap<Class<?>, ReferentialReferenceSet<?>> referentialReferenceSetsByType = getDataSource().updateReferentialReferenceSetsCache(requestName); ===================================== client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/FloatingObjectPartsTreeNode.java deleted ===================================== --- a/client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/FloatingObjectPartsTreeNode.java +++ /dev/null @@ -1,105 +0,0 @@ -package fr.ird.observe.client.ui.content.impl.seine; - -/*- - * #%L - * ObServe :: Client - * %% - * Copyright (C) 2008 - 2017 IRD, Code Lutin, Ultreia.io - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 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 Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -import fr.ird.observe.services.dto.referential.seine.ObjectMaterialDto; -import fr.ird.observe.services.dto.seine.ObjectMaterialHierarchyDto; -import java.util.Iterator; -import org.jdesktop.swingx.treetable.AbstractMutableTreeTableNode; -import org.nuiton.decorator.Decorator; - -/** - * Created by tchemit on 30/05/17. - * - * @author Tony Chemit - dev@tchemit.fr - */ -public class FloatingObjectPartsTreeNode extends AbstractMutableTreeTableNode implements Iterable<FloatingObjectPartsTreeNode> { - - private final FloatingObjectUIModel model; - private final Decorator<ObjectMaterialDto> decorator; - - FloatingObjectPartsTreeNode(Decorator<ObjectMaterialDto> decorator, FloatingObjectUIModel model, ObjectMaterialHierarchyDto userObject) { - super(userObject); - this.decorator = decorator; - this.model = model; - userObject.getChildren().forEach(u -> add(new FloatingObjectPartsTreeNode(decorator, model, u))); - } - - @Override - public ObjectMaterialHierarchyDto getUserObject() { - return (ObjectMaterialHierarchyDto) super.getUserObject(); - } - - @Override - public Object getValueAt(int column) { - switch (column) { - case 0: // label - return decorator.toString(getUserObject()); - case 1: // when arriving - return model.getWhenArriving().get(getUserObject()); - case 2: // when leaving - return model.getWhenLeaving().get(getUserObject()); - - - } - return null; - } - - @Override - public void setValueAt(Object aValue, int column) { - switch (column) { - case 1: // when arriving - model.setWhenArriving(getUserObject().getId(), aValue == null ? null : String.valueOf(aValue)); - break; - case 2: // when leaving - model.setWhenLeaving(getUserObject().getId(), aValue == null ? null : String.valueOf(aValue)); - break; - } - } - - @Override - public boolean isEditable(int column) { - boolean result = column > 0 && getUserObject().isSelectable(); - if (result) { - switch (column) { - case 1: // when arriving - result = model.isArriving(); - break; - case 2: // when leaving - result = model.isLeaving(); - break; - } - } - return result; - } - - @Override - public int getColumnCount() { - return 3; - } - - @Override - public Iterator<FloatingObjectPartsTreeNode> iterator() { - return (Iterator) children.iterator(); - } -} ===================================== client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/FloatingObjectUI.jaxx ===================================== --- a/client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/FloatingObjectUI.jaxx +++ b/client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/FloatingObjectUI.jaxx @@ -38,6 +38,8 @@ fr.ird.observe.client.ui.actions.global.DeleteDataGlobalUIAction fr.ird.observe.client.ui.actions.global.ResetDataGlobalUIAction fr.ird.observe.client.ui.actions.global.SaveDataGlobalUIAction + fr.ird.observe.client.ui.content.impl.seine.dcp.FloatingObjectPartsTreeTableModel + fr.ird.observe.client.ui.content.impl.seine.dcp.FloatingObjectPartLegendTreeCellRenderer fr.ird.observe.client.ui.util.JComment org.jdesktop.swingx.JXTreeTable @@ -46,6 +48,7 @@ org.nuiton.jaxx.widgets.select.BeanComboBox java.awt.Dimension + javax.swing.ListSelectionModel static fr.ird.observe.client.ui.UIHelper.getStringValue static org.nuiton.i18n.I18n.n @@ -61,7 +64,9 @@ <!-- validator --> <BeanValidator id='validator' autoField='true' context='create' errorTableModel='{getErrorTableModel()}' - beanClass='fr.ird.observe.services.dto.seine.FloatingObjectDto'/> + beanClass='fr.ird.observe.services.dto.seine.FloatingObjectDto'> + <field name="materialsValid" component="tableScroll"/> + </BeanValidator> <!-- formulaire --> <JPanel id="body" layout='{new BorderLayout()}'> ===================================== client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/FloatingObjectUI.jcss ===================================== --- a/client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/FloatingObjectUI.jcss +++ b/client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/FloatingObjectUI.jcss @@ -168,3 +168,9 @@ BeanComboBox { focusable:false; } +#table { + treeTableModel:{new FloatingObjectPartsTreeTableModel(getModel())}; + treeCellRenderer:{new FloatingObjectPartLegendTreeCellRenderer()}; + selectionMode:{ListSelectionModel.SINGLE_SELECTION}; +} + ===================================== client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/FloatingObjectUIHandler.java ===================================== --- a/client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/FloatingObjectUIHandler.java +++ b/client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/FloatingObjectUIHandler.java @@ -29,6 +29,10 @@ import fr.ird.observe.client.db.constants.DataContextType; import fr.ird.observe.client.ui.content.ContentMode; import fr.ird.observe.client.ui.content.ContentUIHandler; import fr.ird.observe.client.ui.content.ContentUIModel; +import fr.ird.observe.client.ui.content.impl.seine.dcp.FloatingObjectPartsTableCellEditor; +import fr.ird.observe.client.ui.content.impl.seine.dcp.FloatingObjectPartsTableCellRenderer; +import fr.ird.observe.client.ui.content.impl.seine.dcp.FloatingObjectPartsTreeNode; +import fr.ird.observe.client.ui.content.impl.seine.dcp.FloatingObjectPartsTreeTableModel; import fr.ird.observe.client.ui.tree.navigation.NavigationTree; import fr.ird.observe.client.ui.tree.navigation.nodes.NavigationTreeNodeSupport; import fr.ird.observe.services.dto.FloatingObjectReference; @@ -44,9 +48,7 @@ import fr.ird.observe.services.dto.seine.FloatingObjectHelper; import fr.ird.observe.services.dto.seine.FloatingObjectPartDto; import fr.ird.observe.services.dto.seine.ObjectMaterialHierarchyDto; import fr.ird.observe.services.service.data.seine.FloatingObjectService; -import java.awt.Component; -import java.util.Arrays; -import java.util.EventObject; +import java.awt.Color; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -55,25 +57,17 @@ import java.util.Optional; import java.util.Set; import java.util.TreeMap; import javax.swing.Icon; -import javax.swing.JTable; -import javax.swing.JTree; import javax.swing.SwingUtilities; -import javax.swing.event.CellEditorListener; import javax.swing.event.TableModelListener; import javax.swing.event.TreeModelEvent; -import javax.swing.table.TableCellEditor; -import javax.swing.table.TableCellRenderer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.log4j.lf5.viewer.categoryexplorer.TreeModelAdapter; import org.jdesktop.swingx.JXTable; import org.jdesktop.swingx.JXTreeTable; +import org.jdesktop.swingx.decorator.ColorHighlighter; import org.jdesktop.swingx.table.ColumnFactory; import org.jdesktop.swingx.table.TableColumnExt; -import org.jdesktop.swingx.tree.DefaultXTreeCellRenderer; -import org.jdesktop.swingx.treetable.DefaultMutableTreeTableNode; -import org.jdesktop.swingx.treetable.DefaultTreeTableModel; -import org.nuiton.decorator.Decorator; import org.nuiton.jaxx.runtime.spi.UIHandler; import org.nuiton.jaxx.runtime.swing.SwingUtil; import org.nuiton.jaxx.validator.swing.SwingValidatorMessage; @@ -219,13 +213,16 @@ public class FloatingObjectUIHandler extends ContentUIHandler<FloatingObjectDto, String objectMaterialId = (String) p.getPropertyValue(FloatingObjectPartDto.PROPERTY_OBJECT_MATERIAL + "Id"); String whenArriving = (String) p.getPropertyValue(FloatingObjectPartDto.PROPERTY_WHEN_ARRIVING); String whenLeaving = (String) p.getPropertyValue(FloatingObjectPartDto.PROPERTY_WHEN_LEAVING); - model.setWhenArriving(objectMaterialId, whenArriving); - model.setWhenLeaving(objectMaterialId, whenLeaving); + if (whenArriving != null && !Objects.equals("false", whenArriving)) { + model.setWhenArriving(objectMaterialId, whenArriving); + } + if (whenLeaving != null && !Objects.equals("false", whenLeaving)) { + model.setWhenLeaving(objectMaterialId, whenLeaving); + } } - DefaultTreeTableModel treeTableModel = (DefaultTreeTableModel) table.getTreeTableModel(); - // force to reload model - treeTableModel.setRoot(treeTableModel.getRoot()); + FloatingObjectPartsTreeTableModel treeTableModel = (FloatingObjectPartsTreeTableModel) table.getTreeTableModel(); + treeTableModel.reset(); table.expandAll(); } @@ -373,42 +370,8 @@ public class FloatingObjectUIHandler extends ContentUIHandler<FloatingObjectDto, private void initTable(List<ObjectMaterialHierarchyDto> materials, JXTreeTable table) { - DefaultMutableTreeTableNode root = getModel().createRoot(getDecoratorService().getDecoratorByType(ObjectMaterialDto.class), materials); - DefaultTreeTableModel treeModel = new DefaultTreeTableModel(root, Arrays.asList( - t("observe.content.floatingObject.table.type"), - t("observe.common.whenArriving"), - t("observe.common.whenLeaving"))) { - - @Override - public int getColumnCount() { - return 3; - } - - @Override - public Class<?> getColumnClass(int column) { - switch (column) { - case 0: - return String.class; - case 1: - case 2: - return Object.class; - - } - throw new IllegalStateException(); - } - - @Override - public boolean isCellEditable(Object node, int column) { - if (node instanceof FloatingObjectPartsTreeNode) { - boolean rowEnabled = ((FloatingObjectPartsTreeNode) node).getUserObject().isEnabled(); - if (!rowEnabled) { - return false; - } - } - return super.isCellEditable(node, column); - } - }; - table.setTreeTableModel(treeModel); + FloatingObjectPartsTreeTableModel treeModel = (FloatingObjectPartsTreeTableModel) table.getTreeTableModel(); + treeModel.rebuildRootNode(materials); table.setColumnFactory(new ColumnFactory() { @@ -431,29 +394,26 @@ public class FloatingObjectUIHandler extends ContentUIHandler<FloatingObjectDto, } }); - DefaultXTreeCellRenderer cellRenderer = new DefaultXTreeCellRenderer() { - Decorator<ObjectMaterialDto> decorator = getDecoratorService().getDecoratorByType(ObjectMaterialDto.class); - - @Override - public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { - if (!(value instanceof FloatingObjectPartsTreeNode)) { - return super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); - } - FloatingObjectPartsTreeNode node = (FloatingObjectPartsTreeNode) value; - Component result = super.getTreeCellRendererComponent(tree, decorator.toString(node.getUserObject()), sel, expanded, leaf, row, hasFocus); - result.setEnabled(node.getUserObject().isEnabled()); - return result; + table.setDefaultRenderer(Object.class, new FloatingObjectPartsTableCellRenderer(table)); + table.setDefaultEditor(Object.class, new FloatingObjectPartsTableCellEditor(table)); + table.addHighlighter(new ColorHighlighter((renderer, adapter) -> { + JXTreeTable component = (JXTreeTable) adapter.getComponent(); + int row = adapter.convertRowIndexToModel(adapter.row); + FloatingObjectPartsTreeNode node = (FloatingObjectPartsTreeNode) component.getPathForRow(row).getLastPathComponent(); + boolean valid1 = node.isValid(1); + boolean valid2 = node.isValid(2); + boolean valid = valid1 && valid2; + switch (adapter.convertRowIndexToModel(adapter.column)) { + case 0: + return !valid; + case 1: + return !valid1; + case 2: + return !valid2; } - }; - - cellRenderer.setLeafIcon(null); - cellRenderer.setOpenIcon(null); - cellRenderer.setClosedIcon(null); - table.setTreeCellRenderer(cellRenderer); - TableCellRenderer defaultRenderer = new MyRenderer(table.getDefaultRenderer(Boolean.class), table.getDefaultRenderer(String.class)); - table.setDefaultRenderer(Object.class, defaultRenderer); - table.setDefaultEditor(Object.class, new MyTableCellEditor(table.getDefaultEditor(Boolean.class), table.getDefaultEditor(String.class))); + return true; + }, Color.RED, Color.WHITE)); } private FloatingObjectService getFloatingObjectService() { @@ -486,117 +446,4 @@ public class FloatingObjectUIHandler extends ContentUIHandler<FloatingObjectDto, return (FloatingObjectUIModel) super.getModel(); } - private static class MyRenderer implements TableCellRenderer { - - private final TableCellRenderer editableRenderer; - - private final TableCellRenderer notEditableRenderer; - - private MyRenderer(TableCellRenderer editableRenderer, TableCellRenderer notEditableRenderer) { - this.editableRenderer = editableRenderer; - this.notEditableRenderer = notEditableRenderer; - } - - @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - FloatingObjectPartsTreeNode node = (FloatingObjectPartsTreeNode) ((JXTreeTable) table).getPathForRow(row).getLastPathComponent(); - Objects.requireNonNull(node); - TableCellRenderer renderer = notEditableRenderer; - Object newValue = value; - boolean enabled = true; - if (node.getUserObject().getObjectMaterialType() != null && (!node.getUserObject().isEnabled() || table.isCellEditable(row, column))) { - String objectMaterialType = node.getUserObject().getObjectMaterialType().getId(); - if ("fr.ird.observe.entities.referentiel.seine.ObjectMaterialType#0#0".equals(objectMaterialType)) { - newValue = value == null ? null : Boolean.valueOf(String.valueOf(value)); - renderer = editableRenderer; - } - enabled = node.getUserObject().isEnabled(); - } else { - newValue = ""; - } - - Component component = renderer.getTableCellRendererComponent(table, newValue, isSelected, hasFocus, row, column); - component.setEnabled(enabled); - return component; - } - } - - private static class MyTableCellEditor implements TableCellEditor { - - - private final TableCellEditor booleanEditor; - private final TableCellEditor stringEditor; - - TableCellEditor editor = null; - - MyTableCellEditor(TableCellEditor booleanEditor, TableCellEditor StringEditor) { - this.booleanEditor = booleanEditor; - stringEditor = StringEditor; - } - - @Override - public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { - FloatingObjectPartsTreeNode node = (FloatingObjectPartsTreeNode) ((JXTreeTable) table).getPathForRow(row).getLastPathComponent(); - String objectMaterialType = node.getUserObject().getObjectMaterialType().getId(); - - switch (objectMaterialType) { - case "fr.ird.observe.entities.referentiel.seine.ObjectMaterialType#0#0": //boolean - editor = booleanEditor; - break; - case "fr.ird.observe.entities.referentiel.seine.ObjectMaterialType#0#1": // decimal one digit - editor = stringEditor; - break; - case "fr.ird.observe.entities.referentiel.seine.ObjectMaterialType#0#2": // integer - editor = stringEditor; - break; - case "fr.ird.observe.entities.referentiel.seine.ObjectMaterialType#0#3": // string - editor = stringEditor; - break; - default: - throw new IllegalStateException("Can't manage type: " + objectMaterialType); - - } - return editor.getTableCellEditorComponent(table, value, isSelected, row, column); - } - - @Override - public Object getCellEditorValue() { - Object o = editor == null ? null : editor.getCellEditorValue(); - return o == null ? null : String.valueOf(o); - } - - @Override - public boolean isCellEditable(EventObject anEvent) { - return stringEditor.isCellEditable(anEvent) || booleanEditor.isCellEditable(anEvent); - } - - @Override - public boolean shouldSelectCell(EventObject anEvent) { - return true; - } - - @Override - public boolean stopCellEditing() { - return editor != null && editor.stopCellEditing(); - } - - @Override - public void cancelCellEditing() { - if (editor != null) { - editor.cancelCellEditing(); - } - } - - @Override - public void addCellEditorListener(CellEditorListener l) { - stringEditor.addCellEditorListener(l); - booleanEditor.addCellEditorListener(l); - } - - @Override - public void removeCellEditorListener(CellEditorListener l) { - stringEditor.removeCellEditorListener(l); - booleanEditor.removeCellEditorListener(l); - } - } } ===================================== client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/FloatingObjectUIModel.java ===================================== --- a/client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/FloatingObjectUIModel.java +++ b/client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/FloatingObjectUIModel.java @@ -33,17 +33,14 @@ import fr.ird.observe.services.dto.constants.ReferentialLocale; import fr.ird.observe.services.dto.referential.seine.ObjectMaterialDto; import fr.ird.observe.services.dto.seine.FloatingObjectDto; import fr.ird.observe.services.dto.seine.FloatingObjectPartDto; -import fr.ird.observe.services.dto.seine.ObjectMaterialHierarchyDto; import java.util.LinkedHashMap; import java.util.LinkedHashSet; -import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.jdesktop.swingx.treetable.DefaultMutableTreeTableNode; -import org.nuiton.decorator.Decorator; import static org.nuiton.i18n.I18n.t; @@ -52,12 +49,18 @@ import static org.nuiton.i18n.I18n.t; * Created on 9/28/14. * * @author Tony Chemit - dev@tchemit.fr - * @since XXX + * @since 3.0 */ public class FloatingObjectUIModel extends ContentUIModel<FloatingObjectDto> { private static final long serialVersionUID = 1L; + static final String PROPERTY_PARTS_MODIFIED = "partsModified"; + public static final String PROPERTY_GENERAL_TAB_VALID = "generalTabValid"; + private static final String PROPERTY_MATERIALS_TAB_VALID = "materialsTabValid"; + static final String PROPERTY_REFERENCE = "reference"; + private static final String PROPERTY_ARRIVING = "arriving"; + private static final String PROPERTY_LEAVING = "leaving"; private final ReferenceBinderEngine referenceBinderEngine; private final ReferentialLocale referentialLocale; @@ -67,6 +70,7 @@ public class FloatingObjectUIModel extends ContentUIModel<FloatingObjectDto> { private boolean arriving; private boolean leaving; + public FloatingObjectUIModel() { super(FloatingObjectDto.class); @@ -77,20 +81,13 @@ public class FloatingObjectUIModel extends ContentUIModel<FloatingObjectDto> { this.whenLeaving = new LinkedHashMap<>(); } - public static final String PROPERTY_GENERAL_TAB_VALID = "generalTabValid"; - - private static final String PROPERTY_MATERIALS_TAB_VALID = "materialsTabValid"; - static final String PROPERTY_REFERENCE = "reference"; - private static final String PROPERTY_ARRIVING = "arriving"; - private static final String PROPERTY_LEAVING = "leaving"; - public static final Set<String> GENERAL_TAB_PROPERTIES = ImmutableSet.<String>builder().add(FloatingObjectDto.PROPERTY_OBJECT_OPERATION, FloatingObjectDto.PROPERTY_SUPPORT_VESSEL_NAME, FloatingObjectDto.PROPERTY_COMMENT).build(); static final Set<String> MATERIALS_TAB_PROPERTIES = - ImmutableSet.<String>builder().add(FloatingObjectDto.PROPERTY_COMMENT).build(); + ImmutableSet.<String>builder().add(FloatingObjectDto.PROPERTY_COMMENT, FloatingObjectDto.PROPERTY_MATERIALS_VALID).build(); protected boolean generalTabValid; private boolean materialsTabValid; @@ -141,6 +138,7 @@ public class FloatingObjectUIModel extends ContentUIModel<FloatingObjectDto> { public void reset() { whenArriving.clear(); whenLeaving.clear(); + getBean().setMaterialsValid(true); fireComputedValuesChanged(); } @@ -162,39 +160,27 @@ public class FloatingObjectUIModel extends ContentUIModel<FloatingObjectDto> { } public Set<ObjectMaterialDto> getAll() { - Set<ObjectMaterialDto> alls = new LinkedHashSet<>(whenArriving.keySet()); - alls.addAll(whenLeaving.keySet()); - return alls; + Set<ObjectMaterialDto> all = new LinkedHashSet<>(whenArriving.keySet()); + all.addAll(whenLeaving.keySet()); + return all; } void setReferentialMap(Map<String, ObjectMaterialDto> referentialMap) { this.referentialMap = referentialMap; } - void setWhenArriving(String id, String value) { + public void setWhenArriving(String id, String value) { ObjectMaterialDto dto = referentialMap.get(id); - if (dto == null) { - return; - } + Objects.requireNonNull(dto); whenArriving.put(dto, value); } - void setWhenLeaving(String id, String value) { + public void setWhenLeaving(String id, String value) { ObjectMaterialDto dto = referentialMap.get(id); - if (dto == null) { - return; - } + Objects.requireNonNull(dto); whenLeaving.put(dto, value); } - DefaultMutableTreeTableNode createRoot(Decorator<ObjectMaterialDto> decoratorByType, List<ObjectMaterialHierarchyDto> referential) { - DefaultMutableTreeTableNode root = new DefaultMutableTreeTableNode(); - for (ObjectMaterialHierarchyDto dto : referential) { - root.add(new FloatingObjectPartsTreeNode(decoratorByType, this, dto)); - } - return root; - } - public Optional<FloatingObjectReference> getReference() { return Optional.ofNullable(reference); } @@ -273,4 +259,5 @@ public class FloatingObjectUIModel extends ContentUIModel<FloatingObjectDto> { bean.setComputedWhenLeavingSimplifiedObjectType(null); fireComputedValuesChanged(); } + } ===================================== client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/dcp/FloatingObjectPartLegendTreeCellRenderer.java ===================================== --- /dev/null +++ b/client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/dcp/FloatingObjectPartLegendTreeCellRenderer.java @@ -0,0 +1,64 @@ +package fr.ird.observe.client.ui.content.impl.seine.dcp; + +/*- + * #%L + * ObServe :: Client + * %% + * Copyright (C) 2008 - 2017 IRD, Code Lutin, Ultreia.io + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 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 Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +import fr.ird.observe.client.ObserveSwingApplicationContext; +import fr.ird.observe.services.dto.referential.seine.ObjectMaterialDto; +import java.awt.Component; +import javax.swing.JTree; +import org.jdesktop.swingx.tree.DefaultXTreeCellRenderer; +import org.nuiton.decorator.Decorator; + +/** + * Created by tchemit on 05/08/17. + * + * @author Tony Chemit - dev@tchemit.fr + * @since 7.0 + */ +public class FloatingObjectPartLegendTreeCellRenderer extends DefaultXTreeCellRenderer { + + private Decorator<ObjectMaterialDto> decorator; + + public FloatingObjectPartLegendTreeCellRenderer() { + super(); + setLeafIcon(null); + setOpenIcon(null); + setClosedIcon(null); + } + + @Override + public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { + FloatingObjectPartsTreeNode node = (FloatingObjectPartsTreeNode) value; + Component result = super.getTreeCellRendererComponent(tree, getDecorator().toString(node.getValueAt(0)), sel, expanded, leaf, row, hasFocus); + result.setEnabled(node.isEnabled()); + return result; + } + + private Decorator<ObjectMaterialDto> getDecorator() { + if (decorator == null) { + decorator = ObserveSwingApplicationContext.get().getDecoratorService().getDecoratorByType(ObjectMaterialDto.class); + } + return decorator; + } + +} ===================================== client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/dcp/FloatingObjectPartsTableCellEditor.java ===================================== --- /dev/null +++ b/client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/dcp/FloatingObjectPartsTableCellEditor.java @@ -0,0 +1,140 @@ +package fr.ird.observe.client.ui.content.impl.seine.dcp; + +/*- + * #%L + * ObServe :: Client + * %% + * Copyright (C) 2008 - 2017 IRD, Code Lutin, Ultreia.io + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 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 Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +import com.google.common.collect.ImmutableSet; +import fr.ird.observe.client.ui.UIHelper; +import fr.ird.observe.client.ui.util.treetable.JRadioButtonCellEditor; +import java.awt.Component; +import java.util.EventObject; +import java.util.Objects; +import javax.swing.JTable; +import javax.swing.event.CellEditorListener; +import javax.swing.table.TableCellEditor; +import org.jdesktop.swingx.JXTreeTable; +import org.nuiton.jaxx.widgets.number.NumberCellEditor; + +/** + * Created by tchemit on 05/08/17. + * + * @author Tony Chemit - dev@tchemit.fr + * @since 7.0 + */ +public class FloatingObjectPartsTableCellEditor implements TableCellEditor { + + private final TableCellEditor booleanEditor; + private final TableCellEditor stringEditor; + private final TableCellEditor radioEditor; + private final TableCellEditor intEditor; + private final TableCellEditor floatEditor; + private TableCellEditor editor; + + private final ImmutableSet<TableCellEditor> editors; + + public FloatingObjectPartsTableCellEditor(JXTreeTable table) { + // register as a default editors to get correct integration with ui + table.setDefaultEditor(boolean.class, new JRadioButtonCellEditor()); + table.setDefaultEditor(int.class, new IntegerCellEditor()); + table.setDefaultEditor(float.class, new FloatCellEditor()); + + ImmutableSet.Builder<TableCellEditor> editorBuilder = ImmutableSet.builder(); + + editorBuilder.add(this.booleanEditor = table.getDefaultEditor(Boolean.class)); + editorBuilder.add(this.stringEditor = table.getDefaultEditor(Object.class)); + editorBuilder.add(this.radioEditor = table.getDefaultEditor(boolean.class)); + editorBuilder.add(this.intEditor = table.getDefaultEditor(int.class)); + editorBuilder.add(this.floatEditor = table.getDefaultEditor(float.class)); + this.editors = editorBuilder.build(); + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + FloatingObjectPartsTreeNode node = (FloatingObjectPartsTreeNode) ((JXTreeTable) table).getPathForRow(row).getLastPathComponent(); + + if (node.isBoolean()) { + editor = node.isExclusive() ? radioEditor : booleanEditor; + } else if (node.isText()) { + editor = stringEditor; + } else if (node.isFloat()) { + editor = floatEditor; + } else if (node.isInteger()) { + editor = intEditor; + } else { + throw new IllegalStateException("Can't manage type: " + node.getObjectMaterialType()); + } + return editor.getTableCellEditorComponent(table, value, isSelected, row, column); + } + + @Override + public Object getCellEditorValue() { + Object o = editor == null ? null : editor.getCellEditorValue(); + return o == null ? null : Objects.equals(false, o) ? null : String.valueOf(o); + } + + @Override + public boolean isCellEditable(EventObject anEvent) { + return editors.stream().anyMatch(e -> e.isCellEditable(anEvent)); + } + + @Override + public boolean shouldSelectCell(EventObject anEvent) { + return true; + } + + @Override + public boolean stopCellEditing() { + return editor != null && editor.stopCellEditing(); + } + + @Override + public void cancelCellEditing() { + if (editor != null) { + editor.cancelCellEditing(); + } + } + + @Override + public void addCellEditorListener(CellEditorListener l) { + editors.forEach(e -> e.addCellEditorListener(l)); + } + + @Override + public void removeCellEditorListener(CellEditorListener l) { + editors.forEach(e -> e.removeCellEditorListener(l)); + } + + private static class IntegerCellEditor extends NumberCellEditor<Integer> { + IntegerCellEditor() { + super(Integer.class, false); + numberEditor.setNumberPattern(UIHelper.INT_6_DIGITS_PATTERN); + } + } + + private static class FloatCellEditor extends NumberCellEditor<Float> { + FloatCellEditor() { + super(Float.class, false); + numberEditor.setNumberPattern(UIHelper.DECIMAL1_PATTERN); + } + } + +} ===================================== client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/dcp/FloatingObjectPartsTableCellRenderer.java ===================================== --- /dev/null +++ b/client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/dcp/FloatingObjectPartsTableCellRenderer.java @@ -0,0 +1,78 @@ +package fr.ird.observe.client.ui.content.impl.seine.dcp; + +/*- + * #%L + * ObServe :: Client + * %% + * Copyright (C) 2008 - 2017 IRD, Code Lutin, Ultreia.io + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 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 Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +import fr.ird.observe.client.ui.util.treetable.JRadioButtonProvider; +import fr.ird.observe.services.dto.seine.ObjectMaterialHierarchyDto; +import java.awt.Component; +import java.util.Objects; +import javax.swing.JTable; +import javax.swing.table.TableCellRenderer; +import org.jdesktop.swingx.JXTreeTable; +import org.jdesktop.swingx.renderer.DefaultTableRenderer; + +/** + * Created by tchemit on 05/08/17. + * + * @author Tony Chemit - dev@tchemit.fr + * @since 7.0 + */ +public class FloatingObjectPartsTableCellRenderer implements TableCellRenderer { + + // Render booleans (inclusive) + private final TableCellRenderer booleanInclusiveRenderer; + // Render booleans (exclusive) + private final TableCellRenderer booleanExclusiveRenderer; + // Render anything else + private final TableCellRenderer objectRenderer; + + public FloatingObjectPartsTableCellRenderer(JXTreeTable table) { + // register as a default renderer to get correct integration with ui + table.setDefaultRenderer(boolean.class, new DefaultTableRenderer(new JRadioButtonProvider())); + this.booleanInclusiveRenderer = table.getDefaultRenderer(Boolean.class); + this.objectRenderer = table.getDefaultRenderer(Object.class); + this.booleanExclusiveRenderer = table.getDefaultRenderer(boolean.class); + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + FloatingObjectPartsTreeNode node = (FloatingObjectPartsTreeNode) ((JXTreeTable) table).getPathForRow(row).getLastPathComponent(); + Objects.requireNonNull(node); + TableCellRenderer renderer = objectRenderer; + Object newValue = value; + boolean enabled = true; + if (node.isEditable() && table.isCellEditable(row, column)) { + if (node.isBoolean()) { + newValue = value == null ? null : Boolean.valueOf(String.valueOf(value)); + renderer = node.isExclusive() ? booleanExclusiveRenderer : booleanInclusiveRenderer; + } + enabled = node.isEnabled(); + } else { + newValue = ""; + } + + Component component = renderer.getTableCellRendererComponent(table, newValue, isSelected, hasFocus, row, column); + component.setEnabled(enabled); + return component; + } +} ===================================== client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/dcp/FloatingObjectPartsTreeNode.java ===================================== --- /dev/null +++ b/client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/dcp/FloatingObjectPartsTreeNode.java @@ -0,0 +1,361 @@ +package fr.ird.observe.client.ui.content.impl.seine.dcp; + +/*- + * #%L + * ObServe :: Client + * %% + * Copyright (C) 2008 - 2017 IRD, Code Lutin, Ultreia.io + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 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 Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +import com.google.common.collect.ImmutableSet; +import fr.ird.observe.client.ui.content.impl.seine.FloatingObjectUIModel; +import fr.ird.observe.services.dto.reference.ReferentialReference; +import fr.ird.observe.services.dto.referential.seine.ObjectMaterialTypeDto; +import fr.ird.observe.services.dto.seine.ObjectMaterialHierarchyDto; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.jdesktop.swingx.treetable.AbstractMutableTreeTableNode; +import org.jetbrains.annotations.NotNull; + +/** + * Created by tchemit on 30/05/17. + * + * @author Tony Chemit - dev@tchemit.fr + */ +public class FloatingObjectPartsTreeNode extends AbstractMutableTreeTableNode implements Iterable<FloatingObjectPartsTreeNode> { + + /** Logger. */ + private static final Log log = LogFactory.getLog(FloatingObjectPartsTreeNode.class); + + static FloatingObjectPartsTreeNode createRoot(FloatingObjectUIModel model, List<ObjectMaterialHierarchyDto> referential) { + FloatingObjectPartsTreeNodeContext rootModel = new FloatingObjectPartsTreeNodeContext(model); + FloatingObjectPartsTreeNode root = new FloatingObjectPartsTreeNode(rootModel); + if (referential != null) { + for (ObjectMaterialHierarchyDto dto : referential) { + FloatingObjectPartsTreeNodeContext childModel = new FloatingObjectPartsTreeNodeContext(dto, rootModel); + FloatingObjectPartsTreeNode node = new FloatingObjectPartsTreeNode(childModel); + root.add(node); + ImmutableSet.Builder<FloatingObjectPartsTreeNode> companionsBuilder = dto.isChildrenMultiSelectable() ? ImmutableSet.builder() : null; + node.computeCompanions(companionsBuilder); + node.setCompanions(companionsBuilder); + } + } + return root; + } + + boolean isNotValid() { + return !(getUserObject().validWhenArriving && getUserObject().validWhenLeaving); + } + + private static class FloatingObjectPartsTreeNodeContext { + + // main model to get and store values + private final FloatingObjectUIModel uiModel; + // dto (null for root) + private final ObjectMaterialHierarchyDto dto; + // Is the node is enabled (hierarchic value) ? + private final boolean enabled; + // Is this node editable ? + private final boolean editable; + // Is this node need at least one child selected ? + private final boolean needOneSelection; + // Is this node in the path of at least one mandatory child ancestor ? + private final boolean mandatory; + // Is the node is exclusive (means only one value possible for him and his brothers) ? + private final boolean exclusive; + // Is the node valid for whenArriving column ? + private boolean validWhenArriving = true; + // Is the node valid for whenLeaving column ? + private boolean validWhenLeaving = true; + // Set of brothers of this node that is in a exclusive group of node (only one value among all of them) + private ImmutableSet<FloatingObjectPartsTreeNode> companions; + // Internal to store debug node text + private String text; + + FloatingObjectPartsTreeNodeContext(FloatingObjectUIModel uiModel) { + Objects.requireNonNull(uiModel); + this.uiModel = uiModel; + this.dto = null; + this.enabled = true; + this.editable = false; + this.mandatory = false; + this.exclusive = false; + this.needOneSelection = false; + } + + FloatingObjectPartsTreeNodeContext(ObjectMaterialHierarchyDto dto, FloatingObjectPartsTreeNodeContext parent) { + Objects.requireNonNull(dto); + Objects.requireNonNull(parent); + this.uiModel = parent.uiModel; + this.dto = dto; + // enabled if parent is enabled and dto is enabled + this.enabled = parent.enabled && dto.isEnabled(); + // need one selection if is enabled and dto requires it + this.needOneSelection = enabled && dto.isChildSelectionMandatory(); + // editable if dto is selectable (we also make sure that the object material type is here too) + this.editable = dto.isSelectable() && dto.getObjectMaterialType() != null; + // mandatory if enabled parent is so or parent makes this child to be + this.mandatory = parent.mandatory || parent.needOneSelection; + // exclusive if his parent requires it + this.exclusive = parent.dto != null && parent.dto.isChildrenMultiSelectable(); + log.info(String.format("New node: %s - mandatory %s - needOneSelection %s - exclusive %s", dto.getLabel2(), mandatory, needOneSelection, exclusive)); + } + + Object getValueAt(int column) { + switch (column) { + case 0: // dto + return dto; + case 1: // when arriving + return uiModel.getWhenArriving().get(dto); + case 2: // when leaving + return uiModel.getWhenLeaving().get(dto); + } + throw new IllegalStateException(); + } + + void setValueAt(Object aValue, int column) { + switch (column) { + case 1: // when arriving + uiModel.setWhenArriving(dto.getId(), aValue == null ? null : String.valueOf(aValue)); + return; + case 2: // when leaving + uiModel.setWhenLeaving(dto.getId(), aValue == null ? null : String.valueOf(aValue)); + return; + } + throw new IllegalStateException(); + } + + boolean isColumnEditable(int column) { + switch (column) { + case 1: // when arriving + return uiModel.isArriving(); + case 2: // when leaving + return uiModel.isLeaving(); + } + throw new IllegalStateException(); + } + + boolean isValid(int column) { + switch (column) { + case 1: // when arriving + return validWhenArriving; + case 2: // when leaving + return validWhenLeaving; + } + throw new IllegalStateException(); + } + + Optional<FloatingObjectPartsTreeNode> getSelectedCompanion(int column) { + return companions.stream().filter(n -> n.getValueAt(column) != null).findFirst(); + } + + public String getText() { + if (text == null && dto != null) { + text = String.format("%s [value: %s-%s] [valid: %s-%s]", dto.getLabel2(), getValueAt(1), getValueAt(2), isValid(1), isValid(2)); + } + return text; + } + + } + + private FloatingObjectPartsTreeNode(FloatingObjectPartsTreeNodeContext context) { + super(context); + if (context.dto != null) { + for (ObjectMaterialHierarchyDto dto : context.dto.getChildren()) { + FloatingObjectPartsTreeNodeContext childContext = new FloatingObjectPartsTreeNodeContext(dto, context); + add(new FloatingObjectPartsTreeNode(childContext)); + } + } + } + + @Override + public String toString() { + return getUserObject().getText(); + } + + @Override + public FloatingObjectPartsTreeNodeContext getUserObject() { + return (FloatingObjectPartsTreeNodeContext) super.getUserObject(); + } + + @Override + public Object getValueAt(int column) { + return getUserObject().getValueAt(column); + } + + @Override + public void setValueAt(Object aValue, int column) { + getUserObject().setValueAt(aValue, column); + } + + @Override + public boolean isEditable(int column) { + return column > 0 && getUserObject().enabled && getUserObject().editable && isColumnEditable(column); + } + + private boolean isColumnEditable(int column) { + return getUserObject().isColumnEditable(column); + } + + @Override + public int getColumnCount() { + return 3; + } + + @SuppressWarnings({"unchecked"}) + @Override + @NotNull + public Iterator<FloatingObjectPartsTreeNode> iterator() { + return (Iterator) (children == null ? Collections.emptyIterator() : children.iterator()); + } + + public boolean isValid(int column) { + return getUserObject().isValid(column); + } + + boolean isExclusive() { + return getUserObject().exclusive; + } + + public boolean isEditable() { + return getUserObject().editable; + } + + public boolean isEnabled() { + return getUserObject().enabled; + } + + public String getId() { + return getUserObject().dto.getId(); + } + + public boolean isBoolean() { + return getUserObject().dto.isBoolean(); + } + + public boolean isText() { + return getUserObject().dto.isText(); + } + + public boolean isInteger() { + return getUserObject().dto.isInteger(); + } + + public boolean isFloat() { + return getUserObject().dto.isFloat(); + } + + ReferentialReference<ObjectMaterialTypeDto> getObjectMaterialType() { + return getUserObject().dto.getObjectMaterialType(); + } + + Optional<FloatingObjectPartsTreeNode> getSelectedCompanion(int column) { + return getUserObject().getSelectedCompanion(column); + } + + void resetStates() { + getUserObject().text = null; + getUserObject().validWhenArriving = true; + getUserObject().validWhenLeaving = true; + } + + @Override + public FloatingObjectPartsTreeNode getParent() { + return (FloatingObjectPartsTreeNode) super.getParent(); + } + + void fillNodeSets(ImmutableSet.Builder<FloatingObjectPartsTreeNode> allNodesBuilder, + ImmutableSet.Builder<FloatingObjectPartsTreeNode> needOneSelectionNodesBuilder, + ImmutableSet.Builder<FloatingObjectPartsTreeNode> mandatoryNodesBuilder) { + + allNodesBuilder.add(this); + if (getUserObject().needOneSelection) { + needOneSelectionNodesBuilder.add(this); + } + if (getUserObject().mandatory) { + mandatoryNodesBuilder.add(this); + } + + for (FloatingObjectPartsTreeNode child : this) { + child.fillNodeSets(allNodesBuilder, needOneSelectionNodesBuilder, mandatoryNodesBuilder); + } + + } + + void computeNeedAtLeastOnSelectValidState(boolean whenArriving, boolean whenLeaving) { + + if (whenArriving) { + getUserObject().validWhenArriving = isAtLeastOneSelected(1); + } + if (whenLeaving) { + getUserObject().validWhenLeaving = isAtLeastOneSelected(2); + } + + log.info("Validate node " + this); + + } + + void computeMandatoryValidState(boolean whenArriving, boolean whenLeaving) { + if (whenArriving) { + getUserObject().validWhenArriving = getParent().getUserObject().validWhenArriving; + } + if (whenLeaving) { + getUserObject().validWhenLeaving = getParent().getUserObject().validWhenLeaving; + } + + log.info("Validate node " + this); + } + + private void setCompanions(ImmutableSet.Builder<FloatingObjectPartsTreeNode> companionsBuilder) { + if (companionsBuilder != null) { + ImmutableSet<FloatingObjectPartsTreeNode> companions = companionsBuilder.build(); + for (FloatingObjectPartsTreeNode child : this) { + child.getUserObject().companions = companions; + } + } + } + + private boolean isAtLeastOneSelected(int column) { + if (getValueAt(column) != null) { + return true; + } + for (FloatingObjectPartsTreeNode child : this) { + if (child.isAtLeastOneSelected(column)) { + return true; + } + } + return false; + } + + private void computeCompanions(ImmutableSet.Builder<FloatingObjectPartsTreeNode> companionsBuilder) { + if (companionsBuilder != null) { + companionsBuilder.add(this); + } + + ImmutableSet.Builder<FloatingObjectPartsTreeNode> childCompanionsBuilder = getUserObject().dto.isChildrenMultiSelectable() ? ImmutableSet.builder() : null; + for (FloatingObjectPartsTreeNode child : this) { + child.computeCompanions(childCompanionsBuilder); + } + setCompanions(childCompanionsBuilder); + } +} ===================================== client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/dcp/FloatingObjectPartsTreeTableModel.java ===================================== --- /dev/null +++ b/client/src/main/java/fr/ird/observe/client/ui/content/impl/seine/dcp/FloatingObjectPartsTreeTableModel.java @@ -0,0 +1,131 @@ +package fr.ird.observe.client.ui.content.impl.seine.dcp; + +/*- + * #%L + * ObServe :: Client + * %% + * Copyright (C) 2008 - 2017 IRD, Code Lutin, Ultreia.io + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 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 Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +import com.google.common.collect.ImmutableSet; +import fr.ird.observe.client.ui.content.impl.seine.FloatingObjectUIModel; +import fr.ird.observe.services.dto.seine.ObjectMaterialHierarchyDto; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.jdesktop.swingx.treetable.DefaultTreeTableModel; +import org.jdesktop.swingx.treetable.TreeTableNode; +import org.nuiton.i18n.I18n; + +/** + * Created by tchemit on 05/08/17. + * + * @author Tony Chemit - dev@tchemit.fr + * @since 7.0 + */ +public class FloatingObjectPartsTreeTableModel extends DefaultTreeTableModel { + + /** Logger. */ + private static final Log log = LogFactory.getLog(FloatingObjectPartsTreeTableModel.class); + + private final FloatingObjectUIModel uiModel; + + private ImmutableSet<FloatingObjectPartsTreeNode> allNodes; + private ImmutableSet<FloatingObjectPartsTreeNode> needOneSelectionNodes; + private ImmutableSet<FloatingObjectPartsTreeNode> mandatoryNodes; + + public FloatingObjectPartsTreeTableModel(FloatingObjectUIModel uiModel) { + super(FloatingObjectPartsTreeNode.createRoot(uiModel, Collections.emptyList()), Arrays.asList( + I18n.t("observe.content.floatingObject.table.type"), + I18n.t("observe.common.whenArriving"), + I18n.t("observe.common.whenLeaving"))); + this.uiModel = uiModel; + } + + @Override + public FloatingObjectPartsTreeNode getRoot() { + return (FloatingObjectPartsTreeNode) super.getRoot(); + } + + public void rebuildRootNode(List<ObjectMaterialHierarchyDto> materials) { + FloatingObjectPartsTreeNode root = FloatingObjectPartsTreeNode.createRoot(uiModel, materials); + setRoot(root); + } + + @Override + public void setRoot(TreeTableNode root) { + super.setRoot(root); + + FloatingObjectPartsTreeNode myRoot = (FloatingObjectPartsTreeNode) root; + + ImmutableSet.Builder<FloatingObjectPartsTreeNode> allNodesBuilder = ImmutableSet.builder(); + ImmutableSet.Builder<FloatingObjectPartsTreeNode> needOneSelectionNodesBuilder = ImmutableSet.builder(); + ImmutableSet.Builder<FloatingObjectPartsTreeNode> mandatoryNodesBuilder = ImmutableSet.builder(); + + myRoot.fillNodeSets(allNodesBuilder, needOneSelectionNodesBuilder, mandatoryNodesBuilder); + + allNodes = allNodesBuilder.build(); + needOneSelectionNodes = needOneSelectionNodesBuilder.build(); + mandatoryNodes = mandatoryNodesBuilder.build(); + } + + @Override + public int getColumnCount() { + return 3; + } + + @Override + public Class<?> getColumnClass(int column) { + switch (column) { + case 0: + return String.class; + case 1: + case 2: + return Object.class; + } + throw new IllegalStateException(); + } + + @Override + public void setValueAt(Object value, Object node, int column) { + FloatingObjectPartsTreeNode treeNode = (FloatingObjectPartsTreeNode) node; + Optional<FloatingObjectPartsTreeNode> previousNode = treeNode.isExclusive() && value != null ? treeNode.getSelectedCompanion(column) : Optional.empty(); + previousNode.ifPresent(p -> log.info("Previous selected node: " + p)); + super.setValueAt(value, node, column); + previousNode.ifPresent(t -> super.setValueAt(null, t, column)); + reset(); + uiModel.setModified(true); + } + + public void reset() { + allNodes.forEach(FloatingObjectPartsTreeNode::resetStates); + + boolean whenArriving = uiModel.isArriving(); + boolean whenLeaving = uiModel.isLeaving(); + + needOneSelectionNodes.forEach(n -> n.computeNeedAtLeastOnSelectValidState(whenArriving, whenLeaving)); + mandatoryNodes.forEach(n -> n.computeMandatoryValidState(whenArriving, whenLeaving)); + + boolean notValid = allNodes.stream().anyMatch(FloatingObjectPartsTreeNode::isNotValid); + uiModel.getBean().setMaterialsValid(!notValid); + } + +} ===================================== client/src/main/java/fr/ird/observe/client/ui/util/treetable/JRadioButtonCellEditor.java ===================================== --- /dev/null +++ b/client/src/main/java/fr/ird/observe/client/ui/util/treetable/JRadioButtonCellEditor.java @@ -0,0 +1,159 @@ +package fr.ird.observe.client.ui.util.treetable; + +/*- + * #%L + * ObServe :: Client + * %% + * Copyright (C) 2008 - 2017 IRD, Code Lutin, Ultreia.io + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 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 Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.MouseEvent; +import java.io.Serializable; +import java.util.EventObject; +import javax.swing.AbstractCellEditor; +import javax.swing.JComponent; +import javax.swing.JRadioButton; +import javax.swing.JTable; +import javax.swing.SwingConstants; +import javax.swing.table.TableCellEditor; +import javax.swing.table.TableCellRenderer; + +/** + * Created by tchemit on 05/08/17. + * + * @author Tony Chemit - dev@tchemit.fr + * @since 7.0 + */ +public class JRadioButtonCellEditor extends AbstractCellEditor implements TableCellEditor { + + private JRadioButton editorComponent; + private EditorDelegate delegate; + + public JRadioButtonCellEditor() { + editorComponent = new JRadioButton(); + editorComponent.setHorizontalAlignment(SwingConstants.CENTER); + delegate = new EditorDelegate(); + editorComponent.addActionListener(delegate); + editorComponent.setRequestFocusEnabled(false); + } + + public Component getComponent() { + return editorComponent; + } + + @Override + public Object getCellEditorValue() { + return delegate.getCellEditorValue(); + } + + @Override + public boolean isCellEditable(EventObject anEvent) { + return delegate.isCellEditable(anEvent); + } + + @Override + public boolean shouldSelectCell(EventObject anEvent) { + return delegate.shouldSelectCell(anEvent); + } + + @Override + public boolean stopCellEditing() { + return delegate.stopCellEditing(); + } + + @Override + public void cancelCellEditing() { + delegate.cancelCellEditing(); + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, + boolean isSelected, + int row, int column) { + delegate.setValue(value); + //in order to avoid a "flashing" effect when clicking a checkbox + //in a table, it is important for the editor to have as a border + //the same border that the renderer has, and have as the background + //the same color as the renderer has. This is primarily only + //needed for JCheckBox since this editor doesn't fill all the + //visual space of the table cell, unlike a text field. + TableCellRenderer renderer = table.getCellRenderer(row, column); + Component c = renderer.getTableCellRendererComponent(table, value, isSelected, true, row, column); + if (c != null) { + editorComponent.setOpaque(true); + editorComponent.setBackground(c.getBackground()); + if (c instanceof JComponent) { + editorComponent.setBorder(((JComponent) c).getBorder()); + } + } else { + editorComponent.setOpaque(false); + } + return editorComponent; + } + + protected class EditorDelegate implements ActionListener, ItemListener, Serializable { + + boolean getCellEditorValue() { + return editorComponent.isSelected(); + } + + public void setValue(Object value) { + + boolean selected = false; + if (value instanceof Boolean) { + selected = (Boolean) value; + } else if (value instanceof String) { + selected = value.equals("true"); + } + editorComponent.setSelected(selected); + } + + public boolean isCellEditable(EventObject anEvent) { + return !(anEvent instanceof MouseEvent) || ((MouseEvent) anEvent).getClickCount() > 0; + } + + boolean shouldSelectCell(@SuppressWarnings("unused") EventObject ignored) { + return true; + } + + boolean stopCellEditing() { + fireEditingStopped(); + return true; + } + + void cancelCellEditing() { + fireEditingCanceled(); + } + + @Override + public void actionPerformed(ActionEvent e) { + this.stopCellEditing(); + } + + @Override + public void itemStateChanged(ItemEvent e) { + this.stopCellEditing(); + } + } + +} ===================================== client/src/main/java/fr/ird/observe/client/ui/util/treetable/JRadioButtonProvider.java ===================================== --- /dev/null +++ b/client/src/main/java/fr/ird/observe/client/ui/util/treetable/JRadioButtonProvider.java @@ -0,0 +1,55 @@ +package fr.ird.observe.client.ui.util.treetable; + +/*- + * #%L + * ObServe :: Client + * %% + * Copyright (C) 2008 - 2017 IRD, Code Lutin, Ultreia.io + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 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 Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + + +import javax.swing.JLabel; +import javax.swing.JRadioButton; +import org.jdesktop.swingx.renderer.CellContext; +import org.jdesktop.swingx.renderer.ComponentProvider; + +/** + * Created by tchemit on 05/08/17. + * + * @author Tony Chemit - dev@tchemit.fr + * @since 7.0 + */ +public class JRadioButtonProvider extends ComponentProvider<JRadioButton> { + + @Override + protected void format(CellContext context) { + rendererComponent.setSelected(Boolean.TRUE.equals(context.getValue())); + } + + @Override + protected void configureState(CellContext context) { + rendererComponent.setHorizontalAlignment(JLabel.CENTER); + rendererComponent.setBorderPainted(true); + } + + @Override + protected JRendererRadioButton createRendererComponent() { + return new JRendererRadioButton(); + } + +} ===================================== client/src/main/java/fr/ird/observe/client/ui/util/treetable/JRendererRadioButton.java ===================================== --- /dev/null +++ b/client/src/main/java/fr/ird/observe/client/ui/util/treetable/JRendererRadioButton.java @@ -0,0 +1,275 @@ +package fr.ird.observe.client.ui.util.treetable; + +/*- + * #%L + * ObServe :: Client + * %% + * Copyright (C) 2008 - 2017 IRD, Code Lutin, Ultreia.io + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 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 Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + + +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import javax.swing.JRadioButton; +import javax.swing.UIManager; +import org.jdesktop.swingx.painter.Painter; +import org.jdesktop.swingx.renderer.PainterAware; + +/** + * Created by tchemit on 05/08/17. + * + * @author Tony Chemit - dev@tchemit.fr + * @since 7.0 + */ +public class JRendererRadioButton extends JRadioButton implements PainterAware { + /** the swingx painter */ + private Painter painter; + /** a flag to prevent ui painting from filling the background. */ + private boolean fakeTransparency; + + JRendererRadioButton() { + super(); + // fix # 1546-swingx: striping lost in synth-based lafs + // forcing opaque to enable painting the background + setOpaque(true); + } + + @Override + public Painter getPainter() { + return painter; + } + + @Override + public void setPainter(Painter painter) { + Painter old = getPainter(); + this.painter = painter; + firePropertyChange("painter", old, getPainter()); + } + + /** + * Overridden to return false if painting flag is true.<p> + */ + @Override + public boolean isOpaque() { + return !fakeTransparency && super.isOpaque(); + } + + /** + * Overridden to return false if painting flag is true.<p> + */ + @Override + public boolean isContentAreaFilled() { + return !fakeTransparency && super.isContentAreaFilled(); + } + + /** + * Overridden to not automatically de/register itself from/to the ToolTipManager. + * As rendering component it is not considered to be active in any way, so the + * manager must not listen. + */ + @Override + public void setToolTipText(String text) { + putClientProperty(TOOL_TIP_TEXT_KEY, text); + } + + /** + * Overridden to snatch painting from super if a painter installed or Nimbus + * detected.<p> + * <p> + * The overall logic currently (since 1.6.5) is to simply call super without SwingX + * painter. Otherwise, that is with SwingX painter: + * <ol> + * <li> if opaque + * <ol> + * <li> set a flag which fakes transparency, that is both + * <code>contentAreaFilled</code> and + * <code>opaque</code> return false + * <li> fill background with the component's background color + * <li> apply swingx painter + * <li> hook into <code>ui.paint(...)</code> + * <li> reset the flag + * </ol> + * <li> else + * <ol> apply swingx painter + * <ol> call super + * <li> + * <ol> + * </ol> + * <p> + * Note that Nimbus is special cased (mainly due to its bug of + * even row striping instead of odd) + * and handled as if a SwingX painter were set. + */ + @Override + protected void paintComponent(Graphics g) { + // JW: hack around for #1178-swingx (core issue) + // grab painting if Nimbus detected + if ((painter != null) || isNimbus()) { + // we have a custom (background) painter + // try to inject if possible + // there's no guarantee - some LFs have their own background + // handling elsewhere + if (isOpaque()) { + // replace the paintComponent completely + fakeTransparency = true; + paintComponentWithPainter((Graphics2D) g); + fakeTransparency = false; + } else { + // transparent apply the background painter before calling super + paintPainter(g); + super.paintComponent(g); + } + } else { + // nothing to worry about - delegate to super + super.paintComponent(g); + } + } + + /** + * Hack around Nimbus not respecting background colors if UIResource. + * So by-pass ... + */ + private boolean isNimbus() { + return UIManager.getLookAndFeel().getName().contains("Nimbus"); + } + + + /** + * Hack around AbstractPainter.paint bug which disposes the Graphics. + * So here we give it a scratch to paint on. <p> + * TODO - remove again, the issue is fixed? + * + * @param g the graphics to paint on + */ + private void paintPainter(Graphics g) { + if (painter == null) return; + // fail fast: we assume that g must not be null + // which throws an NPE here instead deeper down the bowels + // this differs from corresponding core implementation! + Graphics2D scratch = (Graphics2D) g.create(); + try { + painter.paint(scratch, this, getWidth(), getHeight()); + } finally { + scratch.dispose(); + } + } + + private void paintComponentWithPainter(Graphics2D g) { + // 1. be sure to fill the background + // 2. paint the painter + // by-pass ui.update and hook into ui.paint directly + if (ui != null) { + // fail fast: we assume that g must not be null + // which throws an NPE here instead deeper down the bowels + // this differs from corresponding core implementation! + Graphics scratchGraphics = g.create(); + try { + scratchGraphics.setColor(getBackground()); + scratchGraphics.fillRect(0, 0, getWidth(), getHeight()); + paintPainter(g); + ui.paint(scratchGraphics, this); + } finally { + scratchGraphics.dispose(); + } + } + + } + + /** + * Overridden for performance reasons. + * See the <a href="#override">Implementation Note</a> + * for more information. + * + * @since 1.5 + */ + @Override + public void invalidate() { + } + + /** + * Overridden for performance reasons. + * See the <a href="#override">Implementation Note</a> + * for more information. + */ + @Override + public void validate() { + } + + /** + * Overridden for performance reasons. + * See the <a href="#override">Implementation Note</a> + * for more information. + */ + @Override + public void revalidate() { + } + + /** + * Overridden for performance reasons. + * See the <a href="#override">Implementation Note</a> + * for more information. + */ + @Override + public void repaint(long tm, int x, int y, int width, int height) { + } + + /** + * Overridden for performance reasons. + * See the <a href="#override">Implementation Note</a> + * for more information. + */ + @Override + public void repaint(Rectangle r) { + } + + /** + * Overridden for performance reasons. + * See the <a href="#override">Implementation Note</a> + * for more information. + * + * @since 1.5 + */ + @Override + public void repaint() { + } + + /** + * Overridden for performance reasons. + * See the <a href="#override">Implementation Note</a> + * for more information. + */ + @Override + protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { + // Strings get interned... + if ("text".equals(propertyName)) { + super.firePropertyChange(propertyName, oldValue, newValue); + } + } + + /** + * Overridden for performance reasons. + * See the <a href="#override">Implementation Note</a> + * for more information. + */ + @Override + public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) { + } + + +} ===================================== persistence/src/main/java/fr/ird/observe/persistence/ObserveTopiaPersistenceContext.java ===================================== --- a/persistence/src/main/java/fr/ird/observe/persistence/ObserveTopiaPersistenceContext.java +++ b/persistence/src/main/java/fr/ird/observe/persistence/ObserveTopiaPersistenceContext.java @@ -55,8 +55,8 @@ public class ObserveTopiaPersistenceContext extends AbstractObserveTopiaPersiste LastUpdateDateTopiaDao dao = getDao(LastUpdateDate.class, LastUpdateDateTopiaDao.class); LastUpdateDate lastUpdateDate = dao.findUniqueByType(entityType.getName()); - if (log.isInfoEnabled()) { - log.info("getLastUpdateDate: " + lastUpdateDate.getLastUpdateDate() + " for entity type: " + entityType.getName()); + if (log.isDebugEnabled()) { + log.debug("getLastUpdateDate: " + lastUpdateDate.getLastUpdateDate() + " for entity type: " + entityType.getName()); } return lastUpdateDate.getLastUpdateDate(); @@ -66,7 +66,7 @@ public class ObserveTopiaPersistenceContext extends AbstractObserveTopiaPersiste entity.setLastUpdateDate(date); - // on met à jour l'entité (cela permet de récupérer son topiaId si l'objet est créé) + // update (will then get new id if was not persisted) getDao(entity).update(entity); Class<E> type = getType(entity); @@ -86,14 +86,14 @@ public class ObserveTopiaPersistenceContext extends AbstractObserveTopiaPersiste lastUpdateDate.setLastUpdateDate(date); lastUpdateDate.setType(entityTypeName); dao.create(lastUpdateDate); - if (log.isInfoEnabled()) { - log.info("Add LastUpdateDate: " + date + " for entity type: " + entityTypeName); + if (log.isDebugEnabled()) { + log.debug("Add LastUpdateDate: " + date + " for entity type: " + entityTypeName); } } else { lastUpdateDate = optionalLastUpdateDate.get(); - if (log.isInfoEnabled()) { - log.info("Change LastUpdateDate: " + date + " for entity type: " + entityTypeName); + if (log.isDebugEnabled()) { + log.debug("Change LastUpdateDate: " + date + " for entity type: " + entityTypeName); } lastUpdateDate.setLastUpdateDate(date); } @@ -108,6 +108,7 @@ public class ObserveTopiaPersistenceContext extends AbstractObserveTopiaPersiste ObserveEntityEnum entityEnum = ObserveEntityEnum.valueOf(entity); Objects.requireNonNull(entityEnum, "Entity " + entity + " is not managed by ToPIA"); + //noinspection unchecked return (Class<E>) entityEnum.getContract(); } @@ -135,13 +136,13 @@ public class ObserveTopiaPersistenceContext extends AbstractObserveTopiaPersiste private final String fullyTableName; - public CountTableSqlWork(String fullyTableName) { + CountTableSqlWork(String fullyTableName) { this.fullyTableName = fullyTableName; } @Override public PreparedStatement prepareQuery(Connection connection) throws SQLException { - String sql = "SELECT count(*) FROM " + fullyTableName; + String sql = String.format("SELECT count(*) FROM %s", fullyTableName); if (showSql) { log.debug(sql); } ===================================== services/src/main/java/fr/ird/observe/services/decoration/ObserveI18nDecoratorHelper.java ===================================== --- a/services/src/main/java/fr/ird/observe/services/decoration/ObserveI18nDecoratorHelper.java +++ b/services/src/main/java/fr/ird/observe/services/decoration/ObserveI18nDecoratorHelper.java @@ -329,5 +329,6 @@ public class ObserveI18nDecoratorHelper { n("observe.common.yearService"); n("observe.common.whenArriving"); n("observe.common.whenLeaving"); + n("observe.common.materialsValid"); } } ===================================== services/src/main/java/fr/ird/observe/services/dto/referential/seine/ObjectMaterialDto.java ===================================== --- /dev/null +++ b/services/src/main/java/fr/ird/observe/services/dto/referential/seine/ObjectMaterialDto.java @@ -0,0 +1,44 @@ +package fr.ird.observe.services.dto.referential.seine; + +/*- + * #%L + * ObServe :: Services + * %% + * Copyright (C) 2008 - 2017 IRD, Code Lutin, Ultreia.io + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 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 Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +public class ObjectMaterialDto extends GeneratedObjectMaterialDto { + + private static final long serialVersionUID = 1L; + + public boolean isBoolean() { + return objectMaterialType != null && "fr.ird.observe.entities.referentiel.seine.ObjectMaterialType#0#0".equals(objectMaterialType.getId()); + } + + public boolean isText() { + return objectMaterialType != null && "fr.ird.observe.entities.referentiel.seine.ObjectMaterialType#0#3".equals(objectMaterialType.getId()); + } + + public boolean isInteger() { + return objectMaterialType != null && "fr.ird.observe.entities.referentiel.seine.ObjectMaterialType#0#2".equals(objectMaterialType.getId()); + } + + public boolean isFloat() { + return objectMaterialType != null && "fr.ird.observe.entities.referentiel.seine.ObjectMaterialType#0#1".equals(objectMaterialType.getId()); + } +} ===================================== services/src/main/models/Observe.model ===================================== --- a/services/src/main/models/Observe.model +++ b/services/src/main/models/Observe.model @@ -628,6 +628,7 @@ computedWhenArrivingSimplifiedObjectType + {*:1} String computedWhenLeavingBiodegradable + {*:1} !fr.ird.observe.common.constants.seine.DcpComputedValue computedWhenLeavingNonEntangling + {*:1} !fr.ird.observe.common.constants.seine.DcpComputedValue computedWhenLeavingSimplifiedObjectType + {*:1} String +materialsValid + {*:1} boolean seine.FloatingObjectObservedSpecies > Commentable objectObservedSpecies {*} seine.ObjectObservedSpecies ===================================== services/src/main/resources/i18n/services_en_GB.properties ===================================== --- a/services/src/main/resources/i18n/services_en_GB.properties +++ b/services/src/main/resources/i18n/services_en_GB.properties @@ -111,6 +111,7 @@ observe.common.lightsticksType=Lightsticks type observe.common.lineType=Line type observe.common.locode=Locode observe.common.longitude=Longitude +observe.common.materialsValid=Materials observe.common.maturityStatus=Maturity status observe.common.maxDepthTargeted=Max depth targeted observe.common.maxGearDepth=Max gear depth ===================================== services/src/main/resources/i18n/services_es_ES.properties ===================================== --- a/services/src/main/resources/i18n/services_es_ES.properties +++ b/services/src/main/resources/i18n/services_es_ES.properties @@ -111,6 +111,7 @@ observe.common.lightsticksType=Tipo de barrita de luz observe.common.lineType=Tipo de línea observe.common.locode=Locode observe.common.longitude=Longitude +observe.common.materialsValid=Materials \#TODO observe.common.maturityStatus=Maturidad observe.common.maxDepthTargeted=Profundidad máxima deseada observe.common.maxGearDepth=Profundidad máxima (m) ===================================== services/src/main/resources/i18n/services_fr_FR.properties ===================================== --- a/services/src/main/resources/i18n/services_fr_FR.properties +++ b/services/src/main/resources/i18n/services_fr_FR.properties @@ -111,6 +111,7 @@ observe.common.lightsticksType=Type de cyalumes observe.common.lineType=Type de ligne observe.common.locode=Locode observe.common.longitude=Longitude +observe.common.materialsValid=Matériels observe.common.maturityStatus=Maturité sexuelle observe.common.maxDepthTargeted=Profondeur maximum ciblée observe.common.maxGearDepth=Profondeur maximum (m) View it on GitLab: https://gitlab.com/ultreiaio/ird-observe/compare/d9a448941ed45d4ab7d267b7e59... --- View it on GitLab: https://gitlab.com/ultreiaio/ird-observe/compare/d9a448941ed45d4ab7d267b7e59... You're receiving this email because of your account on gitlab.com.