blob: d901ebb81b848d18629070c23c67f53421425374 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011 BSI Business Systems Integration AG.
* 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:
* BSI Business Systems Integration AG - initial API and implementation
*******************************************************************************/
package org.eclipse.scout.rt.ui.rap;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.AccessController;
import java.util.List;
import java.util.TreeMap;
import javax.security.auth.Subject;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.service.ServerPushSession;
import org.eclipse.scout.commons.CompositeLong;
import org.eclipse.scout.commons.logger.IScoutLogger;
import org.eclipse.scout.commons.logger.ScoutLogManager;
import org.eclipse.scout.rt.client.IClientSession;
import org.eclipse.scout.rt.client.servicetunnel.http.IClientServiceTunnel;
import org.eclipse.scout.rt.client.ui.form.IForm;
import org.eclipse.scout.rt.ui.rap.util.RwtUtility;
import org.eclipse.scout.rt.ui.rap.window.IRwtScoutPart;
import org.eclipse.scout.rt.ui.rap.window.desktop.RwtScoutDesktop;
import org.eclipse.scout.rt.ui.rap.window.desktop.nonmodalFormBar.RwtScoutFormButtonBar;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.osgi.framework.Bundle;
public abstract class AbstractStandaloneRwtEnvironment extends AbstractRwtEnvironment implements IRwtStandaloneEnvironment {
private static final IScoutLogger LOG = ScoutLogManager.getLogger(AbstractStandaloneRwtEnvironment.class);
private Display m_display;
private RwtScoutDesktop m_uiDesktop;
private RwtScoutFormButtonBar m_uiButtonArea;
private ServerPushSession m_clientNotificationPushSession;
public AbstractStandaloneRwtEnvironment(Bundle applicationBundle, Class<? extends IClientSession> clientSessionClazz) {
super(applicationBundle, clientSessionClazz);
}
@Override
public int createUI() {
// Ensure the UI initialization request to be authenticated.
if (getSubject() == null) {
Subject subject = Subject.getSubject(AccessController.getContext());
if (subject == null) {
throw new SecurityException("/rap request is not authenticated with a Subject");
}
setSubject(subject);
}
return super.createUI();
}
@Override
protected void createContents(Composite parent) {
m_display = Display.getCurrent();
m_display.setData(IRwtEnvironment.class.getName(), this);
m_uiDesktop = createApplicationContent(parent);
m_uiButtonArea = createNonmodalFormButtonArea(parent);
// layout
GridLayoutFactory.fillDefaults().spacing(0, 0).applyTo(parent);
GridDataFactory.swtDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(m_uiDesktop.getUiContainer());
GridDataFactory.swtDefaults().align(SWT.FILL, SWT.FILL).grab(true, false).exclude(true).applyTo(m_uiButtonArea.getUiContainer());
if (needsClientNotificationServerPushSession()) {
// Necessary for client notifications.
m_clientNotificationPushSession = new ServerPushSession();
m_clientNotificationPushSession.start();
}
}
/**
* Creates the controls that constitute the desktop for this application.
*
* @param parent
* the parent composite to contain the application content.
* @return the {@link RwtScoutDesktop} that contains the desktop with a UI container which is to be laid out
* within the given parent composite.
*/
protected RwtScoutDesktop createApplicationContent(final Composite parent) {
final RwtScoutDesktop uiDesktop = createUiDesktop();
ensureInitialized(new Runnable() {
@Override
public void run() {
uiDesktop.createUiField(parent, getScoutDesktop(), AbstractStandaloneRwtEnvironment.this);
}
});
if (!isInitialized()) {
throw new SecurityException("Cannot initialize application");
}
getKeyStrokeManager().setGlobalKeyStrokesActivated(true);
return uiDesktop;
}
/**
* Creates the composite to keep track of non-modal forms. Whenever a non-modal form is shown, a corresponding
* button is shown in this button bar to restore the form if being in minimized state. This button bar is visible once
* a minimizable form is started.
*
* @param parent
* the parent composite to contain the button bar.
* @return the {@link RwtScoutFormButtonBar} that contains the form button with a UI container which is to be laid out
* within the given parent composite.
*/
protected RwtScoutFormButtonBar createNonmodalFormButtonArea(Composite parent) {
RwtScoutFormButtonBar buttonBar = new RwtScoutFormButtonBar();
buttonBar.createUiField(parent, m_uiDesktop.getScoutObject(), this);
return buttonBar;
}
protected RwtScoutDesktop createUiDesktop() {
return new RwtScoutDesktop();
}
/**
* @return <code>boolean</code> indicating if a permanent {@link ServerPushSession} for client notifications should be
* established.
*/
protected boolean needsClientNotificationServerPushSession() {
IClientServiceTunnel serviceTunnel = getClientSession().getServiceTunnel();
if (serviceTunnel != null) {
// necessary if client notification polling is enabled
return serviceTunnel.getClientNotificationPollInterval() > -1;
}
return false;
}
@Override
public RwtScoutDesktop getUiDesktop() {
return m_uiDesktop;
}
@Override
public Display getDisplay() {
// Sanity check for proper display if the calling thread is a user-interface thread.
Display currentDisplay = Display.getCurrent();
if (currentDisplay != null && m_display != currentDisplay) {
LOG.error("WRONG DISPLAY: the calling user-interface thread does not belong to this environment [display_environment={0}, display_callingThread={1}, callingThread={2}]",
new Object[]{m_display, currentDisplay, Thread.currentThread()});
}
return m_display;
}
@Override
public void showFormPart(IForm form) {
if (form == null) {
return;
}
if (form.getDisplayHint() == IForm.DISPLAY_HINT_VIEW) {
IRwtScoutPart part = m_uiDesktop.addForm(form);
if (part != null) {
putPart(form, part);
part.showPart();
}
else {
LOG.error("Form '" + form.getFormId() + "' cannot be displayed because no corresponding UI part could be found.");
}
}
super.showFormPart(form);
if (form.getDisplayHint() == IForm.DISPLAY_HINT_DIALOG && !form.isModal()) {
int buttonCount = m_uiButtonArea.getFormButtonBarCount();
m_uiButtonArea.addFormButton(form);
if (buttonCount != m_uiButtonArea.getFormButtonBarCount()) {
m_uiButtonArea.getUiContainer().setVisible(true);
((GridData) m_uiButtonArea.getUiContainer().getLayoutData()).exclude = false;
m_uiButtonArea.getUiContainer().getParent().layout(true, true);
}
}
}
@Override
public void hideFormPart(IForm form) {
super.hideFormPart(form);
if (form.getDisplayHint() == IForm.DISPLAY_HINT_DIALOG && !form.isModal()) {
m_uiButtonArea.removeFormButton(form);
if (m_uiButtonArea.getFormButtonBarCount() == 0) {
m_uiButtonArea.getUiContainer().setVisible(false);
((GridData) m_uiButtonArea.getUiContainer().getLayoutData()).exclude = true;
m_uiButtonArea.getUiContainer().getParent().layout(true, true);
}
}
}
/**
* {@inheritDoc}
*/
@Override
public Shell getParentShellIgnoringPopups(int modalities) {
Display display = getDisplay();
Shell shell = display.getActiveShell();
if (shell != null) {
while (RwtUtility.isPopupShell(shell) && shell.getParent() instanceof Shell) {
shell = (Shell) shell.getParent();
}
}
// traverse available shells
if (shell == null) {
TreeMap<CompositeLong, Shell> map = new TreeMap<CompositeLong, Shell>();
for (Shell s : display.getShells()) {
RwtUtility.visitShellTreeRec(s, modalities, 0, map);
}
if (map.size() > 0) {
shell = map.get(map.firstKey());
}
}
if (shell != null && shell.getData() instanceof ProgressMonitorDialog) {
// do also ignore the ProgressMonitorDialog, otherwise there will be some strange behaviors
// when displaying a shell on top of the ProgressMonitorDialog-shell (f.e. when the
// ProgressMonitorDialog-shell disappears)
shell = (Shell) shell.getParent();
}
if (shell == null) {
shell = getShell(); // main shell for this entrypoint.
}
return shell;
}
@Override
protected void contributePatches(List<URL> patches) {
super.contributePatches(patches);
// Patch to install a visual marker on editable cells.
contributeEditableCellMarkerPatch(patches);
}
/**
* Contribute the patch to render editable cells with a visual marker.
*
* @param patches
* live-list of the JavaScript-Files to be installed.
*/
protected void contributeEditableCellMarkerPatch(List<URL> patches) {
// Make the visual image marker available for download.
registerEditableCellMarkerIcon();
// Depending on the RAP version used another patch needs to be installed.
Bundle rwtBundle = Platform.getBundle("org.eclipse.rap.rwt");
if (rwtBundle != null && rwtBundle.getVersion().getMajor() >= 3) {
patches.add(Activator.class.getResource("/resources/patches/EditableCellMarkerPatch_v3.x.x.js"));
}
else {
patches.add(Activator.class.getResource("/resources/patches/EditableCellMarkerPatch_v2.x.x.js"));
}
}
protected void registerEditableCellMarkerIcon() {
String icon = "editable_tablecell_marker.png";
if (!RWT.getResourceManager().isRegistered(icon)) {
InputStream is = Activator.class.getResourceAsStream(String.format("/resources/icons/internal/%s", icon));
try {
RWT.getResourceManager().register(icon, is);
}
finally {
try {
is.close();
}
catch (IOException e) {
LOG.warn("Failed to close InputStream for editable cell marker.", e);
}
}
}
}
}