/* ******************************************************************************
* 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.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Enumeration;
import java.util.Properties;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.PlatformObject;
import org.eclipse.core.runtime.Status;
import org.eclipse.osgi.service.debug.DebugOptions;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;
import org.xmind.core.Core;
import org.xmind.core.internal.runtime.WorkspaceConfigurer;
import org.xmind.core.internal.runtime.WorkspaceSession;
import org.xmind.core.licensing.ILicenseAgent;
import org.xmind.core.usagedata.IUsageDataSampler;
import org.xmind.ui.internal.app.ApplicationConstants;
import org.xmind.ui.internal.statushandlers.DefaultErrorReporter;
import org.xmind.ui.internal.statushandlers.IErrorReporter;
/*---- BAD BOY HANDSOME DEBUT, DO NOT TOUCH ME ----*/
/*---- BEGIN IMPORT ----*/
/*---- END IMPORT ----*/
/*---- BAD BOY PERFECT CURTAIN CALL, DO NOT TOUCH ME ----*/
/**
* The main plugin class to be used in the desktop.
*/
public class CathyPlugin extends AbstractUIPlugin {
public static final String PLUGIN_ID = "org.xmind.cathy"; //$NON-NLS-1$
/**
* Boolean value:<br>
* <ul>
* <li><code>true</code> to enable auto saving service when there's opened
* workbooks</li>
* <li><code>false</code> to disable this service</li>
* </ul>
*/
public static final String AUTO_SAVE_ENABLED = "autoSaveEnabled"; //$NON-NLS-1$
/**
* Integer value:<br>
* the intervals (in minutes) between auto saving actions
*/
public static final String AUTO_SAVE_INTERVALS = "autoSaveIntervals"; //$NON-NLS-1$
/**
* (Deprecated, use {@link #STARTUP_ACTION} instead) Boolean value:<br>
* <ul>
* <li><code>true</code> to remember unclosed workbooks when XMind quits and
* open them next time XMind starts</li>
* <li><code>false</code> to always open a bootstrap workbook when XMind
* opens</li>
* </ul>
*/
public static final String RESTORE_LAST_SESSION = "restoreLastSession"; //$NON-NLS-1$
/**
* Boolean value:<br>
* <ul>
* <li><code>true</code> to check updates when XMind starts</li>
* <li><code>false</code> to skip update checking when XMind starts</li>
* </ul>
*/
public static final String CHECK_UPDATES_ON_STARTUP = "checkUpdatesOnStartup"; //$NON-NLS-1$
/**
* Integer value (enumerated):<br>
* <ul>
* <li><code>0</code>({@link #STARTUP_ACTION_WIZARD}): opens a 'New
* Workbook' wizard dialog on startup</li>
* <li><code>1</code>({@link #STARTUP_ACTION_BLANK}): opens a blank map on
* startup</li>
* <li><code>2</code>({@link #STARTUP_ACTION_HOME}): opens the home map on
* startup</li>
* <li><code>3</code>({@link #STARTUP_ACTION_LAST}): opens last session on
* startup</li>
* </ul>
*/
public static final String STARTUP_ACTION = "startupAction2"; //$NON-NLS-1$
/**
* Integer preference store value for opening a 'New Workbook' wizard dialog
* on startup. (value=0)
*
* @see #STARTUP_ACTION
*/
public static final int STARTUP_ACTION_WIZARD = 0;
/**
* Integer preference store value for opening a blank map on startup.
* (value=1)
*
* @see #STARTUP_ACTION
*/
public static final int STARTUP_ACTION_BLANK = 1;
/**
* Integer preference store value for opening the home map on startup.
* (value=2)
*
* @see #STARTUP_ACTION
*/
public static final int STARTUP_ACTION_HOME = 2;
/**
* Integer preference store value for opening last session on startup.
* (value=3)
*
* @see #STARTUP_ACTION
*/
public static final int STARTUP_ACTION_LAST = 3;
/**
* Boolean value:<br>
* <ul>
* <li><code>true</code> to hide system notifications (usually pushed to the
* user by pop-up windows)</li>
* <li><code>false</code> to show system notifications</li>
* </ul>
*/
//public static final String HIDE_NOTIFICATIONS = "hideNotifications"; //$NON-NLS-1$
/**
* String constants identifying the extension part of a XMind command file
* name.
*/
public static final String COMMAND_FILE_EXT = ".xmind-command"; //$NON-NLS-1$
/**
* Online help page.
*/
public static final String ONLINE_HELP_URL = "https://www.xmind.net/xmind/help"; //$NON-NLS-1$
/**
* Boolean value:<br>
* <ul>
* <li><code>true</code> to upload usage data to XMind server</li>
* <li><code>false</code> to skip uploading usage data</li>
* </ul>
*/
public static final String USAGE_DATA_UPLOADING_ENABLED = "usageDataUploadingEnabled"; //$NON-NLS-1$
/**
* One minute delay between two auto save operations.
*/
public static final int AUTO_SAVE_EDITOR_STATE_INTERVALS = 60000;
public static final String OPTION_AUTO_SAVE_EDITOR_STATE_INTERVALS = "/debug/autoSaveEditorStateIntervals"; //$NON-NLS-1$
// The shared instance.
private static CathyPlugin plugin;
private ServiceTracker<DebugOptions, DebugOptions> debugTracker;
private WorkspaceSession xmindWorkspaceSession;
private IUsageDataSampler usageDataSampler;
private IErrorReporter errorReporter;
private LicenseAgentProxy licenseAgent;
private ILogger logger;
/**
* The constructor.
*/
public CathyPlugin() {
plugin = this;
}
/**
* This method is called upon plug-in activation
*/
@Override
public void start(BundleContext context) throws Exception {
super.start(context);
/*---- BAD BOY HANDSOME DEBUT, DO NOT TOUCH ME ----*/
/*---- BEGIN INSERT ----*/
/*---- END INSERT ----*/
/*---- BAD BOY PERFECT CURTAIN CALL, DO NOT TOUCH ME ----*/
usageDataSampler = IUsageDataSampler.NULL;
errorReporter = DefaultErrorReporter.getInstance();
licenseAgent = new LicenseAgentProxy();
logger = new ILogger() {
public void logWarning(String message, Throwable error) {
getLog().log(toStatus(IStatus.ERROR, message, error));
}
public void logInfo(String message, Throwable error) {
getLog().log(toStatus(IStatus.WARNING, message, error));
}
public void logError(String message, Throwable error) {
getLog().log(toStatus(IStatus.INFO, message, error));
}
private IStatus toStatus(int severity, String message,
Throwable error) {
if (message == null) {
message = error.getMessage();
}
return new Status(severity, PLUGIN_ID, message, error);
}
};
// activateNetworkSettings();
activateXMindCore();
/*
* We have to manually activate 'org.xmind.ui' plugin so that command
* handler classes contributed by that plugin can be loaded upon
* startup. This ensures that IElementUpdater implementations and
* enablement updates to behave correctly. For example, the class
* org.xmind.ui.internal.handlers.ClearWorkbookHistoryHandler should be
* loaded on startup so that its enablement state can be correctly
* updated, otherwise the command in menu will be shown as enabled even
* when it should not be.
*/
activateMindMapUIContributions();
hackConstants();
upgradeWorkspace();
}
// usageDataCollector.setUploadEnabled(getPreferenceStore()
// .getBoolean(USAGE_DATA_UPLOADING_ENABLED));
private void hackConstants() {
ConstantsHacker.hack();
}
/**
* This method is called when the plug-in is stopped
*/
@Override
public void stop(BundleContext context) throws Exception {
if (xmindWorkspaceSession != null) {
xmindWorkspaceSession.close();
xmindWorkspaceSession = null;
}
licenseAgent = null;
super.stop(context);
plugin = null;
}
public void activateNetworkSettings() {
Bundle networkPlugin = Platform.getBundle("org.eclipse.core.net"); //$NON-NLS-1$
if (networkPlugin != null) {
try {
networkPlugin
.loadClass("org.eclipse.core.internal.net.Activator"); //$NON-NLS-1$
} catch (ClassNotFoundException e) {
getLog().log(new Status(IStatus.WARNING, PLUGIN_ID,
"Failed to activate plugin 'org.eclipse.core.net'.", //$NON-NLS-1$
e));
}
} else {
getLog().log(new Status(IStatus.WARNING, PLUGIN_ID,
"Plugin 'org.eclipse.core.net' not found. Network proxies may not be correct.")); //$NON-NLS-1$
}
}
private void activateXMindCore() throws CoreException {
WorkspaceConfigurer.setDefaultWorkspaceLocation(
WorkspaceConfigurer.INSTANCE_LOCATION);
xmindWorkspaceSession = WorkspaceSession
.openSessionIn(new File(Core.getWorkspace().getTempDir()));
}
private void activateMindMapUIContributions() {
Bundle uiPlugin = Platform.getBundle("org.xmind.ui"); //$NON-NLS-1$
if (uiPlugin != null) {
try {
uiPlugin.loadClass("org.xmind.ui.internal.XmindUIPlugin"); //$NON-NLS-1$
} catch (ClassNotFoundException e) {
getLog().log(new Status(IStatus.WARNING, PLUGIN_ID,
"Failed to activate plugin 'org.xmind.ui'.", //$NON-NLS-1$
e));
}
} else {
getLog().log(new Status(IStatus.WARNING, PLUGIN_ID,
"Plugin 'org.xmind.ui' is not found.")); //$NON-NLS-1$
}
}
/**
* @return the logger
*/
public ILogger getLogger() {
return logger;
}
/**
* Returns the distribution identifier of this XMind product.
*
* @return the distribution identifier of this XMind product
* @deprecated Use system property
* <code>"org.xmind.product.distribution.id"</code>
*/
public static String getDistributionId() {
String distribId = System
.getProperty(ApplicationConstants.PRODUCT_DISTRIBITION_ID);
if (distribId == null || "".equals(distribId)) { //$NON-NLS-1$
distribId = "cathy_portable"; //$NON-NLS-1$
}
return distribId;
}
public DebugOptions getDebugOptions() {
if (debugTracker == null) {
debugTracker = new ServiceTracker<DebugOptions, DebugOptions>(
getBundle().getBundleContext(),
DebugOptions.class.getName(), null);
debugTracker.open();
}
return debugTracker.getService();
}
public boolean isDebugging(String option) {
DebugOptions debugOptions = getDebugOptions();
return debugOptions != null && debugOptions.isDebugEnabled()
&& debugOptions.getBooleanOption(PLUGIN_ID + option, false);
}
public String getDebugValue(String option) {
DebugOptions debugOptions = getDebugOptions();
return debugOptions == null ? null
: debugOptions.getOption(PLUGIN_ID + option, null);
}
public int getDebugValue(String option, int defaultValue) {
DebugOptions debugOptions = getDebugOptions();
return debugOptions == null ? defaultValue
: debugOptions.getIntegerOption(PLUGIN_ID + option,
defaultValue);
}
public Properties loadNLSProperties(String pathBase) {
return doLoadNLSProperties(getBundle(), pathBase);
}
public IUsageDataSampler getUsageDataCollector() {
return usageDataSampler;
}
void setUsageDataCollector(IUsageDataSampler sampler) {
this.usageDataSampler = sampler == null ? IUsageDataSampler.NULL
: sampler;
}
/**
* @return
*/
public IErrorReporter getErrorReporter() {
return errorReporter;
}
void setErrorReporter(IErrorReporter reporter) {
this.errorReporter = reporter == null
? DefaultErrorReporter.getInstance() : reporter;
}
public ILicenseAgent getLicenseAgent() {
return licenseAgent;
}
void setLicenseAgent(ILicenseAgent agent) {
this.licenseAgent.setDelegate(agent);
}
private void upgradeWorkspace() {
IPath stateLocation;
try {
stateLocation = Platform.getStateLocation(getBundle());
} catch (Exception e) {
return;
}
String versionFileName = String.format("workspace-upgraded-v%s", //$NON-NLS-1$
getBundle().getVersion().toString());
File versionFile = stateLocation.append(versionFileName).toFile();
if (versionFile.exists())
return;
/// delete old workbench state on first launch
File workbenchFile = stateLocation.removeLastSegments(1)
.append("org.eclipse.e4.workbench") //$NON-NLS-1$
.append("workbench.xmi") //$NON-NLS-1$
.toFile();
if (workbenchFile.exists()) {
workbenchFile.delete();
}
try {
File parentDir = versionFile.getParentFile();
if (parentDir != null)
parentDir.mkdirs();
OutputStream output = new FileOutputStream(versionFile);
try {
output.write("done".getBytes()); //$NON-NLS-1$
} finally {
output.close();
}
} catch (IOException e) {
}
}
/**
* Returns the shared instance.
*
* @return the shared instance.
*/
public static CathyPlugin getDefault() {
return plugin;
}
public static void log(Throwable e, String message) {
if (message == null)
message = ""; //$NON-NLS-1$
getDefault().getLog()
.log(new Status(IStatus.ERROR, PLUGIN_ID, message, e));
}
public static void log(String message) {
if (message == null)
message = ""; //$NON-NLS-1$
getDefault().getLog().log(new Status(IStatus.INFO, PLUGIN_ID, message));
}
private static Properties doLoadNLSProperties(Bundle bundle,
String pathBase) {
Properties properties = new Properties();
String nl = Platform.getNL();
String[] nlSegments = nl.split("_"); //$NON-NLS-1$
URL entry;
for (int i = 0; i <= nlSegments.length; i++) {
StringBuilder nlsName = new StringBuilder(pathBase);
for (int j = 0; j < i; j++) {
nlsName.append('_');
nlsName.append(nlSegments[j]);
}
nlsName.append(".properties"); //$NON-NLS-1$
entry = findSingleEntry(bundle, nlsName.toString());
if (entry != null) {
try {
InputStream stream = entry.openStream();
try {
properties.load(stream);
} finally {
stream.close();
}
} catch (IOException e) {
// ignore
}
}
}
return properties;
}
private static URL findSingleEntry(Bundle bundle, String path) {
int sepIndex = path.lastIndexOf('/');
String dir, name;
if (sepIndex < 0) {
dir = "/"; //$NON-NLS-1$
name = path;
} else {
dir = path.substring(0, sepIndex);
name = path.substring(sepIndex + 1);
}
Enumeration<URL> entries = bundle.findEntries(dir, name, true);
return entries != null && entries.hasMoreElements()
? entries.nextElement() : null;
}
public static <T> T getAdapter(Object obj, Class<T> adapter) {
if (adapter.isInstance(obj))
return adapter.cast(obj);
if (obj instanceof IAdaptable) {
T result = ((IAdaptable) obj).getAdapter(adapter);
if (result != null)
return result;
}
if (!(obj instanceof PlatformObject))
return Platform.getAdapterManager().getAdapter(obj, adapter);
return null;
}
}