org.lunifera.vaaclipse.ui.preferences.addon.internal.PreferencesDialog.java Source code

Java tutorial

Introduction

Here is the source code for org.lunifera.vaaclipse.ui.preferences.addon.internal.PreferencesDialog.java

Source

/**
 * Copyright (c) 2011 - 2015, Lunifera GmbH (Gross Enzersdorf), Loetz KG (Heidelberg)
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *         Florian Pirchner - Initial implementation
 */
package org.lunifera.vaaclipse.ui.preferences.addon.internal;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.inject.Inject;

import org.eclipse.e4.core.contexts.ContextInjectionFactory;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.di.annotations.Optional;
import org.eclipse.e4.core.services.events.IEventBroker;
import org.eclipse.emf.common.util.EList;
import org.lunifera.vaaclipse.ui.preferences.addon.PreferencesAuthorization;
import org.lunifera.vaaclipse.ui.preferences.addon.PreferencesEvents;
import org.lunifera.vaaclipse.ui.preferences.addon.internal.exception.ValidationFailedException;
import org.lunifera.vaaclipse.ui.preferences.addon.internal.util.ModelHelper;
import org.lunifera.vaaclipse.ui.preferences.addon.internal.util.PrefHelper;
import org.lunifera.vaaclipse.ui.preferences.model.FieldEditor;
import org.lunifera.vaaclipse.ui.preferences.model.PreferencesCategory;
import org.lunifera.vaaclipse.ui.preferences.model.PreferencesPage;
import org.osgi.framework.BundleContext;
import org.osgi.service.prefs.BackingStoreException;
import org.osgi.service.prefs.Preferences;
import org.semanticsoft.vaaclipse.publicapi.resources.BundleResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.vaadin.data.Item;
import com.vaadin.event.FieldEvents.TextChangeEvent;
import com.vaadin.event.FieldEvents.TextChangeListener;
import com.vaadin.event.ItemClickEvent;
import com.vaadin.server.Sizeable;
import com.vaadin.shared.MouseEventDetails.MouseButton;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.CssLayout;
import com.vaadin.ui.HorizontalSplitPanel;
import com.vaadin.ui.Label;
import com.vaadin.ui.Notification;
import com.vaadin.ui.Panel;
import com.vaadin.ui.TextField;
import com.vaadin.ui.Tree;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;

import e4modelextension.VaaclipseApplication;

/**
 * @author rushan
 *
 */
public class PreferencesDialog {

    static final String PAGE_HEADER_ERROR_TEXT = "page-header-error-text";

    @Inject
    IEventBroker eventBroker;

    @Inject
    VaaclipseApplication app;

    @Inject
    IEclipseContext context;

    @Inject
    @Optional
    PreferencesCategory selectedCategory;

    @Inject
    @Optional
    PreferencesAuthorization authService;

    Logger logger = LoggerFactory.getLogger(PreferencesDialog.class);

    @Inject
    UI ui;

    TextField filterField = new TextField();

    private Tree tree;

    private Window window;

    HorizontalSplitPanel splitPanel = new HorizontalSplitPanel();

    private Panel treePanel;

    private VerticalLayout rightSide;

    private CssLayout leftSide;

    private Button filterButton = new Button();
    private Button clearFilterButton = new Button();

    private CssLayout pageHeader;

    private CssLayout pageContent;

    private CssLayout pageBottom;

    private Button restoreDefaults;

    private Button apply;

    private VerticalLayout root;

    private CssLayout dlgButtonPanel;

    private Button cancelButton;

    private Button okButton;

    private Label pageHeaderText;

    private BundleContext bundleContext;

    private String errorMessage;

    List<PreferencesPage> visitedPages = new ArrayList<>();

    private HashSet<PreferencesCategory> visibleCategories;

    private List<PreferencesCategory> categoryList = new ArrayList<>(100);

    public Window getWindow() {
        return window;
    }

    public PreferencesCategory getSelectedCategory() {
        return selectedCategory;
    }

    public PreferencesPage getCurrentPage() {
        return selectedCategory.getPage();
    }

    @PostConstruct
    public void init() {
        if (selectedCategory == null && !app.getPreferencesCategories().isEmpty()) {
            selectedCategory = app.getPreferencesCategories().get(0);
        }

        createWindow();
        createSearchField();
        createTree();

        addListeners();
    }

