/*******************************************************************************
* Copyright (c) 2010, 2012 AGETO Service GmbH and others.
* 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:
* Mike Tschierschke - initial API and implementation
* Gunnar Wagenknecht - rework to new console look (based on RAP Examples)
*******************************************************************************/
package org.eclipse.gyrex.admin.ui.internal.application;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.gyrex.admin.ui.internal.AdminUiActivator;
import org.eclipse.gyrex.admin.ui.internal.pages.registry.AdminPageRegistry;
import org.eclipse.gyrex.admin.ui.internal.pages.registry.PageContribution;
import org.eclipse.gyrex.admin.ui.pages.AdminPage;
import org.eclipse.gyrex.admin.ui.pages.FilteredAdminPage;
import org.eclipse.gyrex.admin.ui.pages.IAdminUi;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.util.ILogger;
import org.eclipse.jface.util.Policy;
import org.eclipse.jface.util.StatusHandler;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.application.EntryPoint;
import org.eclipse.rap.rwt.client.service.BrowserNavigation;
import org.eclipse.rap.rwt.client.service.BrowserNavigationEvent;
import org.eclipse.rap.rwt.client.service.BrowserNavigationListener;
import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.osgi.framework.Version;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class controls all aspects of the application's execution and is
* contributed through the plugin.xml.
*/
public class AdminApplication implements EntryPoint, IAdminUi {
private static final String HISTORY_TOKEN_SEPARATOR = "--";
private static final String GYREX_WEBSITE_URL = "http://eclipse.org/gyrex/";
private static final int CONTENT_MIN_HEIGHT = 800;
private static final int CENTER_AREA_WIDTH = 998;
private static final Logger LOG = LoggerFactory.getLogger(AdminApplication.class);
private static Label createHeadlineLabel(final Composite parent, final String text) {
final Label label = new Label(parent, SWT.NONE);
label.setText(text.replace("&", "&&"));
label.setData(RWT.CUSTOM_VARIANT, "pageHeadline");
return label;
}
private static FormData createLogoFormData(final Image logo) {
final FormData data = new FormData();
data.left = new FormAttachment(0);
data.top = new FormAttachment(0);
return data;
}
private static FormData createNavBarFormData() {
final FormData data = new FormData();
data.bottom = new FormAttachment(100, 5);
data.right = new FormAttachment(100, 0);
return data;
}
public static Image getImage(final Display display, final String path) {
final ImageDescriptor imageDescriptor = AdminUiActivator.getImageDescriptor("img/" + path);
return imageDescriptor.createImage(display);
}
private static String getVersion() {
final Version version = AdminUiActivator.getInstance().getBundleVersion();
final StringBuilder resultBuffer = new StringBuilder(60);
final String buildId = AdminUiActivator.getInstance().getBundle().getBundleContext().getProperty("gyrex.buildId");
if (StringUtils.isNotBlank(buildId)) {
resultBuffer.append("(Gyrex ").append(buildId);
final String buildTimestamp = AdminUiActivator.getInstance().getBundle().getBundleContext().getProperty("gyrex.buildTimestamp");
if (StringUtils.isNotBlank(buildTimestamp)) {
resultBuffer.append(" Build ").append(buildTimestamp);
resultBuffer.append(buildTimestamp);
}
resultBuffer.append(')');
} else if (StringUtils.equals(version.getQualifier(), "qualifier")) {
// running out of the IDE
resultBuffer.append("(Developer Build)");
} else {
// don't append any version info at all
}
return resultBuffer.toString();
}
private static void makeLink(final Label control, final String url) {
control.setCursor(control.getDisplay().getSystemCursor(SWT.CURSOR_HAND));
control.addMouseListener(new MouseAdapter() {
/** serialVersionUID */
private static final long serialVersionUID = 1L;
@Override
public void mouseDown(final MouseEvent e) {
final JavaScriptExecutor service = RWT.getClient().getService(JavaScriptExecutor.class);
if (service != null) {
service.execute("window.location.href = '" + url + "'");
}
}
});
}
private Composite centerArea;
private NavigationBar navigation;
private Composite navBar;
private final Map<String, AdminPage> pagesById = new HashMap<String, AdminPage>();
private AdminPage currentPage;
private Image logo;
private Composite filterContainer;
private Composite headerCenterArea;
private void activate(final AdminPage page, final PageContribution contribution, String[] args) {
// TODO: should switch to using a StackLayout and not disposing children every time
// however, disposal might be necessary if input changes
for (final Control child : centerArea.getChildren()) {
child.dispose();
}
for (final Control child : filterContainer.getChildren()) {
child.dispose();
}
// initialize arguments (allows safe use within this method as well as for API contract)
if ((args == null) || (args.length == 0)) {
args = new String[] { contribution.getId() };
}
// update page with input
page.setArguments(args);
// create history entry
final String historyText = StringUtils.isNotBlank(page.getTitleToolTip()) ? String.format("%s - %s - Gyrex Admin", contribution.getName(), page.getTitleToolTip()) : String.format("%s - Gyrex Admin", contribution.getName());
final BrowserNavigation browserNavigation = RWT.getClient().getService(BrowserNavigation.class);
if (browserNavigation != null) {
browserNavigation.pushState(StringUtils.join(args, HISTORY_TOKEN_SEPARATOR), historyText);
}
// create page
createPage(page, contribution, centerArea);
// re-layout
headerCenterArea.layout(true, true);
centerArea.layout(true, true);
// activate
page.activate();
}
private void attachHistoryListener() {
final BrowserNavigation browserNavigation = RWT.getClient().getService(BrowserNavigation.class);
if (browserNavigation != null) {
browserNavigation.addBrowserNavigationListener(new BrowserNavigationListener() {
private static final long serialVersionUID = 1L;
@Override
public void navigated(final BrowserNavigationEvent event) {
final String[] tokens = StringUtils.splitByWholeSeparator(event.getState(), HISTORY_TOKEN_SEPARATOR);
final PageContribution contribution = AdminPageRegistry.getInstance().getPage(tokens[0]);
if (contribution != null) {
openPage(contribution, tokens);
}
}
});
}
}
private Composite createCenterArea(final Composite parent, final Control topControl, final Control bottomControl) {
final Composite centerArea = new Composite(parent, SWT.NONE);
centerArea.setLayout(new FillLayout());
centerArea.setLayoutData(createCenterAreaFormData(topControl, bottomControl));
centerArea.setData(RWT.CUSTOM_VARIANT, "centerArea");
return centerArea;
}
private FormData createCenterAreaFormData(final Control topAttachment, final Control bottomAttachment) {
final FormData data = new FormData();
data.top = new FormAttachment(topAttachment, 0, SWT.BOTTOM);
data.bottom = new FormAttachment(bottomAttachment, -10, SWT.TOP);
data.left = new FormAttachment(50, (-CENTER_AREA_WIDTH / 2) + 10);
data.width = CENTER_AREA_WIDTH - 10;
return data;
}
private Composite createContent(final ScrolledComposite scrolledArea) {
logo = getImage(scrolledArea.getDisplay(), "gyrex/gyrex-juno.png");
final Composite comp = new Composite(scrolledArea, SWT.NONE);
comp.setLayout(new FormLayout());
final Composite header = createHeader(comp);
header.setLayoutData(createHeaderFormData(logo.getBounds().height));
createContentBody(comp, header);
return comp;
}
private void createContentBody(final Composite parent, final Composite header) {
// FIXME: the separator is a hack to work around missing "border-top" (or -bottom) in RAP (bug 283872)
final Composite separator = new Composite(parent, SWT.NONE);
separator.setData(RWT.CUSTOM_VARIANT, "mainContentAreaHeaderSeparator");
final FormData data = new FormData();
data.top = new FormAttachment(header, 0);
data.left = new FormAttachment(0, 0);
data.right = new FormAttachment(100, 0);
data.height = 2;
separator.setLayoutData(data);
final Composite composite = new Composite(parent, SWT.NONE);
composite.setData(RWT.CUSTOM_VARIANT, "mainContentArea");
composite.setLayout(new FormLayout());
composite.setLayoutData(createContentBodyFormData(separator));
final Composite footer = createFooter(composite);
centerArea = createCenterArea(composite, separator, footer);
}
private FormData createContentBodyFormData(final Control topControlToAttachTo) {
final FormData data = new FormData();
data.top = new FormAttachment(topControlToAttachTo, 0);
data.left = new FormAttachment(0, 0);
data.right = new FormAttachment(100, 0);
data.bottom = new FormAttachment(100, 0);
return data;
}
private Composite createFilterContainer(final Composite parent, final Control left) {
final Composite filterContainer = new Composite(parent, SWT.NONE);
filterContainer.setData(RWT.CUSTOM_VARIANT, "filter-container");
final FormData data = new FormData();
data.bottom = new FormAttachment(100, 5);
data.left = new FormAttachment(left, 5);
filterContainer.setLayoutData(data);
final GridLayout layout = new GridLayout();
layout.marginWidth = 0;
layout.horizontalSpacing = 0;
layout.verticalSpacing = 0;
filterContainer.setLayout(layout);
return filterContainer;
}
private Composite createFooter(final Composite contentComposite) {
final Composite footer = new Composite(contentComposite, SWT.NONE);
footer.setLayout(new FormLayout());
footer.setData(RWT.CUSTOM_VARIANT, "footer");
footer.setLayoutData(createFooterFormData());
footer.setBackgroundMode(SWT.INHERIT_FORCE);
final Label label = new Label(footer, SWT.NONE);
label.setData(RWT.CUSTOM_VARIANT, "footerLabel");
label.setText("Admin Console " + getVersion());
label.setLayoutData(createFooterLabelFormData(footer));
return footer;
}
private FormData createFooterFormData() {
final FormData data = new FormData();
data.left = new FormAttachment(50, -CENTER_AREA_WIDTH / 2);
data.top = new FormAttachment(100, -40);
data.bottom = new FormAttachment(100);
data.width = CENTER_AREA_WIDTH - 10 - 2;
return data;
}
private FormData createFooterLabelFormData(final Composite footer) {
final FormData data = new FormData();
data.top = new FormAttachment(50, -10);
data.right = new FormAttachment(100, -15);
return data;
}
private Composite createHeader(final Composite parent) {
final Composite comp = new Composite(parent, SWT.NONE);
comp.setData(RWT.CUSTOM_VARIANT, "header");
comp.setBackgroundMode(SWT.INHERIT_DEFAULT);
comp.setLayout(new FormLayout());
headerCenterArea = createHeaderCenterArea(comp);
final Label logoLabel = new Label(headerCenterArea, SWT.NONE);
logoLabel.setImage(logo);
logoLabel.setLayoutData(createLogoFormData(logo));
makeLink(logoLabel, GYREX_WEBSITE_URL);
// final Label title = new Label(headerCenterArea, SWT.NONE);
// title.setText("Admin Console");
// title.setData(RWT.CUSTOM_VARIANT, "title");
// final FormData titleFormData = new FormData();
// titleFormData.bottom = new FormAttachment(100, -18);
// titleFormData.left = new FormAttachment(logo, 0);
// title.setLayoutData(titleFormData);
filterContainer = createFilterContainer(headerCenterArea, logoLabel);
navigation = createNavigation(headerCenterArea);
return comp;
}
private Composite createHeaderCenterArea(final Composite parent) {
final Composite headerCenterArea = new Composite(parent, SWT.NONE);
headerCenterArea.setLayout(new FormLayout());
headerCenterArea.setLayoutData(createHeaderCenterAreaFormData());
return headerCenterArea;
}
private FormData createHeaderCenterAreaFormData() {
final FormData data = new FormData();
data.left = new FormAttachment(50, -CENTER_AREA_WIDTH / 2);
data.top = new FormAttachment(0);
data.bottom = new FormAttachment(100);
data.width = CENTER_AREA_WIDTH;
return data;
}
private FormData createHeaderFormData(final int height) {
final FormData data = new FormData();
data.top = new FormAttachment(0);
data.left = new FormAttachment(0);
data.right = new FormAttachment(100);
data.height = height;
return data;
}
private Shell createMainShell(final Display display) {
final Shell shell = new Shell(display, SWT.NO_TRIM);
shell.setMaximized(true);
shell.setData(RWT.CUSTOM_VARIANT, "mainshell");
return shell;
}
private NavigationBar createNavigation(final Composite parent) {
navBar = new Composite(parent, SWT.NONE);
navBar.setLayoutData(createNavBarFormData());
navBar.setData(RWT.CUSTOM_VARIANT, "nav-bar");
final GridLayout layout = new GridLayout();
layout.marginWidth = 0;
layout.horizontalSpacing = 0;
layout.verticalSpacing = 0;
navBar.setLayout(layout);
final NavigationBar navigation = new NavigationBar(navBar) {
/** serialVersionUID */
private static final long serialVersionUID = 1L;
@Override
protected void openPage(final PageContribution page) {
AdminApplication.this.openPage(page, null);
}
};
return navigation;
}
private void createPage(final AdminPage page, final PageContribution contribution, final Composite parent) {
final Composite pageComp = new Composite(parent, SWT.NONE);
pageComp.setLayout(AdminUiUtil.createGridLayoutWithoutMargin(1, false));
if (page instanceof FilteredAdminPage) {
((FilteredAdminPage) page).createFilterControls(filterContainer);
}
String title = page.getTitle();
if (StringUtils.isBlank(title)) {
title = contribution.getName();
}
if (StringUtils.isNotBlank(title)) {
final Label label = createHeadlineLabel(pageComp, page.getTitle());
final GridData layoutData = new GridData();
layoutData.verticalIndent = 30;
// layoutData.horizontalIndent = DEFAULT_SPACE;
label.setLayoutData(layoutData);
}
final Composite contentComp = new Composite(pageComp, SWT.NONE);
contentComp.setLayoutData(AdminUiUtil.createFillData());
contentComp.setLayout(new FillLayout());
page.createControl(contentComp);
// sanity check
for (final Control child : contentComp.getChildren()) {
if (null != child.getLayoutData()) {
LOG.warn("Programming error in page {}: child composites ({}) should not make any assumptions about the parent layout!", contribution.getId(), child);
child.setLayoutData(null);
}
}
}
private ScrolledComposite createScrolledArea(final Composite parent) {
final ScrolledComposite scrolledComp = new ScrolledComposite(parent, SWT.V_SCROLL | SWT.H_SCROLL);
scrolledComp.setMinHeight(CONTENT_MIN_HEIGHT);
scrolledComp.setMinWidth(CENTER_AREA_WIDTH);
scrolledComp.setExpandVertical(true);
scrolledComp.setExpandHorizontal(true);
return scrolledComp;
}
@Override
public int createUI() {
final Display display = new Display();
setupJFacePolicy();
final Shell shell = createMainShell(display);
shell.setLayout(new FillLayout());
final ScrolledComposite scrolledArea = createScrolledArea(shell);
final Composite content = createContent(scrolledArea);
scrolledArea.setContent(content);
attachHistoryListener();
shell.open();
openInitialPage();
display.disposeExec(new Runnable() {
@Override
public void run() {
if (null != currentPage) {
deactivate(currentPage);
}
}
});
return 0;
}
private void deactivate(final AdminPage page) {
page.deactivate();
}
private AdminPage getPage(final PageContribution contribution) throws CoreException {
if (!pagesById.containsKey(contribution.getId())) {
final AdminPage page = contribution.createPage();
page.setAdminUi(this);
pagesById.put(contribution.getId(), page);
}
return pagesById.get(contribution.getId());
}
private void openInitialPage() {
final PageContribution contribution = navigation.findInitialPage();
if (contribution != null) {
openPage(contribution, null);
}
}
private void openPage(final PageContribution contribution, final String[] args) {
try {
final AdminPage page = getPage(contribution);
if (null == page) {
Policy.getStatusHandler().show(new Status(IStatus.ERROR, AdminUiActivator.SYMBOLIC_NAME, String.format("Page '%s' not found!", contribution.getId())), "Error Opening Page");
return;
}
if (page == currentPage)
// don't do anything if it's the same page
return;
else if (null != currentPage) {
// deactivate old page first
deactivate(currentPage);
}
currentPage = page;
navigation.selectNavigationEntry(contribution);
activate(page, contribution, args);
} catch (final Exception | LinkageError | AssertionError e) {
Policy.getStatusHandler().show(e instanceof CoreException ? ((CoreException) e).getStatus() : new Status(IStatus.ERROR, AdminUiActivator.SYMBOLIC_NAME, String.format("Unable to open page '%s (id %s)'. Please check the server logs.", contribution.getName(), contribution.getId()), e), "Error Opening Page");
}
}
@Override
public void openPage(final String pageId, final String... args) {
if (StringUtils.isBlank(pageId))
throw new IllegalArgumentException("invalid page id");
final PageContribution contribution = AdminPageRegistry.getInstance().getPage(pageId);
if (contribution == null)
return;
final String[] argsWithPageId;
if (args != null) {
argsWithPageId = new String[args.length + 1];
argsWithPageId[0] = pageId;
System.arraycopy(args, 0, argsWithPageId, 1, args.length);
} else {
argsWithPageId = new String[] { pageId };
}
openPage(contribution, argsWithPageId);
}
private void setupJFacePolicy() {
Policy.setLog(new ILogger() {
@Override
public void log(final IStatus status) {
if (status.matches(IStatus.CANCEL) || status.matches(IStatus.ERROR)) {
LOG.error(status.getMessage(), status.getException());
} else if (status.matches(IStatus.WARNING)) {
LOG.warn(status.getMessage(), status.getException());
} else {
LOG.info(status.getMessage(), status.getException());
}
}
});
final StatusHandler defaultStatusHandler = Policy.getStatusHandler();
Policy.setStatusHandler(new StatusHandler() {
@Override
public void show(final IStatus status, final String title) {
Policy.getLog().log(status);
defaultStatusHandler.show(status, title);
}
});
}
}