/* Copyright (C) 2009 Mobile Sorcery AB
This program is free software; you can redistribute it and/or modify it
under the terms of the Eclipse Public License v1.0.
This program 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 Eclipse Public License v1.0 for
more details.
You should have received a copy of the Eclipse Public License v1.0 along
with this program. It is also available at http://www.eclipse.org/legal/epl-v10.html
*/
package com.mobilesorcery.sdk.ui;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.File;
import java.net.URI;
import java.net.URL;
import java.text.MessageFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TimerTask;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.AssertionFailedException;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.resource.FontRegistry;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.jface.util.Util;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IStartup;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWindowListener;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchSite;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.activities.ICategory;
import org.eclipse.ui.activities.ICategoryActivityBinding;
import org.eclipse.ui.activities.IWorkbenchActivitySupport;
import org.eclipse.ui.ide.ResourceUtil;
import org.eclipse.ui.ide.undo.AbstractWorkspaceOperation;
import org.eclipse.ui.ide.undo.CreateProjectOperation;
import org.eclipse.ui.intro.IIntroManager;
import org.eclipse.ui.intro.IIntroPart;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
import com.mobilesorcery.sdk.core.Cache;
import com.mobilesorcery.sdk.core.CoreMoSyncPlugin;
import com.mobilesorcery.sdk.core.IProcessConsole;
import com.mobilesorcery.sdk.core.IProvider;
import com.mobilesorcery.sdk.core.IsExperimentalTester;
import com.mobilesorcery.sdk.core.MoSyncBuilder;
import com.mobilesorcery.sdk.core.MoSyncNature;
import com.mobilesorcery.sdk.core.MoSyncProject;
import com.mobilesorcery.sdk.core.MoSyncTool;
import com.mobilesorcery.sdk.core.NameSpacePropertyOwner;
import com.mobilesorcery.sdk.core.PropertyUtil;
import com.mobilesorcery.sdk.core.build.CommandLineBuildStep;
import com.mobilesorcery.sdk.core.build.CopyBuildResultBuildStep;
import com.mobilesorcery.sdk.core.build.IBuildStepFactory;
import com.mobilesorcery.sdk.core.build.IBuildStepFactoryExtension;
import com.mobilesorcery.sdk.core.launch.AutomaticEmulatorLauncher;
import com.mobilesorcery.sdk.core.launch.MoReLauncher;
import com.mobilesorcery.sdk.core.memory.MemoryLowListener;
import com.mobilesorcery.sdk.core.stats.Stats;
import com.mobilesorcery.sdk.profiles.IVendor;
import com.mobilesorcery.sdk.profiles.ProfileDBManager;
import com.mobilesorcery.sdk.ui.internal.LegacyProfileViewOpener;
import com.mobilesorcery.sdk.ui.internal.MemoryLowDialog;
import com.mobilesorcery.sdk.ui.internal.console.IDEProcessConsole;
import com.mobilesorcery.sdk.ui.internal.decorators.ExcludedResourceDecorator;
import com.mobilesorcery.sdk.ui.internal.launch.AutomaticEmulatorLauncherPart;
import com.mobilesorcery.sdk.ui.internal.launch.EmulatorLaunchConfigurationPartProxy;
import com.mobilesorcery.sdk.ui.internal.launch.MoreLauncherPart;
import com.mobilesorcery.sdk.ui.internal.properties.CommandLineBuildStepEditor;
import com.mobilesorcery.sdk.ui.internal.properties.CopyBuildStepEditor;
import com.mobilesorcery.sdk.ui.launch.IEmulatorLaunchConfigurationPart;
/**
* The activator class controls the plug-in life cycle
*/
public class MosyncUIPlugin extends AbstractUIPlugin implements
IWindowListener, ISelectionListener,
IProvider<IProcessConsole, String>, MemoryLowListener,
IResourceChangeListener, IStartup {
// The plug-in ID
public static final String PLUGIN_ID = "com.mobilesorcery.sdk.ui"; //$NON-NLS-1$
/**
* A property indicating the current project has changed
*/
public static final String CURRENT_PROJECT_CHANGED = PLUGIN_ID
+ ":current.project.changed"; //$NON-NLS-1$
public static final String IMG_OVR_EXCLUDED_RESOURCE = "excl.res"; //$NON-NLS-1$
static final String PASSWORD_SHOW = "p.show"; //$NON-NLS-1$
static final String PASSWORD_HIDE = "p.hide"; //$NON-NLS-1$
static final String COLLAPSE_ALL = "collapse.all"; //$NON-NLS-1$
static final String EXPAND_ALL = "expand.all"; //$NON-NLS-1$
public static final String FONT_INFO_TEXT = "font.instr"; //$NON-NLS-1$
public static final String FONT_DEFAULT_BOLD = "b"; //$NON-NLS-1$
public static final String FONT_DEFAULT_ITALIC = "i"; //$NON-NLS-1$
public static final String PHONE_IMAGE = "phone"; //$NON-NLS-1$
public static final String TARGET_PHONE_IMAGE = "target.phone"; //$NON-NLS-1$
public static final String IMG_BINARY = "binary"; //$NON-NLS-1$
public static final String IMG_FILTER = "filter"; //$NON-NLS-1$
public static final String IMG_LOOKUP = "lookup"; //$NON-NLS-1$
public static final String IMG_BUILD_ONE = "build.one"; //$NON-NLS-1$
public static final String IMG_WIFI = "wifi"; //$NON-NLS-1$
private final static Object NULL = new Object();
protected static final long WB_WAIT_TIMEOUT = 45;
// The shared instance
private static MosyncUIPlugin plugin;
private final CopyOnWriteArrayList<ISelectionListener> customSelectionListeners = new CopyOnWriteArrayList<ISelectionListener>();
private PropertyChangeSupport listeners;
private boolean listenerAdded;
private final IdentityHashMap<IWorkbenchWindow, IProject> currentProjects = new IdentityHashMap<IWorkbenchWindow, IProject>();
private PropertyChangeListener globalListener;
private HashMap<String, IEmulatorLaunchConfigurationPart> launcherParts = null;
private final HashMap<Display, FontRegistry> fontRegistries = new HashMap<Display, FontRegistry>();
private final CountDownLatch workbenchStarted = new CountDownLatch(1);
@SuppressWarnings("serial")
private final Cache<String, Object> platformImages = new Cache<String, Object>(
64) {
@Override
protected void onRemoval(String key, Object value) {
if (value instanceof Image) {
if (CoreMoSyncPlugin.getDefault().isDebugging()) {
CoreMoSyncPlugin.trace("Disposed image " + key); //$NON-NLS-1$
}
((Image) value).dispose();
}
}
};
private LegacyProfileViewOpener legacyProfileViewOpener;
private boolean isUpdating;
private HashMap<String, IConfigurationElement> buildStepEditorsExtensions;
/**
* The constructor
*/
public MosyncUIPlugin() {
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext
* )
*/
@Override
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
listeners = new PropertyChangeSupport(this);
CoreMoSyncPlugin.getDefault().setIDEProcessConsoleProvider(this);
registerGlobalProjectListener();
CoreMoSyncPlugin.getLowMemoryManager().addMemoryLowListener(this, 1);
if (!CoreMoSyncPlugin.isHeadless()) {
awaitWorkbenchStartup(new IWorkbenchStartupListener() {
@Override
public void started(IWorkbench wb) {
checkConfig(wb);
initializeCustomActivities();
askForUsageStatistics(wb);
}
});
legacyProfileViewOpener = new LegacyProfileViewOpener();
// Do not use addListener here, since it will trigger a deadlock-type
// error
if (legacyProfileViewOpener.isActive()) {
listeners.addPropertyChangeListener(legacyProfileViewOpener);
MoSyncProject.addGlobalPropertyChangeListener(legacyProfileViewOpener);
}
}
ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE);
// Explicitly invoke updates
CoreMoSyncPlugin.getDefault().checkAutoUpdate();
}
protected void checkConfig(final IWorkbench wb) {
if (!MoSyncTool.getDefault().isValid()) {
wb.getDisplay().syncExec(new Runnable() {
public void run() {
MessageDialog dialog = new MessageDialog(wb.getModalDialogShellProvider().getShell(),
"Fatal error", null,
MessageFormat.format("The environment variable MOSYNCDIR has not been properly set, or some other serious error has occurred. (Reason: {0})\n\nMoSync will not work properly. Press Ok to quit, or Cancel to continue anyway.",
MoSyncTool.getDefault().validate()),
MessageDialog.ERROR,
new String[] { IDialogConstants.OK_LABEL, IDialogConstants.CANCEL_LABEL },
0);
if (dialog.open() == IDialogConstants.OK_ID) {
wb.close();
}
}
});
}
}
private void initializeLauncherParts() {
if (launcherParts == null) {
launcherParts = new HashMap<String, IEmulatorLaunchConfigurationPart>();
IConfigurationElement[] launcherParts = Platform.getExtensionRegistry()
.getConfigurationElementsFor(
IEmulatorLaunchConfigurationPart.EXTENSION_POINT_ID);
for (int i = 0; i < launcherParts.length; i++) {
IConfigurationElement launcherPart = launcherParts[i];
String id = launcherPart.getAttribute("launcher"); //$NON-NLS-1$
this.launcherParts.put(id,
new EmulatorLaunchConfigurationPartProxy(launcherPart));
}
// Default + auto always present
this.launcherParts.put(AutomaticEmulatorLauncher.ID,
new AutomaticEmulatorLauncherPart());
this.launcherParts.put(MoReLauncher.ID, new MoreLauncherPart());
}
}
private void askForUsageStatistics(final IWorkbench wb) {
final Stats stats = Stats.getStats();
if (stats.getSendInterval() == Stats.UNASSIGNED_SEND_INTERVAL) {
Display display = wb.getDisplay();
display.asyncExec(new Runnable() {
@Override
public void run() {
Shell shell = wb.getActiveWorkbenchWindow().getShell();
boolean ok = MessageDialog.openQuestion(shell,
Messages.MosyncUIPlugin_12,
Messages.MosyncUIPlugin_13);
stats.setSendInterval(ok ? Stats.DEFAULT_SEND_INTERVAL
: Stats.DISABLE_SEND);
}
});
}
}
public boolean isExampleWorkspace() {
IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot();
File wsFile = wsRoot.getLocation().toFile();
File exampleWSPath = MoSyncTool.getDefault()
.getMoSyncExamplesWorkspace().toFile();
if (exampleWSPath.exists()) {
boolean isExampleWorkspace = wsFile.equals(exampleWSPath);
return isExampleWorkspace;
} else {
return false;
}
}
private void closeIntro(IIntroManager im) {
IIntroPart part = im.getIntro();
im.closeIntro(part);
}
public void closeIntro(IWorkbenchSite site) {
closeIntro(site.getWorkbenchWindow().getWorkbench().getIntroManager());
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext
* )
*/
@Override
public void stop(BundleContext context) throws Exception {
plugin = null;
super.stop(context);
ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
CoreMoSyncPlugin.getLowMemoryManager().removeMemoryLowListener(this);
deregisterGlobalProjectListener();
disposePlatformImages();
}
/**
* Returns the shared instance
*
* @return the shared instance
*/
public static MosyncUIPlugin getDefault() {
return plugin;
}
/**
* Convenience method for creating a <code>MoSyncProject</code> at the
* requested location, or in the workspace if location is <code>null</code>.
*
* @param project
* @param location
* @param monitor
* @return
* @throws CoreException
* @deprecated Use
* {@link MoSyncUIPlugin#createNewProject(IProject, URI, IProgressMonitor)}
* instead.
*/
@Deprecated
public static MoSyncProject createProject(IProject project, URI location,
IProgressMonitor monitor) throws CoreException {
return createNewProject(project, location, monitor);
}
/**
* Convenience method for creating a <code>MoSyncProject</code> at the
* requested location, or in the workspace if location is <code>null</code>.
*
* @param project
* @param location
* @param monitor
* @return
* @throws CoreException
*/
public static MoSyncProject createNewProject(IProject project,
URI location, IProgressMonitor monitor) throws CoreException {
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IProjectDescription description = workspace
.newProjectDescription(project.getName());
description.setLocationURI(location);
if (CoreMoSyncPlugin.isHeadless()) {
project.create(description, monitor);
} else {
// Get undo for free.
CreateProjectOperation op = new CreateProjectOperation(description,
"Create Project");
try {
op.execute(monitor, null);
} catch (ExecutionException e) {
if (e.getCause() instanceof CoreException) {
throw (CoreException) e.getCause();
} else {
throw new CoreException(new Status(IStatus.ERROR,
CoreMoSyncPlugin.PLUGIN_ID, e.getMessage(), e));
}
}
}
MoSyncNature.addNatureToProject(project, false);
MoSyncProject.addDefaultResourceFilter(project, new NullProgressMonitor());
MoSyncProject result = MoSyncProject.create(project);
result.activateBuildConfigurations();
int pt = ProfileDBManager.isAvailable() ? MoSyncTool.DEFAULT_PROFILE_TYPE :
MoSyncTool.LEGACY_PROFILE_TYPE;
result.setProperty(MoSyncProject.PROFILE_MANAGER_TYPE_KEY,
PropertyUtil.fromInteger(pt));
MoSyncProject.addCapabilityFilters(result, new String[0]);
MoSyncNature.modifyIncludePaths(project);
// MOSYNC-1735: Set to UTF-8 by default
project.setDefaultCharset("UTF-8", new SubProgressMonitor(monitor, 1));
return result;
}
private void initProjectChangeListener() {
if (!listenerAdded) {
if (PlatformUI.getWorkbench() != null) {
PlatformUI.getWorkbench().addWindowListener(this);
listenerAdded = true;
IWorkbenchWindow[] windows = PlatformUI.getWorkbench()
.getWorkbenchWindows();
for (int i = 0; i < windows.length; i++) {
windows[i].getSelectionService().addSelectionListener(this);
updateCurrentlySelectedProjectFallback();
updateCurrentlySelectedProject(windows[i]);
updateCurrentlySelectedProject(windows[i], null);
}
}
}
}
public void addListener(PropertyChangeListener listener) {
listeners.addPropertyChangeListener(listener);
updateCurrentlySelectedProject(PlatformUI.getWorkbench()
.getActiveWorkbenchWindow());
}
public void removeListener(PropertyChangeListener listener) {
listeners.removePropertyChangeListener(listener);
}
public MoSyncProject getCurrentlySelectedProject(IWorkbenchWindow window) {
if (window == null) {
return null;
}
//updateCurrentlySelectedProject(window);
IProject project = currentProjects.get(window);
return project == null ? null : MoSyncProject.create(project);
}
/**
* Sets the current project given a set of "common" views that may have a
* selected project.
*/
private void updateCurrentlySelectedProjectFallback() {
updateCurrentlySelectedProjectFromView("org.eclipse.ui.navigator.ProjectExplorer"); //$NON-NLS-1$
}
private boolean updateCurrentlySelectedProjectFromView(String viewId) {
try {
IWorkbenchWindow window = PlatformUI.getWorkbench()
.getActiveWorkbenchWindow();
IWorkbenchPage[] pages = window.getPages();
for (int i = 0; i < pages.length; i++) {
IViewPart view = pages[i].findView(viewId);
if (view != null) {
IResource selectedResource = getResource(view.getSite()
.getSelectionProvider().getSelection());
if (selectedResource != null) {
setCurrentProject(window, selectedResource.getProject());
return true;
}
}
}
} catch (Exception e) {
// Just ignore, we did the best we could.
}
return false;
}
private void updateCurrentlySelectedProject(final IWorkbenchWindow window) {
if (isUpdating) {
return;
}
isUpdating = true;
initProjectChangeListener();
Runnable r = new Runnable() {
@Override
public void run() {
ISelection selection = window.getSelectionService()
.getSelection();
IResource selectedResource = getResource(selection);
if (selectedResource != null) {
setCurrentProject(window, selectedResource.getProject());
}
}
};
try {
if (window != null) {
UIUtils.onUiThread(window.getWorkbench().getDisplay(), r, false);
}
} finally {
isUpdating = false;
}
}
private void updateCurrentlySelectedProject(final IWorkbenchWindow window,
final IEditorPart editor) {
Runnable r = new Runnable() {
@Override
public void run() {
if (editor != null) {
IEditorInput input = editor.getEditorInput();
if (input instanceof IFileEditorInput) {
IFile file = ResourceUtil.getFile(input);
if (file != null) {
setCurrentProject(window, file.getProject());
}
}
} else {
IEditorPart activeEditor = window.getActivePage()
.getActiveEditor();
if (activeEditor != null) {
updateCurrentlySelectedProject(window, activeEditor);
}
}
}
};
UIUtils.onUiThread(window.getWorkbench().getDisplay(), r, true);
}
private void setCurrentProject(IWorkbenchWindow window, IProject project) {
IProject oldProject = currentProjects.get(window);
if (MoSyncProject.create(project) == null) {
project = null;
}
currentProjects.put(window, project);
if (oldProject != project) {
listeners.firePropertyChange(new PropertyChangeEvent(this,
CURRENT_PROJECT_CHANGED, oldProject, project));
}
}
IResource getResource(ISelection selection) {
if (selection instanceof TreeSelection) {
TreePath[] paths = ((TreeSelection) selection).getPaths();
IResource result = null;
if (paths != null && paths.length > 0) {
Object firstSegment = paths[0].getFirstSegment();
if (firstSegment instanceof IResource) {
result = (IResource) firstSegment;
} else if (firstSegment instanceof IAdaptable) {
result = (IResource) ((IAdaptable) firstSegment)
.getAdapter(IResource.class);
if (result == null) {
ILaunchConfiguration launchConfig = (ILaunchConfiguration) ((IAdaptable) firstSegment)
.getAdapter(ILaunchConfiguration.class);
try {
result = MoSyncBuilder.getProject(launchConfig);
} catch (CoreException e) {
// Ignore.
}
}
}
return result;
}
}
return null;
}
@Override
public void windowClosed(IWorkbenchWindow window) {
window.getSelectionService().removeSelectionListener(this);
currentProjects.remove(window);
}
@Override
public void windowActivated(IWorkbenchWindow window) {
// Ignore.
}
@Override
public void windowDeactivated(IWorkbenchWindow window) {
// Ignore.
}
@Override
public void windowOpened(IWorkbenchWindow window) {
window.getSelectionService().addSelectionListener(this);
}
@Override
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
if (part instanceof IEditorPart) {
updateCurrentlySelectedProject(part.getSite().getWorkbenchWindow(),
(IEditorPart) part);
} else {
updateCurrentlySelectedProject(part.getSite().getWorkbenchWindow());
}
callOtherSelectionListeners(part, selection);
}
private void callOtherSelectionListeners(final IWorkbenchPart part,
final ISelection selection) {
for (Iterator<ISelectionListener> customSelectionListeners = this.customSelectionListeners
.iterator(); customSelectionListeners.hasNext();) {
final ISelectionListener customSelectionListener = customSelectionListeners
.next();
SafeRunner.run(new ISafeRunnable() {
@Override
public void handleException(Throwable exception) {
log(exception);
}
@Override
public void run() throws Exception {
customSelectionListener.selectionChanged(part, selection);
}
});
}
}
public void registerGlobalProjectListener() {
globalListener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent event) {
Object source = event.getSource();
if (MoSyncProject.BUILD_CONFIGURATION_CHANGED.equals(event
.getPropertyName())
|| MoSyncProject.BUILD_CONFIGURATION_SUPPORT_CHANGED
.equals(event.getPropertyName())
|| MoSyncProject.EXCLUDE_FILTER_KEY
.equals(NameSpacePropertyOwner.getKey(event
.getPropertyName()))) {
try {
final ExcludedResourceDecorator dec = (ExcludedResourceDecorator) PlatformUI
.getWorkbench()
.getDecoratorManager()
.getLabelDecorator(ExcludedResourceDecorator.ID);
if (dec != null) {
IWorkbenchWindow ww = PlatformUI.getWorkbench()
.getActiveWorkbenchWindow();
if (ww != null) {
Shell shell = ww.getShell();
if (shell != null) {
shell.getDisplay().asyncExec(
new Runnable() {
@Override
public void run() {
dec.updateDecorations();
}
});
}
}
}
} catch (Exception e) {
CoreMoSyncPlugin.getDefault().log(e);
}
}
}
};
MoSyncProject.addGlobalPropertyChangeListener(globalListener);
}
private void deregisterGlobalProjectListener() {
MoSyncProject.removeGlobalPropertyChangeListener(globalListener);
}
public void log(Throwable e) {
getLog().log(new Status(IStatus.ERROR, PLUGIN_ID, e.getMessage(), e));
}
@Override
public IProcessConsole get(String name) {
return new IDEProcessConsole(name);
}
@Override
public void initializeImageRegistry(ImageRegistry reg) {
super.initializeImageRegistry(reg);
reg.put(IMG_OVR_EXCLUDED_RESOURCE, AbstractUIPlugin
.imageDescriptorFromPlugin(MosyncUIPlugin.PLUGIN_ID,
"$nl$/icons/exclude_ovr.png")); //$NON-NLS-1$
reg.put(PASSWORD_HIDE, AbstractUIPlugin.imageDescriptorFromPlugin(
MosyncUIPlugin.PLUGIN_ID, "$nl$/icons/hide_pwd.png")); //$NON-NLS-1$
reg.put(PASSWORD_SHOW, AbstractUIPlugin.imageDescriptorFromPlugin(
MosyncUIPlugin.PLUGIN_ID, "$nl$/icons/show_pwd.png")); //$NON-NLS-1$
reg.put(COLLAPSE_ALL, AbstractUIPlugin.imageDescriptorFromPlugin(
PLUGIN_ID, "$nl$/icons/collapseall.gif")); //$NON-NLS-1$
reg.put(EXPAND_ALL, AbstractUIPlugin.imageDescriptorFromPlugin(
PLUGIN_ID, "$nl$/icons/expandall.gif")); //$NON-NLS-1$
reg.put(PHONE_IMAGE,
ImageDescriptor.createFromFile(getClass(), "/icons/phone.png")); //$NON-NLS-1$
reg.put(TARGET_PHONE_IMAGE, ImageDescriptor.createFromFile(getClass(),
"/icons/phoneTarget.png")); //$NON-NLS-1$
reg.put(IMG_BINARY,
ImageDescriptor.createFromFile(getClass(), "/icons/binary.gif")); //$NON-NLS-1$
reg.put(IMG_FILTER,
ImageDescriptor.createFromFile(getClass(), "/icons/filter.gif")); //$NON-NLS-1$
reg.put(IMG_LOOKUP,
ImageDescriptor.createFromFile(getClass(), "/icons/search.gif")); //$NON-NLS-1$
reg.put(IMG_BUILD_ONE,
ImageDescriptor.createFromFile(getClass(), "/icons/build_one.png")); //$NON-NLS-1$
reg.put(IMG_WIFI,
ImageDescriptor.createFromFile(getClass(), "/icons/wireless.png")); //$NON-NLS-1$
}
public static Image resize(Image original, int width, int height,
boolean disposeOriginal, boolean keepAspectRatio) {
Display display = PlatformUI.getWorkbench().getActiveWorkbenchWindow()
.getShell().getDisplay();
if (keepAspectRatio) {
int originalWidth = original.getBounds().width;
int originalHeight = original.getBounds().height;
double aspectRatio = (double) originalWidth
/ (double) originalHeight;
double newWidth = height * aspectRatio;
if (newWidth > width && width > 0) {
double overSizeRatio = newWidth / width;
newWidth = width;
height = (int) Math.floor(height / overSizeRatio);
}
width = (int) newWidth;
}
Image scaled = new Image(display, width, height);
GC gc = new GC(scaled);
gc.setAntialias(SWT.ON);
gc.drawImage(original, 0, 0, original.getBounds().width,
original.getBounds().height, 0, 0, width, height);
gc.dispose();
if (disposeOriginal) {
original.dispose();
}
return scaled;
}
public void showHelp(String helpResource, boolean showInExternalBrowser) {
if (helpResource != null) {
if (showInExternalBrowser) {
try {
URL urlToHelpDoc = FileLocator.find(
Platform.getBundle("com.mobilesorcery.sdk.help"), //$NON-NLS-1$
new Path(helpResource), null);
if (urlToHelpDoc == null) {
throw new IllegalStateException(
"Help files not available!");
}
URL fileUrlToHelpDoc = FileLocator.toFileURL(urlToHelpDoc);
PlatformUI.getWorkbench().getBrowserSupport()
.getExternalBrowser().openURL(fileUrlToHelpDoc);
} catch (Exception e) {
org.eclipse.jface.util.Policy.getStatusHandler().show(
new Status(IStatus.ERROR, PLUGIN_ID,
"Could not show help", e),
"Could not show help");
CoreMoSyncPlugin.getDefault().log(e);
}
} else {
PlatformUI.getWorkbench().getHelpSystem()
.displayHelpResource(helpResource);
}
}
}
public String getUserHash() {
return MoSyncTool.getDefault().getProperty(MoSyncTool.USER_HASH_PROP_2);
}
public String getUserHalfHash() {
String hash = getUserHash();
if (hash != null) {
return hash.substring(0, hash.length() / 2);
}
return null;
}
private void addHalfHash(Map<String, String> request) {
request.put("hhash", getUserHalfHash()); //$NON-NLS-1$
}
// REFACTOR AFTER 3.0.
public Map<String, String> getVersionParameters() {
HashMap<String, String> params = new HashMap<String, String>();
String versionStr = MoSyncTool.getDefault().getVersionInfo(MoSyncTool.BINARY_VERSION);
// For now we send the same version for all components.
params.put("db", versionStr); //$NON-NLS-1$
params.put("sdk", versionStr); //$NON-NLS-1$
params.put("ide", versionStr); //$NON-NLS-1$
return params;
}
/**
* Returns a set of version parameters that may be used by updaters, help
* urls, etc, to inform the server about the user's registration status.
*
* @param hashOnly
* @return
*/
public Map<String, String> getVersionParameters(boolean hashOnly) {
HashMap<String, String> params = new HashMap<String, String>();
if (!hashOnly) {
params.putAll(getVersionParameters());
}
addHalfHash(params);
params.put("hhash", getUserHalfHash()); //$NON-NLS-1$
return params;
}
private void initializeCustomActivities() {
boolean enable = Boolean.TRUE.equals(IsExperimentalTester
.isExperimental());
boolean disable = Boolean.FALSE.equals(IsExperimentalTester
.isExperimental());
if (enable || disable) {
IWorkbenchActivitySupport activitySupport = PlatformUI
.getWorkbench().getActivitySupport();
ICategory category = activitySupport.getActivityManager()
.getCategory("com.mobilesorcery.activities.experimental"); //$NON-NLS-1$
if (category != null) {
HashSet<String> activityIds = new HashSet<String>(
activitySupport.createWorkingCopy()
.getEnabledActivityIds());
for (Object binding : category.getCategoryActivityBindings()) {
if (enable) {
activityIds.add(((ICategoryActivityBinding) binding)
.getActivityId());
} else {
activityIds.remove(((ICategoryActivityBinding) binding)
.getActivityId());
}
}
activitySupport.setEnabledActivityIds(activityIds);
}
}
}
public IEmulatorLaunchConfigurationPart getEmulatorLauncherPart(String id) {
initializeLauncherParts();
return launcherParts.get(id);
}
/**
* <p>
* Returns a standard font used throughout the MoSync IDE. Clients should
* <b>not</b> dispose these fonts.
* </p>
*
* @param fontId
* @return
*/
public Font getFont(String fontId) {
if (Display.getCurrent() == null) {
throw new AssertionFailedException("Must be called from UI thread"); //$NON-NLS-1$
}
return getFontRegistry(Display.getCurrent()).get(fontId);
}
private synchronized FontRegistry getFontRegistry(Display current) {
FontRegistry registry = fontRegistries.get(current);
if (registry == null) {
registry = new FontRegistry(current);
fontRegistries.put(current, registry);
initRegistry(registry);
}
return registry;
}
private void initRegistry(FontRegistry registry) {
int infoTextSizeDelta = Util.isMac() ? -2 : -1;
registry.put(FONT_INFO_TEXT, UIUtils.modifyFont((FontData[]) null,
SWT.DEFAULT, infoTextSizeDelta));
registry.put(FONT_DEFAULT_BOLD,
UIUtils.modifyFont((FontData[]) null, SWT.BOLD, 0));
registry.put(FONT_DEFAULT_ITALIC,
UIUtils.modifyFont((FontData[]) null, SWT.ITALIC, 0));
}
@Override
public void memoryUsageLow() {
final Display d = PlatformUI.getWorkbench().getDisplay();
MemoryLowDialog.open(d);
}
public Image getPlatformImage(IVendor vendor, Point imageSize) {
String key = imageSize + Messages.MosyncUIPlugin_0 + vendor.getName();
Object image = platformImages.get(key);
if (image == null) {
Object addImage = NULL;
ImageDescriptor vendorImageDesc = vendor.getIcon();
if (vendorImageDesc != null) {
addImage = vendorImageDesc.createImage();
if (imageSize != null) {
addImage = MosyncUIPlugin.resize((Image) addImage,
imageSize.x, imageSize.y, true, true);
}
}
platformImages.put(key, addImage);
image = addImage;
if (CoreMoSyncPlugin.getDefault().isDebugging()) {
CoreMoSyncPlugin.trace("Allocated image " + key); //$NON-NLS-1$
}
}
return (Image) (image == NULL ? null : image);
}
public void disposePlatformImages() {
platformImages.clear();
}
@Override
public void resourceChanged(final IResourceChangeEvent event) {
if (!PlatformUI.isWorkbenchRunning()) {
return;
}
UIUtils.onUiThread(PlatformUI.getWorkbench().getDisplay(),
new Runnable() {
@Override
public void run() {
if (event.getType() == IResourceChangeEvent.POST_CHANGE) {
if (event.getSource() instanceof IProject || event.getSource() instanceof IWorkspace) {
updateCurrentlySelectedProject(PlatformUI
.getWorkbench()
.getActiveWorkbenchWindow());
}
}
}
}, true);
}
/**
* <p>Waits for the workbench to startup (if <code>null</code> is passed
* as the listener) or asynchronously sends a message to the listener
* once it's started.</p>
* @param listener The listener to receive events, or <code>null</code> if this
* method should block until the workbench has started.
*/
public void awaitWorkbenchStartup(final IWorkbenchStartupListener listener) {
TimerTask awaitRunnable = new TimerTask() {
@Override
public void run() {
try {
if (!isWorkbenchStarted()) {
workbenchStarted.await(WB_WAIT_TIMEOUT, TimeUnit.SECONDS);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
if (listener != null) {
listener.started(PlatformUI.getWorkbench());
}
}
};
if (listener == null) {
awaitRunnable.run();
} else {
Thread t = new Thread(awaitRunnable);
t.setDaemon(true);
t.start();
}
}
@Override
public void earlyStartup() {
workbenchStarted.countDown();
}
public boolean isWorkbenchStarted() {
return PlatformUI.isWorkbenchRunning() && !PlatformUI.getWorkbench().isStarting() && !PlatformUI.getWorkbench().isClosing();
}
public IBuildStepEditor createBuildStepEditor(MoSyncProject project, IBuildStepFactory factory) {
if (factory == null) {
return null;
}
IBuildStepEditor editor = null;
if (factory instanceof CommandLineBuildStep.Factory) {
editor = new CommandLineBuildStepEditor();
} else if (factory instanceof CopyBuildResultBuildStep.Factory) {
editor = new CopyBuildStepEditor();
} else {
editor = createBuildStepEditorExtension(factory.getId());
}
if (editor != null) {
editor.setProject(project);
editor.setBuildStepFactory(factory);
}
return editor;
}
private IBuildStepEditor createBuildStepEditorExtension(String id) {
if (buildStepEditorsExtensions == null) {
buildStepEditorsExtensions = new HashMap<String, IConfigurationElement>();
IExtensionRegistry registry = Platform.getExtensionRegistry();
IConfigurationElement[] elements = registry
.getConfigurationElementsFor(IBuildStepEditor.EXTENSION_ID);
for (IConfigurationElement element : elements) {
String extId = element.getAttribute("id");
buildStepEditorsExtensions.put(extId, element);
}
}
try {
IConfigurationElement ext = buildStepEditorsExtensions.get(id);
if (ext != null) {
return (IBuildStepEditor) ext.createExecutableExtension("implementation");
}
} catch (CoreException e) {
CoreMoSyncPlugin.getDefault().log(e);
}
return null;
}
}