/** * Copyright (C) 2009 BonitaSoft S.A. * BonitaSoft, 31 rue Gustave Eiffel - 38000 Grenoble * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2.0 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.bonitasoft.web.toolkit.client; import static com.google.gwt.query.client.GQuery.*; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.bonitasoft.console.client.angular.AngularIFrameView; import org.bonitasoft.web.toolkit.client.common.TreeIndexed; import org.bonitasoft.web.toolkit.client.eventbus.MainEventBus; import org.bonitasoft.web.toolkit.client.eventbus.events.ChangeViewEvent; import org.bonitasoft.web.toolkit.client.ui.JsId; import org.bonitasoft.web.toolkit.client.ui.RawView; import org.bonitasoft.web.toolkit.client.ui.component.Link; import org.bonitasoft.web.toolkit.client.ui.component.Refreshable; import org.bonitasoft.web.toolkit.client.ui.component.core.AbstractComponent; import org.bonitasoft.web.toolkit.client.ui.component.core.CustomPanel; import org.bonitasoft.web.toolkit.client.ui.component.form.view.DeleteItemPage; import org.bonitasoft.web.toolkit.client.ui.component.form.view.EditItemPage; import org.bonitasoft.web.toolkit.client.ui.page.ChangeLangPage; import org.bonitasoft.web.toolkit.client.ui.page.PageOnItem; import com.google.gwt.core.client.GWT; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; /** * This Class defines the main controller of the entire GWT application. It is responsible for the interaction between the * different components spread all over the window. * * @author Julien Mege */ public class ViewController { // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // CONFIG // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static final String ROOT_DIV_ID = "body"; public static final String POPUP_DIV_ID = "popup"; // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // FIELDS // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// protected static final ViewController INSTANCE = new ViewController(); private String currentPageToken = null; private static boolean isAngularFrameDisplayed = false; private final List<AbstractComponent> componentsWaitingForLoad = new LinkedList<AbstractComponent>(); private final List<Refreshable> componentsWaitingForRefresh = new LinkedList<Refreshable>(); // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // INIT AND CONSTRUCTOR // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Get the ViewController instance. * * @return the unique instance of the ViewController. */ public static ViewController getInstance() { return INSTANCE; } protected ViewController() { GWT.setUncaughtExceptionHandler(new CatchAllExceptionHandler()); } // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // SHOW VIEWS // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private RawView currentPage = null; public String getCurrentPageToken() { return currentPageToken; } public void setCurrentPageToken(final String currentPageToken) { this.currentPageToken = currentPageToken; } public static RawView showView(final String token) { return showView(token, ROOT_DIV_ID); } public static RawView showView(final String token, final String parentId) { return showView(token, parentId, new TreeIndexed<String>()); } public static RawView showView(final String token, final Map<String, String> params) { return showView(token, null, params); } public static RawView showView(final String token, final TreeIndexed<String> params) { return showView(token, (String) null, params); } public static RawView showView(final RawView view) { return showView(view, ROOT_DIV_ID, view.getParameters()); } public static RawView showView(final RawView view, final String parentId) { return showView(view, parentId, view.getParameters()); } public static RawView showView(final RawView view, final Map<String, String> params) { return showView(view, ROOT_DIV_ID, new TreeIndexed<String>(params)); } public static RawView showView(final String token, final String parentId, final Map<String, String> params) { return showView(token, parentId, new TreeIndexed<String>(params)); } public static RawView showView(final RawView view, final String parentId, final Map<String, String> params) { return showView(view, parentId, new TreeIndexed<String>(params)); } public static RawView showView(final String token, final String parentId, final TreeIndexed<String> params) { Element rootElement; if (parentId == null) { rootElement = DOM.getElementById("body"); } else { rootElement = DOM.getElementById(parentId); } if (rootElement != null) { return showView(token, rootElement, params); } return null; } public static RawView showView(final RawView view, final String parentId, final TreeIndexed<String> params) { assert parentId != null; final Element rootElement = DOM.getElementById(parentId); if (rootElement != null) { return showView(view, rootElement, params); } return view; } public static RawView showView(final String token, final Element rootElement, final HashMap<String, String> params) { return showView(token, rootElement, new TreeIndexed<String>(params)); } public static RawView showView(final RawView view, final Element rootElement, final HashMap<String, String> params) { return showView(view, rootElement, new TreeIndexed<String>(params)); } public static RawView showView(final String token, final Element rootElement, final TreeIndexed<String> params) { return showView(ViewController.getInstance().createView(token, params), rootElement, params); } public static RawView showView(final RawView view, final Element rootElement, final TreeIndexed<String> params) { // Set the parent Element to the view that will be displayed view.setParentElement(rootElement); if (ViewController.ROOT_DIV_ID.equals(rootElement.getId())) { // Reset useless elements ViewController.closePopup(); // getInstance().componentsWaitingForRefresh.clear(); getInstance().currentPage = view; getInstance().setCurrentPageToken(view.getToken()); // Set the URL // if (!BlankPage.TOKEN.equals(view.getToken())) { ClientApplicationURL.setPageToken(view.getToken(), false); // } ClientApplicationURL.setPageAttributes(params); ClientApplicationURL.refreshUrl(false); } final CustomPanel widget = view.toWidget(); final Element widgetElement = widget.getElement(); if (view instanceof AngularIFrameView) { if (!isAngularFrameDisplayed) { $(rootElement).empty(); rootElement.appendChild(widgetElement); } ((AngularIFrameView) view).display(params); isAngularFrameDisplayed = true; } else { if (view.getToken() != null && !view.getToken().trim().equals("")) { isAngularFrameDisplayed = false; } if (view instanceof PageOnItem<?>) { $(widgetElement).hide(); } else { $(rootElement).empty(); } rootElement.appendChild(widgetElement); } ViewController.updateUI(rootElement, true); widget.onLoad(); MainEventBus.getInstance().fireEventFromSource(new ChangeViewEvent(view), getInstance()); return view; } public static void showPopup(final String token) { showPopup(token, new TreeIndexed<String>()); } public static void showPopup(final String token, final Map<String, String> params) { ViewController.showPopup(token, new TreeIndexed<String>(params)); } public static void showPopup(final String token, final TreeIndexed<String> params) { showPopup(ViewController.getInstance().createView(token, params)); } public static void showPopup(final RawView view) { DOM.getElementById(ViewController.POPUP_DIV_ID).setInnerHTML(""); ViewController.openPopup(); addClosePopupAction(view); ViewController.showView(view, ViewController.POPUP_DIV_ID); } private static void addClosePopupAction(final RawView view) { final Element popupHeader = DOM.getElementById("popupcontainerheader"); popupHeader.setInnerHTML(""); // To remove button repetition after popup re-opening popupHeader.appendChild(new Link(new JsId("close_popup"), "Close popup", "Close this popup", view.getClosePopupAction()).getElement()); } private RawView createView(final String token, final TreeIndexed<String> params) { RawView page; if (token == ClientApplicationURL.TOKEN_ADD) { page = new EditItemPage(); } else if (token == ClientApplicationURL.TOKEN_EDIT) { page = new EditItemPage(); } else if (token == ClientApplicationURL.TOKEN_DELETE) { page = new DeleteItemPage(); } else if (token == ChangeLangPage.TOKEN) { page = new ChangeLangPage(); } else { page = ApplicationFactoryClient.getDefaultFactory().defineViewTokens(token); } page.setParameters(params); return page; } // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // POPUP // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static native void openPopup() /*-{ $wnd.$.popup.open(); }-*/; public static native void closePopup() /*-{ $wnd.$.popup.close(); }-*/; public static native boolean hasOpenedPopup() /*-{ return $wnd.$.popup.isOpen(); }-*/; // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // JQUERY+ MAPPER // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static native void updateUI(Element element, boolean force) /*-{ $wnd.$(element).updateUI(force); }-*/; public static native void updateUI(Element element)/*-{ $wnd.$(element).updateUI(); }-*/; public static native void updateUI(String selector, boolean force)/*-{ $wnd.$(selector).updateUI(force); }-*/; public static native void updateUI(String selector)/*-{ $wnd.$(selector).updateUI(); }-*/; public static native void back()/*-{ $wnd.historyBack(); }-*/; public void historyBack() { if (hasOpenedPopup()) { closePopup(); triggerRefresh(); } else { back(); } } // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // PAGE REFRESH // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static void refreshCurrentPage() { ViewController.getInstance().triggerRefresh(); } public void registerOnLoadEvent(final AbstractComponent... components) { for (final AbstractComponent component : components) { if (!componentsWaitingForLoad.contains(component)) { componentsWaitingForLoad.add(component); } } } public void unregisterOnLoadEvent(final AbstractComponent... components) { for (final AbstractComponent component : components) { componentsWaitingForLoad.remove(component); } } public void registerOnPageRefreshEvent(final Refreshable... components) { for (final Refreshable component : components) { if (!componentsWaitingForRefresh.contains(component)) { componentsWaitingForRefresh.add(component); } } } public void unregisterOnPageRefreshEvent(final Refreshable... components) { for (final Refreshable component : components) { componentsWaitingForRefresh.remove(component); } } public void triggerLoad() { for (final AbstractComponent component : componentsWaitingForLoad) { // if (component instanceof AbstractComponent && !component.isInDom()) { // this.componentsWaitingForLoad.remove(component); // continue; // } component.triggerLoad(); } componentsWaitingForLoad.clear(); } public void triggerRefresh() { // Clean components that are no longer in the DOM tree for (int i = 0; i < componentsWaitingForRefresh.size(); i++) { final Refreshable component = componentsWaitingForRefresh.get(i); if (component instanceof AbstractComponent && !((AbstractComponent) component).isInDom()) { componentsWaitingForRefresh.remove(component); i--; } } // Refresh automatically registered components if (currentPage.getAllowAutomatedUpdate()) { for (final Refreshable component : componentsWaitingForRefresh) { component.refresh(); } } // Custom page refresh currentPage.refresh(); } }