package org.activityinfo.ui.client.page.report.editor;
/*
* #%L
* ActivityInfo Server
* %%
* Copyright (C) 2009 - 2013 UNICEF
* %%
* 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 3 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/gpl-3.0.html>.
* #L%
*/
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.MessageBoxEvent;
import com.extjs.gxt.ui.client.widget.Dialog;
import com.extjs.gxt.ui.client.widget.MessageBox;
import com.extjs.gxt.ui.client.widget.MessageBox.MessageBoxType;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.SpanElement;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.dom.client.Style.Visibility;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.inject.Inject;
import com.google.inject.Provider;
import org.activityinfo.i18n.shared.I18N;
import org.activityinfo.legacy.client.Dispatcher;
import org.activityinfo.legacy.shared.command.GenerateElement;
import org.activityinfo.legacy.shared.command.RenderReportHtml;
import org.activityinfo.legacy.shared.command.result.HtmlResult;
import org.activityinfo.legacy.shared.reports.content.Content;
import org.activityinfo.legacy.shared.reports.model.PivotChartReportElement;
import org.activityinfo.legacy.shared.reports.model.ReportElement;
import org.activityinfo.legacy.shared.reports.model.TextReportElement;
import org.activityinfo.ui.client.component.report.view.ChartOFCView;
import org.activityinfo.ui.client.page.report.editor.ElementDialog.Callback;
public class ElementWidget extends Composite {
private static ElementWidgetUiBinder uiBinder = GWT.create(ElementWidgetUiBinder.class);
interface ElementWidgetUiBinder extends UiBinder<Widget, ElementWidget> {
}
interface EventHandler {
void onElementRemoveClicked(ElementWidget widget);
void onElementChanged(ElementWidget widget);
}
interface MyStyle extends CssResource {
String title();
String container();
String editButton();
String removeButton();
String blockHover();
}
@UiField HTMLPanel htmlPanel;
@UiField MyStyle style;
@UiField SpanElement titleElement;
@UiField SpanElement titleChangeElement;
@UiField DivElement buttonElement;
@UiField DivElement contentElement;
@UiField DivElement contentContainerElement;
@UiField DivElement loadingElement;
private ReportElement model;
private Dispatcher dispatcher;
private Provider<ElementDialog> dialogProvider;
private EventHandler parent;
@Inject
public ElementWidget(Dispatcher dispatcher, Provider<ElementDialog> dialogProvider) {
this.dispatcher = dispatcher;
this.dialogProvider = dialogProvider;
initWidget(uiBinder.createAndBindUi(this));
sinkEvents(Event.MOUSEEVENTS | Event.ONCLICK);
}
public void bindHandler(EventHandler handler) {
this.parent = handler;
}
public void bind(ReportElement model) {
this.model = model;
titleElement.setInnerText(ElementTitles.format(model));
// for now, preview html is rendered server side,
// except for charts which we can't due to appthengine
// limitations with text rendering. Thats' fine because we
// want to do everything client side eventually anyway
if (model instanceof PivotChartReportElement) {
loadView();
} else {
loadHtml();
}
}
private void loadView() {
dispatcher.execute(new GenerateElement<Content>(model), new AsyncCallback<Content>() {
@Override
public void onFailure(Throwable caught) {
// TODO
}
@Override
public void onSuccess(Content result) {
model.setContent(result);
ChartOFCView view = new ChartOFCView();
view.setHeight(256);
view.setBorders(false);
view.show((PivotChartReportElement) model);
loadingElement.getStyle().setDisplay(Display.NONE);
htmlPanel.add(view, contentElement);
}
});
}
public ReportElement getModel() {
return model;
}
private void loadHtml() {
contentElement.setInnerHTML("");
loadingElement.getStyle().setDisplay(Display.BLOCK);
if (model instanceof TextReportElement) {
renderStaticHtml();
} else {
dispatcher.execute(new RenderReportHtml(model), new AsyncCallback<HtmlResult>() {
@Override
public void onFailure(Throwable caught) {
// TODO Auto-generated method stub
}
@Override
public void onSuccess(HtmlResult result) {
updateHtml(result.getHtml());
}
});
}
}
private void renderStaticHtml() {
String text = ((TextReportElement) model).getText();
updateHtml(text != null ? SafeHtmlUtils.htmlEscape(text) : "");
}
private void updateHtml(String html) {
loadingElement.getStyle().setDisplay(Display.NONE);
contentElement.setInnerHTML(html);
}
@Override
public void onBrowserEvent(Event event) {
Element clicked = event.getEventTarget().cast();
if (event.getTypeInt() == Event.ONCLICK) {
if (titleChangeElement.isOrHasChild(clicked)) {
editTitle();
} else if (clicked.getClassName().contains(style.editButton())) {
edit();
} else if (clicked.getClassName().contains(style.removeButton())) {
parent.onElementRemoveClicked(this);
} else if (contentElement.isOrHasChild(clicked)) {
edit();
}
} else if (event.getTypeInt() == Event.ONMOUSEOVER) {
buttonElement.getStyle().setVisibility(Visibility.VISIBLE);
titleChangeElement.getStyle().setVisibility(Visibility.VISIBLE);
contentContainerElement.addClassName(style.blockHover());
} else if (event.getTypeInt() == Event.ONMOUSEOUT) {
buttonElement.getStyle().setVisibility(Visibility.HIDDEN);
titleChangeElement.getStyle().setVisibility(Visibility.HIDDEN);
contentContainerElement.removeClassName(style.blockHover());
}
}
private void editTitle() {
final MessageBox box = new MessageBox();
box.setTitleHtml(SafeHtmlUtils.htmlEscape(I18N.CONSTANTS.changeTitleDialogTitle()));
box.setType(MessageBoxType.PROMPT);
box.setButtons(Dialog.OKCANCEL);
box.show();
box.getTextBox().setValue(model.getTitle());
box.addCallback(new Listener<MessageBoxEvent>() {
@Override
public void handleEvent(MessageBoxEvent be) {
if (be.getButtonClicked().getItemId().equals(Dialog.OK)) {
model.setTitle(box.getTextBox().getValue());
titleElement.setInnerText(ElementTitles.format(model));
}
}
});
}
private void edit() {
ElementDialog dialog = dialogProvider.get();
dialog.hideCancel();
dialog.show(model, new Callback() {
@Override
public void onOK(boolean dirty) {
onElementUpdated();
}
@Override
public void onClose(boolean dirty) {
onElementUpdated();
}
});
}
private void onElementUpdated() {
loadHtml();
parent.onElementChanged(ElementWidget.this);
}
}