ccc.client.gwt.views.gxt.EditTemplateDialog.java Source code

Java tutorial

Introduction

Here is the source code for ccc.client.gwt.views.gxt.EditTemplateDialog.java

Source

/*-----------------------------------------------------------------------------
 * Copyright (c) 2008 Civic Computing Ltd
 * All rights reserved.
 *
 * This file is part of Content Control.
 *
 * Content Control 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.
 *
 * Content Control 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 Content Control.  If not, see http://www.gnu.org/licenses/.
 *
 * Revision      $Rev$
 * Modified by   $Author$
 * Modified on   $Date$
 *
 * Changes: see subversion log
 *-----------------------------------------------------------------------------
 */

package ccc.client.gwt.views.gxt;

import static ccc.client.core.InternalServices.*;

import java.util.UUID;

import ccc.api.core.Resource;
import ccc.api.core.ResourceSummary;
import ccc.api.core.Template;
import ccc.api.types.MimeType;
import ccc.api.types.ResourceName;
import ccc.api.types.ResourceType;
import ccc.client.actions.CreateTemplateAction;
import ccc.client.actions.UpdateTemplateAction;
import ccc.client.core.DialogMode;
import ccc.client.core.I18n;
import ccc.client.core.InternalServices;
import ccc.client.core.SingleSelectionModel;
import ccc.client.core.ValidationResult;
import ccc.client.gwt.binding.EnumModelData;
import ccc.client.gwt.widgets.CodeMirrorEditor;
import ccc.client.gwt.widgets.CodeMirrorEditor.EditorListener;
import ccc.client.gwt.widgets.CodeMirrorEditor.Type;

import com.extjs.gxt.ui.client.Style.HorizontalAlignment;
import com.extjs.gxt.ui.client.Style.SortDir;
import com.extjs.gxt.ui.client.event.BoxComponentEvent;
import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.ComponentEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
import com.extjs.gxt.ui.client.event.SelectionChangedListener;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.HorizontalPanel;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.Text;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.form.ComboBox;
import com.extjs.gxt.ui.client.widget.form.FormPanel;
import com.extjs.gxt.ui.client.widget.form.HiddenField;
import com.extjs.gxt.ui.client.widget.form.TextField;
import com.extjs.gxt.ui.client.widget.form.TriggerField;
import com.extjs.gxt.ui.client.widget.form.ComboBox.TriggerAction;
import com.extjs.gxt.ui.client.widget.form.FormPanel.Method;
import com.extjs.gxt.ui.client.widget.layout.FormData;
import com.extjs.gxt.ui.client.widget.layout.FormLayout;
import com.extjs.gxt.ui.client.widget.layout.TableData;
import com.google.gwt.user.client.Window;

/**
 * Dialog for creating / updating templates.
 *
 * @author Civic Computing Ltd.
 */
public class EditTemplateDialog extends AbstractWizardDialog implements EditorListener {

    /** DEFAULT_WIDTH : int. */
    protected static final int DEFAULT_WIDTH = 640;
    /** DEFAULT_HEIGHT : int. */
    protected static final int DEFAULT_HEIGHT = 430;
    /** TEXT_AREA_HEIGHT : int. */
    protected static final int TEXT_AREA_HEIGHT = 300;

    private final FormPanel _first = new FormPanel();
    private final FormPanel _second = new FormPanel();
    private final PreviewFormPanel _third = new PreviewFormPanel();
    private HiddenField<String> _postBody = new HiddenField<String>();
    private final TriggerField<String> _targetPath = new TriggerField<String>();

    private final TextField<String> _name = new TextField<String>();
    private final TextField<String> _mimePrimary = new TextField<String>();
    private final TextField<String> _mimeSub = new TextField<String>();
    private CodeMirrorEditor _body;
    private CodeMirrorEditor _definition;

    private enum TemplateTypes {
        Velocity, Javascript;
    }

