/* * Copyright (c) 2009-2011 Lockheed Martin Corporation * * 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. */ package org.eurekastreams.web.client.ui.pages.settings; import java.io.Serializable; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import org.eurekastreams.server.action.response.settings.RetrieveSettingsResponse; import org.eurekastreams.server.domain.NotificationFilterPreference; import org.eurekastreams.server.domain.NotificationFilterPreference.Category; import org.eurekastreams.server.domain.NotificationFilterPreferenceDTO; import org.eurekastreams.server.domain.Page; import org.eurekastreams.web.client.events.Observer; import org.eurekastreams.web.client.events.ShowNotificationEvent; import org.eurekastreams.web.client.events.data.GotPersonalSettingsResponseEvent; import org.eurekastreams.web.client.events.data.UpdatedPersonalSettingsResponseEvent; import org.eurekastreams.web.client.history.CreateUrlRequest; import org.eurekastreams.web.client.model.PersonalSettingsModel; import org.eurekastreams.web.client.ui.Session; import org.eurekastreams.web.client.ui.common.dialog.Dialog; import org.eurekastreams.web.client.ui.common.form.FormBuilder; import org.eurekastreams.web.client.ui.common.form.FormBuilder.Method; import org.eurekastreams.web.client.ui.common.form.elements.FormElement; import org.eurekastreams.web.client.ui.common.notifier.Notification; import org.eurekastreams.web.client.ui.pages.master.StaticResourceBundle; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.Grid; import com.google.gwt.user.client.ui.InlineLabel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.Panel; /** * Personal Settings Panel Composite. * */ public class NotificationsSettingsPanelComposite extends FlowPanel { /** Form builder. */ private FormBuilder form; /** List of notification preference categories for personal activities. */ private static final Map<String, Category> PERSONAL_PREF_CATEGORIES = new LinkedHashMap<String, Category>(); /** List of notification preference categories for group activities. */ private static final Map<String, Category> GROUP_PREF_CATEGORIES = new LinkedHashMap<String, Category>(); /** List of notification preference categories for organization activities. */ private static final Map<String, Category> ORG_PREF_CATEGORIES = new LinkedHashMap<String, Category>(); static { PERSONAL_PREF_CATEGORIES.put("Activity posted to your stream", Category.POST_TO_PERSONAL_STREAM); PERSONAL_PREF_CATEGORIES.put("Colleague likes activity you posted to your stream or a group stream", Category.LIKE); PERSONAL_PREF_CATEGORIES.put("Comment is posted to an activity in your stream or an activity " + "you posted to a group stream", Category.COMMENT); PERSONAL_PREF_CATEGORIES.put("Comment is posted to an activity you saved", Category.COMMENT_TO_SAVED_ACTIVITY); PERSONAL_PREF_CATEGORIES.put("New follower is added to your stream", Category.FOLLOW_PERSON); // Note: Since group coordinators are also members by default (although they can leave), "joined" mostly covers // the "coordinate" case, although it does not allow for the notifications to be different GROUP_PREF_CATEGORIES.put("Activity is posted to a group you joined", Category.POST_TO_JOINED_GROUP); // GROUP_PREF_CATEGORIES.put("Activity is posted to a group you coordinate", Category.POST_TO_GROUP_STREAM); // GROUP_PREF_CATEGORIES.put("Comments", Category.COMMENT_IN_GROUP_STREAM); GROUP_PREF_CATEGORIES.put("New member joins a group you coordinate", Category.FOLLOW_GROUP); GROUP_PREF_CATEGORIES.put("Group Membership is requested in a private group you coordinate", Category.REQUEST_GROUP_ACCESS); GROUP_PREF_CATEGORIES.put("Your request for membership in a private group has been approved or denied", Category.REQUEST_GROUP_ACCESS_RESPONSE); ORG_PREF_CATEGORIES.put("Activity is Flagged in an organization you coordinate", Category.FLAG_ACTIVITY); ORG_PREF_CATEGORIES .put("New group is requested in an organization you coordinate", Category.REQUEST_NEW_GROUP); } /** * Constructor. */ public NotificationsSettingsPanelComposite() { // UI setup addStyleName(StaticResourceBundle.INSTANCE.coreCss().personalSettings()); // listen for model events Session.getInstance().getEventBus() .addObserver(GotPersonalSettingsResponseEvent.class, new Observer<GotPersonalSettingsResponseEvent>() { public void update(final GotPersonalSettingsResponseEvent ev) { generateForm(ev.getSettings(), ev.getSupport()); } }); // request data PersonalSettingsModel.getInstance().fetch(null, true); } /** * Builds the form using the data supplied. * * @param inSettings * User's settings. * @param inSupport * Supporting data. */ public void generateForm(final Map<String, Object> inSettings, final Map<String, Object> inSupport) { form = new FormBuilder("", PersonalSettingsModel.getInstance(), Method.UPDATE); form.addStyleName(StaticResourceBundle.INSTANCE.coreCss().notifSettingsForm()); form.turnOffChangeCheck(); setupFormCommands(); buildNotificationPreferencesSection( (Collection<NotificationFilterPreferenceDTO>) inSettings .get(RetrieveSettingsResponse.SETTINGS_NOTIFICATION_FILTERS), (HashMap<String, String>) inSupport.get(RetrieveSettingsResponse.SUPPORT_NOTIFIER_TYPES)); add(form); } /** * Builds the notification filter preference part of the form using the supplied data. * * @param filters * User's filter selections. * @param notifiers * List of available notifiers. */ private void buildNotificationPreferencesSection(final Collection<NotificationFilterPreferenceDTO> filters, final HashMap<String, String> notifiers) { Label label; Panel panel = new FlowPanel(); panel.addStyleName(StaticResourceBundle.INSTANCE.coreCss().notifSettingsPanel()); form.addWidget(panel); label = new Label("My Activity and Connections"); label.addStyleName(StaticResourceBundle.INSTANCE.coreCss().formLabel()); panel.add(label); label = new Label("Eureka Streams will notify you when new activity has taken place that involves you."); label.addStyleName(StaticResourceBundle.INSTANCE.coreCss().instructions()); panel.add(label); panel.add(buildNotificationFilterGrid(notifiers, PERSONAL_PREF_CATEGORIES, filters)); label = new Label("My Groups' Activity and Connections"); label.addStyleName(StaticResourceBundle.INSTANCE.coreCss().formLabel()); panel.add(label); label = new Label("Eureka Streams will notify you when new activity has taken place in the groups that " + "you coordinate or groups that you have joined."); label.addStyleName(StaticResourceBundle.INSTANCE.coreCss().instructions()); panel.add(label); Grid groupGrid = buildNotificationFilterGrid(notifiers, GROUP_PREF_CATEGORIES, filters); panel.add(groupGrid); label = new Label("My Organizations' Activity and Connections"); label.addStyleName(StaticResourceBundle.INSTANCE.coreCss().formLabel()); panel.add(label); label = new Label("Eureka Streams will notify you when new activity has " + "taken place in the organizations that you coordinate."); label.addStyleName(StaticResourceBundle.INSTANCE.coreCss().instructions()); panel.add(label); panel.add(buildNotificationFilterGrid(notifiers, ORG_PREF_CATEGORIES, filters)); label = new InlineLabel("Email notifications will be sent to: "); panel.add(label); label = new InlineLabel(Session.getInstance().getCurrentPerson().getEmail()); label.addStyleName(StaticResourceBundle.INSTANCE.coreCss().notifEmailValue()); panel.add(label); // add link for managing groups int row = 0; for (Category category : GROUP_PREF_CATEGORIES.values()) { row++; if (Category.POST_TO_JOINED_GROUP.equals(category)) { String caption = groupGrid.getText(row, 0); FlowPanel cellPanel = new FlowPanel(); cellPanel.add(new InlineLabel(caption + " ")); GroupSubscriptionDialogContent dialogContent = new GroupSubscriptionDialogContent(); final Dialog dialog = new Dialog(dialogContent); InlineLabel manageLink = new InlineLabel("(manage)"); manageLink.addStyleName(StaticResourceBundle.INSTANCE.coreCss().linkedLabel()); manageLink.addClickHandler(new ClickHandler() { public void onClick(final ClickEvent inArg0) { dialog.showCentered(); } }); cellPanel.add(manageLink); groupGrid.setWidget(row, 0, cellPanel); break; } } } /** * Builds the personal/group grid for notification preferences. * * @param notifiers * List of notifiers. * @param categories * Names and enum values of the notification preference categories to include in this grid. * @param filters * User's current notification preferences. * @return Grid. */ private Grid buildNotificationFilterGrid(final Map<String, String> notifiers, final Map<String, Category> categories, final Collection<NotificationFilterPreferenceDTO> filters) { Grid grid = new Grid(1 + categories.size(), 1 + notifiers.size()); grid.addStyleName(StaticResourceBundle.INSTANCE.coreCss().notifGrid()); // display each category name (one per row) int row = 0; for (String categoryName : categories.keySet()) { row++; grid.setText(row, 0, categoryName); } // display each notifier column int col = 0; for (Map.Entry<String, String> entry : notifiers.entrySet()) { col++; // display the names of the notifiers grid.setText(0, col, entry.getValue()); grid.getColumnFormatter().addStyleName(col, "notif-selection-column"); // create the checkboxes for that notifier per category row = 0; for (Category category : categories.values()) { row++; setupNotificationFilterCheckbox(grid, row, col, entry.getKey(), category, filters); } } return grid; } /** * Creates an sets up a given checkbox. * * @param grid * The grid in which the checkbox goes. * @param col * The column in which the checkbox goes. * @param row * The row in which the checkbox goes. * @param notifierType * The notifier type the checkbox represents. * @param category * The category the checkbox represents * @param prefs * The list of preferences. */ private void setupNotificationFilterCheckbox(final Grid grid, final int row, final int col, final String notifierType, final NotificationFilterPreference.Category category, final Collection<NotificationFilterPreferenceDTO> prefs) { NotificationPreferenceFormElement elem = new NotificationPreferenceFormElement(notifierType, category); grid.setWidget(row, col, elem.getWidget()); form.addFormElement(elem); // determine initial state - certainly not the most efficient, but the list should be really short for (NotificationFilterPreferenceDTO pref : prefs) { if (pref.getNotificationCategory().equals(category) && pref.getNotifierType().equals(notifierType)) { elem.getWidget().setValue(false); break; } } } /** * Configures the form builder for submit and cancel. */ private void setupFormCommands() { if (form == null) { return; } Session.getInstance() .getEventBus() .addObserver(UpdatedPersonalSettingsResponseEvent.class, new Observer<UpdatedPersonalSettingsResponseEvent>() { public void update(final UpdatedPersonalSettingsResponseEvent arg1) { form.onSuccess(); Session.getInstance() .getEventBus() .notifyObservers(new ShowNotificationEvent(new Notification("Settings saved"))); } }); form.setOnCancelHistoryToken(Session.getInstance().generateUrl(new CreateUrlRequest(Page.START))); } /** * Form element specific to notification preference checkboxes to allow prefs to be set via FormBuilder approach. * Does not inherit from a widget so that the FormBuilder will not try to add it to the panel. */ public static class NotificationPreferenceFormElement implements FormElement { /** Notifier type. */ private final String notifierType; /** Category. */ private final NotificationFilterPreference.Category category; /** Checkbox. */ private final CheckBox checkbox = new CheckBox(); /** * Constructor. * * @param inNotifierType * Notifier type. * @param inCategory * Category. */ public NotificationPreferenceFormElement(final String inNotifierType, final Category inCategory) { notifierType = inNotifierType; category = inCategory; checkbox.setValue(true); } /** * {@inheritDoc} */ public String getKey() { return "notif-" + notifierType + "-" + category.name(); } /** * {@inheritDoc} */ public Serializable getValue() { return checkbox.getValue() ? null : new NotificationFilterPreferenceDTO(notifierType, category); } /** * {@inheritDoc} */ public void onError(final String inErrMessage) { } /** * {@inheritDoc} */ public void onSuccess() { // nothing to do } /** * @return The widget. */ CheckBox getWidget() { return checkbox; } } }