/**
*
*/
package net.frontlinesms.ui.handler;
import static net.frontlinesms.ui.UiGeneratorControllerConstants.COMPONENT_EVENTS_LIST;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import net.frontlinesms.AppProperties;
import net.frontlinesms.events.AppPropertiesEventNotification;
import net.frontlinesms.events.EventBus;
import net.frontlinesms.events.EventObserver;
import net.frontlinesms.events.FrontlineEventNotification;
import net.frontlinesms.ui.Event;
import net.frontlinesms.ui.FrontlineUI;
import net.frontlinesms.ui.FrontlineUiUtils;
import net.frontlinesms.ui.Icon;
import net.frontlinesms.ui.UiDestroyEvent;
import net.frontlinesms.ui.UiGeneratorController;
import net.frontlinesms.ui.UiGeneratorControllerConstants;
import net.frontlinesms.ui.UiProperties;
import net.frontlinesms.ui.events.FrontlineUiUpateJob;
import net.frontlinesms.ui.handler.message.MessagePanelHandler;
import net.frontlinesms.ui.i18n.FileLanguageBundle;
import net.frontlinesms.ui.i18n.InternationalisationUtils;
import net.frontlinesms.ui.settings.HomeTabLogoChangedEventNotification;
/**
* Event handler for the Home tab and associated dialogs
* @author Alex Anderson <alex@frontlinesms.com>
* @author Morgan Belkadi <morgan@frontlinesms.com>
*/
public class HomeTabHandler extends BaseTabHandler implements EventObserver {
//> STATIC CONSTANTS
/** Limit of the number of events to be displayed on the home screen */
static final int EVENTS_LIMIT = 30;
/** UI XML File Path: the Home Tab itself */
protected static final String UI_FILE_HOME_TAB = "/ui/core/home/homeTab.xml";
/** UI XML File Path: settings dialog for the home tab logo */
private static final String UI_FILE_HOME_TAB_SETTINGS = "/ui/core/home/dgHomeTabSettings.xml";
/** UI XML File Path: statistics dialog */
private static final String UI_FILE_STATS_DIALOG = "/ui/core/home/dgStatistics.xml";
/** Thinlet Component Name: Home Tab: logo */
private static final String COMPONENT_LB_HOME_TAB_LOGO = "lbHomeTabLogo";
/** Thinlet Component Name: Settings dialog: radio indicating if the logo is visible */
private static final String COMPONENT_CB_HOME_TAB_LOGO_INVISIBLE = "cbHomeTabLogoInvisible";
/** Thinlet Component Name: Settings dialog: radio used to choose the default logo */
private static final String COMPONENT_CB_HOME_TAB_USE_DEFAULT_LOGO = "cbHomeTabLogoDefault";
/** Thinlet Component Name: Settings dialog: radio used to choose a custom logo */
private static final String COMPONENT_CB_HOME_TAB_USE_CUSTOM_LOGO = "cbHomeTabLogoCustom";
/** Thinlet Component Name: Settings dialog: checkbox used to choose a custom logo */
private static final String COMPONENT_CB_HOME_TAB_LOGO_KEEP_ORIGINAL_SIZE = "cbHomeTabLogoKeepOriginalSize";
/** Thinlet Component Name: Settings dialog: panel grouping the path of the image file for the logo */
private static final String COMPONENT_PN_CUSTOM_IMAGE = "pnCustomImage";
/** Thinlet Component Name: Settings dialog: textfield inidicating the path of the image file for the logo */
private static final String COMPONENT_TF_IMAGE_SOURCE = "tfImageSource";
/** Default FrontlineSMS home logo */
private static final String FRONTLINE_LOGO = "/icons/frontlineSMS_logo.png";
/** Max FrontlineSMS home logo width */
private static final double FRONTLINE_LOGO_MAX_WIDTH = 484.0;
/** Max FrontlineSMS home logo height */
private static final double FRONTLINE_LOGO_MAX_HEIGHT = 300.0;
private EventBus eventBus;
private MessagePanelHandler messagePanel;
//> INSTANCE PROPERTIES
//> CONSTRUCTORS
/**
* Create a new instance of this class.
* @param ui value for {@link #ui}
*/
public HomeTabHandler(UiGeneratorController ui) {
super(ui);
this.eventBus = ui.getFrontlineController().getEventBus();
this.eventBus.registerObserver(this);
}
//> UI METHODS
/** Show the settings dialog for the home tab. */
public void showHomeTabSettings() {
log.trace("ENTER");
Object homeTabSettings = ui.loadComponentFromFile(UI_FILE_HOME_TAB_SETTINGS, this);
UiProperties uiProperties = UiProperties.getInstance();
boolean visible = uiProperties.isHometabLogoVisible();
boolean isCustomLogo = uiProperties.isHometabCustomLogo();
boolean isOriginalSizeKept = uiProperties.isHometabLogoOriginalSizeKept();
String imageLocation = uiProperties.getHometabLogoPath();
log.debug("Visible? " + visible);
log.debug("Logo: " + (isCustomLogo ? "custom" : "default"));
if (isCustomLogo)
log.debug("Keep original size: " + isOriginalSizeKept);
log.debug("Image location [" + imageLocation + "]");
String radioButtonName;
if(!visible) {
radioButtonName = COMPONENT_CB_HOME_TAB_LOGO_INVISIBLE;
} else if(isCustomLogo) {
radioButtonName = COMPONENT_CB_HOME_TAB_USE_CUSTOM_LOGO;
} else {
radioButtonName = COMPONENT_CB_HOME_TAB_USE_DEFAULT_LOGO;
}
ui.setSelected(ui.find(homeTabSettings, radioButtonName), true);
ui.setSelected(ui.find(homeTabSettings, COMPONENT_CB_HOME_TAB_LOGO_KEEP_ORIGINAL_SIZE), isOriginalSizeKept);
setHomeTabCustomLogo(ui.find(homeTabSettings, COMPONENT_PN_CUSTOM_IMAGE), isCustomLogo && visible);
if (imageLocation != null && imageLocation.length() > 0) {
ui.setText(ui.find(homeTabSettings, COMPONENT_TF_IMAGE_SOURCE), imageLocation);
}
ui.add(homeTabSettings);
log.trace("EXIT");
}
/** Show the settings dialog for the home tab. */
public void showStatsDialog() {
log.trace("ENTER");
Object homeTabSettings = ui.loadComponentFromFile(UI_FILE_STATS_DIALOG, this);
ui.add(homeTabSettings);
log.trace("EXIT");
}
/**
* Save the home tab settings from the settings dialog, and remove the dialog.
* @param panel
*/
public void saveHomeTabSettings(Object panel) {
log.trace("ENTER");
boolean invisible = ui.isSelected(ui.find(panel, COMPONENT_CB_HOME_TAB_LOGO_INVISIBLE));
boolean isCustomLogo = ui.isSelected(ui.find(panel, COMPONENT_CB_HOME_TAB_USE_CUSTOM_LOGO));
boolean isOriginalSizeKept = ui.isSelected(ui.find(panel, COMPONENT_CB_HOME_TAB_LOGO_KEEP_ORIGINAL_SIZE));
String imgSource = ui.getText(ui.find(panel, COMPONENT_TF_IMAGE_SOURCE));
log.debug("Hidden? " + invisible);
log.debug("Logo: " + (isCustomLogo ? "default" : "custom"));
log.debug("Image location [" + imgSource + "]");
UiProperties uiProperties = UiProperties.getInstance();
uiProperties.setHometabLogoVisible(!invisible);
uiProperties.setHometabCustomLogo(isCustomLogo);
uiProperties.setHometabLogoOriginalSizeKept(isOriginalSizeKept);
uiProperties.setHometabLogoPath(imgSource);
uiProperties.saveToDisk();
// Update visibility of logo
refreshLogoVisibility(getTab());
ui.remove(panel);
log.trace("EXIT");
}
/**
* Enable or disable the bottom panel whether the logo is custom or not.
* @param panel
* @param isCustom <code>true</code> if the logo is a custom logo; <code>false</code> otherwise.
*/
public void setHomeTabCustomLogo(Object panel, boolean isCustom) {
ui.setEnabled(panel, isCustom);
for (Object obj : ui.getItems(panel)) {
ui.setEnabled(obj, isCustom);
}
}
//> UI PASSTHRU METHODS TO UiGC
/**
* @param component Component whose contents are to be removed
* @see UiGeneratorController#removeAll()
*/
public void removeAll(Object component) {
this.ui.removeAll(component);
}
/**
* @param component
* @see UiGeneratorController#showOpenModeFileChooser(Object)
*/
public void showFileChooser(Object component) {
this.ui.showFileChooser(component);
}
//> INSTANCE HELPER METHODS
/**
* Refresh the contents of the tab.
*/
protected Object initialiseTab() {
Object tabComponent = ui.loadComponentFromFile(UI_FILE_HOME_TAB, this);
Object pnSend = ui.find(tabComponent, UiGeneratorControllerConstants.COMPONENT_PN_SEND);
final boolean shouldDisplayRecipientField = true;
final boolean shouldCheckMaxMessageLength = false;
final int numberOfRecipients = 1;
messagePanel = MessagePanelHandler.create(this.ui, shouldDisplayRecipientField, shouldCheckMaxMessageLength, numberOfRecipients);
ui.add(pnSend, messagePanel.getPanel());
refreshLogoVisibility(tabComponent);
Object fastLanguageSwitch = ui.find(tabComponent, "fastLanguageSwitch");
for (FileLanguageBundle languageBundle : InternationalisationUtils.getLanguageBundles()) {
// Don't show the flag for the current language
if(languageBundle.equals(FrontlineUI.currentResourceBundle)) continue;
Object button = ui.createLink("", "changeLanguage(this)", tabComponent);
ui.setIcon(button, ui.getFlagIcon(languageBundle));
ui.setString(button, "tooltip", languageBundle.getLanguageName());
ui.setWeight(button, 1, 0);
ui.setAttachedObject(button, languageBundle.getFile().getAbsolutePath());
ui.add(fastLanguageSwitch, button);
}
return tabComponent;
}
public void refresh() { /* No refresh required */ }
/**
* Update the visibility of the logo.
* @param tabComponent The tab component. This is passed in, as this method can be called form {@link #initialiseTab()}, in which case {@link #getTab()} will return null.
*/
private void refreshLogoVisibility(Object tabComponent) {
Object lbLogo = ui.find(tabComponent, COMPONENT_LB_HOME_TAB_LOGO);
if (!UiProperties.getInstance().isHometabLogoVisible()) {
Image noIcon = null;
ui.setIcon(lbLogo, noIcon);
} else {
String imageLocation = UiProperties.getInstance().getHometabLogoPath();
boolean useDefault = true;
if (UiProperties.getInstance().isHometabCustomLogo() && imageLocation != null && imageLocation.length() > 0) {
// Absolute or relative path provided
try {
BufferedImage homeTabLogoImage = ImageIO.read(new File(imageLocation));
// If the "Keep original size" box is unchecked, we resize the image
if (!UiProperties.getInstance().isHometabLogoOriginalSizeKept())
{
ui.setIcon(lbLogo,
FrontlineUiUtils.getLimitedSizeImage(homeTabLogoImage,
FRONTLINE_LOGO_MAX_WIDTH, FRONTLINE_LOGO_MAX_HEIGHT));
}
else
ui.setIcon(lbLogo, homeTabLogoImage);
useDefault = false;
} catch (IOException e) {
// We are unable to find the specified image, using the default
log.warn("We are unable to find the specified image [" + imageLocation + "], using the default one.", e);
}
}
if (useDefault) {
// We go for the default one, inside the package
ui.setIcon(lbLogo, ui.getIcon(FRONTLINE_LOGO));
}
}
}
//> UI HELPER METHODS
private Object getRow(Event newEvent) {
Object row = ui.createTableRow(newEvent);
String icon = null;
switch(newEvent.getType()) {
case Event.TYPE_INCOMING_MESSAGE:
icon = Icon.SMS_RECEIVE;
break;
case Event.TYPE_OUTGOING_MESSAGE:
icon = Icon.SMS_SEND;
break;
case Event.TYPE_INCOMING_MMS:
icon = Icon.MMS_RECEIVE;
break;
case Event.TYPE_OUTGOING_MESSAGE_FAILED:
icon = Icon.SMS_SEND_FAILURE;
break;
case Event.TYPE_OUTGOING_EMAIL:
icon = Icon.EMAIL_SEND;
break;
case Event.TYPE_PHONE_CONNECTED:
icon = Icon.PHONE_CONNECTED;
break;
case Event.TYPE_SMS_INTERNET_SERVICE_CONNECTED:
icon = Icon.SMS_INTERNET_SERVICE_CONNECTED;
break;
case Event.TYPE_SMS_INTERNET_SERVICE_RECEIVING_FAILED:
icon = Icon.SMS_INTERNET_SERVICE_RECEIVING_FAILED;
break;
}
Object cell = ui.createTableCell("");
ui.setIcon(cell, icon);
ui.add(row, cell);
ui.add(row, ui.createTableCell(newEvent.getDescription()));
ui.add(row, ui.createTableCell(InternationalisationUtils.getDatetimeFormat().format(newEvent.getTime())));
return row;
}
//> LISTENER EVENT METHODS
public void newEvent(final Event newEvent) {
new FrontlineUiUpateJob() {
public void run() {
Object eventListComponent = find(COMPONENT_EVENTS_LIST);
if(eventListComponent != null) {
if (ui.getItems(eventListComponent).length >= HomeTabHandler.EVENTS_LIMIT) {
ui.remove(ui.getItem(eventListComponent, 0));
}
ui.add(eventListComponent, getRow(newEvent));
}
}
}.execute();
}
public void notify(FrontlineEventNotification notification) {
if (notification instanceof HomeTabLogoChangedEventNotification) {
this.refreshLogoVisibility(getTab());
} else if (notification instanceof AppPropertiesEventNotification) {
String property = ((AppPropertiesEventNotification) notification).getProperty();
if (property.equals(AppProperties.KEY_SMS_COST_SENT_MESSAGES)
|| property.equals(UiProperties.CURRENCY_FORMAT)
|| property.equals(UiProperties.CURRENCY_FORMAT_IS_CUSTOM)) {
this.messagePanel.updateCost();
}
} else if (notification instanceof UiDestroyEvent) {
if(((UiDestroyEvent) notification).isFor(this.ui)) {
this.ui.getFrontlineController().getEventBus().unregisterObserver(this);
}
}
}
//> STATIC FACTORIES
//> STATIC HELPER METHODS
}