/* ******************************************************************************
* Copyright (c) 2006-2012 XMind Ltd. and others.
*
* This file is a part of XMind 3. XMind releases 3 and
* above are dual-licensed under the Eclipse Public License (EPL),
* which is available at http://www.eclipse.org/legal/epl-v10.html
* and the GNU Lesser General Public License (LGPL),
* which is available at http://www.gnu.org/licenses/lgpl.html
* See http://www.xmind.net/license.html for details.
*
* Contributors:
* XMind Ltd. - initial API and implementation
*******************************************************************************/
package org.xmind.cathy.internal;
import java.awt.Toolkit;
import java.io.File;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.Platform;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.IPreferenceConstants;
import org.eclipse.ui.internal.WorkbenchPlugin;
import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
import org.xmind.core.Core;
import org.xmind.core.internal.dom.DOMConstants;
import org.xmind.core.usagedata.IUsageDataSampler;
import org.xmind.ui.internal.MindMapUIPlugin;
import org.xmind.ui.internal.app.IApplicationValidator;
import org.xmind.ui.prefs.PrefConstants;
/**
* This class controls all aspects of the application's execution
*/
public class CathyApplication implements IApplication {
public static final String SYS_VERSION = "org.xmind.product.version"; //$NON-NLS-1$
public static final String SYS_BUILDID = "org.xmind.product.buildid"; //$NON-NLS-1$
public static final String SYS_BRANDING_VERSION = "org.xmind.product.brandingVersion"; //$NON-NLS-1$
public static final String SYS_APP_STATUS = "org.xmind.cathy.app.status"; //$NON-NLS-1$
/**
* @see org.eclipse.equinox.app.IApplication#start(org.eclipse.equinox.app.IApplicationContext)
*/
public Object start(IApplicationContext context) throws Exception {
// Check product information.
// Product build id and version may have been set in config.ini.
// If not set, calculate them using runtime properties.
String buildId = System.getProperty(SYS_BUILDID);
if (buildId == null || "".equals(buildId)) { //$NON-NLS-1$
buildId = calculateBuildId(context);
System.setProperty(SYS_BUILDID, buildId);
}
String appVersion = System.getProperty(SYS_VERSION);
if (appVersion == null || "".equals(appVersion)) { //$NON-NLS-1$
appVersion = extractVersionNumber(buildId);
System.setProperty(SYS_VERSION, appVersion);
}
System.setProperty("org.xmind.product.about.copyright", //$NON-NLS-1$
WorkbenchMessages.About_Copyright);
System.setProperty("org.xmind.product.about.homepage", //$NON-NLS-1$
WorkbenchMessages.About_Homepage);
IPreferenceStore pref = MindMapUIPlugin.getDefault()
.getPreferenceStore();
String name = pref.getString(PrefConstants.AUTHOR_INFO_NAME);
if (name == null || "".equals(name)) //$NON-NLS-1$
name = System.getProperty("user.name"); //$NON-NLS-1$
if (name != null)
System.setProperty(DOMConstants.AUTHOR_NAME, name);
if (pref.getString(PrefConstants.AUTHOR_INFO_EMAIL) != null)
System.setProperty(DOMConstants.AUTHOR_EMAIL,
pref.getString(PrefConstants.AUTHOR_INFO_EMAIL));
if (pref.getString(PrefConstants.AUTHOR_INFO_ORG) != null)
System.setProperty(DOMConstants.AUTHOR_ORG,
pref.getString(PrefConstants.AUTHOR_INFO_ORG));
// Set Cathy product as the workbook creator.
Core.getWorkbookBuilder().setCreator("XMind", buildId); //$NON-NLS-1$
// Create the default display instance.
Display display = PlatformUI.createDisplay();
try {
// Install global OpenDocument listener:
OpenDocumentQueue.getInstance().hook(display);
/// Activate network proxy settings. On Linux, we need a
/// UI environment to show a dialog for retrieving the master
/// password of the secure storage containing proxy server
/// credentials.
CathyPlugin.getDefault().activateNetworkSettings();
// Check if we are in beta and should quit due to beta expiry.
if (new BetaVerifier(display).shouldExitAfterBetaExpired())
return EXIT_OK;
// Check if this app session should exit early:
if (shouldExitEarly(context)) {
// Log all application arguments to local disk to exchange
// between running XMind instances:
logApplicationArgs();
return EXIT_OK;
}
// Log all application arguments to local disk to exchange
// between running XMind instances:
logApplicationArgs();
// Mark application status to 'starting':
System.setProperty(SYS_APP_STATUS, "starting"); //$NON-NLS-1$
// Set cookies to let web pages loaded within internal web browser
// to recognize the environment:
initializeInternalBrowserCookies();
//Close model's auto-save to avoid repeated model elements
//which application exits non-normally:
WorkbenchPlugin.getDefault().getPreferenceStore()
.setValue(IPreferenceConstants.WORKBENCH_SAVE_INTERVAL, 0);
try {
captureAppSessionInfo(
CathyPlugin.getDefault().getUsageDataCollector(),
context, buildId);
// Launch workbench and get return code:
int returnCode = PlatformUI.createAndRunWorkbench(display,
new CathyWorkbenchAdvisor());
if (returnCode == PlatformUI.RETURN_RESTART) {
// Restart:
return EXIT_RESTART;
}
// Quit:
return EXIT_OK;
} finally {
CathyPlugin.getDefault().getUsageDataCollector().put(
"ShutDownTime", //$NON-NLS-1$
System.currentTimeMillis());
}
} finally {
display.dispose();
}
}
/**
* @param sampler
* @param context
* @param buildId
*/
private void captureAppSessionInfo(IUsageDataSampler sampler,
IApplicationContext context, String buildId) {
sampler.put("StartUpTime", //$NON-NLS-1$
System.currentTimeMillis());
sampler.put("AppId", //$NON-NLS-1$
context.getBrandingApplication());
sampler.put("BuildId", buildId); //$NON-NLS-1$
sampler.put("DistributionId", //$NON-NLS-1$
System.getProperty("org.xmind.product.distribution.id", //$NON-NLS-1$
null));
sampler.put("NL", Platform.getNL()); //$NON-NLS-1$
sampler.put("OS", Platform.getOS()); //$NON-NLS-1$
sampler.put("Arch", Platform.getOSArch()); //$NON-NLS-1$
sampler.put("OSName", System.getProperty("os.name", null)); //$NON-NLS-1$ //$NON-NLS-2$
sampler.put("OSVersion", System.getProperty("os.version", null)); //$NON-NLS-1$ //$NON-NLS-2$
sampler.put("Country", System.getProperty("user.country", null)); //$NON-NLS-1$ //$NON-NLS-2$
sampler.put("JavaVersion", System.getProperty("java.version", null)); //$NON-NLS-1$ //$NON-NLS-2$
sampler.put("JavaVendor", System.getProperty("java.vendor", null)); //$NON-NLS-1$ //$NON-NLS-2$
sampler.put("ScreenWidth", //$NON-NLS-1$
Toolkit.getDefaultToolkit().getScreenSize().width);
sampler.put("ScreenHeight", //$NON-NLS-1$
Toolkit.getDefaultToolkit().getScreenSize().height);
sampler.put("ScreenResolution", //$NON-NLS-1$
Toolkit.getDefaultToolkit().getScreenResolution());
}
private static String calculateBuildId(IApplicationContext context) {
String buildId = System.getProperty("eclipse.buildId"); //$NON-NLS-1$
if (buildId != null && !"".equals(buildId)) //$NON-NLS-1$
return buildId;
return context.getBrandingBundle().getVersion().toString();
}
private static String extractVersionNumber(String buildId) {
String[] numbers = buildId.split("\\."); //$NON-NLS-1$
StringBuilder buffer = new StringBuilder(10);
for (int i = 0; i < 3; i++) {
if (i >= numbers.length)
break;
if (buffer.length() > 0) {
buffer.append('.');
}
buffer.append(numbers[i]);
}
return buffer.toString();
}
private void initializeInternalBrowserCookies() {
String appVersion = System.getProperty(SYS_VERSION);
Browser.setCookie(
"_env=xmind_" + appVersion //$NON-NLS-1$
+ "; path=/; domain=.xmind.net", //$NON-NLS-1$
"http://www.xmind.net/"); //$NON-NLS-1$
}
private void logApplicationArgs() {
final String[] args = Platform.getApplicationArgs();
if (args == null || args.length == 0)
return;
Log openingLog = Log.get(Log.OPENING);
for (String arg : args) {
if ("-p".equals(arg)) {//$NON-NLS-1$
// The "-p" argument is used to start Presentation Mode
// immediately on startup:
System.setProperty("org.xmind.cathy.startup.presentation", //$NON-NLS-1$
"true"); //$NON-NLS-1$
} else if (arg.startsWith("xmind:") || new File(arg).exists()) { //$NON-NLS-1$
// Add xmind command or existing file path to '.opening' log:
openingLog.append(arg);
} else if (!arg.startsWith("-psn_0_")) { //$NON-NLS-1$
// The "-psn_0_<ProcessSerialNumber>" argument is passed in by
// Mac OS X for each GUI application. No need to log that.
// Log any other unknown command line argument for debugging:
CathyPlugin.log("Skip unrecognized command line argument: '" //$NON-NLS-1$
+ arg + "'"); //$NON-NLS-1$
}
}
}
private boolean shouldExitEarly(IApplicationContext appContext)
throws Exception {
IExtensionPoint extPoint = Platform.getExtensionRegistry()
.getExtensionPoint(
"org.xmind.ui.toolkit.applicationValidators"); //$NON-NLS-1$
if (extPoint != null) {
for (IExtension ext : extPoint.getExtensions()) {
for (IConfigurationElement validatorElement : ext
.getConfigurationElements()) {
if ("applicationValidator" //$NON-NLS-1$
.equals(validatorElement.getName())) {
Object validator = validatorElement
.createExecutableExtension(
IWorkbenchRegistryConstants.ATT_CLASS);
if (validator instanceof IApplicationValidator
&& ((IApplicationValidator) validator)
.shouldApplicationExitEarly(
appContext)) {
return true;
}
}
}
}
}
return false;
}
/**
* @see org.eclipse.equinox.app.IApplication#stop()
*/
public void stop() {
if (!PlatformUI.isWorkbenchRunning())
return;
final IWorkbench workbench = PlatformUI.getWorkbench();
if (workbench == null)
return;
Display display = workbench.getDisplay();
if (display == null || display.isDisposed())
return;
display.syncExec(new Runnable() {
public void run() {
workbench.close();
}
});
}
}