    public void createWindow() {
        window = new Window();
        window.setCaption("Preferences");
        window.addStyleName("preferences-dialog");
        window.setWidth("800px");
        window.setHeight("600px");

        splitPanel.setSizeFull();

        dlgButtonPanel = new CssLayout();
        dlgButtonPanel.setWidth("100%");
        dlgButtonPanel.addStyleName("dlg-button-panel");

        // dlgButtonPanel.addComponent(new Label("<hr/>", ContentMode.HTML));

        cancelButton = new Button("Cancel");
        cancelButton.addStyleName("cancel-button");
        dlgButtonPanel.addComponent(cancelButton);
        okButton = new Button("OK");
        okButton.addStyleName("ok-button");
        dlgButtonPanel.addComponent(okButton);

        root = new VerticalLayout();
        root.setSizeFull();
        window.setContent(root);
        root.addComponent(splitPanel);
        root.addComponent(dlgButtonPanel);
        root.setExpandRatio(splitPanel, 10);
        root.setExpandRatio(dlgButtonPanel, 0);

        treePanel = new Panel();
        treePanel.addStyleName("categories-panel");
        treePanel.addStyleName("borderless");
        treePanel.setSizeFull();

        leftSide = new CssLayout();
        leftSide.addStyleName("categories");
        leftSide.setSizeFull();
        // filterField.setWidth("70%");
        filterField.addStyleName("categories-filter");
        leftSide.addComponent(filterField);

        filterButton.setIcon(BundleResource
                .valueOf("platform:/plugin/org.lunifera.vaaclipse.ui.preferences.addon/img/find.png"));
        filterButton.addStyleName("vaaclipsebutton");
        filterButton.addStyleName("icon-only");
        filterButton.addStyleName("filter-category-button");

        clearFilterButton.setIcon(BundleResource
                .valueOf("platform:/plugin/org.lunifera.vaaclipse.ui.preferences.addon/img/clear.png"));
        clearFilterButton.addStyleName("vaaclipsebutton");
        clearFilterButton.addStyleName("icon-only");
        clearFilterButton.addStyleName("clear-filter-button");

        leftSide.addComponent(clearFilterButton);
        leftSide.addComponent(filterButton);
        leftSide.addComponent(treePanel);

        rightSide = new VerticalLayout();
        rightSide.setSizeFull();
        // rightSide.setMargin(new MarginInfo(true, true, false, true));

        pageHeader = new CssLayout();
        pageHeader.addStyleName("page-header-panel");
        pageHeader.setWidth("100%");
        pageHeaderText = new Label("Page");
        pageHeaderText.addStyleName("page-header-text");
        pageHeader.addComponent(pageHeaderText);
        rightSide.addComponent(pageHeader);

        pageContent = new CssLayout();
        // pageContent.setSizeFull();
        Panel pageContentPanel = new Panel(pageContent);// wrap page content to
        // panel - if content is
        // too large, scrolling
        // needed
        pageContentPanel.setSizeFull();
        rightSide.addComponent(pageContentPanel);

        pageBottom = new CssLayout();
        pageBottom.addStyleName("page-bottom-panel");
        pageBottom.setWidth("100%");
        rightSide.addComponent(pageBottom);

        apply = new Button("Apply");
        apply.addStyleName("apply");
        pageBottom.addComponent(apply);

        restoreDefaults = new Button("RestoreDefaults");
        restoreDefaults.addStyleName("restore-defaults");
        pageBottom.addComponent(restoreDefaults);

        splitPanel.addComponent(leftSide);
        splitPanel.addComponent(rightSide);
        splitPanel.setSplitPosition(30, Sizeable.Unit.PERCENTAGE);

        rightSide.setExpandRatio(pageHeader, 0);
        rightSide.setExpandRatio(pageContentPanel, 1);
        rightSide.setExpandRatio(pageBottom, 0);

        clearFilterButton.addClickListener(new ClickListener() {
            @Override
            public void buttonClick(ClickEvent event) {
                filterField.setValue("");
                refreshTree();
            }
        });

        filterButton.addClickListener(new ClickListener() {

            @Override
            public void buttonClick(ClickEvent event) {
                refreshTree();
            }
        });
    }