    private final ComboBox<EnumModelData<TemplateTypes>> _bodyMime = new ComboBox<EnumModelData<TemplateTypes>>();
    private final ListStore<EnumModelData<TemplateTypes>> _store = new ListStore<EnumModelData<TemplateTypes>>();

    private Template _model;
    private UUID _parentFolderId = null;
    private final DialogMode _mode;
    private final SingleSelectionModel _ssm;
    private ResourceSummary _proxy;
    private final String _definitionString;
    private final String _bodyString;

    private EditTemplateDialog(final DialogMode mode, final SingleSelectionModel ssm, final String definitionString,
            final String bodyString) {
        super(I18n.uiConstants.editTemplate(), InternalServices.globals);

        _mode = mode;
        _ssm = ssm;
        _definitionString = definitionString;
        _bodyString = bodyString;

        _store.add(new EnumModelData(TemplateTypes.Javascript));
        _store.add(new EnumModelData(TemplateTypes.Velocity));
        _store.sort(ResourceSummary.Properties.NAME, SortDir.ASC);
        _bodyMime.setStore(_store);
    }

    /**
     * Constructor.
     *
     * @param parentFolderId The id of the parent folder.
     * @param ssm The selection model.
     */
    public EditTemplateDialog(final UUID parentFolderId, final SingleSelectionModel ssm) {
        this(DialogMode.CREATE, ssm, "<fields></fields>", "<html/>");

        setWidth(DEFAULT_WIDTH);
        setHeight(DEFAULT_HEIGHT);

        _parentFolderId = parentFolderId;

        _bodyMime.setValue(new EnumModelData<TemplateTypes>(TemplateTypes.Velocity));

        populateFirstScreen();
        populateSecondScreen();
        populateThirdScreen();

        addCard(_first);
        addCard(_second);
        addCard(_third);

        addResizeListener();

        refresh();
    }

    /**
     * Constructor.
     *
     * @param model The template to update.
     * @param proxy The resource model.
     * @param ssm The selection model.
     */
    public EditTemplateDialog(final Template model, final ResourceSummary proxy, final SingleSelectionModel ssm) {
        this(DialogMode.UPDATE, ssm, model.getDefinition(), model.getBody());

        setWidth(DEFAULT_WIDTH);
        setHeight(DEFAULT_HEIGHT);

        _proxy = proxy;
        _model = model;

        populateFirstScreen();
        populateSecondScreen();
        populateThirdScreen();

        addCard(_first);
        addCard(_second);
        addCard(_third);

        addResizeListener();

        _name.setReadOnly(true);
        _name.disable();

        _name.setValue(proxy.getName().toString());
        _mimePrimary.setValue(model.getMimeType().getPrimaryType());
        _mimeSub.setValue(model.getMimeType().getSubType());

        final TemplateTypes tt = (MimeType.JAVASCRIPT.equals(model.getBodyMimeType())) ? TemplateTypes.Javascript
                : TemplateTypes.Velocity;
        _bodyMime.setValue(new EnumModelData<TemplateTypes>(tt));

        refresh();
    }

    private void addResizeListener() {

        addListener(Events.Resize, new Listener<BoxComponentEvent>() {
            @Override
            public void handleEvent(final BoxComponentEvent be) {
                final int h = be.getHeight() - (DEFAULT_HEIGHT - TEXT_AREA_HEIGHT);
                if (h > (DEFAULT_HEIGHT - TEXT_AREA_HEIGHT)) {
                    _definition.setEditorHeight(h + "px");
                    _body.setEditorHeight((h - 40) + "px");
                }
            }
        });
    }

    private void populateFirstScreen() {
        _first.setWidth("100%");
        _first.setBorders(false);
        _first.setBodyBorder(false);
        _first.setHeaderVisible(false);

        _name.setFieldLabel(getUiConstants().name());
        _name.setAllowBlank(false);
        _first.add(_name, new FormData("95%"));

        _mimePrimary.setFieldLabel(getUiConstants().mimePrimaryType());
        _mimePrimary.setAllowBlank(false);
        _first.add(_mimePrimary, new FormData("95%"));

        _mimeSub.setFieldLabel(getUiConstants().mimeSubType());
        _mimeSub.setAllowBlank(false);
        _first.add(_mimeSub, new FormData("95%"));
    }

