Tony CHEMIT pushed to branch develop at ultreiaio / ird-observe
Commits:
-
7d737dec
by Tony Chemit at 2021-02-17T17:09:54+01:00
-
70b71ffc
by Tony Chemit at 2021-02-17T17:09:54+01:00
-
84ab2eee
by Tony Chemit at 2021-02-17T17:09:54+01:00
-
ee10922f
by Tony Chemit at 2021-02-17T17:09:54+01:00
-
f450d7ae
by Tony Chemit at 2021-02-17T17:09:54+01:00
-
9445e2c4
by Tony Chemit at 2021-02-17T18:18:29+01:00
22 changed files:
- client/datasource/editor/api/src/main/java/fr/ird/observe/client/datasource/editor/api/ObserveKeyStrokesEditorApi.java
- client/datasource/editor/api/src/main/java/fr/ird/observe/client/datasource/editor/api/content/actions/delete/DeleteExecutor.java
- client/datasource/editor/api/src/main/java/fr/ird/observe/client/datasource/editor/api/content/data/open/ContentOpenableUINavigationHandler.java
- client/datasource/editor/api/src/main/java/fr/ird/observe/client/datasource/editor/api/content/data/open/ContentOpenableUINavigationInitializer.java
- client/datasource/editor/api/src/main/java/fr/ird/observe/client/datasource/editor/api/navigation/tree/NavigationNode.java
- client/datasource/editor/common/src/main/i18n/getters/jaxx.getter
- client/datasource/editor/ps/src/main/i18n/getters/jaxx.getter
- client/datasource/editor/ps/src/main/java/fr/ird/observe/client/datasource/editor/ps/data/observation/FloatingObjectUI.jaxx
- client/datasource/editor/ps/src/main/java/fr/ird/observe/client/datasource/editor/ps/data/observation/FloatingObjectUI.jcss
- client/datasource/editor/ps/src/main/java/fr/ird/observe/client/datasource/editor/ps/data/observation/FloatingObjectUIHandler.java
- client/datasource/editor/ps/src/main/java/fr/ird/observe/client/datasource/editor/ps/data/observation/FloatingObjectUIModel.java
- client/datasource/editor/ps/src/main/java/fr/ird/observe/client/datasource/editor/ps/data/observation/FloatingObjectUIModelStates.java
- client/datasource/editor/ps/src/main/java/fr/ird/observe/client/datasource/editor/ps/data/observation/actions/FloatingObjectUIAddFloatingObjectPreset.java
- + client/datasource/editor/ps/src/main/java/fr/ird/observe/client/datasource/editor/ps/data/observation/dcp/UsePresetAction.java
- models/dto/java/src/main/i18n/getters/java.getter
- models/dto/java/src/main/java/fr/ird/observe/dto/data/ps/observation/ActivityReference.java
- models/dto/java/src/main/java/fr/ird/observe/dto/decoration/ObserveI18nLabelsBuilder.java
- + models/dto/java/src/test/java/fr/ird/observe/dto/decoration/ObserveI18nLabelsBuilderTest.java
- pom.xml
- services/i18n/src/main/i18n/translations/services_en_GB.properties
- services/i18n/src/main/i18n/translations/services_es_ES.properties
- services/i18n/src/main/i18n/translations/services_fr_FR.properties
Changes:
| ... | ... | @@ -67,6 +67,7 @@ public class ObserveKeyStrokesEditorApi extends ObserveKeyStrokesSupport { |
| 67 | 67 |
public static final KeyStroke KEY_STROKE_DELETE_DATA_GLOBAL = KeyStroke.getKeyStroke("pressed F6");
|
| 68 | 68 |
public static final KeyStroke KEY_STROKE_MOVE = KeyStroke.getKeyStroke("pressed F7");
|
| 69 | 69 |
public static final KeyStroke KEY_STROKE_DUPLICATE = KeyStroke.getKeyStroke("pressed F7");
|
| 70 |
+ public static final KeyStroke KEY_STROKE_ADD_PRESET = KeyStroke.getKeyStroke("pressed F9");
|
|
| 70 | 71 |
public static final KeyStroke KEY_STROKE_GENERATE = KeyStroke.getKeyStroke("pressed F9");
|
| 71 | 72 |
public static final KeyStroke KEY_STROKE_CHANGE_ID = KeyStroke.getKeyStroke("pressed F9");
|
| 72 | 73 |
public static final KeyStroke KEY_STROKE_SHOW_TECHNICAL_INFORMATIONS = KeyStroke.getKeyStroke("pressed F10");
|
| ... | ... | @@ -30,7 +30,6 @@ import org.apache.logging.log4j.Logger; |
| 30 | 30 |
import org.nuiton.jaxx.runtime.swing.application.ActionExecutor;
|
| 31 | 31 |
|
| 32 | 32 |
import javax.swing.SwingUtilities;
|
| 33 |
-import java.lang.reflect.InvocationTargetException;
|
|
| 34 | 33 |
import java.util.Objects;
|
| 35 | 34 |
import java.util.Optional;
|
| 36 | 35 |
import java.util.Set;
|
| ... | ... | @@ -94,8 +93,8 @@ public class DeleteExecutor { |
| 94 | 93 |
DeleteTreeAdapter<?> treeAdapter = this.treeAdapter.apply(request);
|
| 95 | 94 |
try {
|
| 96 | 95 |
SwingUtilities.invokeAndWait(() -> treeAdapter.adaptTree(request, tree));
|
| 97 |
- } catch (InterruptedException | InvocationTargetException e) {
|
|
| 98 |
- log.error(e);
|
|
| 96 |
+ } catch (Exception e) {
|
|
| 97 |
+ UIHelper.handlingError(e);
|
|
| 99 | 98 |
}
|
| 100 | 99 |
log.info(String.format("Delete adapt tree [end..] %s", ids));
|
| 101 | 100 |
}
|
| ... | ... | @@ -53,7 +53,7 @@ public abstract class ContentOpenableUINavigationHandler<N extends ContentOpenab |
| 53 | 53 |
|
| 54 | 54 |
@Override
|
| 55 | 55 |
public final boolean isLeaf() {
|
| 56 |
- return getNode().getInitializer().isNotPersisted() || super.isLeaf();
|
|
| 56 |
+ return getNode().getInitializer().isNotPersisted() || getNode().getInitializer().isLeaf() || super.isLeaf();
|
|
| 57 | 57 |
}
|
| 58 | 58 |
|
| 59 | 59 |
@Override
|
| ... | ... | @@ -27,6 +27,8 @@ import fr.ird.observe.client.datasource.editor.api.navigation.tree.NavigationIni |
| 27 | 27 |
import fr.ird.observe.client.datasource.editor.api.navigation.tree.NavigationScope;
|
| 28 | 28 |
import fr.ird.observe.dto.reference.DataDtoReference;
|
| 29 | 29 |
import fr.ird.observe.dto.reference.DtoReference;
|
| 30 |
+import io.ultreia.java4all.bean.definition.JavaBeanPropertyDefinition;
|
|
| 31 |
+import io.ultreia.java4all.util.SingletonSupplier;
|
|
| 30 | 32 |
|
| 31 | 33 |
import java.util.Objects;
|
| 32 | 34 |
|
| ... | ... | @@ -38,6 +40,10 @@ import java.util.Objects; |
| 38 | 40 |
*/
|
| 39 | 41 |
public final class ContentOpenableUINavigationInitializer extends NavigationInitializer<ContentOpenableUINavigationContext> {
|
| 40 | 42 |
|
| 43 |
+ /**
|
|
| 44 |
+ * flag to force a node to be a leaf even if it is not loaded.
|
|
| 45 |
+ */
|
|
| 46 |
+ private final SingletonSupplier<Boolean> leaf;
|
|
| 41 | 47 |
private DtoReference parentReference;
|
| 42 | 48 |
private DataDtoReference reference;
|
| 43 | 49 |
|
| ... | ... | @@ -45,60 +51,74 @@ public final class ContentOpenableUINavigationInitializer extends NavigationInit |
| 45 | 51 |
super(scope);
|
| 46 | 52 |
this.parentReference = Objects.requireNonNull(parentReference);
|
| 47 | 53 |
this.reference = Objects.requireNonNull(reference);
|
| 54 |
+ this.leaf = SingletonSupplier.of(this::computeLeaf);
|
|
| 55 |
+ }
|
|
| 56 |
+ |
|
| 57 |
+ private Boolean computeLeaf() {
|
|
| 58 |
+ @SuppressWarnings("unchecked") JavaBeanPropertyDefinition<DataDtoReference, ?> propertyDefinition = (JavaBeanPropertyDefinition<DataDtoReference, ?>) reference.javaBeanDefinition().properties().get("emptyNode");
|
|
| 59 |
+ if (propertyDefinition != null && propertyDefinition.canRead()) {
|
|
| 60 |
+ return (Boolean) propertyDefinition.get(reference);
|
|
| 61 |
+ }
|
|
| 62 |
+ return false;
|
|
| 48 | 63 |
}
|
| 49 | 64 |
|
| 50 | 65 |
@Override
|
| 51 |
- protected DataDtoReference init(NavigationContext<ContentOpenableUINavigationContext> context) {
|
|
| 66 |
+ protected final DataDtoReference init(NavigationContext<ContentOpenableUINavigationContext> context) {
|
|
| 52 | 67 |
context.initReference(parentReference);
|
| 53 | 68 |
context.initReference(reference);
|
| 54 | 69 |
return getReference();
|
| 55 | 70 |
}
|
| 56 | 71 |
|
| 57 | 72 |
@Override
|
| 58 |
- protected void open(NavigationContext<ContentOpenableUINavigationContext> context) {
|
|
| 73 |
+ protected final void open(NavigationContext<ContentOpenableUINavigationContext> context) {
|
|
| 59 | 74 |
updateSelectNodeId(getSelectId());
|
| 60 | 75 |
}
|
| 61 | 76 |
|
| 62 | 77 |
@Override
|
| 63 |
- protected void reload(NavigationContext<ContentOpenableUINavigationContext> context) {
|
|
| 78 |
+ protected final void reload(NavigationContext<ContentOpenableUINavigationContext> context) {
|
|
| 64 | 79 |
this.parentReference = context.reloadReference(getParentReference());
|
| 65 | 80 |
this.reference = context.reloadReference(getReference());
|
| 81 |
+ leaf.clear();
|
|
| 66 | 82 |
}
|
| 67 | 83 |
|
| 68 | 84 |
@Override
|
| 69 |
- public String toString() {
|
|
| 85 |
+ public final String toString() {
|
|
| 70 | 86 |
return super.toString() + "" + getSelectId();
|
| 71 | 87 |
}
|
| 72 | 88 |
|
| 73 |
- public DtoReference getParentReference() {
|
|
| 89 |
+ public final DtoReference getParentReference() {
|
|
| 74 | 90 |
return parentReference;
|
| 75 | 91 |
}
|
| 76 | 92 |
|
| 77 |
- public DataDtoReference getReference() {
|
|
| 93 |
+ public final DataDtoReference getReference() {
|
|
| 78 | 94 |
return reference;
|
| 79 | 95 |
}
|
| 80 | 96 |
|
| 81 |
- public String getSelectId() {
|
|
| 97 |
+ public final String getSelectId() {
|
|
| 82 | 98 |
return getReference().getId();
|
| 83 | 99 |
}
|
| 84 | 100 |
|
| 85 |
- public String getSelectedParentId() {
|
|
| 101 |
+ public final String getSelectedParentId() {
|
|
| 86 | 102 |
return getParentReference().getId();
|
| 87 | 103 |
}
|
| 88 | 104 |
|
| 89 |
- public boolean isOpen() {
|
|
| 105 |
+ public final boolean isOpen() {
|
|
| 90 | 106 |
return Objects.equals(getSelectId(), getEditNodeId());
|
| 91 | 107 |
}
|
| 92 | 108 |
|
| 93 |
- public boolean isPersisted() {
|
|
| 109 |
+ public final boolean isPersisted() {
|
|
| 94 | 110 |
return getSelectId() != null;
|
| 95 | 111 |
}
|
| 96 | 112 |
|
| 97 |
- public boolean isNotPersisted() {
|
|
| 113 |
+ public final boolean isNotPersisted() {
|
|
| 98 | 114 |
return getSelectId() == null;
|
| 99 | 115 |
}
|
| 100 | 116 |
|
| 101 |
- public void setReference(DataDtoReference reference) {
|
|
| 117 |
+ public final boolean isLeaf() {
|
|
| 118 |
+ return leaf.get();
|
|
| 119 |
+ }
|
|
| 120 |
+ |
|
| 121 |
+ public final void setReference(DataDtoReference reference) {
|
|
| 102 | 122 |
this.reference = Objects.requireNonNull(reference);
|
| 103 | 123 |
}
|
| 104 | 124 |
|
| ... | ... | @@ -450,17 +450,10 @@ public abstract class NavigationNode extends DefaultMutableTreeNode implements W |
| 450 | 450 |
super.remove(childIndex);
|
| 451 | 451 |
}
|
| 452 | 452 |
|
| 453 |
-// @Override
|
|
| 454 |
-// public void removeFromParent() {
|
|
| 455 |
-// NavigationNode parent = getParent();
|
|
| 456 |
-// int index = parent.getIndex(this);
|
|
| 457 |
-// parent.remove(index);
|
|
| 458 |
-// }
|
|
| 459 |
- |
|
| 460 | 453 |
public void removeChildren(Set<String> ids) {
|
| 461 | 454 |
for (String id : ids) {
|
| 462 | 455 |
NavigationNode childNode = findChildById(id);
|
| 463 |
- childNode.removeFromParent();
|
|
| 456 |
+ Objects.requireNonNull(childNode, String.format("Could not find child node from %s with id: '%s'.", id, this)).removeFromParent();
|
|
| 464 | 457 |
}
|
| 465 | 458 |
}
|
| 466 | 459 |
|
| ... | ... | @@ -488,7 +481,7 @@ public abstract class NavigationNode extends DefaultMutableTreeNode implements W |
| 488 | 481 |
// il faut charger les fils du nœud pour effectuer la recherche
|
| 489 | 482 |
populateChildrenIfNotLoaded();
|
| 490 | 483 |
|
| 491 |
- if (isLeaf()) {
|
|
| 484 |
+ if (getChildCount() == 0) {
|
|
| 492 | 485 |
// au final le nœud est une feuille, donc ne convient pas
|
| 493 | 486 |
return null;
|
| 494 | 487 |
}
|
| 1 | 1 |
observe.Id.comment
|
| 2 |
+observe.Id.coordinate
|
|
| 2 | 3 |
observe.Id.country
|
| 3 | 4 |
observe.Id.description
|
| 4 | 5 |
observe.Id.ocean
|
| 1 | 1 |
observe.Id.comment
|
| 2 |
+observe.Id.coordinate
|
|
| 2 | 3 |
observe.Id.country
|
| 3 | 4 |
observe.Id.homeId
|
| 4 | 5 |
observe.Id.ocean
|
| ... | ... | @@ -320,5 +320,5 @@ |
| 320 | 320 |
<JPanel id="invisible">
|
| 321 | 321 |
<JLabel id='noBaliseEditor' styleClass="skipI18n"/>
|
| 322 | 322 |
</JPanel>
|
| 323 |
- <JMenuItem id="addFloatingObjectPreset"/>
|
|
| 323 |
+ <JMenuItem id="addPreset"/>
|
|
| 324 | 324 |
</fr.ird.observe.client.datasource.editor.api.content.data.edit.ContentEditUI>
|
| ... | ... | @@ -36,7 +36,7 @@ |
| 36 | 36 |
}
|
| 37 | 37 |
|
| 38 | 38 |
#addFloatingObjectPreset {
|
| 39 |
- enabled:{states.isUpdatingMode() && states.getReference() == null};
|
|
| 39 |
+ enabled:{!states.isCreatingMode() && states.getReference() == null};
|
|
| 40 | 40 |
}
|
| 41 | 41 |
|
| 42 | 42 |
#objectOperation {
|
| ... | ... | @@ -21,6 +21,7 @@ |
| 21 | 21 |
*/
|
| 22 | 22 |
package fr.ird.observe.client.datasource.editor.ps.data.observation;
|
| 23 | 23 |
|
| 24 |
+import fr.ird.observe.client.datasource.editor.ps.data.observation.actions.FloatingObjectUIAddFloatingObjectPreset;
|
|
| 24 | 25 |
import fr.ird.observe.client.datasource.editor.ps.data.observation.dcp.FloatingObjectPartsTreeTableModel;
|
| 25 | 26 |
import fr.ird.observe.dto.ProtectedIdsPs;
|
| 26 | 27 |
import fr.ird.observe.dto.data.ps.TypeTransmittingBuoyOperation;
|
| ... | ... | @@ -79,14 +80,19 @@ public class FloatingObjectUIHandler extends GeneratedFloatingObjectUIHandler { |
| 79 | 80 |
model.getStates().getBean().addPropertyChangeListener(FloatingObjectDto.PROPERTY_OBJECT_OPERATION, e -> updateMaterials((ObjectOperationReference) e.getNewValue()));
|
| 80 | 81 |
}
|
| 81 | 82 |
|
| 82 |
- //FIXME:Focus ui.getModel().getStates().isCreatingMode() ? getUi().getObjectOperation() : getUi().getSupportVesselName()
|
|
| 83 |
+ @Override
|
|
| 84 |
+ protected void installExtraActions() {
|
|
| 85 |
+ super.installExtraActions();
|
|
| 86 |
+ FloatingObjectUIAddFloatingObjectPreset.init(ui, ui.getAddPreset(), FloatingObjectUIAddFloatingObjectPreset.class);
|
|
| 87 |
+ }
|
|
| 88 |
+//FIXME:Focus ui.getModel().getStates().isCreatingMode() ? getUi().getObjectOperation() : getUi().getSupportVesselName()
|
|
| 83 | 89 |
|
| 84 | 90 |
@Override
|
| 85 | 91 |
public void onOpenForm(Form<?> form) {
|
| 86 | 92 |
|
| 87 | 93 |
FloatingObjectUIModel model = getModel();
|
| 88 | 94 |
|
| 89 |
- Optional<FloatingObjectPreset> floatingObjectReference = model.getStates().getReference();
|
|
| 95 |
+ FloatingObjectPreset floatingObjectReference = model.getStates().getReference();
|
|
| 90 | 96 |
|
| 91 | 97 |
FloatingObjectDto bean = model.getStates().getBean();
|
| 92 | 98 |
|
| ... | ... | @@ -98,7 +104,7 @@ public class FloatingObjectUIHandler extends GeneratedFloatingObjectUIHandler { |
| 98 | 104 |
TypeTransmittingBuoyOperation typeTransmittingBuoyOperation = bean.getTypeTransmittingBuoyOperation();
|
| 99 | 105 |
ui.getTypeOperation().setSelectedItem(typeTransmittingBuoyOperation);
|
| 100 | 106 |
|
| 101 |
- ui.getTable().openTable(model, bean.isPersisted() || floatingObjectReference.isPresent());
|
|
| 107 |
+ ui.getTable().openTable(model, bean.isPersisted() || floatingObjectReference != null);
|
|
| 102 | 108 |
|
| 103 | 109 |
Optional.ofNullable(bean.getFirstBuoy()).ifPresent(b -> b.copy(getUi().getTransmittingBuoy1()));
|
| 104 | 110 |
Optional.ofNullable(bean.getSecondBuoy()).ifPresent(b -> b.copy(getUi().getTransmittingBuoy2()));
|
| ... | ... | @@ -22,33 +22,12 @@ package fr.ird.observe.client.datasource.editor.ps.data.observation; |
| 22 | 22 |
* #L%
|
| 23 | 23 |
*/
|
| 24 | 24 |
|
| 25 |
-import fr.ird.observe.client.ClientUIContext;
|
|
| 26 | 25 |
import fr.ird.observe.client.WithClientUIContext;
|
| 27 |
-import fr.ird.observe.client.datasource.dcp.FloatingObjectPresetsManager;
|
|
| 28 |
-import fr.ird.observe.client.datasource.editor.ps.ObservePsKeyStrokes;
|
|
| 26 |
+import fr.ird.observe.client.datasource.editor.ps.data.observation.dcp.UsePresetAction;
|
|
| 29 | 27 |
import fr.ird.observe.dto.data.ps.dcp.FloatingObjectPreset;
|
| 30 |
-import fr.ird.observe.dto.data.ps.dcp.FloatingObjectPresetModel;
|
|
| 31 | 28 |
import fr.ird.observe.dto.data.ps.observation.FloatingObjectDto;
|
| 32 |
-import fr.ird.observe.dto.decoration.WithDecoratorService;
|
|
| 33 | 29 |
import fr.ird.observe.dto.form.Form;
|
| 34 | 30 |
import fr.ird.observe.services.ObserveServicesProvider;
|
| 35 |
-import org.apache.logging.log4j.LogManager;
|
|
| 36 |
-import org.apache.logging.log4j.Logger;
|
|
| 37 |
- |
|
| 38 |
-import javax.swing.AbstractAction;
|
|
| 39 |
-import javax.swing.JButton;
|
|
| 40 |
-import javax.swing.JComponent;
|
|
| 41 |
-import javax.swing.JOptionPane;
|
|
| 42 |
-import javax.swing.JPanel;
|
|
| 43 |
-import javax.swing.KeyStroke;
|
|
| 44 |
-import java.awt.Font;
|
|
| 45 |
-import java.awt.GridLayout;
|
|
| 46 |
-import java.awt.event.ActionEvent;
|
|
| 47 |
-import java.util.Objects;
|
|
| 48 |
-import java.util.Set;
|
|
| 49 |
- |
|
| 50 |
-import static fr.ird.observe.client.datasource.editor.api.content.referential.usage.UsageUIHandlerSupport.findButton;
|
|
| 51 |
-import static io.ultreia.java4all.i18n.I18n.t;
|
|
| 52 | 31 |
|
| 53 | 32 |
/**
|
| 54 | 33 |
* Created on 9/28/14.
|
| ... | ... | @@ -58,36 +37,6 @@ import static io.ultreia.java4all.i18n.I18n.t; |
| 58 | 37 |
*/
|
| 59 | 38 |
public class FloatingObjectUIModel extends GeneratedFloatingObjectUIModel implements WithClientUIContext {
|
| 60 | 39 |
|
| 61 |
- private static final Logger log = LogManager.getLogger(FloatingObjectUIModel.class);
|
|
| 62 |
- |
|
| 63 |
- public static class UsePresetAction extends AbstractAction implements WithDecoratorService {
|
|
| 64 |
- |
|
| 65 |
- private final FloatingObjectPreset preset;
|
|
| 66 |
- private final KeyStroke keyStroke;
|
|
| 67 |
- private JOptionPane pane;
|
|
| 68 |
- |
|
| 69 |
- public UsePresetAction(FloatingObjectPreset preset, int index) {
|
|
| 70 |
- this.preset = Objects.requireNonNull(preset);
|
|
| 71 |
- this.keyStroke = Objects.requireNonNull(KeyStroke.getKeyStroke("F" + index));
|
|
| 72 |
- putValue(UsePresetAction.class.getName(), getClass().getName() + "_" + index);
|
|
| 73 |
- putValue(NAME, getDecoratorService().getDecoratorByType(preset.getClass()).toString(preset));
|
|
| 74 |
- }
|
|
| 75 |
- |
|
| 76 |
- public void install(JButton parent, JOptionPane pane) {
|
|
| 77 |
- this.pane = pane;
|
|
| 78 |
- String actionMapKey = (String) getValue(UsePresetAction.class.getName());
|
|
| 79 |
- pane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, actionMapKey);
|
|
| 80 |
- pane.getActionMap().put(actionMapKey, this);
|
|
| 81 |
- ObservePsKeyStrokes.addKeyStroke(parent, keyStroke);
|
|
| 82 |
- }
|
|
| 83 |
- |
|
| 84 |
- @Override
|
|
| 85 |
- public void actionPerformed(ActionEvent e) {
|
|
| 86 |
- log.info(String.format("Choose dcp preset: %s", preset.getLabel1()));
|
|
| 87 |
- pane.setValue(preset);
|
|
| 88 |
- }
|
|
| 89 |
- }
|
|
| 90 |
- |
|
| 91 | 40 |
public FloatingObjectUIModel(FloatingObjectUINavigationNode source) {
|
| 92 | 41 |
super(source);
|
| 93 | 42 |
}
|
| ... | ... | @@ -95,50 +44,16 @@ public class FloatingObjectUIModel extends GeneratedFloatingObjectUIModel implem |
| 95 | 44 |
@Override
|
| 96 | 45 |
public void open() {
|
| 97 | 46 |
FloatingObjectUIModelStates states = getStates();
|
| 98 |
- if (states.getReference().isPresent()) {
|
|
| 99 |
- log.info(String.format("%s Will use dcp preset: %s", getPrefix(), states.getReference()));
|
|
| 100 |
- }
|
|
| 101 | 47 |
super.open();
|
| 102 | 48 |
if (states.isCreatingMode()) {
|
| 103 |
- FloatingObjectPreset reference = chooseFloatingObjectPreset();
|
|
| 49 |
+ FloatingObjectPreset reference = UsePresetAction.chooseFloatingObjectPreset(getClientUIContext());
|
|
| 104 | 50 |
states.setReference(reference);
|
| 105 | 51 |
}
|
| 106 | 52 |
}
|
| 107 | 53 |
|
| 108 | 54 |
@Override
|
| 109 | 55 |
public Form<FloatingObjectDto> preCreateForm(ObserveServicesProvider servicesProvider, String parentId) {
|
| 110 |
- return servicesProvider.getPsObservationFloatingObjectService().preCreate2(parentId, getStates().getReference().orElse(null));
|
|
| 111 |
- }
|
|
| 112 |
- |
|
| 113 |
- private FloatingObjectPreset chooseFloatingObjectPreset() {
|
|
| 114 |
- |
|
| 115 |
- FloatingObjectPresetsManager floatingObjectPresetsManager = getClientUIContext().getFloatingObjectPresetsManager();
|
|
| 116 |
- Set<FloatingObjectPreset> psObservation = floatingObjectPresetsManager.getPresets(FloatingObjectPresetModel.ps_observation);
|
|
| 117 |
- if (!psObservation.isEmpty()) {
|
|
| 118 |
- |
|
| 119 |
- JPanel userConfigs = new JPanel(new GridLayout(0, 2));
|
|
| 120 |
- |
|
| 121 |
- String replaceText = t("observe.ui.choice.dcp.default") + " (Enter)";
|
|
| 122 |
- Object[] options = {replaceText};
|
|
| 123 |
- JOptionPane pane = new JOptionPane(userConfigs, JOptionPane.QUESTION_MESSAGE, JOptionPane.DEFAULT_OPTION, null, options, options[0]);
|
|
| 124 |
- JButton jButton = Objects.requireNonNull(findButton(pane, replaceText));
|
|
| 125 |
- Font font = jButton.getFont().deriveFont(18f);
|
|
| 126 |
- jButton.setFont(font.deriveFont(Font.ITALIC));
|
|
| 127 |
- int index = 0;
|
|
| 128 |
- for (FloatingObjectPreset preset : psObservation) {
|
|
| 129 |
- UsePresetAction a = new UsePresetAction(preset, ++index);
|
|
| 130 |
- JButton b = new JButton(a);
|
|
| 131 |
- b.setFont(font);
|
|
| 132 |
- userConfigs.add(b);
|
|
| 133 |
- a.install(b, pane);
|
|
| 134 |
- }
|
|
| 135 |
- ClientUIContext.askUser(pane, t("observe.data.ps.observation.FloatingObjectReference.choose.title"), options);
|
|
| 136 |
- Object value = pane.getValue();
|
|
| 137 |
- if (value instanceof FloatingObjectPreset) {
|
|
| 138 |
- return (FloatingObjectPreset) value;
|
|
| 139 |
- }
|
|
| 140 |
- }
|
|
| 141 |
- return null;
|
|
| 56 |
+ return servicesProvider.getPsObservationFloatingObjectService().preCreate2(parentId, getStates().getReference());
|
|
| 142 | 57 |
}
|
| 143 | 58 |
|
| 144 | 59 |
}
|
| ... | ... | @@ -153,8 +153,8 @@ public class FloatingObjectUIModelStates extends GeneratedFloatingObjectUIModelS |
| 153 | 153 |
return whenLeaving.get(dto);
|
| 154 | 154 |
}
|
| 155 | 155 |
|
| 156 |
- public Optional<FloatingObjectPreset> getReference() {
|
|
| 157 |
- return Optional.ofNullable(reference);
|
|
| 156 |
+ public FloatingObjectPreset getReference() {
|
|
| 157 |
+ return reference;
|
|
| 158 | 158 |
}
|
| 159 | 159 |
|
| 160 | 160 |
public void setReference(FloatingObjectPreset reference) {
|
| ... | ... | @@ -24,8 +24,9 @@ package fr.ird.observe.client.datasource.editor.ps.data.observation.actions; |
| 24 | 24 |
|
| 25 | 25 |
import fr.ird.observe.client.ClientUIContext;
|
| 26 | 26 |
import fr.ird.observe.client.datasource.dcp.FloatingObjectPresetsManager;
|
| 27 |
+import fr.ird.observe.client.datasource.editor.api.ObserveKeyStrokesEditorApi;
|
|
| 28 |
+import fr.ird.observe.client.datasource.editor.api.content.actions.ConfigureMenuAction;
|
|
| 27 | 29 |
import fr.ird.observe.client.datasource.editor.api.content.actions.ContentUIActionSupport;
|
| 28 |
-import fr.ird.observe.client.datasource.editor.api.content.actions.InsertMenuAction;
|
|
| 29 | 30 |
import fr.ird.observe.client.datasource.editor.ps.data.dcp.presets.FloatingObjectPresetUI;
|
| 30 | 31 |
import fr.ird.observe.client.datasource.editor.ps.data.observation.FloatingObjectUI;
|
| 31 | 32 |
import fr.ird.observe.client.util.UIHelper;
|
| ... | ... | @@ -51,13 +52,14 @@ import static io.ultreia.java4all.i18n.I18n.t; |
| 51 | 52 |
*
|
| 52 | 53 |
* @author Tony Chemit - dev@tchemit.fr
|
| 53 | 54 |
*/
|
| 54 |
-public class FloatingObjectUIAddFloatingObjectPreset extends ContentUIActionSupport<FloatingObjectUI> implements InsertMenuAction<FloatingObjectUI> {
|
|
| 55 |
+public class FloatingObjectUIAddFloatingObjectPreset extends ContentUIActionSupport<FloatingObjectUI> implements ConfigureMenuAction<FloatingObjectUI> {
|
|
| 55 | 56 |
|
| 56 | 57 |
private static final Logger log = LogManager.getLogger(FloatingObjectUIAddFloatingObjectPreset.class);
|
| 57 | 58 |
|
| 58 | 59 |
public FloatingObjectUIAddFloatingObjectPreset() {
|
| 59 | 60 |
super(t("observe.data.ps.observation.FloatingObjectReference.action.add"),
|
| 60 |
- t("observe.data.ps.observation.FloatingObjectReference.action.add.tip"), "add-preset", null);
|
|
| 61 |
+ t("observe.data.ps.observation.FloatingObjectReference.action.add.tip"), "add-preset",
|
|
| 62 |
+ ObserveKeyStrokesEditorApi.KEY_STROKE_ADD_PRESET);
|
|
| 61 | 63 |
}
|
| 62 | 64 |
|
| 63 | 65 |
@Override
|
| 1 |
+package fr.ird.observe.client.datasource.editor.ps.data.observation.dcp;
|
|
| 2 |
+ |
|
| 3 |
+/*-
|
|
| 4 |
+ * #%L
|
|
| 5 |
+ * ObServe Client :: DataSource :: Editor :: PS
|
|
| 6 |
+ * %%
|
|
| 7 |
+ * Copyright (C) 2008 - 2021 IRD, Code Lutin, Ultreia.io
|
|
| 8 |
+ * %%
|
|
| 9 |
+ * This program is free software: you can redistribute it and/or modify
|
|
| 10 |
+ * it under the terms of the GNU General Public License as
|
|
| 11 |
+ * published by the Free Software Foundation, either version 3 of the
|
|
| 12 |
+ * License, or (at your option) any later version.
|
|
| 13 |
+ *
|
|
| 14 |
+ * This program is distributed in the hope that it will be useful,
|
|
| 15 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
| 16 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
| 17 |
+ * GNU General Public License for more details.
|
|
| 18 |
+ *
|
|
| 19 |
+ * You should have received a copy of the GNU General Public
|
|
| 20 |
+ * License along with this program. If not, see
|
|
| 21 |
+ * <http://www.gnu.org/licenses/gpl-3.0.html>.
|
|
| 22 |
+ * #L%
|
|
| 23 |
+ */
|
|
| 24 |
+ |
|
| 25 |
+import fr.ird.observe.client.ClientUIContext;
|
|
| 26 |
+import fr.ird.observe.client.WithClientUIContext;
|
|
| 27 |
+import fr.ird.observe.client.datasource.dcp.FloatingObjectPresetsManager;
|
|
| 28 |
+import fr.ird.observe.client.datasource.editor.api.ObserveKeyStrokesEditorApi;
|
|
| 29 |
+import fr.ird.observe.client.datasource.editor.ps.ObservePsKeyStrokes;
|
|
| 30 |
+import fr.ird.observe.dto.data.ps.dcp.FloatingObjectPreset;
|
|
| 31 |
+import fr.ird.observe.dto.data.ps.dcp.FloatingObjectPresetModel;
|
|
| 32 |
+import fr.ird.observe.dto.decoration.WithDecoratorService;
|
|
| 33 |
+import org.apache.logging.log4j.LogManager;
|
|
| 34 |
+import org.apache.logging.log4j.Logger;
|
|
| 35 |
+ |
|
| 36 |
+import javax.swing.AbstractAction;
|
|
| 37 |
+import javax.swing.JButton;
|
|
| 38 |
+import javax.swing.JComponent;
|
|
| 39 |
+import javax.swing.JOptionPane;
|
|
| 40 |
+import javax.swing.JPanel;
|
|
| 41 |
+import javax.swing.KeyStroke;
|
|
| 42 |
+import java.awt.Font;
|
|
| 43 |
+import java.awt.GridLayout;
|
|
| 44 |
+import java.awt.event.ActionEvent;
|
|
| 45 |
+import java.util.Objects;
|
|
| 46 |
+import java.util.Set;
|
|
| 47 |
+ |
|
| 48 |
+import static fr.ird.observe.client.datasource.editor.api.content.referential.usage.UsageUIHandlerSupport.findButton;
|
|
| 49 |
+import static io.ultreia.java4all.i18n.I18n.t;
|
|
| 50 |
+ |
|
| 51 |
+/**
|
|
| 52 |
+ * Created on 17/02/2021.
|
|
| 53 |
+ *
|
|
| 54 |
+ * @author Tony Chemit - dev@tchemit.fr
|
|
| 55 |
+ * @since 8.0.6
|
|
| 56 |
+ */
|
|
| 57 |
+public class UsePresetAction extends AbstractAction implements WithDecoratorService {
|
|
| 58 |
+ private static final Logger log = LogManager.getLogger(UsePresetAction.class);
|
|
| 59 |
+ private final FloatingObjectPreset preset;
|
|
| 60 |
+ private final KeyStroke keyStroke;
|
|
| 61 |
+ private JOptionPane pane;
|
|
| 62 |
+ |
|
| 63 |
+ public static FloatingObjectPreset chooseFloatingObjectPreset(ClientUIContext context) {
|
|
| 64 |
+ |
|
| 65 |
+ FloatingObjectPresetsManager floatingObjectPresetsManager = context.getFloatingObjectPresetsManager();
|
|
| 66 |
+ Set<FloatingObjectPreset> psObservation = floatingObjectPresetsManager.getPresets(FloatingObjectPresetModel.ps_observation);
|
|
| 67 |
+ if (!psObservation.isEmpty()) {
|
|
| 68 |
+ |
|
| 69 |
+ JPanel userConfigs = new JPanel(new GridLayout(0, 2));
|
|
| 70 |
+ |
|
| 71 |
+ String replaceText = ObserveKeyStrokesEditorApi.suffixTextWithKeyStroke(t("observe.ui.choice.dcp.default"), KeyStroke.getKeyStroke("pressed ENTER"));
|
|
| 72 |
+ Object[] options = {replaceText};
|
|
| 73 |
+ JOptionPane pane = new JOptionPane(userConfigs, JOptionPane.QUESTION_MESSAGE, JOptionPane.DEFAULT_OPTION, null, options, options[0]);
|
|
| 74 |
+ JButton jButton = Objects.requireNonNull(findButton(pane, replaceText));
|
|
| 75 |
+ Font font = jButton.getFont().deriveFont(18f);
|
|
| 76 |
+ jButton.setFont(font.deriveFont(Font.ITALIC));
|
|
| 77 |
+ int index = 0;
|
|
| 78 |
+ for (FloatingObjectPreset preset : psObservation) {
|
|
| 79 |
+ UsePresetAction a = new UsePresetAction(preset, ++index);
|
|
| 80 |
+ JButton b = new JButton(a);
|
|
| 81 |
+ b.setFont(font);
|
|
| 82 |
+ userConfigs.add(b);
|
|
| 83 |
+ a.install(b, pane);
|
|
| 84 |
+ }
|
|
| 85 |
+ ClientUIContext.askUser(pane, t("observe.data.ps.observation.FloatingObjectReference.choose.title"), options);
|
|
| 86 |
+ Object value = pane.getValue();
|
|
| 87 |
+ if (value instanceof FloatingObjectPreset) {
|
|
| 88 |
+ return (FloatingObjectPreset) value;
|
|
| 89 |
+ }
|
|
| 90 |
+ }
|
|
| 91 |
+ return null;
|
|
| 92 |
+ }
|
|
| 93 |
+ |
|
| 94 |
+ public UsePresetAction(FloatingObjectPreset preset, int index) {
|
|
| 95 |
+ this.preset = Objects.requireNonNull(preset);
|
|
| 96 |
+ this.keyStroke = Objects.requireNonNull(KeyStroke.getKeyStroke("F" + index));
|
|
| 97 |
+ putValue(UsePresetAction.class.getName(), getClass().getName() + "_" + index);
|
|
| 98 |
+ putValue(NAME, getDecoratorService().getDecoratorByType(preset.getClass()).toString(preset));
|
|
| 99 |
+ }
|
|
| 100 |
+ |
|
| 101 |
+ public void install(JButton parent, JOptionPane pane) {
|
|
| 102 |
+ this.pane = pane;
|
|
| 103 |
+ String actionMapKey = (String) getValue(UsePresetAction.class.getName());
|
|
| 104 |
+ pane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(keyStroke, actionMapKey);
|
|
| 105 |
+ pane.getActionMap().put(actionMapKey, this);
|
|
| 106 |
+ ObservePsKeyStrokes.addKeyStroke(parent, keyStroke);
|
|
| 107 |
+ }
|
|
| 108 |
+ |
|
| 109 |
+ @Override
|
|
| 110 |
+ public void actionPerformed(ActionEvent e) {
|
|
| 111 |
+ log.info(String.format("Choose dcp preset: %s", preset.getLabel1()));
|
|
| 112 |
+ pane.setValue(preset);
|
|
| 113 |
+ }
|
|
| 114 |
+}
|
| 1 | 1 |
observe.Id.comment
|
| 2 |
+observe.Id.coordinate
|
|
| 2 | 3 |
observe.Id.country
|
| 3 | 4 |
observe.Id.description
|
| 4 | 5 |
observe.Id.gearCharacteristic
|
| ... | ... | @@ -93,4 +93,8 @@ public class ActivityReference extends GeneratedActivityReference { |
| 93 | 93 |
public void setFloatingObject(ImmutableList<FloatingObjectReference> floatingObject) {
|
| 94 | 94 |
this.floatingObject = floatingObject;
|
| 95 | 95 |
}
|
| 96 |
+ |
|
| 97 |
+ public final boolean isEmptyNode() {
|
|
| 98 |
+ return getSet() == null && (floatingObject == null || floatingObject.isEmpty());
|
|
| 99 |
+ }
|
|
| 96 | 100 |
}
|
| ... | ... | @@ -69,6 +69,7 @@ public class ObserveI18nLabelsBuilder extends BeanPropertyI18nKeyProducerSupport |
| 69 | 69 |
n("validator.scope.info.label");
|
| 70 | 70 |
n("validator.scope.warning.label");
|
| 71 | 71 |
n("observe.Id.comment");
|
| 72 |
+ n("observe.Id.coordinate");
|
|
| 72 | 73 |
n("observe.Id.country");
|
| 73 | 74 |
n("observe.Id.homeId");
|
| 74 | 75 |
n("observe.Id.sex");
|
| ... | ... | @@ -130,7 +131,16 @@ public class ObserveI18nLabelsBuilder extends BeanPropertyI18nKeyProducerSupport |
| 130 | 131 |
if (latitude == null || longitude == null) {
|
| 131 | 132 |
return t("observe.common.no.coordinate");
|
| 132 | 133 |
}
|
| 133 |
- return String.format("(%s°;%s°)", Numbers.roundThreeDigits(latitude), Numbers.roundThreeDigits(longitude));
|
|
| 134 |
+ return String.format("(%s°;%s°)", fillCoordinateComponent(2,latitude), fillCoordinateComponent(3,longitude));
|
|
| 135 |
+ }
|
|
| 136 |
+ |
|
| 137 |
+ public static String fillCoordinateComponent(int integerPartDigit, Float component) {
|
|
| 138 |
+ boolean withSign = component<0;
|
|
| 139 |
+ String round = String.valueOf(Numbers.roundThreeDigits(component));
|
|
| 140 |
+ int index = round.indexOf(".");
|
|
| 141 |
+ return (withSign?"-":" ")
|
|
| 142 |
+ +StringUtils.leftPad(round.substring(0,index).replace("-", ""), integerPartDigit, "0")
|
|
| 143 |
+ + StringUtils.rightPad(round.substring(index), 5, "0");
|
|
| 134 | 144 |
}
|
| 135 | 145 |
|
| 136 | 146 |
public ObserveI18nLabelsBuilder() {
|
| ... | ... | @@ -182,6 +192,7 @@ public class ObserveI18nLabelsBuilder extends BeanPropertyI18nKeyProducerSupport |
| 182 | 192 |
.put("quadrant", idDtoPrefix)
|
| 183 | 193 |
.put("whenArriving", idDtoPrefix)
|
| 184 | 194 |
.put("whenLeaving", idDtoPrefix)
|
| 195 |
+ .put("coordinate", idDtoPrefix)
|
|
| 185 | 196 |
|
| 186 | 197 |
.put("species", referentialDtoPrefix)
|
| 187 | 198 |
.put(ReferentialDto.PROPERTY_URI, referentialDtoPrefix)
|
| 1 |
+package fr.ird.observe.dto.decoration;
|
|
| 2 |
+ |
|
| 3 |
+/*-
|
|
| 4 |
+ * #%L
|
|
| 5 |
+ * ObServe Models :: Dto :: Java
|
|
| 6 |
+ * %%
|
|
| 7 |
+ * Copyright (C) 2008 - 2021 IRD, Code Lutin, Ultreia.io
|
|
| 8 |
+ * %%
|
|
| 9 |
+ * This program is free software: you can redistribute it and/or modify
|
|
| 10 |
+ * it under the terms of the GNU General Public License as
|
|
| 11 |
+ * published by the Free Software Foundation, either version 3 of the
|
|
| 12 |
+ * License, or (at your option) any later version.
|
|
| 13 |
+ *
|
|
| 14 |
+ * This program is distributed in the hope that it will be useful,
|
|
| 15 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
| 16 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
| 17 |
+ * GNU General Public License for more details.
|
|
| 18 |
+ *
|
|
| 19 |
+ * You should have received a copy of the GNU General Public
|
|
| 20 |
+ * License along with this program. If not, see
|
|
| 21 |
+ * <http://www.gnu.org/licenses/gpl-3.0.html>.
|
|
| 22 |
+ * #L%
|
|
| 23 |
+ */
|
|
| 24 |
+ |
|
| 25 |
+import org.junit.Assert;
|
|
| 26 |
+import org.junit.Test;
|
|
| 27 |
+ |
|
| 28 |
+/**
|
|
| 29 |
+ * Created on 17/02/2021.
|
|
| 30 |
+ *
|
|
| 31 |
+ * @author Tony Chemit - dev@tchemit.fr
|
|
| 32 |
+ * @since 8.0.6
|
|
| 33 |
+ */
|
|
| 34 |
+public class ObserveI18nLabelsBuilderTest {
|
|
| 35 |
+ |
|
| 36 |
+ @Test
|
|
| 37 |
+ public void fillCoordinateComponent() {
|
|
| 38 |
+ assertFillCoordinateComponent(1.02f, " 001.0200");
|
|
| 39 |
+ assertFillCoordinateComponent(-1.02f, "-001.0200");
|
|
| 40 |
+ assertFillCoordinateComponent(-10.02f, "-010.0200");
|
|
| 41 |
+ assertFillCoordinateComponent(-10.032f, "-010.0320");
|
|
| 42 |
+ assertFillCoordinateComponent(10.032f, " 010.0320");
|
|
| 43 |
+ assertFillCoordinateComponent(-100.0321f,"-100.0321");
|
|
| 44 |
+ }
|
|
| 45 |
+ |
|
| 46 |
+ private void assertFillCoordinateComponent(Float component, String excepted) {
|
|
| 47 |
+ String actual = ObserveI18nLabelsBuilder.fillCoordinateComponent(3,component);
|
|
| 48 |
+ Assert.assertEquals(excepted, actual);
|
|
| 49 |
+ }
|
|
| 50 |
+}
|
| ... | ... | @@ -147,7 +147,7 @@ |
| 147 | 147 |
<maven.build.timestamp.format>dd/MM/yyyy HH:mm z</maven.build.timestamp.format>
|
| 148 | 148 |
<buildDate>${maven.build.timestamp}</buildDate>
|
| 149 | 149 |
|
| 150 |
- <toolkit.version>5.0.3</toolkit.version>
|
|
| 150 |
+ <toolkit.version>5.0.4-SNAPSHOT</toolkit.version>
|
|
| 151 | 151 |
|
| 152 | 152 |
<lib.version.ognl>3.1.28</lib.version.ognl>
|
| 153 | 153 |
<!--can't use 1.4.197 (date has changed + blob also)-->
|
| 1 | 1 |
boolean.false=No
|
| 2 | 2 |
boolean.true=Yes
|
| 3 | 3 |
observe.Id.comment=Comment
|
| 4 |
+observe.Id.coordinate=Coordinate
|
|
| 4 | 5 |
observe.Id.country=Country
|
| 5 | 6 |
observe.Id.description=Description
|
| 6 |
-observe.Id.gearCharacteristic=Caracteristic
|
|
| 7 |
+observe.Id.gearCharacteristic=Characteristic
|
|
| 7 | 8 |
observe.Id.homeId=Home id
|
| 8 | 9 |
observe.Id.latitude=Latitude
|
| 9 | 10 |
observe.Id.longitude=Longitude
|
| ... | ... | @@ -45,9 +46,9 @@ observe.constant.NonTargetCatchReleaseStatus.P=Perfect |
| 45 | 46 |
observe.constant.NonTargetCatchReleaseStatus.S=Bad
|
| 46 | 47 |
observe.constant.NonTargetCatchReleaseStatus.U=Unknown
|
| 47 | 48 |
observe.constant.ObserveModelType.LL=Longline
|
| 48 |
-observe.constant.ObserveModelType.LL.description=Display Palangre's programs
|
|
| 49 |
+observe.constant.ObserveModelType.LL.description=Display Longline programs
|
|
| 49 | 50 |
observe.constant.ObserveModelType.PS=Seine
|
| 50 |
-observe.constant.ObserveModelType.PS.description=Display Seine's programs
|
|
| 51 |
+observe.constant.ObserveModelType.PS.description=Display Senne programs
|
|
| 51 | 52 |
observe.constant.TripMapPointType.llActivityLogbook=Logbook - Other activity
|
| 52 | 53 |
observe.constant.TripMapPointType.llActivityLogbookInHarbour=Logbook - At Harbour
|
| 53 | 54 |
observe.constant.TripMapPointType.llActivityLogbookWithHaulingEnd=Logbook - Hauling end
|
| 1 | 1 |
boolean.false=No
|
| 2 | 2 |
boolean.true=Si
|
| 3 | 3 |
observe.Id.comment=Commentario
|
| 4 |
+observe.Id.coordinate=Coordinate \#TODO
|
|
| 4 | 5 |
observe.Id.country=País
|
| 5 | 6 |
observe.Id.description=Descripción
|
| 6 | 7 |
observe.Id.gearCharacteristic=Característica
|
| 1 | 1 |
boolean.false=Non
|
| 2 | 2 |
boolean.true=Oui
|
| 3 | 3 |
observe.Id.comment=Commentaire
|
| 4 |
+observe.Id.coordinate=Coordonnées
|
|
| 4 | 5 |
observe.Id.country=Pays
|
| 5 | 6 |
observe.Id.description=Description
|
| 6 | 7 |
observe.Id.gearCharacteristic=Caractéristique
|