package org.argeo.cms.e4.rap;
-import java.security.PrivilegedAction;
import java.util.HashMap;
import java.util.Map;
import javax.security.auth.Subject;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.ui.dialogs.CmsFeedback;
import org.eclipse.rap.e4.E4ApplicationConfig;
-import org.eclipse.rap.e4.E4EntryPointFactory;
import org.eclipse.rap.rwt.application.Application;
import org.eclipse.rap.rwt.application.Application.OperationMode;
import org.eclipse.rap.rwt.application.ApplicationConfiguration;
-import org.eclipse.rap.rwt.application.EntryPoint;
+import org.eclipse.rap.rwt.application.ExceptionHandler;
import org.eclipse.rap.rwt.client.WebClient;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
public abstract class AbstractRapE4App implements ApplicationConfiguration {
+ private final static Log log = LogFactory.getLog(AbstractRapE4App.class);
+
private final BundleContext bc = FrameworkUtil.getBundle(AbstractRapE4App.class).getBundleContext();
private String pageTitle;
private String path;
public void configure(Application application) {
+ application.setExceptionHandler(new ExceptionHandler() {
+
+ @Override
+ public void handleException(Throwable throwable) {
+ CmsFeedback.show("Unexpected RWT exception", throwable);
+ // log.error("Unexpected RWT exception", throwable);
+
+ }
+ });
+
String lifeCycleUri = "bundleclass://" + bc.getBundle().getSymbolicName() + "/"
+ CmsLoginLifecycle.class.getName();
Map<String, String> properties = new HashMap<String, String>();
properties.put(WebClient.PAGE_TITLE, pageTitle);
E4ApplicationConfig config = new E4ApplicationConfig(e4Xmi, lifeCycleUri, null, false, true, true);
- config.isClearPersistedState();
- E4EntryPointFactory entryPointFactory = new E4EntryPointFactory(config) {
-
- @Override
- public EntryPoint create() {
- Subject subject = new Subject();
- EntryPoint ep = createEntryPoint();
- EntryPoint authEp = new EntryPoint() {
-
- @Override
- public int createUI() {
- return Subject.doAs(subject, new PrivilegedAction<Integer>() {
-
- @Override
- public Integer run() {
- return ep.createUI();
- }
-
- });
- }
- };
- return authEp;
- }
-
- protected EntryPoint createEntryPoint() {
- return super.create();
- }
+ Subject subject = new Subject();
+ addEntryPoint(application, subject, config, properties);
+ // config.isClearPersistedState();
+ // E4EntryPointFactory entryPointFactory = new E4EntryPointFactory(config) {
+ //
+ // @Override
+ // public EntryPoint create() {
+ // Subject subject = new Subject();
+ // EntryPoint ep = createEntryPoint();
+ // EntryPoint authEp = new EntryPoint() {
+ //
+ // @Override
+ // public int createUI() {
+ // return Subject.doAs(subject, new PrivilegedAction<Integer>() {
+ //
+ // @Override
+ // public Integer run() {
+ // return ep.createUI();
+ // }
+ //
+ // });
+ // }
+ // };
+ // return authEp;
+ // }
+ //
+ // protected EntryPoint createEntryPoint() {
+ // return super.create();
+ // }
+ //
+ // };
+ }
- };
+ protected void addEntryPoint(Application application, Subject subject, E4ApplicationConfig config,
+ Map<String, String> properties) {
+ CmsE4EntryPointFactory entryPointFactory = new CmsE4EntryPointFactory(subject, config);
application.addEntryPoint(path, entryPointFactory, properties);
application.setOperationMode(OperationMode.SWT_COMPATIBILITY);
}
--- /dev/null
+package org.argeo.cms.e4.rap;
+
+import java.security.PrivilegedAction;
+
+import javax.security.auth.Subject;
+
+import org.eclipse.rap.e4.E4ApplicationConfig;
+import org.eclipse.rap.e4.E4EntryPointFactory;
+import org.eclipse.rap.rwt.application.EntryPoint;
+
+public class CmsE4EntryPointFactory extends E4EntryPointFactory {
+ private Subject subject;
+
+ public CmsE4EntryPointFactory(Subject subject, E4ApplicationConfig config) {
+ super(config);
+ this.subject = subject;
+ }
+
+ @Override
+ public EntryPoint create() {
+ // Subject subject = new Subject();
+ EntryPoint ep = createEntryPoint();
+ EntryPoint authEp = new EntryPoint() {
+
+ @Override
+ public int createUI() {
+ return Subject.doAs(subject, new PrivilegedAction<Integer>() {
+
+ @Override
+ public Integer run() {
+ return ep.createUI();
+ }
+
+ });
+ }
+ };
+ return authEp;
+ }
+
+ protected EntryPoint createEntryPoint() {
+ return super.create();
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.dialogs;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.eclipse.ui.Selected;
+import org.argeo.eclipse.ui.dialogs.LightweightDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+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.eclipse.swt.widgets.Text;
+
+public class CmsFeedback extends LightweightDialog {
+ private final static Log log = LogFactory.getLog(CmsFeedback.class);
+
+ private String message;
+ private Throwable exception;
+
+ public CmsFeedback(Shell parentShell, String message, Throwable e) {
+ super(parentShell);
+ this.message = message;
+ this.exception = e;
+ log.error(message, e);
+ }
+
+ public static void show(String message, Throwable e) {
+ // rethrow ThreaDeath in order to make sure that RAP will properly clean
+ // up the UI thread
+ if (e instanceof ThreadDeath)
+ throw (ThreadDeath) e;
+
+ new CmsFeedback(getDisplay().getActiveShell(), message, e).open();
+ }
+
+ public static void show(String message) {
+ new CmsFeedback(getDisplay().getActiveShell(), message, null).open();
+ }
+
+ /** Tries to find a display */
+ private static Display getDisplay() {
+ try {
+ Display display = Display.getCurrent();
+ if (display != null)
+ return display;
+ else
+ return Display.getDefault();
+ } catch (Exception e) {
+ return Display.getCurrent();
+ }
+ }
+
+ protected Control createDialogArea(Composite parent) {
+ parent.setLayout(new GridLayout(2, false));
+
+ Label messageLbl = new Label(parent, SWT.WRAP);
+ if (message != null)
+ messageLbl.setText(message);
+ else if (exception != null)
+ messageLbl.setText(exception.getLocalizedMessage());
+
+ Button close = new Button(parent, SWT.FLAT);
+ close.setText("Close");
+ close.setLayoutData(new GridData(SWT.END, SWT.TOP, false, false));
+ close.addSelectionListener((Selected) (e) -> closeShell(OK));
+
+ // Composite composite = new Composite(dialogarea, SWT.NONE);
+ // composite.setLayout(new GridLayout(2, false));
+ // composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ if (exception != null) {
+ Text stack = new Text(parent, SWT.MULTI | SWT.LEAD | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
+ stack.setEditable(false);
+ stack.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
+ StringWriter sw = new StringWriter();
+ exception.printStackTrace(new PrintWriter(sw));
+ stack.setText(sw.toString());
+ }
+
+ // parent.pack();
+ return messageLbl;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.ui.dialogs;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.argeo.cms.CmsException;
+import org.argeo.cms.util.CmsUtils;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.eclipse.ui.Selected;
+import org.argeo.eclipse.ui.dialogs.LightweightDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.wizard.IWizard;
+import org.eclipse.jface.wizard.IWizardContainer2;
+import org.eclipse.jface.wizard.IWizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+
+public class CmsWizardDialog extends LightweightDialog implements IWizardContainer2 {
+ private static final long serialVersionUID = -2123153353654812154L;
+
+ private IWizard wizard;
+ private IWizardPage currentPage;
+
+ private Label titleBar;
+ private Label message;
+ private Composite body;
+ private Composite buttons;
+ private Button back;
+ private Button next;
+ private Button finish;
+
+ public CmsWizardDialog(Shell parentShell, IWizard wizard) {
+ super(parentShell);
+ this.wizard = wizard;
+ wizard.setContainer(this);
+ // create the pages
+ wizard.addPages();
+ currentPage = wizard.getStartingPage();
+ if (currentPage == null)
+ throw new CmsException("At least one wizard page is required");
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ updateWindowTitle();
+
+ Composite messageArea = new Composite(parent, SWT.NONE);
+ messageArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ {
+ messageArea.setLayout(CmsUtils.noSpaceGridLayout(new GridLayout(2, false)));
+ titleBar = new Label(messageArea, SWT.WRAP);
+ titleBar.setFont(EclipseUiUtils.getBoldFont(parent));
+ titleBar.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, true, false));
+ updateTitleBar();
+ Button cancelButton = new Button(messageArea, SWT.FLAT);
+ cancelButton.setText("Cancel");
+ cancelButton.setLayoutData(new GridData(SWT.END, SWT.TOP, false, false, 1, 3));
+ cancelButton.addSelectionListener((Selected) (e) -> closeShell(CANCEL));
+ message = new Label(messageArea, SWT.WRAP);
+ message.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 2));
+ updateMessage();
+ }
+
+ body = new Composite(parent, SWT.BORDER);
+ body.setLayout(CmsUtils.noSpaceGridLayout());
+ body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ showPage(currentPage);
+
+ buttons = new Composite(parent, SWT.NONE);
+ buttons.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
+ {
+ boolean singlePage = wizard.getPageCount() == 1;
+ GridLayout layout = new GridLayout(singlePage ? 1 : 3, true);
+ layout.marginWidth = 0;
+ layout.marginHeight = 0;
+ buttons.setLayout(layout);
+ // TODO revert order for right-to-left languages
+
+ if (!singlePage) {
+ back = new Button(buttons, SWT.PUSH);
+ back.setText("Back");
+ back.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
+ back.addSelectionListener((Selected) (e) -> backPressed());
+
+ next = new Button(buttons, SWT.PUSH);
+ next.setText("Next");
+ next.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
+ next.addSelectionListener((Selected) (e) -> nextPressed());
+ }
+ finish = new Button(buttons, SWT.PUSH);
+ finish.setText("Finish");
+ finish.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
+ finish.addSelectionListener((Selected) (e) -> finishPressed());
+
+ updateButtons();
+ }
+ return body;
+ }
+
+ @Override
+ public IWizardPage getCurrentPage() {
+ return currentPage;
+ }
+
+ @Override
+ public Shell getShell() {
+ return getForegoundShell();
+ }
+
+ @Override
+ public void showPage(IWizardPage page) {
+ // clear
+ for (Control c : body.getChildren())
+ c.dispose();
+ page.createControl(body);
+ currentPage = page;
+ }
+
+ @Override
+ public void updateButtons() {
+ if (back != null)
+ back.setEnabled(wizard.getPreviousPage(currentPage) != null);
+ if (next != null)
+ next.setEnabled(wizard.getNextPage(currentPage) != null && currentPage.canFlipToNextPage());
+ finish.setEnabled(wizard.canFinish());
+ }
+
+ @Override
+ public void updateMessage() {
+ message.setText(currentPage.getMessage());
+ }
+
+ @Override
+ public void updateTitleBar() {
+ titleBar.setText(currentPage.getTitle());
+ }
+
+ @Override
+ public void updateWindowTitle() {
+ setTitle(wizard.getWindowTitle());
+ }
+
+ @Override
+ public void run(boolean fork, boolean cancelable, IRunnableWithProgress runnable)
+ throws InvocationTargetException, InterruptedException {
+ runnable.run(null);
+ }
+
+ @Override
+ public void updateSize() {
+ // TODO pack?
+ }
+
+ protected boolean onCancel() {
+ return wizard.performCancel();
+ }
+
+ protected void nextPressed() {
+ IWizardPage page = wizard.getNextPage(currentPage);
+ showPage(page);
+ }
+
+ protected void backPressed() {
+ IWizardPage page = wizard.getPreviousPage(currentPage);
+ showPage(page);
+ }
+
+ protected void finishPressed() {
+ if (wizard.performFinish())
+ closeShell(OK);
+ }
+}
--- /dev/null
+package org.argeo.eclipse.ui;
+
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+
+/**
+ * {@link SelectionListener} as a functional interface in order to use lambda
+ * expression in UI code.
+ * {@link SelectionListener#widgetDefaultSelected(SelectionEvent)} does nothing
+ * by default.
+ */
+@FunctionalInterface
+public interface Selected extends SelectionListener {
+ @Override
+ public void widgetSelected(SelectionEvent e);
+
+ default public void widgetDefaultSelected(SelectionEvent e) {
+ // does nothing
+ }
+
+}
log.error(message, e);
}
- public void open() {
+ public int open() {
if (shell != null)
throw new EclipseUiException("There is already a shell");
shell = new Shell(getDisplay(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
});
shell.open();
+ return OK;
}
protected void closeShell() {
/** Generic lightweight dialog, not based on JFace. */
public class LightweightDialog {
- // private final static Log log = LogFactory.getLog(LightweightDialog.class);
+ // must be the same value as org.eclipse.jface.window.Window#OK
+ public final static int OK = 0;
+ // must be the same value as org.eclipse.jface.window.Window#CANCEL
+ public final static int CANCEL = 1;
private Shell parentShell;
private Shell backgroundShell;
- private Shell shell;
+ private Shell foregoundShell;
+
+ private Integer returnCode = null;
+ private boolean block = true;
+
+ private String title;
/** Tries to find a display */
private static Display getDisplay() {
this.parentShell = parentShell;
}
- public void open() {
- if (shell != null)
+ public int open() {
+ if (foregoundShell != null)
throw new EclipseUiException("There is already a shell");
- backgroundShell = new Shell(parentShell, SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
- backgroundShell.setMaximized(true);
+ backgroundShell = new Shell(parentShell, SWT.DIALOG_TRIM | SWT.ON_TOP);
+ backgroundShell.setFullScreen(true);
+ // backgroundShell.setMaximized(true);
backgroundShell.setAlpha(128);
backgroundShell.setBackground(getDisplay().getSystemColor(SWT.COLOR_BLACK));
backgroundShell.open();
- shell = new Shell(backgroundShell, SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
- shell.setLayout(new GridLayout());
- // shell.setText("Error");
- shell.setSize(getInitialSize());
- createDialogArea(shell);
+ foregoundShell = new Shell(backgroundShell, SWT.NO_TRIM | SWT.ON_TOP);
+ if (title != null)
+ setTitle(title);
+ foregoundShell.setLayout(new GridLayout());
+ foregoundShell.setSize(getInitialSize());
+ createDialogArea(foregoundShell);
// shell.pack();
// shell.layout();
Rectangle shellBounds = Display.getCurrent().getBounds();// RAP
- Point dialogSize = shell.getSize();
+ Point dialogSize = foregoundShell.getSize();
int x = shellBounds.x + (shellBounds.width - dialogSize.x) / 2;
int y = shellBounds.y + (shellBounds.height - dialogSize.y) / 2;
- shell.setLocation(x, y);
+ foregoundShell.setLocation(x, y);
- shell.addShellListener(new ShellAdapter() {
+ foregoundShell.addShellListener(new ShellAdapter() {
private static final long serialVersionUID = -2701270481953688763L;
@Override
public void shellDeactivated(ShellEvent e) {
- closeShell();
+ if (returnCode == null)// not yet closed
+ closeShell(CANCEL);
+ }
+
+ @Override
+ public void shellClosed(ShellEvent e) {
+ notifyClose();
}
+
});
- shell.open();
+ foregoundShell.open();
// after the foreground shell has been opened
backgroundShell.addFocusListener(new FocusListener() {
private static final long serialVersionUID = 3137408447474661070L;
@Override
public void focusGained(FocusEvent event) {
- closeShell();
+ if (returnCode == null)// not yet closed
+ closeShell(CANCEL);
}
});
+
+ if (block) {
+ runEventLoop(foregoundShell);
+ }
+ if (returnCode == null)
+ returnCode = OK;
+ return returnCode;
}
- protected void closeShell() {
- if (shell != null) {
- shell.close();
- shell.dispose();
- shell = null;
+ // public synchronized int openAndWait() {
+ // open();
+ // while (returnCode == null)
+ // try {
+ // wait(100);
+ // } catch (InterruptedException e) {
+ // // silent
+ // }
+ // return returnCode;
+ // }
+
+ private synchronized void notifyClose() {
+ if (returnCode == null)
+ returnCode = CANCEL;
+ notifyAll();
+ }
+
+ protected void closeShell(int returnCode) {
+ this.returnCode = returnCode;
+ if (CANCEL == returnCode)
+ onCancel();
+ if (foregoundShell != null && !foregoundShell.isDisposed()) {
+ foregoundShell.close();
+ foregoundShell.dispose();
+ foregoundShell = null;
}
- if (backgroundShell != null) {
+ if (backgroundShell != null && !backgroundShell.isDisposed()) {
backgroundShell.close();
backgroundShell.dispose();
}
// if (exception != null)
// return new Point(800, 600);
// else
- return new Point(400, 400);
+ return new Point(600, 400);
}
protected Control createDialogArea(Composite parent) {
dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
return dialogarea;
}
+
+ protected Shell getBackgroundShell() {
+ return backgroundShell;
+ }
+
+ protected Shell getForegoundShell() {
+ return foregoundShell;
+ }
+
+ public void setBlockOnOpen(boolean shouldBlock) {
+ block = shouldBlock;
+ }
+
+ private void runEventLoop(Shell loopShell) {
+ Display display;
+ if (foregoundShell == null) {
+ display = Display.getCurrent();
+ } else {
+ display = loopShell.getDisplay();
+ }
+
+ while (loopShell != null && !loopShell.isDisposed()) {
+ try {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ } catch (Throwable e) {
+ handleException(e);
+ }
+ }
+ if (!display.isDisposed())
+ display.update();
+ }
+
+ protected void handleException(Throwable t) {
+ if (t instanceof ThreadDeath) {
+ // Don't catch ThreadDeath as this is a normal occurrence when
+ // the thread dies
+ throw (ThreadDeath) t;
+ }
+ // Try to keep running.
+ t.printStackTrace();
+ }
+
+ /** @return false, if the dialog should not be closed. */
+ protected boolean onCancel() {
+ return true;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ if (getForegoundShell() != null)
+ getForegoundShell().setText(title);
+ }
+
}
\ No newline at end of file