blob: 2ea6f3f313d09c268c02facdefc089404190890c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010 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.swing;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dialog;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Image;
import java.awt.KeyboardFocusManager;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyVetoException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.WeakHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.RootPaneContainer;
import javax.swing.SwingUtilities;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.border.LineBorder;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.scout.commons.CSSPatch;
import org.eclipse.scout.commons.HTMLUtility;
import org.eclipse.scout.commons.HTMLUtility.DefaultFont;
import org.eclipse.scout.commons.StringUtility;
import org.eclipse.scout.commons.beans.IPropertyObserver;
import org.eclipse.scout.commons.job.JobEx;
import org.eclipse.scout.commons.logger.IScoutLogger;
import org.eclipse.scout.commons.logger.ScoutLogManager;
import org.eclipse.scout.rt.client.ClientSyncJob;
import org.eclipse.scout.rt.client.IClientSession;
import org.eclipse.scout.rt.client.busy.IBusyManagerService;
import org.eclipse.scout.rt.client.ui.ClientUIPreferences;
import org.eclipse.scout.rt.client.ui.action.IAction;
import org.eclipse.scout.rt.client.ui.basic.filechooser.IFileChooser;
import org.eclipse.scout.rt.client.ui.desktop.DesktopEvent;
import org.eclipse.scout.rt.client.ui.desktop.DesktopListener;
import org.eclipse.scout.rt.client.ui.desktop.IDesktop;
import org.eclipse.scout.rt.client.ui.form.FormEvent;
import org.eclipse.scout.rt.client.ui.form.IForm;
import org.eclipse.scout.rt.client.ui.form.fields.IFormField;
import org.eclipse.scout.rt.client.ui.form.fields.groupbox.IGroupBox;
import org.eclipse.scout.rt.client.ui.form.fields.htmlfield.IHtmlField;
import org.eclipse.scout.rt.client.ui.form.fields.mailfield.IMailField;
import org.eclipse.scout.rt.client.ui.messagebox.IMessageBox;
import org.eclipse.scout.rt.ui.swing.action.ISwingScoutAction;
import org.eclipse.scout.rt.ui.swing.basic.SwingScoutComposite;
import org.eclipse.scout.rt.ui.swing.concurrency.SwingScoutSynchronizer;
import org.eclipse.scout.rt.ui.swing.ext.IEmbeddedFrameProviderService;
import org.eclipse.scout.rt.ui.swing.ext.JDialogEx;
import org.eclipse.scout.rt.ui.swing.ext.JFrameEx;
import org.eclipse.scout.rt.ui.swing.ext.JStatusLabelEx;
import org.eclipse.scout.rt.ui.swing.ext.JStatusLabelTop;
import org.eclipse.scout.rt.ui.swing.ext.busy.SwingBusyHandler;
import org.eclipse.scout.rt.ui.swing.focus.SwingScoutFocusTraversalPolicy;
import org.eclipse.scout.rt.ui.swing.form.ISwingScoutForm;
import org.eclipse.scout.rt.ui.swing.form.SwingScoutForm;
import org.eclipse.scout.rt.ui.swing.form.fields.ISwingScoutFormField;
import org.eclipse.scout.rt.ui.swing.form.fields.OnFieldLabelDecorator;
import org.eclipse.scout.rt.ui.swing.form.fields.tabbox.ISwingScoutTabItem;
import org.eclipse.scout.rt.ui.swing.form.fields.tabbox.SwingScoutTabItem;
import org.eclipse.scout.rt.ui.swing.inject.ActionInjector;
import org.eclipse.scout.rt.ui.swing.inject.AppendActionsInjector;
import org.eclipse.scout.rt.ui.swing.inject.InitLookAndFeelInjector;
import org.eclipse.scout.rt.ui.swing.inject.UIDefaultsInjector;
import org.eclipse.scout.rt.ui.swing.window.ISwingScoutBoundsProvider;
import org.eclipse.scout.rt.ui.swing.window.ISwingScoutView;
import org.eclipse.scout.rt.ui.swing.window.desktop.ISwingScoutDesktop;
import org.eclipse.scout.rt.ui.swing.window.desktop.ISwingScoutRootFrame;
import org.eclipse.scout.rt.ui.swing.window.desktop.SwingScoutDesktop;
import org.eclipse.scout.rt.ui.swing.window.desktop.SwingScoutRootFrame;
import org.eclipse.scout.rt.ui.swing.window.desktop.layout.MultiSplitLayoutConstraints;
import org.eclipse.scout.rt.ui.swing.window.desktop.tray.ISwingScoutTray;
import org.eclipse.scout.rt.ui.swing.window.desktop.tray.SwingScoutTray;
import org.eclipse.scout.rt.ui.swing.window.dialog.SwingScoutDialog;
import org.eclipse.scout.rt.ui.swing.window.filechooser.ISwingScoutFileChooser;
import org.eclipse.scout.rt.ui.swing.window.filechooser.SwingScoutFileChooser;
import org.eclipse.scout.rt.ui.swing.window.frame.SwingScoutFrame;
import org.eclipse.scout.rt.ui.swing.window.internalframe.SwingScoutInternalFrame;
import org.eclipse.scout.rt.ui.swing.window.messagebox.ISwingScoutMessageBox;
import org.eclipse.scout.rt.ui.swing.window.messagebox.SwingScoutMessageBox;
import org.eclipse.scout.rt.ui.swing.window.popup.SwingScoutPopup;
import org.eclipse.scout.service.SERVICES;
public abstract class AbstractSwingEnvironment implements ISwingEnvironment {
private static final IScoutLogger LOG = ScoutLogManager.getLogger(AbstractSwingEnvironment.class);
private boolean m_initialized;
private IClientSession m_scoutSession;
private SwingScoutSynchronizer m_synchronizer;
private SwingIconLocator m_iconLocator;
private ISwingScoutTray m_trayComposite;
private Frame m_rootFrame;
private FormFieldFactory m_formFieldFactory;
private ISwingScoutRootFrame m_rootComposite;
private final PropertyChangeSupport m_propertySupport = new PropertyChangeSupport(this);
private final WeakHashMap<IForm, ISwingScoutForm> m_standaloneFormComposites;
private Component m_popupOwner;
private Rectangle m_popupOwnerBounds;
private final Object m_immediateSwingJobsLock = new Object();
private final List<Runnable> m_immediateSwingJobs = new ArrayList<Runnable>();
public AbstractSwingEnvironment() {
checkThread();
m_standaloneFormComposites = new WeakHashMap<IForm, ISwingScoutForm>();
init();
}
@Override
public void init() {
checkThread();
if (!m_initialized) {
m_initialized = true;
// disable direct draw (see
// http://java.sun.com/j2se/1.5.0/docs/guide/2d/flags.html#noddraw)
System.setProperty("sun.java2d.noddraw", "true");
System.getProperty("sun.java2d.noddraw", "true");// read to make it
//only system properties are visible inside javax.swing
initLookAndFeel(System.getProperties());
interceptUIDefaults(UIManager.getDefaults());
CSSPatch.apply();
m_rootFrame = createRootFrame();
if (m_rootFrame != null) {
setWindowIcon(m_rootFrame);
}
m_synchronizer = new SwingScoutSynchronizer(this);
}
}
/**
* Initialize the Swing look and feel.
* Three styles are supported: Scout, Synth (Swing), and Default (Swing)
* <p>
* Properties: scout.laf, javax.swing.plaf.synth.style, swing.defaultlaf
*/
protected void initLookAndFeel(Properties initProperties) {
new InitLookAndFeelInjector().inject(initProperties);
}
@Override
public Icon getIcon(String name) {
Icon icon = m_iconLocator.getIcon(name);
// No application icon could be found. Look for a respective Scout icon.
if (icon == null) {
icon = Activator.getIcon(name);
}
return icon;
}
@Override
public Image getImage(String name) {
Image image = m_iconLocator.getImage(name);
// No application image could be found. Look for a respective Scout image.
if (image == null) {
image = Activator.getImage(name);
}
return image;
}
public List<Image> getImages(String... names) {
List<Image> result = new ArrayList<Image>();
if (names != null) {
for (String name : names) {
if (name != null) {
Image img = getImage(name);
if (img != null) {
result.add(img);
}
}
}
}
return result;
}
/**
* Sets the icon of the specified window (e.g. used in the Task bar, Title bar, etc.).
* If 'legacyIcon' is not null, the specified image is used. If (and only if) 'legacyIcon'
* is null, the 'icons' list is used. The operating system can then choose the best
* matching image out of this list (usually, you put different sizes of icons in this list).
*/
protected void setWindowIcon(Window window) {
// legacy
Image legacyIcon = Activator.getImage(SwingIcons.Window);
if (legacyIcon != null) {
window.setIconImage(legacyIcon);
}
else {
ArrayList<Image> icons = new ArrayList<Image>();
for (String name : new String[]{SwingIcons.Window16, SwingIcons.Window32, SwingIcons.Window48, SwingIcons.Window256}) {
if (name != null) {
Image img = Activator.getImage(name);
if (img != null) {
icons.add(img);
}
}
}
window.setIconImages(icons);
}
}
protected ISwingScoutTray createTray(IDesktop desktop) {
SwingScoutTray ui = new SwingScoutTray();
ui.createField(desktop, this);
decorate(desktop, ui);
return ui;
}
@Override
public ISwingScoutTray getTrayComposite() {
return m_trayComposite;
}
@Override
public int getFormColumnWidth() {
return 360;
}
@Override
public int getFormColumnGap() {
return 12;
}
@Override
public int getFormRowHeight() {
return 23;
}
@Override
public int getFormRowGap() {
return 6;
}
@Override
public int getFieldLabelWidth() {
return 130;
}
@Override
public int getProcessButtonHeight() {
return 28;
}
@Override
public int getIconButtonSize() {
return 23;
}
@Override
public int getDropDownButtonWidth() {
return 35;
}
@Override
public void interceptUIDefaults(UIDefaults defaults) {
new UIDefaultsInjector().inject(defaults);
}
@Override
public Frame getRootFrame() {
checkThread();
return m_rootFrame;
}
@Override
public ISwingScoutRootFrame getRootComposite() {
return m_rootComposite;
}
/**
* Is called before desktop is displayed
*
* @param clientSession
* @return true to start desktop or false to exit application
* @throws Exception
*/
protected boolean execBeforeDesktop(IClientSession clientSession) throws Exception {
return true;
}
@Override
public void showGUI(IClientSession session) {
checkThread();
m_scoutSession = session;
//set global text provider
SwingUtility.setNlsTexts(m_scoutSession.getTexts());
if (m_rootFrame == null) {
m_scoutSession.stopSession();
return;
}
m_iconLocator = createIconLocator();
try {
if (!execBeforeDesktop(session)) {
System.exit(0);
}
}
catch (Exception e) {
LOG.error("GUI initialization failed", e);
System.exit(0);
}
final IDesktop desktop = m_scoutSession.getDesktop();
if (desktop != null) {
m_scoutSession.getDesktop().addDesktopListener(new DesktopListener() {
@Override
public void desktopChanged(final DesktopEvent e) {
switch (e.getType()) {
case DesktopEvent.TYPE_FORM_ADDED: {
Runnable t = new Runnable() {
@Override
public void run() {
showStandaloneForm(null, e.getForm());
}
};
invokeSwingLater(t);
break;
}
case DesktopEvent.TYPE_FORM_REMOVED: {
Runnable t = new Runnable() {
@Override
public void run() {
hideStandaloneForm(e.getForm());
}
};
invokeSwingLater(t);
break;
}
case DesktopEvent.TYPE_FORM_ENSURE_VISIBLE: {
Runnable t = new Runnable() {
@Override
public void run() {
activateStandaloneForm(e.getForm());
}
};
invokeSwingLater(t);
break;
}
case DesktopEvent.TYPE_MESSAGE_BOX_ADDED: {
Runnable t = new Runnable() {
@Override
public void run() {
showMessageBox(null, e.getMessageBox());
}
};
invokeSwingLater(t);
break;
}
case DesktopEvent.TYPE_FILE_CHOOSER_ADDED: {
Runnable t = new Runnable() {
@Override
public void run() {
showFileChooser(null, e.getFileChooser());
}
};
invokeSwingLater(t);
break;
}
case DesktopEvent.TYPE_FIND_FOCUS_OWNER: {
final Object lock = new Object();
Runnable t = new Runnable() {
@Override
public void run() {
try {
IFormField f = findFocusOwnerField();
if (f != null) {
e.setFocusedField(f);
}
}
finally {
synchronized (lock) {
lock.notifyAll();
}
}
}
};
synchronized (lock) {
invokeSwingLater(t);
try {
lock.wait(2000L);
}
catch (InterruptedException e1) {
//nop
}
}
break;
}
}
}
});
m_rootComposite = createRootComposite(getRootFrame(), m_scoutSession.getDesktop());
m_rootComposite.showSwingFrame();
// load state of views
for (IForm f : desktop.getViewStack()) {
if (f.isAutoAddRemoveOnDesktop()) {
showStandaloneForm(getRootFrame(), f);
}
}
//tray icon
if (desktop.isTrayVisible()) {
m_trayComposite = createTray(desktop);
}
// dialogs
for (IForm f : desktop.getDialogStack()) {
if (f.isAutoAddRemoveOnDesktop()) {
showStandaloneForm(getRootFrame(), f);
}
}
// messageboxes
for (IMessageBox mb : desktop.getMessageBoxStack()) {
showMessageBox(getRootFrame(), mb);
}
// notify desktop that it is loaded
new ClientSyncJob("Desktop opened", session) {
@Override
protected void runVoid(IProgressMonitor monitor) throws Throwable {
desktop.getUIFacade().fireDesktopOpenedFromUI();
desktop.getUIFacade().fireGuiAttached();
}
}.schedule();
}
attachBusyHandler(session);
}
protected SwingBusyHandler attachBusyHandler(IClientSession session) {
IBusyManagerService service = SERVICES.getService(IBusyManagerService.class);
if (service == null) {
return null;
}
SwingBusyHandler handler = new SwingBusyHandler(session);
service.register(session, handler);
return handler;
}
@Override
public void addPropertyChangeListener(PropertyChangeListener listener) {
m_propertySupport.addPropertyChangeListener(listener);
}
@Override
public void removePropertyChangeListener(PropertyChangeListener listener) {
m_propertySupport.removePropertyChangeListener(listener);
}
@Override
public IClientSession getScoutSession() {
return m_scoutSession;
}
@SuppressWarnings("deprecation")
@Override
public boolean isBusy() {
//replaced by SwingBusyHandler
return false;
}
@SuppressWarnings("deprecation")
@Override
public void setBusyFromSwing(boolean b) {
//replaced by SwingBusyHandler
}
@Override
public void postImmediateSwingJob(Runnable r) {
synchronized (m_immediateSwingJobsLock) {
m_immediateSwingJobs.add(r);
}
}
@Override
public void dispatchImmediateSwingJobs() {
List<Runnable> list;
synchronized (m_immediateSwingJobsLock) {
list = new ArrayList<Runnable>(m_immediateSwingJobs);
m_immediateSwingJobs.clear();
}
for (Runnable r : list) {
try {
r.run();
}
catch (Throwable t) {
LOG.warn("running " + r, t);
}
}
}
@Override
public JobEx invokeScoutLater(Runnable j, long cancelTimeout) {
synchronized (m_immediateSwingJobsLock) {
m_immediateSwingJobs.clear();
}
return m_synchronizer.invokeScoutLater(j, cancelTimeout);
}
@Override
public void invokeSwingLater(Runnable j) {
m_synchronizer.invokeSwingLater(j);
}
/*
* Factory
*/
protected SwingIconLocator createIconLocator() {
return new SwingIconLocator(getScoutSession().getIconLocator());
}
@Override
public Frame createRootFrame() {
Frame rootFrame = null;
/*
* support for (browser) embedded applications using a hWnd
*/
long hWnd = 0;
Pattern pat = Pattern.compile("hWnd=([-]?[0-9]+)");
for (String s : Platform.getApplicationArgs()) {
Matcher m = pat.matcher(s.trim());
if (m.matches()) {
hWnd = Long.parseLong(m.group(1));
break;
}
}
if (hWnd != 0) {
IEmbeddedFrameProviderService es = SERVICES.getService(IEmbeddedFrameProviderService.class);
if (es != null) {
try {
rootFrame = es.createEmbeddedFrame(hWnd);
rootFrame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(WindowEvent e) {
m_rootFrame = null;
if (m_scoutSession != null) {
m_scoutSession.stopSession();
}
}
});
}
catch (Throwable t) {
LOG.error("create embedded frame using " + es.getClass(), t);
}
}
}
if (rootFrame == null) {
rootFrame = new JFrameEx();
((JFrameEx) rootFrame).getRootPane().setName("Synth.Frame");
((JFrameEx) rootFrame).setAutoCorrectSize(false);
}
if (rootFrame instanceof RootPaneContainer) {
decorateAppZone((RootPaneContainer) rootFrame);
}
return rootFrame;
}
@Override
public ISwingScoutRootFrame createRootComposite(Frame rootFrame, IDesktop desktop) {
ISwingScoutRootFrame ui = new SwingScoutRootFrame(rootFrame);
ui.createField(desktop, this);
decorate(desktop, ui);
return ui;
}
protected void decorate(Object scoutObject, Object swingScoutComposite) {
}
/**
* decorateAppZone is called after a frame or dialog is created
*
* <pre>
* app.zone=prod | production (paints no special border around all dialogs and frames, this is the default)
* app.zone=int | integration (paints a yellow border around all dialogs and frames)
* app.zone=test (paints an orange border around all dialogs and frames)
* app.zone=dev | development (paints a red border around all dialogs and frames)
* </pre>
*/
protected void decorateAppZone(RootPaneContainer root) {
String zone = Activator.getDefault().getBundle().getBundleContext().getProperty("app.zone");
if (zone == null) {
//production
}
else if (zone.equals("int") || zone.equals("integration")) {
root.getRootPane().setBorder(new LineBorder(Color.yellow, 3));
}
else if (zone.equals("test")) {
root.getRootPane().setBorder(new LineBorder(Color.orange, 3));
}
else if (zone.equals("dev") || zone.equals("development")) {
root.getRootPane().setBorder(new LineBorder(Color.red, 3));
}
}
protected Window getOwnerForChildWindow(Component parent) {
if (parent != null) {
if (parent instanceof Window) {
return (Window) parent;
}
Window w = SwingUtilities.getWindowAncestor(parent);
if (w != null) {
return w;
}
}
return SwingUtility.getOwnerForChildWindow();
}
@Override
public ISwingScoutDesktop createDesktop(Window owner, IDesktop desktop) {
ISwingScoutDesktop ui = new SwingScoutDesktop();
ui.createField(desktop, this);
decorate(desktop, ui);
return ui;
}
@Override
public void showStandaloneForm(Component parent, IForm f) {
if (f == null) {
return;
}
ISwingScoutView view = null;
ISwingScoutForm formComposite = m_standaloneFormComposites.get(f);
if (formComposite != null) {
view = formComposite.getView();
}
if (view != null) {
return;
}
//
Window w = getOwnerForChildWindow(parent);
switch (f.getDisplayHint()) {
case IForm.DISPLAY_HINT_DIALOG: {
if (f.isModal() || w instanceof Dialog) {
view = createDialog(w, f);
}
else {
view = createFrame(w, f);
}
break;
}
case IForm.DISPLAY_HINT_VIEW: {
Object constraints = getViewLayoutConstraintsFor(f);
view = createView(constraints, f);
break;
}
case IForm.DISPLAY_HINT_POPUP_WINDOW: {
view = createPopupWindow(w, f);
if (view == null) {
LOG.error("showing popup for " + f + ", but there is neither a focus owner nor the property 'ISwingEnvironment.getPopupOwner()'");
return;
}
break;
}
case IForm.DISPLAY_HINT_POPUP_DIALOG: {
view = createPopupDialog(w, f);
if (view == null) {
LOG.error("showing popup for " + f + ", but there is neither a focus owner nor the property 'ISwingEnvironment.getPopupOwner()'");
return;
}
break;
}
}
if (view != null) {
formComposite = createForm(view, f);
m_standaloneFormComposites.put(f, formComposite);
view.openView();
}
}
@Override
public void hideStandaloneForm(IForm f) {
if (f != null) {
ISwingScoutForm formComposite = m_standaloneFormComposites.remove(f);
if (formComposite != null) {
ISwingScoutView viewComposite = formComposite.getView();
formComposite.detachSwingView();
if (viewComposite != null) {
viewComposite.closeView();
}
}
}
}
@Override
public ISwingScoutForm[] getStandaloneFormComposites() {
ArrayList<ISwingScoutForm> list = new ArrayList<ISwingScoutForm>();
for (ISwingScoutForm f : m_standaloneFormComposites.values()) {
if (f != null) {
list.add(f);
}
}
return list.toArray(new ISwingScoutForm[list.size()]);
}
@Override
public ISwingScoutForm getStandaloneFormComposite(IForm f) {
if (f != null) {
ISwingScoutForm formComposite = m_standaloneFormComposites.get(f);
return formComposite;
}
return null;
}
@Override
public void activateStandaloneForm(IForm f) {
if (f != null) {
ISwingScoutForm formComposite = m_standaloneFormComposites.get(f);
if (formComposite != null) {
RootPaneContainer root = (RootPaneContainer) SwingUtilities.getAncestorOfClass(RootPaneContainer.class, formComposite.getSwingFormPane());
if (root instanceof JInternalFrame) {
try {
((JInternalFrame) root).setSelected(true);
}
catch (PropertyVetoException e) {
}
}
else if (root instanceof Window) {
((Window) root).requestFocusInWindow();
}
}
}
}
@Override
public Object getViewLayoutConstraintsFor(IForm f) {
String viewId = f.getDisplayViewId();
return getViewLayoutConstraintsFor(viewId);
}
@Override
public Object getViewLayoutConstraintsFor(String viewId) {
// begin mapping
if (IForm.VIEW_ID_OUTLINE_SELECTOR.equalsIgnoreCase(viewId)) {
viewId = IForm.VIEW_ID_SW;
}
else if (IForm.VIEW_ID_OUTLINE.equalsIgnoreCase(viewId)) {
viewId = IForm.VIEW_ID_NW;
}
else if (IForm.VIEW_ID_PAGE_DETAIL.equalsIgnoreCase(viewId)) {
viewId = IForm.VIEW_ID_N;
}
else if (IForm.VIEW_ID_PAGE_TABLE.equalsIgnoreCase(viewId)) {
viewId = IForm.VIEW_ID_CENTER;
}
else if (IForm.VIEW_ID_PAGE_SEARCH.equalsIgnoreCase(viewId)) {
viewId = IForm.VIEW_ID_S;
}
// end mapping
if (viewId == null) {
return new MultiSplitLayoutConstraints(1, 1, 0, new float[]{10, 10, 10, 10, 10, 10, 10, 10, 10});
}
else if (viewId.equalsIgnoreCase(IForm.VIEW_ID_N)) {
return new MultiSplitLayoutConstraints(0, 1, 40, new float[]{7, 9, 7, 6, 6, 5, 4, 3, 4});
}
else if (viewId.equalsIgnoreCase(IForm.VIEW_ID_NE)) {
return new MultiSplitLayoutConstraints(0, 2, 70, new float[]{0, 0, 9, 0, 0, 8, 0, 0, 5});
}
else if (viewId.equalsIgnoreCase(IForm.VIEW_ID_E)) {
return new MultiSplitLayoutConstraints(1, 2, 80, new float[]{0, 0, 8, 0, 0, 9, 0, 0, 8});
}
else if (viewId.equalsIgnoreCase(IForm.VIEW_ID_SE)) {
return new MultiSplitLayoutConstraints(2, 2, 90, new float[]{0, 0, 5, 0, 0, 7, 0, 0, 9});
}
else if (viewId.equalsIgnoreCase(IForm.VIEW_ID_S)) {
return new MultiSplitLayoutConstraints(2, 1, 60, new float[]{5, 3, 4, 5, 5, 4, 6, 9, 7});
}
else if (viewId.equalsIgnoreCase(IForm.VIEW_ID_SW)) {
return new MultiSplitLayoutConstraints(2, 0, 10, new float[]{0, 0, 0, 0, 0, 0, 9, 0, 0});
}
else if (viewId.equalsIgnoreCase(IForm.VIEW_ID_W)) {
return new MultiSplitLayoutConstraints(1, 0, 20, new float[]{8, 0, 0, 9, 0, 0, 8, 0, 0});
}
else if (viewId.equalsIgnoreCase(IForm.VIEW_ID_NW)) {
return new MultiSplitLayoutConstraints(0, 0, 30, new float[]{9, 0, 0, 8, 0, 0, 7, 0, 0});
}
else if (viewId.equalsIgnoreCase(IForm.VIEW_ID_CENTER)) {
return new MultiSplitLayoutConstraints(1, 1, 50, new float[]{6, 6, 6, 7, 9, 6, 5, 6, 6});
}
else {
LOG.warn("unexpected viewId \"" + viewId + "\"");
return new MultiSplitLayoutConstraints(1, 1, 50, new float[]{6, 6, 6, 7, 9, 6, 6, 6, 6});
}
}
@Override
public IFormField findFocusOwnerField() {
Component comp = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
while (comp instanceof JComponent) {
IPropertyObserver o = SwingScoutComposite.getScoutModelOnWidget(comp);
if (o instanceof IFormField) {
return (IFormField) o;
}
// next
comp = comp.getParent();
}
return null;
}
@Override
public void showMessageBox(Component parent, IMessageBox mb) {
ISwingScoutMessageBox mbox = createMessageBox(getOwnerForChildWindow(parent), mb);
mbox.showSwingMessageBox();
}
@Override
public ISwingScoutMessageBox createMessageBox(Window w, IMessageBox mb) {
ISwingScoutMessageBox ui = new SwingScoutMessageBox(w);
ui.createField(mb, this);
ui.setName("Synth.Dialog");
decorate(mb, ui);
return ui;
}
@Override
public void showFileChooser(Component parent, IFileChooser fc) {
ISwingScoutFileChooser sfc = createFileChooser(getOwnerForChildWindow(parent), fc);
sfc.showFileChooser();
}
@Override
public ISwingScoutFileChooser createFileChooser(Window w, IFileChooser fc) {
ISwingScoutFileChooser ui = new SwingScoutFileChooser(this, fc, w, false);
decorate(fc, ui);
return ui;
}
@Override
public ISwingScoutFormField createFormField(JComponent parent, IFormField field) {
if (m_formFieldFactory == null) {
m_formFieldFactory = new FormFieldFactory();
}
ISwingScoutFormField ui = m_formFieldFactory.createFormField(parent, field, this);
decorate(field, ui);
return ui;
}
@Override
public JDialogEx createJDialogEx(Dialog swingParent) {
return new JDialogEx(swingParent);
}
@Override
public JDialogEx createJDialogEx(Frame swingParent) {
return new JDialogEx(swingParent);
}
@Override
public ISwingScoutView createDialog(Window owner, IForm form) {
ISwingScoutBoundsProvider boundsProvider = null;
if (form.isCacheBounds()) {
boundsProvider = new P_FormBoundsProvider(form);
}
ISwingScoutView ui = new SwingScoutDialog(this, owner, boundsProvider, form.isModal());
ui.setName("Synth.Dialog");
Window w = SwingUtilities.getWindowAncestor(ui.getSwingContentPane());
if (w != null) {
setWindowIcon(w);
}
decorate(form, ui);
if (w instanceof RootPaneContainer) {
decorateAppZone((RootPaneContainer) w);
}
return ui;
}
@Override
public ISwingScoutView createFrame(Window owner, IForm form) {
ISwingScoutBoundsProvider boundsProvider = null;
if (form.isCacheBounds()) {
boundsProvider = new P_FormBoundsProvider(form);
}
ISwingScoutView ui = new SwingScoutFrame(this, boundsProvider);
ui.setName("Synth.Frame");
Window w = SwingUtilities.getWindowAncestor(ui.getSwingContentPane());
if (w != null) {
setWindowIcon(w);
}
decorate(form, ui);
if (w instanceof RootPaneContainer) {
decorateAppZone((RootPaneContainer) w);
}
return ui;
}
@Override
public ISwingScoutView createPopupDialog(Window parentWindow, IForm form) {
Component owner = getPopupOwner();
if (owner == null) {
owner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
}
if (owner == null) {
return null;
}
Rectangle ownerBounds = getPopupOwnerBounds();
if (ownerBounds == null) {
ownerBounds = owner.getBounds();
}
final Rectangle ownerBoundsFinal = ownerBounds;
ISwingScoutBoundsProvider boundsProvider = new ISwingScoutBoundsProvider() {
@Override
public Rectangle getBounds() {
return ownerBoundsFinal;
}
@Override
public void storeBounds(Rectangle bounds) {
}
};
ISwingScoutView ui = new SwingScoutDialog(this, parentWindow, boundsProvider);
ui.setName("Synth.Dialog");
Window w = SwingUtilities.getWindowAncestor(ui.getSwingContentPane());
if (w != null) {
setWindowIcon(w);
}
decorate(form, ui);
return ui;
}
@Override
public ISwingScoutView createPopupWindow(Window parentWindow, IForm form) {
Component owner = getPopupOwner();
if (owner == null) {
owner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
}
if (owner == null) {
return null;
}
Rectangle ownerBounds = getPopupOwnerBounds();
if (ownerBounds == null) {
ownerBounds = owner.getBounds();
}
final SwingScoutPopup ui = new SwingScoutPopup(this, owner, ownerBounds);
//close popup when PARENT shell is activated, closed or focused
SwingUtilities.getWindowAncestor(owner).addWindowListener(new WindowAdapter() {
@Override
public void windowActivated(WindowEvent e) {
//auto-detach
e.getWindow().removeWindowListener(this);
ui.closeView();
}
@Override
public void windowClosed(WindowEvent e) {
//auto-detach
e.getWindow().removeWindowListener(this);
ui.closeView();
}
});
SwingUtilities.getWindowAncestor(owner).addWindowFocusListener(new WindowAdapter() {
@Override
public void windowGainedFocus(WindowEvent e) {
//auto-detach
e.getWindow().removeWindowFocusListener(this);
ui.closeView();
}
});
ui.setName("Synth.Popup");
decorate(form, ui);
return ui;
}
@Override
public ISwingScoutView createView(Object viewConstraints, IForm form) {
ISwingScoutBoundsProvider boundsProvider = null;
if (form.isCacheBounds()) {
boundsProvider = new P_FormBoundsProvider(form);
}
ISwingScoutView ui = createInternalFrame(viewConstraints, form, boundsProvider);
ui.setName("Synth.View");
decorate(form, ui);
return ui;
}
protected ISwingScoutView createInternalFrame(Object viewConstraints, IForm form, ISwingScoutBoundsProvider boundsProvider) {
return new SwingScoutInternalFrame(this, viewConstraints, boundsProvider);
}
@Override
public ISwingScoutForm createForm(JComponent parent, IForm model) {
ISwingScoutForm ui = new SwingScoutForm(this, model);
ui.createField(model, this);
decorate(model, ui);
return ui;
}
@Override
public ISwingScoutForm createForm(ISwingScoutView targetViewComposite, IForm model) {
ISwingScoutForm ui = new SwingScoutForm(this, targetViewComposite, model);
ui.createField(model, this);
decorate(model, ui);
return ui;
}
@Override
public ISwingScoutTabItem createTabItem(JComponent parent, IGroupBox field) {
SwingScoutTabItem ui = new SwingScoutTabItem();
ui.createField(field, this);
decorate(field, ui);
return ui;
}
@Override
public void appendActions(JComponent parent, List<? extends IAction> actions) {
new AppendActionsInjector().inject(this, parent, actions);
}
@Override
public ISwingScoutAction createAction(JComponent parent, IAction action) {
ISwingScoutAction ui = new ActionInjector().inject(this, parent, action);
decorate(action, ui);
return ui;
}
/**
* @return true if component can realistically gain focus
*/
@Override
@SuppressWarnings("deprecation")
public boolean acceptAsFocusTarget(Component comp) {
checkThread();
return new SwingScoutFocusTraversalPolicy().accept(comp);
}
@SuppressWarnings("deprecation")
@Override
public JStatusLabelEx createStatusLabel() {
return createStatusLabel(null);
}
@Override
public JStatusLabelEx createStatusLabel(IFormField formField) {
JStatusLabelEx ui = null;
if (formField != null && formField.getLabelPosition() == IFormField.LABEL_POSITION_TOP) {
ui = new JStatusLabelTop();
}
else {
ui = new JStatusLabelEx();
}
ui.setName("Synth.StatusLabel");
return ui;
}
@Override
public OnFieldLabelDecorator createOnFieldLabelDecorator(JComponent c, boolean mandatory) {
return new OnFieldLabelDecorator(c, mandatory);
}
@Override
public JComponent createLogo() {
JLabel logo = new JLabel();
logo.setIcon(Activator.getIcon(SwingIcons.Logo));
return logo;
}
@Override
public Component getPopupOwner() {
return m_popupOwner;
}
@Override
public Rectangle getPopupOwnerBounds() {
return m_popupOwnerBounds;
}
@Override
public void setPopupOwner(Component owner, Rectangle ownerBounds) {
m_popupOwner = owner;
m_popupOwnerBounds = ownerBounds;
}
@Override
public String styleHtmlText(ISwingScoutFormField<?> uiComposite, String rawHtml) {
String cleanHtml = rawHtml;
if (cleanHtml == null) {
cleanHtml = "";
}
if (uiComposite.getScoutObject() instanceof IHtmlField) {
IHtmlField htmlField = (IHtmlField) uiComposite.getScoutObject();
if (htmlField.isHtmlEditor()) {
/*
* In HTML editor mode, the HTML is not styled except that an empty HTML skeleton is created in case the given HTML is empty.
* In general no extra styling should be applied because the HTML installed in the editor should be the very same as
* provided. Otherwise, if the user did some modifications in the HTML source and reloads the HTML in the editor anew,
* unwanted auto-corrections would be applied.
*/
if (!StringUtility.hasText(cleanHtml)) {
cleanHtml = "<html><head></head><body></body></html>";
}
}
else {
cleanHtml = HTMLUtility.cleanupHtml(cleanHtml, false, true, createDefaultFontSettings(uiComposite.getSwingField()));
}
}
else if (uiComposite.getScoutObject() instanceof IMailField) {
cleanHtml = HTMLUtility.cleanupHtml(cleanHtml, false, true, createDefaultFontSettings(uiComposite.getSwingField()));
}
return cleanHtml;
}
/**
* Get Swing specific default font settings
*/
protected DefaultFont createDefaultFontSettings(JComponent component) {
Font f = component.getFont();
Color color = component.getForeground();
DefaultFont defaultFont = new DefaultFont();
defaultFont.setFamilies(new String[]{f.getFamily(), "sans-serif"});
defaultFont.setSize(f.getSize());
defaultFont.setSizeUnit("pt");
defaultFont.setForegroundColor(color.getRGB());
return defaultFont;
}
private static void checkThread() {
if (!SwingUtilities.isEventDispatchThread()) {
throw new IllegalStateException("Must be called in swing thread");
}
}
@SuppressWarnings("deprecation")
@Override
public FormEvent[] fetchPendingPrintEvents(IForm form) {
return new FormEvent[0];
}
/**
* To provide cached bounds
*/
private class P_FormBoundsProvider implements ISwingScoutBoundsProvider {
private final IForm m_form;
public P_FormBoundsProvider(IForm form) {
m_form = form;
}
@Override
public Rectangle getBounds() {
Rectangle r = ClientUIPreferences.getInstance(getScoutSession()).getFormBounds(m_form);
// ticket 78127: validate on screen to avoid out-of-screen placement
if (r != null) {
r = SwingUtility.validateRectangleOnScreen(r, false, false);
}
return r;
}
@Override
public void storeBounds(Rectangle bounds) {
ClientUIPreferences.getInstance(getScoutSession()).setFormBounds(m_form, bounds);
}
}
}