package org.eclipse.swt.widgets; // package abbot.swt; import java.lang.reflect.Method; import org.eclipse.swt.SWT; import org.eclipse.swt.SWTException; import org.eclipse.swt.custom.CTabItem; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.internal.win32.MENUBARINFO; import org.eclipse.swt.internal.win32.OS; import org.eclipse.swt.internal.win32.RECT; import abbot.tester.swt.TableItemTester; /** * This class provides workarounds for non-public SWT methods. * Note that current code only works on/for win32. * * @author gjohnsto * @version $Id: SWTWorkarounds.java,v 1.1 2005/07/25 04:13:29 tlroche Exp $ */ public class SWTWorkarounds { /** * Workaround for package scope of MenuItem.getBounds(). * Returns a rectangle describing the receiver's size and location * relative to its parent (or its display if its parent is null). * * @return the receiver's bounding rectangle * * @exception SWTException * * @since 3.1 */ public static Rectangle getBounds(MenuItem menuItem) { // start code adapted from https://bugs.eclipse.org/bugs/show_bug.cgi?id=38436#c113 Menu parent = menuItem.getParent(); Method m1 = null; try { m1 = parent.getClass().getDeclaredMethod("getBounds", null); } catch (Exception e) { return getBoundsHack(menuItem, parent); } Rectangle menuRect = null; // Avoid NPE for Eclipse 3.0 if (m1 != null) { m1.setAccessible(true); try { menuRect = (Rectangle) m1.invoke(parent, null); } catch (Exception e) { return getBoundsHack(menuItem, parent); } } else { return getBoundsHack(menuItem, parent); } Method m2 = null; try { m2 = menuItem.getClass().getDeclaredMethod("getBounds", null); } catch (Exception e) { return getBoundsHack(menuItem, parent); } m2.setAccessible(true); Rectangle itemRect = null; try { itemRect = (Rectangle) m2.invoke(menuItem, null); } catch (Exception e) { return getBoundsHack(menuItem, parent); } return translateRectangle(parent, menuRect, itemRect); // end code adapted from https://bugs.eclipse.org/bugs/show_bug.cgi?id=38436#c113 } // start code adapted from o.e.swt.patched.MenuItem.getBounds() // Menu parent = menuItem.getParent(); // Decorations parentControl = parent.getParent(); // if (OS.IsWinCE) return new Rectangle (0, 0, 0, 0); // int index = parent.indexOf (menuItem); // if (index == -1) return new Rectangle (0, 0, 0, 0); // RECT rect = new RECT(); // boolean success = OS.GetMenuItemRect(((parent.getStyle()&SWT.BAR)==SWT.BAR)?parentControl.handle:0, // parent.handle, // index, // rect); // if (!success) { // /* the OS API call couldn't get the MenuItem bounds, so return an empty rectangle */ // return new Rectangle(0, 0, 0, 0); // } // if ((parentControl.getStyle() & SWT.MIRRORED) == 0) { // /* coordinates are not mirrored */ // Point p = parentControl.toControl(rect.left,rect.top); // int width = rect.right - rect.left; // int height = rect.bottom - rect.top; // return new Rectangle(p.x,p.y,width,height); // } else { // /* coordinates are mirrored */ // /* TODO: this has not been tested */ // Point p = parentControl.toControl(rect.left,rect.top); // int width = rect.left - rect.right; // int height = rect.bottom - rect.top; // return new Rectangle(p.x,p.y,width,height); // } //end code adapted from o.e.swt.patched.MenuItem.getBounds() protected static Rectangle translateRectangle(Menu parent, Rectangle menuRect, Rectangle itemRect) { if ((parent.getStyle() & SWT.RIGHT_TO_LEFT) != 0) { itemRect.x = menuRect.x + menuRect.width - itemRect.width - itemRect.x; } else { itemRect.x += menuRect.x; } itemRect.y += menuRect.y; return itemRect; } /** * Kludge for versions of Eclipse lacking * {@link org.eclipse.swt.widgets.MenuItem#getBounds()}. * This is a copy/mod of code from 3.1-M7. The only * mod is rectangle translation: see * {@link #translateRectangleHack(Rectangle, int, int)} */ // TODO: need better handling of Eclipse versions! protected static Rectangle getBoundsHack(MenuItem menuItem, Menu parent) { // start code copy/mod from org.eclipse.swt.widgets.MenuItem.getBounds() if (OS.IsWinCE) return new Rectangle (0, 0, 0, 0); int index = parent.indexOf (menuItem); if (index == -1) return new Rectangle (0, 0, 0, 0); if ((parent.getStyle() & SWT.BAR) != 0) { Decorations shell = parent.getParent(); if (shell.getMenuBar() != parent) { return new Rectangle (0, 0, 0, 0); } int hwndShell = shell.handle; MENUBARINFO info1 = new MENUBARINFO (); info1.cbSize = MENUBARINFO.sizeof; if (!OS.GetMenuBarInfo (hwndShell, OS.OBJID_MENU, 1, info1)) { return new Rectangle (0, 0, 0, 0); } MENUBARINFO info2 = new MENUBARINFO (); info2.cbSize = MENUBARINFO.sizeof; if (!OS.GetMenuBarInfo (hwndShell, OS.OBJID_MENU, index + 1, info2)) { return new Rectangle (0, 0, 0, 0); } int x = info2.left - info1.left; int y = info2.top - info1.top; int width = info2.right - info2.left; int height = info2.bottom - info2.top; // return new Rectangle (x, y, width, height); return translateRectangleHack( new Rectangle (x, y, width, height), info1.left, info1.top); } else { int hMenu = parent.handle; RECT rect1 = new RECT (); if (!OS.GetMenuItemRect (0, hMenu, 0, rect1)) { return new Rectangle (0, 0, 0, 0); } RECT rect2 = new RECT (); if (!OS.GetMenuItemRect (0, hMenu, index, rect2)) { return new Rectangle (0, 0, 0, 0); } int x = rect2.left - (rect1.left + 2); int y = rect2.top - (rect1.top + 2); int width = rect2.right - rect2.left; int height = rect2.bottom - rect2.top; // return new Rectangle (x, y, width, height); return translateRectangleHack( new Rectangle (x, y, width, height), (rect1.left + 2), (rect1.top + 2)); } // end code copy/mod from org.eclipse.swt.widgets.MenuItem.getBounds() } /** * Does translation for {@link getBoundsHack(MenuItem, Menu)}. * (May only be needed for 3.0 support.) * Thanks Joerg Weingarten! */ protected static Rectangle translateRectangleHack( Rectangle itemRect, int deltaX, int deltaY) { itemRect.x += deltaX; itemRect.y += deltaY; return itemRect; } /** * Workaround for lack of Menu.getBounds(). * Adapted from the non-public org.eclipse.swt.widgets.Menu.getBounds() in Eclipse 3.1M6. * * Returns a rectangle describing the receiver's size and location * relative to its parent (or its display if its parent is null), * unless the receiver is a menu or a shell. In this case, the * location is relative to the display. *

