/* * 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.start; import org.eurekastreams.server.action.request.start.SetGadgetStateRequest; import org.eurekastreams.server.action.request.start.SetGadgetStateRequest.State; import org.eurekastreams.server.domain.Gadget; import org.eurekastreams.server.domain.gadgetspec.GadgetMetaDataDTO; import org.eurekastreams.server.domain.gadgetspec.UserPrefDTO; import org.eurekastreams.web.client.events.GadgetStateChangeEvent; import org.eurekastreams.web.client.events.GotGadgetMetaDataEvent; import org.eurekastreams.web.client.events.HideNotificationEvent; import org.eurekastreams.web.client.events.Observer; import org.eurekastreams.web.client.events.ShowNotificationEvent; import org.eurekastreams.web.client.events.UpdateGadgetPrefsEvent; import org.eurekastreams.web.client.events.UpdateHistoryEvent; import org.eurekastreams.web.client.events.UpdatedHistoryParametersEvent; import org.eurekastreams.web.client.events.data.DeletedGadgetResponseEvent; import org.eurekastreams.web.client.events.data.UnDeletedGadgetResponseEvent; import org.eurekastreams.web.client.history.CreateUrlRequest; import org.eurekastreams.web.client.jsni.GadgetRenderer; import org.eurekastreams.web.client.jsni.WidgetJSNIFacadeImpl; import org.eurekastreams.web.client.model.GadgetModel; import org.eurekastreams.web.client.ui.Session; import org.eurekastreams.web.client.ui.common.notifier.Notification; import org.eurekastreams.web.client.ui.common.notifier.UndoDeleteNotification; import org.eurekastreams.web.client.ui.pages.master.StaticResourceBundle; import org.eurekastreams.web.client.ui.pages.start.layouts.DropZonePanel; import com.allen_sauer.gwt.dnd.client.PickupDragController; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONParser; import com.google.gwt.user.client.ui.Anchor; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.FocusPanel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.RootPanel; /** * GadgetPanel. The UI Representation of a Gadget. This is used to wrap the shindig gadget around. JSNI methods are used * to add functionality to the GWT elements that are provided by Shindig. This class only wraps methods that manipulate * gadget specific functionality. It should not wrap gadgetContainer Methods. */ public class GadgetPanel extends FlowPanel { /** * The GadgetRenderer is the JSNI interface to the gadget container. */ private final GadgetRenderer gadgetRenderer = GadgetRenderer.getInstance(); /** * The current state of the gadget. */ private SetGadgetStateRequest.State gadgetState = SetGadgetStateRequest.State.NORMAL; /** * prefix for all dynamically created Render Zones. */ private final String gadgetRenderZonePrefix = "gadget-zone-render-zone-"; /** * prefix for all dynamically created gadget title label styles. */ private final String gadgetTitleLabelPrefix = "remote_iframe_"; /** Restore button. */ private final Label restoreButton = new Label("Exit Canvas Mode"); /** * minimize button. */ Anchor minimizeButton = new Anchor("Minimize"); /** * refresh button. */ Anchor refreshButton = new Anchor("Refresh"); /** * Edit button. */ Anchor editButton = new Anchor("Edit Settings"); /** * Close button. */ Anchor closeButton = new Anchor("Remove"); /** * Maximize button. */ Anchor maximizeButton = new Anchor("Maximize"); /** * Spacer button. */ Anchor spacerButton = new Anchor(""); /** * Help button. */ Anchor helpButton = new Anchor("Help"); /** * gadgetData sent via the constructor argument. */ Gadget gadgetData; /** * GadgetZone Id. */ Long gadgetIdModifier = null; /** * this field is needed because of a rendering problem that shindig has if a gadget is minimized by default. */ Boolean initallyMinimized = false; /** * The second of two children of the GadgetZonePanel, The gadget is rendered in this Panel. */ FlowPanel renderZone = new FlowPanel(); /** * One of two children of the GadgetZonePanel, contains all buttons and the title for the gadget. */ FlowPanel titleBar = new FlowPanel(); /** * The title for the gadget. */ FlowPanel title = new FlowPanel(); /** * Label for the gadget title. */ Label titleLabel = new Label(); /** * The Element ID of the div to render a gadget in. This will simply be a prefix with the gadgetIdModifier added to * it. */ private final String gadgetRenderZoneId; /** * needed to enable drag and drop. */ private final FocusPanel titleBarContainer = new FocusPanel(); /** * The class applied when a gadget is minimized. */ private static final String MINIMIZED_CSS_CLASS = StaticResourceBundle.INSTANCE.coreCss().gadgetZoneMinimized(); /** * The gadget drag controller. */ private PickupDragController gadgetDragController; /** * The parent drop zone. */ private DropZonePanel parentDropZone = null; /** * Is this gadget delegating? */ private boolean delegationOn = false; /** * Creates the Gadget render zone and gives the zone a incremented id. * * @param gadget * The Gadget from the Model you are rendering. */ public GadgetPanel(final Gadget gadget) { gadgetIdModifier = gadget.getId(); gadgetRenderZoneId = gadgetRenderZonePrefix + gadgetIdModifier.toString(); renderZone.getElement().setId(gadgetRenderZoneId); gadgetData = gadget; // Style the pieces of the title bar title.setStylePrimaryName(StaticResourceBundle.INSTANCE.coreCss().gadgetZoneChromeTitleBarTitleButton()); titleLabel.getElement().setId(gadgetTitleLabelPrefix + gadgetIdModifier.toString() + "_title"); title.add(restoreButton); title.add(titleLabel); restoreButton.addStyleName(StaticResourceBundle.INSTANCE.coreCss().gadgetRestore()); closeButton.addStyleName(StaticResourceBundle.INSTANCE.coreCss().gadgetClose()); maximizeButton.addStyleName(StaticResourceBundle.INSTANCE.coreCss().gadgetMaximize()); spacerButton.addStyleName(StaticResourceBundle.INSTANCE.coreCss().gadgetButtonSpacer()); refreshButton.addStyleName(StaticResourceBundle.INSTANCE.coreCss().gadgetRefresh()); minimizeButton.addStyleName(StaticResourceBundle.INSTANCE.coreCss().gadgetMinimize()); editButton.addStyleName(StaticResourceBundle.INSTANCE.coreCss().gadgetEdit()); helpButton.addStyleName(StaticResourceBundle.INSTANCE.coreCss().gadgetHelp()); closeButton.addStyleName(StaticResourceBundle.INSTANCE.coreCss().gadgetButton()); maximizeButton.addStyleName(StaticResourceBundle.INSTANCE.coreCss().gadgetButton()); spacerButton.addStyleName(StaticResourceBundle.INSTANCE.coreCss().gadgetButton()); refreshButton.addStyleName(StaticResourceBundle.INSTANCE.coreCss().gadgetButton()); minimizeButton.addStyleName(StaticResourceBundle.INSTANCE.coreCss().gadgetButton()); editButton.addStyleName(StaticResourceBundle.INSTANCE.coreCss().gadgetButton()); helpButton.addStyleName(StaticResourceBundle.INSTANCE.coreCss().gadgetButton()); // Creates the title Bar titleBar.setStylePrimaryName(StaticResourceBundle.INSTANCE.coreCss().gadgetZoneChromeTitleBar()); titleBar.getElement().setId("gadgets-gadget-title-bar-" + gadgetIdModifier.toString()); // Add buttons to title bar titleBar.add(minimizeButton); titleBar.add(title); titleBar.add(maximizeButton); titleBar.add(spacerButton); titleBar.add(closeButton); titleBar.add(editButton); titleBar.add(helpButton); titleBar.add(refreshButton); titleBarContainer.add(titleBar); this.setStylePrimaryName(StaticResourceBundle.INSTANCE.coreCss().gadgetZone()); this.add(titleBarContainer); this.add(renderZone); spacerButton.setVisible(false); restoreButton.setVisible(false); // set up the close command closeButton.addClickHandler(new ClickHandler() { public void onClick(final ClickEvent event) { if (new WidgetJSNIFacadeImpl().confirm("Are you sure you want to delete this app?")) { GadgetModel.getInstance().delete(gadgetData.getId()); } } }); editButton.addClickHandler(new ClickHandler() { public void onClick(final ClickEvent event) { if (delegationOn) { callEditButtonClickedForDelegation(gadgetIdModifier); } gadgetRenderer.openPreferences(gadgetIdModifier.toString()); if (gadgetState == State.MINIMIZED) { if (initallyMinimized) { gadgetRenderer.registerSingleGadgetInContainer(gadget.getGadgetDefinition().getUrl(), gadgetIdModifier, gadget.getGadgetDefinition().getId(), gadget.getGadgetUserPref()); gadgetRenderer.renderGadget(gadgetIdModifier.toString()); initallyMinimized = false; } setGadgetState(State.NORMAL); } } }); refreshButton.addClickHandler(new ClickHandler() { public void onClick(final ClickEvent event) { gadgetRenderer.refreshGadget(gadgetIdModifier.toString()); } }); helpButton.addClickHandler(new ClickHandler() { public void onClick(final ClickEvent event) { setGadgetState(State.HELP); } }); maximizeButton.addClickHandler(new ClickHandler() { public void onClick(final ClickEvent event) { setGadgetState(State.MAXIMIZED); } }); restoreButton.addClickHandler(new ClickHandler() { public void onClick(final ClickEvent event) { setGadgetState(State.NORMAL); } }); minimizeButton.addClickHandler(new ClickHandler() { public void onClick(final ClickEvent event) { if (gadgetState == State.MINIMIZED) { if (initallyMinimized) { gadgetRenderer.registerSingleGadgetInContainer(gadget.getGadgetDefinition().getUrl(), gadgetIdModifier, gadget.getGadgetDefinition().getId(), gadget.getGadgetUserPref()); gadgetRenderer.renderGadget(gadgetIdModifier.toString()); initallyMinimized = false; } setGadgetState(State.NORMAL); } else { setGadgetState(State.MINIMIZED); } } }); if (gadgetData.isMinimized()) { initallyMinimized = true; setGadgetState(State.MINIMIZED); } setUpEvents(); if (!initallyMinimized) { gadgetRenderer.registerSingleGadgetInContainer(gadget.getGadgetDefinition().getUrl(), gadgetIdModifier, gadget.getGadgetDefinition().getId(), gadget.getGadgetUserPref()); } } /** * Set up the event handling. */ private void setUpEvents() { final GadgetPanel thisBuffered = this; Session.getInstance().getEventBus().addObserver(DeletedGadgetResponseEvent.class, new Observer<DeletedGadgetResponseEvent>() { public void update(final DeletedGadgetResponseEvent event) { if (event.getResponse() == gadgetData.getId()) { thisBuffered.setVisible(false); thisBuffered.addStyleName(StaticResourceBundle.INSTANCE.coreCss().hidden()); Session.getInstance().getEventBus().notifyObservers( new ShowNotificationEvent(new Notification(new UndoDeleteNotification("App", new ClickHandler() { public void onClick(final ClickEvent event) { GadgetModel.getInstance().undoDelete(gadgetData.getId()); Session.getInstance().getEventBus().notifyObservers( new HideNotificationEvent()); } }), ""))); } } }); Session.getInstance().getEventBus().addObserver(UnDeletedGadgetResponseEvent.class, new Observer<UnDeletedGadgetResponseEvent>() { public void update(final UnDeletedGadgetResponseEvent arg1) { if (arg1.getResponse().getId() == gadgetData.getId()) { thisBuffered.setVisible(true); thisBuffered.removeStyleName(StaticResourceBundle.INSTANCE.coreCss().hidden()); } } }); Session.getInstance().getEventBus().addObserver(GotGadgetMetaDataEvent.class, new Observer<GotGadgetMetaDataEvent>() { public void update(final GotGadgetMetaDataEvent arg1) { for (GadgetMetaDataDTO metadata : arg1.getMetadata()) { if (metadata.getGadgetDefinition().getId() == gadgetData.getGadgetDefinition().getId()) { boolean foundSetting = false; String titleText = metadata.getTitle(); helpButton.setVisible(metadata.getViewNames().contains("help")); maximizeButton.setVisible(metadata.getViewNames().contains("canvas")); delegationOn = metadata.getFeatures().contains("eurekastreams-delegation"); if (metadata.getUserPrefs() != null) { // had to go to with a normal for loop rather than a for-in due to some // issues with GWT making wierd javascript for (int i = 0; i < metadata.getUserPrefs().size(); i++) { if (metadata.getUserPrefs().get(i).getClass() == UserPrefDTO.class) { UserPrefDTO userPref = metadata.getUserPrefs().get(i); if (!userPref.getDataType().equals(UserPrefDTO.DataType.HIDDEN)) { foundSetting = true; break; } gadgetData.getGadgetUserPref(); } } } editButton.setVisible(foundSetting || delegationOn); if (gadgetData.getGadgetUserPref() != null && !gadgetData.getGadgetUserPref().equals("")) { JSONObject gadgetUserPrefsJSON = (JSONObject) JSONParser.parse(gadgetData .getGadgetUserPref()); String gadgetTitleFromUserPrefs = getGadgetTitleFromUserPrefs(gadgetUserPrefsJSON .getJavaScriptObject()); if (gadgetTitleFromUserPrefs != null && !gadgetTitleFromUserPrefs.equals("")) { titleText = getGadgetTitleFromUserPrefs(gadgetUserPrefsJSON .getJavaScriptObject()); } } if (titleLabel.getText() == "") { titleLabel.setText(titleText); } } } } }); Session.getInstance().getEventBus().addObserver(GadgetStateChangeEvent.class, new Observer<GadgetStateChangeEvent>() { public void update(final GadgetStateChangeEvent event) { if (event.getId() == gadgetData.getId()) { if (event.getView().equals("canvas")) { setGadgetState(State.MAXIMIZED, event.getParams()); } else if (event.getView().equals("home")) { setGadgetState(State.NORMAL, event.getParams()); } } } }); Session.getInstance().getEventBus().addObserver(UpdateGadgetPrefsEvent.class, new Observer<UpdateGadgetPrefsEvent>() { public void update(final UpdateGadgetPrefsEvent event) { if (event.getId() == gadgetData.getId()) { gadgetData.setGadgetUserPref(event.getUserPrefs()); } } }); Session.getInstance().getEventBus().addObserver(UpdatedHistoryParametersEvent.class, new Observer<UpdatedHistoryParametersEvent>() { public void update(final UpdatedHistoryParametersEvent arg1) { // If we were in canvas mode, and our history token isn't set, // implying we just hit the back button. if (arg1.getParameters().get("canvas") == null && gadgetState.equals(State.MAXIMIZED)) { setGadgetState(State.NORMAL); } } }); } /** * @param inParentDropZone * the parent drop zone. */ public void setDropZone(final DropZonePanel inParentDropZone) { parentDropZone = inParentDropZone; } /** * Gets the entity type of the JSON object. * * @param jsObj * the JSON object. * @return the entity type. */ private native String getGadgetTitleFromUserPrefs(final JavaScriptObject jsObj) /*-{ return jsObj['eureka-container-gadget-title']; }-*/; /** * Tell the delegation feature the edit button was clicked. * * @param gadgetId * the gadget id. */ private native void callEditButtonClickedForDelegation(final Long gadgetId) /*-{ $wnd.eurekastreams.delegation.container.editButtonClicked(gadgetId); }-*/; /** * Set the gadget state w/o params. * * @param state * the gadget state. */ public void setGadgetState(final State state) { setGadgetState(state, null); } /** * Gets the state. * * @return the state. */ public State getGadgetState() { return gadgetState; } /** * Setter. * * @param state * new state of the gadget * @param viewParams * the params. */ public void setGadgetState(final State state, final String viewParams) { State previousGadgetState = gadgetState; gadgetState = state; if (state != State.MINIMIZED) { // Hide user preferences if it is shown for any reason while changing state. gadgetRenderer.hidePreferences(gadgetIdModifier.toString()); } switch (state) { case HELP: gadgetDragController.makeDraggable(this, titleBarContainer); if (previousGadgetState != State.HELP) { gadgetRenderer.changeContainerView("help"); gadgetRenderer.refreshGadgetIFrameUrl(gadgetIdModifier.toString(), viewParams); } break; case NORMAL: gadgetDragController.makeDraggable(this, titleBarContainer); RootPanel.get().removeStyleName(StaticResourceBundle.INSTANCE.coreCss().maximizedGadget()); if (null != parentDropZone) { parentDropZone.removeStyleName(StaticResourceBundle.INSTANCE.coreCss().maximizedDropZone()); } gadgetRenderer.restoreGadgetZone(); minimizeButton.removeStyleName(StaticResourceBundle.INSTANCE.coreCss().minimized()); renderZone.setStyleName(""); if (previousGadgetState == State.MAXIMIZED || previousGadgetState == State.HELP) { gadgetRenderer.gadgetIFrameUrlRefreshing(gadgetIdModifier.toString()); gadgetRenderer.changeContainerView("home"); gadgetRenderer.refreshGadgetIFrameUrl(gadgetIdModifier.toString(), viewParams); } restoreButton.setVisible(false); maximizeButton.setVisible(true); spacerButton.setVisible(false); Session.getInstance().getEventBus().notifyObservers( new UpdateHistoryEvent(new CreateUrlRequest("canvas", null, false))); break; case MAXIMIZED: makeGadgetUndraggable(); RootPanel.get().addStyleName(StaticResourceBundle.INSTANCE.coreCss().maximizedGadget()); if (null != parentDropZone) { parentDropZone.addStyleName(StaticResourceBundle.INSTANCE.coreCss().maximizedDropZone()); } gadgetRenderer.gadgetIFrameUrlRefreshing(gadgetIdModifier.toString()); gadgetRenderer.changeContainerView("canvas"); gadgetRenderer.refreshGadgetIFrameUrl(gadgetIdModifier.toString(), viewParams); gadgetRenderer.changeContainerView("home"); minimizeButton.removeStyleName(StaticResourceBundle.INSTANCE.coreCss().minimized()); restoreButton.setVisible(true); maximizeButton.setVisible(false); gadgetRenderer.maximizeGadgetZone(this.getElement()); Session.getInstance().getEventBus().notifyObservers( new UpdateHistoryEvent(new CreateUrlRequest("canvas", "true", false))); break; case MINIMIZED: minimizeButton.addStyleName(StaticResourceBundle.INSTANCE.coreCss().minimized()); maximizeButton.setVisible(false); restoreButton.setVisible(false); spacerButton.setVisible(true); renderZone.setStyleName(MINIMIZED_CSS_CLASS); break; default: break; } GadgetModel.getInstance().setState(new SetGadgetStateRequest(gadgetData.getId(), state)); } /** * Make the gadget draggable. * * @param inGadgetDragController * the gadget drag controller. */ public void makeGadgetDraggable(final PickupDragController inGadgetDragController) { gadgetDragController = inGadgetDragController; gadgetDragController.makeDraggable(this, titleBarContainer); } /** * Make the gadget undraggable. */ public void makeGadgetUndraggable() { if (gadgetDragController != null) { gadgetDragController.makeNotDraggable(this); } } /** * Get the gadget data. * * @return the gadget data. */ public Gadget getGadgetData() { return gadgetData; } /** * Refresh the gadget. (Used after drag-and-drop operations. Without this, the RPC gets broken and the callbacks to * RPC-based APIs simply never get called on the gadget side.) */ public void rerender() { gadgetRenderer.gadgetIFrameUrlRefreshing(gadgetIdModifier.toString()); gadgetRenderer.refreshGadget(gadgetIdModifier.toString()); } }