    private void populateSecondScreen() {
        _second.setWidth("100%");
        _second.setBorders(false);
        _second.setBodyBorder(false);
        _second.setHeaderVisible(false);

        final Text fieldName = new Text(getUiConstants().definitionXML());
        fieldName.setStyleName("x-form-item");
        _second.add(fieldName);
        _definition = new CodeMirrorEditor("definition", this, CodeMirrorEditor.Type.DEFINITION, false);
        _second.add(_definition, new FormData("95%"));
    }

    private void populateThirdScreen() {
        _third.setMethod(Method.POST);
        _third.setTarget("_templatePreview");
        _third.setWidth("100%");
        _third.setBorders(false);
        _third.setBodyBorder(false);
        _third.setHeaderVisible(false);

        _postBody.setName("hiddenbody");
        _third.add(_postBody);

        _targetPath.setFieldLabel(constants().path());
        _targetPath.setValue("");
        _targetPath.addListener(Events.TriggerClick, new TargetListener());

        final Button previewButton = new Button("preview", new SelectionListener<ButtonEvent>() {
            @Override
            public void componentSelected(final ButtonEvent ce) {
                Window.open("", "_templatePreview", "");
                _third.setAction(InternalServices.globals.appURL() + "previewtemplate" + _targetPath.getValue());
                _postBody.setValue(_body.getEditorCode());
                _third.submit();
            }
        });

        final HorizontalPanel previewPanel = new HorizontalPanel();
        final FormLayout layout = new FormLayout();
        final LayoutContainer lc = new LayoutContainer(layout);
        lc.add(_targetPath);

        previewPanel.setWidth("95%");
        previewPanel.setTableWidth("100%");
        final TableData tdr = new TableData();
        final TableData tdl = new TableData();
        tdr.setHorizontalAlign(HorizontalAlignment.RIGHT);
        tdl.setHorizontalAlign(HorizontalAlignment.LEFT);

        previewPanel.add(lc, tdl);
        previewPanel.add(previewButton, tdr);
        _third.add(previewPanel);

        _bodyMime.setFieldLabel(getUiConstants().type());
        _bodyMime.setDisplayField(ResourceSummary.Properties.NAME);
        _bodyMime.setEditable(false);
        _bodyMime.setForceSelection(true);
        _bodyMime.setTriggerAction(TriggerAction.ALL);
        _bodyMime.addSelectionChangedListener(new SelectionChangedListener<EnumModelData<TemplateTypes>>() {
            @Override
            public void selectionChanged(final SelectionChangedEvent<EnumModelData<TemplateTypes>> se) {
                final String bodyParser = parserForMimeType(se.getSelectedItem().getValue());
                _body.setParser(bodyParser);
            }
        });
        _third.add(_bodyMime, new FormData("95%"));

        final Text fieldName = new Text(getUiConstants().body());
        fieldName.setStyleName("x-form-item");
        _third.add(fieldName);
        _body = new CodeMirrorEditor("body", this, CodeMirrorEditor.Type.BODY, false, TEXT_AREA_HEIGHT - 40);
        _third.add(_body, new FormData("95%"));
    }

    private Template model() {
        final Template delta = new Template();
        delta.setBody(_body.getEditorCode());
        delta.setDefinition(_definition.getEditorCode());
        delta.setMimeType(new MimeType(_mimePrimary.getValue(), _mimeSub.getValue()));

        final MimeType tt = (TemplateTypes.Javascript == _bodyMime.getValue().getValue()) ? MimeType.JAVASCRIPT
                : MimeType.VELOCITY;
        delta.setBodyMimeType(tt);

        return delta;
    }

