/*
* File : Utils.java
* Created : 25 sept. 2003 16:15:07
* By : Olivier
*
* Azureus - a Java Bittorrent client
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details ( see the LICENSE file ).
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.gudy.azureus2.ui.swt;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.dnd.*;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.program.Program;
import org.eclipse.swt.widgets.*;
import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.internat.MessageText;
import org.gudy.azureus2.core3.util.*;
import org.gudy.azureus2.ui.swt.mainwindow.Colors;
import org.gudy.azureus2.ui.swt.mainwindow.SWTThread;
import org.gudy.azureus2.ui.swt.mainwindow.TorrentOpener;
import org.gudy.azureus2.ui.swt.views.utils.VerticalAligner;
import com.aelitis.azureus.core.impl.AzureusCoreImpl;
import com.aelitis.azureus.ui.swt.UIFunctionsManagerSWT;
import com.aelitis.azureus.ui.swt.UIFunctionsSWT;
/**
* @author Olivier
*
*/
public class Utils {
private static final String GOOD_STRING = "(/|,jI~`gy";
public static final boolean isGTK = SWT.getPlatform().equals("gtk");
/** Some platforms expand the last column to fit the remaining width of
* the table.
*/
public static final boolean LAST_TABLECOLUMN_EXPANDS = isGTK;
/** GTK already handles alternating background for tables */
public static final boolean TABLE_GRIDLINE_IS_ALTERNATING_COLOR = isGTK;
private static final boolean DIRECT_SETCHECKED = !Constants.isOSX
|| SWT.getVersion() >= 3212;
public static final boolean SWT32_TABLEPAINT = false; //SWT.getVersion() >= 3200;
private static final boolean DEBUG_SWTEXEC = false;
private static ArrayList queue;
private static AEDiagnosticsLogger diag_logger;
static {
if (DEBUG_SWTEXEC) {
queue = new ArrayList();
diag_logger = AEDiagnostics.getLogger("swt");
diag_logger.log("\n\nSWT Logging Starts");
} else {
queue = null;
diag_logger = null;
}
}
public static void disposeComposite(Composite composite,boolean disposeSelf) {
if(composite == null || composite.isDisposed())
return;
Control[] controls = composite.getChildren();
for(int i = 0 ; i < controls.length ; i++) {
Control control = controls[i];
if(control != null && ! control.isDisposed()) {
if(control instanceof Composite) {
disposeComposite((Composite) control,true);
}
try {
control.dispose();
} catch (SWTException e) {
Debug.printStackTrace( e );
}
}
}
// It's possible that the composite was destroyed by the child
if (!composite.isDisposed() && disposeSelf)
try {
composite.dispose();
} catch (SWTException e) {
Debug.printStackTrace( e );
}
}
public static void disposeComposite(Composite composite) {
disposeComposite(composite,true);
}
/**
* Dispose of a list of SWT objects
*
* @param disposeList
*/
public static void disposeSWTObjects(List disposeList) {
disposeSWTObjects(disposeList.toArray());
disposeList.clear();
}
public static void disposeSWTObjects(Object[] disposeList) {
boolean bResourceObjectExists = SWT.getVersion() >= 3129;
for (int i = 0; i < disposeList.length; i++) {
Object o = disposeList[i];
if (o instanceof Widget && !((Widget) o).isDisposed())
((Widget) o).dispose();
else if (bResourceObjectExists && (o instanceof Resource)
&& !((Resource) o).isDisposed())
((Resource) o).dispose();
else {
try {
// For Pre-SWT 3.1
if ((o instanceof Cursor) && !((Cursor)o).isDisposed()) {
((Cursor)o).dispose();
} else if ((o instanceof Font) && !((Font)o).isDisposed()) {
((Font)o).dispose();
} else if ((o instanceof GC) && !((GC)o).isDisposed()) {
((GC)o).dispose();
} else if ((o instanceof Image) && !((Image)o).isDisposed()) {
((Image)o).dispose();
} else if ((o instanceof Region) && !((Region)o).isDisposed()) {
((Region)o).dispose(); // 3.0
} else if ((o instanceof TextLayout) && !((TextLayout)o).isDisposed()) {
((TextLayout) o).dispose(); // 3.0
}
} catch (NoClassDefFoundError e) {
// ignore
}
// Path, Pattern, Transform are all 3.1, which will be instances of
// Resource
}
}
}
/**
* Initializes the URL dialog with http://
* If a valid link is found in the clipboard, it will be inserted
* and the size (and location) of the dialog is adjusted.
* @param shell to set the dialog location if needed
* @param url the URL text control
* @param accept_magnets
*
* @author Rene Leonhardt
*/
public static void
setTextLinkFromClipboard(
final Shell shell, final Text url, boolean accept_magnets ) {
String link = getLinkFromClipboard(shell.getDisplay(),accept_magnets);
if (link != null)
url.setText(link);
}
/**
* <p>Gets an URL from the clipboard if a valid URL for downloading has been copied.</p>
* <p>The supported protocols currently are http, https, and magnet.</p>
* @param display
* @param accept_magnets
* @return first valid link from clipboard, else "http://"
*/
public static String
getLinkFromClipboard(
Display display,
boolean accept_magnets )
{
final Clipboard cb = new Clipboard(display);
final TextTransfer transfer = TextTransfer.getInstance();
String data = (String)cb.getContents(transfer);
String text = UrlUtils.parseTextForURL(data, accept_magnets);
if (text == null) {
return "http://";
}
return text;
}
public static void centreWindow(Shell shell) {
Rectangle displayArea; // area to center in
try {
displayArea = shell.getMonitor().getClientArea();
} catch (NoSuchMethodError e) {
displayArea = shell.getDisplay().getClientArea();
}
Rectangle shellRect = shell.getBounds();
if (shellRect.height > displayArea.height) {
shellRect.height = displayArea.height;
}
if (shellRect.width > displayArea.width - 50) {
shellRect.width = displayArea.width;
}
shellRect.x = displayArea.x
+ (displayArea.width - shellRect.width) / 2;
shellRect.y = displayArea.y
+ (displayArea.height - shellRect.height) / 2;
shell.setBounds(shellRect);
}
/**
* Centers a window relative to a control. That is to say, the window will be located at the center of the control.
* @param window
* @param control
*/
public static void centerWindowRelativeTo(final Shell window, final Control control)
{
final Rectangle bounds = control.getBounds();
final Point shellSize = window.getSize();
window.setLocation(
bounds.x + (bounds.width / 2) - shellSize.x / 2,
bounds.y + (bounds.height / 2) - shellSize.y / 2
);
}
public static void createTorrentDropTarget(Composite composite,
boolean bAllowShareAdd) {
try {
createDropTarget(composite, bAllowShareAdd, null);
} catch (Exception e) {
Debug.out(e);
}
}
/**
* @param control the control (usually a Shell) to add the DropTarget
* @param url the Text control where to set the link text
*
* @author Rene Leonhardt
*/
public static void createURLDropTarget(Composite composite,
Text url) {
try {
createDropTarget(composite, false, url);
} catch (Exception e) {
Debug.out(e);
}
}
private static void createDropTarget(Composite composite,
final boolean bAllowShareAdd, final Text url,
DropTargetListener dropTargetListener) {
Transfer[] transferList;
if (SWT.getVersion() >= 3107) {
transferList = new Transfer[] { HTMLTransfer.getInstance(),
URLTransfer.getInstance(), FileTransfer.getInstance(),
TextTransfer.getInstance() };
} else {
transferList = new Transfer[] { URLTransfer.getInstance(),
FileTransfer.getInstance(), TextTransfer.getInstance() };
}
final DropTarget dropTarget = new DropTarget(composite, DND.DROP_DEFAULT
| DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK | DND.DROP_TARGET_MOVE);
dropTarget.setTransfer(transferList);
dropTarget.addDropListener(dropTargetListener);
// Note: DropTarget will dipose when the parent it's on diposes
// On Windows, dropping on children moves up to parent
// On OSX, each child needs it's own drop.
if (Constants.isWindows)
return;
Control[] children = composite.getChildren();
for (int i = 0; i < children.length; i++) {
Control control = children[i];
if (!control.isDisposed()) {
if (control instanceof Composite) {
createDropTarget((Composite) control, bAllowShareAdd, url,
dropTargetListener);
} else {
final DropTarget dropTarget2 = new DropTarget(control,
DND.DROP_DEFAULT | DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK
| DND.DROP_TARGET_MOVE);
dropTarget2.setTransfer(transferList);
dropTarget2.addDropListener(dropTargetListener);
}
}
}
}
private static void createDropTarget(Composite composite,
boolean bAllowShareAdd, Text url) {
URLDropTarget target = new URLDropTarget(url, bAllowShareAdd);
createDropTarget(composite, bAllowShareAdd, url, target);
}
private static class URLDropTarget extends DropTargetAdapter {
private final Text url;
private final boolean bAllowShareAdd;
public URLDropTarget(Text url, boolean bAllowShareAdd) {
this.url = url;
this.bAllowShareAdd = bAllowShareAdd;
}
public void dropAccept(DropTargetEvent event) {
event.currentDataType = URLTransfer.pickBestType(event.dataTypes,
event.currentDataType);
}
public void dragOver(DropTargetEvent event) {
// skip setting detail if user is forcing a drop type (ex. via the
// ctrl key), providing that the operation is valid
if (event.detail != DND.DROP_DEFAULT
&& ((event.operations & event.detail) > 0))
return;
if ((event.operations & DND.DROP_LINK) > 0)
event.detail = DND.DROP_LINK;
else if ((event.operations & DND.DROP_DEFAULT) > 0)
event.detail = DND.DROP_DEFAULT;
else if ((event.operations & DND.DROP_COPY) > 0)
event.detail = DND.DROP_COPY;
}
public void drop(DropTargetEvent event) {
if (url == null || url.isDisposed()) {
TorrentOpener.openDroppedTorrents(AzureusCoreImpl.getSingleton(),
event, bAllowShareAdd);
} else {
if (event.data instanceof URLTransfer.URLType) {
if (((URLTransfer.URLType) event.data).linkURL != null)
url.setText(((URLTransfer.URLType) event.data).linkURL);
} else if (event.data instanceof String) {
String sURL = UrlUtils.parseTextForURL((String) event.data, true);
if (sURL != null) {
url.setText(sURL);
}
}
}
}
}
/**
* Force label to use more vertical space if wrapped and in a GridLayout
* Place this listener on the _parent_ of the label
* See Eclipse SWT Bug #9866 (GridLayout does not handle wrapped Label properly)
* This workaround only works for labels who:
* - horizontally span their whole parent
* (ie. the parent has 3 columns, the label must span 3 columns)
* - GridData style has GridData.FILL_HORIZONTAL
* - Label style has SWT.WRAP
*
* @author TuxPaper
* @note Bug 9866 fixed in 3105 and later
*/
public static class LabelWrapControlListener extends ControlAdapter{
public void controlResized(ControlEvent e){
if (SWT.getVersion() >= 3105)
return;
Composite parent = (Composite)e.widget;
Control children[] = parent.getChildren();
if (children.length > 0) {
GridLayout parentLayout = (GridLayout)parent.getLayout();
if (parentLayout != null) {
Point size;
int marginWidth = parentLayout.marginWidth;
Composite grandParent = parent.getParent();
if (grandParent instanceof ScrolledComposite) {
Composite greatGP = grandParent.getParent();
if (greatGP != null) {
size = greatGP.getSize();
if (greatGP.getLayout() instanceof GridLayout) {
marginWidth += ((GridLayout)greatGP.getLayout()).marginWidth;
}
} else {
// not tested
size = grandParent.getSize();
}
if (grandParent.getLayout() instanceof GridLayout) {
marginWidth += ((GridLayout)grandParent.getLayout()).marginWidth;
}
ScrollBar sb = grandParent.getVerticalBar();
if (sb != null) {
// I don't know why, but we have to remove one
size.x -= sb.getSize().x + 1;
}
} else
size = parent.getSize();
boolean oneChanged = false;
for (int i = 0; i < children.length; i++) {
if ((children[i] instanceof Label) &&
(children[i].getStyle() & SWT.WRAP) == SWT.WRAP) {
GridData gd = (GridData)children[i].getLayoutData();
if (gd != null &&
gd.horizontalAlignment == GridData.FILL) {
if (gd.horizontalSpan == parentLayout.numColumns) {
gd.widthHint = size.x - 2 * marginWidth;
oneChanged = true;
} else {
Point pt = children[i].getLocation();
gd.widthHint = size.x - pt.x - (2 * marginWidth);
oneChanged = true;
}
}
}
}
if (oneChanged) {
parent.layout(true);
if (grandParent instanceof ScrolledComposite) {
((ScrolledComposite)grandParent).setMinSize(parent.computeSize(SWT.DEFAULT, SWT.DEFAULT, true));
}
}
}
} // size
} // controlResized
} // class
public static void alternateRowBackground(TableItem item) {
if (Utils.TABLE_GRIDLINE_IS_ALTERNATING_COLOR) {
if (!item.getParent().getLinesVisible())
item.getParent().setLinesVisible(true);
return;
}
if (item == null || item.isDisposed())
return;
Color[] colors = { item.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND),
Colors.colorAltRow };
Color newColor = colors[ item.getParent().indexOf(item) % colors.length];
if (!item.getBackground().equals(newColor)) {
item.setBackground(newColor);
}
}
public static void alternateTableBackground(Table table) {
if (table == null || table.isDisposed())
return;
if (Utils.TABLE_GRIDLINE_IS_ALTERNATING_COLOR) {
if (!table.getLinesVisible())
table.setLinesVisible(true);
return;
}
int iTopIndex = table.getTopIndex();
int iBottomIndex = getTableBottomIndex(table, iTopIndex);
Color[] colors = { table.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND),
Colors.colorAltRow };
int iFixedIndex = iTopIndex;
for (int i = iTopIndex; i <= iBottomIndex; i++) {
TableItem row = table.getItem(i);
// Rows can be disposed!
if (!row.isDisposed()) {
Color newColor = colors[iFixedIndex % colors.length];
iFixedIndex++;
if (!row.getBackground().equals(newColor)) {
// System.out.println("setting "+rows[i].getBackground() +" to " + newColor);
row.setBackground(newColor);
}
}
}
}
/**
* <p>
* Set a MenuItem's image with the given ImageRepository key. In compliance with platform
* human interface guidelines, the images are not set under Mac OS X.
* </p>
* @param item SWT MenuItem
* @param repoKey ImageRepository image key
* @see <a href="http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGMenus/chapter_7_section_3.html#//apple_ref/doc/uid/TP30000356/TPXREF116">Apple HIG</a>
*/
public static void setMenuItemImage(final MenuItem item, final String repoKey)
{
if(!Constants.isOSX)
item.setImage(ImageRepository.getImage(repoKey));
}
public static void setMenuItemImage(final MenuItem item, final Image image)
{
if(!Constants.isOSX)
item.setImage(image);
}
/**
* Sets the shell's Icon(s) to the default Azureus icon. OSX doesn't require
* an icon, so they are skipped
*
* @param shell
*/
public static void setShellIcon(Shell shell) {
final String[] sImageNames = { "azureus", "azureus32", "azureus64",
"azureus128" };
if (Constants.isOSX)
return;
try {
ArrayList list = new ArrayList();
Image[] images = new Image[] { ImageRepository.getImage("azureus"),
ImageRepository.getImage("azureus32"),
ImageRepository.getImage("azureus64"),
ImageRepository.getImage("azureus128") };
for (int i = 0; i < images.length; i++) {
Image image = ImageRepository.getImage(sImageNames[i]);
if (image != null)
list.add(image);
}
if (list.size() == 0)
return;
shell.setImages((Image[]) list.toArray(new Image[0]));
} catch (NoSuchMethodError e) {
// SWT < 3.0
Image image = ImageRepository.getImage(sImageNames[0]);
if (image != null)
shell.setImage(image);
}
}
/**
* Execute code in the Runnable object using SWT's thread. If current
* thread it already SWT's thread, the code will run immediately. If the
* current thread is not SWT's, code will be run either synchronously or
* asynchronously on SWT's thread at the next reasonable opportunity.
*
* This method does not catch any exceptions.
*
* @param code code to run
* @param async true if SWT asyncExec, false if SWT syncExec
* @return success
*/
public static boolean execSWTThread(final Runnable code,
boolean async) {
SWTThread swt = SWTThread.getInstance();
Display display;
if (swt == null) {
display = Display.getDefault();
if (display == null) {
System.err.println("SWT Thread not started yet!");
return false;
}
} else {
if (swt.isTerminated()) {
return false;
}
display = swt.getDisplay();
}
if (display == null || display.isDisposed() || code == null)
return false;
if (display.getThread() == Thread.currentThread()) {
if (queue == null) {
code.run();
} else {
long lStartTimeRun = SystemTime.getCurrentTime();
code.run();
long wait = SystemTime.getCurrentTime() - lStartTimeRun;
if (wait > 700) {
diag_logger.log(SystemTime.getCurrentTime() + "] took " + wait
+ "ms to run " + Debug.getCompressedStackTrace(4));
}
}
} else if (async) {
try {
if (queue == null) {
display.asyncExec(code);
} else {
queue.add(code);
diag_logger.log(SystemTime.getCurrentTime() + "] + QUEUE. size= "
+ queue.size() + "; add " + code + " via "
+ Debug.getCompressedStackTrace(4));
final long lStart = SystemTime.getCurrentTime();
final Display fDisplay = display;
display.asyncExec(new AERunnable() {
public void runSupport() {
long wait = SystemTime.getCurrentTime() - lStart;
if (wait > 700) {
diag_logger.log(SystemTime.getCurrentTime() + "] took " + wait
+ "ms before SWT ran async code " + code);
}
long lStartTimeRun = SystemTime.getCurrentTime();
if (fDisplay.isDisposed()) {
Debug.out("Display disposed while trying to execSWTThread "
+ code);
// run anayway, except trap SWT error
try {
code.run();
} catch (SWTException e) {
Debug.out("Error while execSWTThread w/disposed Display", e);
}
} else {
code.run();
}
wait = SystemTime.getCurrentTime() - lStartTimeRun;
if (wait > 500) {
diag_logger.log(SystemTime.getCurrentTime() + "] took " + wait
+ "ms to run " + code);
}
diag_logger.log(SystemTime.getCurrentTime()
+ "] - QUEUE. size=" + queue.size());
queue.remove(code);
}
});
}
} catch (NullPointerException e) {
// If the display is being disposed of, asyncExec may give a null
// pointer error
return false;
}
} else {
display.syncExec(code);
}
return true;
}
/**
* Execute code in the Runnable object using SWT's thread. If current
* thread it already SWT's thread, the code will run immediately. If the
* current thread is not SWT's, code will be run asynchronously on SWT's
* thread at the next reasonable opportunity.
*
* This method does not catch any exceptions.
*
* @param code code to run
* @return success
*/
public static boolean execSWTThread(Runnable code) {
return execSWTThread(code, true);
}
public static boolean isThisThreadSWT() {
SWTThread swt = SWTThread.getInstance();
if (swt == null) {
System.err.println("SWT Thread not started yet");
return false;
}
Display display = swt.getDisplay();
if (display == null || display.isDisposed())
return false;
return (display.getThread() == Thread.currentThread());
}
/** Open a messagebox using resource keys for title/text
*
* @param parent Parent shell for messagebox
* @param style SWT styles for messagebox
* @param keyPrefix message bundle key prefix used to get title and text.
* Title will be keyPrefix + ".title", and text will be set to
* keyPrefix + ".text"
* @param textParams any parameters for text
*
* @return what the messagebox returns
*/
public static int openMessageBox(Shell parent, int style, String keyPrefix,
String[] textParams) {
MessageBox mb = new MessageBox(parent, style);
mb.setMessage(MessageText.getString(keyPrefix + ".text", textParams));
mb.setText(MessageText.getString(keyPrefix + ".title"));
return mb.open();
}
/** Open a messagebox with actual title and text
*
* @param parent
* @param style
* @param title
* @param text
* @return
*/
public static int openMessageBox(Shell parent, int style, String title,
String text) {
MessageBox mb = new MessageBox(parent, style);
mb.setMessage(text);
mb.setText(title);
return mb.open();
}
/**
* Bottom Index may be negative
*/
public static int getTableBottomIndex(Table table, int iTopIndex) {
// on Linux, getItemHeight is slow AND WRONG. so is getItem(x).getBounds().y
// getItem(Point) is slow on OSX
int itemCount = table.getItemCount();
if (!table.isVisible() || iTopIndex >= itemCount)
return -1;
if (Constants.isOSX) {
try {
TableItem item = table.getItem(iTopIndex);
Rectangle bounds = item.getBounds();
Rectangle clientArea = table.getClientArea();
int itemHeight = table.getItemHeight();
int iBottomIndex = Math.min(iTopIndex
+ (clientArea.height + clientArea.y - bounds.y - 1) / itemHeight,
itemCount - 1);
// System.out.println(bounds + ";" + clientArea + ";" + itemHeight + ";bi="
// + iBottomIndex + ";ti=" + iTopIndex + ";"
// + (clientArea.height + clientArea.y - bounds.y - 1));
return iBottomIndex;
} catch (NoSuchMethodError e) {
// item.getBounds is 3.2
return Math.min(iTopIndex
+ ((table.getClientArea().height - table.getHeaderHeight() - 1) /
table.getItemHeight()) + 1, table.getItemCount() - 1);
}
}
// getItem will return null if clientArea's height is smaller than
// header height.
int areaHeight = table.getClientArea().height;
if (areaHeight <= table.getHeaderHeight())
return -1;
// 2 offset to be on the safe side
TableItem bottomItem = table.getItem(new Point(2,
table.getClientArea().height - 1));
int iBottomIndex = (bottomItem != null) ? table.indexOf(bottomItem) :
itemCount - 1;
return iBottomIndex;
}
public static void launch(String sFile) {
if (sFile == null) {
return;
}
if (SWT.getVersion() >= 3315 || SWT.getVersion() < 3300
|| UrlUtils.isURL(sFile) || sFile.startsWith("mailto:")) {
Program.launch(sFile);
} else {
if (Constants.isOSX) {
Program.launch("file://" + sFile.replaceAll(" ", "%20"));
} else {
Program.launch(sFile);
}
}
}
/**
* Sets the checkbox in a Virtual Table while inside a SWT.SetData listener
* trigger. SWT 3.1 has an OSX bug that needs working around.
*
* @param item
* @param checked
*/
public static void setCheckedInSetData(final TableItem item,
final boolean checked) {
if (DIRECT_SETCHECKED) {
item.setChecked(checked);
} else {
item.setChecked(!checked);
item.getDisplay().asyncExec(new AERunnable() {
public void runSupport() {
item.setChecked(checked);
}
});
}
if (Constants.isWindowsXP || isGTK) {
Rectangle r = item.getBounds(0);
Table table = item.getParent();
Rectangle rTable = table.getClientArea();
r.y += VerticalAligner.getTableAdjustVerticalBy(table);
table.redraw(0, r.y, rTable.width, r.height, true);
}
}
public static boolean linkShellMetricsToConfig(final Shell shell,
final String sConfigPrefix) {
String windowRectangle = COConfigurationManager.getStringParameter(
sConfigPrefix + ".rectangle", null);
boolean bDidResize = false;
if (null != windowRectangle) {
int i = 0;
int[] values = new int[4];
StringTokenizer st = new StringTokenizer(windowRectangle, ",");
try {
while (st.hasMoreTokens() && i < 4) {
values[i++] = Integer.valueOf(st.nextToken()).intValue();
}
if (i == 4) {
Rectangle shellBounds = new Rectangle(values[0], values[1],
values[2], values[3]);
shell.setBounds(shellBounds);
verifyShellRect(shell, true);
bDidResize = true;
}
} catch (Exception e) {
}
}
boolean isMaximized = COConfigurationManager.getBooleanParameter(
sConfigPrefix + ".maximized") && !Constants.isOSX;
shell.setMaximized(isMaximized);
new ShellMetricsResizeListener(shell, sConfigPrefix);
return bDidResize;
}
private static class ShellMetricsResizeListener implements Listener {
private int state = -1;
private String sConfigPrefix;
private Rectangle bounds = null;
ShellMetricsResizeListener(Shell shell, String sConfigPrefix) {
this.sConfigPrefix = sConfigPrefix;
state = calcState(shell);
if (state == SWT.NONE)
bounds = shell.getBounds();
shell.addListener(SWT.Resize, this);
shell.addListener(SWT.Move, this);
shell.addListener(SWT.Dispose, this);
}
private int calcState(Shell shell) {
return shell.getMinimized() ? SWT.MIN : shell.getMaximized()
&& !Constants.isOSX ? SWT.MAX : SWT.NONE;
}
private void saveMetrics() {
COConfigurationManager.setParameter(sConfigPrefix + ".maximized",
state == SWT.MAX);
if (bounds == null)
return;
COConfigurationManager.setParameter(sConfigPrefix + ".rectangle",
bounds.x + "," + bounds.y + "," + bounds.width + "," + bounds.height);
}
public void handleEvent(Event event) {
Shell shell = (Shell) event.widget;
state = calcState(shell);
if (event.type != SWT.Dispose && state == SWT.NONE)
bounds = shell.getBounds();
if (event.type == SWT.Dispose)
saveMetrics();
}
}
public static GridData setGridData(Composite composite, int gridStyle,
Control ctrlBestSize, int maxHeight) {
GridData gridData = new GridData(gridStyle);
gridData.heightHint = ctrlBestSize.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
if (gridData.heightHint > maxHeight && maxHeight > 0)
gridData.heightHint = maxHeight;
composite.setLayoutData(gridData);
return gridData;
}
public static FormData getFilledFormData() {
FormData formData = new FormData();
formData.top = new FormAttachment(0, 0);
formData.left = new FormAttachment(0, 0);
formData.right = new FormAttachment(100, 0);
formData.bottom = new FormAttachment(100, 0);
return formData;
}
public static int pixelsToPoint(int pixels, int dpi) {
int ret = (int) Math.round((pixels * 72.0) / dpi);
return ret;
}
public static int pixelsToPoint(double pixels, int dpi) {
int ret = (int) Math.round((pixels * 72.0) / dpi);
return ret;
}
public static boolean drawImage(GC gc, Image image, Rectangle dstRect,
Rectangle clipping, int hOffset, int vOffset, boolean clearArea)
{
return drawImage(gc, image, new Point(0, 0), dstRect, clipping, hOffset,
vOffset, clearArea);
}
public static boolean drawImage(GC gc, Image image, Rectangle dstRect,
Rectangle clipping, int hOffset, int vOffset)
{
return drawImage(gc, image, new Point(0, 0), dstRect, clipping, hOffset,
vOffset, false);
}
public static boolean drawImage(GC gc, Image image, Point srcStart,
Rectangle dstRect, Rectangle clipping, int hOffset, int vOffset,
boolean clearArea)
{
Rectangle srcRect;
Point dstAdj;
if (clipping == null) {
dstAdj = new Point(0, 0);
srcRect = new Rectangle(srcStart.x, srcStart.y, dstRect.width,
dstRect.height);
} else {
if (!dstRect.intersects(clipping)) {
return false;
}
dstAdj = new Point(Math.max(0, clipping.x - dstRect.x), Math.max(0,
clipping.y - dstRect.y));
srcRect = new Rectangle(0, 0, 0, 0);
srcRect.x = srcStart.x + dstAdj.x;
srcRect.y = srcStart.y + dstAdj.y;
srcRect.width = Math.min(dstRect.width - dstAdj.x, clipping.x
+ clipping.width - dstRect.x);
srcRect.height = Math.min(dstRect.height - dstAdj.y, clipping.y
+ clipping.height - dstRect.y);
}
if (!srcRect.isEmpty()) {
try {
if (clearArea) {
gc.fillRectangle(dstRect.x + dstAdj.x + hOffset, dstRect.y + dstAdj.y
+ vOffset, srcRect.width, srcRect.height);
}
gc.drawImage(image, srcRect.x, srcRect.y, srcRect.width,
srcRect.height, dstRect.x + dstAdj.x + hOffset, dstRect.y
+ dstAdj.y + vOffset, srcRect.width, srcRect.height);
} catch (Exception e) {
System.out.println("drawImage: " + e.getMessage() + ": " + image + ", " + srcRect
+ ", " + (dstRect.x + dstAdj.y + hOffset) + ","
+ (dstRect.y + dstAdj.y + vOffset) + "," + srcRect.width + ","
+ srcRect.height + "; imageBounds = " + image.getBounds());
}
}
return true;
}
/**
* @param area
* @param event id
* @param listener
*/
public static void addListenerAndChildren(Composite area, int event,
Listener listener)
{
area.addListener(event, listener);
Control[] children = area.getChildren();
for (int i = 0; i < children.length; i++) {
Control child = children[i];
if (child instanceof Composite) {
addListenerAndChildren((Composite)child, event, listener);
} else {
child.addListener(event, listener);
}
}
}
public static Shell findAnyShell() {
// Pick the main shell if we can
UIFunctionsSWT uiFunctions = UIFunctionsManagerSWT.getUIFunctionsSWT();
if (uiFunctions != null) {
Shell shell = uiFunctions.getMainShell();
if (shell != null && !shell.isDisposed()) {
return shell;
}
}
// Get active shell from current display if we can
Display current = Display.getCurrent();
if (current == null) {
return null;
}
Shell shell = current.getActiveShell();
if (shell != null && !shell.isDisposed()) {
return shell;
}
// Get first shell of current display if we can
Shell[] shells = current.getShells();
if (shells.length == 0) {
return null;
}
if (shells[0] != null && !shells[0].isDisposed()) {
return shells[0];
}
return null;
}
/**
* @param listener
*/
public static boolean verifyShellRect(Shell shell, boolean bAdjustIfInvalid) {
boolean bMetricsOk;
try {
bMetricsOk = false;
Point ptTopLeft = shell.getLocation();
Monitor[] monitors = shell.getDisplay().getMonitors();
for (int j = 0; j < monitors.length && !bMetricsOk; j++) {
Rectangle bounds = monitors[j].getBounds();
bMetricsOk = bounds.contains(ptTopLeft);
}
} catch (NoSuchMethodError e) {
Rectangle bounds = shell.getDisplay().getBounds();
bMetricsOk = shell.getBounds().intersects(bounds);
}
if (!bMetricsOk && bAdjustIfInvalid) {
centreWindow(shell);
}
return bMetricsOk;
}
/**
* Relayout all composites up from control until there's enough room for the
* control to fit
*
* @param control Control that had it's sized changed and needs more room
*/
public static void relayout(Control control) {
relayout(control, false);
}
/**
* Relayout all composites up from control until there's enough room for the
* control to fit
*
* @param control Control that had it's sized changed and needs more room
*/
public static void relayout(Control control, boolean expandOnly) {
if (control == null || control.isDisposed()) {
return;
}
Composite parent = control.getParent();
Point targetSize = control.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
Point size = control.getSize();
if (size.y == targetSize.y && size.x == targetSize.x) {
return;
}
if (expandOnly && size.y >= targetSize.y && size.x >= targetSize.x) {
parent.layout();
return;
}
while (parent != null) {
parent.layout(true, true);
parent = parent.getParent();
Point newSize = control.getSize();
//System.out.println("new=" + newSize + ";target=" + targetSize);
if (newSize.y >= targetSize.y && newSize.x >= targetSize.x) {
break;
}
}
if (parent != null) {
parent.layout();
}
}
/**
*
*/
public static void beep() {
execSWTThread(new AERunnable() {
public void runSupport() {
Display display = Display.getDefault();
if (display != null) {
display.beep();
}
}
});
}
/**
*
* @param baseFont
* @param gc Can be null
* @param heightInPixels
* @return
*
* @since 3.0.0.7
*/
public static int getFontHeightFromPX(Font baseFont, GC gc, int heightInPixels) {
Font font = null;
Device device = baseFont.getDevice();
// hack..
heightInPixels++;
// This isn't accurate, but gets us close
int size = Utils.pixelsToPoint(heightInPixels, device.getDPI().y) + 1;
if (size <= 0) {
return 0;
}
boolean bOurGC = gc == null || gc.isDisposed();
try {
if (bOurGC) {
gc = new GC(device);
}
FontData[] fontData = baseFont.getFontData();
do {
if (font != null) {
size--;
font.dispose();
}
fontData[0].setHeight(size);
font = new Font(device, fontData);
gc.setFont(font);
} while (font != null && gc.textExtent(GOOD_STRING).y > heightInPixels
&& size > 1);
} finally {
if (bOurGC) {
gc.dispose();
}
}
return size;
}
public static int getFontHeightFromPX(Device device, FontData[] fontData,
GC gc, int heightInPixels) {
Font font = null;
// hack..
heightInPixels++;
// This isn't accurate, but gets us close
int size = Utils.pixelsToPoint(heightInPixels, device.getDPI().y) + 1;
if (size <= 0) {
return 0;
}
boolean bOurGC = gc == null || gc.isDisposed();
try {
if (bOurGC) {
gc = new GC(device);
}
do {
if (font != null) {
size--;
font.dispose();
}
fontData[0].setHeight(size);
font = new Font(device, fontData);
gc.setFont(font);
} while (font != null && gc.textExtent(GOOD_STRING).y > heightInPixels
&& size > 1);
} finally {
if (bOurGC) {
gc.dispose();
}
}
return size;
}
public static Font getFontWithHeight(Font baseFont, GC gc, int heightInPixels) {
Font font = null;
Device device = baseFont.getDevice();
// hack..
heightInPixels++;
// This isn't accurate, but gets us close
int size = Utils.pixelsToPoint(heightInPixels, device.getDPI().y) + 1;
if (size <= 0) {
size = 2;
}
boolean bOurGC = gc == null || gc.isDisposed();
try {
if (bOurGC) {
gc = new GC(device);
}
FontData[] fontData = baseFont.getFontData();
do {
if (font != null) {
size--;
font.dispose();
}
fontData[0].setHeight(size);
font = new Font(device, fontData);
gc.setFont(font);
} while (font != null && gc.textExtent(GOOD_STRING).y > heightInPixels
&& size > 1);
} finally {
if (bOurGC) {
gc.dispose();
}
}
return font;
}
public static boolean execSWTThreadWithBool(String ID,
AERunnableBoolean code) {
return execSWTThreadWithBool(ID, code, 0);
}
public static boolean execSWTThreadWithBool(String ID,
AERunnableBoolean code, long millis) {
if (code == null) {
return false;
}
final AESemaphore sem = new AESemaphore(ID);
boolean[] returnValueObject = { false };
try{
code.setupReturn(ID, returnValueObject, sem);
if (!execSWTThread(code)) {
// code never got run
// XXX: throw instead?
return false;
}
}catch( Throwable e ){
Debug.out(ID, e);
sem.release();
}
sem.reserve(millis);
return returnValueObject[0];
}
public static Object execSWTThreadWithObject(String ID,
AERunnableObject code) {
return execSWTThreadWithObject(ID, code, 0);
}
public static Object execSWTThreadWithObject(String ID,
AERunnableObject code, long millis) {
if (code == null) {
return null;
}
final AESemaphore sem = new AESemaphore(ID);
Object[] returnValueObject = { null };
try{
code.setupReturn(ID, returnValueObject, sem);
if (!execSWTThread(code)) {
// XXX: throw instead?
return null;
}
}catch( Throwable e ){
Debug.out(ID, e);
sem.release();
}
sem.reserve(millis);
return returnValueObject[0];
}
/**
* Waits until modal dialogs are disposed. Assumes we are one SWT thread
*
* @since 3.0.1.3
*/
public static void waitForModals() {
SWTThread swt = SWTThread.getInstance();
Display display;
if (swt == null) {
display = Display.getDefault();
if (display == null) {
System.err.println("SWT Thread not started yet!");
return;
}
} else {
if (swt.isTerminated()) {
return;
}
display = swt.getDisplay();
}
if (display == null || display.isDisposed()) {
return;
}
Shell[] shells = display.getShells();
Shell modalShell = null;
for (int i = 0; i < shells.length; i++) {
Shell shell = shells[i];
if ((shell.getStyle() & SWT.APPLICATION_MODAL) > 0) {
modalShell = shell;
break;
}
}
if (modalShell != null) {
while (!modalShell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
}
public static GridData getWrappableLabelGridData(int hspan, int styles) {
GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | styles);
gridData.horizontalSpan = hspan;
gridData.widthHint = 0;
return gridData;
}
}
|