...
 
Commits (9)
## Sprint 89 - v3.9.7
- Pas de mise à jour de modèle
## Sprint 88 - v3.9.5 & v3.9.6
- Pas de mise à jour de modèle
......
......@@ -10,7 +10,7 @@
<groupId>fr.ifremer.reefdb</groupId>
<artifactId>reefdb</artifactId>
<version>3.9.6</version>
<version>3.9.7</version>
<packaging>pom</packaging>
<name>Reef DB</name>
......@@ -171,7 +171,7 @@
<maven.compiler.debug>true</maven.compiler.debug>
<!-- Quadrige3 Core version -->
<quadrige3-core.version>3.6.11</quadrige3-core.version>
<quadrige3-core.version>3.6.13</quadrige3-core.version>
<!-- Last ReefDb launcher version -->
<launcherVersion>3.0.3</launcherVersion>
......
......@@ -4,7 +4,7 @@
<parent>
<groupId>fr.ifremer.reefdb</groupId>
<artifactId>reefdb</artifactId>
<version>3.9.6</version>
<version>3.9.7</version>
</parent>
<artifactId>reefdb-core</artifactId>
......
......@@ -35,7 +35,7 @@
# Please fill the missing licenses for dependencies :
#
#
#Fri Mar 06 16:15:32 CET 2020
#Mon Mar 23 12:33:10 CET 2020
com.oracle--ojdbc7--12.1.0.2.0=OTN license
commons-primitives--commons-primitives--1.0=The Apache Software License, Version 2.0
dom4j--dom4j--1.6.1=BSD License
......
......@@ -905,9 +905,9 @@ public final class ReefDbConfiguration extends QuadrigeCoreConfiguration {
String configOption = applicationConfig.getOption(ReefDbConfigurationOption.PMFM_IDS_TRANSITION_LENGTH.getKey());
if (StringUtils.isBlank(configOption)) return result;
List<String> triplets = Splitter.on(";").splitToList(configOption);
List<String> triplets = Splitter.on(";").omitEmptyStrings().splitToList(configOption);
for (String triplet : triplets) {
List<String> pmfmsIdsStr = Splitter.on(",").splitToList(triplet);
List<String> pmfmsIdsStr = Splitter.on(",").omitEmptyStrings().trimResults().splitToList(triplet);
if (CollectionUtils.size(pmfmsIdsStr) == 3) {
try {
Integer[] pmfmIds = new Integer[3];
......
......@@ -42,6 +42,7 @@ import fr.ifremer.reefdb.dto.configuration.programStrategy.PmfmStrategyDTO;
import fr.ifremer.reefdb.dto.configuration.programStrategy.ProgramDTO;
import fr.ifremer.reefdb.dto.data.measurement.MeasurementAware;
import fr.ifremer.reefdb.dto.data.measurement.MeasurementDTO;
import fr.ifremer.reefdb.dto.data.sampling.SamplingOperationDTO;
import fr.ifremer.reefdb.dto.data.survey.CampaignDTO;
import fr.ifremer.reefdb.dto.data.survey.SurveyDTO;
import fr.ifremer.reefdb.dto.enums.*;
......@@ -90,36 +91,6 @@ public class ReefDbBeans extends QuadrigeBeans {
}
}
/**
* <p>computeAddress.</p>
*
* @param street a {@link String} object.
* @param zipCode a {@link String} object.
* @param city a {@link String} object.
* @return a {@link String} object.
*/
public static String computeAddress(String street, String zipCode, String city) {
StringBuilder addressBuilder = new StringBuilder();
if (StringUtils.isNotBlank(street)) {
addressBuilder.append(street.replaceAll("[ ]+", " "));
if (StringUtils.isNotBlank(zipCode) || StringUtils.isNotBlank(city)) {
addressBuilder.append(", ");
}
}
if (StringUtils.isNotBlank(zipCode)) {
addressBuilder.append(zipCode);
if (StringUtils.isNotBlank(city)) {
addressBuilder.append(" ");
}
}
if (StringUtils.isNotBlank(city)) {
addressBuilder.append(city);
}
return addressBuilder.toString();
}
public static String toQuotedString(String string) {
return "'" + string.replaceAll("'", "''") + "'";
}
......@@ -189,6 +160,47 @@ public class ReefDbBeans extends QuadrigeBeans {
return bean.toString();
}
public static List<MeasurementDTO> duplicate(List<MeasurementDTO> measurements) {
if (measurements == null)
return new ArrayList<>();
return measurements.stream().map(ReefDbBeans::duplicate).collect(Collectors.toList());
}
public static MeasurementDTO duplicate(MeasurementDTO measurement) {
// Clone object
MeasurementDTO clone = clone(measurement);
// Remove Id & individualId
clone.setId(null);
clone.setIndividualId(null);
// remove errors
clone.setErrors(null);
return clone;
}
public static SamplingOperationDTO duplicate(final SamplingOperationDTO samplingOperation) {
// Clone object
final SamplingOperationDTO clone = clone(samplingOperation);
// Remove ID
clone.setId(null);
// clone coordinate
clone.setCoordinate(clone(samplingOperation.getCoordinate()));
// remove errors
clone.setErrors(null);
// duplicate measurements
clone.setMeasurements(duplicate(samplingOperation.getMeasurements()));
clone.setIndividualMeasurements(duplicate(samplingOperation.getIndividualMeasurements()));
return clone;
}
/**
* <p>filterNotEmptyAppliedPeriod.</p>
*
......
......@@ -26,7 +26,6 @@ package fr.ifremer.reefdb.service.observation;
import fr.ifremer.quadrige3.core.ProgressionCoreModel;
import fr.ifremer.reefdb.dto.configuration.programStrategy.ProgStratDTO;
import fr.ifremer.reefdb.dto.configuration.programStrategy.ProgramDTO;
import fr.ifremer.reefdb.dto.data.measurement.MeasurementDTO;
import fr.ifremer.reefdb.dto.data.sampling.SamplingOperationDTO;
import fr.ifremer.reefdb.dto.data.survey.CampaignDTO;
import fr.ifremer.reefdb.dto.data.survey.SurveyDTO;
......@@ -128,24 +127,6 @@ public interface ObservationService {
@PreAuthorize("hasPermission(null, T(fr.ifremer.quadrige3.core.security.QuadrigeUserAuthority).USER)")
SurveyDTO duplicateSurvey(SurveyDTO survey, boolean fullDuplication, boolean copyCoordinates, boolean duplicateSurveyMeasurements);
/**
* Duplicate prelevement.
*
* @param samplingOperation Prelevement to duplicate
* @return Prelvement duplicated
*/
@PreAuthorize("hasPermission(null, T(fr.ifremer.quadrige3.core.security.QuadrigeUserAuthority).USER)")
SamplingOperationDTO duplicateSamplingOperation(SamplingOperationDTO samplingOperation);
/**
* Duplicate a list of measurements.
*
* @param measurements Measurements to duplicate
* @return Measurements duplicate
*/
@PreAuthorize("hasPermission(null, T(fr.ifremer.quadrige3.core.security.QuadrigeUserAuthority).USER)")
List<MeasurementDTO> duplicateMeasurements(List<MeasurementDTO> measurements);
/**
* <p>getAvailablePrograms.</p>
*
......
......@@ -538,59 +538,6 @@ public class ObservationServiceImpl implements ObservationInternalService {
}
/**
* {@inheritDoc}
*/
@Override
public SamplingOperationDTO duplicateSamplingOperation(final SamplingOperationDTO samplingOperation) {
// Duplicate sampling operation
final SamplingOperationDTO duplicatedSamplingOperation = ReefDbBeans.clone(samplingOperation);
// Remove ID
duplicatedSamplingOperation.setId(null);
// duplicate coordinate
duplicatedSamplingOperation.setCoordinate(ReefDbBeans.clone(samplingOperation.getCoordinate()));
// remove errors
duplicatedSamplingOperation.setErrors(null);
// duplicate measurements
duplicatedSamplingOperation.setMeasurements(duplicateMeasurements(samplingOperation.getMeasurements()));
duplicatedSamplingOperation.setIndividualMeasurements(duplicateMeasurements(samplingOperation.getIndividualMeasurements()));
return duplicatedSamplingOperation;
}
/**
* {@inheritDoc}
*/
@Override
public List<MeasurementDTO> duplicateMeasurements(List<MeasurementDTO> measurements) {
List<MeasurementDTO> duplicatedMeasurements = Lists.newArrayList();
if (CollectionUtils.isNotEmpty(measurements)) {
for (MeasurementDTO measurement : measurements) {
// duplicated measurement
final MeasurementDTO duplicatedMeasurement = ReefDbBeans.clone(measurement);
// Remove Id & individualId
duplicatedMeasurement.setId(null);
duplicatedMeasurement.setIndividualId(null);
// remove errors
duplicatedMeasurement.setErrors(null);
duplicatedMeasurements.add(duplicatedMeasurement);
}
}
return duplicatedMeasurements;
}
/**
* {@inheritDoc}
*/
......
......@@ -4,7 +4,7 @@
<parent>
<groupId>fr.ifremer.reefdb</groupId>
<artifactId>reefdb</artifactId>
<version>3.9.6</version>
<version>3.9.7</version>
</parent>
<artifactId>reefdb-ui-swing</artifactId>
......
......@@ -23,12 +23,15 @@ package fr.ifremer.reefdb.ui.swing.content.home.operation;
* #L%
*/
import fr.ifremer.reefdb.dto.ReefDbBeans;
import fr.ifremer.reefdb.dto.data.sampling.SamplingOperationDTO;
import fr.ifremer.reefdb.ui.swing.action.AbstractReefDbAction;
/**
* Duplicate sampling operation action.
* {@link Deprecated} Use fr.ifremer.reefdb.dto.ReefDbBeans#duplicate(fr.ifremer.reefdb.dto.data.sampling.SamplingOperationDTO) outside an action
*/
@Deprecated
public class DuplicateOperationAction extends AbstractReefDbAction<OperationsTableUIModel, OperationsTableUI, OperationsTableUIHandler> {
/**
......@@ -60,12 +63,10 @@ public class DuplicateOperationAction extends AbstractReefDbAction<OperationsTab
if (operationsTableRowModel != null) {
// Duplicate operation
final SamplingOperationDTO duplicatePrelevement = getContext().getObservationService().duplicateSamplingOperation(operationsTableRowModel.toBean());
if (duplicatePrelevement != null) {
final SamplingOperationDTO duplicateOperation = ReefDbBeans.duplicate(operationsTableRowModel.toBean());
// Add duplicate operation to table
newRow = getModel().addNewRow(duplicatePrelevement);
}
newRow = getModel().addNewRow(duplicateOperation);
}
}
......
......@@ -252,7 +252,7 @@ public class OperationsTableUIHandler extends AbstractReefDbTableUIHandler<Opera
}
// save actual table context before loading new survey
getContext().saveComponentInSwingSession(getTable(), getTableModel().getStateContext());
saveTableState();
// affect new selected survey
getModel().setSurvey(survey);
......@@ -739,7 +739,7 @@ public class OperationsTableUIHandler extends AbstractReefDbTableUIHandler<Opera
forceRevalidateModel();
// restore table state from swing session
getContext().restoreComponentFromSwingSession(getTable());
restoreTableState();
// hide analyst column if no pmfm (Mantis #42619)
// forceColumnVisibleAtLastPosition(OperationsTableModel.ANALYST, notEmpty);
......
......@@ -439,14 +439,12 @@ public class AddOperationTableUIHandler extends AbstractReefDbTableUIHandler<Ope
for (int i = 0; i < nbOperation; i++) {
// Ajout du prelevement dans la liste
final SamplingOperationDTO newOperation = getContext().getObservationService().duplicateSamplingOperation(operation);
if (newOperation != null) {
final SamplingOperationDTO newOperation = ReefDbBeans.duplicate(operation);
operations.add(newOperation);
// do it at creation time
newOperation.setMeasurementsLoaded(true);
}
}
// Ajout des prelevements
getModel().setBeans(operations);
......
package fr.ifremer.reefdb.ui.swing.content.observation.operation.measurement.grouped;
/*
* #%L
* Reef DB :: UI
* $Id:$
* $HeadURL:$
* %%
* Copyright (C) 2014 - 2015 Ifremer
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
import fr.ifremer.reefdb.ui.swing.action.AbstractReefDbAction;
/**
* Action dupliquer mesure (ecran prelevements/mesure).
*/
public class DuplicateOperationMeasurementsAction extends AbstractReefDbAction<OperationMeasurementsGroupedTableUIModel, OperationMeasurementsGroupedTableUI, OperationMeasurementsGroupedTableUIHandler> {
/**
* La ligne ajoutee.
*/
private OperationMeasurementsGroupedRowModel row;
/**
* Constrcuteur.
*
* @param handler Controller
*/
public DuplicateOperationMeasurementsAction(final OperationMeasurementsGroupedTableUIHandler handler) {
super(handler, false);
}
/** {@inheritDoc} */
@Override
public boolean prepareAction() throws Exception {
return super.prepareAction() && getModel().getSelectedRows().size() == 1;
}
/** {@inheritDoc} */
@Override
public void doAction() {
// Selected measurement
final OperationMeasurementsGroupedRowModel rowToDuplicate = getModel().getSelectedRows().iterator().next();
if (rowToDuplicate != null) {
row = new OperationMeasurementsGroupedRowModel(false);
row.setSamplingOperation(rowToDuplicate.getSamplingOperation());
row.setTaxonGroup(rowToDuplicate.getTaxonGroup());
row.setTaxon(rowToDuplicate.getTaxon());
row.setInputTaxonId(rowToDuplicate.getInputTaxonId());
row.setInputTaxonName(rowToDuplicate.getInputTaxonName());
row.setComment(rowToDuplicate.getComment());
row.setIndividualPmfms(rowToDuplicate.getIndividualPmfms());
// add also analyst (MAntis #45054)
row.setAnalyst(rowToDuplicate.getAnalyst());
// duplicate measurements by service
row.setIndividualMeasurements(getContext().getObservationService().duplicateMeasurements(rowToDuplicate.getIndividualMeasurements()));
}
}
/** {@inheritDoc} */
@Override
public void postSuccessAction() {
super.postSuccessAction();
// Add duplicate measurement to table
getModel().insertRowAfterSelected(row);
// save directly to sampling operation
getHandler().saveMeasurementsInModel(row);
// send update event on sampling operation
if (row.getSamplingOperation() != null) {
getModel().firePropertyChanged(OperationMeasurementsGroupedTableUIModel.PROPERTY_SAMPLING_OPERATION, null, row.getSamplingOperation());
}
getHandler().recomputeRowsValidState();
getModel().setModify(true);
// Ajouter le focus sur la cellule de la ligne cree
getHandler().setFocusOnCell(row);
}
}
......@@ -60,7 +60,7 @@
<JPanel id='tableauBasPanelButtons' layout='{new BorderLayout()}' constraints="BorderLayout.PAGE_END">
<JPanel layout='{new FlowLayout()}' constraints='BorderLayout.LINE_START'>
<JButton id='addButton' alignmentX='{Component.CENTER_ALIGNMENT}' onActionPerformed="model.insertNewRowAfterSelected()"/>
<JButton id='duplicateButton' alignmentX='{Component.CENTER_ALIGNMENT}'/>
<JButton id='duplicateButton' alignmentX='{Component.CENTER_ALIGNMENT}' onActionPerformed="handler.duplicateSelectedRow()"/>
<JButton id='initDataGridButton' alignmentX='{Component.CENTER_ALIGNMENT}' onActionPerformed="handler.initializeDataGrid()"/>
<JButton id='multiEditButton' alignmentX='{Component.CENTER_ALIGNMENT}' onActionPerformed="handler.editSelectedMeasurements()"/>
<JButton id='deleteButton' alignmentX='{Component.CENTER_ALIGNMENT}' onActionPerformed="handler.removeIndividualMeasurements()"/>
......
......@@ -52,7 +52,6 @@
actionIcon: copy;
text: "reefdb.action.duplicate.label";
toolTipText: "reefdb.action.duplicate.measurement.tip";
_applicationAction: {DuplicateOperationMeasurementsAction.class};
enabled: {model.getSurvey().isEditable() && !model.getSelectedRows().isEmpty() && (model.getSelectedRows().size() == 1) && !model.getPmfms().isEmpty()};
}
......
......@@ -150,6 +150,22 @@ public class OperationMeasurementsGroupedTableUIHandler
// update some controls
getUI().processDataBinding(OperationMeasurementsGroupedTableUI.BINDING_INIT_DATA_GRID_BUTTON_ENABLED);
break;
// TODO ? force sort on sampling operation and transition column
// case OperationMeasurementsGroupedTableUIModel.PROPERTY_PIT_TRANSITION_LENGTH_PMFM_ID:
//
// // Try to apply sort on sampling operation and transition column
// if (getModel().getPitTransitionLengthPmfmId() != null) {
// TableColumnExt samplingColumn = getTable().getColumnExt(OperationMeasurementsGroupedTableModel.SAMPLING);
// PmfmTableColumn transitionColumn = findPmfmColumnByPmfmId(getModel().getPmfmColumns(), getModel().getPitTransitionLengthPmfmId());
// if (samplingColumn != null && transitionColumn != null) {
// getTable().getRowSorter().setSortKeys(ImmutableList.of(
// new RowSorter.SortKey(samplingColumn.getModelIndex(), SortOrder.ASCENDING),
// new RowSorter.SortKey(transitionColumn.getModelIndex(), SortOrder.ASCENDING)
// ));
// }
// }
// break;
}
});
......@@ -185,11 +201,10 @@ public class OperationMeasurementsGroupedTableUIHandler
@Override
protected List<? extends MeasurementAware> getMeasurementAwareModels() {
List<SamplingOperationDTO> samplingOperations = Lists.newArrayList(getModel().getSamplingOperations());
return getModel().getSamplingOperations().stream()
// sort by name
samplingOperations.sort(Comparator.comparing(SamplingOperationDTO::getName));
return samplingOperations;
.sorted(Comparator.comparing(SamplingOperationDTO::getName))
.collect(Collectors.toList());
}
@Override
......@@ -205,7 +220,7 @@ public class OperationMeasurementsGroupedTableUIHandler
@Override
protected void onRowModified(int rowIndex, OperationMeasurementsGroupedRowModel row, String propertyName, Integer propertyIndex, Object oldValue, Object newValue) {
// update individual id when sampling operation changes
// when sampling operation changes
if (OperationMeasurementsGroupedRowModel.PROPERTY_SAMPLING_OPERATION.equals(propertyName)) {
// remove measurement from old sampling
......@@ -235,6 +250,14 @@ public class OperationMeasurementsGroupedTableUIHandler
super.onRowModified(rowIndex, row, propertyName, propertyIndex, oldValue, newValue);
}
@Override
protected void onDuplicatedRowAdded(OperationMeasurementsGroupedRowModel row) {
// send update event on sampling operation
if (row.getSamplingOperation() != null) {
getModel().firePropertyChanged(OperationMeasurementsGroupedTableUIModel.PROPERTY_SAMPLING_OPERATION, null, row.getSamplingOperation());
}
}
@Override
protected void resetIndividualMeasurementIds(OperationMeasurementsGroupedRowModel row) {
......@@ -421,15 +444,14 @@ public class OperationMeasurementsGroupedTableUIHandler
for (Integer transition : initModel.getResultMap().get(samplingOperation)) {
// Compute next individual id
incrementNextIndividualId(samplingOperation, individualId);
OperationMeasurementsGroupedRowModel row = getTableModel().createNewRow();
// Initialize the row
row.setSamplingOperation(samplingOperation);
// Affect individual pmfms from parent model
row.setIndividualPmfms(new ArrayList<>(getModel().getPmfms()));
OperationMeasurementsGroupedRowModel row = createNewRow(false, samplingOperation);
// Set the individualId
row.setIndividualId(individualId.get());
// Affect individual pmfms from parent model
row.setIndividualPmfms(new ArrayList<>(getModel().getPmfms()));
// Create empty measurements
ReefDbBeans.createEmptyMeasurements(row);
// Get the measurement
......@@ -452,14 +474,6 @@ public class OperationMeasurementsGroupedTableUIHandler
}
}
private void incrementNextIndividualId(SamplingOperationDTO samplingOperation, AtomicInteger nextIndividualId) {
do {
nextIndividualId.incrementAndGet();
} while (getModel().getRows().stream().anyMatch(row ->
samplingOperation.equals(row.getSamplingOperation()) && nextIndividualId.get() == row.getIndividualId()));
}
public void editSelectedMeasurements() {
OperationMeasurementsMultiEditUI editUI = new OperationMeasurementsMultiEditUI(getUI());
......
......@@ -44,6 +44,7 @@ public class OperationMeasurementsGroupedTableUIModel
* property identifier used to propagate row sampling operation property change to parent
*/
public static final String PROPERTY_SAMPLING_OPERATION = "samplingOperation";
public static final String PROPERTY_PIT_TRANSITION_LENGTH_PMFM_ID = "pitTransitionLengthPmfmId";
// pmfm ids for grid initialization (pit protocol)
private Integer pitTransectOriginPmfmId;
......@@ -85,6 +86,7 @@ public class OperationMeasurementsGroupedTableUIModel
public void setPitTransitionLengthPmfmId(Integer pitTransitionLengthPmfmId) {
this.pitTransitionLengthPmfmId = pitTransitionLengthPmfmId;
firePropertyChange(PROPERTY_PIT_TRANSITION_LENGTH_PMFM_ID, null, pitTransitionLengthPmfmId);
}
public boolean isPitTransitionGridInitializationEnabled() {
......
......@@ -170,7 +170,7 @@ public class OperationMeasurementsUngroupedTableUIHandler extends AbstractReefDb
filterSamplingOperations();
// restore table from swing session
getContext().restoreComponentFromSwingSession(getTable());
restoreTableState();
// hide analyst if no pmfm
// forceColumnVisibleAtLastPosition(OperationMeasurementsUngroupedTableModel.ANALYST, notEmpty);
......
......@@ -30,6 +30,7 @@ import com.google.common.collect.Maps;
import fr.ifremer.quadrige3.core.dao.technical.Assert;
import fr.ifremer.quadrige3.core.dao.technical.factorization.pmfm.AllowedQualitativeValuesMap;
import fr.ifremer.quadrige3.ui.core.dto.DirtyAware;
import fr.ifremer.quadrige3.ui.swing.table.SwingTable;
import fr.ifremer.quadrige3.ui.swing.table.editor.ExtendedComboBoxCellEditor;
import fr.ifremer.reefdb.decorator.DecoratorService;
import fr.ifremer.reefdb.dto.ErrorDTO;
......@@ -50,6 +51,7 @@ import fr.ifremer.reefdb.dto.referential.TaxonGroupDTO;
import fr.ifremer.reefdb.dto.referential.pmfm.PmfmDTO;
import fr.ifremer.reefdb.dto.referential.pmfm.QualitativeValueDTO;
import fr.ifremer.reefdb.ui.swing.content.observation.operation.measurement.grouped.OperationMeasurementsGroupedRowModel;
import fr.ifremer.reefdb.ui.swing.util.OneShotListener;
import fr.ifremer.reefdb.ui.swing.util.ReefDbUI;
import fr.ifremer.reefdb.ui.swing.util.table.AbstractReefDbTableUIHandler;
import fr.ifremer.reefdb.ui.swing.util.table.PmfmTableColumn;
......@@ -95,6 +97,14 @@ public abstract class AbstractMeasurementsGroupedTableUIHandler<
super(properties);
}
@Override
protected String[] getRowPropertiesToIgnore() {
return new String[]{
AbstractMeasurementsGroupedRowModel.PROPERTY_INPUT_TAXON_ID,
AbstractMeasurementsGroupedRowModel.PROPERTY_INPUT_TAXON_NAME
};
}
@Override
public void beforeInit(UI ui) {
super.beforeInit(ui);
......@@ -288,7 +298,7 @@ public abstract class AbstractMeasurementsGroupedTableUIHandler<
filterMeasurements();
// restore table from swing session
getContext().restoreComponentFromSwingSession(getTable());
restoreTableState();
// hide analyst if no pmfm
// forceColumnVisibleAtLastPosition(AbstractMeasurementsGroupedTableModel.ANALYST, notEmpty);
......@@ -313,9 +323,11 @@ public abstract class AbstractMeasurementsGroupedTableUIHandler<
List<? extends MeasurementAware> measurementAwareBeans = getMeasurementAwareModels();
for (MeasurementAware bean : measurementAwareBeans) {
List<MeasurementDTO> measurements = Lists.newArrayList(bean.getIndividualMeasurements());
List<MeasurementDTO> measurements = bean.getIndividualMeasurements().stream()
// sort by individual id
measurements.sort(Comparator.comparingInt(MeasurementDTO::getIndividualId));
.sorted(Comparator.comparingInt(MeasurementDTO::getIndividualId))
.collect(Collectors.toList());
R row = null;
for (final MeasurementDTO measurement : measurements) {
......@@ -438,10 +450,14 @@ public abstract class AbstractMeasurementsGroupedTableUIHandler<
}
// set default analyst from pmfm strategies (Mantis #42619)
setDefaultAnalyst(ImmutableList.of(newRow));
setDefaultAnalyst(newRow);
// now calculate individual id
// now calculate individual id after table is sorted
if (getTable().getRowSorter().getSortKeys().isEmpty()) {
calculateIndividualIds(newRow);
} else {
OneShotListener.create(getTable(), SwingTable.PROPERTY_SORTED, propertyChangeEvent -> calculateIndividualIds(newRow));
}
// reset the cell editors
resetCellEditors();
......@@ -458,6 +474,10 @@ public abstract class AbstractMeasurementsGroupedTableUIHandler<
}
}
protected void setDefaultAnalyst(R row) {
setDefaultAnalyst(Collections.singleton(row));
}
protected void setDefaultAnalyst(Collection<R> rows) {
if (CollectionUtils.isEmpty(rows))
......@@ -473,25 +493,47 @@ public abstract class AbstractMeasurementsGroupedTableUIHandler<
protected void calculateIndividualIds(R rowToUpdate) {
MeasurementAware bean = getMeasurementAwareModelForRow(rowToUpdate);
calculateIndividualIds(getMeasurementAwareModelForRow(rowToUpdate));
}
protected void calculateIndividualIds(MeasurementAware bean) {
if (bean == null) return;
Predicate<? super R> predicate = getRowForBeanPredicate(bean);
AtomicInteger individualId = new AtomicInteger();
// iterate over all ordered rows and set incremental individualId
getModel().getRows().stream().filter(getRowForBeanPredicate(bean)).forEach(row -> {
// iterate over sorted rows and set incremental individualId (see Mantis #51520)
for (int i = 0; i < getTable().getRowCount(); i++) {
R row = getTableModel().getEntry(getTable().convertRowIndexToModel(i));
if (predicate.test(row)) {
// increment and set row individual id
row.setIndividualId(individualId.incrementAndGet());
// update all individual measurements
if (CollectionUtils.isNotEmpty(row.getIndividualMeasurements())) {
for (MeasurementDTO individualMeasurement : row.getIndividualMeasurements()) {
individualMeasurement.setIndividualId(individualId.get());
row.getIndividualMeasurements().forEach(measurement -> measurement.setIndividualId(individualId.get()));
}
}
});
setDirty(bean);
}
/**
* Increment the nextIndividualId to next unused individual id in rows
*
* @param bean the current bean
* @param nextIndividualId the counter to increment
*/
protected void incrementNextIndividualId(MeasurementAware bean, AtomicInteger nextIndividualId) {
do {
nextIndividualId.incrementAndGet();
} while (getModel().getRows().stream()
.filter(getRowForBeanPredicate(bean))
.anyMatch(row -> Objects.equals(nextIndividualId.get(), row.getIndividualId())));
Assert.isTrue(nextIndividualId.get() > 0, "the next individual id must be > 0");
}
/**
* return a predicate to tell if the row is associated to the bean (true by default)
*
......@@ -648,12 +690,20 @@ public abstract class AbstractMeasurementsGroupedTableUIHandler<
if (askBeforeDelete(t("reefdb.action.delete.survey.measurement.titre"), t("reefdb.action.delete.survey.measurement.message"))) {
// Get distinct models to update after rows removed
Collection<MeasurementAware> modelsToUpdate = getModel().getSelectedRows().stream()
.map(this::getMeasurementAwareModelForRow)
.collect(Collectors.toSet());
// Remove from table
getModel().deleteSelectedRows();
// Remove from model
removeIndividualMeasurements(measurementToDelete);
// Recalculate individual ids
modelsToUpdate.forEach(this::calculateIndividualIds);
recomputeRowsValidState();
}
......@@ -661,6 +711,40 @@ public abstract class AbstractMeasurementsGroupedTableUIHandler<
protected abstract void removeIndividualMeasurements(List<MeasurementDTO> measurementToDelete);
public void duplicateSelectedRow() {
if (getModel().getSelectedRows().size() == 1 && getModel().getSingleSelectedRow() != null) {
R rowToDuplicate = getModel().getSingleSelectedRow();
R row = createNewRow(false, getMeasurementAwareModelForRow(rowToDuplicate));
row.setTaxonGroup(rowToDuplicate.getTaxonGroup());
row.setTaxon(rowToDuplicate.getTaxon());
row.setInputTaxonId(rowToDuplicate.getInputTaxonId());
row.setInputTaxonName(rowToDuplicate.getInputTaxonName());
row.setComment(rowToDuplicate.getComment());
row.setIndividualPmfms(rowToDuplicate.getIndividualPmfms());
// add also analyst (MAntis #45054)
row.setAnalyst(rowToDuplicate.getAnalyst());
// duplicate measurements
row.setIndividualMeasurements(ReefDbBeans.duplicate(rowToDuplicate.getIndividualMeasurements()));
// Add duplicate measurement to table
getModel().insertRowAfterSelected(row);
// save directly to sampling operation
saveMeasurementsInModel(row);
onDuplicatedRowAdded(row);
recomputeRowsValidState();
getModel().setModify(true);
setFocusOnCell(row);
}
}
protected void onDuplicatedRowAdded(R row) {
// nothing by default
}
/* validation section */
/**
......@@ -1130,7 +1214,7 @@ public abstract class AbstractMeasurementsGroupedTableUIHandler<
*/
protected void editSelectedMeasurements(JDialog dialog) {
// save current table state to be able to restore it in dialog's table
saveTableInSwingSession();
saveTableState();
Assert.isInstanceOf(ReefDbUI.class, dialog);
ReefDbUI<?, ?> multiEditUI = (ReefDbUI<?, ?>) dialog;
......
package fr.ifremer.reefdb.ui.swing.content.observation.survey.measurement.grouped;
/*
* #%L
* Reef DB :: UI
* $Id:$
* $HeadURL:$
* %%
* Copyright (C) 2014 - 2015 Ifremer
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
import fr.ifremer.reefdb.ui.swing.action.AbstractReefDbAction;
/**
* Action dupliquer mesure (ecran observation/mesure).
*/
public class DuplicateSurveyMeasurementsAction extends AbstractReefDbAction<SurveyMeasurementsGroupedTableUIModel, SurveyMeasurementsGroupedTableUI, SurveyMeasurementsGroupedTableUIHandler> {
/**
* La ligne ajoutee.
*/
private SurveyMeasurementsGroupedRowModel row;
/**
* Constrcuteur.
*
* @param handler Controller
*/
public DuplicateSurveyMeasurementsAction(final SurveyMeasurementsGroupedTableUIHandler handler) {
super(handler, false);
}
/** {@inheritDoc} */
@Override
public boolean prepareAction() throws Exception {
return super.prepareAction() && getModel().getSelectedRows().size() == 1;
}
/** {@inheritDoc} */
@Override
public void doAction() {
// Selected measurement
final SurveyMeasurementsGroupedRowModel rowToDuplicate = getModel().getSelectedRows().iterator().next();
if (rowToDuplicate != null) {
row = new SurveyMeasurementsGroupedRowModel(false);
row.setTaxonGroup(rowToDuplicate.getTaxonGroup());
row.setTaxon(rowToDuplicate.getTaxon());
row.setInputTaxonId(rowToDuplicate.getInputTaxonId());
row.setInputTaxonName(rowToDuplicate.getInputTaxonName());
row.setComment(rowToDuplicate.getComment());
row.setIndividualPmfms(rowToDuplicate.getIndividualPmfms());
// add also analyst (MAntis #45054)
row.setAnalyst(rowToDuplicate.getAnalyst());
// duplicate measurements by service
row.setIndividualMeasurements(getContext().getObservationService().duplicateMeasurements(rowToDuplicate.getIndividualMeasurements()));
}
}
/** {@inheritDoc} */
@Override
public void postSuccessAction() {
super.postSuccessAction();
// Add duplicate measurement to table
getModel().insertRowAfterSelected(row);
// save directly to sampling operation
getHandler().saveMeasurementsInModel(row);
getHandler().recomputeRowsValidState();
getModel().setModify(true);
// Ajouter le focus sur la cellule de la ligne cree
getHandler().setFocusOnCell(row);
}
}
......@@ -60,7 +60,7 @@
<JPanel id='tableauBasPanelButtons' layout='{new BorderLayout()}' constraints="BorderLayout.PAGE_END">
<JPanel layout='{new FlowLayout()}' constraints='BorderLayout.LINE_START'>
<JButton id='newButton' alignmentX='{Component.CENTER_ALIGNMENT}' onActionPerformed="model.insertNewRowAfterSelected()"/>
<JButton id='duplicateButton' alignmentX='{Component.CENTER_ALIGNMENT}'/>
<JButton id='duplicateButton' alignmentX='{Component.CENTER_ALIGNMENT}' onActionPerformed="handler.duplicateSelectedRow()"/>
<JButton id='multiEditButton' alignmentX='{Component.CENTER_ALIGNMENT}' onActionPerformed="handler.editSelectedMeasurements()"/>
<JButton id='deleteButton' alignmentX='{Component.CENTER_ALIGNMENT}' onActionPerformed="handler.removeIndividualMeasurements()"/>
</JPanel>
......
......@@ -52,7 +52,6 @@
actionIcon: copy;
text: "reefdb.action.duplicate.label";
toolTipText: "reefdb.action.duplicate.measurement.tip";
_applicationAction: {DuplicateSurveyMeasurementsAction.class};
enabled: {model.getSurvey().isEditable() && !model.getSelectedRows().isEmpty() && (model.getSelectedRows().size() == 1) && !model.getPmfms().isEmpty()};
}
......
......@@ -172,7 +172,7 @@ public class SurveyMeasurementsUngroupedTableUIHandler
recomputeRowsValidState();
// restore table from swing session
getContext().restoreComponentFromSwingSession(getTable());
restoreTableState();
// hide analyst if no pmfm
// forceColumnVisibleAtLastPosition(SurveyMeasurementsUngroupedTableModel.ANALYST, notEmpty);
......
package fr.ifremer.reefdb.ui.swing.util;
/*-
* #%L
* Reef DB :: UI
* $Id:$
* $HeadURL:$
* %%
* Copyright (C) 2014 - 2020 Ifremer
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
import javax.annotation.Nonnull;
import java.awt.Component;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.function.Consumer;
/**
* a PropertyChangeListener that auto remove after fired
*
* @author peck7 on 20/03/2020.
*/
public class OneShotListener implements PropertyChangeListener {
private final Component parent;
private final String propertyName;
private final Consumer<PropertyChangeEvent> consumer;
/**
* Create and add to parent object
*
* @param parent the component on which this listener will be added
* @param propertyName the property to listen to
* @param consumer the consumer function
*/
public static void create(@Nonnull Component parent, @Nonnull String propertyName, @Nonnull Consumer<PropertyChangeEvent> consumer) {
OneShotListener listener = new OneShotListener(parent, propertyName, consumer);
parent.addPropertyChangeListener(propertyName, listener);
}
private OneShotListener(Component parent, String propertyName, Consumer<PropertyChangeEvent> consumer) {
this.parent = parent;
this.propertyName = propertyName;
this.consumer = consumer;
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
consumer.accept(evt);
parent.removePropertyChangeListener(propertyName, this);
}
}
......@@ -31,6 +31,15 @@
</properties>
<body>
<release version="3.9.7" date="2020-03-23" description="Stable release">
<action dev="ludovic.pecquot@e-is.pro" type="fix" issue="51520">
Rework the calculation of individual ids on grouped measurements, now use table sorting if possible
</action>
<action dev="ludovic.pecquot@e-is.pro" type="add">
Upgrade quadrige3-core to version 3.6.13
</action>
</release>
<release version="3.9.6" date="2020-03-06" description="Stable release">
<action dev="ludovic.pecquot@e-is.pro" type="fix" issue="51385">
Upgrade quadrige3-core to version 3.6.11
......
......@@ -108,26 +108,26 @@ Un déploiement sans modification des scripts de Tomcat est possible :
- Décommenté les parties XML suivantes, et renseigner les attributs XML : ``url``, ``username``, ``password``, ``value`` (``/path/to/config/file``) :
> <Resource
> name="quadrige3-ds"
> auth="Container"
> type="javax.sql.DataSource"
> driverClassName="oracle.jdbc.driver.OracleDriver"
> url="jdbc:oracle:thin:@HOST:1521:INSTANCE"
> username="USER"
> password="PWD"
> maxActive="20"
> maxIdle="2"
> maxWait="-1"
> />
>
> <!-- Use to set the configuration file path (default path is: <WAR>/WEB-INF/classes/synchro-server.config) -->
> <Environment
> name="synchro-server.config"
> type="java.lang.String"
> value="/path/to/config/file"
> override="false"
> />
<Resource
name="quadrige3-ds"
auth="Container"
type="javax.sql.DataSource"
driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:@HOST:1521:INSTANCE"
username="USER"
password="PWD"
maxActive="20"
maxIdle="2"
maxWait="-1"
/>
<!-- Use to set the configuration file path (default path is: <WAR>/WEB-INF/classes/synchro-server.config) -->
<Environment
name="synchro-server.config"
type="java.lang.String"
value="/path/to/config/file"
override="false"
/>
- Reconstruire le fichier ``.war``, puis dployer sous Tomcat comme précédemment (sans modifier les scripts de lancement).
......