    public void createSearchField() {
        filterField.addTextChangeListener(new TextChangeListener() {

            @Override
            public void textChange(TextChangeEvent event) {
                refreshTree();
            }
        });
    }

    private void createTree() {
        tree = new Tree();
        tree.setSizeFull();
        tree.setImmediate(true);
        treePanel.setContent(tree);

        tree.addContainerProperty("name", String.class, "NoName");
        tree.setItemCaptionPropertyId("name");

        ModelHelper.buildChildCategoryListIncludeThisList(app.getPreferencesCategories(), categoryList);

        refreshTree();

        tree.addItemClickListener(new ItemClickEvent.ItemClickListener() {

            public void itemClick(final ItemClickEvent event) {
                if (event.getButton() == MouseButton.LEFT) {
                    PreferencesCategory selectedCat = (PreferencesCategory) event.getItemId();
                    if (selectedCat != null) {
                        openPreferencePageForCategory(selectedCat);
                    }
                }
            }
        });

        if (selectedCategory != null) {
            tree.select(selectedCategory);
            openPreferencePageForCategory(selectedCategory);
        }
    }

    private void refreshTree() {
        tree.removeAllItems();

        EList<PreferencesCategory> catList = app.getPreferencesCategories();

        markVisibility();

        fillCategories(catList, null);

        for (Object id : tree.rootItemIds()) {
            tree.expandItemsRecursively(id);
        }
    }

    private void markVisibility() {
        visibleCategories = new HashSet<PreferencesCategory>();

        String filterValue = filterField.getValue();
        if (filterValue.isEmpty()) {
            return;
        }
        for (PreferencesCategory category : categoryList) {
            if (category != null && category.getName().contains(filterValue)) {
                do {
                    visibleCategories.add(category);
                    category = category.getParentCategory();
                } while (category != null);
            }
        }
    }

    @SuppressWarnings("unchecked")
    private void fillCategories(List<PreferencesCategory> list, PreferencesCategory parentCat) {
        String search = filterField.getValue().trim();
        for (PreferencesCategory c : list) {

            if (authService != null && c.getParentCategory() != null && "user".equals(c.getParentCategory().getId())
                    && !authService.isAllowed(c)) {
                continue;
            }

            if (c.getName() == null)
                c.setName("No Name");
            if (filterField.getValue().isEmpty() || visibleCategories.contains(c)) {

                Item catItem = tree.addItem(c);
                catItem.getItemProperty("name").setValue(c.getName());
                if (c.getChildCategories().isEmpty())
                    tree.setChildrenAllowed(c, false);

                if (parentCat != null)
                    tree.setParent(c, parentCat);

                fillCategories(c.getChildCategories(), c);
            }
        }
    }

    private void openPreferencePageForCategory(PreferencesCategory selectedCat) {
        selectedCategory = selectedCat;
        refreshHeaderMessage();

        pageContent.removeAllComponents();

        if (selectedCat.getPage() != null) {
            IEclipseContext pageContext = context.createChild();
            pageContext.set(CssLayout.class, pageContent);
            pageContext.set(PreferencesPage.class, selectedCat.getPage());
            PreferencesPageRenderer pageRenderer = ContextInjectionFactory.make(PreferencesPageRenderer.class,
                    pageContext);
            pageRenderer.render();
            visitedPages.add(selectedCat.getPage());
        } else if (!selectedCat.getChildCategories().isEmpty()) {
            pageContent.addComponent(new Label("Expand the tree to edit a preferences for a specific feature"));
        }
    }

    private void addListeners() {

        restoreDefaults.addClickListener(new ClickListener() {

            @Override
            public void buttonClick(ClickEvent event) {
                restoreDefaults();
            }
        });

        apply.addClickListener(new ClickListener() {

            @Override
            public void buttonClick(ClickEvent event) {
                applyPressed();
            }
        });

        okButton.addClickListener(new ClickListener() {

            @Override
            public void buttonClick(ClickEvent event) {
                okPressed();
            }
        });

        cancelButton.addClickListener(new ClickListener() {

            @Override
            public void buttonClick(ClickEvent event) {
                cancelPressed();
            }
        });
    }

    public void setErrorMessage(String errorMessage) {
        this.errorMessage = errorMessage;
        refreshHeaderMessage();
    }

    public void clearErrorMessage() {
        this.errorMessage = null;
        refreshHeaderMessage();
    }

