/*******************************************************************************
* Copyright (c) 2005-2010, G. Weirich and Elexis
* 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:
* G. Weirich - initial implementation
*
*******************************************************************************/
package ch.elexis.core.ui.util;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
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.Layout;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.events.IHyperlinkListener;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.TableWrapData;
import org.eclipse.ui.forms.widgets.TableWrapLayout;
import org.eclipse.ui.statushandlers.StatusManager;
import ch.elexis.core.ui.Hub;
import ch.elexis.core.ui.UiDesk;
import ch.rgw.tools.StringTool;
/** statische Hilfsfunktionen für SWT-Objekte */
public class SWTHelper {
/**
* Singleton-Variable, die einen FocusListener enthaelt, der in einem Text-Control den Text
* selektiert, wenn das Control den Focus erhaelt. Siehe setSelectOnFocus().
*/
private static FocusListener selectOnFocusListener = null;
private static Log log = Log.get("Global: "); //$NON-NLS-1$
/** Ein Objekt innerhalb des parents zentrieren */
public static void center(final Shell parent, final Composite child){
if (parent != null && child != null) {
Rectangle par = parent.getBounds();
Rectangle ch = child.getBounds();
if (par != null && ch != null) {
int xOff = (par.width - ch.width) / 2;
int yOff = (par.height - ch.height) / 2;
child.setBounds(par.x + xOff, par.y + yOff, ch.width, ch.height);
}
}
}
/** Ein Objekt innerhalb des parents zentrieren */
public static void center(final Shell parent, final Shell child){
if (parent != null && child != null) {
Rectangle par = parent.getBounds();
Rectangle ch = child.getBounds();
if (par != null && ch != null) {
int xOff = (par.width - ch.width) / 2;
int yOff = (par.height - ch.height) / 2;
child.setBounds(par.x + xOff, par.y + yOff, ch.width, ch.height);
}
}
}
/**
* Ein Objekt auf dem Bildschirm zentrieren. Robust. Sollte nie eine Exception werfen. Ändert im
* Zweifelsfall nichts an der Position.
* */
public static void center(final Shell child){
if (child != null) {
Display display = UiDesk.getDisplay();
if (display != null) {
Rectangle par = display.getBounds();
if (par != null) {
Rectangle ch = child.getBounds();
if (ch != null) {
ch.width = Math.max(30, ch.width);
ch.height = Math.max(20, ch.height);
int xOff = (par.width - ch.width) / 2;
int yOff = (par.height - ch.height) / 2;
child.setBounds(par.x + xOff, par.y + yOff, ch.width, ch.height);
}
}
}
}
}
/** Einen Text zentriert in ein Rechteck schreiben */
public static void writeCentered(final GC gc, final String text, final Rectangle bounds){
int w = gc.getFontMetrics().getAverageCharWidth();
int h = gc.getFontMetrics().getHeight();
int woff = (bounds.width - text.length() * w) >> 1;
int hoff = (bounds.height - h) >> 1;
gc.drawString(text, bounds.x + woff, bounds.y + hoff);
}
/** Eine Alertbox anzeigen (synchron) */
public static void alert(final String title, final String message){
UiDesk.getDisplay().syncExec(new Runnable() {
public void run(){
Shell shell = UiDesk.getDisplay().getActiveShell();
if (shell == null) {
shell = new Shell(UiDesk.getDisplay());
}
MessageBox msg = new MessageBox(shell, SWT.ICON_ERROR | SWT.OK);
msg.setText(title);
msg.setMessage(message);
msg.open();
}
});
}
/**
* Eine Standard-Fehlermeldung asynchron im UI-Thread zeigen
*
* @param title
* Titel
* @param message
* Nachricht
*/
public static void showError(final String title, final String message){
UiDesk.getDisplay().syncExec(new Runnable() {
public void run(){
Shell shell = UiDesk.getTopShell();
MessageDialog.openError(shell, title, message);
}
});
}
/**
* Eine Standard-Fehlermeldung asynchron zeigen und loggen
*
* @param title
* Titel
* @param message
* Nachricht
*/
public static void showError(final String logHeader, final String title, final String message){
log.log(logHeader + ": " + title + "->" + message, Log.ERRORS); //$NON-NLS-1$ //$NON-NLS-2$
UiDesk.getDisplay().syncExec(new Runnable() {
public void run(){
Shell shell = UiDesk.getDisplay().getActiveShell();
MessageDialog.openError(shell, title, message);
}
});
}
/**
* Eine Standard-Infomeldung asynchron zeigen
*
* @param title
* Titel
* @param message
* Nachricht
*/
public static void showInfo(final String title, final String message){
UiDesk.getDisplay().syncExec(new Runnable() {
public void run(){
Shell shell = UiDesk.getTopShell();
MessageDialog.openInformation(shell, title, message);
}
});
}
/**
* Eine mit Ja oder Nein zu beantwortende Frage im UI-Thread zeigen
*
* @param title
* Titel
* @param message
* Nachricht
* @return true: User hat Ja geklickt
*/
public static boolean askYesNo(final String title, final String message){
InSync rn = new InSync(title, message);
UiDesk.getDisplay().syncExec(rn);
return rn.ret;
}
private static class InSync implements Runnable {
boolean ret;
String title, message;
InSync(final String title, final String message){
this.title = title;
this.message = message;
}
public void run(){
Shell shell = UiDesk.getTopShell();
ret = MessageDialog.openConfirm(shell, title, message);
}
}
/**
* Eine mit Ja, Nein oder Abbrechen zu beantwortende Frage im UI-Thread zeigen
*
* @param title
* Titel
* @param message
* Nachricht
* @return true: User hat Ja geklickt
*/
public static Boolean askYesNoCancel(final String title, final String message){
InSyncYesNoCancel rn = new InSyncYesNoCancel(title, message);
UiDesk.getDisplay().syncExec(rn);
return rn.ret;
}
private static class InSyncYesNoCancel implements Runnable {
Boolean ret = null;
String title, message;
InSyncYesNoCancel(final String title, final String message){
this.title = title;
this.message = message;
}
public void run(){
Shell shell = UiDesk.getTopShell();
MessageDialog dialog = new MessageDialog(shell, title, null, // accept
// the
// default
// window
// icon
message, MessageDialog.QUESTION, new String[] {
Messages.SWTHelper_yes, Messages.SWTHelper_no, //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
Messages.SWTHelper_cancel
}, 0);
// ok is the default
int result = dialog.open();
if (result != 2) {
ret = result == 0;
}
}
}
/**
* Shortcut for getFillGridData(1,true,1,true);
*
* @return
*/
public static GridData getFillGridData(){
return getFillGridData(1, true, 1, true);
}
/**
* Ein GridData-Objekt erzeugen, das den horizontalen und/oder vertikalen Freiraum ausfüllt.
*
* @param horizontal
* true, wenn horizontal gefüllt werden soll
* @param vertical
* true, wenn vertikal gefüllt werden soll.
* @return ein neu erzeugtes, direkt verwendbares GridData-Objekt
*/
public static GridData getFillGridData(final int hSpan, final boolean hFill, final int vSpan,
final boolean vFill){
int ld = 0;
if (hFill) {
ld = GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL;
}
if (vFill) {
ld |= GridData.FILL_VERTICAL | GridData.GRAB_VERTICAL;
}
GridData ret = new GridData(ld);
ret.horizontalSpan = (hSpan < 1) ? 1 : hSpan;
ret.verticalSpan = vSpan < 1 ? 1 : vSpan;
return ret;
}
public static GridData fillGrid(final Composite parent, final int cols){
parent.setLayout(new GridLayout(cols, false));
return getFillGridData(1, true, 1, true);
}
/**
* Set a GridData to the given Control that sets the specified height in lines calculated with
* the control's current font.
*
* @param control
* the control
* @param lines
* reuqested height of the control in lines
* @param fillHorizontal
* true if the control should require all horizontal space
* @return the GridData (that is already set to the control)
*/
public static GridData setGridDataHeight(final Control control, final int lines,
final boolean fillHorizontal){
int h = Math.round(control.getFont().getFontData()[0].height);
GridData gd = getFillGridData(1, fillHorizontal, 1, false);
gd.heightHint = lines * (h + 2);
control.setLayoutData(gd);
return gd;
}
/**
* Constructor wrapper for TableWrapLayout, so that parameters are identical to
* GridLayout(numColumns, makeColumnsEqualWidth)
*/
public static TableWrapLayout createTableWrapLayout(final int numColumns,
final boolean makeColumnsEqualWidth){
TableWrapLayout layout = new TableWrapLayout();
layout.numColumns = numColumns;
layout.makeColumnsEqualWidth = makeColumnsEqualWidth;
return layout;
}
/**
* Ein TableWrapDAta-Objekt erzeugen, das den horizontalen und/oder vertikalen Freiraum
* ausfüllt.
*
* @param horizontal
* true, wenn horizontal gefüllt werden soll
* @param vertical
* true, wenn vertikal gefüllt werden soll.
* @return ein neu erzeugtes, direkt verwendbares GridData-Objekt
*/
public static TableWrapData getFillTableWrapData(final int hSpan, final boolean hFill,
final int vSpan, final boolean vFill){
TableWrapData layoutData = new TableWrapData(TableWrapData.LEFT, TableWrapData.TOP);
if (hFill) {
layoutData.grabHorizontal = true;
layoutData.align = TableWrapData.FILL;
}
if (vFill) {
layoutData.grabVertical = true;
layoutData.valign = TableWrapData.FILL;
}
layoutData.colspan = (hSpan < 1 ? 1 : hSpan);
layoutData.rowspan = (vSpan < 1 ? 1 : vSpan);
return layoutData;
}
/**
* Return a color that contrasts optimally to the given color
*
* @param col
* an SWT Color
* @return black if col was rather bright, white if col was rather dark.
*/
public static Color getContrast(final Color col){
double val = col.getRed() * 0.56 + col.getGreen() * 0.33 + col.getBlue() * 0.11;
if (val <= 110) {
return UiDesk.getDisplay().getSystemColor(SWT.COLOR_WHITE);
}
return UiDesk.getDisplay().getSystemColor(SWT.COLOR_BLACK);
}
/**
* Return a Label that acts as a hyperlink
*
* @param parent
* parent control
* @param text
* text to display
* @param lis
* hyperlink listener that is called on Mouse click
* @return a Label
*/
public static Label createHyperlink(final Composite parent, final String text,
final IHyperlinkListener lis){
final Label ret = new Label(parent, SWT.NONE);
ret.setText(text);
ret.setForeground(UiDesk.getColorRegistry().get(Messages.SWTHelper_blue)); //$NON-NLS-1$
ret.addMouseListener(new MouseAdapter() {
@Override
public void mouseDown(final MouseEvent e){
if (lis != null) {
lis.linkActivated(new HyperlinkEvent(ret, ret, text, e.stateMask));
}
}
});
return ret;
}
/**
* Create a multiline text widget with a specified height in lines (calculated with the Text's
* default font)
*
* @param parent
* parent composite
* @param lines
* requested height of the text field
* @param flags
* creation flags (SWT.MULTI and SWT.WRAP are added automatocally)
* @return a Text control
*/
public static Text createText(final Composite parent, final int lines, final int flags){
int lNum = SWT.SINGLE;
if (lines > 1) {
lNum = SWT.MULTI | SWT.WRAP;
}
Text ret = new Text(parent, SWT.BORDER | flags | lNum);
GridData gd = getFillGridData(1, true, 1, false);
int h = Math.round(ret.getFont().getFontData()[0].height);
gd.minimumHeight = (lines + 1) * (h + 2);
gd.heightHint = gd.minimumHeight;
ret.setLayoutData(gd);
return ret;
}
public static Text createText(final FormToolkit tk, final Composite parent, final int lines,
final int flags){
int lNum = SWT.SINGLE;
if (lines > 1) {
lNum = SWT.MULTI | SWT.WRAP;
}
Text ret = tk.createText(parent, "", lNum | flags | SWT.BORDER); //$NON-NLS-1$
GridData gd = getFillGridData(1, true, 1, true);
int h = Math.round(ret.getFont().getFontData()[0].height);
gd.minimumHeight = (lines + 1) * (h + 2);
gd.heightHint = gd.minimumHeight;
ret.setLayoutData(gd);
return ret;
}
public static LabeledInputField createLabeledField(final Composite parent, final String label,
final LabeledInputField.Typ typ){
LabeledInputField ret = new LabeledInputField(parent, label, typ);
ret.setLayoutData(SWTHelper.getFillGridData(1, true, 1, false));
return ret;
}
/**
* Check whether the String is empty and give an error message if so
*
* @param test
* the String to test
* @param name
* the name for the String
* @return false if it was empty
*/
public static boolean blameEmptyString(final String test, final String name){
if (StringTool.isNothing(test)) {
showError(Messages.SWTHelper_BadParameter, name + Messages.SWTHelper_HasNoValidContents); //$NON-NLS-1$ //$NON-NLS-2$
return false;
}
return true;
}
/**
* Adds a FocusListener to <code>text</code> so that the text is selected as soon as the control
* gets the focus. The selection is cleared when the focus is lost.
*
* @param text
* the Text control to add a focus listener to
*/
public static void setSelectOnFocus(final Text text){
if (selectOnFocusListener == null) {
selectOnFocusListener = new FocusListener() {
public void focusGained(final FocusEvent e){
Text t = (Text) e.widget;
t.selectAll();
}
public void focusLost(final FocusEvent e){
Text t = (Text) e.widget;
if (t.getSelectionCount() > 0) {
t.clearSelection();
}
}
};
}
text.addFocusListener(selectOnFocusListener);
}
public static class SimpleDialog extends Dialog {
IControlProvider dialogAreaProvider;
public SimpleDialog(final IControlProvider control){
super(UiDesk.getTopShell());
dialogAreaProvider = control;
}
@Override
protected Control createDialogArea(final Composite parent){
return dialogAreaProvider.getControl(parent);
}
@Override
protected void okPressed(){
dialogAreaProvider.beforeClosing();
super.okPressed();
}
}
public interface IControlProvider {
public Control getControl(Composite parent);
public void beforeClosing();
}
public static java.awt.Font createAWTFontFromSWTFont(final Font swtFont){
String name = swtFont.getFontData()[0].getName();
int style = swtFont.getFontData()[0].getStyle();
int height = swtFont.getFontData()[0].getHeight();
java.awt.Font awtFont = new java.awt.Font(name, style, height);
return awtFont;
}
public static int size(final Rectangle r){
if (r == null) {
return 0;
}
return (r.width - r.x) * (r.height - r.y);
}
public static Point getStringBounds(Composite c, String s){
GC gc = new GC(c);
Point ret = gc.textExtent(s);
gc.dispose();
return ret;
}
/**
* Convenience method to add a separator bar to the composite.
* <p>
* The parent composite must have a <code>GridLayout</code>. The separator bar will span all
* columns of the parent grid layout. <br>
* <br>
* Code from: http://www.softwarerevolution.com/blueprints/ The Software Revolution Inc. by
* Thomas Holland under GPLv3
* </p>
*
* @param parent
* <code>Composite</code>
*/
public static void addSeparator(Composite parent){
Label separator = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL);
Layout parentlayout = parent.getLayout();
if (parentlayout instanceof GridLayout) {
int columns = ((GridLayout) parentlayout).numColumns;
GridData gridData = new GridData(SWT.FILL, SWT.NONE, true, false, columns, 1);
separator.setLayoutData(gridData);
}
}
/**
* This method "reloads" a view, by closing and opening it. It is the programmatical equivalent
* to closing a view and then select Open/View/and the view ID.
*
* This method should NOT be used, as it identifies an architectural problem. The UI itself
* should support the respective update.
*
* @param viewID
*/
public static void reloadViewPart(String viewID){
IViewPart page =
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().findView(viewID);
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().hideView(page);
try {
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().showView(viewID);
} catch (PartInitException e) {
Status status =
new Status(IStatus.ERROR, Hub.PLUGIN_ID, "Error reopening viewPart " + viewID, e);
StatusManager.getManager().handle(status, StatusManager.SHOW);
}
}
}