/******************************************************************************* * Copyright (c) 2004, 2010 BREDEX GmbH. * 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: * BREDEX GmbH - initial API and implementation and/or initial documentation *******************************************************************************/ package org.eclipse.jubula.client.ui.rcp; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.persistence.PersistenceException; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.jface.action.IStatusLineManager; import org.eclipse.jface.action.StatusLineManager; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.window.Window; import org.eclipse.jubula.client.alm.mylyn.core.bp.CommentReporter; import org.eclipse.jubula.client.core.ClientTest; import org.eclipse.jubula.client.core.businessprocess.CompNameManager; import org.eclipse.jubula.client.core.businessprocess.ExternalTestDataBP; import org.eclipse.jubula.client.core.businessprocess.IComponentNameCache; import org.eclipse.jubula.client.core.businessprocess.progress.OperationCanceledUtil; import org.eclipse.jubula.client.core.errorhandling.ErrorMessagePresenter; import org.eclipse.jubula.client.core.errorhandling.IErrorMessagePresenter; import org.eclipse.jubula.client.core.events.AutAgentEvent; import org.eclipse.jubula.client.core.events.DataChangedEvent; import org.eclipse.jubula.client.core.events.DataEventDispatcher; import org.eclipse.jubula.client.core.events.DataEventDispatcher.DataState; import org.eclipse.jubula.client.core.events.DataEventDispatcher.IDataChangedListener; import org.eclipse.jubula.client.core.events.IServerEventListener; import org.eclipse.jubula.client.core.events.ServerEvent; import org.eclipse.jubula.client.core.model.IProjectPO; import org.eclipse.jubula.client.core.persistence.GeneralStorage; import org.eclipse.jubula.client.core.progress.IProgressConsole; import org.eclipse.jubula.client.core.progress.ProgressConsoleRegistry; import org.eclipse.jubula.client.core.utils.Languages; import org.eclipse.jubula.client.core.utils.StringHelper; import org.eclipse.jubula.client.ui.constants.Constants; import org.eclipse.jubula.client.ui.constants.IconConstants; import org.eclipse.jubula.client.ui.editors.TestResultViewer; import org.eclipse.jubula.client.ui.rcp.businessprocess.CompletenessBP; import org.eclipse.jubula.client.ui.rcp.businessprocess.ImportFileBP; import org.eclipse.jubula.client.ui.rcp.businessprocess.ProblemsBP; import org.eclipse.jubula.client.ui.rcp.businessprocess.ToolkitBP; import org.eclipse.jubula.client.ui.rcp.controllers.TestExecutionContributor; import org.eclipse.jubula.client.ui.rcp.controllers.dnd.LocalSelectionClipboardTransfer; import org.eclipse.jubula.client.ui.rcp.editors.AbstractJBEditor; import org.eclipse.jubula.client.ui.rcp.editors.AbstractTestCaseEditor; import org.eclipse.jubula.client.ui.rcp.editors.IJBEditor; import org.eclipse.jubula.client.ui.rcp.editors.TestJobEditor; import org.eclipse.jubula.client.ui.rcp.i18n.Messages; import org.eclipse.jubula.client.ui.rcp.provider.contentprovider.DirtyStarListContentProvider; import org.eclipse.jubula.client.ui.rcp.provider.labelprovider.DirtyStarListLabelProvider; import org.eclipse.jubula.client.ui.rcp.search.query.AbstractQuery; import org.eclipse.jubula.client.ui.rcp.utils.Utils; import org.eclipse.jubula.client.ui.rcp.widgets.StatusLineContributionItem; import org.eclipse.jubula.client.ui.utils.ErrorHandlingUtil; import org.eclipse.jubula.client.ui.views.IJBPart; import org.eclipse.jubula.tools.internal.constants.EnvConstants; import org.eclipse.jubula.tools.internal.constants.StringConstants; import org.eclipse.jubula.tools.internal.exception.JBException; import org.eclipse.jubula.tools.internal.exception.JBFatalException; import org.eclipse.jubula.tools.internal.exception.JBRuntimeException; import org.eclipse.jubula.tools.internal.i18n.CompSystemI18n; import org.eclipse.jubula.tools.internal.messagehandling.MessageIDs; import org.eclipse.jubula.tools.internal.utils.EnvironmentUtils; import org.eclipse.jubula.tools.internal.utils.IsAliveThread; import org.eclipse.osgi.util.NLS; import org.eclipse.search.ui.IQueryListener; import org.eclipse.search.ui.ISearchQuery; import org.eclipse.search.ui.NewSearchUI; import org.eclipse.search2.internal.ui.SearchView; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorReference; import org.eclipse.ui.IViewPart; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.console.ConsolePlugin; import org.eclipse.ui.console.IConsole; import org.eclipse.ui.console.MessageConsole; import org.eclipse.ui.console.MessageConsoleStream; import org.eclipse.ui.dialogs.ListSelectionDialog; import org.eclipse.ui.help.IWorkbenchHelpSystem; import org.eclipse.ui.internal.WorkbenchWindow; import org.eclipse.ui.part.EditorPart; import org.eclipse.ui.part.IContributedContentsView; import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.plugin.AbstractUIPlugin; import org.eclipse.ui.preferences.ScopedPreferenceStore; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Base class for plug-ins that integrate with the Eclipse platform UI. * * @author BREDEX GmbH * @created 06.07.2004 */ public class Plugin extends AbstractUIPlugin implements IProgressConsole { /** plugin id */ public static final String PLUGIN_ID = "org.eclipse.jubula.client.ui.rcp"; //$NON-NLS-1$ /** test style plugin id */ public static final String TEST_STYLE_PLUGIN_ID = "org.eclipse.jubula.client.teststyle"; //$NON-NLS-1$ /** maps images to their "generated" (green-tinted) counterparts */ public static final Map<Image, Image> GENERATED_IMAGES = new HashMap<Image, Image>(); /** maps images to their "cutted" (grey-tinted) counterparts */ public static final Map<Image, Image> GRAYED_IMAGES = new HashMap<Image, Image>(); /** * @param original The original, or base, image. * @return the "cut" version of the image. Client should not * dispose this image. */ public static final Image TC_DISABLED_IMAGE = new Image( IconConstants.TC_IMAGE.getDevice(), IconConstants.TC_IMAGE, SWT.IMAGE_GRAY); /** name of the Jubula console */ private static final String JB_CONSOLE_NAME = "Console"; //$NON-NLS-1$ /** for log messages */ private static Logger log = LoggerFactory.getLogger(Plugin.class); /** single instance of plugin */ private static Plugin plugin; /** StatusLineText */ private static String statusLineText = Messages.StatusLine_NotConnected; /** StatusLineText */ private static int connectionStatusIcon = Constants.DEFAULT_ICON; /** current workbench window */ private static IWorkbenchWindow workbenchWindow; /** <code>CONNECTION_INFO_STATUSLINE_ITEM</code> */ private static final String CONNECTION_INFO_STATUSLINE_ITEM = "connectionInfo"; //$NON-NLS-1$ /** <code>AUT_TOOLKIT_STATUSLINE_ITEM</code> */ private static final String AUT_TOOLKIT_STATUSLINE_ITEM = "autToolKitInfo"; //$NON-NLS-1$ /** Connection console name **/ private static final String CONNECTION_CONSOLE_NAME = "Connection:"; //$NON-NLS-1$ /** the client status */ private ClientStatus m_status = ClientStatus.STARTING; /** the preference store for this bundle */ private ScopedPreferenceStore m_preferenceStore = null; /** the console */ private MessageConsole m_console; /** standard message stream for the console */ private MessageConsoleStream m_standardMessageStream; /** error message stream for the console */ private MessageConsoleStream m_errorMessageStream; /** warning message stream for the console */ private MessageConsoleStream m_warningMessageStream; /** the currently running application title */ private String m_runningApplicationTitle = null; /** the DataChangedListener which listens for a project*/ private IDataChangedListener m_projectLifecycleLister = null; /** aut agent disconnect listener, which closes the progress console(s) */ private IServerEventListener m_agentCloseListener = new IServerEventListener() { @Override public void stateChanged(AutAgentEvent event) { if (event.getState() == ServerEvent.CONNECTION_CLOSED) { ProgressConsoleRegistry.INSTANCE.getConsole().closeConsole(); } } }; static { GENERATED_IMAGES.put(IconConstants.TC_IMAGE, IconConstants.getImage("testCase_generated.gif")); //$NON-NLS-1$ GENERATED_IMAGES.put(IconConstants.TC_REF_IMAGE, IconConstants.getImage("testCaseRef_generated.gif")); //$NON-NLS-1$ GENERATED_IMAGES.put(IconConstants.CATEGORY_IMAGE, IconConstants.getImage("category_generated.gif")); //$NON-NLS-1$ } /** * Creates an UI plug-in runtime object */ public Plugin() { super(); } /** * The Client Status */ public enum ClientStatus { /** * Jubula is launched completely */ RUNNING, /** * Jubula is starting up */ STARTING, /** * Jubula is shutting down */ STOPPING } /** * * @param statust - the new ClientStatus (RUNNING,STOPPING,STARTING) */ public void setClientStatus(ClientStatus statust) { m_status = statust; } /** * * @return the actual ClientStatus (RUNNING,STARTING,STOPPING) */ public ClientStatus getClientStatus() { return m_status; } /** * {@inheritDoc} */ public void stop(BundleContext context) throws Exception { super.stop(context); if (m_projectLifecycleLister != null) { DataEventDispatcher.getInstance().removeDataChangedListener( m_projectLifecycleLister); } ProgressConsoleRegistry.INSTANCE.deregister(); ClientTest.instance().removeAutAgentEventListener(m_agentCloseListener); } /** * {@inheritDoc} */ public IPreferenceStore getPreferenceStore() { // Create the preference store lazily. if (m_preferenceStore == null) { // Use the Plugin ID from org.eclipse.jubula.client.ui so that // preferences will continue to be saved to that area. Otherwise, // users would lose their preferences after the UI bundle was split // into client.ui and client.ui.rcp. m_preferenceStore = new ScopedPreferenceStore( InstanceScope.INSTANCE, Constants.PLUGIN_ID); } return m_preferenceStore; } /** * @return The display. */ public static Display getDisplay() { return PlatformUI.getWorkbench().getDisplay(); } /** * Sets a text in the Status Line * @param text String */ private static void setStatusLineText(String text) { statusLineText = text; showStatusLine(null); } /** * Gets Status Line Text * @return String StatusLine m_text */ public static String getStatusLineText() { return statusLineText; } /** * Displays a text in the Status Line * @param text String * @param ampel String */ public static void showStatusLine(final int ampel, final String text) { Display.getDefault().asyncExec(new Runnable() { @SuppressWarnings("synthetic-access") public void run() { setConnectionStatusIcon(ampel); setStatusLineText(text); } }); } /** * Displays a m_text in the Status Line * @param partFocused IWorkbenchPart */ public static void showStatusLine(IWorkbenchPart partFocused) { IWorkbench workbench = getDefault().getWorkbench(); IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); if (getActivePage() == null && partFocused == null) { return; } IWorkbenchPart part; if (partFocused != null) { part = partFocused; } else { part = getActivePart(); } IStatusLineManager manager = ((WorkbenchWindow)window) .getStatusLineManager(); if (part instanceof ViewPart) { manager = ((ViewPart)part).getViewSite().getActionBars() .getStatusLineManager(); } else if (part instanceof EditorPart) { manager = ((EditorPart)part).getEditorSite().getActionBars() .getStatusLineManager(); } if (window instanceof WorkbenchWindow) { StatusLineContributionItem item = (StatusLineContributionItem)manager.find( CONNECTION_INFO_STATUSLINE_ITEM); if (item == null) { if (getDefault().getWorkbench().getActiveWorkbenchWindow() != null) { createStatusLineItems(); item = (StatusLineContributionItem)manager.find( CONNECTION_INFO_STATUSLINE_ITEM); } if (item == null) { return; } } switch (isConnectionStatusIcon()) { case Constants.NO_SERVER: item.setMessage(IconConstants.NO_SERVER_IMAGE, getStatusLineText()); break; case Constants.NO_SC: case Constants.NO_AUT: item.setMessage(IconConstants.NO_CONNECTION_IMAGE, getStatusLineText()); break; case Constants.AUT_UP: item.setMessage(IconConstants.AUT_RUNNING_IMAGE, getStatusLineText()); break; case Constants.RECORDING: item.setMessage(IconConstants.CAM_IMAGE, getStatusLineText()); break; case Constants.CHECKING: item.setMessage(IconConstants.CHECK_CAM_IMAGE, getStatusLineText()); break; case Constants.MAPPING: item.setMessage(IconConstants.MAP_IMAGE, getStatusLineText()); break; case Constants.PAUSED: item.setMessage(IconConstants.PAUSE_IMAGE, getStatusLineText()); break; default: item.setMessage(IconConstants.NO_AUT_IMAGE, getStatusLineText()); } manager.update(true); } } /** * Returns the active View or null. * @return a <code>ViewPart</code> value. The active View. */ public static ViewPart getActiveView() { IWorkbenchPart view = getActivePart(); if (view instanceof ViewPart) { return (ViewPart)view; } return null; } /** * Returns the active editor or null. * @return a <code>EditorPart</code> value. The active Editor. */ public static IEditorPart getActiveEditor() { final IWorkbenchPage activePage = getActivePage(); if (activePage == null) { return null; } final IEditorPart editor = activePage.getActiveEditor(); if (editor != null) { return editor; } // If a view is maximized, getActiveEditor() returns null. // So lets ask all IJBEditors. final IEditorReference[] editorReferences = activePage .getEditorReferences(); for (IEditorReference edRef : editorReferences) { final IEditorPart editorPart = edRef.getEditor(false); if (editorPart instanceof IJBEditor) { IJBEditor gdEd = (IJBEditor)editorPart; if (gdEd.getEditorHelper().isActive()) { return gdEd; } } } return null; } /** * @return all references to open editors. */ public static List < IEditorReference > getAllEditors() { if (getActivePage() == null) { return new ArrayList < IEditorReference > (); } IEditorReference[] editors = getActivePage().getEditorReferences(); List < IEditorReference > editorList = new ArrayList < IEditorReference > (); for (IEditorReference editor : editors) { if (editor.getId().equals(Constants.TEST_CASE_EDITOR_ID) || editor.getId().equals(Constants.OBJECTMAPPINGEDITOR_ID) || editor.getId().equals(Constants.TEST_SUITE_EDITOR_ID)) { editorList.add(editor); } } return editorList; } /** * clear clipboard on all editors */ public static void clearAllEditorsClipboard() { for (IEditorReference editorRef : getAllEditors()) { IEditorPart editorPart = editorRef.getEditor(true); if (editorPart instanceof AbstractJBEditor) { ((AbstractJBEditor)editorPart).getEditorHelper().getClipboard() .clearContents(); } } LocalSelectionClipboardTransfer.getInstance() .setSelection(null, false); } /** * Returns the active part or null. * @return an <code>IWorkbenchPart</code> value. The active part. */ public static IWorkbenchPart getActivePart() { if (getActivePage() != null) { return getActivePage().getActivePart(); } return null; } /** * Returns the active page or null. * @return an <code>IWorkbenchPage</code> value. The active page. */ public static IWorkbenchPage getActivePage() { IWorkbenchWindow ww = PlatformUI.getWorkbench() .getActiveWorkbenchWindow(); if (ww == null) { return null; } return ww.getActivePage(); } /** * @param id The ID of the view to find. * @return A <code>IViewReference</code> value. The view or null. **/ @Deprecated public static IViewPart getView(String id) { Validate.notEmpty(id, Messages.Missing_ID); if (getActivePage() != null) { IViewPart vp = getActivePage().findView(id); return vp; } return null; } /** * Writes a line of text to the console. * * @param msg the message to print. * @param forceActivate whether the console should be activated if it is not * already open. */ public void writeLineToConsole(String msg, boolean forceActivate) { // FIXME zeb this "if" statement is necessary because the DB Tool, which never // starts the workbench because it never intends to use PlatformUI, // depends on and uses methods from org.eclipse.jubula.client.ui.rcp. // Thus, these dependencies should be removed, and then the "if" // statement should thereafter also be removed. if (PlatformUI.isWorkbenchRunning()) { MessageConsoleStream stream = getStandardConsoleStream(); if (forceActivate) { stream.getConsole().activate(); } stream.println(msg); } } /** * Writes the given line to the given console * * @param console the console * @param msg the text * @param forceActivate if this is true than activate will be called on the console */ public void writeLineToConsole(MessageConsole console, String msg, boolean forceActivate) { // FIXME zeb this "if" statement is necessary because the DB Tool, which never // starts the workbench because it never intends to use PlatformUI, // depends on and uses methods from org.eclipse.jubula.client.ui.rcp. // Thus, these dependencies should be removed, and then the "if" // statement should thereafter also be removed. if (PlatformUI.isWorkbenchRunning()) { MessageConsoleStream stream = console.newMessageStream(); if (forceActivate) { stream.getConsole().activate(); } stream.println(msg); } } /** * Writes a line of text to the console. * * @param msg the message to print. * @param forceActivate whether the console should be activated if it is not * already open. */ public void writeErrorLineToConsole(String msg, boolean forceActivate) { // FIXME zeb this "if" statement is necessary because the DB Tool, which never // starts the workbench because it never intends to use PlatformUI, // depends on and uses methods from ClientGUI. // Thus, these dependencies should be removed, and then the "if" // statement should thereafter also be removed. if (PlatformUI.isWorkbenchRunning()) { MessageConsoleStream stream = getErrorConsoleStream(); if (forceActivate) { stream.getConsole().activate(); } stream.println(msg); } } /** * Lazy retrieval of the standard message console stream. * * @return the standard message stream for the console */ private synchronized MessageConsoleStream getStandardConsoleStream() { if (m_standardMessageStream == null) { m_standardMessageStream = getConsole().newMessageStream(); } return m_standardMessageStream; } /** * Lazy retrieval of the error message console stream. * * @return the error message stream for the console */ private synchronized MessageConsoleStream getErrorConsoleStream() { if (m_errorMessageStream == null) { m_errorMessageStream = getConsole().newMessageStream(); final Display d = getDisplay(); final MessageConsoleStream stream = m_errorMessageStream; d.syncExec(new Runnable() { public void run() { stream.setColor(d.getSystemColor(SWT.COLOR_RED)); } }); } return m_errorMessageStream; } /** * Lazy retrieval of the console. * * @return the console */ private synchronized MessageConsole getConsole() { if (m_console == null) { m_console = new MessageConsole(JB_CONSOLE_NAME, null); m_console.activate(); ConsolePlugin.getDefault().getConsoleManager().addConsoles( new IConsole [] {m_console}); } return m_console; } /** * Return the console with the given name or creates a new one * @param name the name of the console * @return the console */ private synchronized MessageConsole getConsole(String name) { IConsole[] cons = ConsolePlugin.getDefault().getConsoleManager() .getConsoles(); for (IConsole c : cons) { if (c.getName().equals(CONNECTION_CONSOLE_NAME + name) && c instanceof MessageConsole) { return (MessageConsole) c; } } MessageConsole console = new MessageConsole(CONNECTION_CONSOLE_NAME + name, null); ConsolePlugin.getDefault().getConsoleManager() .addConsoles(new IConsole[] { console }); return console; } /** * Shows the view with the given id. * @param id The ID of the view to show. * @return the View. */ public static IViewPart showView(String id) { return showView(id, null, IWorkbenchPage.VIEW_ACTIVATE); } /** * Shows the view with the given id. * * @see org.eclipse.ui.IWorkbenchPage.showView * * @param viewID * The ID of the view to show. * @param secondaryViewID * the secondaryViewID * @param mode * the view mode * @return the View. */ public static IViewPart showView(String viewID, String secondaryViewID, int mode) { Validate.notEmpty(viewID, Messages.Missing_ID); if (getActivePage() != null) { IViewPart vp = null; try { vp = getActivePage().showView(viewID, secondaryViewID, mode); } catch (PartInitException e) { ErrorHandlingUtil.createMessageDialog(new JBException( NLS.bind(Messages.PluginCantOpenView + viewID, MessageIDs.E_CLASS_NOT_FOUND), null, null)); } return vp; } return null; } /** * activates the given workbench part if an active page is available * * @param part * the part to activate */ public static void activate(IWorkbenchPart part) { if (getActivePage() != null) { getActivePage().activate(part); } } /** * @return Returns the connectionStatusIcon. */ public static int isConnectionStatusIcon() { return connectionStatusIcon; } /** * @param aS The ampelStatus to set. */ private static void setConnectionStatusIcon(int aS) { connectionStatusIcon = aS; showStatusLine(null); } /** * Gets the Editor by title * @param title the title of the editor * @return an IWorkbenchPart, the editor or null if not found. */ public static IEditorPart getEditorByTitle(String title) { IEditorReference[] editors = getActivePage().getEditorReferences(); for (int i = 0; i < editors.length; i++) { String edTitle = editors[i].getTitle(); if (title.equals(edTitle)) { return (IEditorPart)editors[i].getPart(false); } } return null; } /** * Checks if a view with the given ID is open. * @param id The ID of the view. * @return a <code>boolean</code> value. */ public static boolean isViewOpen(String id) { return getView(id) != null; } /** * @return An array of IEditorParts. */ public IEditorPart[] getDirtyEditors() { if (getActivePage() != null) { return getActivePage().getDirtyEditors(); } return new IEditorPart[0]; } /** * @return the active Jubula editor or null if no Jubula editor is active */ public AbstractJBEditor getActiveJBEditor() { IWorkbenchPage activePage = getActivePage(); if (activePage == null) { // during shutdown return null; } IEditorPart iEditorPart = getActiveEditor(); if (iEditorPart != null && iEditorPart instanceof AbstractJBEditor) { return (AbstractJBEditor) iEditorPart; } return null; } /** * @return the active TestCaseEditor or null if no TC editor is active */ public AbstractTestCaseEditor getActiveTCEditor() { if (getActiveJBEditor() instanceof AbstractTestCaseEditor) { return (AbstractTestCaseEditor)getActiveJBEditor(); } return null; } /** * @return the active TestJobEditor or null if no TJ editor is active */ public TestJobEditor getActiveTJEditor() { IWorkbenchPage activePage = getActivePage(); if (activePage == null) { // during shutdown return null; } IEditorPart iEditorPart = getActiveEditor(); if (iEditorPart != null && iEditorPart instanceof TestJobEditor) { return (TestJobEditor)iEditorPart; } return null; } /** * Closes all opened Jubula editors (ex. TCE, TSE, OME). This method must be * called from the GUI thread. If it is called from a thread that is *not* * the GUI thread, it will do nothing. * * @param alsoProjectIndependent * whether also project independent editors should be closed such * as the testresultviewer */ public static void closeAllOpenedJubulaEditors( boolean alsoProjectIndependent) { IWorkbenchPage activePage = getActivePage(); if (activePage != null) { List<IEditorReference> editorParts = getAllOpenedJubulaEditors( alsoProjectIndependent); activePage.closeEditors( editorParts.toArray( new IEditorReference[editorParts.size()]), false); } } /** * @param original The original, or base, image. * @return the "generated" version of the image. Client should not * dispose this image. */ public static Image getGeneratedImage(Image original) { Image genImage = GENERATED_IMAGES.get(original); if (genImage == null) { log.error("'Generated' image does not exist."); //$NON-NLS-1$ genImage = original; } return genImage; } /** * * @param original The original, or base, image. * @return the "cut" version of the image. Client should not * dispose this image. */ public static Image getCutImage(Image original) { Image cutImage = GRAYED_IMAGES.get(original); if (cutImage == null) { cutImage = new Image(original.getDevice(), original, SWT.IMAGE_GRAY); GRAYED_IMAGES.put(original, cutImage); } return cutImage; } /** * @param alsoProjectIndependent * True, if also project independent editors should be collected such * as the test result viewer, otherwise false. * @return A set of editor references of all opened Jubula editors (i.e. TCE, TSE, OME), * or an empty set. If this method is not called from the GUI thread, the set is empty. */ private static List<IEditorReference> getAllOpenedJubulaEditors( boolean alsoProjectIndependent) { List<IEditorReference> editorRefs = new ArrayList<IEditorReference>(); IWorkbenchPage activePage = getActivePage(); if (activePage != null) { for (IEditorReference editorRef: activePage.getEditorReferences()) { IEditorPart editor = editorRef.getEditor(true); if (editor instanceof IJBPart) { if (alsoProjectIndependent || !(editor instanceof TestResultViewer)) { editorRefs.add(editorRef); } } } } return editorRefs; } /** * * @return the shell for the active workbench window. Note that dialogs are * not workbench windows. */ public static Shell getActiveWorkbenchWindowShell() { return PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); } /** * This method does not necessarily return the active shell. Rather, * it returns the 0th shell in the display's shell array. * * @return The actual shell. */ public static Shell getShell() { return (PlatformUI.getWorkbench().getDisplay().getShells())[0]; } /** * checks, if any editor was not saved before starting the AUT * @return true, if there are unsaved m_editors, false otherwise */ public boolean anyDirtyStar() { return !getProjectDependentDirtyEditors().isEmpty(); } /** * @return A list of project dependent dirty editors. */ private List<IEditorReference> getProjectDependentDirtyEditors() { List<IEditorReference> dirtyEditors = new ArrayList<IEditorReference>(); for (IEditorReference editorRef: getAllOpenedJubulaEditors(false)) { if (editorRef.isDirty()) { dirtyEditors.add(editorRef); } } return dirtyEditors; } /** * Opens the {@link ListSelectionDialog} with a preselected list of all * project dependent dirty editors. If the list is empty, the dialog is not * shown. * * @param parentShell * the parent shell to show the dialog for * @return True, if there are not dirty editors or all preselected dirty * editors have been saved, otherwise false. */ public boolean showSaveEditorDialog(Shell parentShell) { return showSaveEditorDialogWithMessage( Messages.SelectEditorsToSave, parentShell); } /** * Opens the {@link ListSelectionDialog} with a preselected list of all * project dependent dirty editors. If the list is empty, the dialog is not * shown. * * @param parentShell * the parent shell to show the dialog for * @param msg * the message to display * @return True, if there are not dirty editors or all preselected dirty * editors have been saved, otherwise false. */ public boolean showSaveEditorDialogWithMessage(String msg, Shell parentShell) { List<IEditorReference> dirtyEditors = getProjectDependentDirtyEditors(); boolean hasDirtyEditors = !dirtyEditors.isEmpty(); if (hasDirtyEditors) { ListSelectionDialog dialog = new ListSelectionDialog(parentShell, dirtyEditors.toArray(), new DirtyStarListContentProvider(), new DirtyStarListLabelProvider(), msg); dialog.setTitle(Messages.SaveEditorsTitle); dialog.setInitialElementSelections(dirtyEditors); dialog.open(); if (dialog.getReturnCode() == Window.OK) { // save all selected editors Object[] editorRefs = dialog.getResult(); if (editorRefs != null) { for (Object editorObj : editorRefs) { if (editorObj instanceof IEditorReference) { IEditorReference editorRef = (IEditorReference) editorObj; IEditorPart editorPart = editorRef.getEditor(true); editorPart.doSave(new NullProgressMonitor()); } } } hasDirtyEditors = !getProjectDependentDirtyEditors() .isEmpty(); } } setNormalCursor(); return !hasDirtyEditors; } /** Sets the hour glass cursor. */ private static void setWaitCursor() { getDisplay().syncExec(new Runnable() { public void run() { getActiveWorkbenchWindowShell().setCursor( getDisplay().getSystemCursor(SWT.CURSOR_WAIT)); } }); } /** Sets the normal (=arrow) cursor. */ private static void setNormalCursor() { getDisplay().syncExec(new Runnable() { public void run() { getActiveWorkbenchWindowShell().setCursor( getDisplay().getSystemCursor(SWT.CURSOR_ARROW)); } }); } /** * @return IWorkbenchHelpSystem. */ public static IWorkbenchHelpSystem getHelpSystem() { return PlatformUI.getWorkbench().getHelpSystem(); } /** * {@inheritDoc} */ public Object handleError(final Throwable e) { Plugin.getDisplay().asyncExec(new Runnable() { @SuppressWarnings("synthetic-access") public void run() { if (e instanceof RuntimeException && OperationCanceledUtil.isOperationCanceled( (RuntimeException)e)) { // root cause of exception is the cancellation of an // operation, so it can be safely ignored return; } log.error(Messages.UnhandledThrowable + StringConstants.SPACE + StringConstants.COLON + StringConstants.SPACE, e); if (e instanceof JBRuntimeException) { JBRuntimeException gdEx = (JBRuntimeException)e; ErrorHandlingUtil.createMessageDialog(gdEx); } else if (e instanceof JBException) { JBException gdEx = (JBException)e; ErrorHandlingUtil.createMessageDialog(gdEx, null, null); } else if (isRCPException(e)) { // there are a few bugs in RCP which will trigger // an exception, notably the // org.eclipse.ui.views.markers.internal.MarkerAdapter.buildAllMarkers() // well known racing condition. Since the error is not // critical, is is ignored. log.error(Messages.InternalRcpError, e); } else if (isGEFException(e)) { // there are a few bugs in GEF which will trigger // an exception, notably the // org.eclipse.gmf.runtime.diagram.ui.tools.DragEditPartsTrackerEx.addSourceCommands // well known racing condition. Since the error is not // critical, is is ignored. log.error(Messages.InternalGefError, e); } else if (e instanceof PersistenceException) { ErrorHandlingUtil.createMessageDialog( MessageIDs.E_DATABASE_GENERAL, null, new String [] {e.getLocalizedMessage()}); } else { ErrorHandlingUtil.createMessageDialog( new JBFatalException(e, MessageIDs.E_UNEXPECTED_EXCEPTION)); } } }); return null; } /** * checks if the exception is caused by a known RCP problem * @param t the Throwable which was caught in the error handler * @return true if the exception was cause by an RCP bug */ public static boolean isRCPException(Throwable t) { Throwable work = t; do { StackTraceElement[] stack = work.getStackTrace(); for (StackTraceElement el : stack) { String className = el.getClassName(); // check for // org.eclipse.ui.views.markers.internal.MarkerAdapter.buildAllMarkers if (className.indexOf("MarkerAdapter") != -1) { //$NON-NLS-1$ return true; } // double click error in help view if (className.indexOf("EngineResultSection") != -1) { //$NON-NLS-1$ return true; } // Context Sensitive Help when DSV Cell Editor is open #3291 if (className.indexOf("ContextHelpPart") != -1) { //$NON-NLS-1$ return true; } // http://bugzilla.bredex.de/84 if (className.indexOf("CompositeImageDescriptor") != -1) { //$NON-NLS-1$ return true; } // http://bugzilla.bredex.de/933 if (className.indexOf("EditorStateParticipant") != -1) { //$NON-NLS-1$ return true; } // http://bugzilla.bredex.de/1258 if (className.indexOf("LightweightDecoratorManager") != -1) { //$NON-NLS-1$ return true; } } // Recursive activation on MacOSX on expand tree item #3618 String detailMessage = work.getMessage(); if (detailMessage != null && detailMessage.indexOf("WARNING: Prevented recursive attempt to activate part") != -1) { //$NON-NLS-1$ return true; } work = work.getCause(); } while (work != null); return false; } /** * checks if the exception is caused by a known Content Assist problem * @param t the Throwable which was caught in the error handler * @return true if the exception was cause by a known Content Assist bug */ public static boolean isContentAssistException(Throwable t) { Throwable work = t; do { if (work instanceof NullPointerException) { StackTraceElement[] stack = work.getStackTrace(); for (StackTraceElement el : stack) { // check for // NPE in recomputeProposals if (Messages.RecomputeProposals. equals(el.getMethodName())) { return true; } } } work = work.getCause(); } while (work != null); return false; } /** * checks if the exception is caused by a known GEF problem * @param t the Throwable which was caught in the error handler * @return true if the exception was cause by an GEF bug */ public static boolean isGEFException(Throwable t) { Throwable work = t; do { StackTraceElement[] stack = work.getStackTrace(); for (StackTraceElement el : stack) { // check for // org.eclipse.gmf.runtime.diagram.ui.tools.DragEditPartsTrackerEx.addSourceCommands if (el.getClassName().indexOf("DragEditPartsTrackerEx") != -1) { //$NON-NLS-1$ return true; } } work = work.getCause(); } while (work != null); return false; } /** * {@inheritDoc} */ public void start(BundleContext context) throws Exception { super.start(context); plugin = this; ErrorMessagePresenter.setPresenter(new IErrorMessagePresenter() { public void showErrorMessage(JBException ex, Object[] params, String[] details) { ErrorHandlingUtil.createMessageDialog(ex, params, details); } public void showErrorMessage(Integer messageID, Object[] params, String[] details) { ErrorHandlingUtil.createMessageDialog( messageID, params, details); } }); new IsAliveThread(new Runnable() { public void run() { // init (java)available languages Languages.getInstance(); } }).start(); registerPermanentServices(); m_projectLifecycleLister = new IDataChangedListener() { public void handleDataChanged(DataChangedEvent... events) { for (DataChangedEvent event : events) { if (event.getPo() instanceof IProjectPO && event.getDataState() == DataState.Deleted) { Utils.clearClient(false); GeneralStorage.getInstance().nullProject(); } } } }; DataEventDispatcher.getInstance().addDataChangedListener( m_projectLifecycleLister, true); ProgressConsoleRegistry.INSTANCE.register(this); ClientTest.instance().addAutAgentEventListener(m_agentCloseListener); parseCommandLine(); } /** * Parses the command line for some options */ private void parseCommandLine() { String[] args = Platform.getCommandLineArgs(); String ip = EnvironmentUtils.getArgValue(args, EnvConstants.CLIENTIP_KEY); if (StringUtils.isNotEmpty(ip)) { System.setProperty(EnvConstants.CLIENTIP_KEY, ip); } String port = EnvironmentUtils.getArgValue(args, EnvConstants.CLIENTPORT_KEY); if (StringUtils.isNotEmpty(port)) { System.setProperty(EnvConstants.CLIENTPORT_KEY, port); } } /** * register business processes and service that should be available * while complete Jubula life cycle * - ProgressController * - ComponentNamesListBP */ private void registerPermanentServices() { // register problem view listeners ProblemsBP.getInstance(); // register AutStarter, AutServer, and test listeners TestExecutionContributor.getInstance(); CommentReporter instance = CommentReporter.getInstance(); instance.setConsole(this); propagateDataDir(); Plugin.getDefault().getPreferenceStore().addPropertyChangeListener( new IPropertyChangeListener() { public void propertyChange(PropertyChangeEvent event) { propagateDataDir(); } }); // register search result updater registerSearchResultListener(); ImportFileBP.getInstance(); // register service for checking completeness CompletenessBP.getInstance(); // register service for toolkit ToolkitBP.getInstance(); try { Platform.getBundle(TEST_STYLE_PLUGIN_ID).start(); } catch (BundleException e) { e.printStackTrace(); } } /** * displays the auttoolkit * @param toolkit the aut ToolKit of the actual project. */ public static void showAutToolKitInfo(String toolkit) { IStatusLineManager manager = getStatusLineManager(); StatusLineContributionItem item = (StatusLineContributionItem)manager .find(AUT_TOOLKIT_STATUSLINE_ITEM); if (item == null) { return; } item.setText(CompSystemI18n.getString(toolkit)); manager.update(true); } /** * create the items for the status line */ public static void createStatusLineItems() { IStatusLineManager manager = getStatusLineManager(); StatusLineContributionItem connectionItem = new StatusLineContributionItem( CONNECTION_INFO_STATUSLINE_ITEM); manager.insertBefore(StatusLineManager.END_GROUP, connectionItem); StatusLineContributionItem autToolKitItem = new StatusLineContributionItem(AUT_TOOLKIT_STATUSLINE_ITEM); autToolKitItem.setText(StringConstants.EMPTY); manager.insertBefore(CONNECTION_INFO_STATUSLINE_ITEM, autToolKitItem); manager.update(true); } /** * @return the status line manager of the current workbench window */ public static IStatusLineManager getStatusLineManager() { IWorkbench workbench = getDefault().getWorkbench(); workbenchWindow = workbench.getActiveWorkbenchWindow(); if (workbenchWindow == null) { Display.getDefault().syncExec(new Runnable() { @SuppressWarnings("synthetic-access") public void run() { Shell shell = getShell(); while (shell != null) { Object data = shell.getData(); if (data instanceof IWorkbenchWindow) { workbenchWindow = (IWorkbenchWindow) data; break; } shell = (Shell)shell.getParent(); } } }); } IStatusLineManager manager = ((WorkbenchWindow)workbenchWindow) .getStatusLineManager(); return manager; } /** * Resets the status line and mousecursor after a long running operation. */ public static void stopLongRunning() { Display.getDefault().syncExec(new Runnable() { @SuppressWarnings("synthetic-access") public void run() { getStatusLineManager().setErrorMessage(null); setNormalCursor(); } }); } /** * Sets the given message in the status line and the mousecursor (hourglass) * when a long running operation starts. * * @param message the message to set */ public static void startLongRunning(final String message) { Display.getDefault().syncExec(new Runnable() { public void run() { getStatusLineManager().setErrorMessage( IconConstants.LONG_RUNNING_IMAGE, message); startLongRunning(); } }); } /** * Sets the mousecursor (hourglass) when a long running operation starts. * The status line is ignored by this method. */ public static void startLongRunning() { Display.getDefault().syncExec(new Runnable() { @SuppressWarnings("synthetic-access") public void run() { setWaitCursor(); } }); } /** * * @return the component cache corresponding to the active editor, or * the master session cache if the active editor has no * coresponding cache or if no editor is currently active. */ public static IComponentNameCache getActiveCompCache() { IWorkbenchPart activePart = Plugin.getActivePart(); if (activePart instanceof IContributedContentsView) { activePart = ((IContributedContentsView)activePart).getContributingPart(); } IComponentNameCache cache = null; if (activePart != null) { cache = activePart.getAdapter(IComponentNameCache.class); } if (cache != null) { return cache; } return CompNameManager.getInstance(); } /** * {@inheritDoc} */ public void writeErrorLine(String line) { writeErrorLineToConsole(line, true); } /** {@inheritDoc} */ public void writeWarningLine(String line) { writeWarningLineToConsole(line, true); } /** * Writes a line of text to the console. * * @param msg the message to print. * @param forceActivate whether the console should be activated if it is not * already open. */ public void writeWarningLineToConsole(String msg, boolean forceActivate) { // FIXME zeb this "if" statement is necessary because the DB Tool, which never // starts the workbench because it never intends to use PlatformUI, // depends on and uses methods from ClientGUI. // Thus, these dependencies should be removed, and then the "if" // statement should thereafter also be removed. if (PlatformUI.isWorkbenchRunning()) { MessageConsoleStream stream = getWarningConsoleStream(); if (forceActivate) { stream.getConsole().activate(); } stream.println(msg); } } /** * Lazy retrieval of the warning message console stream. * * @return the warning message stream for the console */ private synchronized MessageConsoleStream getWarningConsoleStream() { if (m_warningMessageStream == null) { m_warningMessageStream = getConsole().newMessageStream(); final Display d = getDisplay(); final MessageConsoleStream stream = m_warningMessageStream; d.syncExec(new Runnable() { public void run() { stream.setColor(d.getSystemColor(SWT.COLOR_DARK_YELLOW)); } }); } return m_warningMessageStream; } /** * {@inheritDoc} */ public void writeLine(String line) { writeLineToConsole(line, true); } @Override public void writeStatus(IStatus status) { writeStatus(status, null); } /** * Prints the given status in the given console * @param status the status * @param c the console * @param activate set this to true if you want to activate this console */ private void printStatus(IStatus status, MessageConsole c, boolean activate) { List<IStatus> statuus = new ArrayList<IStatus>(); statuus.add(status); if (status.isMultiStatus()) { statuus.addAll(Arrays.asList(status.getChildren())); } for (IStatus message : statuus) { writeLineToConsole(c, StringHelper.getStringOf( status, false), activate); } } @Override public void writeStatus(IStatus status, String id) { MessageConsole c = id != null ? getConsole(id) : getConsole(); boolean activate = false; //Only activate console if the status is a warning or error if (status.isMultiStatus()) { for (IStatus s : status.getChildren()) { if (!s.isOK()) { activate = true; break; } } } else { activate = !status.isOK(); } printStatus(status, c, activate); } @Override public void closeConsole() { ConsolePlugin consolePlugin = ConsolePlugin.getDefault(); if (consolePlugin != null && consolePlugin.getConsoleManager() != null) { IConsole[] cons = ConsolePlugin.getDefault().getConsoleManager() .getConsoles(); ArrayList<IConsole> toRemove = new ArrayList<IConsole>(); for (IConsole c : cons) { if (c.getName().contains(CONNECTION_CONSOLE_NAME) && c instanceof MessageConsole) { toRemove.add(c); } } ConsolePlugin.getDefault().getConsoleManager().removeConsoles( toRemove.toArray(new IConsole[toRemove.size()])); } } /** * @return the running application title */ public String getRunningApplicationTitle() { if (m_runningApplicationTitle == null) { m_runningApplicationTitle = getActiveWorkbenchWindowShell() .getText(); } return m_runningApplicationTitle; } /** * register listener to display new AbstractSearchQuery results */ private void registerSearchResultListener() { NewSearchUI.addQueryListener(new IQueryListener() { /** {@inheritDoc} */ public void queryAdded(ISearchQuery query) { // handle if necessary } /** {@inheritDoc} */ public void queryFinished(final ISearchQuery query) { if (query instanceof AbstractQuery) { PlatformUI.getWorkbench().getDisplay().syncExec( new Runnable() { public void run() { // see // http://eclip.se/72661 and // http://eclip.se/72771 SearchView sv = (SearchView)Plugin .getView(NewSearchUI.SEARCH_VIEW_ID); if (sv != null) { sv.showSearchResult(query .getSearchResult()); } } }); } } /** {@inheritDoc} */ public void queryRemoved(ISearchQuery query) { // handle if necessary } /** {@inheritDoc} */ public void queryStarting(ISearchQuery query) { // handle if necessary } }); } /** * gets the data directory info from the preferences and sets * them in the BP. */ private void propagateDataDir() { IPreferenceStore preferenceStore = Plugin.getDefault().getPreferenceStore(); if (!preferenceStore.getBoolean( Constants.DATADIR_WS_KEY)) { ExternalTestDataBP.setDataDir( new File(preferenceStore.getString( Constants.DATADIR_PATH_KEY))); } else { ExternalTestDataBP.setDataDir( Platform.getLocation().toFile()); } } /** * @return instance of plugin */ public static Plugin getDefault() { return plugin; } }