/******************************************************************************* * Copyright (c) 2007, 2010, 2018 Association for Decentralized Information Management * in Industry THTH ry. * 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: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.ui; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.viewers.ISelection; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Widget; import org.eclipse.ui.PlatformUI; import org.simantics.DatabaseJob; import org.simantics.Simantics; import org.simantics.db.Resource; import org.simantics.db.Session; import org.simantics.db.common.primitiverequest.Adapter; import org.simantics.db.common.utils.Logger; import org.simantics.db.common.utils.RequestUtil; import org.simantics.db.exception.DatabaseException; import org.simantics.db.management.ISessionContext; import org.simantics.db.management.ISessionContextProvider; import org.simantics.db.management.ISessionContextProviderSource; import org.simantics.project.IProject; import org.simantics.project.ProjectKeys; import org.simantics.utils.datastructures.Arrays; import org.simantics.utils.ui.BundleUtils; import org.simantics.utils.ui.ISelectionUtils; import org.simantics.utils.ui.SWTUtils; /** */ public class SimanticsUI { public static final String PLUGIN_ID = "org.simantics.ui"; /** * The maximum amount of time in milliseconds to wait for the execution of a * database request to start when the request is executed synchronously in * the UI thread. The timeout counting starts from the moment the request is * first scheduled into the database {@link Session}. The purpose is to * prevent synchronous UI thread database requests from locking the whole UI * thread up. * *

* The default value is 20. The default value can be customized at class * load time by setting the system property * simantics.ui.request.start.timeout to the desired value at * JVM startup. * * @see RequestUtil */ public static final long UI_THREAD_REQUEST_START_TIMEOUT; /** * The maximum amount of time in milliseconds to wait for the execution of a * database request to complete when the request is executed synchronously * in the UI thread. The timeout counting starts from the moment the request * execution is scheduled. The purpose is to prevent synchronous UI thread * database requests from locking the whole UI thread up. * *

* The default value is 50. The default value can be customized at class * load time by setting the system property * simantics.ui.request.execution.timeout to the desired value * at JVM startup. * * @see RequestUtil */ public static final long UI_THREAD_REQUEST_EXECUTION_TIMEOUT; /** * *

* The default value is 100. The default value can be customized at class * load time by setting the system property * simantics.ui.request.execution.timeout.long to the desired * value at JVM startup. * * @see RequestUtil */ public static final long UI_THREAD_REQUEST_EXECUTION_TIMEOUT_LONG; static { UI_THREAD_REQUEST_START_TIMEOUT = parseLongProperty("simantics.ui.request.start.timeout", 500L); UI_THREAD_REQUEST_EXECUTION_TIMEOUT = parseLongProperty("simantics.ui.request.exec.timeout", 50L); UI_THREAD_REQUEST_EXECUTION_TIMEOUT_LONG = parseLongProperty("simantics.ui.request.exec.timeout.long", 100L); } /** * Information of the currently open database session for the Simantics UI. * Contains just the vital information to connect to the database. Is * null when there is no open database session. */ private static ISessionContextProviderSource providerSource = null; // /** // * TODO: support different contexts // * @deprecated no replacement // */ // @Deprecated // public static void undo() { // try { // PlatformUI.getWorkbench().getOperationSupport().getOperationHistory().undo( // IOperationHistory.GLOBAL_UNDO_CONTEXT, null, null); // } catch (ExecutionException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // } // // /** // * TODO: support different contexts // * @deprecated no replacement // */ // @Deprecated // public static void redo() { // try { // PlatformUI.getWorkbench().getOperationSupport().getOperationHistory().redo( // IOperationHistory.GLOBAL_UNDO_CONTEXT, null, null); // } catch (ExecutionException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // } /** * Only for use in application startup code such as the workbench window * advisor. Must be invoked before calling any other methods in this class. * * @param manager the ISessionManager to be used by the application * @throw IllegalArgumentException if manager is null */ public static void setSessionContextProviderSource(ISessionContextProviderSource source) { if (source == null) throw new IllegalArgumentException("null provider source"); providerSource = source; } /** * Asserts that the current context provider source has been initialized * before allowing access to it. * * @return current context provider source */ public static ISessionContextProviderSource getProviderSource() { if (providerSource == null) throw new IllegalStateException( "providerSource must be initialized by the application before using SimanticsUI"); return providerSource; } /** * Close and remove the current session contexts of the UI. Afterwards * getSessionContext will return null. * * Not for client use, only for internal purposes. */ public static synchronized void closeSessions() { ISessionContextProviderSource source = providerSource; if (source == null) return; for (ISessionContextProvider p : source.getAll()) { ISessionContext ctx = p.setSessionContext(null); if (ctx != null) { ctx.dispose(); } } } /** * @return true if the session manager contains the specified * session context */ public static synchronized boolean isInUse(ISessionContext ctx) { for (ISessionContextProvider p : getProviderSource().getAll()) { if (p.getSessionContext() == ctx) return true; } return false; } /** * @param project the project to check * @param excluding * @return true if the session manager contains an * ISessionContext that contains a reference to the specified * project, disregarding the excluded ISessionContexts listed */ public static synchronized boolean isInUse(IProject project, ISessionContext... excluding) { for (ISessionContextProvider p : getProviderSource().getAll()) { ISessionContext ctx = p.getSessionContext(); if (ctx != null) { if (Arrays.indexOf(excluding, ctx) == -1) { if (ctx.getHint(ProjectKeys.KEY_PROJECT) == project) return true; } } } return false; } // /** // * Looks if there is an ISessionContextProvider within the Simantics workbench // * that is currently using a ProCore database server at the specified // * address. // * // * @param address the address to look for connections to // * @return null if there is currently no session in use to the // * specified address. // */ // public static synchronized ISessionContext findSessionTo(ServerAddress address) { // if (address == null) // throw new IllegalArgumentException("null address"); // for (ISessionContextProvider provider : getProviderSource().getAll()) { // ISessionContext ctx = provider.getSessionContext(); // if (ctx != null) { // ServerAddress addr = ctx.getAddress(); // if (address.equals(addr)) // return ctx; // } // } // return null; // } /** * Returns the session context provider for the specified handle if one * exists. Workbench windows (IWorkbenchWindow) are currently used as * handles. * * @param handle the handle associated with the requested session context * provider * @return null if there is no session associated to the * specified handle */ public static ISessionContextProvider getSessionContextProvider(Object handle) { return getProviderSource().get(handle); } /** * Returns the database session context associated with the currently active * workbench window. This method should be used to retrieve session contexts * only when the client is sure that the correct workbench window has focus. * *

* If the client knows the workbench window it is working with, but it isn't * sure that the correct workbench window has focus, use * {@link #getSessionContext(Object)} instead. *

* * @return the session context associated with the currently active * workbench window or null if the active window has no * session context */ @Deprecated public static ISessionContext getSessionContext() { return Simantics.getSessionContext(); } /** * Returns the database session context associated with the specified * handle. Workbench windows (IWorkbenchWindow) are currently used as * handles. This method should be used to retrieve session contexts in cases * where the workbench window is known, but the thread of execution is such * that the client cannot be certain that the same workbench window has * focus. * * @return the session context associated with the specified handle * (IWorkbenchWindow) */ public static ISessionContext getSessionContext(Object handle) { return getSessionContextProvider(handle).getSessionContext(); } /** * Associates the specified ISessionContext with the currently active * workbench window. To remove an ISessionContext association from the * active workbench window, specify null as ctx. * *

* After invoking this method you should be able to retrieve the same * ISessionContext through {@link #getSessionContext()}, provided that the * same workbench window has focus at that time. *

* * @param ctx the new UI database session context or null to * replace the current UI session with no session. * @return The previous session context if one existed, otherwise * null. If the specified ctx matched the * current session context (null or * non-null), null is also returned and nothing is * done. */ public static synchronized ISessionContext setSessionContext(ISessionContext ctx) { return Simantics.getSessionContextProvider().setSessionContext(ctx); } /** * Associates the specified ISessionContext with the specified handle * object. * *

* Currently IWorkbenchWindow's are used as handles. This implies * that each workbench window can only have one active ISessionContext bound * to it. After invoking this method with a valid workbench window handle * you should be able to retrieve the same ISessionContext through * {@link #getSessionContext(Object)} with the same workbench window * specified as the handle. *

* * @param handle the handle to associate the specified ISessionContext with. * @param ctx the new UI database session context or null to * replace the current UI session with no session. * @return The previous session context if one existed, otherwise * null. If the specified ctx matched the * current session context (null or * non-null), null is also returned and nothing is * done. */ public static synchronized ISessionContext setSessionContext(Object handle, ISessionContext ctx) { ISessionContextProvider provider = getProviderSource().get(handle); if (provider != null) return provider.setSessionContext(ctx); return null; } /** * @return the currently open and active project for the specified database * session or null if there is no current project */ @Deprecated public static IProject peekProject(ISessionContext ctx) { if (ctx == null) return null; return ctx.getHint(ProjectKeys.KEY_PROJECT); } /** * TODO: refactor this out of here * * @param imageFilePath * @return */ public static ImageDescriptor getImageDescriptor(String imageFilePath) { return BundleUtils.getImageDescriptorFromPlugin(PLUGIN_ID, imageFilePath); } /** * TODO: [Tuukka] I'm really unsure this belongs here. * * @param * @param sel * @param assignableFrom * @return */ public static T filterSingleSelection(ISelection sel, Class assignableFrom) { T result = ISelectionUtils.filterSingleSelection(sel, assignableFrom); if (result != null) return result; Resource resource = ISelectionUtils.filterSingleSelection(sel, Resource.class); if(resource == null) return null; try { return Simantics.getSession().syncRequest(new Adapter(resource, assignableFrom)); } catch (DatabaseException e) { Logger.defaultLogError(e); return null; } } public static T filterSingleWorkbenchSelection(Class assignableFrom) { return filterSingleSelection(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService().getSelection(), assignableFrom); } public static void asyncExecSWT(final Widget widget, final Runnable runnable) { SWTUtils.asyncExec(widget, delayedExecSWT(null, widget, runnable)); } public static void asyncExecSWT(final Display display, final Runnable runnable) { SWTUtils.asyncExec(display, delayedExecSWT(display, null, runnable)); } private static Runnable delayedExecSWT(final Display display, final Widget widget, final Runnable runnable) { if (display == null && widget == null) throw new IllegalArgumentException("both display and widget are null"); return new Runnable() { @Override public void run() { if (display != null && display.isDisposed()) return; if (widget != null && widget.isDisposed()) return; if (DatabaseJob.inProgress()) { Display d = display != null ? display : widget.getDisplay(); d.timerExec(50, this); return; } runnable.run(); } }; } private static long parseLongProperty(String propertyName, long defaultValue) { String value = System.getProperty(propertyName, null); try { return value != null ? Long.parseLong(value) : defaultValue; } catch (NumberFormatException e) { return defaultValue; } } public static boolean isLinuxGTK() { String ws = System.getProperty("osgi.ws"); return ws != null && "gtk".equals(ws); } }