* Note that the bounds of a menu or menu item are undefined when * the menu is not visible. This is because most platforms compute * the bounds of a menu dynamically just before it is displayed. *

* * @return the receiver's bounding rectangle * * @exception SWTException * * @since 3.1 */ public static Rectangle getBounds (Menu menu) { // menu.getParent() calls checkWidget() on itself. //checkWidget (); Decorations parent = menu.getParent(); if (OS.IsWinCE) return new Rectangle (0, 0, 0, 0); if ((menu.getStyle() & SWT.BAR) != 0) { if (parent.getMenuBar() != menu) { return new Rectangle (0, 0, 0, 0); } int hwndShell = parent.handle; MENUBARINFO info = new MENUBARINFO (); info.cbSize = MENUBARINFO.sizeof; if (OS.GetMenuBarInfo (hwndShell, OS.OBJID_MENU, 0, info)) { int width = info.right - info.left; int height = info.bottom - info.top; return new Rectangle (info.left, info.top, width, height); } } else { int count = menu.getItemCount(); if (count != 0) { RECT rect1 = new RECT (); if (OS.GetMenuItemRect (0, menu.handle, 0, rect1)) { RECT rect2 = new RECT (); if (OS.GetMenuItemRect (0, menu.handle, count - 1, rect2)) { int x = rect1.left - 2, y = rect1.top - 2; int width = (rect2.right - rect2.left) + 4; int height = (rect2.bottom - rect1.top) + 4; return new Rectangle (x, y, width, height); } } } } return new Rectangle (0, 0, 0, 0); } /** * Workaround for lack of ScrollBar.getBounds(). * Adapted from the non-public org.eclipse.swt.widgets.ScrollBar.getBounds() in Eclipse 3.1M6. */ public static Rectangle getBounds (ScrollBar scrollBar) { // scrollBar.getParent() calls checkWidget() on itself. // checkWidget (); Scrollable parent = scrollBar.getParent(); // Use getClientArea() to call forceResize(), which is private. //parent.forceResize (); parent.getClientArea(); RECT rect = new RECT (); OS.GetClientRect (parent.handle, rect); int x = 0, y = 0, width, height; if ((scrollBar.getStyle() & SWT.HORIZONTAL) != 0) { y = rect.bottom - rect.top; width = rect.right - rect.left; height = OS.GetSystemMetrics (OS.SM_CYHSCROLL); } else { x = rect.right - rect.left; width = OS.GetSystemMetrics (OS.SM_CXVSCROLL); height = rect.bottom - rect.top; } return new Rectangle (x, y, width, height); } // Below is the original adaptation of the patch version. // public static Rectangle getBounds (ScrollBar scrollBar) { // //// Call to (private) checkWidget not needed because getParent() calls it first thing. //// scrollBar.checkWidget (); // Scrollable parent = scrollBar.getParent(); // //// Can't call forceResize() because it's private. //// So, instead call getClientArea(), which calls forceResize(), throwing away the result. //// parent.forceResize (); // parent.getClientArea(); // // RECT rect = new RECT (); // OS.GetClientRect (parent.handle, rect); // int x = 0, y = 0, width, height; // if ((scrollBar.getStyle() & SWT.HORIZONTAL) != 0) { // y = rect.bottom - rect.top; // width = rect.right - rect.left; // height = OS.GetSystemMetrics (OS.SM_CYHSCROLL); // } else { // x = rect.right - rect.left; // width = OS.GetSystemMetrics (OS.SM_CXVSCROLL); // height = rect.bottom - rect.top; // } // return new Rectangle (x, y, width, height); // } /** * Workaround for lack of TabItem.getBounds(). * * Returns a rectangle describing a TabItem's size and location * relative to its parent. * * @return the specified TabItem's bounding rectangle * * @exception SWTException */ public static Rectangle getBounds(TabItem tabItem){ // Call to tabItem.getParent(), next, first calls checkWidget(). // tabItem.checkWidget(); TabFolder parent = tabItem.getParent(); int index = parent.indexOf(tabItem); if (index == -1) return new Rectangle (0, 0, 0, 0); RECT rect = new RECT(); OS.SendMessage( parent.handle, OS.TCM_GETITEMRECT, index, rect); int width = rect.right - rect.left; int height = rect.bottom - rect.top; // return new Rectangle(rect.left,rect.top,width,height); // moved code from WidgetLocator so as to centralize in this class Rectangle bounds = new Rectangle(rect.left,rect.top,width,height); Point p = tabItem.getParent().toDisplay(bounds.x,bounds.y); return new Rectangle(p.x,p.y,bounds.width,bounds.height); } /* Used by getBounds(TableColumn), below. */ private static final int OS_HDM_GETITEMRECT = OS.HDM_FIRST + 7; /** * Returns a rectangle describing the receiver's header relative * to its parent table. * * @return the bounding rectangle of the receiver's header * * @exception SWTException */ public static Rectangle getBounds(TableColumn tableColumn) { // Call to tableColumn.getParent(), next, first calls checkWidget(). // tableColumn.checkWidget(); Table parent = tableColumn.getParent(); int index = parent.indexOf(tableColumn); if (index == -1) return new Rectangle (0, 0, 0, 0); int hwnd = parent.handle; int hwndHeader = OS.SendMessage (hwnd, OS.LVM_GETHEADER, 0, 0); RECT rect = new RECT(); OS.SendMessage(hwndHeader,OS_HDM_GETITEMRECT,index,rect); int width = rect.right - rect.left; int height = rect.bottom - rect.top; // return new Rectangle(rect.left,rect.top,width,height); // moved code from WidgetLocator so as to centralize in this class Rectangle bounds = new Rectangle(rect.left,rect.top,width,height); Point p = tableColumn.getParent().toDisplay(bounds.x,bounds.y); return new Rectangle(p.x,p.y,bounds.width,bounds.height); } /** * {@link org.eclipse.swt.widgets.TableItem#getBounds()} is not public? * Hence this workaround. Note request for public-ity in * * the getBounds() bugzilla */ public static Rectangle getBounds(TableItem item) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=38436#c86 // return TableItemTester.getTableItemTester().getBounds(item, 0); // moved code from WidgetLocator so as to centralize in this class Rectangle bounds = TableItemTester.getTableItemTester().getBounds(item, 0); Point p = item.getParent().toDisplay(bounds.x,bounds.y); return new Rectangle(p.x,p.y,bounds.width,bounds.height); } public static Rectangle getBounds(TreeItem item) { // moved code from WidgetLocator so as to centralize in this class Rectangle bounds = item.getBounds(); Point p = item.getParent().toDisplay(bounds.x,bounds.y); return new Rectangle(p.x,p.y,bounds.width,bounds.height); } public static Rectangle getBounds(CTabItem item) { // moved code from WidgetLocator so as to centralize in this class // CTabItem has getBounds(), though TabItem does not Rectangle bounds = item.getBounds(); Point p = item.getParent().toDisplay(bounds.x,bounds.y); return new Rectangle(p.x,p.y,bounds.width,bounds.height); } public static Rectangle getBounds(ToolItem item) { // moved code from WidgetLocator so as to centralize in this class Rectangle bounds = item.getBounds(); Point p = item.getParent().toDisplay(bounds.x,bounds.y); return new Rectangle(p.x,p.y,bounds.width,bounds.height); } public static Rectangle getBounds(CoolItem item) { // moved code from WidgetLocator so as to centralize in this class Rectangle bounds = item.getBounds(); Point p = item.getParent().toDisplay(bounds.x,bounds.y); return new Rectangle(p.x,p.y,bounds.width,bounds.height); } /** * Translates from SWT keys values to native keys, e.g. * from SWT.ESC to OS.VK_ESCAPE. * For details see * {@link org.eclipse.swt.widgets.Display#KeyTable} * Workaround for package scope of * {@link org.eclipse.swt.widgets.Display#untranslateKey(int)} */ public static int swt2OS(int swtKeyValue) { return Display.untranslateKey(swtKeyValue); } }