| /* |
| * 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); |
| } |
| } |
| } |