Author: kmorin Date: 2013-04-18 16:20:46 +0200 (Thu, 18 Apr 2013) New Revision: 820 Url: http://forge.codelutin.com/projects/tutti/repository/revisions/820 Log: - fixes #2009 [RAPPORT] composition du trait - perform release action after postSuccess or postError calls - start replacing messages by i18n keys - refs #1866 [CAPTURE] - Captures accidentelles (validation) - refs #1867 [CAPTURE] - Observations individuelles (validation) Added: trunk/tutti-service/src/main/java/fr/ifremer/tutti/service/catches/ExportCatchesReportService.java trunk/tutti-service/src/main/resources/ftl/ trunk/tutti-service/src/main/resources/ftl/catchesReport_fr.ftl trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/SendCatchesReportAction.java trunk/tutti-ui-swing/src/main/resources/fr/ifremer/tutti/ui/swing/content/operation/catches/accidental/ trunk/tutti-ui-swing/src/main/resources/fr/ifremer/tutti/ui/swing/content/operation/catches/accidental/create/ trunk/tutti-ui-swing/src/main/resources/fr/ifremer/tutti/ui/swing/content/operation/catches/accidental/create/CreateAccidentalBatchUIModel-error-validation.xml Modified: trunk/pom.xml trunk/tutti-service/pom.xml trunk/tutti-service/src/main/java/fr/ifremer/tutti/service/catches/TuttiWeightComputingService.java trunk/tutti-service/src/main/resources/i18n/tutti-service_en_GB.properties trunk/tutti-service/src/main/resources/i18n/tutti-service_fr_FR.properties trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/TuttiUIContext.java trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/UpdateApplicationAction.java trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/ExportProtocolAction.java trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/ImportProtocolAction.java trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/SelectCruiseUI.css trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/SelectCruiseUI.jaxx trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/util/TuttiUIUtil.java trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/util/action/TuttiActionSwingWorker.java trunk/tutti-ui-swing/src/main/resources/fr/ifremer/tutti/ui/swing/content/operation/catches/individualobservation/create/CreateIndividualObservationBatchUIModel-error-validation.xml trunk/tutti-ui-swing/src/main/resources/i18n/tutti-ui-swing_en_GB.properties trunk/tutti-ui-swing/src/main/resources/i18n/tutti-ui-swing_fr_FR.properties Modified: trunk/pom.xml =================================================================== --- trunk/pom.xml 2013-04-18 06:34:25 UTC (rev 819) +++ trunk/pom.xml 2013-04-18 14:20:46 UTC (rev 820) @@ -405,6 +405,27 @@ <scope>test</scope> </dependency> + <dependency> + <groupId>com.itextpdf</groupId> + <artifactId>itextpdf</artifactId> + <version>5.4.1</version> + <scope>compile</scope> + </dependency> + + <dependency> + <groupId>org.xhtmlrenderer</groupId> + <artifactId>flying-saucer-pdf-itext5</artifactId> + <version>9.0.1</version> + <scope>compile</scope> + </dependency> + + <dependency> + <groupId>org.freemarker</groupId> + <artifactId>freemarker</artifactId> + <version>2.3.19</version> + <scope>compile</scope> + </dependency> + </dependencies> </dependencyManagement> Modified: trunk/tutti-service/pom.xml =================================================================== --- trunk/tutti-service/pom.xml 2013-04-18 06:34:25 UTC (rev 819) +++ trunk/tutti-service/pom.xml 2013-04-18 14:20:46 UTC (rev 820) @@ -143,6 +143,21 @@ <artifactId>mockito-core</artifactId> </dependency> + <dependency> + <groupId>com.itextpdf</groupId> + <artifactId>itextpdf</artifactId> + </dependency> + + <dependency> + <groupId>org.xhtmlrenderer</groupId> + <artifactId>flying-saucer-pdf-itext5</artifactId> + </dependency> + + <dependency> + <groupId>org.freemarker</groupId> + <artifactId>freemarker</artifactId> + </dependency> + </dependencies> <build> Added: trunk/tutti-service/src/main/java/fr/ifremer/tutti/service/catches/ExportCatchesReportService.java =================================================================== --- trunk/tutti-service/src/main/java/fr/ifremer/tutti/service/catches/ExportCatchesReportService.java (rev 0) +++ trunk/tutti-service/src/main/java/fr/ifremer/tutti/service/catches/ExportCatchesReportService.java 2013-04-18 14:20:46 UTC (rev 820) @@ -0,0 +1,231 @@ +package fr.ifremer.tutti.service.catches; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.itextpdf.text.DocumentException; +import fr.ifremer.tutti.TuttiBusinessException; +import fr.ifremer.tutti.persistence.entities.data.*; +import fr.ifremer.tutti.persistence.entities.referential.Species; +import fr.ifremer.tutti.service.AbstractTuttiService; +import fr.ifremer.tutti.service.PersistenceService; +import fr.ifremer.tutti.service.TuttiServiceContext; +import freemarker.cache.ClassTemplateLoader; +import freemarker.ext.beans.BeansWrapper; +import freemarker.template.Configuration; +import freemarker.template.Template; +import freemarker.template.TemplateException; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.io.IOUtils; +import org.xhtmlrenderer.pdf.ITextRenderer; + +import java.io.*; +import java.util.*; + +import static org.nuiton.i18n.I18n._; + +/** + * @author kmorin <kmorin@codelutin.com> + * @since 2.0 + */ +public class ExportCatchesReportService extends AbstractTuttiService { + + protected Configuration freemarkerConfiguration; + + protected PersistenceService persistenceService; + + protected TuttiWeightComputingService tuttiWeightComputingService; + + public ExportCatchesReportService() { + super(); + + freemarkerConfiguration = new Configuration(); + + // needed to overwrite "Defaults to default system encoding." + // fix encoding issue on some systems + freemarkerConfiguration.setEncoding(Locale.getDefault(), "UTF-8"); + + // specific template loader to get template from jars (classpath) + ClassTemplateLoader templateLoader = new ClassTemplateLoader(ExportCatchesReportService.class, "/ftl"); + freemarkerConfiguration.setTemplateLoader(templateLoader); + + // pour les maps dans les template (entre autre) + freemarkerConfiguration.setObjectWrapper(new BeansWrapper()); + } + + @Override + public void setServiceContext(TuttiServiceContext context) { + super.setServiceContext(context); + persistenceService = getService(PersistenceService.class); + tuttiWeightComputingService = getService(TuttiWeightComputingService.class); + } + + /** + * Generate the PDF report + * + * @param targetFile pdf file to generate + * @param locale generated pdf locale + * @return the generated file + * @throws TuttiBusinessException + */ + public File generatePDFFile(File targetFile, String cruiseId, Locale locale) throws TuttiBusinessException { + + File result = null; + + OutputStream os = null; + + Map<String, Object> data = Maps.newHashMap(); + + List<FishingOperation> allFishingOperation = + persistenceService.getAllFishingOperation(cruiseId); + + List<Map<String, Object>> operations = Lists.newArrayList(); + for (FishingOperation fishingOperation : allFishingOperation) { + + // get operation and catch data + String fishingOperationId = fishingOperation.getId(); + CatchBatch catchBatch = persistenceService.getCatchBatchFromFishingOperation(fishingOperationId); + + BatchContainer<SpeciesBatch> rootSpeciesBatch; + rootSpeciesBatch = tuttiWeightComputingService.getComputedSpeciesBatches(fishingOperation); + + BatchContainer<BenthosBatch> rootBenthosBatch; + rootBenthosBatch = tuttiWeightComputingService.getComputedBenthosBatches(fishingOperation); + + tuttiWeightComputingService.computeCatchBatchWeights(catchBatch, rootSpeciesBatch, rootBenthosBatch, null); + + // create operation data model + Map<String, Object> op = createOperation(fishingOperation); + + Float totalWeight = catchBatch.getCatchTotalWeight(); + if (totalWeight == null) { + totalWeight = catchBatch.getCatchTotalComputedWeight(); + } + op.put("totalWeight", totalWeight); + + Float totalSortedWeight = catchBatch.getCatchTotalSortedComputedWeight(); + op.put("totalSortedWeight", totalSortedWeight); + + // create catches data model + + Map<Species, Map<String, Object>> catches = Maps.newHashMap(); + Float ratio = totalWeight / totalSortedWeight; + + // create catches rows + List<SpeciesBatch> speciesBatches = rootSpeciesBatch.getChildren(); + for (SpeciesBatch batch : speciesBatches) { + createSpeciesCatch(batch, catches, ratio, totalWeight); + } + List<Map<String, Object>> catchList = Lists.newArrayList(catches.values()); + + // add the benthos row + if (!CollectionUtils.isEmpty(rootBenthosBatch.getChildren())) { + Map<String, Object> benthosCatch = + createBenthosCatch(rootBenthosBatch, catchBatch.getBenthosTotalComputedWeight(), totalWeight); + catchList.add(benthosCatch); + } + + op.put("catches", catchList); + operations.add(op); + } + data.put("operations", operations); + + // generate the report + try { + + // render freemarker template + Template mapTemplate = freemarkerConfiguration.getTemplate("catchesReport.ftl", locale); + + Writer out = new StringWriter(); + mapTemplate.process(data, out); + out.flush(); + + // render template output as pdf + os = new FileOutputStream(targetFile); + + ITextRenderer renderer = new ITextRenderer(); + renderer.setDocumentFromString(out.toString()); + renderer.layout(); + renderer.createPDF(os); + + os.close(); + + } catch (Exception ex) { + throw new TuttiBusinessException(_("tutti.service.operations.exportCatchesReport.error"), ex); + } finally { + IOUtils.closeQuietly(os); + } + + return result; + } + + protected Map<String, Object> createOperation(FishingOperation fishingOperation) { + Map<String, Object> op = Maps.newHashMap(); + op.put("number", fishingOperation.getFishingOperationNumber()); + op.put("station", fishingOperation.getStationNumber()); + op.put("rigNumber", fishingOperation.getMultirigAggregation()); + op.put("startDate", fishingOperation.getGearShootingStartDate()); + op.put("endDate", fishingOperation.getGearShootingEndDate()); + + return op; + } + + protected void createSpeciesCatch(SpeciesBatch batch, + Map<Species, Map<String, Object>> catches, + float ratio, + float totalWeight) { + + Species species = batch.getSpecies(); + + Float existingWeight; + Map<String, Object> ktch = catches.get(species); + if (ktch == null) { + ktch = Maps.newHashMap(); + ktch.put("code", species.getRefTaxCode()); + ktch.put("scientificName", species.getName()); + + Species speciesWithVerncularCode = persistenceService.getSpeciesByReferenceTaxonIdWithVernacularCode(species.getReferenceTaxonId()); + ktch.put("commonName", speciesWithVerncularCode.getVernacularCode()); + + existingWeight = 0f; + + } else { + existingWeight = (Float) ktch.get("sortedWeight"); + } + + Float weight = batch.getSampleCategoryWeight(); + if (weight == null) { + weight = batch.getSampleCategoryComputedWeight(); + } + weight += existingWeight; + + ktch.put("sortedWeight", weight); + Float totalBatchWeight = weight * ratio; + ktch.put("totalWeight", totalBatchWeight); + ktch.put("percentage", 100 * totalBatchWeight / totalWeight); + catches.put(species, ktch); + } + + protected Map<String, Object> createBenthosCatch(BatchContainer<BenthosBatch> rootBenthosBatch, + float benthosTotalWeight, + float totalWeight) { + Map<String, Object> ktch = Maps.newHashMap(); + ktch.put("code", "BENTHOS"); + ktch.put("scientificName", ""); + ktch.put("commonName", "Benthos"); + + Float weight = 0f; + List<BenthosBatch> benthosBatches = rootBenthosBatch.getChildren(); + for (BenthosBatch batch : benthosBatches) { + Float batchWeight = batch.getSampleCategoryWeight(); + if (batchWeight == null) { + batchWeight = batch.getSampleCategoryComputedWeight(); + } + weight += batchWeight; + } + ktch.put("sortedWeight", weight); + ktch.put("totalWeight", benthosTotalWeight); + ktch.put("percentage", 100 * benthosTotalWeight / totalWeight); + + return ktch; + } +} Modified: trunk/tutti-service/src/main/java/fr/ifremer/tutti/service/catches/TuttiWeightComputingService.java =================================================================== --- trunk/tutti-service/src/main/java/fr/ifremer/tutti/service/catches/TuttiWeightComputingService.java 2013-04-18 06:34:25 UTC (rev 819) +++ trunk/tutti-service/src/main/java/fr/ifremer/tutti/service/catches/TuttiWeightComputingService.java 2013-04-18 14:20:46 UTC (rev 820) @@ -209,21 +209,23 @@ Float speciesTotalComputedSortedWeight = 0f; Float speciesTotalComputedUnsortedWeight = 0f; - for (int i = 0; i < rootSpeciesBatch.getChildren().size(); i++) { - SpeciesBatch row = rootSpeciesBatch.getChildren().get(i); - Float weight = row.getSampleCategoryWeight(); - if (weight == null) { - weight = row.getSampleCategoryComputedWeight(); - } - if (weight == null) { - return; - } + if (rootSpeciesBatch != null) { + for (int i = 0; i < rootSpeciesBatch.getChildren().size(); i++) { + SpeciesBatch row = rootSpeciesBatch.getChildren().get(i); + Float weight = row.getSampleCategoryWeight(); + if (weight == null) { + weight = row.getSampleCategoryComputedWeight(); + } + if (weight == null) { + return; + } - CaracteristicQualitativeValue value = (CaracteristicQualitativeValue) row.getSampleCategoryValue(); - if (SortedUnsortedEnum.SORTED.matchValue(value)) { - speciesTotalComputedSortedWeight += weight; - } else { - speciesTotalComputedUnsortedWeight += weight; + CaracteristicQualitativeValue value = (CaracteristicQualitativeValue) row.getSampleCategoryValue(); + if (SortedUnsortedEnum.SORTED.matchValue(value)) { + speciesTotalComputedSortedWeight += weight; + } else { + speciesTotalComputedUnsortedWeight += weight; + } } } @@ -263,21 +265,23 @@ Float benthosTotalComputedSortedWeight = 0f; Float benthosTotalComputedUnsortedWeight = 0f; - for (int i = 0; i < rootBenthosBatch.getChildren().size(); i++) { - BenthosBatch row = rootBenthosBatch.getChildren().get(i); - Float weight = row.getSampleCategoryWeight(); - if (weight == null) { - weight = row.getSampleCategoryComputedWeight(); - } - if (weight == null) { - return; - } + if (rootBenthosBatch != null) { + for (int i = 0; i < rootBenthosBatch.getChildren().size(); i++) { + BenthosBatch row = rootBenthosBatch.getChildren().get(i); + Float weight = row.getSampleCategoryWeight(); + if (weight == null) { + weight = row.getSampleCategoryComputedWeight(); + } + if (weight == null) { + return; + } - CaracteristicQualitativeValue value = (CaracteristicQualitativeValue) row.getSampleCategoryValue(); - if (SortedUnsortedEnum.SORTED.matchValue(value)) { - benthosTotalComputedSortedWeight += weight; - } else { - benthosTotalComputedUnsortedWeight += weight; + CaracteristicQualitativeValue value = (CaracteristicQualitativeValue) row.getSampleCategoryValue(); + if (SortedUnsortedEnum.SORTED.matchValue(value)) { + benthosTotalComputedSortedWeight += weight; + } else { + benthosTotalComputedUnsortedWeight += weight; + } } } @@ -316,14 +320,16 @@ // Marine litter Float marineLitterTotalComputedWeight = 0f; - for (int i = 0; i < rootMarineLitterBatch.getChildren().size(); i++) { - MarineLitterBatch row = rootMarineLitterBatch.getChildren().get(i); - Float rowWeight = row.getWeight(); - if (rowWeight == null) { - marineLitterTotalComputedWeight = null; - break; + if (rootMarineLitterBatch != null) { + for (int i = 0; i < rootMarineLitterBatch.getChildren().size(); i++) { + MarineLitterBatch row = rootMarineLitterBatch.getChildren().get(i); + Float rowWeight = row.getWeight(); + if (rowWeight == null) { + marineLitterTotalComputedWeight = null; + break; + } + marineLitterTotalComputedWeight += rowWeight; } - marineLitterTotalComputedWeight += rowWeight; } catchBatch.setMarineLitterTotalComputedWeight(marineLitterTotalComputedWeight); Added: trunk/tutti-service/src/main/resources/ftl/catchesReport_fr.ftl =================================================================== --- trunk/tutti-service/src/main/resources/ftl/catchesReport_fr.ftl (rev 0) +++ trunk/tutti-service/src/main/resources/ftl/catchesReport_fr.ftl 2013-04-18 14:20:46 UTC (rev 820) @@ -0,0 +1,91 @@ +<html> + <head> + <style type="text/css"> + + <#assign blueColor="#000080"> + + h1, h4 { + color: ${blueColor}; + font-weight: bold; + font-style: italic; + } + + th { + color: ${blueColor}; + font-weight: bold; + } + + td, th { + padding-right: 10pt; + } + + td.number { + text-align: right; + } + + .operationInfo { + font-weight: bold; + } + + .label { + color: ${blueColor}; + } + + .value { + margin-right: 50pt; + } + + </style> + </head> + <body> + + <h1>Rapport des traits validés</h1> + + <#assign orderedOperations = operations?sort_by("startDate")?reverse> + <#list orderedOperations as operation> + + <p class='operationInfo'> + <span class="label">Station :</span> <span class="value">${operation.station} - ${operation.number}</span> + <span class="label">Poche :</span> <span class="value">${operation.rigNumber}</span> + <span class="label"> + du ${operation.startDate?date?string.full} ${operation.startDate?time?string.short} + <#if operation.endDate??>au ${operation.endDate?date?string.full} ${operation.endDate?time?string.short}</#if> + </span> + </p> + + <p class='operationInfo'> + <span class="label">Poids total :</span> <span class="value"><#if operation.totalWeight??>${operation.totalWeight?string("0.00")}</#if></span> + <span class="label">Poids total trié :</span> <#if operation.totalSortedWeight??>${operation.totalSortedWeight?string("0.00")}</#if> + </p> + + <h4>Composition du trait par espèce :</h4> + <table> + <tr> + <th>Espèce</th> + <th>Nom scientifique</th> + <th>Nom commun</th> + <th>Trié (kg)</th> + <th>Total (kg)</th> + <th>%</th> + </tr> + + <#list operation.catches?sort_by("sortedWeight")?reverse as catch> + <tr> + <td><#if catch.code??>${catch.code}</#if></td> + <td><em>${catch.scientificName}</em></td> + <td><#if catch.commonName??>${catch.commonName}</#if></td> + <td class="number">${catch.sortedWeight?string("0.00")}</td> + <td class="number">${catch.totalWeight?string("0.00")}</td> + <td class="number">${catch.percentage?string("0.0")}</td> + </tr> + </#list> + </table> + + <#if operation != orderedOperations?last> + <h2 style="page-break-after:always"/> + </#if> + + </#list> + + </body> +</html> \ No newline at end of file Modified: trunk/tutti-service/src/main/resources/i18n/tutti-service_en_GB.properties =================================================================== --- trunk/tutti-service/src/main/resources/i18n/tutti-service_en_GB.properties 2013-04-18 06:34:25 UTC (rev 819) +++ trunk/tutti-service/src/main/resources/i18n/tutti-service_en_GB.properties 2013-04-18 14:20:46 UTC (rev 820) @@ -81,6 +81,7 @@ tutti.service.operations.computeWeights.species.error.incoherentRowWeightFrequency= tutti.service.operations.computeWeights.species.error.incoherentTotalSorted= tutti.service.operations.computeWeights.species.error.noWeight= +tutti.service.operations.exportCatchesReport.error= tutti.validator.error.comment.too.long= tutti.validator.error.cruise.beginDate.required= tutti.validator.error.cruise.dates.endBeforeStart= Modified: trunk/tutti-service/src/main/resources/i18n/tutti-service_fr_FR.properties =================================================================== --- trunk/tutti-service/src/main/resources/i18n/tutti-service_fr_FR.properties 2013-04-18 06:34:25 UTC (rev 819) +++ trunk/tutti-service/src/main/resources/i18n/tutti-service_fr_FR.properties 2013-04-18 14:20:46 UTC (rev 820) @@ -65,6 +65,7 @@ tutti.service.operations.computeWeights.species.error.incoherentSampleWeight=Le poids de sous-échantillonage d'un lot des espèces est supérieur au poids de la catégorie tutti.service.operations.computeWeights.species.error.incoherentTotalSorted=Le poids total Vrac des espèces est inférieur à la somme des poids Vrac triés, inerte trié et vivant non détaillé trié tutti.service.operations.computeWeights.species.error.noWeight=Un lot des espèces n'a pas de poids +tutti.service.operations.exportCatchesReport.error=Erreur lors de la génération du rapport des captures tutti.validator.error.comment.too.long=Taille de commentaire trop longue (limitée à %s caractères) tutti.validator.error.cruise.beginDate.required=La date de début est obligatoire tutti.validator.error.cruise.dates.endBeforeStart=La date de fin doit être après la date de début Modified: trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/TuttiUIContext.java =================================================================== --- trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/TuttiUIContext.java 2013-04-18 06:34:25 UTC (rev 819) +++ trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/TuttiUIContext.java 2013-04-18 14:20:46 UTC (rev 820) @@ -31,6 +31,7 @@ import fr.ifremer.tutti.TuttiTechnicalException; import fr.ifremer.tutti.persistence.RessourceClassLoader; import fr.ifremer.tutti.service.*; +import fr.ifremer.tutti.service.catches.ExportCatchesReportService; import fr.ifremer.tutti.service.catches.TuttiWeightComputingService; import fr.ifremer.tutti.service.catches.ValidateCruiseOperationsService; import fr.ifremer.tutti.service.protocol.TuttiProtocolImportExportService; @@ -527,6 +528,10 @@ return serviceContext.getService(ValidationService.class); } + public ExportCatchesReportService getGeneratePDFService() { + return serviceContext.getService(ExportCatchesReportService.class); + } + public boolean useRealPersistenceService() { return isDbExist() && isDbLoaded(); } Modified: trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/UpdateApplicationAction.java =================================================================== --- trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/UpdateApplicationAction.java 2013-04-18 06:34:25 UTC (rev 819) +++ trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/UpdateApplicationAction.java 2013-04-18 14:20:46 UTC (rev 820) @@ -121,7 +121,7 @@ } else { - sendMessage("Aucune mise à jour de l'application détectée."); + sendMessage(_("tutti.updateApplication.noUpdate")); } } } @@ -146,10 +146,8 @@ // tell user restart will be done - getHandler().showSuccessMessage( - "Redémarrage de Tutti nécessaire...", - "La mise à jour nécessite le rédémarrage du Tutti.\nL'application va se fermer puis se réouvrir automatiquement." - ); + getHandler().showSuccessMessage(_("tutti.updateApplication.title.success"), + _("tutti.updateApplication.message.success")); CloseApplicationAction action = TuttiActionHelper.createLogicAction( getHandler(), CloseApplicationAction.class); Modified: trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/ExportProtocolAction.java =================================================================== --- trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/ExportProtocolAction.java 2013-04-18 06:34:25 UTC (rev 819) +++ trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/ExportProtocolAction.java 2013-04-18 14:20:46 UTC (rev 820) @@ -102,8 +102,7 @@ getContext().getTuttiProtocolImportExportService(); service.exportProtocol(protocol, file); - sendMessage("Protocole [" + protocol.getName() + - "] exporté dans le fichier " + file.getName() + "."); + sendMessage(_("tutti.exportProtocol.action.success", protocol.getName(), file.getName())); getHandler().resetEditProtolAction(); } Modified: trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/ImportProtocolAction.java =================================================================== --- trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/ImportProtocolAction.java 2013-04-18 06:34:25 UTC (rev 819) +++ trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/ImportProtocolAction.java 2013-04-18 14:20:46 UTC (rev 820) @@ -97,7 +97,7 @@ getContext().getTuttiProtocolImportExportService(); TuttiProtocol protocol = service.importProtocol(file); - sendMessage("Protocole [" + protocol.getName() + "] lu depuis le fichier."); + sendMessage(_("tutti.importProtocol.action.success", protocol.getName())); // store protocol in context IMPORT_PROTOCOL_ENTRY.setContextValue(getContext().getMainUI(), protocol); Modified: trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/SelectCruiseUI.css =================================================================== --- trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/SelectCruiseUI.css 2013-04-18 06:34:25 UTC (rev 819) +++ trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/SelectCruiseUI.css 2013-04-18 14:20:46 UTC (rev 820) @@ -210,4 +210,15 @@ _tuttiAction: {ValidateCatchesAction.class}; enabled: {model.isValid() && uiContext.isCruiseFilled()}; _help: {"tutti.selectCruise.action.validateCatches.help"}; +} + + +#exportCatchesButton { + actionIcon: validate; + text: "tutti.selectCruise.action.validateCatches"; + toolTipText: "tutti.selectCruise.action.validateCatches.tip"; + i18nMnemonic: "tutti.selectCruise.action.validateCatches.mnemonic"; + _tuttiAction: {ExportCatchesAction.class}; + enabled: {model.isValid() && uiContext.isCruiseFilled()}; + _help: {"tutti.selectCruise.action.validateCatches.help"}; } \ No newline at end of file Modified: trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/SelectCruiseUI.jaxx =================================================================== --- trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/SelectCruiseUI.jaxx 2013-04-18 06:34:25 UTC (rev 819) +++ trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/SelectCruiseUI.jaxx 2013-04-18 14:20:46 UTC (rev 820) @@ -144,6 +144,7 @@ <JPanel layout='{new GridLayout(1,0)}'> <JButton id='editCatchesButton'/> <JButton id='validateCatchesButton'/> + <JButton id='exportCatchesButton'/> </JPanel> </cell> </row> Copied: trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/SendCatchesReportAction.java (from rev 810, trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/ExportProtocolAction.java) =================================================================== --- trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/SendCatchesReportAction.java (rev 0) +++ trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/SendCatchesReportAction.java 2013-04-18 14:20:46 UTC (rev 820) @@ -0,0 +1,91 @@ +package fr.ifremer.tutti.ui.swing.content.home; + +import com.google.common.base.Preconditions; +import fr.ifremer.tutti.TuttiIOUtil; +import fr.ifremer.tutti.persistence.entities.data.Cruise; +import fr.ifremer.tutti.service.catches.ExportCatchesReportService; +import fr.ifremer.tutti.ui.swing.util.TuttiUIUtil; +import fr.ifremer.tutti.ui.swing.util.action.AbstractTuttiAction; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.File; + +import static org.nuiton.i18n.I18n._; + +/** + * Opens a file chooser and exports the protocol into the selected file. + * + * @author tchemit <chemit@codelutin.com> + * @since 1.0 + */ +public class SendCatchesReportAction extends AbstractTuttiAction<SelectCruiseUIModel, SelectCruiseUI, SelectCruiseUIHandler> { + + /** Logger. */ + private static final Log log = + LogFactory.getLog(SendCatchesReportAction.class); + + protected File file; + + public SendCatchesReportAction(SelectCruiseUIHandler handler) { + super(handler, true); + } + + @Override + protected boolean prepareAction() throws Exception { + + boolean doAction = super.prepareAction(); + + if (doAction) { + + // choose file to export + file = TuttiUIUtil.chooseFile( + getContext().getMainUI(), + _("tutti.sendCatchesReport.title.choose.exportFile"), + _("tutti.sendCatchesReport.action.chooseFile"), + "^.+\\.pdf$", _("tutti.common.file.pdf") + ); + doAction = file != null; + if (doAction) { + file = TuttiIOUtil.addExtensionIfMissing(file, ".pdf"); + + // ask user to confirm overwrite. + doAction = getHandler().askOverwriteFile(file); + } + } + return doAction; + } + + @Override + protected void releaseAction() { + file = null; + super.releaseAction(); + } + + @Override + protected void doAction() throws Exception { + Cruise cruise = getModel().getCruise(); + Preconditions.checkNotNull(cruise); + Preconditions.checkNotNull(file); + + if (log.isInfoEnabled()) { + log.info("Will export cruise " + cruise.getId() + + " to file: " + file); + } + + // export catches + ExportCatchesReportService service = + getContext().getGeneratePDFService(); + service.generatePDFFile(file, cruise.getId(), getConfig().getI18nLocale()); + + TuttiUIUtil.mail(_("tutti.sendCatchesReport.mail.subject", cruise.getName()), + _("tutti.sendCatchesReport.mail.body", cruise.getName(), file.getAbsolutePath())); + + } + + @Override + public void postSuccessAction() { + super.postSuccessAction(); + sendMessage(_("tutti.sendCatchesReport.action.success", file.getName())); + } +} Property changes on: trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/SendCatchesReportAction.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Modified: trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/util/TuttiUIUtil.java =================================================================== --- trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/util/TuttiUIUtil.java 2013-04-18 06:34:25 UTC (rev 819) +++ trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/util/TuttiUIUtil.java 2013-04-18 14:20:46 UTC (rev 820) @@ -48,6 +48,7 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.net.URLEncoder; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; @@ -280,6 +281,20 @@ public static void openLink(URI uri) { + Desktop desktop = getDesktopForBrowse(); + + try { + + desktop.browse(uri); + } catch (Exception e) { + + throw new TuttiTechnicalException( + _("swing.error.cannot.open.link", uri), e); + } + } + + public static Desktop getDesktopForMail() { + if (!Desktop.isDesktopSupported()) { throw new TuttiTechnicalException( _("swing.error.desktop.not.supported")); @@ -287,19 +302,27 @@ Desktop desktop = Desktop.getDesktop(); - if (!desktop.isSupported(Desktop.Action.BROWSE)) { + if (!desktop.isSupported(Desktop.Action.MAIL)) { throw new TuttiTechnicalException( - _("swing.error.desktop.browse.not.supported")); + _("swing.error.desktop.mail.not.supported")); } + return desktop; + } + + public static void mail(String subject, String body) { + + Desktop desktop = getDesktopForMail(); + try { + URI mailtoURI = new URI("mailto", null, null, "subject=" + subject + "&body=" + body, null); + desktop.mail(mailtoURI); - desktop.browse(uri); } catch (Exception e) { throw new TuttiTechnicalException( - _("swing.error.cannot.open.link", uri), e); + _("swing.error.cannot.mail"), e); } } Modified: trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/util/action/TuttiActionSwingWorker.java =================================================================== --- trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/util/action/TuttiActionSwingWorker.java 2013-04-18 06:34:25 UTC (rev 819) +++ trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/util/action/TuttiActionSwingWorker.java 2013-04-18 14:20:46 UTC (rev 820) @@ -97,8 +97,6 @@ if (log.isInfoEnabled()) { log.info("Task [" + this + "] done"); } - - action.releaseAction(); } } return null; @@ -122,6 +120,8 @@ action.postFailedAction(error); } + action.releaseAction(); + if (timer != null) { timer.cancel(); Added: trunk/tutti-ui-swing/src/main/resources/fr/ifremer/tutti/ui/swing/content/operation/catches/accidental/create/CreateAccidentalBatchUIModel-error-validation.xml =================================================================== --- trunk/tutti-ui-swing/src/main/resources/fr/ifremer/tutti/ui/swing/content/operation/catches/accidental/create/CreateAccidentalBatchUIModel-error-validation.xml (rev 0) +++ trunk/tutti-ui-swing/src/main/resources/fr/ifremer/tutti/ui/swing/content/operation/catches/accidental/create/CreateAccidentalBatchUIModel-error-validation.xml 2013-04-18 14:20:46 UTC (rev 820) @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE validators PUBLIC + "-//Apache Struts//XWork Validator 1.0.3//EN" + "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> +<validators> + + <field name="species"> + <field-validator type="required" short-circuit="true"> + <message> + tutti.validator.error.createAccidentalBatch.species.required + </message> + </field-validator> + </field> + +</validators> \ No newline at end of file Modified: trunk/tutti-ui-swing/src/main/resources/fr/ifremer/tutti/ui/swing/content/operation/catches/individualobservation/create/CreateIndividualObservationBatchUIModel-error-validation.xml =================================================================== --- trunk/tutti-ui-swing/src/main/resources/fr/ifremer/tutti/ui/swing/content/operation/catches/individualobservation/create/CreateIndividualObservationBatchUIModel-error-validation.xml 2013-04-18 06:34:25 UTC (rev 819) +++ trunk/tutti-ui-swing/src/main/resources/fr/ifremer/tutti/ui/swing/content/operation/catches/individualobservation/create/CreateIndividualObservationBatchUIModel-error-validation.xml 2013-04-18 14:20:46 UTC (rev 820) @@ -29,9 +29,33 @@ <field name="species"> <field-validator type="required" short-circuit="true"> <message> - tutti.validator.error.createIndividualObservationBatch.individualObservationSpecies.required + tutti.validator.error.createIndividualObservationBatch.species.required </message> </field-validator> </field> + <field name="weight"> + <field-validator type="required" short-circuit="true"> + <message> + tutti.validator.error.createIndividualObservationBatch.weight.required + </message> + </field-validator> + </field> + + <field name="size"> + <field-validator type="required" short-circuit="true"> + <message> + tutti.validator.error.createIndividualObservationBatch.size.required + </message> + </field-validator> + </field> + + <field name="lengthStepCaracteristic"> + <field-validator type="required" short-circuit="true"> + <message> + tutti.validator.error.createIndividualObservationBatch.lengthStepCaracteristic.required + </message> + </field-validator> + </field> + </validators> \ No newline at end of file Modified: trunk/tutti-ui-swing/src/main/resources/i18n/tutti-ui-swing_en_GB.properties =================================================================== --- trunk/tutti-ui-swing/src/main/resources/i18n/tutti-ui-swing_en_GB.properties 2013-04-18 06:34:25 UTC (rev 819) +++ trunk/tutti-ui-swing/src/main/resources/i18n/tutti-ui-swing_en_GB.properties 2013-04-18 14:20:46 UTC (rev 820) @@ -1,3 +1,4 @@ +swing.error.cannot.mail= swing.error.cannot.open.file= swing.error.cannot.open.link= swing.error.desktop.browse.not.supported= @@ -2,2 +3,3 @@ swing.error.desktop.extension.not.supported= +swing.error.desktop.mail.not.supported= swing.error.desktop.not.supported= @@ -59,6 +61,7 @@ tutti.common.cancel.mnemonic= tutti.common.file.csv= tutti.common.file.ibts= +tutti.common.file.pdf= tutti.common.file.protocol= tutti.common.file.zip= tutti.common.validate= @@ -823,6 +826,7 @@ tutti.error.errorpane.htmlmessage= tutti.error.ui.business.error= tutti.error.ui.other.error= +tutti.exportProtocol.action.success= tutti.fishingOperations.action.newFishingOperation.mnemonic= tutti.fishingOperations.action.newFishingOperation.tip= tutti.fishingOperations.info.no.fishingOperation.selected= @@ -864,6 +868,7 @@ tutti.gearUseFeatureTable.table.header.key= tutti.gearUseFeatureTable.table.header.value= tutti.gearUseFeatureTable.title= +tutti.importProtocol.action.success= tutti.importPupitri.carrouselFile.extension= tutti.importPupitri.carrouselFile.extension.description= tutti.importPupitri.error.fileMissing.message= @@ -1081,6 +1086,12 @@ tutti.selectSpecies.action.validate.mnemonic= tutti.selectSpecies.action.validate.tip= tutti.selectSpecies.title= +tutti.sendCatchesReport.action.chooseFile= +tutti.sendCatchesReport.action.chooseProtocolFile= +tutti.sendCatchesReport.action.success= +tutti.sendCatchesReport.mail.body= +tutti.sendCatchesReport.mail.subject= +tutti.sendCatchesReport.title.choose.exportFile= tutti.splitBenthosBatch.action.cancel= tutti.splitBenthosBatch.action.cancel.mnemonic= tutti.splitBenthosBatch.action.cancel.tip= @@ -1124,8 +1135,16 @@ tutti.update.i18n= tutti.update.jre= tutti.update.tutti= +tutti.updateApplication.message.success= +tutti.updateApplication.noUpdate= +tutti.updateApplication.title.success= tutti.validator.error.comment.too.long= +tutti.validator.error.createAccidentalBatch.species.required= tutti.validator.error.createIndividualObservationBatch.individualObservationSpecies.required= +tutti.validator.error.createIndividualObservationBatch.lengthStepCaracteristic.required= +tutti.validator.error.createIndividualObservationBatch.size.required= +tutti.validator.error.createIndividualObservationBatch.species.required= +tutti.validator.error.createIndividualObservationBatch.weight.required= tutti.validator.error.createMarineLitterBatch.categoryAndSizeCategory.notAvailable= tutti.validator.error.createMarineLitterBatch.marineLitterCategory.required= tutti.validator.error.createMarineLitterBatch.marineLitterSizeCategory.required= Modified: trunk/tutti-ui-swing/src/main/resources/i18n/tutti-ui-swing_fr_FR.properties =================================================================== --- trunk/tutti-ui-swing/src/main/resources/i18n/tutti-ui-swing_fr_FR.properties 2013-04-18 06:34:25 UTC (rev 819) +++ trunk/tutti-ui-swing/src/main/resources/i18n/tutti-ui-swing_fr_FR.properties 2013-04-18 14:20:46 UTC (rev 820) @@ -1,6 +1,8 @@ +swing.error.cannot.mail=Aucun programme n'est défini pour envoyer des emails. swing.error.cannot.open.file=Aucun programme n'est défini pour ouvrir ce type de fichier. Enregistrez le fichier et ouvrez le en dehors de Tutti. swing.error.cannot.open.link=Impossible d'ouvrir le fichier %s. swing.error.desktop.browse.not.supported=Le navigateur n'a pas pu être ouvert. Vérifiez que vous avez défini un navigateur par défaut dans votre système. +swing.error.desktop.mail.not.supported=Le client mail n'a pas pu être ouvert. Vérifiez que vous avez défini un client mail par défaut dans votre système. swing.error.desktop.not.supported=Votre système ne permet pas d'ouvrir des liens ou fichiers en dehors de Tutti. tutti.about.bottomText=Copyright %s - %s - version %s tutti.about.message=<h3>Tutti</h3><p><strong>Outil de saisie de données d'opérations et de captures au cours des campagnes halieutiques.</strong></p><br/><p>Ce logiciel permettra la saisie en mer des données d'opération de pêche (positions, environnement, engin, etc) et des captures associées (composition de la capture en espèces scientifiques avec poids, nombres, tailles etc) pour l'ensemble des campagnes halieutiques réalisées par l'Ifremer.</p><p>Ce projet a été initiée en 2012 par l'<a href\="http\://www.ifremer.fr">Ifremer</a> et réalisé par la société <a href\="http\://codelutin.com">Codelutin</a>.</p><hr/><br/><p>Pour plus d'informations, vous pouvez visiter le <a href\="http\://maven-site.forge.codelutin.com/tutti">site du projet</a>.</p><p>Projet hébergé sur la forge <a href\="http\://forge.codelutin.com/projects/tutti">Forge.codelutin.com</a>.</p> @@ -56,6 +58,7 @@ tutti.common.cancel=Annuler tutti.common.cancel.mnemonic=A tutti.common.file.csv=Extension d'un fichier csv +tutti.common.file.pdf=Extension d'un fichier pdf tutti.common.file.protocol=Extension d'un fichier de protocole Tutti tutti.common.file.zip=Extension d'une archive zip tutti.common.validate=Valider @@ -824,6 +827,7 @@ tutti.error.errorpane.htmlmessage=<html><body><b>Une erreur s'est produite</b>\:<br/>%s</body></html> tutti.error.ui.business.error=Erreur tutti.error.ui.other.error=Erreur +tutti.exportProtocol.action.success=Protocole [%1s] exporté dans le fichier %2s. tutti.fishingOperations.action.newFishingOperation.mnemonic=N tutti.fishingOperations.action.newFishingOperation.tip=Créer une nouvelle opération de pêche tutti.fishingOperations.info.no.fishingOperation.selected=< Aucun trait sélectionné > @@ -864,6 +868,7 @@ tutti.gearUseFeatureTable.table.header.key=Caractéristique tutti.gearUseFeatureTable.table.header.value=Valeur tutti.gearUseFeatureTable.title=Mise en oeuvre de l'engin +tutti.importProtocol.action.success=Protocole [%s] lu depuis le fichier. tutti.importPupitri.carrouselFile.extension=car tutti.importPupitri.carrouselFile.extension.description=Fichier du carrousel (.car) tutti.importPupitri.error.fileMissing.message=Vous devez sélectionner un fichier pour le trémie et un fichier pour le carrousel pour pouvoir continuer l'import. @@ -1079,6 +1084,11 @@ tutti.selectSpecies.action.validate.mnemonic=V tutti.selectSpecies.action.validate.tip=Valider la sélection de l'espèce tutti.selectSpecies.title=Choisissez une espèce +tutti.sendCatchesReport.action.chooseFile=Choisir le fichier de rapport +tutti.sendCatchesReport.action.success=Les captures ont correctement été exporté dans le fichier %s +tutti.sendCatchesReport.mail.body=Bonjour,\n\nveuillez trouver ci-joint le rapport des captures de la campagne %1s.\n*Pensez à joindre le fichier %2s*\n\nCordialement,\n\n*Votre nom* +tutti.sendCatchesReport.mail.subject=Captures de la campagne %s +tutti.sendCatchesReport.title.choose.exportFile=Exporter les captures de la campagne tutti.splitBenthosBatch.action.cancel=Annuler tutti.splitBenthosBatch.action.cancel.mnemonic=A tutti.splitBenthosBatch.action.cancel.tip=Annuler le sous-échantillonnage @@ -1122,8 +1132,15 @@ tutti.update.i18n=Traductions tutti.update.jre=Java tutti.update.tutti=Tutti +tutti.updateApplication.message.success=La mise à jour nécessite le rédémarrage du Tutti.\nL'application va se fermer puis se réouvrir automatiquement. +tutti.updateApplication.noUpdate=Aucune mise à jour de l'application détectée. +tutti.updateApplication.title.success=Redémarrage de Tutti nécessaire... tutti.validator.error.comment.too.long=Taille de commentaire trop longue (limitée à %s caractères) -tutti.validator.error.createIndividualObservationBatch.individualObservationSpecies.required=L'espèce est obligatoire +tutti.validator.error.createAccidentalBatch.species.required=L'espèce est obligatoire +tutti.validator.error.createIndividualObservationBatch.lengthStepCaracteristic.required=La classe de taille est obligatoire +tutti.validator.error.createIndividualObservationBatch.size.required=La taille est obligatoire +tutti.validator.error.createIndividualObservationBatch.species.required=L'espèce est obligatoire +tutti.validator.error.createIndividualObservationBatch.weight.required=Le poids est obligatoire tutti.validator.error.createMarineLitterBatch.categoryAndSizeCategory.notAvailable=Couple (catégorie de déchet - catégorie de taille) déjà utilisée tutti.validator.error.createMarineLitterBatch.marineLitterCategory.required=La catégorie de déchet est obligatoire tutti.validator.error.createMarineLitterBatch.marineLitterSizeCategory.required=La catégorie de taille est obligatoire