blob: ea4e51532661815d76837f4c1395d5a181a4f273 [file] [log] [blame]
/*
* Copyright (c) 2014 Eike Stepper (Loehne, Germany) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.oomph.internal.ui;
import org.eclipse.oomph.ui.UIUtil;
import org.eclipse.oomph.util.ReflectUtil;
import org.eclipse.jface.dialogs.IDialogPage;
import org.eclipse.jface.wizard.ProgressMonitorPart;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Scrollable;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.PlatformUI;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicReference;
/**
* @author Ed Merks
*/
public abstract class Capture<T>
{
protected abstract T create(Shell shell);
protected abstract Shell getShell(T element);
protected abstract void open(T element);
public Image capture()
{
final AtomicReference<Image> image = new AtomicReference<Image>();
final Display display = PlatformUI.getWorkbench().getDisplay();
final org.eclipse.jface.dialogs.Dialog backgroundDialog = new org.eclipse.jface.dialogs.Dialog((Shell)null)
{
{
setShellStyle(SWT.MAX);
}
@Override
protected Control createDialogArea(Composite parent)
{
Control control = super.createDialogArea(parent);
control.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
return control;
}
};
UIUtil.asyncExec(new Runnable()
{
public void run()
{
backgroundDialog.open();
}
});
while (backgroundDialog.getShell() == null)
{
try
{
Thread.sleep(100);
}
catch (InterruptedException ex)
{
// Ignore.
}
}
final Shell backgroundShell = backgroundDialog.getShell();
final T element = new WorkUnit<T, RuntimeException>()
{
@Override
protected T doExecute()
{
backgroundShell.setMaximized(true);
return create(backgroundShell);
}
}.execute();
UIUtil.asyncExec(new Runnable()
{
public void run()
{
open(element);
}
});
UIUtil.asyncExec(new Runnable()
{
public void run()
{
Shell shell = getShell(element);
Rectangle bounds = shell.getBounds();
bounds.x = 30;
bounds.y = 50;
shell.setBounds(bounds);
}
});
while (!new WorkUnit<Boolean, RuntimeException>()
{
@Override
protected Boolean doExecute()
{
return isReady(element);
}
}.execute())
{
try
{
Thread.sleep(100);
}
catch (InterruptedException ex)
{
// Ignore.
}
}
try
{
Thread.sleep(1000);
}
catch (InterruptedException ex)
{
// Ignore.
}
new WorkUnit.Void<RuntimeException>()
{
@Override
protected void doProcess()
{
preprocess(element);
}
}.execute();
new WorkUnit.Void<RuntimeException>()
{
@Override
protected void doProcess()
{
postProcess(element);
}
}.execute();
new WorkUnit.Void<RuntimeException>()
{
@Override
protected void doProcess()
{
image.set(capture(element));
}
}.execute();
new WorkUnit.Void<RuntimeException>()
{
@Override
protected void doProcess()
{
close(element);
backgroundShell.close();
}
}.execute();
return image.get();
}
protected Control getControl(T element)
{
return getShell(element);
}
protected boolean isReady(T element)
{
Shell shell = getShell(element);
if (shell == null)
{
return false;
}
if (shell.getShells().length > 1)
{
return false;
}
return true;
}
protected void preprocess(T element)
{
}
protected void postProcess(T element)
{
Button defaultButton = getShell(element).getDefaultButton();
if (defaultButton != null)
{
ReflectUtil.invokeMethod(ReflectUtil.getMethod(Button.class, "setDefault", boolean.class), defaultButton, false);
}
}
protected Image capture(T element)
{
return AccessUtil.capture(getControl(element));
}
protected Image capture(IDialogPage page, Map<Control, Image> decorations)
{
Control control = page.getControl();
// Get the control of the overall page.
Composite pageControl = control.getParent().getParent().getParent();
Control[] children = pageControl.getChildren();
// Get the overall wizard control.
Composite wizardControl = pageControl.getParent();
// Compute the bounds to capture by extending the bounds of the page control to include the title area but to exclude the bottom button area.
Rectangle bounds = pageControl.getBounds();
Point size = children[1].getSize();
bounds.height += bounds.y - 2;
bounds.y = 0;
bounds.height -= size.y;
Point displayOffset = wizardControl.toDisplay(bounds.x, bounds.y);
Image result = AccessUtil.capture(control.getDisplay(), new Rectangle(displayOffset.x, displayOffset.y, bounds.width, bounds.height));
if (decorations != null && !decorations.isEmpty())
{
decorate(result, wizardControl, bounds, decorations);
}
return result;
}
protected void decorate(Image image, Control parent, Rectangle bounds, Map<Control, Image> decorations)
{
GC gc = new GC(image);
for (Entry<Control, Image> entry : decorations.entrySet())
{
Control control = entry.getKey();
Image decoration = entry.getValue();
if (decoration != null)
{
Rectangle controlBounds = control.getBounds();
int border = control.getBorderWidth();
Point controlLocation = control.getParent().toDisplay(controlBounds.x + controlBounds.width - 1 - border, controlBounds.y - border);
Point relativeControlLocation = parent.toControl(controlLocation);
Rectangle imageBounds = decoration.getBounds();
imageBounds.x = bounds.x + relativeControlLocation.x - (imageBounds.width - 1) - 11;
imageBounds.y = bounds.y + relativeControlLocation.y + 11;
if (control instanceof Scrollable)
{
Scrollable scrollable = (Scrollable)control;
Rectangle clientArea = scrollable.getClientArea();
imageBounds.x -= controlBounds.width - clientArea.width - 2 * border;
if (control instanceof Tree)
{
imageBounds.y += ((Tree)control).getHeaderHeight();
}
if (control instanceof Table)
{
imageBounds.y += ((Table)control).getHeaderHeight();
}
}
gc.drawImage(decoration, imageBounds.x, imageBounds.y);
}
}
gc.dispose();
}
protected Image getImage(final Control control)
{
Point size = control.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
if (control instanceof Combo)
{
Combo combo = (Combo)control;
GC gc = new GC(control);
Point textExtent = gc.textExtent(combo.getText());
size.x = textExtent.x + 30;
gc.dispose();
}
control.setSize(size);
AccessUtil.busyWait(10);
Image result = AccessUtil.capture(control);
return result;
}
protected <W extends Widget> W getWidget(T element, String key)
{
return AccessUtil.getWidget(getShell(element), key);
}
protected Image getImage(T element, String key)
{
Widget widget = AccessUtil.getWidget(getShell(element), key);
if (widget instanceof ToolItem)
{
ToolItem toolItem = (ToolItem)widget;
Image image = toolItem.getImage();
return new Image(image.getDevice(), image.getImageData());
}
if (widget instanceof Button)
{
Button button = (Button)widget;
Shell shell = button.getShell();
Color background = button.getBackground();
boolean isEnabled = button.isEnabled();
try
{
int style = button.getStyle();
if ((style & SWT.PUSH) != 0)
{
button.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_WHITE));
}
button.setEnabled(true);
AccessUtil.busyWait(1000);
return AccessUtil.capture(button);
}
finally
{
button.setBackground(background);
button.setEnabled(isEnabled);
}
}
if (widget instanceof ProgressMonitorPart)
{
ProgressMonitorPart progressMonitorPart = (ProgressMonitorPart)widget;
progressMonitorPart.setSize(170, progressMonitorPart.getSize().y);
AccessUtil.busyWait(10);
return AccessUtil.capture(progressMonitorPart);
}
if (widget instanceof Text)
{
Text text = (Text)widget;
return getImage(text);
}
if (widget instanceof Combo)
{
Combo combo = (Combo)widget;
return getImage(combo);
}
if (widget instanceof Control)
{
Control control = (Control)widget;
return AccessUtil.capture(control);
}
throw new UnsupportedOperationException("Unexpected widget " + widget);
}
protected void close(T element)
{
Shell shell = getShell(element);
shell.close();
}
/**
* @author Ed Merks
*/
public static abstract class Window<W extends org.eclipse.jface.window.Window> extends Capture<W>
{
@Override
protected Shell getShell(W window)
{
return window.getShell();
}
@Override
protected void open(W window)
{
window.open();
}
}
/**
* @author Ed Merks
*/
public static abstract class Dialog<D extends org.eclipse.swt.widgets.Dialog> extends Capture<D>
{
@Override
protected Shell getShell(D dialog)
{
return dialog.getParent();
}
@Override
protected void open(D dialog)
{
ReflectUtil.invokeMethod(ReflectUtil.getMethod(dialog.getClass(), "open"), dialog);
}
}
}