summaryrefslogblamecommitdiffstats
path: root/dozentenmodul/src/main/java/org/openslx/dozmod/gui/helper/Gui.java
blob: 0868861d8039d5939632ee88c8b70786cb4d10e7 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12

                                      


                                                   






                                          

                                                                         













































































































                                                                                                        

































                                                                                                

 
package org.openslx.dozmod.gui.helper;

import java.util.concurrent.atomic.AtomicReference;

import org.apache.log4j.Logger;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Monitor;
import org.eclipse.swt.widgets.Shell;

public class Gui {
	
	private static final Logger LOGGER = Logger.getLogger(Gui.class);

	/**
	 * The one and only display to use throughout the application
	 */
	public static final Display display = new Display();

	/**
	 * Center the given shell on the {@link Monitor} it is displayed on.
	 * 
	 * @param shell Some shell
	 */
	public static void centerShell(Shell shell) {
		Monitor activeMonitor = getMonitorFromRectangle(shell.getBounds(), true);
		Rectangle bounds = activeMonitor.getClientArea();
		Rectangle rect = shell.getBounds();
		int x = bounds.x + (bounds.width - rect.width) / 2;
		int y = bounds.y + (bounds.height - rect.height) / 2;
		shell.setLocation(x, y);
	}

	/**
	 * Make sure the given shell fits the {@link Monitor} it is displayed on.
	 * 
	 * @param shell Some shell
	 */
	public static void limitShellSize(Shell shell) {
		Monitor activeMonitor = getMonitorFromRectangle(shell.getBounds(), true);
		Rectangle bounds = activeMonitor.getClientArea();
		Rectangle rect = shell.getBounds();
		boolean changed = false;
		if (rect.width + 20 > bounds.width) {
			rect.width = bounds.width - 20;
			changed = true;
		}
		if (rect.height + 20 > bounds.height) {
			rect.height = bounds.height - 20;
			changed = true;
		}
		if (changed) {
			shell.setSize(rect.width, rect.height);
			rect = shell.getBounds();
		}
		changed = false;
		if (rect.x + rect.width >= bounds.x + bounds.width) {
			rect.x = 5;
			changed = true;
		}
		if (rect.y + rect.height >= bounds.y + bounds.height) {
			rect.y = 5;
			changed = true;
		}
		if (changed) {
			shell.setLocation(rect.x, rect.y);
		}
	}

	/**
	 * Get the {@link Monitor} which the given {@link Point} lies in.
	 * 
	 * @param point The point in question
	 * @param defaultToPrimary if no monitor matches the check, return the
	 *            primary monitor if true, <code>null</code> otherwise
	 * @return the {@link Monitor}
	 */
	public static Monitor getMonitorFromPoint(Point point, boolean defaultToPrimary) {
		Monitor[] monitors = display.getMonitors();
		for (Monitor monitor : monitors) {
			Rectangle bounds = monitor.getBounds();
			if (bounds.contains(point))
				return monitor;
		}
		if (defaultToPrimary)
			return display.getPrimaryMonitor();
		return null;
	}

	/**
	 * Get the {@link Monitor} which most of the given rectangle overlaps.
	 * 
	 * @param rect The rectangle to check
	 * @param defaultToPrimary if no monitor matches the check, return the
	 *            primary monitor if true, <code>null</code> otherwise
	 * @return the {@link Monitor}
	 */
	public static Monitor getMonitorFromRectangle(Rectangle rect, boolean defaultToPrimary) {
		// Make sure rectangle is in bounds. This is not completely accurate
		// in case there are multiple monitors that have different resolutions.
		Rectangle bounds = display.getBounds();
		if (rect.x + rect.width >= bounds.x + bounds.width) {
			rect.width -= (rect.x + rect.width) - (bounds.x + bounds.width);
			if (rect.width < 1)
				rect.width = 1;
		}
		if (rect.y + rect.height >= bounds.y + bounds.height) {
			rect.height -= (rect.y + rect.height) - (bounds.y + bounds.height);
			if (rect.height < 1)
				rect.height = 1;
		}
		if (rect.x < bounds.x) {
			rect.width -= bounds.x - rect.x;
			rect.x = bounds.x;
		}
		if (rect.y < bounds.y) {
			rect.height -= bounds.y - rect.y;
			rect.y = bounds.y;
		}
		// Now just use the same code as *FromPoint by using the rectangle's center
		return getMonitorFromPoint(new Point(rect.x + rect.width / 2, rect.y + rect.height / 2),
				defaultToPrimary);
	}
	
	/**
	 * Run given task in the GUI thread, blocking the calling thread until the task is done.
	 *
	 * @param task Task to run
	 * @return return value of the task
	 */
	public static <T> T syncExec(final GuiCallable<T> task) {
		final AtomicReference<T> instance = new AtomicReference<>();
		display.syncExec(new Runnable() {
			@Override
			public void run() {
				try {
					instance.set(task.run());
				} catch (Throwable e) {
					LOGGER.warn("syncExec failed!", e);
				}
			}
		});
		return null;
	}
	
	public static void asyncExec(final Runnable task) {
		display.asyncExec(task);
	}
	
	/**
	 * Pretty much the same as Callable, but no exceptions are allowed.
	 *
	 * @param <T> return value
	 */
	public static interface GuiCallable<T> {
		T run();
	}

}