org.hippoecm.frontend.plugins.cms.browse.tree.SectionTreePlugin.java Source code

Java tutorial

Introduction

Here is the source code for org.hippoecm.frontend.plugins.cms.browse.tree.SectionTreePlugin.java

Source

/*
 *  Copyright 2008-2015 Hippo B.V. (http://www.onehippo.com)
 *
 *  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.hippoecm.frontend.plugins.cms.browse.tree;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.IChoiceRenderer;
import org.apache.wicket.markup.html.internal.HtmlHeaderContainer;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.EmptyPanel;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.model.IDetachable;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.StringResourceModel;
import org.hippoecm.frontend.l10n.ResourceBundleModel;
import org.hippoecm.frontend.model.IModelReference;
import org.hippoecm.frontend.model.JcrNodeModel;
import org.hippoecm.frontend.plugin.IPlugin;
import org.hippoecm.frontend.plugin.IPluginContext;
import org.hippoecm.frontend.plugin.config.IPluginConfig;
import org.hippoecm.frontend.service.IRenderService;
import org.hippoecm.frontend.service.render.AbstractRenderService;
import org.hippoecm.frontend.service.render.ListRenderService;
import org.hippoecm.frontend.service.render.RenderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@SuppressWarnings("unused")
public class SectionTreePlugin extends ListRenderService implements IPlugin {

    private static final long serialVersionUID = 1L;

    private class Section implements IDetachable {
        private static final long serialVersionUID = 1L;

        private final String extension;
        private final String header;
        private boolean focused;
        private boolean selected;
        private final AbstractRenderService.ExtensionPoint extPt;

        Section(String extension, String header) {
            this.extension = extension;
            this.header = header;
            this.focused = false;
            this.extPt = children.get(extension);
        }

        boolean hasChildren() {
            return !extPt.getChildren().isEmpty();
        }

        @SuppressWarnings("unchecked")
        List<IRenderService> getChildren() {
            return extPt.getChildren();
        }

        public IRenderService getRenderer() {
            if (hasChildren()) {
                return (IRenderService) extPt.getChildren().get(0);
            }
            return null;
        }

        public void detach() {
            for (IRenderService service : getChildren()) {
                service.getComponent().detach();
            }
        }
    }

    static final Logger log = LoggerFactory.getLogger(SectionTreePlugin.class);

    final DropDownChoice<Section> select;
    final IModel<List<Section>> sections;
    boolean findSectionForInitialFocus = true;

    public SectionTreePlugin(final IPluginContext context, final IPluginConfig config) {
        super(context, config);

        setOutputMarkupId(true);
        add(new AttributeAppender("class", Model.of("section-viewer"), " "));

        final List<String> headers = Arrays.asList(config.getStringArray("headers"));
        final List<String> extensions = Arrays.asList(config.getStringArray(RenderService.EXTENSIONS_ID));
        final List<Section> allSections = new ArrayList<>(extensions.size());
        for (int i = 0; i < extensions.size(); i++) {
            String extension = extensions.get(i);
            String header = extension;
            if (!headers.isEmpty() && i < headers.size()) {
                header = headers.get(i);
            }
            allSections.add(new Section(extension, header));
        }

        sections = new AbstractReadOnlyModel<List<Section>>() {
            @Override
            public List<Section> getObject() {
                return allSections.stream().filter(Section::hasChildren).collect(Collectors.toList());
            }
        };

        add(new ListView<Section>("list", sections) {
            private static final long serialVersionUID = 1L;

            @Override
            protected void populateItem(ListItem<Section> item) {
                final Section section = item.getModelObject();
                if (section.hasChildren()) {
                    Component c = section.getRenderer().getComponent();
                    item.add(c);
                } else {
                    item.add(new EmptyPanel("id"));
                }

                item.add(new AttributeAppender("class", new AbstractReadOnlyModel<String>() {
                    @Override
                    public String getObject() {
                        return section.focused ? "selected" : "unselected";
                    }
                }, " "));

            }
        });

        final Form form = new Form("selection-form");
        add(form);

        final IModel<Section> selectModel = new Model<>(null);
        select = new DropDownChoice<Section>("select", selectModel, sections, new IChoiceRenderer<Section>() {
            @Override
            public Object getDisplayValue(final Section section) {
                return new ResourceBundleModel("hippo:cms.sections", section.header).getObject();
            }

            @Override
            public String getIdValue(final Section section, final int index) {
                return section.extension;
            }
        }) {
            @Override
            public boolean isEnabled() {
                if (sections != null) {
                    final List<Section> choices = sections.getObject();
                    return choices != null && choices.size() > 1;
                }
                return false;
            }
        };
        select.add(new AjaxFormComponentUpdatingBehavior("onchange") {
            @Override
            protected void onUpdate(final AjaxRequestTarget target) {
                Section section = selectModel.getObject();
                focusSection(section);
                SectionTreePlugin.this.redraw();
            }
        });
        form.add(select);
    }

    @Override
    public void onBeforeRender() {
        final List<Section> sectionList = sections.getObject();

        if (findSectionForInitialFocus) {
            Section section = findFocus();
            if (section != null) {
                focusRenderer(section);
            } else {
                if (!sectionList.isEmpty()) {
                    section = sectionList.get(0);
                    select.getModel().setObject(section);
                    focusSection(section);
                }
            }
            findSectionForInitialFocus = false;
        }

        for (Section section : sectionList) {
            for (IRenderService service : section.getChildren()) {
                Component component = service.getComponent();
                component.setVisible(section.focused);
            }
        }
        super.onBeforeRender();
    }

    private void focusRenderer(final Section section) {
        final IRenderService renderer = section.getRenderer();
        if (renderer != null) {
            renderer.focus(null);
        }
    }

    @Override
    public void renderHead(final HtmlHeaderContainer container) {
        super.renderHead(container);

        final IHeaderResponse response = container.getHeaderResponse();
        final String selectricOptions = "{ " + "optionsItemBuilder: '<span class=\"{value}\">{text}</span>',"
                + "labelBuilder: '<span title=\"{text}\">{text}</span>'" + "}";
        final String selectricInit = String.format("jQuery('#%s').selectric(%s);", select.getMarkupId(),
                selectricOptions);
        response.render(OnDomReadyHeaderItem.forScript(selectricInit));
    }

    @Override
    public void focus(IRenderService child) {
        if (child != null) {
            for (Section section : sections.getObject()) {
                if (section.extPt.getChildren().contains(child)) {
                    if (updateStates(section)) {
                        redraw();
                    }
                    break;
                }
            }
        } else {
            super.focus(null);
        }
    }

    @Override
    protected void onModelChanged() {
        super.onModelChanged();
        Section section = findFocus();
        if (section != null) {
            focusRenderer(section);
        }
    }

    @Override
    protected void onDetach() {
        sections.getObject().forEach(SectionTreePlugin.Section::detach);
        super.onDetach();
    }

    private Section findFocus() {
        JcrNodeModel model = (JcrNodeModel) getDefaultModel();
        if (model == null || model.getItemModel() == null || model.getItemModel().getPath() == null) {
            return null;
        }

        int matchLength = 0;
        Section focusedSection = null;
        for (Section section : sections.getObject()) {
            if (section.hasChildren()) {
                IRenderService renderService = section.getRenderer();
                IModelReference modelService = getPluginContext().getService(
                        getPluginContext().getReference(renderService).getServiceId(), IModelReference.class);
                if (modelService != null) {
                    IModel sectionModel = modelService.getModel();
                    if (sectionModel instanceof JcrNodeModel) {
                        JcrNodeModel sectionRoot = (JcrNodeModel) sectionModel;
                        if (sectionRoot.getItemModel() != null) {
                            if (model.getItemModel().getPath().startsWith(sectionRoot.getItemModel().getPath())) {
                                if (sectionRoot.getItemModel().getPath().length() > matchLength) {
                                    matchLength = sectionRoot.getItemModel().getPath().length();
                                    focusedSection = section;
                                }
                            }
                        }
                    }
                }
            }
        }
        return focusedSection;
    }

    private void focusSection(final Section section) {
        if (section.hasChildren()) {
            IRenderService renderer = section.getRenderer();
            IModelReference modelService = getPluginContext()
                    .getService(getPluginContext().getReference(renderer).getServiceId(), IModelReference.class);
            if (modelService != null) {
                IModel sectionModel = modelService.getModel();
                SectionTreePlugin.this.setDefaultModel(sectionModel);
            }
        }
        updateStates(section);
    }

    private boolean updateStates(Section section) {
        boolean dirty = false;
        for (Section curSection : sections.getObject()) {
            if (curSection == section) {
                if (!curSection.focused) {
                    curSection.focused = true;
                    dirty = true;
                }
                if (!curSection.selected) {
                    curSection.selected = true;
                    dirty = true;
                }
            } else {
                if (curSection.focused) {
                    curSection.focused = false;
                    dirty = true;
                }
                if (curSection.selected) {
                    curSection.selected = false;
                    dirty = true;
                }
            }
        }
        return dirty;
    }

    public void start() {
    }

    public void stop() {
    }

}