    public void refreshHeaderMessage() {
        if (errorMessage != null) {
            pageHeaderText.addStyleName(PAGE_HEADER_ERROR_TEXT);
            pageHeaderText.setValue(errorMessage);
        } else {
            pageHeaderText.removeStyleName(PAGE_HEADER_ERROR_TEXT);
            pageHeaderText.setValue(selectedCategory.getName());
        }
    }

    private void restoreDefaults() {
        PreferencesPage currentPage = getCurrentPage();
        if (currentPage != null) {
            try {
                restoreDefaultsOnPage(currentPage);
            } catch (Exception e) {
                Notification.show("Error restoring defaults", "Restoring defaults on this page failed",
                        Notification.Type.ERROR_MESSAGE);
                return;
            }
            fireEvent(PreferencesEvents.PREFERENCES_TO_DEFAULTS, currentPage);

            // Refresh the current page (it should be rerendered)
            openPreferencePageForCategory(getSelectedCategory());
        }
    }

    private void okPressed() {

        Exception exception = null;
        for (PreferencesPage page : visitedPages) {
            try {
                applyChangesOnPage(page);
            } catch (ValidationFailedException validationException) {
                setErrorMessage(validationException.getLocalizedMessage());
                Notification.show("Validation failed", validationException.getLocalizedMessage(),
                        Notification.Type.WARNING_MESSAGE);
                return;
            } catch (Exception e) {
                exception = e;
            }
        }
        if (exception != null) {
            String errorMessage = "Saving changes was failed on some pages";
            setErrorMessage(errorMessage);
            Notification.show("Error apply changes", errorMessage, Notification.Type.ERROR_MESSAGE);
            return;
        } else {
            fireEvent(PreferencesEvents.PREFERENCES_APPLIED,
                    (PreferencesPage[]) visitedPages.toArray(new PreferencesPage[visitedPages.size()]));
        }

        clearErrorMessage();

        ui.removeWindow(window);
    }

    private void cancelPressed() {
        ui.removeWindow(window);
    }

    private void applyPressed() {
        PreferencesPage currentPage = getCurrentPage();
        if (currentPage != null) {
            try {
                applyChangesOnPage(currentPage);
            } catch (ValidationFailedException validationException) {
                setErrorMessage(validationException.getLocalizedMessage());
                Notification.show("Validation failed", "The preferences is not correct",
                        Notification.Type.WARNING_MESSAGE);
                return;
            } catch (Exception e) {
                setErrorMessage("Applying changes on this page failed");
                Notification.show("Error apply changes", "Applying changes on this page failed",
                        Notification.Type.ERROR_MESSAGE);
                return;
            }
            clearErrorMessage();
            fireEvent(PreferencesEvents.PREFERENCES_APPLIED, currentPage);
        }
    }

    private void applyChangesOnPage(PreferencesPage page) throws BackingStoreException, ValidationFailedException {
        PreferencesPageRenderer pageRenderer = (PreferencesPageRenderer) page.getRenderer();

        pageRenderer.validate();

        try {
            pageRenderer.save();
        } catch (Exception e) {
            logger.error("Error copy changes from UI to preferences for category {}", selectedCategory.getName(),
                    e);
            throw e;
        }

        try {
            PrefHelper.flush(page);
        } catch (BackingStoreException e) {
            logger.error("Error flushing changes for category {}", page.getCategory().getName(), e);
            throw e;
        }
    }

    private void restoreDefaultsOnPage(PreferencesPage page) throws BackingStoreException {

        try {
            for (FieldEditor<?> fieldEditor : page.getChildren()) {
                String defaultValue = fieldEditor.getDefaultValue();
                if (defaultValue != null)
                    ((Preferences) fieldEditor.getPreferences()).put(fieldEditor.getPreferenceName(), defaultValue);
            }
        } catch (Exception e) {
            logger.error("Error copy default values from model to preferences for category {}",
                    page.getCategory().getName(), e);
            throw e;
        }

        try {
            PrefHelper.flush(page);
        } catch (BackingStoreException e) {
            logger.error("Error flushing changes for category {}", page.getCategory().getName(), e);
            throw e;
        }
    }

    private void fireEvent(String topic, PreferencesPage... pages) {
        eventBroker.send(topic, pages);
    }
}