/** * */ package net.frontlinesms.ui.handler.email; import static net.frontlinesms.FrontlineSMSConstants.COMMON_CONTENT; import static net.frontlinesms.FrontlineSMSConstants.COMMON_DATE; import static net.frontlinesms.FrontlineSMSConstants.COMMON_RECIPIENT; import static net.frontlinesms.FrontlineSMSConstants.COMMON_SENDER; import static net.frontlinesms.FrontlineSMSConstants.COMMON_STATUS; import static net.frontlinesms.FrontlineSMSConstants.COMMON_SUBJECT; import static net.frontlinesms.FrontlineSMSConstants.DEFAULT_END_DATE; import static net.frontlinesms.FrontlineSMSConstants.MESSAGE_EMAILS_LOADED; import static net.frontlinesms.FrontlineSMSConstants.PROPERTY_FIELD; import static net.frontlinesms.ui.UiGeneratorControllerConstants.TAB_EMAIL_LOG; import java.util.List; import thinlet.Thinlet; import thinlet.ThinletText; import net.frontlinesms.EmailSender; import net.frontlinesms.EmailServerHandler; import net.frontlinesms.FrontlineSMS; import net.frontlinesms.data.Order; import net.frontlinesms.data.domain.Email; import net.frontlinesms.data.domain.EmailAccount; import net.frontlinesms.data.domain.Email.Field; import net.frontlinesms.data.repository.EmailDao; import net.frontlinesms.events.EventObserver; import net.frontlinesms.events.FrontlineEventNotification; import net.frontlinesms.ui.UiDestroyEvent; import net.frontlinesms.ui.UiGeneratorController; import net.frontlinesms.ui.events.TabChangedNotification; import net.frontlinesms.ui.handler.BaseTabHandler; import net.frontlinesms.ui.handler.ComponentPagingHandler; import net.frontlinesms.ui.handler.PagedComponentItemProvider; import net.frontlinesms.ui.handler.PagedListDetails; import net.frontlinesms.ui.i18n.InternationalisationUtils; import net.frontlinesms.ui.i18n.TextResourceKeyOwner; /** * @author Alex Anderson * <li> alex(at)masabi(dot)com * @author Carlos Eduardo Genz * <li> kadu(at)masabi(dot)com */ @TextResourceKeyOwner(prefix="MESSAGE_") public class EmailTabHandler extends BaseTabHandler implements PagedComponentItemProvider, EventObserver { //> UI LAYOUT FILES /** Thinlet XML Layout file for the email tab */ public static final String UI_FILE_EMAILS_TAB = "/ui/core/email/emailsTab.xml"; //> UI COMPONENT NAMES public static final String COMPONENT_EMAIL_LIST = "emailList"; public static final String COMPONENT_PN_EMAIL = "pnEmail"; public static final String COMPONENT_EMAILS_TOOLBAR = "emails_toolbar"; public static final String MESSAGE_EMAILS_DELETED = "message.emails.deleted"; public static final String MESSAGE_REMOVING_EMAILS = "message.removing.emails"; //> INSTANCE PROPERTIES /** Manager of {@link EmailAccount}s and {@link EmailSender}s */ private EmailServerHandler emailManager; /** DAO for {@link Email}s */ private EmailDao emailDao; /** DAO for {@link EmailAccount}s */ /** Thinlet UI Component: list of emails */ private Object emailListComponent; /** Paging handler for {@link #emailListComponent} */ private ComponentPagingHandler emailListPager; //> CONSTRUCTORS /** * Create a new {@link EmailTabHandler} tied to the specified UI and frontline controller. * @param ui * @param frontlineController */ public EmailTabHandler(UiGeneratorController ui) { super(ui); FrontlineSMS frontlineController = ui.getFrontlineController(); this.emailManager = frontlineController .getEmailServerHandler(); this.emailDao = frontlineController.getEmailDao(); } //> ACCESSORS /** Refresh the view */ public void refresh() { this.emailListPager.refresh(); } /** @see BaseTabHandler#init() */ protected Object initialiseTab() { Object tabComponent = ui.loadComponentFromFile(UI_FILE_EMAILS_TAB, this); // We register the observer to the UIGeneratorController, which notifies when tabs have changed this.ui.getFrontlineController().getEventBus().registerObserver(this); emailListComponent = ui.find(tabComponent, COMPONENT_EMAIL_LIST); this.emailListPager = new ComponentPagingHandler(this.ui, this, this.emailListComponent); Object pnEmail = ui.find(tabComponent, COMPONENT_PN_EMAIL); ui.add(pnEmail, this.emailListPager.getPanel(), 2); // Set the types for the email list columns... initEmailTableForSorting(); return tabComponent; } //> PAGING METHODS /** @see PagedComponentItemProvider#getListDetails(Object, int, int) */ public PagedListDetails getListDetails(Object list, int startIndex, int limit) { if(list == this.emailListComponent) { return getEmailListDetails(startIndex, limit); } else throw new IllegalStateException(); } /** @return {@link PagedListDetails} for the {@link #emailListComponent} */ private PagedListDetails getEmailListDetails(int startIndex, int limit) { int totalItemCount = this.emailDao.getEmailCount(); List<Email> emails = this.emailDao.getEmailsWithLimit(getSortField(), getSortOrder(), startIndex, limit); Object[] components = new Object[emails.size()]; for (int i=0; i<components.length; ++i) { Email email = emails.get(i); components[i] = getRow(email); } return new PagedListDetails(totalItemCount, components); } /** @return the order to sort emails in {@link #emailListComponent} */ private Order getSortOrder() { Object header = Thinlet.get(emailListComponent, ThinletText.HEADER); Object tableColumn = ui.getSelectedItem(header); Order order = Order.DESCENDING; if (tableColumn != null) { order = Thinlet.get(tableColumn, ThinletText.SORT).equals(ThinletText.ASCENT) ? Order.ASCENDING : Order.DESCENDING; } return order; } /** @return the column to sort emails in {@link #emailListComponent} by */ private Field getSortField() { Object header = Thinlet.get(emailListComponent, ThinletText.HEADER); Object tableColumn = ui.getSelectedItem(header); Email.Field field = null; if (tableColumn != null) { field = (Email.Field) ui.getProperty(tableColumn, PROPERTY_FIELD); } return field; } //> /** Set up the email table's columns to allow easy sorting */ private void initEmailTableForSorting() { Object header = Thinlet.get(emailListComponent, ThinletText.HEADER); for (Object o : ui.getItems(header)) { String text = ui.getString(o, Thinlet.TEXT); // Here, the FIELD property is set on each column of the message table. These field objects are // then used for easy sorting of the message table. if (text != null) { if (text.equalsIgnoreCase(InternationalisationUtils.getI18nString(COMMON_STATUS))) ui.putProperty(o, PROPERTY_FIELD, Email.Field.STATUS); else if(text.equalsIgnoreCase(InternationalisationUtils.getI18nString(COMMON_DATE))) ui.putProperty(o, PROPERTY_FIELD, Email.Field.DATE); else if(text.equalsIgnoreCase(InternationalisationUtils.getI18nString(COMMON_SENDER))) ui.putProperty(o, PROPERTY_FIELD, Email.Field.FROM); else if(text.equalsIgnoreCase(InternationalisationUtils.getI18nString(COMMON_RECIPIENT))) ui.putProperty(o, PROPERTY_FIELD, Email.Field.TO); else if(text.equalsIgnoreCase(InternationalisationUtils.getI18nString(COMMON_CONTENT))) ui.putProperty(o, PROPERTY_FIELD, Email.Field.EMAIL_CONTENT); else if(text.equalsIgnoreCase(InternationalisationUtils.getI18nString(COMMON_SUBJECT))) ui.putProperty(o, PROPERTY_FIELD, Email.Field.SUBJECT); } } } //> UI EVENT HANDLING METHODS /** * Removes the selected emails */ public void removeSelectedFromEmailList() { log.trace("ENTER"); ui.removeConfirmationDialog(); ui.setStatus(InternationalisationUtils.getI18nString(MESSAGE_REMOVING_EMAILS)); final Object[] selected = ui.getSelectedItems(emailListComponent); int numberRemoved = 0; for (Object o : selected) { Email toBeRemoved = ui.getEmail(o); log.debug("E-mail [" + toBeRemoved + "]"); Email.Status status = toBeRemoved.getStatus(); if (status != Email.Status.PENDING && status != Email.Status.RETRYING) { log.debug("Removing from database.."); if (status == Email.Status.OUTBOX) { emailManager.removeFromOutbox(toBeRemoved); } emailDao.deleteEmail(toBeRemoved); numberRemoved++; } else { log.debug("E-mail status is [" + toBeRemoved.getStatus() + "]. Do not remove..."); } } if (numberRemoved > 0) { updateEmailList(); } ui.setStatus(InternationalisationUtils.getI18nString(MESSAGE_EMAILS_DELETED)); log.trace("EXIT"); } /** Update the email list inside the email log tab. */ public void updateEmailList() { this.emailListPager.refresh(); enableOptions(emailListComponent, null, find(COMPONENT_EMAILS_TOOLBAR)); } /** Re-Sends the selected emails */ public void resendSelectedFromEmailList() { Object[] selected = ui.getSelectedItems(emailListComponent); for (Object o : selected) { Email toBeReSent = ui.getEmail(o); Email.Status status = toBeReSent.getStatus(); if (status == Email.Status.FAILED) { emailManager.sendEmail(toBeReSent); } else if (status == Email.Status.SENT ) { Email newEmail = new Email(toBeReSent.getEmailFrom(), toBeReSent.getEmailRecipients(), toBeReSent.getEmailSubject(), toBeReSent.getEmailContent()); emailDao.saveEmail(newEmail); emailManager.sendEmail(newEmail); } } } /** * Enables or disables menu options in a List Component's popup list * and toolbar. These enablements are based on whether any items in * the list are selected, and if they are, on the nature of these * items. * @param list * @param popup * @param toolbar */ public void enableOptions(Object list, Object popup, Object toolbar) { Object[] selectedItems = ui.getSelectedItems(list); boolean hasSelection = selectedItems.length > 0; if(popup!= null && !hasSelection) { ui.setVisible(popup, false); return; } if (hasSelection && popup != null) { // If nothing is selected, hide the popup menu ui.setVisible(popup, true); } if (toolbar != null && !toolbar.equals(popup)) { for (Object o : ui.getItems(toolbar)) { ui.setEnabled(o, hasSelection); } } } //> UI HELPER METHODS /** * Creates a Thinlet UI table row containing details of an Email. * @param email * @return */ private Object getRow(Email email) { Object row = ui.createTableRow(email); ui.add(row, ui.createTableCell(InternationalisationUtils.getI18nString(email.getStatus()))); if (email.getDate() == DEFAULT_END_DATE) { ui.add(row, ui.createTableCell("")); } else { ui.add(row, ui.createTableCell(InternationalisationUtils.getDatetimeFormat().format(email.getDate()))); } ui.add(row, ui.createTableCell(email.getEmailFrom().getAccountName())); ui.add(row, ui.createTableCell(email.getEmailRecipients())); ui.add(row, ui.createTableCell(email.getEmailSubject())); ui.add(row, ui.createTableCell(email.getEmailContent())); return row; } //> LISTENER EVENT METHODS public synchronized void outgoingEmailEvent(EmailSender sender, Email email) { log.debug("Refreshing e-mail list"); int index = -1; for (int i = 0; i < ui.getItems(emailListComponent).length; i++) { Email e = ui.getEmail(ui.getItem(emailListComponent, i)); if (e.equals(email)) { index = i; break; } } if (index != -1) { //Updating ui.remove(ui.getItem(emailListComponent, index)); ui.add(emailListComponent, getRow(email), index); } else { int limit = this.emailListPager.getMaxItemsPerPage(); //Adding if (ui.getItems(emailListComponent).length < limit && email.getStatus() == Email.Status.OUTBOX) { ui.add(emailListComponent, getRow(email)); } } } /** * UI event called when the user changes tab */ public void notify(FrontlineEventNotification notification) { // This object is registered to the UIGeneratorController and get notified when the users changes tab if(notification instanceof TabChangedNotification) { String newTabName = ((TabChangedNotification) notification).getNewTabName(); if (newTabName.equals(TAB_EMAIL_LOG)) { this.refresh(); this.ui.setStatus(InternationalisationUtils.getI18nString(MESSAGE_EMAILS_LOADED)); } } else if (notification instanceof UiDestroyEvent) { if(((UiDestroyEvent) notification).isFor(this.ui)) { this.ui.getFrontlineController().getEventBus().unregisterObserver(this); } } } }