blob: 9e5e1f53b6963ee90aaa0b1d698ffcafabf998c0 [file] [log] [blame]
/**
* Copyright (c) 2011, 2015 - Lunifera GmbH (Gross Enzersdorf, Austria), Loetz GmbH&Co.KG (69115 Heidelberg, Germany)
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Florian Pirchner - Initial implementation
*/
package org.eclipse.osbp.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.eclipse.osbp.vaaclipse.ui.preferences.addon.PreferencesAuthorization;
import org.eclipse.osbp.vaaclipse.ui.preferences.addon.PreferencesEvents;
import org.eclipse.osbp.vaaclipse.ui.preferences.addon.internal.exception.ValidationFailedException;
import org.eclipse.osbp.vaaclipse.ui.preferences.addon.internal.util.ModelHelper;
import org.eclipse.osbp.vaaclipse.ui.preferences.addon.internal.util.PrefHelper;
import org.eclipse.osbp.vaaclipse.ui.preferences.model.FieldEditor;
import org.eclipse.osbp.vaaclipse.ui.preferences.model.PreferencesCategory;
import org.eclipse.osbp.vaaclipse.ui.preferences.model.PreferencesPage;
import org.osgi.framework.BundleContext;
import org.osgi.service.prefs.BackingStoreException;
import org.osgi.service.prefs.Preferences;
import org.eclipse.osbp.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.eclipse.osbp.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.eclipse.osbp.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);
}
}