Java tutorial
/* ***************************************************************************** * org.nightlabs.base.ui - NightLabs Eclipse utilities * * Copyright (C) 2004-2005 NightLabs - http://NightLabs.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2.1 of the License, or (at your option) any later version. * * * * This library 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 * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, * * Boston, MA 02110-1301 USA * * * * Or get it online : * * http://www.gnu.org/copyleft/lesser.html * * * * * ******************************************************************************/ package org.nightlabs.base.ui.util; import java.awt.Dimension; import java.awt.Toolkit; import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.eclipse.core.resources.CompatibleResources; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Platform; import org.eclipse.jface.action.IContributionItem; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.ColumnLayoutData; import org.eclipse.jface.viewers.ColumnPixelData; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.jface.viewers.TableLayout; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontMetrics; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorReference; import org.eclipse.ui.IPageLayout; import org.eclipse.ui.IPerspectiveDescriptor; import org.eclipse.ui.IPerspectiveRegistry; import org.eclipse.ui.IViewPart; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchPartReference; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.WorkbenchException; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.internal.EditorAreaHelper; import org.eclipse.ui.internal.EditorPane; import org.eclipse.ui.internal.EditorStack; import org.eclipse.ui.internal.WorkbenchPage; import org.nightlabs.base.ui.composite.ChildStatusController; import org.nightlabs.base.ui.composite.XComposite; import org.nightlabs.base.ui.context.UIContext; import org.nightlabs.base.ui.form.AbstractBaseFormPage; import org.nightlabs.base.ui.layout.WeightedTableLayout; import org.nightlabs.base.ui.resource.Messages; import org.nightlabs.eclipse.compatibility.CompatibleGC; import org.nightlabs.eclipse.compatibility.CompatibleSWT; import org.nightlabs.util.IOUtil; /** * @author Alexander Bieber <alex[AT]nightlabs[DOT]de> * @author Marco Schulze - marco at nightlabs dot de * @author Fitas Amine - fitas at nightlabs dot de */ public class RCPUtil { private static final Logger logger = Logger.getLogger(RCPUtil.class); /** * Recursively sets the enabled flag for the given Composite and all its children. * <p> * <b>Important:</b> It is highly recommended to extend your containers in a way that they * automatically do this and when re-enabling the container do <b>not</b> enable child-elements * that where disabled before. The {@link XComposite} already implements this behaviour (just * like other NightLabs-UI elements as well). In order to implement this behaviour yourself, * you should use a {@link ChildStatusController}. * </p> * * @param comp The parent control * @param enabled The enabled flag to set */ public static void setControlEnabledRecursive(Composite comp, boolean enabled) { comp.setEnabled(enabled); Control[] children = comp.getChildren(); for (int i = 0; i < children.length; i++) { if (children[i] instanceof Composite) setControlEnabledRecursive((Composite) children[i], enabled); } } /** * Sets the given button selected if it is contained in the given parent Composite, * and deselects all other buttons in this Composite * * @param parent the parent Composite * @param button a Button with style Param SWT.TOGGLE or SWT.RADIO which should be selected */ public static void setButtonSelected(Composite parent, Button button) { button.setSelection(true); Control[] children = parent.getChildren(); for (int i = 0; i < children.length; i++) { if (!children[i].equals(button)) { if ((((children[i].getStyle() & SWT.TOGGLE) != 0) || ((children[i].getStyle() & SWT.RADIO) != 0)) && (children[i] instanceof Button)) { ((Button) children[i]).setSelection(false); } } } } /** * Take a screen shot of the application. This method tries to only include windows of the current * application (and not to include any information from other apps). * <p> * If there are {@link Shell}s (= windows) existing, the screen shot is taken for the * smallest rectangle that contains all of the application's windows. If there is no {@link Shell} existing, * the complete screen will be taken. * </p> * <p> * In the future, this method should overwrite areas inbetween different shells (where other applications' windows * are [partially] visible) with black. At the moment, this information is not yet cut out. * </p> * * @return image of the current screen. */ public static ImageData takeApplicationScreenShot() { Display display = Display.getCurrent(); if (display == null) throw new IllegalStateException("This method must be called on the SWT UI thread!"); //$NON-NLS-1$ int minX = Integer.MAX_VALUE; int minY = Integer.MAX_VALUE; int maxX = Integer.MIN_VALUE; int maxY = Integer.MIN_VALUE; // find the area rectangle of the screen that contains all the shells boolean hasVisibleShell = false; // iterate all shells in order to get the smallest rectangle containing all of them for (Shell shell : display.getShells()) { if (!shell.isVisible()) continue; if (shell.isDisposed()) continue; hasVisibleShell = true; shell.redraw(); Rectangle bounds = shell.getBounds(); minX = Math.min(bounds.x, minX); maxX = Math.max(bounds.x + bounds.width, maxX); minY = Math.min(bounds.y, minY); maxY = Math.max(bounds.y + bounds.height, maxY); } // if there is no visible shell, take the complete screen if (!hasVisibleShell) { Rectangle bounds = display.getBounds(); minX = bounds.x; maxX = minX + bounds.width; minY = bounds.y; maxY = minY + bounds.height; } // ensure everything has been redrawn display.readAndDispatch(); // Taking the screen shot with AWT is a bit complicated since AWT manages a multi-screen-environment // really separated - hence we would need to put our screen shot together ourselves. Thus, we use SWT now. // for (GraphicsDevice gd : GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()) { // java.awt.Rectangle rect = gd.getDefaultConfiguration().getBounds(); // rect.getBounds(); // } // return new Robot().createScreenCapture(new java.awt.Rectangle(minX, minY, maxX - minX, maxY - minY)); Image image = CompatibleSWT.newImage(display, new Rectangle(minX, minY, maxX - minX, maxY - minY)); try { GC gc = new GC(display); try { CompatibleGC.copyArea(gc, image, minX, minY); } finally { gc.dispose(); } return image.getImageData(); } finally { image.dispose(); } } /** * Returns whether the ViewPart with the given id is currently visible in * one of the pages of the active Workbench window. Will also return * true when the page-book containing this view is minimized. * * @param viewID The id of the view to be queried * @return Whether the view is visible */ public static boolean isViewVisible(String viewID) { // IWorkbenchPage[] pages = Workbench.getInstance().getActiveWorkbenchWindow().getPages(); IWorkbenchPage[] pages = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getPages(); for (int i = 0; i < pages.length; i++) { IWorkbenchPart part = pages[i].findView(viewID); if (part != null) { return isPartVisible(part); } } return false; } /** * Show/Hide all ViewActions of the given View. * * @param view The View which ViewActions should be shown/hidden * @param visible true to show all Actions, fals to hide them */ public static void setViewActionsVisible(IViewPart view, boolean visible) { IToolBarManager toolBarManager = view.getViewSite().getActionBars().getToolBarManager(); IMenuManager menuManager = view.getViewSite().getActionBars().getMenuManager(); IContributionItem[] tItems = toolBarManager.getItems(); for (int i = 0; i < tItems.length; i++) { tItems[i].setVisible(visible); tItems[i].update(); } IContributionItem[] mItems = menuManager.getItems(); for (int i = 0; i < mItems.length; i++) { mItems[i].setVisible(visible); mItems[i].update(); } toolBarManager.update(true); menuManager.update(true); } /** * Returns wether the given IWorkbenchPart is currently visble in * one of the pages of the active Workbench window. Will also return * true when the page-book containing this view is minimized. * * @param part The part to check * @return Wether the view is visible */ public static boolean isPartVisible(IWorkbenchPart part) { boolean visible = false; IWorkbenchPage[] pages = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getPages(); for (int i = 0; i < pages.length; i++) { if (part != null) if (pages[i].isPartVisible(part)) { visible = true; } } return visible; } /** * Shows the view with the given viewID in all workbench-pages * * @param viewID The id of the view to be queried * @return Wether the view is visible */ public static IWorkbenchPart showView(String viewID) { IWorkbenchPage[] pages = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getPages(); for (int i = 0; i < pages.length; i++) { IWorkbenchPart view = null; try { view = pages[0].showView(viewID); } catch (PartInitException e) { throw new RuntimeException(e); } if (view != null) return view; } return null; } /** * Shows the desired perspective in the active workbench window. * * @param perspectiveID The perspective to show. * @return The IWorkbenchPage the perspective was opened in. */ public static IWorkbenchPage showPerspective(String perspectiveID) { IPerspectiveRegistry perspectiveRegistry = PlatformUI.getWorkbench().getPerspectiveRegistry(); if (perspectiveID != null) { IPerspectiveDescriptor perspectiveDescriptor = perspectiveRegistry.findPerspectiveWithId(perspectiveID); if (perspectiveDescriptor != null) { IWorkbench workbench = PlatformUI.getWorkbench(); try { return workbench.showPerspective(perspectiveID, workbench.getActiveWorkbenchWindow()); } catch (WorkbenchException e) { throw new RuntimeException(e); } } } return null; } /** * Shows the view with the given viewID and * gives it focus. * * @param viewID The id of the view to be queried * @return Wether the view is visible */ public static IWorkbenchPart activateView(String viewID) { IWorkbenchPage[] pages = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getPages(); for (int i = 0; i < pages.length; i++) { IWorkbenchPart view = null; try { view = pages[0].showView(viewID); } catch (PartInitException e) { throw new RuntimeException(e); } if (view != null) { pages[0].activate(view); return view; } } return null; } /** * @deprecated Use {@link #getActiveWorkbenchShell()} instead! */ @Deprecated public static Shell getWorkbenchShell() { return getActiveWorkbenchShell(); } /** * Returns the active WorkbenchWindow's shell. In most use cases (e.g. opening a dialog), you should instead use {@link #getActiveShell()}. * @return The active WorkbenchWindow's shell or <code>null</code>, if there is no active workbench window (or if its {@link IWorkbenchWindow#getShell()} method returns <code>null</code>). * @see #getActiveShell() */ public static Shell getActiveWorkbenchShell() { IWorkbenchWindow window = getActiveWorkbenchWindow(); return window == null ? null : window.getShell(); } /** * Returns the active shell. This method first calls {@link Display#getActiveShell()}. If this returns <code>null</code>, * it calls {@link #getActiveWorkbenchShell()}. * * @return The active shell or <code>null</code>, if there is neither a global active shell nor an active workbench shell. */ public static Shell getActiveShell() { Shell shell = null; if (Display.getCurrent() != null) shell = Display.getCurrent().getActiveShell(); if (shell == null) shell = Display.getDefault().getActiveShell(); if (shell == null) shell = getActiveWorkbenchShell(); return shell; } /** * Returns the active WorkbenchWindow's active page. * @return The active WorkbenchWindow's active page. */ public static IWorkbenchWindow getActiveWorkbenchWindow() { return PlatformUI.getWorkbench().getActiveWorkbenchWindow(); } /** * @deprecated Use {@link #getActiveWorkbenchPage()} instead! */ @Deprecated public static IWorkbenchPage getWorkbenchPage() { return getActiveWorkbenchPage(); } /** * Returns the active WorkbenchWindow's active page. * @return The active WorkbenchWindow's active page. */ public static IWorkbenchPage getActiveWorkbenchPage() { IWorkbenchWindow window = getActiveWorkbenchWindow(); return window == null ? null : window.getActivePage(); } /** * returns the id of the current perspective * @return the id of the current perspective */ public static String getActivePerspectiveID() { IWorkbenchPage page = getActiveWorkbenchPage(); IPerspectiveDescriptor perspectiveDescriptor = page == null ? null : page.getPerspective(); return perspectiveDescriptor == null ? null : perspectiveDescriptor.getId(); } /** * opens a ErrorDialog with the given message * * @param message the message to display * @param buttonStyle the buttonStyle * @return the returnCode of the Dialog */ public static void showErrorDialog(String message) { MessageDialog.openError(getActiveShell(), Messages.getString("org.nightlabs.base.ui.util.RCPUtil.showErrorDialog.title"), message); //$NON-NLS-1$ } /** * opens a MessageBox which asks the user if he want to overwrite the file, * with the given fileName * * @param fileName the name of the file * @return the returnCode of the Dialog */ public static boolean showConfirmOverwriteDialog(String fileName) { return MessageDialog.openConfirm(getActiveShell(), Messages.getString("org.nightlabs.base.ui.util.RCPUtil.showConfirmOverwriteDialog.title"), //$NON-NLS-1$ String.format( Messages.getString("org.nightlabs.base.ui.util.RCPUtil.showConfirmOverwriteDialog.message"), //$NON-NLS-1$ new Object[] { fileName })); } /** * disposes the given Composite with all of its children * * @param comp the Composite to dispose with all of its children */ public static void disposeAllChildren(Composite comp) { if (comp != null) { if (!comp.isDisposed()) { Control[] children = comp.getChildren(); for (int i = 0; i < children.length; i++) { Control c = children[i]; c.dispose(); } } } } /** * Opens an editor with the given input and editorID and returns it. * * @param input The editors input * @param editorID The editors id * @return The editor opened * @throws PartInitException */ public static IEditorPart openEditor(IEditorInput input, String editorID) throws PartInitException { return getActiveWorkbenchPage().openEditor(input, editorID); } /** * Opens an editor with the given input and editorID and returns it. * * @param input The editors input * @param editorID The editors id * @return The editor opened * @throws PartInitException */ public static IEditorPart openEditor(IEditorInput input, String editorID, boolean activate) throws PartInitException { return getActiveWorkbenchPage().openEditor(input, editorID, activate); } /** * Finds the editor for the given input in the workbench's * active workbenchpage. Returns null if no editor for * the given input was found. * * @param input The input for which to search a currently open editor. */ public static IEditorPart findEditor(IEditorInput input) { return getActiveWorkbenchPage().findEditor(input); } /** * If there is an open editor for the given <code>input</code>, * it will be closed. If no editor can be found, this * method is a no-op. * * @param input The input specifying the editor to close. * @param save Whether or not to save - this is passed to {@link IWorkbenchPage#closeEditor(IEditorPart, boolean)}. * @return <code>true</code>, if no open editor was found or if it has been successfully closed. * <code>false</code>, if the open editor for the given <code>input</code> was not closed (e.g. because * the user cancelled closing in case <code>save == true</code>). */ public static boolean closeEditor(IEditorInput input, boolean save) { IWorkbenchPage page = getActiveWorkbenchPage(); IEditorPart editor = page.findEditor(input); if (editor == null) return true; return page.closeEditor(editor, save); } /** * Finds the view with the given id in the workbench's * active workbenchpage. Returns null if no view for the * given viewID was found. * * @param viewID The id of the view. */ public static IViewPart findView(String viewID) { return getActiveWorkbenchPage().findView(viewID); } /** * * @param bounds the bounds of a Control * @return the Point which determines the Location so that the given Bounds are * centered on the screen */ public static Point getCenterPosition(Rectangle bounds) { Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); int x = 0; int y = 0; if (bounds.width < screenSize.getWidth()) x = (((int) screenSize.getWidth()) - bounds.width) / 2; if (bounds.height < screenSize.getHeight()) y = (((int) screenSize.getHeight()) - bounds.height) / 2; return new Point(x, y); } /** * Adds all known perspectives as perspective shortcuts to the given * layout. */ public static void addAllPerspectiveShortcuts(IPageLayout layout) { IPerspectiveDescriptor[] perspectives = PlatformUI.getWorkbench().getPerspectiveRegistry() .getPerspectives(); for (int i = 0; i < perspectives.length; i++) layout.addPerspectiveShortcut(perspectives[i].getId()); // IConfigurationElement[] configPerspectives = Platform.getExtensionRegistry().getConfigurationElementsFor("org.eclipse.ui.perspectives"); // for(int i = 0; i < configPerspectives.length; i++) // layout.addPerspectiveShortcut(configPerspectives[i].getAttribute("id")); } /** * * @param comp the Composite to set the Form Border for * @see FormToolkit#paintBordersFor(Composite) */ public static void setFormBorder(Composite comp) { comp.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER); } /** * sets the location of a dialog so that it apperas in the center of the screen * @param d the Dialog to center */ public static void centerDialog(Dialog d) { Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Point shellSize = d.getShell().getSize(); int diffWidth = screenSize.width - shellSize.x; int diffHeight = screenSize.height - shellSize.y; d.getShell().setLocation(diffWidth / 2, diffHeight / 2); } /** * checks if a IMenuManager with the given ID is contained in * the given IMenuManager and returns it. * * @param id the ID of the ContributionItem * @param menuMan the MenuManager to search in * @return the ContributionItem with the given ID or null if not contained */ public static IContributionItem getMenuItem(String id, IMenuManager menuMan) { if (menuMan != null) { IContributionItem[] menuItems = menuMan.getItems(); for (int i = 0; i < menuItems.length; i++) { IContributionItem menuItem = menuItems[i]; if (menuItem != null && menuItem.getId() != null) { if (menuItem.getId().equals(id)) return menuItem; } } } return null; } /** * Returns the either the active {@link IWorkbenchPage} * or the first found. If none can be found <code>null</code> * will be returned. * * @return An {@link IWorkbenchPage} or null */ public static IWorkbenchPage searchWorkbenchPage() { IWorkbenchWindow window = getActiveWorkbenchWindow(); if (window == null) return null; IWorkbenchPage[] pages = window.getPages(); if (pages.length > 0) return pages[0]; else return null; } /** * Tries to find a reference for the given part somewhere in the Workbench and returns it. * If a reference can not be found <code>null</code> will be returned. * * @param part The part to search a reference for */ public static IWorkbenchPartReference searchPartReference(IWorkbenchPart part) { IWorkbenchWindow window = getActiveWorkbenchWindow(); if (window == null) return null; IWorkbenchPage[] pages = window.getPages(); for (int i = 0; i < pages.length; i++) { IWorkbenchPartReference ref = pages[i].getReference(part); if (ref != null) return ref; } return null; } /** * logs all parents and its layoutData of the given control to the given logger * * @param control the {@link Control} to log its parents * @param logger the logger to log * @param logLevel the logLevel to use */ public static void logControlParents(Control control, Logger logger, Level logLevel) { Composite parent = control.getParent(); if (parent != null) { logger.log(logLevel, "control = " + control); //$NON-NLS-1$ logger.log(logLevel, "control.getLayoutData() = " + control.getLayoutData()); //$NON-NLS-1$ logger.log(logLevel, "parent = " + parent); //$NON-NLS-1$ logger.log(logLevel, "parent.getLayout() = " + parent.getLayout()); //$NON-NLS-1$ logControlParents(parent, logger, logLevel); } } private static IProgressMonitor nullMonitor = new NullProgressMonitor(); /** * Checks the given monitor and returns it if not <code>null</code>. If * the given monitor is null an instance of {@link NullProgressMonitor} * will be returned. * * @param monitor The monitor to check */ public static IProgressMonitor getSaveProgressMonitor(IProgressMonitor monitor) { if (monitor != null) return monitor; return nullMonitor; } public static boolean isDisplayThread() { Display display = UIContext.getDisplay(); return display != null && display.getThread().equals(Thread.currentThread()); } /** * This method is a convenience method calling * <code>ResourcesPlugin.getWorkspace().getRoot().getLocation().toOSString()</code> * * @return Returns a {@link File} instance pointing to the workspace root directory. */ public File getResourcesWorkspace() { return CompatibleResources.getWorkspaceRootLocationPath(); } /** * Returns a {@link File} representation of the given {@link IResource}. * * @param resource The resource to get the {@link File} from. * @return A {@link File} representation of the given {@link IResource}. */ public static File getResourceAsFile(IResource resource) { return CompatibleResources.getResourceAsFile(resource); } /** * Sets the font of the given Control to its old font adding/removing the given styles. * So, for example, to maket the text bold do: * <pre> * RCPUtil.setControlFontStyle(myControl, SWT.BOLD, 0); * </pre> * Styles are first added then removed. * * @param control The {@link Control} to change the font of. * @param addStyle The style flag(s that should be added to the controls actual font. * @param removeStyle The style flag(s) that should be removed from the contros actual font. */ public static void setControlFontStyle(Control control, int addStyle, int removeStyle) { Font oldFont = control.getFont(); int newStyle = oldFont.getFontData()[0].getStyle() | addStyle; newStyle = newStyle & (~removeStyle); final Font newFont = new Font(oldFont.getDevice(), oldFont.getFontData()[0].getName(), oldFont.getFontData()[0].getHeight(), newStyle); control.setFont(newFont); control.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { newFont.dispose(); } }); } public static int getFontHeight(Control control) { int fontHeight = 0; // since the standard font can change - we recalculate this every time GC gc = new GC(control.getParent()); try { gc.setFont(control.getFont()); FontMetrics fontMetrics = gc.getFontMetrics(); fontHeight = fontMetrics.getHeight(); } finally { gc.dispose(); } return fontHeight; } /** * clears the workspace folder * @param ask determines if the user should be asked before */ public static void clearWorkspace(boolean ask) { if (ask) { boolean ok = MessageDialog.openConfirm(RCPUtil.getActiveShell(), Messages.getString("org.nightlabs.base.ui.util.RCPUtil.clearWorkspace.title"), //$NON-NLS-1$ Messages.getString("org.nightlabs.base.ui.util.RCPUtil.clearWorkspace.message")); //$NON-NLS-1$ if (!ok) return; } File workspace = Platform.getLocation().toFile(); IOUtil.deleteDirectoryRecursively(workspace); } /** * Adds a new {@link org.eclipse.ui.internal.layout.IWindowTrim} * to the {@link org.eclipse.ui.internal.layout.TrimLayout} of the given shell * and prepends it to the the trim with the given id (pependTo). * The new trim will be filled with the contents of the given contributionItem. * * @param shell The shell to add the trim to. * @param contributionItem The contributionItem to fill the trim with. * @param prependTo The id of the trim the new trim should be prepended to. */ @SuppressWarnings("restriction") //$NON-NLS-1$ public static void addContributionItemTrim(Shell shell, IContributionItem contributionItem, String prependTo) { if (shell != null && (shell.getLayout() instanceof org.eclipse.ui.internal.layout.TrimLayout)) { // This is how the WorkbenchWindow add the progress and heapstatus controls // can't be that wrong :-) org.eclipse.ui.internal.layout.TrimLayout layout = (org.eclipse.ui.internal.layout.TrimLayout) shell .getLayout(); Composite comp = new Composite(shell, SWT.NONE); contributionItem.fill(comp); org.eclipse.ui.internal.WindowTrimProxy trimProxy = new org.eclipse.ui.internal.WindowTrimProxy(comp, contributionItem.getId(), contributionItem.getClass().getSimpleName(), SWT.BOTTOM | SWT.TOP) { @Override public void handleClose() { getControl().dispose(); } @Override public boolean isCloseable() { return true; } }; org.eclipse.ui.internal.layout.IWindowTrim prependTrim = layout.getTrim(prependTo); trimProxy.setWidthHint(comp.computeSize(SWT.DEFAULT, SWT.DEFAULT).x); trimProxy.setHeightHint(comp.computeSize(SWT.DEFAULT, SWT.DEFAULT).y); layout.addTrim(SWT.BOTTOM, trimProxy, prependTrim); comp.setVisible(true); } } /** * Used internally for the TableLayout workaround. */ private static class WorkaroundTableLayout extends TableLayout { private List<ColumnLayoutData> originalData; private List<ColumnPixelData> pixelData = null; /** * @param originalData */ public WorkaroundTableLayout(List<ColumnLayoutData> originalData) { assert originalData != null; this.originalData = originalData; this.pixelData = new ArrayList<ColumnPixelData>(originalData.size()); for (int i = 0; i < originalData.size(); i++) { // set min size of 10 pixels per column final ColumnPixelData pData = new ColumnPixelData(10); pixelData.add(pData); addColumnData(pData); } } public List<ColumnLayoutData> getOriginalData() { return originalData; } @Override public void layout(Composite c, boolean flush) { // check if there is currently a vertical scroll bar visible in the composite tree where // the given tree of table is used in. If so reduce the available width. // Note: The weird thing is, that the ScrollBar is always set and the width is always > 0, // BUT with this fix, the table width always matches perfectly. (marius) // AAV: why height?! final int verticalScrollBarWidth = CompatibleSWT.getVerticalScrollBarHeight(c); final int width = c.getClientArea().width - verticalScrollBarWidth; if (width > 1) { setPixelData(originalData, pixelData, width); } super.layout(c, flush); } } /** * Performs {@link RCPUtil#workaroundFormTableLayout(Table, boolean)} for every Table found * in the Composite graph of the given parent. * * @param parent The parent to replace layouts for. * @param doLayout Whether the tables should be re-layouted. * @deprecated this shouldn't be needed anymore see {@link AbstractBaseFormPage}. */ @Deprecated public static void workaroundFormPageTableLayouts(Control parent, boolean doLayout) { if (parent instanceof Table) { workaroundFormTableLayout((Table) parent, doLayout); } else if (parent instanceof Composite) { Composite comp = (Composite) parent; Control[] children = comp.getChildren(); for (Control child : children) { workaroundFormPageTableLayouts(child, doLayout); } } } /** * Delegates to {@link #workaroundFormTableLayout(Table, boolean)} with * <code>doLayout = false</code>. * * @param table The table to layout that has already a TableLayout set. * @deprecated this shouldn't be needed anymore see {@link AbstractBaseFormPage}. */ @Deprecated public static void workaroundFormTableLayout(final Table table) { workaroundFormTableLayout(table, false); } /** * Workaround method to apply normal {@link ColumnLayoutData}s to a table used in a {@link org.eclipse.ui.forms.widgets.Form} with GridLayout. * This prevents the table to calculate a wrong size in a {@link org.eclipse.ui.forms.widgets.Form} and to let the Section grow on every resize. * * @param table The table to layout that has already a TableLayout set. * @param layoutData The layout data to apply to the table. * @deprecated this shouldn't be needed anymore see {@link AbstractBaseFormPage}. */ @Deprecated public static void workaroundFormTableLayout(final Table table, final boolean doLayout) { // TODO: WORKAROUND: FIXME: XXX: This is a workaround for wrong size calculation within a form if (!(table.getLayout() instanceof TableLayout) && !(table.getLayout() instanceof WorkaroundTableLayout) && !(table.getLayout() instanceof WeightedTableLayout)) return; // The table does not have a TableLayout set. List<ColumnLayoutData> lData = null; if (table.getLayout() instanceof WorkaroundTableLayout) { lData = ((WorkaroundTableLayout) table.getLayout()).getOriginalData(); } else if (table.getLayout() instanceof WeightedTableLayout) { lData = ((WeightedTableLayout) table.getLayout()).translateToColumnLayoutData(); } else if (table.getLayout() instanceof TableLayout) { final TableLayout oldLayout = (TableLayout) table.getLayout(); // tableLayout.addColumnData(new ColumnWeightData(10)); Field columnsField = null; try { columnsField = TableLayout.class.getDeclaredField("columns"); //$NON-NLS-1$ } catch (NoSuchFieldException e) { throw new RuntimeException(e); } columnsField.setAccessible(true); try { lData = (List<ColumnLayoutData>) columnsField.get(oldLayout); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } final WorkaroundTableLayout tableLayout = new WorkaroundTableLayout(new ArrayList<ColumnLayoutData>(lData)); table.setLayout(tableLayout); // final List<ColumnLayoutData> layoutData = lData; // final List<ColumnPixelData> pixelData = new ArrayList<ColumnPixelData>(layoutData.size()); // for (int i=0; i < layoutData.size(); i++) // { // // set min size of 10 pixels per column // final ColumnPixelData pData = new ColumnPixelData(10); // pixelData.add(pData); // tableLayout.addColumnData(pData); // } // // in case the table hasn't been layouted yet, this width is 0 and the WorkaroundTableLayout // // has to set correct pixel datas on layout call. // final int clientWidth = table.getClientArea().width; // if (clientWidth != 0) // { // setPixelData(layoutData, pixelData, clientWidth); // } // table.addControlListener(new ControlAdapter() { // public void controlResized(final ControlEvent e) { // setPixelData(layoutData, pixelData, table.getClientArea().width); // try { // final Field firstTimeField = TableLayout.class.getDeclaredField("firstTime"); // firstTimeField.setAccessible(true); // firstTimeField.set(tableLayout, true); // } catch (final Exception ex) { // table.layout(true, true); // return; // well, the workaround broke. // } // table.layout(true, true); // } // }); if (doLayout) { table.layout(true, true); } } private static void setPixelData(List<ColumnLayoutData> layoutData, List<ColumnPixelData> pixelDatas, int clientWidth) { int clientRest = clientWidth - 25; int weightSum = 0; for (int i = 0; i < layoutData.size(); i++) { final ColumnLayoutData columnData = layoutData.get(i); if (columnData instanceof ColumnPixelData) { clientRest -= ((ColumnPixelData) columnData).width; pixelDatas.get(i).width = ((ColumnPixelData) columnData).width; } else { weightSum += ((ColumnWeightData) columnData).weight; } } for (int i = 0; i < layoutData.size(); i++) { final ColumnLayoutData columnData = layoutData.get(i); final ColumnPixelData pixelData = pixelDatas.get(i); if (columnData instanceof ColumnWeightData) { pixelData.width = clientRest * ((ColumnWeightData) columnData).weight / weightSum; } } } /** * Returns all {@link IEditorReference} for the {@link IWorkbench}. * @return all {@link IEditorReference} for the {@link IWorkbench}. */ public static IEditorReference[] getAllEditorReferences() { Collection<IEditorReference> editorReferences = new HashSet<IEditorReference>(); for (IWorkbenchWindow win : PlatformUI.getWorkbench().getWorkbenchWindows()) { for (IWorkbenchPage page : win.getPages()) { IEditorReference[] editorRefs = getEditorReferencesPerPage(page); for (IEditorReference editorRef : editorRefs) { editorReferences.add(editorRef); } } } return editorReferences.toArray(new IEditorReference[editorReferences.size()]); } /** * Returns an array with all {@link IEditorReference} of the given {@link IWorkbenchPage}. * In case the patched version of org.eclipse.ui from NightLabs is used which provides EditorPart to Perspective binding, * this method will also work properly in contrast to {@link IWorkbenchPage#getEditorReferences()} which * only returns the IEditorReferences of the the current displayed perspective. * If the patch is not installed/used this method will just delegate to {@link IWorkbenchPage#getEditorReferences()}. * * @param page the {@link IWorkbenchPage} to get all {@link IEditorReference} for. * @return an array with all {@link IEditorReference} of the given {@link IWorkbenchPage}. */ public static IEditorReference[] getEditorReferencesPerPage(IWorkbenchPage page) { if (page instanceof WorkbenchPage) { Collection<IEditorReference> editorReferences = new HashSet<IEditorReference>(); WorkbenchPage workbenchPage = (WorkbenchPage) page; EditorAreaHelper editorAreaHelper = workbenchPage.getEditorPresentation(); try { Method method = EditorAreaHelper.class.getMethod("getEditorStack", String.class); IConfigurationElement[] elements = Platform.getExtensionRegistry() .getExtensionPoint("org.eclipse.ui.perspectives") //$NON-NLS-1$ .getConfigurationElements(); for (int i = 0; i < elements.length; i++) { String perspectiveId = elements[i].getAttribute("id").trim(); //$NON-NLS-1$ Object o = method.invoke(editorAreaHelper, perspectiveId); if (o instanceof EditorStack) { EditorStack editorStack = (EditorStack) o; EditorPane[] editorPanes = editorStack.getEditors(); for (EditorPane editorPane : editorPanes) { IEditorReference editorReference = editorPane.getEditorReference(); editorReferences.add(editorReference); } } } return editorReferences.toArray(new IEditorReference[editorReferences.size()]); } catch (Exception e) { logger.warn("Could not access method getEditorStack(String perspectiveID) for class " + EditorAreaHelper.class.getName() + ". Assume that not the patched editor perspective version of org.nightlabs.eclipse.ui is used and try to close editors the normal way.", e); return page.getEditorReferences(); } } return page.getEditorReferences(); } }