    /** {@inheritDoc} */
    @Override
    protected SelectionListener<ButtonEvent> saveAction() {
        return new SelectionListener<ButtonEvent>() {
            @Override
            public void componentSelected(final ButtonEvent ce) {

                final ValidationResult vr = new ValidationResult();
                vr.addError(validator.notEmpty(_definition.getEditorCode(), getUiConstants().definitionXML()));
                vr.addError(validator.notEmpty(_name.getValue(), _name.getFieldLabel()));
                vr.addError(validator.notEmpty(_body.getEditorCode(), getUiConstants().body()));
                vr.addError(validator.notEmpty(_mimePrimary.getValue(), _mimePrimary.getFieldLabel()));
                vr.addError(validator.notEmpty(_mimeSub.getValue(), _mimeSub.getFieldLabel()));
                vr.addError(validator.notValidResourceName(_name.getValue(), _name.getFieldLabel()));
                vr.addError(validator.notValidXML(_definition.getEditorCode()));

                if (!vr.isValid()) {
                    InternalServices.window.alert(vr.getErrorText());
                    return;
                }

                createTemplates();
            }
        };
    }

    private void createTemplates() {
        final Template delta = model();
        switch (_mode) {
        case CREATE:

            delta.setTitle(_name.getValue());
            delta.setDescription(_name.getValue());
            delta.setName(new ResourceName(_name.getValue()));
            delta.setParent(_parentFolderId);

            new CreateTemplateAction(delta) {
                @Override
                protected void execute(final Template template) {
                    _ssm.create(template);
                    hide();
                }
            }.execute();
            break;
        case UPDATE:

            delta.setId(_proxy.getId());
            delta.addLink(Resource.Links.SELF, _model.getLink(Resource.Links.SELF));

            new UpdateTemplateAction(delta) {
                /** {@inheritDoc} */
                @Override
                protected void onSuccess(final Template t) {
                    _ssm.update(_proxy);
                    hide();
                }
            }.execute();
            break;
        default:
            InternalServices.window.alert(constants().error());
            break;
        }
    }

    /** {@inheritDoc} */
    @Override
    public void onInitialized(final Type type, final CodeMirrorEditor editor) {
        // FIXME: Dodgy.
        if (CodeMirrorEditor.Type.BODY == type) {
            editor.setEditorCode(_bodyString);
            final String bodyParser = parserForMimeType(_bodyMime.getValue().getValue());
            editor.setParser(bodyParser);
        } else if (CodeMirrorEditor.Type.DEFINITION == type) {
            editor.setEditorCode(_definitionString);
        }
    }

    private String parserForMimeType(final TemplateTypes tt) {
        if (TemplateTypes.Javascript == tt) {
            return "JSParser";
        }
        return "HTMLMixedParser";
    }

    /**
     * Class required to override private 'setTarget' method in FormPanel.
     *
     * @author petteri
     *
     */
    public class PreviewFormPanel extends FormPanel {
        public native void setTarget(String target)/*-{
                                                   this.@com.extjs.gxt.ui.client.widget.form.FormPanel::setTarget(Ljava/lang/String;)(target);
                                                   }-*/;
    };

    public class TargetListener implements Listener<ComponentEvent> {
        public void handleEvent(final ComponentEvent be) {

            ResourceSummary root = null;

            for (final ResourceSummary item : InternalServices.roots.getElements()) {
                if (item.getName().toString().equals("content")) {
                    root = item;
                }
            }

            final ResourceSelectionDialog resourceSelect = new ResourceSelectionDialog(root, null);
            resourceSelect.addListener(Events.Hide, new Listener<ComponentEvent>() {
                public void handleEvent(final ComponentEvent be2) {
                    final ResourceSummary target = resourceSelect.selectedResource();
                    if (target != null && target.getType() != ResourceType.RANGE_FOLDER) {
                        _targetPath.setValue(target.getAbsolutePath());
                    }
                }
            });
            resourceSelect.show();
        }
    }
}