it.tidalwave.bluebill.mobile.taxonomy.factsheet.sound.TaxonSoundFactSheetController Maven / Gradle / Ivy
/***********************************************************************************************************************
*
* blueBill Mobile - open source birdwatching
* ==========================================
*
* Copyright (C) 2009, 2010 by Tidalwave s.a.s. (http://www.tidalwave.it)
* http://bluebill.tidalwave.it/mobile/
*
***********************************************************************************************************************
*
* 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.
*
***********************************************************************************************************************
*
* $Id: TaxonSoundFactSheetController.java,v 7facb9eec0c2 2010/07/06 15:48:36 fabrizio $
*
**********************************************************************************************************************/
package it.tidalwave.bluebill.mobile.taxonomy.factsheet.sound;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.inject.Provider;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Arrays;
import java.util.List;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.Reader;
import org.openide.util.NbBundle;
import it.tidalwave.util.AsException;
import it.tidalwave.util.Identifiable;
import it.tidalwave.util.Removable;
import it.tidalwave.util.logging.Logger;
import it.tidalwave.netbeans.util.Locator;
import it.tidalwave.mobile.util.Downloadable;
import it.tidalwave.mobile.util.Downloadable.Status;
import it.tidalwave.mobile.io.MasterFileSystem;
import it.tidalwave.mobile.media.MediaPlayer;
import it.tidalwave.mobile.media.MediaPlayer.Controller;
import it.tidalwave.mobile.media.Media;
import it.tidalwave.semantic.io.json.RdfJsonUnmarshaller;
import it.tidalwave.bluebill.observation.Observation;
import it.tidalwave.bluebill.taxonomy.Taxon;
import it.tidalwave.bluebill.observation.ObservationSet;
import it.tidalwave.bluebill.mobile.network.NetworkingPreferences;
import static it.tidalwave.mobile.util.Downloadable.Status.*;
/***********************************************************************************************************************
*
* @author Fabrizio Giudici
* @version $Id: $
*
**********************************************************************************************************************/
public abstract class TaxonSoundFactSheetController
{
private static final String CLASS = TaxonSoundFactSheetController.class.getName();
private static final Logger logger = Logger.getLogger(CLASS);
private final static double MEGA = 1024.0 * 1024.0;
/* package */ final static long MIN_FREE_SPACE = 20L * 1024 * 1024;
private final static List WATCHED_PROPERTIES = Arrays.asList(Downloadable.PROP_STATUS, Downloadable.PROP_DOWNLOAD_PROGRESS);
private enum Operation
{
DOWNLOAD
{
public void run (final @Nonnull Downloadable downloadable)
{
downloadable.download();
}
},
REFRESH
{
public void run (final @Nonnull Downloadable downloadable)
{
downloadable.refresh();
}
};
public abstract void run (@Nonnull Downloadable downloadable);
}
public static enum DefaultAction
{
DO_NOTHING
{
public void run (final @Nonnull TaxonSoundFactSheetController controller, final @Nonnegative int index)
{
}
},
DOWNLOAD
{
public void run (final @Nonnull TaxonSoundFactSheetController controller, final @Nonnegative int index)
{
controller.downloadMedia(index);
}
},
PLAY
{
public void run (final @Nonnull TaxonSoundFactSheetController controller, final @Nonnegative int index)
{
controller.playMedia(index);
}
},
STOP
{
public void run (final @Nonnull TaxonSoundFactSheetController controller, final @Nonnegative int index)
{
controller.stopPlayer();
}
};
public abstract void run (@Nonnull TaxonSoundFactSheetController controller, @Nonnegative int index);
}
@Nonnull
private final TaxonSoundFactSheetUI ui;
@Nonnull
protected final Taxon taxon;
@CheckForNull
/* package */ Controller controller;
@Nonnull
private final Provider mediaPlayer = Locator.createProviderFor(MediaPlayer.class);
@Nonnull
private final Provider masterFileSystem = Locator.createProviderFor(MasterFileSystem.class);
private int playingIndex;
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
/* package */ final PropertyChangeListener mediaChangeListener = new PropertyChangeListener()
{
public void propertyChange (final @Nonnull PropertyChangeEvent event)
{
notifyStatusChanged();
}
};
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
/* package */ final PropertyChangeListener downloadablePropertyChangeListener = new PropertyChangeListener()
{
public void propertyChange (final @Nonnull PropertyChangeEvent event)
{
// logger.info("propertyChange(%s)", event);
if (WATCHED_PROPERTIES.contains(event.getPropertyName()) && (event.getOldValue() != event.getNewValue()))
{
notifyStatusChanged();
if (event.getPropertyName().equals(Downloadable.PROP_STATUS))
{
switch ((Status)event.getNewValue())
{
case DOWNLOADED:
final double freeSpace = masterFileSystem.get().getExternalFileSystem().getFreeSpace() / MEGA;
ui.notify(NbBundle.getMessage(TaxonSoundFactSheetController.class, "downloadComplete", freeSpace));
((Downloadable)event.getSource()).removePropertyChangeListener(downloadablePropertyChangeListener);
break;
case BROKEN:
ui.notify(NbBundle.getMessage(TaxonSoundFactSheetController.class, "downloadFailed"));
((Downloadable)event.getSource()).removePropertyChangeListener(downloadablePropertyChangeListener);
break;
case DOWNLOADING:
case NOT_DOWNLOADED:
case OBSOLETE:
case QUEUED:
}
}
}
}
};
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public TaxonSoundFactSheetController (final @Nonnull TaxonSoundFactSheetUI ui, final @Nonnull Taxon taxon)
throws IOException
{
this.ui = ui;
this.taxon = taxon;
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public void disposePlayer()
{
if (controller != null)
{
controller.removePropertyChangeListener(mediaChangeListener);
controller.dispose();
controller = null;
}
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public boolean isDownloadable (final @Nonnegative int index)
{
return isStatus(index, NOT_DOWNLOADED, OBSOLETE, BROKEN);
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public boolean isRefreshable (final @Nonnegative int index)
{
return isStatus(index, DOWNLOADED, OBSOLETE, BROKEN);
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public boolean isDeletable (final @Nonnegative int index)
{
return isStatus(index, DOWNLOADED, OBSOLETE);
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public boolean isPlayable (final @Nonnegative int index)
{
return isStatus(index, DOWNLOADED, OBSOLETE);
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public boolean isPlaying (final @Nonnegative int index)
{
return isPlayable(index) && (controller != null) && controller.isPlaying() && (index == playingIndex);
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public boolean hasWebPage (final @Nonnegative int index)
{
try
{
getObservation(index).as(Identifiable.class).getId();
return true;
}
catch (AsException e)
{
return false;
}
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public void downloadMedia (final @Nonnegative int index)
{
if (isDownloadable(index))
{
downloadMediaWithConfirmation(index, Operation.DOWNLOAD);
}
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public void refreshMedia (final @Nonnegative int index)
{
if (isRefreshable(index))
{
downloadMediaWithConfirmation(index, Operation.REFRESH);
}
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public void deleteMedia (final @Nonnegative int index)
{
if (isDeletable(index))
{
final String title = NbBundle.getMessage(TaxonSoundFactSheetController.class, "confirmDeletionTitle");
final String message = NbBundle.getMessage(TaxonSoundFactSheetController.class, "confirmDeletionMessage");
ui.getCommonUITasks().alertDialog(title, message, new Runnable()
{
public void run()
{
try
{
getMedia(index).as(Removable.class).remove();
final double freeSpace = masterFileSystem.get().getExternalFileSystem().getFreeSpace() / MEGA;
ui.notify(NbBundle.getMessage(TaxonSoundFactSheetController.class, "deletionCompleted", freeSpace));
}
catch (Exception e)
{
ui.notify(NbBundle.getMessage(TaxonSoundFactSheetController.class, "deletionFailed"));
logger.warning("Can't delete media %s", e);
logger.throwing("deleteMedia()", CLASS, e);
}
// Needed because at this point the PropertyChangeListener has been detached.
// Maybe it would be better to keep the listener attached, implement a dispose() method that
// detaches it at the end.
notifyStatusChanged();
}
});
}
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public void playMedia (final @Nonnegative int index)
{
if (isPlayable(index))
{
try
{
disposePlayer();
playingIndex = index;
controller = mediaPlayer.get().play(getMedia(index));
controller.addPropertyChangeListener(mediaChangeListener);
ui.notifyPlayMedia(controller);
notifyStatusChanged();
}
catch (Exception e)
{
ui.notify(NbBundle.getMessage(TaxonSoundFactSheetController.class, "playFailed"));
logger.warning("Can't play sound %s", e);
logger.throwing("downloadMedia()", CLASS, e);
}
}
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public void stopPlayer()
{
disposePlayer();
notifyStatusChanged();
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public void goToPage (final @Nonnegative int index)
{
try
{
ui.openWebPage(getObservation(index).as(Identifiable.class).getId().stringValue());
}
catch (Exception e)
{
logger.warning("Can't open web page %s", e);
logger.throwing("goToPage()", CLASS, e);
}
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
@Nonnull
public DefaultAction getDefaultAction (final @Nonnegative int index)
{
if (isPlaying(index))
{
return DefaultAction.STOP;
}
else if (isPlayable(index))
{
return DefaultAction.PLAY;
}
else if (isDownloadable(index))
{
return DefaultAction.DOWNLOAD;
}
else
{
return DefaultAction.DO_NOTHING;
}
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
@Nonnull
protected Media getMedia (final @Nonnegative int index)
{
return getObservation(index).as(Media.class);
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
@Nonnull
protected abstract Observation getObservation (final @Nonnegative int index);
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
protected abstract void notifyStatusChanged();
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
@Nonnull
protected ObservationSet loadObservationSet (final @Nonnull InputStream is)
throws IOException
{
final Reader r = new InputStreamReader(is, "UTF-8");
final RdfJsonUnmarshaller unmarshaller = new RdfJsonUnmarshaller();
return unmarshaller.unmarshal(r, ObservationSet.class);
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
private void downloadMediaWithConfirmation (final @Nonnegative int index, final @Nonnull Operation operation)
{
final String title = NbBundle.getMessage(TaxonSoundFactSheetController.class, "confirmDownloadTitle");
final String message = NbBundle.getMessage(TaxonSoundFactSheetController.class, "confirmDownloadMessage");
if (Locator.find(NetworkingPreferences.class).isNetworkConnectionAllowed())
{
doDownloadMedia(index, operation);
}
else
{
ui.getCommonUITasks().alertDialog(title, message, new Runnable()
{
public void run()
{
doDownloadMedia(index, operation);
}
});
}
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
/* package */ void doDownloadMedia (final @Nonnegative int index, final @Nonnull Operation operation)
{
if (!masterFileSystem.get().getExternalFileSystem().isWritable())
{
final String title = NbBundle.getMessage(TaxonSoundFactSheetController.class, "downloadFailed");
final String message = NbBundle.getMessage(TaxonSoundFactSheetController.class, "diskNotMountedMessage");
ui.getCommonUITasks().alertDialog(title, message, null);
}
else if(masterFileSystem.get().getExternalFileSystem().getFreeSpace() <= MIN_FREE_SPACE)
{
final String title = NbBundle.getMessage(TaxonSoundFactSheetController.class, "downloadFailed", MIN_FREE_SPACE / MEGA);
final String message = NbBundle.getMessage(TaxonSoundFactSheetController.class, "diskFullMessage", MIN_FREE_SPACE / MEGA);
ui.getCommonUITasks().alertDialog(title, message, null);
}
else
{
final Downloadable downloadable = getMedia(index).as(Downloadable.class);
downloadable.addPropertyChangeListener(downloadablePropertyChangeListener);
operation.run(downloadable);
ping();
}
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
private boolean isStatus (final @Nonnegative int index, final @Nonnull Status ... status)
{
final Downloadable downloadable = getMedia(index).as(Downloadable.class);
return Arrays.asList(status).contains(downloadable.getStatus());
}
protected void ping()
{
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy