package org.activityinfo.ui.client.page.report; /* * #%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.Style.LayoutRegion; import com.extjs.gxt.ui.client.event.*; import com.extjs.gxt.ui.client.widget.ContentPanel; import com.extjs.gxt.ui.client.widget.Dialog; import com.extjs.gxt.ui.client.widget.Info; import com.extjs.gxt.ui.client.widget.MessageBox; import com.extjs.gxt.ui.client.widget.button.Button; import com.extjs.gxt.ui.client.widget.layout.BorderLayout; import com.extjs.gxt.ui.client.widget.layout.BorderLayoutData; import com.google.common.base.Strings; import com.google.gwt.i18n.client.DateTimeFormat; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.inject.Inject; import org.activityinfo.i18n.shared.I18N; import org.activityinfo.legacy.client.AsyncMonitor; import org.activityinfo.legacy.client.Dispatcher; import org.activityinfo.legacy.client.monitor.MaskingAsyncMonitor; import org.activityinfo.legacy.shared.Log; import org.activityinfo.legacy.shared.command.CreateReport; import org.activityinfo.legacy.shared.command.GetReportModel; import org.activityinfo.legacy.shared.command.RenderElement.Format; import org.activityinfo.legacy.shared.command.UpdateReportModel; import org.activityinfo.legacy.shared.command.UpdateReportSubscription; import org.activityinfo.legacy.shared.command.result.CreateResult; import org.activityinfo.legacy.shared.command.result.VoidResult; import org.activityinfo.legacy.shared.model.ReportDTO; import org.activityinfo.legacy.shared.model.ReportMetadataDTO; import org.activityinfo.legacy.shared.reports.model.Report; import org.activityinfo.ui.client.EventBus; import org.activityinfo.ui.client.page.*; import org.activityinfo.ui.client.page.common.dialog.SaveChangesCallback; import org.activityinfo.ui.client.page.common.dialog.SavePromptMessageBox; import org.activityinfo.ui.client.page.common.toolbar.ExportCallback; import org.activityinfo.ui.client.page.report.editor.CompositeEditor2; import org.activityinfo.ui.client.page.report.editor.EditorProvider; import org.activityinfo.ui.client.page.report.editor.ReportElementEditor; import org.activityinfo.ui.client.page.report.resources.ReportResources; import java.util.Date; public class ReportDesignPage extends ContentPanel implements Page, ExportCallback { private class SaveCallback implements AsyncCallback<VoidResult> { @Override public void onSuccess(final VoidResult result) { Info.display(I18N.CONSTANTS.saved(), I18N.MESSAGES.reportSaved(currentModel.getTitle())); onSaved(); } @Override public final void onFailure(final Throwable caught) { MessageBox.alert(I18N.CONSTANTS.serverError(), caught.getMessage(), null); } public void onSaved() { } } public static final PageId PAGE_ID = new PageId("report"); private final EventBus eventBus; private final Dispatcher dispatcher; private final EditorProvider editorProvider; private boolean reportEdited; private ReportBar reportBar; private boolean dirty = false; /** * The model being edited on this page */ private Report currentModel; private ReportMetadataDTO currentMetadata; /** * The editor for the model */ private ReportElementEditor currentEditor; @Inject public ReportDesignPage(final EventBus eventBus, final Dispatcher service, final EditorProvider editorProvider) { this.eventBus = eventBus; this.dispatcher = service; this.editorProvider = editorProvider; ReportResources.INSTANCE.style().ensureInjected(); setLayout(new BorderLayout()); setHeaderVisible(false); createToolbar(); eventBus.addListener(ReportChangeEvent.TYPE, new Listener<ReportChangeEvent>() { @Override public void handleEvent(final ReportChangeEvent event) { if (event.getModel() == currentModel || currentModel.getElements().contains(event.getModel())) { Log.debug("marking report as dirty"); dirty = true; } } }); } public void createToolbar() { reportBar = new ReportBar(); BorderLayoutData reportBarLayout = new BorderLayoutData(LayoutRegion.NORTH); reportBarLayout.setSize(35); add(reportBar, reportBarLayout); reportBar.getExportButton().setCallback(this); reportBar.addTitleEditCompleteListener(new Listener<EditorEvent>() { @Override public void handleEvent(final EditorEvent be) { String newTitle = (String) be.getValue(); if (newTitle != null && !newTitle.equals(currentModel.getTitle())) { currentModel.setTitle(newTitle); reportBar.setReportTitle(newTitle); save(new SaveCallback()); } } }); reportBar.getSaveButton().addSelectionListener(new SelectionListener<ButtonEvent>() { @Override public void componentSelected(final ButtonEvent ce) { saveTitled(null, new SaveCallback()); } }); reportBar.getShareButton().addSelectionListener(new SelectionListener<ButtonEvent>() { @Override public void componentSelected(final ButtonEvent ce) { showShareForm(); } }); reportBar.getDashboardButton().addSelectionListener(new SelectionListener<ButtonEvent>() { @Override public void componentSelected(final ButtonEvent ce) { pinToDashboard(reportBar.getDashboardButton().isPressed()); } }); reportBar.getSwitchViewButton().addSelectionListener(new SelectionListener<ButtonEvent>() { @Override public void componentSelected(final ButtonEvent ce) { switchView(); } }); } @Override public boolean navigate(final PageState place) { if (place instanceof ReportDesignPageState) { go(((ReportDesignPageState) place).getReportId()); return true; } return false; } public void go(final int reportId) { loadReport(reportId); } private void loadReport(final int reportId) { dispatcher.execute(new GetReportModel(reportId, true), new MaskingAsyncMonitor(this, I18N.CONSTANTS.loading()), new AsyncCallback<ReportDTO>() { @Override public void onFailure(final Throwable caught) { } @Override public void onSuccess(final ReportDTO result) { onModelLoaded(result); } }); } private void onModelLoaded(final ReportDTO result) { this.currentModel = result.getReport(); this.currentMetadata = result.getReportMetadataDTO(); reportBar.setReportTitle(currentModel.getTitle()); reportBar.getDashboardButton().toggle(currentMetadata.isDashboard()); if (currentModel.getElements().size() == 1) { ReportElementEditor editor = editorProvider.create(currentModel.getElement(0)); editor.bind(currentModel.getElement(0)); installEditor(editor); reportBar.getSwitchViewButton().setVisible(true); } else { installCompositeEditor(); } } private void installCompositeEditor() { CompositeEditor2 editor = (CompositeEditor2) editorProvider.create(currentModel); editor.bind(currentModel); installEditor(editor); reportBar.getSwitchViewButton().setVisible(false); } protected void switchView() { installCompositeEditor(); } private void installEditor(final ReportElementEditor editor) { if (currentEditor != null) { remove(currentEditor.getWidget()); } reportBar.getExportButton().setFormats(editor.getExportFormats()); add(editor.getWidget(), new BorderLayoutData(LayoutRegion.CENTER)); this.currentEditor = editor; layout(); } private void pinToDashboard(final boolean pressed) { saveTitled(new SaveCallback() { @Override public void onSaved() { final UpdateReportSubscription update = new UpdateReportSubscription(); update.setReportId(currentModel.getId()); update.setPinnedToDashboard(pressed); dispatcher.execute(update, new SaveCallback() { @Override public void onSuccess(final VoidResult result) { if (update.getPinnedToDashboard()) { Info.display(I18N.CONSTANTS.saved(), I18N.MESSAGES.addedToDashboard(currentModel.getTitle())); } else { Info.display(I18N.CONSTANTS.saved(), I18N.MESSAGES.removedFromDashboard(currentModel.getTitle())); } } }); } }); } private void saveTitled(final AsyncMonitor monitor, final SaveCallback callback) { if (untitled()) { promptForTitle(callback); } else { save(monitor, callback); } } private void saveTitled(final SaveCallback callback) { if (untitled()) { promptForTitle(callback); } else { callback.onSaved(); } } private void promptForTitle(final AsyncCallback<VoidResult> callback) { MessageBox.prompt(I18N.CONSTANTS.save(), I18N.CONSTANTS.chooseReportTitle(), new Listener<MessageBoxEvent>() { @Override public void handleEvent(final MessageBoxEvent be) { String newTitle = be.getMessageBox().getTextBox().getValue(); if (!Strings.isNullOrEmpty(newTitle)) { currentModel.setTitle(newTitle); reportBar.setReportTitle(newTitle); save(callback); } } }); } private void save(final AsyncCallback<VoidResult> callback) { save(null, callback); } private void save(final AsyncMonitor monitor, final AsyncCallback<VoidResult> callback) { if (currentMetadata.isEditAllowed()) { performUpdate(monitor, callback); } else { confirmCreate(monitor, callback); } } private void performUpdate(final AsyncMonitor monitor, final AsyncCallback<VoidResult> callback) { UpdateReportModel updateReport = new UpdateReportModel(); updateReport.setModel(currentModel); dispatcher.execute(updateReport, monitor, new AsyncCallback<VoidResult>() { @Override public void onFailure(final Throwable caught) { callback.onFailure(caught); } @Override public void onSuccess(final VoidResult result) { dirty = false; callback.onSuccess(result); } }); } private void confirmCreate(final AsyncMonitor monitor, final AsyncCallback<VoidResult> callback) { MessageBox.confirm(I18N.CONSTANTS.save(), I18N.MESSAGES.confirmSaveCopy(), new Listener<MessageBoxEvent>() { @Override public void handleEvent(final MessageBoxEvent be) { Button btn = be.getButtonClicked(); if (Dialog.YES.equalsIgnoreCase(btn.getItemId())) { performCreate(); } } }); } private void performCreate() { currentModel.setTitle(currentModel.getTitle() + " (" + I18N.CONSTANTS.copy() + ")"); dispatcher.execute(new CreateReport(currentModel), new AsyncCallback<CreateResult>() { @Override public void onFailure(final Throwable caught) { } @Override public void onSuccess(final CreateResult created) { eventBus.fireEvent(new NavigationEvent(NavigationHandler.NAVIGATION_REQUESTED, new ReportDesignPageState(created.getNewId()))); } }); } public void setReportEdited(final boolean edited) { reportEdited = edited; } public boolean reportEdited() { return reportEdited; } @Override public void shutdown() { // TODO Auto-generated method stub } @Override public PageId getPageId() { return PAGE_ID; } @Override public Object getWidget() { return this; } @Override public void requestToNavigateAway(final PageState place, final NavigationCallback callback) { if (!dirty) { callback.onDecided(true); } else { SavePromptMessageBox box = new SavePromptMessageBox(); box.show(new SaveChangesCallback() { @Override public void save(final AsyncMonitor monitor) { saveTitled(monitor, new SaveCallback() { @Override public void onSaved() { callback.onDecided(true); } }); } @Override public void discard() { callback.onDecided(true); } @Override public void cancel() { callback.onDecided(false); } }); } } @Override public String beforeWindowCloses() { // TODO Auto-generated method stub return null; } public void showShareForm() { saveTitled(new SaveCallback() { @Override public void onSaved() { final ShareReportDialog dialog = new ShareReportDialog(dispatcher); // form.updateForm(currentReportId); dialog.show(currentModel); } }); } @Override public void export(final Format format) { StringBuilder fileName = new StringBuilder(); fileName.append(untitled() ? I18N.CONSTANTS.untitledReport() : currentModel.getTitle()); fileName.append(" "); fileName.append(DateTimeFormat.getFormat("yyyyMMdd_HHmm").format(new Date())); ExportDialog dialog = new ExportDialog(dispatcher); dialog.export(fileName.toString(), currentEditor.getModel(), format); } private boolean untitled() { return currentModel.getTitle() == null; } }