
it.tidalwave.bluebill.mobile.observation.ui.spi.DefaultObservationsViewController Maven / Gradle / Ivy
The newest version!
/***********************************************************************************************************************
*
* blueBill Mobile - Android - open source birding
* Copyright (C) 2009-2011 by Tidalwave s.a.s. (http://www.tidalwave.it)
*
***********************************************************************************************************************
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
***********************************************************************************************************************
*
* WWW: http://bluebill.tidalwave.it/mobile
* SCM: https://java.net/hg/bluebill-mobile~android-src
*
**********************************************************************************************************************/
package it.tidalwave.bluebill.mobile.observation.ui.spi;
import it.tidalwave.bluebill.mobile.observation.ui.ObservationsView;
import it.tidalwave.bluebill.mobile.observation.ui.ObservationsViewController;
import it.tidalwave.bluebill.mobile.observation.ui.ReportUserNotificationWithFeedback;
import javax.annotation.Nonnull;
import javax.inject.Provider;
import java.util.Date;
import java.util.Calendar;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.io.File;
import java.io.IOException;
import it.tidalwave.util.thread.ThreadAssertions;
import it.tidalwave.util.ui.UserNotificationWithFeedback;
import it.tidalwave.netbeans.util.Locator;
import it.tidalwave.observation.Observation;
import it.tidalwave.observation.Observation.Builder;
import it.tidalwave.observation.ObservationItem;
import it.tidalwave.observation.ObservationManager;
import it.tidalwave.observation.ObservationSet;
import it.tidalwave.mobile.util.DateUpdater;
import it.tidalwave.mobile.io.FileSystem;
import it.tidalwave.mobile.io.MasterFileSystem;
import it.tidalwave.mobile.location.LocationFinder;
import it.tidalwave.semantic.document.Document;
import it.tidalwave.semantic.document.DocumentWriter;
import it.tidalwave.observation.bluebill.ObservationClipboard;
import it.tidalwave.bluebill.mobile.preferences.SharingPreferences;
import it.tidalwave.bluebill.taxonomy.mobile.Taxon;
import lombok.extern.slf4j.Slf4j;
import static org.openide.util.NbBundle.*;
import static it.tidalwave.util.thread.ThreadType.*;
import static it.tidalwave.util.ui.UserNotification.notification;
import static it.tidalwave.util.ui.UserNotificationWithFeedback.notificationWithFeedback;
import static it.tidalwave.role.PlainTextRenderable.PlainTextRenderable;
import static it.tidalwave.bluebill.taxonomy.mobile.Taxon.Taxon;
import static it.tidalwave.semantic.document.Sendable.Sendable;
/***********************************************************************************************************************
*
* @stereotype Controller
*
* @author Fabrizio Giudici
* @version $Id$
*
**********************************************************************************************************************/
@Slf4j
public class DefaultObservationsViewController implements ObservationsViewController
{
private static final Class _ = DefaultObservationsViewController.class;
@Nonnull
private final ObservationClipboard observationClipboard = Locator.find(ObservationClipboard.class);
@Nonnull
private final LocationFinder locationFinder = Locator.find(LocationFinder.class);
@Nonnull
private final ObservationManager observationManager = Locator.find(ObservationManager.class);
@Nonnull
private final ObservationSet observationSet = observationManager.findOrCreateObservationSetById(null);
@Nonnull
private final Provider sharingPreferences = Locator.createProviderFor(SharingPreferences.class);
@Nonnull
private final Provider masterFileSystem = Locator.createProviderFor(MasterFileSystem.class);
@Nonnull
private final ObservationsView view;
/*******************************************************************************************************************
*
*
*
******************************************************************************************************************/
public DefaultObservationsViewController (final @Nonnull ObservationsView view)
{
this.view = view;
}
/*******************************************************************************************************************
*
* {@inheritDoc}
*
******************************************************************************************************************/
public void startNewObservationSequence()
{
ThreadAssertions.assertThread(UI);
log.info("startNewObservationSequence()");
observationClipboard.clear();
final Builder builder = observationClipboard.getBuilder();
observationClipboard.setBuilder(builder.at(Calendar.getInstance().getTime()));
locationFinder.start(); // search needs time, and we pre-start it
}
/*******************************************************************************************************************
*
* {@inheritDoc}
*
******************************************************************************************************************/
public void browseToFactSheet()
{
ThreadAssertions.assertThread(UI);
log.info("browseToFactSheet()");
// nothing to do by default
}
/*******************************************************************************************************************
*
* {@inheritDoc}
*
******************************************************************************************************************/
public void commitNewObservation()
{
ThreadAssertions.assertThread(UI);
log.info("commitNewObservation()");
final Observation.Builder builder = observationClipboard.getBuilder();
if (builder.getItemCount() > 0)
{
builder.build();
view.highlightLatestObservation();
view.notifyNewObservationCommitted(notification().withText(_, "addedNewObservation"));
}
observationClipboard.clear();
}
/*******************************************************************************************************************
*
* {@inheritDoc}
*
******************************************************************************************************************/
public void cancelNewObservation()
{
ThreadAssertions.assertThread(UI);
log.info("cancelNewObservation()");
locationFinder.stop(); // we pre-started it
view.notifyNewObservationCancelled(notification().withText(_, "addedNewObservationCancelled"));
}
/*******************************************************************************************************************
*
* {@inheritDoc}
*
******************************************************************************************************************/
public void updateObservationDate (final @Nonnull Observation observation, final @Nonnull DateUpdater dateUpdater)
{
ThreadAssertions.assertThread(UI);
final Date date = dateUpdater.update(observation.getDate());
observation.change().at(date).apply();
view.notifyObservationDateTimeUpdated(notification().withText(_, "observationDateTimeUpdated"));
}
/*******************************************************************************************************************
*
* {@inheritDoc}
*
******************************************************************************************************************/
public void exportObservations()
{
ThreadAssertions.assertThread(UI);
log.info("exportObservations()");
view.askForExportOptions(new ReportUserNotificationWithFeedback(getMessage(_, "exportOptions"))
{
@Override
protected void onConfirmInBackground()
{
log.info("exportObservations({})", this);
progressListener.start();
final String reportBaseName = getReportBaseName();
final Document report = getReportFactory().createReport(observationSet, reportBaseName, progressListener);
progressListener.setProgressName(getMessage(_, "exportSaving"));
final FileSystem fileSystem = masterFileSystem.get().getExternalFileSystem();
final String reportExportFolderName = getMessage(_, "exportFolder");
try
{
final File reportContainerFolder = fileSystem.getFile(reportExportFolderName);
final File reportFolder = new File(reportContainerFolder, reportBaseName);
log.info(">>>> saving report to {}", reportFolder.getAbsolutePath());
if (!reportFolder.mkdirs() && !reportFolder.exists())
{
throw new IOException("Cannot create " + reportFolder.getAbsolutePath());
}
report.accept(new DocumentWriter(reportBaseName, reportFolder));
// FIXME: this is brittle and based on a hidden behaviour of ExternalFileSystem.
final File storageRoot = reportContainerFolder.getParentFile().getParentFile();
final String path = reportFolder.getAbsolutePath().substring(storageRoot.getAbsolutePath().length());
view.notifyExportCompleted(notificationWithFeedback().withCaption(_, "export")
.withText(_, "exportCompleted", path));
}
catch (Throwable t)
{
// FIXME: now that we have Exception reporting, why we just don't have this throwing exception?
log.error("exportObservations()", t);
view.notifyExportFailed(notificationWithFeedback().withCaption(_, "export")
.withText(_, "exportFailed"));
throw new RuntimeException(t);
}
finally
{
progressListener.stop();
}
}
});
}
/*******************************************************************************************************************
*
* {@inheritDoc}
*
******************************************************************************************************************/
public void shareObservations()
{
ThreadAssertions.assertThread(UI);
log.info("shareObservations()");
view.askForShareOptions(new ReportUserNotificationWithFeedback(getMessage(_, "shareOptions"))
{
@Override
protected void onConfirmInBackground()
throws Exception
{
try
{
log.info("shareObservations({})", this);
Document report = null;
try
{
progressListener.start();
final String reportBaseName = getReportBaseName();
report = getReportFactory().createReport(observationSet, reportBaseName, progressListener);
}
finally
{
progressListener.stop(); // before sending the report
}
report.as(Sendable).sendTo(view, sharingPreferences.get().getDefaultRecipients());
// view.showLightNotification(NbBundle.getMessage(C, "shareCompleted"));
// TODO: a light notification that the operation completed, but we must get notified about the send activity.
}
catch (Throwable t)
{
// FIXME: now that we have Exception reporting, why we just don't have this throwing exception?
log.error("shareObservations()", t);
view.notifyExportFailed(notificationWithFeedback().withCaption(_, "share")
.withText(_, "shareFailed"));
throw new RuntimeException(t);
}
}
});
}
/*******************************************************************************************************************
*
* {@inheritDoc}
*
******************************************************************************************************************/
public void deleteAllObservations()
{
ThreadAssertions.assertThread(UI);
log.info("deleteAllObservations()");
view.confirmToDeleteAllObservations(notificationWithFeedback().withCaption(_, "confirm")
.withText(_, "confirmEraseAllObservations")
.withFeedback(new UserNotificationWithFeedback.Feedback()
{
@Override
public void onConfirm()
{
observationSet.clear();
view.notifyAllObservationsDeleted(notification().withText(_, "allObservationsErased"));
}
}));
}
/*******************************************************************************************************************
*
* {@inheritDoc}
*
******************************************************************************************************************/
public void deleteObservationItem (final @Nonnull ObservationItem observationItem)
{
ThreadAssertions.assertThread(UI);
log.info("deleteObservationItem({})", observationItem);
final Taxon taxon = observationItem.getObservable().as(Taxon);
view.confirmToDeleteAnObservationItem(notificationWithFeedback().withCaption(_, "confirm")
.withText(_, "confirmDeleteObservationItem", taxon.as(PlainTextRenderable).render())
.withFeedback(new UserNotificationWithFeedback.Feedback()
{
@Override
public void onConfirm()
{
observationItem.getObservation().change().without(observationItem).apply();
view.notifyObservationItemDeleted(notification().withText(_, "itemDeleted"));
}
}));
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
@Nonnull
private static String getReportBaseName()
{
final DateFormat df = new SimpleDateFormat("'blueBill-Observations-'yyyy-MM-dd_HHmm");
return df.format(new Date());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy