From 83ac34ef096f327f30c801d27ee7c1469f16894d Mon Sep 17 00:00:00 2001 From: Kondal Kolipaka Date: Thu, 17 Aug 2017 16:20:43 +0800 Subject: [PATCH 1/3] Portal plugin experiment --- .../com.aptana.portal.ui/META-INF/MANIFEST.MF | 15 +- plugins/com.aptana.portal.ui/plugin.xml | 62 --- .../com/aptana/portal/ui/PortalUIPlugin.java | 226 ++++---- .../browser/AbstractPortalBrowserEditor.java | 3 - .../ui/browser/HyperlinkMessageDialog.java | 158 ++++++ .../com/aptana/portal/ui/browser/UIUtils.java | 64 +++ .../ui/browser/WorkbenchBrowserUtil.java | 235 +++++++++ .../TemplateActionController.java | 129 ----- .../ThemeActionController.java | 158 ------ .../WorkbenchActionController.java | 67 --- .../DispatcherBrowserFunction.java | 21 - .../TemplatesNotification.java | 126 ----- .../InstallerConfigurationProcessor.java | 286 ---------- .../JavaScriptLibraryInstallProcessor.java | 269 ---------- .../configurationProcessors/Messages.java | 96 ---- .../PythonInstallProcessor.java | 429 --------------- .../RubyInstallProcessor.java | 391 -------------- .../VersionsConfigurationProcessor.java | 207 -------- .../XAMPPInstallProcessor.java | 487 ------------------ .../installer/InstallerOptionsDialog.java | 308 ----------- .../JavaScriptImporterOptionsDialog.java | 412 --------------- .../messages.properties | 68 --- .../CachedVersionProcessorDelegate.java | 136 ----- .../RailsVersionProcessor.java | 27 - .../RubyVersionProcessor.java | 27 - .../SQLiteVersionProcessor.java | 28 - .../com/aptana/portal/ui/internal/Portal.java | 135 +++-- .../NewProjectFromTemplateCommandHandler.java | 109 ++-- .../startpage/StartPageBrowserEditor.java | 2 +- plugins/com.aptana.projects/plugin.xml | 8 - 30 files changed, 655 insertions(+), 4034 deletions(-) create mode 100644 plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/browser/HyperlinkMessageDialog.java create mode 100644 plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/browser/UIUtils.java create mode 100644 plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/browser/WorkbenchBrowserUtil.java delete mode 100644 plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/actionControllers/TemplateActionController.java delete mode 100644 plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/actionControllers/ThemeActionController.java delete mode 100644 plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/actionControllers/WorkbenchActionController.java delete mode 100644 plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/browserNotifications/TemplatesNotification.java delete mode 100644 plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/InstallerConfigurationProcessor.java delete mode 100644 plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/JavaScriptLibraryInstallProcessor.java delete mode 100644 plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/Messages.java delete mode 100644 plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/PythonInstallProcessor.java delete mode 100644 plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/RubyInstallProcessor.java delete mode 100644 plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/VersionsConfigurationProcessor.java delete mode 100644 plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/XAMPPInstallProcessor.java delete mode 100644 plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/installer/InstallerOptionsDialog.java delete mode 100644 plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/installer/JavaScriptImporterOptionsDialog.java delete mode 100644 plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/messages.properties delete mode 100644 plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/processorDelegates/CachedVersionProcessorDelegate.java delete mode 100644 plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/processorDelegates/RailsVersionProcessor.java delete mode 100644 plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/processorDelegates/RubyVersionProcessor.java delete mode 100644 plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/processorDelegates/SQLiteVersionProcessor.java diff --git a/plugins/com.aptana.portal.ui/META-INF/MANIFEST.MF b/plugins/com.aptana.portal.ui/META-INF/MANIFEST.MF index d123f7f7ed..24afa9c752 100644 --- a/plugins/com.aptana.portal.ui/META-INF/MANIFEST.MF +++ b/plugins/com.aptana.portal.ui/META-INF/MANIFEST.MF @@ -6,19 +6,16 @@ Bundle-Version: 3.0.0.qualifier Bundle-Activator: com.aptana.portal.ui.PortalUIPlugin Bundle-Vendor: %providerName Require-Bundle: com.aptana.jetty.util.epl, - com.aptana.core, - com.aptana.core.io, org.eclipse.ui.browser, org.eclipse.ui.console, org.eclipse.debug.ui, - com.aptana.ui, com.aptana.configurations, - com.aptana.usage;bundle-version="4.0.0", - com.aptana.theme, - com.aptana.explorer, com.aptana.browser;visibility:=reexport, - com.aptana.projects, - org.eclipse.e4.ui.workbench;resolution:=optional + org.eclipse.e4.ui.workbench;resolution:=optional, + org.eclipse.ui, + org.eclipse.core.runtime, + org.eclipse.core.expressions, + com.aptana.core Bundle-RequiredExecutionEnvironment: J2SE-1.5 Bundle-ActivationPolicy: lazy Export-Package: com.aptana.portal.ui, @@ -27,8 +24,6 @@ Export-Package: com.aptana.portal.ui, com.aptana.portal.ui.dispatch.actionControllers, com.aptana.portal.ui.dispatch.browserFunctions, com.aptana.portal.ui.dispatch.browserNotifications, - com.aptana.portal.ui.dispatch.configurationProcessors, - com.aptana.portal.ui.dispatch.configurationProcessors.installer, com.aptana.portal.ui.dispatch.processorDelegates, com.aptana.portal.ui.internal;x-internal:=true, com.aptana.portal.ui.internal.command;x-internal:=true, diff --git a/plugins/com.aptana.portal.ui/plugin.xml b/plugins/com.aptana.portal.ui/plugin.xml index 14ee2e207e..6867bf0a7d 100644 --- a/plugins/com.aptana.portal.ui/plugin.xml +++ b/plugins/com.aptana.portal.ui/plugin.xml @@ -18,57 +18,6 @@ class="com.aptana.portal.ui.internal.startup.PortalStartup"> - - - - - - - - - - - - - - - - - - - - - - diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/PortalUIPlugin.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/PortalUIPlugin.java index 8324ecc25c..7629529c22 100644 --- a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/PortalUIPlugin.java +++ b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/PortalUIPlugin.java @@ -7,28 +7,12 @@ */ package com.aptana.portal.ui; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.preferences.IPreferencesService; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.ImageRegistry; import org.eclipse.swt.graphics.Image; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.IEditorReference; -import org.eclipse.ui.IViewReference; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.PlatformUI; import org.eclipse.ui.plugin.AbstractUIPlugin; import org.osgi.framework.BundleContext; -import com.aptana.core.resources.IProjectContext; -import com.aptana.explorer.ExplorerPlugin; -import com.aptana.explorer.IExplorerUIConstants; -import com.aptana.explorer.IPreferenceConstants; - /** * The activator class controls the plug-in life cycle */ @@ -86,111 +70,111 @@ public static PortalUIPlugin getDefault() { return plugin; } - - /** - * Try to resolve and return the last active project in the App Explorer. - * - * @return The active IProject. Can be null if not resolved. - */ - public static IProject getActiveProject() - { - // FIXME: Shalom - This is a modified of a code taken from the com.aptana.explorer plugin. Change this code to - // use a more generic solution for the active project problem once it's implemented. - - // First try and get the active project for the instance of the App Explorer open in the active window - final IProject[] projects = new IProject[1]; - PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() - { - public void run() - { - IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); - if (window == null) - { - return; - } - IWorkbenchPage page = window.getActivePage(); - if (page == null) - { - return; - } - // First, check the view references. - IViewReference[] refs = page.getViewReferences(); - if (refs == null) - { - return; - } - for (IViewReference ref : refs) - { - if (ref == null || !ref.getId().equals(IExplorerUIConstants.VIEW_ID)) - { - continue; - } - IProjectContext view = (IProjectContext) ref.getPart(false); - if (view == null) - { - continue; - } - IProject activeProject = view.getActiveProject(); - if (activeProject != null) - { - projects[0] = activeProject; - return; - } - } - // If we got to this point, we could not find the SingleProjectView and its active project. - // Try to find the a project by the active editor. - IEditorPart activeEditor = page.getActiveEditor(); - if (activeEditor != null) - { - IResource resource = null; - if (activeEditor.getEditorInput().getPersistable() != null) - { - // it's probably a non-browser editor. - resource = (IResource) activeEditor.getEditorInput().getAdapter(IResource.class); - } - else - { - // look for the first persistable editor input we can find. - IEditorReference[] editorReferences = page.getEditorReferences(); - for (IEditorReference reference : editorReferences) - { - IEditorPart editor = reference.getEditor(false); - if (editor != null) - { - resource = (IResource) editor.getEditorInput().getAdapter(IResource.class); - if (resource != null) - { - break; - } - } - } - } - if (resource != null) - { - projects[0] = ((IResource) resource).getProject(); - return; - } - } - } - }); - if (projects[0] != null) - { - return projects[0]; - } - - // Fall back to using project stored in prefs. - IPreferencesService preferencesService = Platform.getPreferencesService(); - String activeProjectName = preferencesService.getString(ExplorerPlugin.PLUGIN_ID, - IPreferenceConstants.ACTIVE_PROJECT, null, null); - IProject result = null; - - if (activeProjectName != null) - { - result = ResourcesPlugin.getWorkspace().getRoot().getProject(activeProjectName); - } - - return result; - } +// +// /** +// * Try to resolve and return the last active project in the App Explorer. +// * +// * @return The active IProject. Can be null if not resolved. +// */ +// public static IProject getActiveProject() +// { +// // FIXME: Shalom - This is a modified of a code taken from the com.aptana.explorer plugin. Change this code to +// // use a more generic solution for the active project problem once it's implemented. +// +// // First try and get the active project for the instance of the App Explorer open in the active window +// final IProject[] projects = new IProject[1]; +// PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() +// { +// public void run() +// { +// IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); +// if (window == null) +// { +// return; +// } +// IWorkbenchPage page = window.getActivePage(); +// if (page == null) +// { +// return; +// } +// // First, check the view references. +// IViewReference[] refs = page.getViewReferences(); +// if (refs == null) +// { +// return; +// } +// for (IViewReference ref : refs) +// { +// if (ref == null || !ref.getId().equals(IExplorerUIConstants.VIEW_ID)) +// { +// continue; +// } +// IProjectContext view = (IProjectContext) ref.getPart(false); +// if (view == null) +// { +// continue; +// } +// IProject activeProject = view.getActiveProject(); +// if (activeProject != null) +// { +// projects[0] = activeProject; +// return; +// } +// } +// // If we got to this point, we could not find the SingleProjectView and its active project. +// // Try to find the a project by the active editor. +// IEditorPart activeEditor = page.getActiveEditor(); +// if (activeEditor != null) +// { +// IResource resource = null; +// if (activeEditor.getEditorInput().getPersistable() != null) +// { +// // it's probably a non-browser editor. +// resource = (IResource) activeEditor.getEditorInput().getAdapter(IResource.class); +// } +// else +// { +// // look for the first persistable editor input we can find. +// IEditorReference[] editorReferences = page.getEditorReferences(); +// for (IEditorReference reference : editorReferences) +// { +// IEditorPart editor = reference.getEditor(false); +// if (editor != null) +// { +// resource = (IResource) editor.getEditorInput().getAdapter(IResource.class); +// if (resource != null) +// { +// break; +// } +// } +// } +// } +// if (resource != null) +// { +// projects[0] = ((IResource) resource).getProject(); +// return; +// } +// } +// } +// }); +// if (projects[0] != null) +// { +// return projects[0]; +// } +// +// // Fall back to using project stored in prefs. +// IPreferencesService preferencesService = Platform.getPreferencesService(); +// String activeProjectName = preferencesService.getString(ExplorerPlugin.PLUGIN_ID, +// IPreferenceConstants.ACTIVE_PROJECT, null, null); +// IProject result = null; +// +// if (activeProjectName != null) +// { +// result = ResourcesPlugin.getWorkspace().getRoot().getProject(activeProjectName); +// } +// +// return result; +// } public static Image getImage(String string) { diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/browser/AbstractPortalBrowserEditor.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/browser/AbstractPortalBrowserEditor.java index e392b98a14..21038f2239 100644 --- a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/browser/AbstractPortalBrowserEditor.java +++ b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/browser/AbstractPortalBrowserEditor.java @@ -45,9 +45,6 @@ import com.aptana.portal.ui.internal.BrowserViewerWrapper; import com.aptana.portal.ui.internal.BrowserWrapper; import com.aptana.portal.ui.internal.startpage.IStartPageUISystemProperties; -import com.aptana.ui.dialogs.HyperlinkMessageDialog; -import com.aptana.ui.util.UIUtils; -import com.aptana.ui.util.WorkbenchBrowserUtil; /** * A portal browser editor. diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/browser/HyperlinkMessageDialog.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/browser/HyperlinkMessageDialog.java new file mode 100644 index 0000000000..575be5d354 --- /dev/null +++ b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/browser/HyperlinkMessageDialog.java @@ -0,0 +1,158 @@ +/** + * Aptana Studio + * Copyright (c) 2005-2012 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). + * Please see the license.html included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ +package com.aptana.portal.ui.browser; + +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Link; +import org.eclipse.swt.widgets.Shell; + +import com.aptana.core.util.StringUtil; + +/** + * @author Max Stepanov + */ +public class HyperlinkMessageDialog extends MessageDialog +{ + + private Link messageLink; + + private String toggleMessage; + private boolean toggleState; + + /** + * @param parentShell + * @param dialogTitle + * @param dialogTitleImage + * @param dialogMessage + * @param dialogImageType + * @param dialogButtonLabels + * @param defaultIndex + */ + public HyperlinkMessageDialog(Shell parentShell, String dialogTitle, Image dialogTitleImage, String dialogMessage, + int dialogImageType, String[] dialogButtonLabels, int defaultIndex, String toggleMessage) + { + super(parentShell, dialogTitle, dialogTitleImage, dialogMessage, dialogImageType, dialogButtonLabels, + defaultIndex); + this.toggleMessage = toggleMessage; + } + + public boolean getToggleState() + { + return toggleState; + } + + @Override + protected Control createDialogArea(Composite parent) + { + Composite dialogAreaComposite = (Composite) super.createDialogArea(parent); + if (!StringUtil.isEmpty(toggleMessage)) + { + createToggleButton(dialogAreaComposite); + } + return dialogAreaComposite; + } + + /* + * (non-Javadoc) + * @see org.eclipse.jface.dialogs.IconAndMessageDialog#createMessageArea(org.eclipse.swt.widgets.Composite) + */ + @Override + protected Control createMessageArea(Composite composite) + { + String message = this.message; + this.message = null; + Composite messageArea = (Composite) super.createMessageArea(composite); + messageLink = new Link(messageArea, getMessageLabelStyle() | SWT.NO_FOCUS); + messageLink.setText("" + message); //$NON-NLS-1$ + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.BEGINNING).grab(true, false) + .hint(convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH), SWT.DEFAULT) + .applyTo(messageLink); + messageLink.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + openLink(e); + } + }); + return messageArea; + } + + protected Button createToggleButton(Composite parent) + { + final Button button = new Button(parent, SWT.CHECK | SWT.LEFT); + button.setLayoutData(GridDataFactory.swtDefaults().span(2, 1).create()); + button.setFont(parent.getFont()); + button.setText(toggleMessage); + button.addSelectionListener(new SelectionAdapter() + { + + public void widgetSelected(SelectionEvent e) + { + toggleState = button.getSelection(); + } + }); + + return button; + } + + protected void openLink(SelectionEvent e) + { + WorkbenchBrowserUtil.launchExternalBrowser(e.text); + } + + public static boolean open(int kind, Shell parent, String title, String message, int style) + { + return open(kind, parent, title, message, null, style); + } + + public static boolean open(int kind, Shell parent, String title, String message, String toggleMessage, int style) + { + HyperlinkMessageDialog dialog = new HyperlinkMessageDialog(parent, title, null, message, kind, + getButtonLabels(kind), 0, toggleMessage); + return dialog.open() == 0; + } + + public static void openInformation(Shell parent, String title, String message) + { + open(INFORMATION, parent, title, message, null, SWT.NONE); + } + + public static void openError(Shell parent, String title, String message) + { + open(ERROR, parent, title, message, SWT.NONE); + } + + public static String[] getButtonLabels(int kind) + { + switch (kind) + { + case ERROR: + case INFORMATION: + case WARNING: + return new String[] { IDialogConstants.OK_LABEL }; + case CONFIRM: + return new String[] { IDialogConstants.OK_LABEL, IDialogConstants.CANCEL_LABEL }; + case QUESTION: + return new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL }; + case QUESTION_WITH_CANCEL: + return new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL, + IDialogConstants.CANCEL_LABEL }; + default: + throw new IllegalArgumentException("Illegal value for kind in HyperlinkMessageDialog.open()"); //$NON-NLS-1$ + } + } +} diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/browser/UIUtils.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/browser/UIUtils.java new file mode 100644 index 0000000000..86b47d9dc9 --- /dev/null +++ b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/browser/UIUtils.java @@ -0,0 +1,64 @@ +package com.aptana.portal.ui.browser; + +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +public class UIUtils +{ + + /** + * Gets the active shell for the workbench + * + * @return the active shell + */ + public static Shell getActiveShell() + { + Shell shell = getDisplay().getActiveShell(); + if (shell == null) + { + IWorkbenchWindow window = getActiveWorkbenchWindow(); + if (window != null) + { + shell = window.getShell(); + } + } + return shell; + } + + /** + * Gets the display for the workbench + * + * @return the display + */ + public static Display getDisplay() + { + return PlatformUI.getWorkbench().getDisplay(); + } + + public static IWorkbenchWindow getActiveWorkbenchWindow() + { + try + { + return PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + } + catch (IllegalStateException e) + { + // Workbench has not been created yet + return null; + } + } + + public static IWorkbenchPage getActivePage() + { + IWorkbenchWindow workbench = getActiveWorkbenchWindow(); + if (workbench == null) + { + return null; + } + return workbench.getActivePage(); + } + +} diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/browser/WorkbenchBrowserUtil.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/browser/WorkbenchBrowserUtil.java new file mode 100644 index 0000000000..a3cee606df --- /dev/null +++ b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/browser/WorkbenchBrowserUtil.java @@ -0,0 +1,235 @@ +/** + * Aptana Studio + * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). + * Please see the license.html included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ + +package com.aptana.portal.ui.browser; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.swt.program.Program; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.browser.IWebBrowser; +import org.eclipse.ui.browser.IWorkbenchBrowserSupport; + +import com.aptana.core.logging.IdeLog; +import com.aptana.core.util.IProcessRunner; +import com.aptana.core.util.PlatformUtil; +import com.aptana.core.util.ProcessRunner; +import com.aptana.core.util.StringUtil; +import com.aptana.portal.ui.PortalUIPlugin; + +/** + * @author Max Stepanov + */ +public class WorkbenchBrowserUtil +{ + + private static final Pattern ARG_SPLITTER = Pattern.compile("([^\"]\\S*|\".+?\")\\s*"); //$NON-NLS-1$ + + private IProcessRunner runner; + private IWorkbenchBrowserSupport support; + + /** + * + */ + private WorkbenchBrowserUtil() + { + this(new ProcessRunner(), PlatformUI.getWorkbench().getBrowserSupport()); + } + + protected WorkbenchBrowserUtil(IProcessRunner runner, IWorkbenchBrowserSupport support) + { + this.runner = runner; + this.support = support; + } + + public static void launchExternalBrowser(String url) + { + try + { + launchExternalBrowser(new URL(url)); + } + catch (MalformedURLException e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), e); + } + } + + public static void launchExternalBrowser(URL url) + { + launchExternalBrowser(url, null); + } + + public static IWebBrowser launchExternalBrowser(String url, String browserId) + { + try + { + return launchExternalBrowser(new URL(url), browserId); + } + catch (MalformedURLException e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), e); + } + return null; + } + + public static IWebBrowser launchExternalBrowser(URL url, String browserId) + { + return new WorkbenchBrowserUtil().doLaunchExternalBrowser(url, browserId); + } + + IWebBrowser doLaunchExternalBrowser(URL url, String browserId) + { + if (browserId != null) + { + try + { + IWebBrowser webBrowser = support.createBrowser(IWorkbenchBrowserSupport.AS_EXTERNAL, browserId, null, + null); + if (webBrowser != null) + { + webBrowser.openURL(url); + return webBrowser; + } + } + catch (PartInitException e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), e); + } + } + try + { + IWebBrowser webBrowser = support.getExternalBrowser(); + webBrowser.openURL(url); + return webBrowser; + } + catch (Exception e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), e); + launchBrowserByCommand(url); + } + return null; + } + + /** + * If we try to open URLs in the splash (before the platform loads), we typically fail and need a fallback mechanism + * to open URLs externally. + * + * @param url + */ + public static void launchBrowserByCommand(URL url) + { + new WorkbenchBrowserUtil().doLaunchBrowserByCommand(url); + } + + @SuppressWarnings("nls") + void doLaunchBrowserByCommand(URL url) + { + if (launchProgram(url)) + { + return; + } + + // Can we fall back to running a command to load the URL? + if (isMac()) + { + runner.runInBackground("open", url.toString()); + } + else if (isWindows()) + { + List args = new ArrayList(); + IStatus result = runner.runInBackground("reg", "query", "HKEY_CLASSES_ROOT\\http\\shell\\open\\command"); + if (result.isOK()) + { + String output = result.getMessage(); + int index = output.indexOf("REG_SZ"); + if (index != -1) + { + output = output.substring(index + 6); + // Split by lines, take first line, remove leading and trailing whitespace + String firstLine = StringUtil.LINE_SPLITTER.split(output)[0].trim(); + // Now grab all the args which are delimited by spaces, unless quoted. + Matcher m = ARG_SPLITTER.matcher(firstLine); + while (m.find()) + { + // Replace %1 with the url we want to hit + args.add(StringUtil.stripQuotes(m.group(1)).replace("%1", url.toString())); + } + } + } + // We failed to grab the location of the default browser from the registry! + if (args.isEmpty()) + { + args.add("iexplore.exe"); + args.add(url.toString()); + } + runner.runInBackground(args.toArray(new String[args.size()])); + } + else + { + runner.runInBackground("xdg-open", url.toString()); + } + } + + /** + * Attempts to use {@link Program#launch(String)} to open a URL. + * + * @param url + * @return + */ + protected boolean launchProgram(URL url) + { + return Program.launch(url.toString()); + } + + protected boolean isWindows() + { + return PlatformUtil.isWindows(); + } + + protected boolean isMac() + { + return PlatformUtil.isMac(); + } + + /** + * Opens an URL with the default settings (which will typically open in an internal browser with no toolbar/url + * bar/etc). + * + * @param url + * @return + */ + public static IWebBrowser openURL(String url) + { + return new WorkbenchBrowserUtil().doOpenURL(url); + } + + IWebBrowser doOpenURL(String url) + { + try + { + IWebBrowser webBrowser = support.createBrowser(null); + if (webBrowser != null) + { + webBrowser.openURL(new URL(url)); + } + return webBrowser; + } + catch (Exception e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), e); + } + return null; + } +} diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/actionControllers/TemplateActionController.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/actionControllers/TemplateActionController.java deleted file mode 100644 index 903aa35621..0000000000 --- a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/actionControllers/TemplateActionController.java +++ /dev/null @@ -1,129 +0,0 @@ -/** - * Aptana Studio - * Copyright (c) 2011 by Appcelerator, Inc. All Rights Reserved. - * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). - * Please see the license.html included with this distribution for details. - * Any modifications to this file must keep this entire header intact. - */ -package com.aptana.portal.ui.dispatch.actionControllers; - -import java.net.URI; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.aptana.configurations.processor.ConfigurationStatus; -import com.aptana.core.projects.templates.IProjectTemplate; -import com.aptana.core.projects.templates.TemplateType; -import com.aptana.core.util.ResourceUtil; -import com.aptana.core.util.StringUtil; -import com.aptana.jetty.util.epl.ajax.JSON; -import com.aptana.projects.ProjectsPlugin; - -/** - * Action controller for Template operations - * - * @author nle - */ -public class TemplateActionController extends AbstractActionController -{ - /** - * Template-Info enum. - */ - public static enum TEMPLATE_INFO - { - ID("id"), //$NON-NLS-1$ - NAME("name"), //$NON-NLS-1$ - DESCRIPTION("description"), //$NON-NLS-1$ - TEMPLATE_TYPE("type"), //$NON-NLS-1$ - IMAGE_URL("image"), //$NON-NLS-1$ - TAG("tag"); //$NON-NLS-1$ - - private String key; - - private TEMPLATE_INFO(String key) - { - this.key = key; - } - - public String toString() - { - return key; - } - }; - - private static final String[] ALL_TYPES = new String[] { TemplateType.PHP.name(), TemplateType.PYTHON.name(), - TemplateType.RAILS.name(), TemplateType.RUBY.name(), TemplateType.TITANIUM_DESKTOP.name(), - TemplateType.TITANIUM_MOBILE.name(), TemplateType.WEB.name() }; - - public void configurationStateChanged(ConfigurationStatus status, Set attributesChanged) - { - } - - /** - * Return the template types - * - * @return - */ - @ControllerAction - public Object getTemplateTypes() - { - return JSON.toString(ALL_TYPES); - } - - /** - * Return the template for give types - * - * @return - */ - @ControllerAction - public Object getTemplates(Object templateTypes) - { - List types = new ArrayList(); - if (!(templateTypes instanceof Object[]) || ((Object[]) templateTypes).length < 1) - { - templateTypes = ALL_TYPES; - } - - for (Object object : (Object[]) templateTypes) - { - if (object instanceof String) - { - TemplateType templateType = TemplateType.valueOf((String) object); - if (templateType != null) - { - types.add(templateType); - } - } - } - - List templates = ProjectsPlugin.getDefault().getTemplatesManager() - .getTemplates(types.toArray(new TemplateType[types.size()])); - List> templateObjects = new ArrayList>(); - - for (IProjectTemplate template : templates) - { - if (template.getId() == null || template.getId().length() == 0) - { - continue; - } - - Map properties = new HashMap(); - properties.put(TEMPLATE_INFO.ID.toString(), template.getId()); - properties.put(TEMPLATE_INFO.NAME.toString(), template.getDisplayName()); - properties.put(TEMPLATE_INFO.DESCRIPTION.toString(), template.getDescription()); - properties.put(TEMPLATE_INFO.TEMPLATE_TYPE.toString(), template.getType().name()); - if (template.getIconURL() != null) - { - URI iconPath = ResourceUtil.resourcePathToURI(template.getIconURL()); - properties.put(TEMPLATE_INFO.IMAGE_URL.toString(), iconPath.toASCIIString()); - } - properties.put(TEMPLATE_INFO.TAG.toString(), StringUtil.join(",", template.getTags())); //$NON-NLS-1$ - templateObjects.add(properties); - } - - return JSON.toString(templateObjects.toArray(new Map[templateObjects.size()])); - } -} diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/actionControllers/ThemeActionController.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/actionControllers/ThemeActionController.java deleted file mode 100644 index d47c243c0c..0000000000 --- a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/actionControllers/ThemeActionController.java +++ /dev/null @@ -1,158 +0,0 @@ -/** - * Aptana Studio - * Copyright (c) 2005-2012 by Appcelerator, Inc. All Rights Reserved. - * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). - * Please see the license.html included with this distribution for details. - * Any modifications to this file must keep this entire header intact. - */ -package com.aptana.portal.ui.dispatch.actionControllers; - -import java.text.MessageFormat; -import java.util.Set; - -import org.eclipse.e4.core.contexts.IEclipseContext; -import org.eclipse.e4.ui.css.swt.theme.ITheme; -import org.eclipse.e4.ui.css.swt.theme.IThemeEngine; -import org.eclipse.e4.ui.model.application.MApplication; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.PlatformUI; - -import com.aptana.configurations.processor.ConfigurationStatus; -import com.aptana.core.IFilter; -import com.aptana.core.logging.IdeLog; -import com.aptana.core.util.CollectionsUtil; -import com.aptana.core.util.StringUtil; -import com.aptana.jetty.util.epl.ajax.JSON; -import com.aptana.portal.ui.PortalUIPlugin; -import com.aptana.portal.ui.dispatch.IBrowserNotificationConstants; -import com.aptana.theme.IThemeManager; -import com.aptana.theme.Theme; -import com.aptana.theme.ThemePlugin; - -/** - * Action controller that provides Theme functionalities. - * - * @author Shalom Gibly - */ -public class ThemeActionController extends AbstractActionController -{ - private static final String UNKNOWN = "Unknown"; //$NON-NLS-1$ - private IThemeManager themeManager; - - public ThemeActionController() - { - themeManager = ThemePlugin.getDefault().getThemeManager(); - } - - // ############## Actions ############### - /** - * Returns a list of theme names. - * - *
-	 *   Sample JS code:
-	 *   result = dispatch($H({controller:'portal.themes', action:"getThemes"}).toJSON());
-	 * 
- */ - @ControllerAction - public Object getThemes() - { - Set themeNames = themeManager.getThemeNames(); - return JSON.toString(themeNames.toArray(new String[themeNames.size()])); - } - - /** - * Returns the active theme name. - * - *
-	 *   Sample JS code:
-	 *   result = dispatch($H({controller:'portal.themes', action:"getActiveTheme"}).toJSON());
-	 * 
- */ - @ControllerAction - public Object getActiveTheme() - { - Theme currentTheme = themeManager.getCurrentTheme(); - return JSON.toString(currentTheme != null ? currentTheme.getName() : UNKNOWN); - } - - /** - * Set the active theme. - * - *
-	 *   Sample JS code:
-	 *   result = dispatch($H({controller:'portal.themes', action:"setActiveTheme", args:["theme-name"]}).toJSON());
-	 * 
- */ - @ControllerAction - public Object setActiveTheme(Object attributes) - { - final String themeName = getThemeName(attributes); - if (!StringUtil.isEmpty(themeName)) - { - // FIXME this is a bit of a hack, and assumes we'll have an editor and overall theme with the exact same name - // Set editor theme - Theme theme = themeManager.getTheme(themeName); - themeManager.setCurrentTheme(theme); - - // Also set overall theme - IWorkbench workbench = PlatformUI.getWorkbench(); - MApplication application = (MApplication) workbench.getService(MApplication.class); - IEclipseContext context = application.getContext(); - - IThemeEngine e4ThemeEngine = context.get(IThemeEngine.class); - ITheme selection = CollectionsUtil.find(e4ThemeEngine.getThemes(), new IFilter() - { - - public boolean include(ITheme item) - { - return themeName.equals(item.getLabel()); - } - }); - if (selection != null) - { - e4ThemeEngine.setTheme(selection, true); - } - return IBrowserNotificationConstants.JSON_OK; - } - return IBrowserNotificationConstants.JSON_ERROR; - } - - /* - * (non-Javadoc) - * @see com.aptana.configurations.processor.IConfigurationProcessorListener#configurationStateChanged(com.aptana. - * configurations.processor.ConfigurationStatus, java.util.Set) - */ - public void configurationStateChanged(ConfigurationStatus status, Set attributesChanged) - { - // Nothing to do here... - } - - /** - * Extracts a theme name from the given attributes, and returns a {@link Theme} instance that match it. - * - * @param attributes - * @return A {@link Theme}; null if there is an error, or there is not theme with the given name. - */ - private String getThemeName(Object attributes) - { - if (attributes instanceof Object[]) - { - Object[] arr = (Object[]) attributes; - if (arr.length == 1 && arr[0] != null) - { - return (String) arr[0]; - } - String message = MessageFormat - .format("Wrong argument count passed to ThemeActionController::setActiveTheme. Expected 1 and got {0}", arr.length); //$NON-NLS-1$ - IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(message)); - } - else - { - String message = MessageFormat - .format("Wrong argument type passed to ThemeActionController::setActiveTheme. Expected Object[] and got {0}", //$NON-NLS-1$ - ((attributes == null) ? "null" : attributes.getClass().getName())); //$NON-NLS-1$ - IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(message)); - } - return null; - } -} diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/actionControllers/WorkbenchActionController.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/actionControllers/WorkbenchActionController.java deleted file mode 100644 index 799daf9ec9..0000000000 --- a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/actionControllers/WorkbenchActionController.java +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Aptana Studio - * Copyright (c) 2005-2012 by Appcelerator, Inc. All Rights Reserved. - * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). - * Please see the license.html included with this distribution for details. - * Any modifications to this file must keep this entire header intact. - */ -package com.aptana.portal.ui.dispatch.actionControllers; - -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import org.eclipse.ui.IPerspectiveDescriptor; - -import com.aptana.configurations.processor.ConfigurationStatus; -import com.aptana.core.util.ArrayUtil; -import com.aptana.jetty.util.epl.ajax.JSON; -import com.aptana.ui.util.UIUtils; - -/** - * A action controller for workbench related actions. - * - * @author Shalom Gibly - */ -public class WorkbenchActionController extends AbstractActionController -{ - private static final String ID = "id"; //$NON-NLS-1$ - private static final String DESCRIPTION = "description"; //$NON-NLS-1$ - private static final String LABEL = "label"; //$NON-NLS-1$ - - // ############## Actions ############### - /** - * Returns a JSON map representation for the active perspective. - * - *
-	 *   Sample JS code:
-	 *   result = dispatch($H({controller:'portal.workbench', action:"getActivePerspective"}).toJSON());
-	 * 
- * - * @return A JSON map with label, description and id key-value pairs. - */ - @ControllerAction - public Object getActivePerspective() - { - IPerspectiveDescriptor descriptor = UIUtils.getActivePerspectiveDescriptor(); - Map result = new HashMap(); - if (descriptor == null) - { - return JSON.toString(ArrayUtil.NO_STRINGS); - } - result.put(LABEL, descriptor.getLabel()); - result.put(DESCRIPTION, descriptor.getDescription()); - result.put(ID, descriptor.getId()); - return JSON.toString(result); - } - - /* - * (non-Javadoc) - * @see com.aptana.configurations.processor.IConfigurationProcessorListener#configurationStateChanged(com.aptana. - * configurations.processor.ConfigurationStatus, java.util.Set) - */ - public void configurationStateChanged(ConfigurationStatus status, Set attributesChanged) - { - // Nothing to do here - } -} diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/browserFunctions/DispatcherBrowserFunction.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/browserFunctions/DispatcherBrowserFunction.java index 62afbc0ff8..3dcda2157d 100644 --- a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/browserFunctions/DispatcherBrowserFunction.java +++ b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/browserFunctions/DispatcherBrowserFunction.java @@ -7,7 +7,6 @@ */ package com.aptana.portal.ui.dispatch.browserFunctions; -import java.text.MessageFormat; import java.util.Map; import com.aptana.core.logging.IdeLog; @@ -18,9 +17,6 @@ import com.aptana.portal.ui.dispatch.IActionController; import com.aptana.portal.ui.dispatch.IBrowserNotificationConstants; import com.aptana.portal.ui.internal.IBrowserFunctionHandler; -import com.aptana.usage.FeatureEvent; -import com.aptana.usage.IStudioAnalytics; -import com.aptana.usage.UsagePlugin; /** * This class is the main functions dispatcher for all the registered IActionControllers. @@ -120,27 +116,10 @@ public Object function(Object[] arguments) return BrowserNotifier.toJSONErrorNotification(IBrowserNotificationConstants.JSON_ERROR_WRONG_ARGUMENTS, e.getMessage()); } - // Send an Analytics ping - sendEvent(new FeatureEvent(MessageFormat.format("{0}.{1}", controllerID, action), null)); //$NON-NLS-1$ // OK... Done with the checks. Now dispatch. return dispatch(controller, action, args); } - private void sendEvent(FeatureEvent featureEvent) - { - UsagePlugin plugin = UsagePlugin.getDefault(); - if (plugin == null) - { - return; - } - IStudioAnalytics analytics = plugin.getStudioAnalytics(); - if (analytics == null) - { - return; - } - analytics.sendEvent(featureEvent); - } - /** * Dispatch the action controller function in a synchronous way.
* The action that is being dispatched can still create a Job that will run asynchronously and report back when diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/browserNotifications/TemplatesNotification.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/browserNotifications/TemplatesNotification.java deleted file mode 100644 index ca2111bd18..0000000000 --- a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/browserNotifications/TemplatesNotification.java +++ /dev/null @@ -1,126 +0,0 @@ -/** - * Aptana Studio - * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. - * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). - * Please see the license.html included with this distribution for details. - * Any modifications to this file must keep this entire header intact. - */ -package com.aptana.portal.ui.dispatch.browserNotifications; - -import java.util.HashMap; -import java.util.Map; - -import com.aptana.jetty.util.epl.ajax.JSON; - -import com.aptana.core.logging.IdeLog; -import com.aptana.core.projects.templates.IProjectTemplate; -import com.aptana.portal.ui.IDebugScopes; -import com.aptana.portal.ui.dispatch.IBrowserNotificationConstants; -import com.aptana.portal.ui.dispatch.actionControllers.TemplateActionController.TEMPLATE_INFO; -import com.aptana.projects.ProjectsPlugin; -import com.aptana.projects.templates.IProjectTemplateListener; - -/** - * A class that notify the portal browser when a new template is loaded. - * - * @author Shalom Gibly - */ -public class TemplatesNotification extends AbstractBrowserNotification -{ - - private IProjectTemplateListener listener; - - /* - * (non-Javadoc) - * @see com.aptana.portal.ui.dispatch.browserNotifications.AbstractBrowserNotification#start() - */ - @Override - public synchronized void start() - { - isListening = true; - ProjectsPlugin.getDefault().getTemplatesManager().addListener(getListener()); - IdeLog.logInfo(ProjectsPlugin.getDefault(), "Template Portal notifier started", IDebugScopes.START_PAGE); //$NON-NLS-1$ - } - - /* - * (non-Javadoc) - * @see com.aptana.portal.ui.dispatch.browserNotifications.AbstractBrowserNotification#stop() - */ - @Override - public synchronized void stop() - { - isListening = false; - ProjectsPlugin.getDefault().getTemplatesManager().removeListener(getListener()); - listener = null; - IdeLog.logInfo(ProjectsPlugin.getDefault(), "Template Portal notifier stopped", IDebugScopes.START_PAGE); //$NON-NLS-1$ - } - - /** - * Notify a template addition - * - * @param template - */ - protected void notifyAdd(IProjectTemplate template) - { - IdeLog.logInfo(ProjectsPlugin.getDefault(), "Template added. Notifying portal...", IDebugScopes.START_PAGE); //$NON-NLS-1$ - notifyTargets(IBrowserNotificationConstants.EVENT_ID_TEMPLATES, IBrowserNotificationConstants.EVENT_TYPE_ADDED, - createTemplateInfo(template), true); - } - - /** - * Notify a template removal - * - * @param template - */ - protected void notifyRemoved(IProjectTemplate template) - { - IdeLog.logInfo(ProjectsPlugin.getDefault(), "Template removed. Notifying portal...", IDebugScopes.START_PAGE); //$NON-NLS-1$ - notifyTargets(IBrowserNotificationConstants.EVENT_ID_TEMPLATES, - IBrowserNotificationConstants.EVENT_TYPE_DELETED, createTemplateInfo(template), true); - } - - /** - * Create a JSON template info that will be send as the browser notification data. - * - * @param template - * @return A JSON representation of the template that was added or removed. - */ - protected String createTemplateInfo(IProjectTemplate template) - { - Map templateInfo = new HashMap(); - templateInfo.put(TEMPLATE_INFO.ID.toString(), template.getId()); - templateInfo.put(TEMPLATE_INFO.NAME.toString(), template.getDisplayName()); - templateInfo.put(TEMPLATE_INFO.DESCRIPTION.toString(), template.getDescription()); - templateInfo.put(TEMPLATE_INFO.TEMPLATE_TYPE.toString(), template.getType().name()); - return JSON.toString(templateInfo); - } - - /** - * @return an {@link IProjectTemplateListener} - */ - protected synchronized IProjectTemplateListener getListener() - { - if (listener == null) - { - listener = new IProjectTemplateListener() - { - public void templateAdded(IProjectTemplate template) - { - if (isListening) - { - notifyAdd(template); - } - } - - public void templateRemoved(IProjectTemplate template) - { - if (isListening) - { - notifyRemoved(template); - } - } - }; - } - return listener; - } -} diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/InstallerConfigurationProcessor.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/InstallerConfigurationProcessor.java deleted file mode 100644 index 2e7041ae58..0000000000 --- a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/InstallerConfigurationProcessor.java +++ /dev/null @@ -1,286 +0,0 @@ -/** - * Aptana Studio - * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. - * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). - * Please see the license.html included with this distribution for details. - * Any modifications to this file must keep this entire header intact. - */ -package com.aptana.portal.ui.dispatch.configurationProcessors; - -import java.io.File; -import java.net.URI; -import java.net.URISyntaxException; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.Status; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.preference.IPreferenceStore; -import org.osgi.framework.Version; - -import com.aptana.configurations.processor.AbstractConfigurationProcessor; -import com.aptana.configurations.processor.ConfigurationStatus; -import com.aptana.core.logging.IdeLog; -import com.aptana.core.util.CollectionsUtil; -import com.aptana.core.util.InputStreamGobbler; -import com.aptana.core.util.StringUtil; -import com.aptana.core.util.VersionUtil; -import com.aptana.ide.core.io.downloader.DownloadManager; -import com.aptana.jetty.util.epl.ajax.JSON; -import com.aptana.portal.ui.IPortalPreferences; -import com.aptana.portal.ui.PortalUIPlugin; -import com.aptana.ui.util.UIUtils; - -/** - * Basic, abstract implementation, of a processor that deals with installing software. - * - * @author Shalom Gibly - */ -public abstract class InstallerConfigurationProcessor extends AbstractConfigurationProcessor -{ - protected static final String APTANA_PROPERTIES_FILE_NAME = ".aptana"; //$NON-NLS-1$ - protected static final String NAME_ATTRIBUTE = "name"; //$NON-NLS-1$ - protected static final String INSTALL_DIR_ATTRIBUTE = "install_dir"; //$NON-NLS-1$ - - protected List downloadedPaths; - - /* - * (non-Javadoc) - * @see com.aptana.configurations.processor.AbstractConfigurationProcessor#computeStatus(org.eclipse.core.runtime. - * IProgressMonitor, java.lang.Object) - */ - @Override - public ConfigurationStatus computeStatus(IProgressMonitor progressMonitor, Object attributes) - { - // This one does nothing. We should compute the status in the generic VersionsConfigurationProcessor - return configurationStatus; - } - - /** - * Returns the application's name. - * - * @return The application's name (e.g. XAMPP, Ruby) - */ - protected abstract String getApplicationName(); - - /** - * Download the remote content and store it the temp directory. - * - * @param URLs - * @param progressMonitor - */ - public IStatus download(String[] URLs, IProgressMonitor progressMonitor) - { - if (URLs.length == 0) - { - String err = Messages.InstallerConfigurationProcessor_missingDownloadTargets; - applyErrorAttributes(err); - IdeLog.logError(PortalUIPlugin.getDefault(), - "We expected an array of URLs, but got an empty array.", new Exception(err)); //$NON-NLS-1$ - return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, err); - } - downloadedPaths = null; - DownloadManager downloadManager = new DownloadManager(); - List urlsList = new ArrayList(URLs.length); - for (int i = 0; i < URLs.length; i++) - { - try - { - urlsList.add(new URI(urls[i])); - } - catch (URISyntaxException mue) - { - IdeLog.logError(PortalUIPlugin.getDefault(), mue); - } - } - try - { - downloadManager.addURIs(urlsList); - IStatus status = downloadManager.start(progressMonitor); - if (status.isOK()) - { - downloadedPaths = downloadManager.getContentsLocations(); - } - return status; - } - catch (Exception e) - { - IdeLog.logError(PortalUIPlugin.getDefault(), e); - } - return Status.CANCEL_STATUS; - } - - /** - * Cache the installed application location and version in the preferences. - * - * @param installDir - * - The directory the application was installed to. - * @param versionedFileLocation - * - Can be the URL that we grabbed the installer from, or any other string that contains a version - * information in a form of x.y.z. - * @param appName - * - The application name (e.g. xampp) - */ - @SuppressWarnings("unchecked") - public void cacheVersion(String installDir, String versionedFileLocation, String appName) - - { - IPreferenceStore preferenceStore = PortalUIPlugin.getDefault().getPreferenceStore(); - String versions = preferenceStore.getString(IPortalPreferences.CACHED_VERSIONS_PROPERTY_NAME); - Map> versionsMap = null; - if (versions == null || versions.equals(StringUtil.EMPTY)) - { - versionsMap = new HashMap>(); - } - else - { - versionsMap = (Map>) JSON.parse(versions); - } - Map appVersionMap = new HashMap(); - Version version = VersionUtil.parseVersion(versionedFileLocation); - if (!VersionUtil.isEmpty(version)) - { - appVersionMap.put(IPortalPreferences.CACHED_VERSION_PROPERTY, version.toString()); - appVersionMap.put(IPortalPreferences.CACHED_LOCATION_PROPERTY, installDir); - versionsMap.put(appName.toLowerCase(), appVersionMap); - preferenceStore.setValue(IPortalPreferences.CACHED_VERSIONS_PROPERTY_NAME, JSON.toString(versionsMap)); - } - else - { - IdeLog.logError(PortalUIPlugin.getDefault(), MessageFormat.format( - "Could not cache the location and version for {0}. Install dir: {1}, versionedFileLocation: {2}", //$NON-NLS-1$ - appName, installDir, versionedFileLocation), new Exception()); - } - } - - /** - * Extract the given zip file into the target folder on a Windows machine. - * - * @param sfxZip - * Self extracting 7zip file. - * @param targetFolder - * @return The status of that extraction result. - */ - public static IStatus extractWin(IPath sfxZip, IPath targetFolder) - { - IStatus errorStatus = new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, - Messages.InstallerConfigurationProcessor_unableToExtractZip); - if (!Platform.OS_WIN32.equals(Platform.getOS())) - { - IdeLog.logError( - PortalUIPlugin.getDefault(), - "Unable to extract the Zip file. A Windows OS extractor was called for a non-Windows platform.", new Exception()); //$NON-NLS-1$ - return errorStatus; - } - if (sfxZip == null || targetFolder == null) - { - IdeLog.logError(PortalUIPlugin.getDefault(), "Undefined zip file or target folder", new Exception()); //$NON-NLS-1$ - return errorStatus; - } - File destinationFolder = targetFolder.toFile(); - if (!destinationFolder.exists() && !destinationFolder.mkdirs()) - { - IdeLog.logError(PortalUIPlugin.getDefault(), - "Failed to create destination directory " + destinationFolder, new Exception()); //$NON-NLS-1$ - return errorStatus; - } - // TODO Use ProcessUtil! - ProcessBuilder processBuilder = new ProcessBuilder(sfxZip.toOSString(), "-o" + targetFolder.toOSString(), //$NON-NLS-1$ - "-y", //$NON-NLS-1$ - sfxZip.toOSString()); - processBuilder.directory(destinationFolder); - processBuilder.redirectErrorStream(true); - String output = null; - try - { - Process process = processBuilder.start(); - InputStreamGobbler errorGobbler = new InputStreamGobbler(process.getErrorStream(), "\n", null); //$NON-NLS-1$ - InputStreamGobbler outputGobbler = new InputStreamGobbler(process.getInputStream(), "\n", null); //$NON-NLS-1$ - outputGobbler.start(); - errorGobbler.start(); - process.waitFor(); - outputGobbler.interrupt(); - errorGobbler.interrupt(); - outputGobbler.join(); - errorGobbler.join(); - output = outputGobbler.getResult(); - String errors = errorGobbler.getResult(); - int exitVal = process.exitValue(); - if (exitVal == 0) - { - return Status.OK_STATUS; - } - IdeLog.logError( - PortalUIPlugin.getDefault(), - "Zip extraction failed. The process returned " + exitVal, new Exception("Process output:\n" + errors)); //$NON-NLS-1$ //$NON-NLS-2$ - return errorStatus; - } - catch (Exception e) - { - IdeLog.logError(PortalUIPlugin.getDefault(), e); - return errorStatus; - } - finally - { - if (output != null) - { - IdeLog.logInfo(PortalUIPlugin.getDefault(), output); - } - } - } - - /** - * Display a message dialog in a UI thread. - * - * @param kind - * See {@link MessageDialog} for the types allowed. - * @param title - * @param message - */ - public void displayMessageInUIThread(final int kind, final String title, final String message) - { - UIUtils.showMessageDialogFromBgThread(kind, title, message, null); - } - - /** - * Finalize the installation.
- * This implementation just marks to delete on exit any downaloaded file. - * - * @param installDir - */ - protected void finalizeInstallation(String installDir) - { - deleteDownloadedPaths(); - // Cache the version and the location of the installed app. - // We assume here that the version of app is specified in the install URL! - if (installDir != null) - { - cacheVersion(installDir, urls[0], getApplicationName()); - } - } - - /** - * Mark the downloaded paths to be deleted on exit. - */ - protected void deleteDownloadedPaths() - { - if (!CollectionsUtil.isEmpty(downloadedPaths)) - { - for (IPath f : downloadedPaths) - { - File toDelete = f.toFile(); - if (toDelete.exists()) - { - toDelete.deleteOnExit(); - } - } - } - } -} diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/JavaScriptLibraryInstallProcessor.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/JavaScriptLibraryInstallProcessor.java deleted file mode 100644 index a27456518d..0000000000 --- a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/JavaScriptLibraryInstallProcessor.java +++ /dev/null @@ -1,269 +0,0 @@ -/** - * Aptana Studio - * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. - * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). - * Please see the license.html included with this distribution for details. - * Any modifications to this file must keep this entire header intact. - */ -package com.aptana.portal.ui.dispatch.configurationProcessors; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.MultiStatus; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.SubMonitor; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.window.Window; -import org.eclipse.osgi.util.NLS; -import org.eclipse.swt.widgets.Display; -import org.eclipse.ui.progress.UIJob; - -import com.aptana.configurations.processor.ConfigurationStatus; -import com.aptana.core.logging.IdeLog; -import com.aptana.core.util.EclipseUtil; -import com.aptana.core.util.IOUtil; -import com.aptana.portal.ui.PortalUIPlugin; -import com.aptana.portal.ui.dispatch.configurationProcessors.installer.JavaScriptImporterOptionsDialog; - -/** - * An installer (import) processor for JavaScript libraries, such as jQuery and Prototype.
- * This processor download and place the JS library under a custom javascript folder in the selected (or active) - * project. It also allows the use to select the location manually. - * - * @author Shalom Gibly - */ -public class JavaScriptLibraryInstallProcessor extends InstallerConfigurationProcessor -{ - private static final String JS_LIBRARY = "JS Library"; //$NON-NLS-1$ - private static boolean installationInProgress; - private String libraryName; - private IProject targetProject; - - /** - * Returns the JS Library name. - */ - @Override - protected String getApplicationName() - { - return libraryName; - } - - /** - * Install a JavaScript library into a user-specified project.
- * The configuration will grab the name and the location of the library from the given attributes.
- * We expect an array of attributes with the same structure described at {@link #loadAttributes(Object)}. - * - * @param attributes - * A non-empty string array, which contains the URLs for the JS library file(s) and an optional Map of - * additional attributes. - * @see com.aptana.configurations.processor.AbstractConfigurationProcessor#configure(org.eclipse.core.runtime.IProgressMonitor, - * java.lang.Object) - * @see #loadAttributes(Object) - */ - @Override - public ConfigurationStatus configure(IProgressMonitor progressMonitor, Object attributes) - { - // Get a Class lock to avoid multiple installations at the same time even with multiple instances of this - // RubyInstallProcessor - synchronized (this.getClass()) - { - if (installationInProgress) - { - return configurationStatus; - } - installationInProgress = true; - } - try - { - configurationStatus.removeAttribute(CONFIG_ATTR); - clearErrorAttributes(); - - // Load the installer's attributes - IStatus loadingStatus = loadAttributes(attributes); - if (!loadingStatus.isOK()) - { - String message = loadingStatus.getMessage(); - applyErrorAttributes(message); - IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(message)); - return configurationStatus; - } - - // Check that we got the expected single install URL - - if (urls.length == 0) - { - // structure error - String err = NLS.bind(Messages.InstallProcessor_wrongNumberOfInstallLinks, new Object[] { JS_LIBRARY, - 1, urls.length }); - applyErrorAttributes(err); - IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(err)); - return configurationStatus; - } - // Try to get the library name from the optional attributes. If it's not there, we log a warning and use a - // default one. - libraryName = attributesMap.get(NAME_ATTRIBUTE); - if (libraryName == null) - { - // just in case - libraryName = JS_LIBRARY; - IdeLog.logWarning(PortalUIPlugin.getDefault(), - "Expected a name attribute for the JS library, but got null."); //$NON-NLS-1$ - } - // Start the installation... - configurationStatus.setStatus(ConfigurationStatus.PROCESSING); - IStatus status = download(urls, progressMonitor); - if (status.isOK()) - { - status = install(progressMonitor); - } - switch (status.getSeverity()) - { - case IStatus.OK: - case IStatus.INFO: - case IStatus.WARNING: - displayMessageInUIThread(MessageDialog.INFORMATION, - NLS.bind(Messages.InstallProcessor_installerTitle, libraryName), - NLS.bind(Messages.InstallProcessor_installationSuccessful, libraryName)); - configurationStatus.setStatus(ConfigurationStatus.OK); - break; - case IStatus.ERROR: - configurationStatus.setStatus(ConfigurationStatus.ERROR); - break; - case IStatus.CANCEL: - configurationStatus.setStatus(ConfigurationStatus.INCOMPLETE); - break; - default: - configurationStatus.setStatus(ConfigurationStatus.UNKNOWN); - } - return configurationStatus; - } - finally - { - synchronized (this.getClass()) - { - installationInProgress = false; - } - } - } - - /** - * Install the library.
- * The installation will display a selection dialog, displaying the projects in the workspace, and selecting the - * active project by default. It also takes into account the type of the project (nature) when suggesting the - * location to save the JS libraries. - * - * @param progressMonitor - * @return A status indication of the process success or failure. - */ - protected IStatus install(IProgressMonitor progressMonitor) - { - Job job = new UIJob(Messages.JSLibraryInstallProcessor_directorySelection) - { - @Override - public IStatus runInUIThread(IProgressMonitor monitor) - { - JavaScriptImporterOptionsDialog dialog = new JavaScriptImporterOptionsDialog(Display.getDefault() - .getActiveShell(), libraryName); - if (dialog.open() == Window.OK) - { - String selectedLocation = dialog.getSelectedLocation(); - IPath path = Path.fromOSString(selectedLocation); - targetProject = ResourcesPlugin.getWorkspace().getRoot().getProject(path.segment(0)); - // Making sure that the project is not null, although this should never happen - if (targetProject != null) - { - String fullPath = targetProject.getLocation().append(path.removeFirstSegments(1)).toOSString(); - File targetFolder = new File(fullPath); - if (!targetFolder.exists() && !targetFolder.mkdirs()) - { - // could not create the directories needed! - IdeLog.logError( - PortalUIPlugin.getDefault(), - "Failed to create directories when importing JS slibrary!", new Exception("Failed to create '" + fullPath + '\'')); //$NON-NLS-1$ //$NON-NLS-2$ - return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, - Messages.JSLibraryInstallProcessor_directoriesCreationFailed); - } - // Copy the downloaded content into the created directory - List errors = new ArrayList(); - for (IPath f : downloadedPaths) - { - try - { - File sourceLocation = f.toFile(); - File targetLocation = new File(targetFolder, sourceLocation.getName()); - if (targetLocation.exists()) - { - if (!MessageDialog.openQuestion( - Display.getDefault().getActiveShell(), - Messages.JSLibraryInstallProcessor_fileConflictTitle, - Messages.JSLibraryInstallProcessor_fileConflictMessage - + sourceLocation.getName() - + Messages.JSLibraryInstallProcessor_overwriteQuestion)) - { - continue; - } - } - IOUtil.copyFile(sourceLocation, targetLocation); - } - catch (IOException e) - { - errors.add(new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, e.getMessage(), e)); - } - } - if (!errors.isEmpty()) - { - return new MultiStatus(PortalUIPlugin.PLUGIN_ID, 0, errors.toArray(new IStatus[errors - .size()]), Messages.JSLibraryInstallProcessor_multipleErrorsWhileImportingJS, null); - } - // Since we don't cache the installed location for javascript libraries, we pass null here. This - // will only mark for deletion the downloaded content. - finalizeInstallation(null); - } - else - { - IdeLog.logError(PortalUIPlugin.getDefault(), - "Unexpected null project when importing a JS library!", new Exception()); //$NON-NLS-1$ - return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, - Messages.JSLibraryInstallProcessor_unexpectedNull); - } - try - { - targetProject.refreshLocal(IResource.DEPTH_INFINITE, SubMonitor.convert(monitor)); - } - catch (CoreException e) - { - IdeLog.logError(PortalUIPlugin.getDefault(), "Error while refreshing the project.", e); //$NON-NLS-1$ - } - return Status.OK_STATUS; - } - else - { - return Status.CANCEL_STATUS; - } - } - }; - EclipseUtil.setSystemForJob(job); - job.schedule(); - try - { - job.join(); - } - catch (InterruptedException e) - { - IdeLog.logError(PortalUIPlugin.getDefault(), e); - } - return job.getResult(); - } -} diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/Messages.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/Messages.java deleted file mode 100644 index e3f3a3b609..0000000000 --- a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/Messages.java +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Aptana Studio - * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. - * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). - * Please see the license.html included with this distribution for details. - * Any modifications to this file must keep this entire header intact. - */ -package com.aptana.portal.ui.dispatch.configurationProcessors; - -import org.eclipse.osgi.util.NLS; - -public class Messages extends NLS -{ - - private static final String BUNDLE_NAME = "com.aptana.portal.ui.dispatch.configurationProcessors.messages"; //$NON-NLS-1$ - - public static String GemsConfigurationProcessor_errorInvokingGemList; - public static String GemsConfigurationProcessor_missingShellError; - public static String GemsConfigurationProcessor_wrongGemsRequest; - - public static String ImportJavaScriptLibraryDialog_emptyPathError; - public static String ImportJavaScriptLibraryDialog_folderSelectionDialogMessage; - public static String ImportJavaScriptLibraryDialog_folderSelectionDialogTitle; - public static String ImportJavaScriptLibraryDialog_invalidPathError; - public static String ImportJavaScriptLibraryDialog_locationLabel; - public static String ImportJavaScriptLibraryDialog_noAccessibleProjectsError; - public static String ImportJavaScriptLibraryDialog_projectLable; - public static String ImportJavaScriptLibraryDialog_useDefaultLocation; - public static String ImportJavaScriptLibraryDialog_wrongProjectRootError; - - public static String InstallerConfigurationProcessor_emptyURLsArrayError; - public static String InstallerConfigurationProcessor_expectedArrayError; - public static String InstallerConfigurationProcessor_expectedMapError; - public static String InstallerConfigurationProcessor_expectedURLsArrayError; - public static String InstallerConfigurationProcessor_unableToExtractZip; - - public static String InstallProcessor_couldNotLocateInstaller; - public static String InstallProcessor_corruptedZip; - public static String InstallProcessor_couldNotLocatePackage; - public static String InstallProcessor_errorWhileInstalling; - public static String InstallProcessor_extractingPackageTaskName; - public static String InstallProcessor_failedToInstallSeeLog; - public static String InstallProcessor_failedToInstall; - public static String InstallProcessor_failedToWrite; - public static String InstallProcessor_installationError_installDirMissing; - public static String InstallProcessor_installationErrorMessage; - public static String InstallProcessor_installationErrorTitle; - public static String InstallProcessor_installerGroupTitle; - public static String InstallProcessor_installerMessage; - public static String InstallProcessor_installerProgressInfo; - public static String InstallProcessor_installerShellTitle; - public static String InstallProcessor_installerTitle; - public static String InstallProcessor_extractingJobName; - public static String InstallProcessor_installingTaskName; - public static String InstallProcessor_executingTaskName; - public static String InstallProcessor_missingInstallURLs; - public static String InstallProcessor_installationSuccessful; - public static String InstallProcessor_installerJobName; - public static String InstallProcessor_seeErrorLog; - public static String InstallProcessor_updatingTaskName; - public static String InstallProcessor_InstallForAllUsers; - public static String InstallProcessor_wrongNumberOfInstallLinks; - - public static String InstallerConfigurationProcessor_missingAttributeMap; - public static String InstallerConfigurationProcessor_missingDownloadTargets; - public static String InstallerOptionsDialog_creatingDirectoriesErrorMessage; - public static String InstallerOptionsDialog_creatingDirectoriesErrorTitle; - public static String InstallerOptionsDialog_emptyPathError; - public static String InstallerOptionsDialog_inputDirectoryWillBeCreated; - public static String InstallerOptionsDialog_nonExistingPathError; - - public static String JSLibraryInstallProcessor_directoriesCreationFailed; - public static String JSLibraryInstallProcessor_directorySelection; - public static String JSLibraryInstallProcessor_fileConflictMessage; - public static String JSLibraryInstallProcessor_fileConflictTitle; - public static String JSLibraryInstallProcessor_multipleErrorsWhileImportingJS; - public static String JSLibraryInstallProcessor_overwriteQuestion; - public static String JSLibraryInstallProcessor_unexpectedNull; - - public static String InstallProcessor_aptanaInstallationComment; - public static String SystemConfigurationProcessor_missingConfigurationItems; - public static String SystemConfigurationProcessor_noShellCommandPath; - public static String SystemConfigurationProcessor_wrongConfigurationAttributesStructure; - public static String XAMPPInstallProcessor_executeXAMPPAutoSetup; - public static String XAMPPInstallProcessor_openXAMPPConsoleJobName; - - static - { - // initialize resource bundle - NLS.initializeMessages(BUNDLE_NAME, Messages.class); - } - - private Messages() - { - } -} diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/PythonInstallProcessor.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/PythonInstallProcessor.java deleted file mode 100644 index 5b1843c5ba..0000000000 --- a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/PythonInstallProcessor.java +++ /dev/null @@ -1,429 +0,0 @@ -/** - * Aptana Studio - * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. - * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). - * Please see the license.html included with this distribution for details. - * Any modifications to this file must keep this entire header intact. - */ -package com.aptana.portal.ui.dispatch.configurationProcessors; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.SubMonitor; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.window.Window; -import org.eclipse.osgi.util.NLS; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; -import org.eclipse.ui.progress.UIJob; - -import com.aptana.configurations.processor.ConfigurationStatus; -import com.aptana.core.logging.IdeLog; -import com.aptana.core.util.CollectionsUtil; -import com.aptana.ide.core.io.LockUtils; -import com.aptana.portal.ui.PortalUIPlugin; -import com.aptana.portal.ui.dispatch.configurationProcessors.installer.InstallerOptionsDialog; - -/** - * A Python install processor.
- * This class is in charge of downloading and installing Python for Windows operating systems.
- * Note: In case we decide to support something similar for MacOSX and Linux, this processor would probably need - * delegators set up. - * - * @author Shalom Gibly - */ -public class PythonInstallProcessor extends InstallerConfigurationProcessor -{ - protected static final String PYTHON_DEFAULT_INSTALL_DIR = "C:\\Python"; //$NON-NLS-1$ - protected static final String INSTALL_FOR_ALL_USERS_ATTR = "install_for_all"; //$NON-NLS-1$ - private static final String PYTHON = "Python"; //$NON-NLS-1$ - protected static final int PYTHON_INSTALLER_PROCESS_CANCEL_CODE = 1602; - private static boolean installationInProgress; - private String installDir; - - /** - * Install Python on the machine.
- * The configuration will grab the installer from the given attributes.
- * We expect an array of attributes with the same structure described at {@link #loadAttributes(Object)}. - * - * @param attributes - * First - A string array of size 1, which contains the URL for the Python installer (.exe). Second - - * (optional) map of additional attributes. - * @see com.aptana.configurations.processor.AbstractConfigurationProcessor#configure(org.eclipse.core.runtime.IProgressMonitor, - * java.lang.Object) - * @see #loadAttributes(Object) - */ - @Override - public ConfigurationStatus configure(IProgressMonitor progressMonitor, Object attributes) - { - // Get a Class lock to avoid multiple installations at the same time even with multiple instances of this - // processor - synchronized (this.getClass()) - { - if (installationInProgress) - { - return configurationStatus; - } - installationInProgress = true; - } - if (!Platform.OS_WIN32.equals(Platform.getOS())) - { - String err = "The Python installer processor is designed to work on Windows."; //$NON-NLS-1$ - IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(err)); - applyErrorAttributes(err); - installationInProgress = false; - return configurationStatus; - } - try - { - configurationStatus.removeAttribute(CONFIG_ATTR); - clearErrorAttributes(); - - // Load the installer's attributes - IStatus loadingStatus = loadAttributes(attributes); - if (!loadingStatus.isOK()) - { - String message = loadingStatus.getMessage(); - applyErrorAttributes(message); - IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(message)); - return configurationStatus; - } - - // Check that we got the expected single install URL - if (urls.length != 1) - { - // structure error - String err = NLS.bind(Messages.InstallProcessor_wrongNumberOfInstallLinks, new Object[] { PYTHON, 1, - urls.length }); - applyErrorAttributes(err); - IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(err)); - return configurationStatus; - } - // Try to get the default install directory from the optional attributes - installDir = attributesMap.get(INSTALL_DIR_ATTRIBUTE); - if (installDir == null) - { - installDir = PYTHON_DEFAULT_INSTALL_DIR; - } - // Start the installation... - configurationStatus.setStatus(ConfigurationStatus.PROCESSING); - IStatus status = download(urls, progressMonitor); - if (status.isOK()) - { - status = install(progressMonitor); - } - switch (status.getSeverity()) - { - case IStatus.OK: - case IStatus.INFO: - case IStatus.WARNING: - displayMessageInUIThread(MessageDialog.INFORMATION, - NLS.bind(Messages.InstallProcessor_installerTitle, PYTHON), - NLS.bind(Messages.InstallProcessor_installationSuccessful, PYTHON)); - configurationStatus.setStatus(ConfigurationStatus.OK); - break; - case IStatus.ERROR: - configurationStatus.setStatus(ConfigurationStatus.ERROR); - break; - case IStatus.CANCEL: - configurationStatus.setStatus(ConfigurationStatus.INCOMPLETE); - break; - default: - configurationStatus.setStatus(ConfigurationStatus.UNKNOWN); - } - return configurationStatus; - } - finally - { - synchronized (this.getClass()) - { - installationInProgress = false; - } - } - } - - /** - * Returns the application name. - * - * @return "PYTHON" - */ - protected String getApplicationName() - { - return PYTHON; - } - - /** - * Do the PYTHON installation. - * - * @param progressMonitor - * @return A status indication of the process success or failure. - */ - protected IStatus install(IProgressMonitor progressMonitor) - { - if (CollectionsUtil.isEmpty(downloadedPaths)) - { - String failureMessge = Messages.InstallProcessor_couldNotLocateInstaller; - String err = NLS.bind(Messages.InstallProcessor_failedToInstall, PYTHON); - displayMessageInUIThread(MessageDialog.ERROR, Messages.InstallProcessor_installationErrorTitle, err + ' ' - + failureMessge); - return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, err + ' ' + failureMessge); - } - SubMonitor subMonitor = SubMonitor.convert(progressMonitor, Messages.InstallProcessor_installerProgressInfo, - IProgressMonitor.UNKNOWN); - final Map installationAttributes = new HashMap(); - try - { - subMonitor.beginTask(NLS.bind(Messages.InstallProcessor_installingTaskName, PYTHON), - IProgressMonitor.UNKNOWN); - final String[] installDir = new String[1]; - Job installPythonDialog = new UIJob("Python installer options") //$NON-NLS-1$ - { - @Override - public IStatus runInUIThread(IProgressMonitor monitor) - { - PythonInstallerOptionsDialog dialog = new PythonInstallerOptionsDialog(); - if (dialog.open() == Window.OK) - { - installationAttributes.putAll(dialog.getAttributes()); - return Status.OK_STATUS; - } - return Status.CANCEL_STATUS; - } - }; - installPythonDialog.schedule(); - try - { - installPythonDialog.join(); - } - catch (InterruptedException e) - { - } - IStatus result = installPythonDialog.getResult(); - if (!result.isOK()) - { - return result; - } - - IStatus status = installPYTHON(installationAttributes); - if (!status.isOK()) - { - return status; - } - IdeLog.logInfo(PortalUIPlugin.getDefault(), MessageFormat.format( - "Successfully installed PYTHON into {0}. PYTHON installation completed.", installDir[0])); //$NON-NLS-1$ - // note that we called the finalizeInstallation from the installPYTHON Job. - return Status.OK_STATUS; - } - catch (Exception e) - { - IdeLog.logError(PortalUIPlugin.getDefault(), "Error while installing PYTHON", e); //$NON-NLS-1$ - return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, NLS.bind( - Messages.InstallProcessor_errorWhileInstalling, PYTHON)); - } - finally - { - subMonitor.done(); - } - } - - /** - * Run the PYTHON installer and install XMAPP into the given directory. - * - * @param installationAttributes - * - Attributes map that contains the installation directory and a specification whether to run the - * PYTHON auto-install script. - * @return The status of this installation - */ - protected IStatus installPYTHON(final Map installationAttributes) - { - Job job = new Job(NLS.bind(Messages.InstallProcessor_installerJobName, PYTHON + ' ' - + Messages.InstallProcessor_installerGroupTitle)) - { - @Override - protected IStatus run(IProgressMonitor monitor) - { - try - { - // extract the values from the attributes: - String installDir = (String) installationAttributes.get(InstallerOptionsDialog.INSTALL_DIR_ATTR); - // This installer requires Windows path slashes style (backslashes) - installDir = installDir.replaceAll("/", "\\\\"); //$NON-NLS-1$ //$NON-NLS-2$ - - SubMonitor subMonitor = SubMonitor.convert(monitor, IProgressMonitor.UNKNOWN); - subMonitor.beginTask(NLS.bind(Messages.InstallProcessor_installingTaskName, PYTHON), - IProgressMonitor.UNKNOWN); - IdeLog.logInfo(PortalUIPlugin.getDefault(), "Installing Python into " + installDir); //$NON-NLS-1$ - - // Try to get a file lock first, before running the process. This file was just downloaded, so there - // is a chance it's still being held by the OS or by the downloader. - IStatus fileLockStatus = LockUtils.waitForLockRelease(downloadedPaths.get(0).toOSString(), 10000L); - if (!fileLockStatus.isOK()) - { - return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, NLS.bind( - Messages.InstallProcessor_failedToInstallSeeLog, PYTHON)); - } - // Run the Python installer, as specified in this link: - // http://www.python.org/download/releases/2.5/msi/ - List command = new ArrayList(4); - command.add("msiexec"); //$NON-NLS-1$ - command.add("/i"); //$NON-NLS-1$ - command.add(downloadedPaths.get(0).toOSString()); - command.add("/qr"); //$NON-NLS-1$ - command.add("TARGETDIR=\"" + installDir + '\"'); //$NON-NLS-1$ - if (Boolean.FALSE.toString().equals(attributesMap.get(INSTALL_FOR_ALL_USERS_ATTR))) - { - command.add("ALLUSERS=0"); //$NON-NLS-1$ - } - else - { - command.add("ALLUSERS=1"); //$NON-NLS-1$ - } - ProcessBuilder processBuilder = new ProcessBuilder(command); - Process process = processBuilder.start(); - int res = process.waitFor(); - if (res == PYTHON_INSTALLER_PROCESS_CANCEL_CODE) - { - IdeLog.logInfo(PortalUIPlugin.getDefault(), "Python installation cancelled"); //$NON-NLS-1$ - return Status.CANCEL_STATUS; - } - if (res != 0) - { - // We had an error while installing - IdeLog.logError( - PortalUIPlugin.getDefault(), - "Failed to install Python. The PYTHON installer process returned a termination code of " + res); //$NON-NLS-1$ - return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, res, NLS.bind( - Messages.InstallProcessor_installationErrorMessage, PYTHON, PYTHON), null); - } - else if (!new File(installDir).exists()) - { - // Just to be sure that we got everything in place - IdeLog.logError( - PortalUIPlugin.getDefault(), - "Failed to install Python. The " + installDir + " directory was not created", (Throwable) null); //$NON-NLS-1$ //$NON-NLS-2$ - return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, res, NLS.bind( - Messages.InstallProcessor_installationError_installDirMissing, PYTHON), null); - } - - finalizeInstallation(installDir); - return Status.OK_STATUS; - } - catch (Exception e) - { - IdeLog.logError(PortalUIPlugin.getDefault(), e.getMessage(), e); - return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, NLS.bind( - Messages.InstallProcessor_failedToInstallSeeLog, PYTHON), e); - } - finally - { - monitor.done(); - } - } - }; - // Give it a little delay, just in case the downloader still holds on to the installer file. - job.schedule(1000); - try - { - job.join(); - } - catch (InterruptedException e) - { - IdeLog.logError(PortalUIPlugin.getDefault(), e.getMessage(), e); - return Status.CANCEL_STATUS; - } - return job.getResult(); - } - - /** - * Finalize the installation by placing a .aptana file in the installed directory, specifying some properties. - * - * @param installDir - */ - protected void finalizeInstallation(String installDir) - { - super.finalizeInstallation(installDir); - File propertiesFile = new File(installDir, APTANA_PROPERTIES_FILE_NAME); - Properties properties = new Properties(); - properties.put("PYTHON_install", urls[0]); //$NON-NLS-1$ - FileOutputStream fileOutputStream = null; - try - { - fileOutputStream = new FileOutputStream(propertiesFile); - properties.store(fileOutputStream, NLS.bind(Messages.InstallProcessor_aptanaInstallationComment, PYTHON)); - } - catch (IOException e) - { - IdeLog.logError(PortalUIPlugin.getDefault(), e); - } - finally - { - if (fileOutputStream != null) - { - try - { - fileOutputStream.flush(); - fileOutputStream.close(); - } - catch (IOException e) - { - } - } - } - } - - private class PythonInstallerOptionsDialog extends InstallerOptionsDialog - { - private Button installForAllUsersBt; - - public PythonInstallerOptionsDialog() - { - super(Display.getDefault().getActiveShell(), PYTHON); - setTitleImage(PortalUIPlugin.getDefault().getImageRegistry().get(PortalUIPlugin.PYTHON_IMAGE)); - } - - @Override - protected void setAttributes() - { - attributes.put(INSTALL_DIR_ATTR, installDir); - attributes.put(INSTALL_FOR_ALL_USERS_ATTR, Boolean.TRUE); - } - - /** - * Add the 'Auto-Setup' checkbox. - */ - @Override - protected Composite createInstallerGroupControls(Composite group) - { - Composite control = super.createInstallerGroupControls(group); - installForAllUsersBt = new Button(group, SWT.CHECK); - installForAllUsersBt.setText(Messages.InstallProcessor_InstallForAllUsers); - installForAllUsersBt.setSelection(true); - installForAllUsersBt.addSelectionListener(new SelectionAdapter() - { - @Override - public void widgetSelected(SelectionEvent e) - { - attributes.put(INSTALL_FOR_ALL_USERS_ATTR, installForAllUsersBt.getSelection()); - } - }); - return control; - } - } -} \ No newline at end of file diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/RubyInstallProcessor.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/RubyInstallProcessor.java deleted file mode 100644 index a5c1fbbe80..0000000000 --- a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/RubyInstallProcessor.java +++ /dev/null @@ -1,391 +0,0 @@ -/** - * Aptana Studio - * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. - * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). - * Please see the license.html included with this distribution for details. - * Any modifications to this file must keep this entire header intact. - */ -package com.aptana.portal.ui.dispatch.configurationProcessors; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.Properties; - -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.SubMonitor; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.window.Window; -import org.eclipse.osgi.util.NLS; -import org.eclipse.swt.widgets.Display; -import org.eclipse.ui.progress.UIJob; - -import com.aptana.configurations.processor.ConfigurationStatus; -import com.aptana.core.logging.IdeLog; -import com.aptana.core.util.CollectionsUtil; -import com.aptana.ide.core.io.LockUtils; -import com.aptana.portal.ui.PortalUIPlugin; -import com.aptana.portal.ui.dispatch.configurationProcessors.installer.InstallerOptionsDialog; - -/** - * A Ruby install processor.
- * This class is in charge of downloading and installing Ruby and DevKit for Windows operating systems.
- * Note: In case we decide to support something similar for MacOSX and Linux, this processor would probably need - * delegators set up. - * - * @author Shalom Gibly - */ -public class RubyInstallProcessor extends InstallerConfigurationProcessor -{ - private static final String RUBY = "Ruby"; //$NON-NLS-1$ - protected static final String RUBY_DEFAULT_INSTALL_DIR = "C:\\Ruby"; //$NON-NLS-1$ - // The process return code for a Ruby installer cancel. - private static final int RUBY_INSTALLER_PROCESS_CANCEL = 5; - private static boolean installationInProgress; - - private String installDir; - - /** - * Install Ruby on the machine.
- * The configuration will grab the installer and the DevKit from the given attributes.
- * We expect an array of attributes with the same structure described at {@link #loadAttributes(Object)}. - * - * @param attributes - * An array of strings holding an optional attributes map and an array of rubyinstaller and the devkit - * URLs. - * @see com.aptana.configurations.processor.AbstractConfigurationProcessor#configure(org.eclipse.core.runtime.IProgressMonitor, - * java.lang.Object) - * @see #loadAttributes(Object) - */ - @Override - public ConfigurationStatus configure(IProgressMonitor progressMonitor, Object attributes) - { - // Get a Class lock to avoid multiple installations at the same time even with multiple instances of this - // RubyInstallProcessor - synchronized (this.getClass()) - { - if (installationInProgress) - { - return configurationStatus; - } - installationInProgress = true; - } - if (!Platform.OS_WIN32.equals(Platform.getOS())) - { - String err = "The Ruby installer processor is designed to work on Windows."; //$NON-NLS-1$ - IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(err)); - applyErrorAttributes(err); - installationInProgress = false; - return configurationStatus; - } - try - { - configurationStatus.removeAttribute(CONFIG_ATTR); - clearErrorAttributes(); - - // Load the installer's attributes - IStatus loadingStatus = loadAttributes(attributes); - if (!loadingStatus.isOK()) - { - String message = loadingStatus.getMessage(); - applyErrorAttributes(message); - IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(message)); - return configurationStatus; - } - - // Check that we got the expected two install URLs - // TODO - Once we place DevKit back again, this should hold a value of 2 URLs. - if (urls.length != 1) - { - // structure error - String err = NLS.bind(Messages.InstallProcessor_wrongNumberOfInstallLinks, new Object[] { RUBY, 1, - urls.length }); - applyErrorAttributes(err); - IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(err)); - return configurationStatus; - } - // Try to get the default install directory from the optional attributes - installDir = attributesMap.get(INSTALL_DIR_ATTRIBUTE); - if (installDir == null) - { - installDir = RUBY_DEFAULT_INSTALL_DIR; - } - // Start the installation... - configurationStatus.setStatus(ConfigurationStatus.PROCESSING); - IStatus status = download(urls, progressMonitor); - if (status.isOK()) - { - status = install(progressMonitor); - } - switch (status.getSeverity()) - { - case IStatus.OK: - case IStatus.INFO: - case IStatus.WARNING: - displayMessageInUIThread(MessageDialog.INFORMATION, - NLS.bind(Messages.InstallProcessor_installerTitle, RUBY), - NLS.bind(Messages.InstallProcessor_installationSuccessful, RUBY)); - configurationStatus.setStatus(ConfigurationStatus.OK); - break; - case IStatus.ERROR: - configurationStatus.setStatus(ConfigurationStatus.ERROR); - break; - case IStatus.CANCEL: - configurationStatus.setStatus(ConfigurationStatus.INCOMPLETE); - break; - default: - configurationStatus.setStatus(ConfigurationStatus.UNKNOWN); - } - return configurationStatus; - } - finally - { - synchronized (this.getClass()) - { - installationInProgress = false; - } - } - } - - /** - * Returns the application name. - * - * @return "Ruby" - */ - protected String getApplicationName() - { - return RUBY; - } - - /** - * Install Ruby and DevKit. - * - * @param progressMonitor - * @return - */ - protected IStatus install(IProgressMonitor progressMonitor) - { - if (CollectionsUtil.isEmpty(downloadedPaths) || CollectionsUtil.getFirstElement(downloadedPaths) == null) - { - String failureMessge = Messages.InstallProcessor_couldNotLocateInstaller; - String err = NLS.bind(Messages.InstallProcessor_failedToInstall, RUBY); - displayMessageInUIThread(MessageDialog.ERROR, Messages.InstallProcessor_installationErrorTitle, err + ' ' - + failureMessge); - return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, err + ' ' + failureMessge); - } - SubMonitor subMonitor = SubMonitor.convert(progressMonitor, Messages.InstallProcessor_installerProgressInfo, - IProgressMonitor.UNKNOWN); - try - { - subMonitor - .beginTask(NLS.bind(Messages.InstallProcessor_installingTaskName, RUBY), IProgressMonitor.UNKNOWN); - final IPath[] installDir = new IPath[1]; - Job installRubyDialog = new UIJob("Ruby installer options") //$NON-NLS-1$ - { - @Override - public IStatus runInUIThread(IProgressMonitor monitor) - { - RubyInstallerOptionsDialog dialog = new RubyInstallerOptionsDialog(); - if (dialog.open() == Window.OK) - { - installDir[0] = Path.fromOSString(dialog.getInstallDir()); - return Status.OK_STATUS; - } - return Status.CANCEL_STATUS; - } - }; - installRubyDialog.schedule(); - try - { - installRubyDialog.join(); - } - catch (InterruptedException e) - { - } - IStatus result = installRubyDialog.getResult(); - if (!result.isOK()) - { - return result; - } - - IStatus status = installRuby(installDir[0]); - if (!status.isOK()) - { - return status; - } - IdeLog.logInfo(PortalUIPlugin.getDefault(), "Successfully installed Ruby into " + installDir[0]); //$NON-NLS-1$ - finalizeInstallation(installDir[0]); - return Status.OK_STATUS; - } - catch (Exception e) - { - IdeLog.logError(PortalUIPlugin.getDefault(), "Error while installing Ruby", e); //$NON-NLS-1$ - return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, NLS.bind( - Messages.InstallProcessor_errorWhileInstalling, RUBY)); - } - finally - { - subMonitor.done(); - } - } - - /** - * Run the Ruby installer and install Ruby into the given directory. - * - * @param installDir - * @return The status of this installation - */ - protected IStatus installRuby(final IPath installDir) - { - Job job = new Job(NLS.bind(Messages.InstallProcessor_installerJobName, RUBY + ' ' - + Messages.InstallProcessor_installerGroupTitle)) - { - @Override - protected IStatus run(IProgressMonitor monitor) - { - try - { - SubMonitor subMonitor = SubMonitor.convert(monitor, IProgressMonitor.UNKNOWN); - subMonitor.beginTask(NLS.bind(Messages.InstallProcessor_installingTaskName, RUBY), - IProgressMonitor.UNKNOWN); - IdeLog.logInfo(PortalUIPlugin.getDefault(), "Installing Ruby into " + installDir); //$NON-NLS-1$ - - // Try to get a file lock first, before running the process. This file was just downloaded, so there - // is a chance it's still being held by the OS or by the downloader. - IPath downloadPath = downloadedPaths.get(0); - IStatus fileLockStatus = LockUtils.waitForLockRelease(downloadPath.toOSString(), 10000L); - if (!fileLockStatus.isOK()) - { - return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, NLS.bind( - Messages.InstallProcessor_failedToInstallSeeLog, RUBY)); - } - - ProcessBuilder processBuilder = new ProcessBuilder(downloadPath.toOSString(), - "/silent", "/dir=\"" + installDir.toOSString() + "\"", "/tasks=\"modpath\""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ - Process process = processBuilder.start(); - int res = process.waitFor(); - if (res == RUBY_INSTALLER_PROCESS_CANCEL) - { - IdeLog.logInfo(PortalUIPlugin.getDefault(), "Ruby installation cancelled"); //$NON-NLS-1$ - return Status.CANCEL_STATUS; - } - if (res != 0) - { - // We had an error while installing - IdeLog.logError( - PortalUIPlugin.getDefault(), - "Failed to install Ruby. The ruby installer process returned a termination code of " + res); //$NON-NLS-1$ - return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, res, NLS.bind( - Messages.InstallProcessor_installationErrorMessage, RUBY, RUBY), null); - } - else if (!installDir.toFile().exists()) - { - // Just to be sure that we got everything in place - IdeLog.logError(PortalUIPlugin.getDefault(), - "Failed to install Ruby. The " + installDir + " directory was not created"); //$NON-NLS-1$ //$NON-NLS-2$ - return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, res, NLS.bind( - Messages.InstallProcessor_installationError_installDirMissing, RUBY), null); - } - return Status.OK_STATUS; - } - catch (Exception e) - { - IdeLog.logError(PortalUIPlugin.getDefault(), e); - return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, NLS.bind( - Messages.InstallProcessor_failedToInstallSeeLog, RUBY), e); - } - finally - { - monitor.done(); - } - } - }; - // Give it a little delay, just in case the downloader still holds on to the rubyinstaller file. - job.schedule(1000); - try - { - job.join(); - } - catch (InterruptedException e) - { - IdeLog.logError(PortalUIPlugin.getDefault(), e.getMessage(), e); - return Status.CANCEL_STATUS; - } - return job.getResult(); - } - - /** - * Finalize the installation by placing a .aptana file in the installed directory, specifying some properties. - * - * @param installDir - */ - protected void finalizeInstallation(IPath installDir) - { - super.finalizeInstallation(installDir.toOSString()); - File propertiesFile = installDir.append(APTANA_PROPERTIES_FILE_NAME).toFile(); - Properties properties = new Properties(); - properties.put("ruby_install", urls[0]); //$NON-NLS-1$ - FileOutputStream fileOutputStream = null; - try - { - fileOutputStream = new FileOutputStream(propertiesFile); - properties.store(fileOutputStream, - NLS.bind(Messages.InstallProcessor_aptanaInstallationComment, "Ruby & DevKit")); //$NON-NLS-1$ - } - catch (IOException e) - { - IdeLog.logError(PortalUIPlugin.getDefault(), e); - } - finally - { - if (fileOutputStream != null) - { - try - { - fileOutputStream.flush(); - fileOutputStream.close(); - } - catch (IOException e) - { - } - } - } - } - - /** - * Ruby installer dialog.
- * This dialog only asks for the install directory. - * - * @author Shalom Gibly - */ - private class RubyInstallerOptionsDialog extends InstallerOptionsDialog - { - public RubyInstallerOptionsDialog() - { - super(Display.getDefault().getActiveShell(), RUBY); - setTitleImage(PortalUIPlugin.getDefault().getImageRegistry().get(PortalUIPlugin.RUBY_IMAGE)); - } - - /** - * Returns the installation dir selected in the text field. - * - * @return the installation directory - */ - public String getInstallDir() - { - return attributes.get(INSTALL_DIR_ATTR).toString(); - } - - @Override - protected void setAttributes() - { - attributes.put(INSTALL_DIR_ATTR, installDir); - } - } -} diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/VersionsConfigurationProcessor.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/VersionsConfigurationProcessor.java deleted file mode 100644 index 5fbc0623ab..0000000000 --- a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/VersionsConfigurationProcessor.java +++ /dev/null @@ -1,207 +0,0 @@ -/** - * Aptana Studio - * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. - * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). - * Please see the license.html included with this distribution for details. - * Any modifications to this file must keep this entire header intact. - */ -package com.aptana.portal.ui.dispatch.configurationProcessors; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.preferences.IPreferencesService; -import com.aptana.jetty.util.epl.ajax.JSON; -import org.osgi.framework.Version; - -import com.aptana.configurations.processor.AbstractConfigurationProcessor; -import com.aptana.configurations.processor.ConfigurationProcessorsRegistry; -import com.aptana.configurations.processor.ConfigurationStatus; -import com.aptana.configurations.processor.IConfigurationProcessorDelegate; -import com.aptana.core.logging.IdeLog; -import com.aptana.core.util.VersionUtil; -import com.aptana.explorer.ExplorerPlugin; -import com.aptana.explorer.IPreferenceConstants; -import com.aptana.portal.ui.PortalUIPlugin; -import com.aptana.portal.ui.dispatch.processorDelegates.CachedVersionProcessorDelegate; - -/** - * A configuration processor that can identify the versions of some specific applications. The supported applications - * are: - *
    - *
  • ruby
  • - *
  • rails
  • - *
  • git
  • - *
  • sqlite3
  • - *
- * - * @author Shalom Gibly - */ -public class VersionsConfigurationProcessor extends AbstractConfigurationProcessor -{ - /** - * Compute the versions of the given items in the attributes instance. Items that are not in the supported list of - * programs are set to an 'unknown' state, just as they are not installed.
- * The computation expects an attributes array with three items - (this - * specific call don't use the installer-URL, but it needs to be there for the Portal's functionalities) - */ - @Override - public ConfigurationStatus computeStatus(IProgressMonitor progressMonitor, Object attributes) - { - configurationStatus.removeAttribute(CONFIG_ATTR); - clearErrorAttributes(); - if (attributes == null || !(attributes instanceof Object[])) - { - String message = Messages.SystemConfigurationProcessor_missingConfigurationItems; - applyErrorAttributes(message); - IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(message)); - return configurationStatus; - } - // Place the array values into a hash. - Object[] attrArray = (Object[]) attributes; - Map attrItems = new HashMap(); - for (Object itemDef : attrArray) - { - Object[] def = null; - if (!(itemDef instanceof Object[]) || (def = (Object[]) itemDef).length != 3) - { - String message = Messages.SystemConfigurationProcessor_wrongConfigurationAttributesStructure; - applyErrorAttributes(message); - IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(message)); - return configurationStatus; - } - // We only use the first two arguments. The third is the installation site URL. - attrItems.put((String) def[0], (String) def[1]); - } - // Do the actual processing - configurationStatus.setStatus(ConfigurationStatus.PROCESSING); - - // For each requested element, check that the item has a processor delegate. - // If it's there, execute the delegate. If not, set the item's state as unknown. - Map> itemsData = new HashMap>(); - String[] apps = attrItems.keySet().toArray(new String[attrItems.size()]); - // This processor should have delegators that do the actual processing of the versions. - // Load the delegators into a new set that we can manipulate. - Map processorDelegators = getVersionDelegators(apps); - for (String app : apps) - { - if (!processorDelegators.containsKey(app)) - { - // We'll deal with these later - continue; - } - IConfigurationProcessorDelegate delegate = processorDelegators.get(app); - Object commandResult = delegate.runCommand(IConfigurationProcessorDelegate.VERSION_COMMAND, - getActiveWorkingDir()); - if (commandResult != null) - { - Version version = VersionUtil.parseVersion(commandResult.toString()); - if (!VersionUtil.isEmpty(version)) - { - Version minVersion = VersionUtil.parseVersion(attrItems.get(app)); - String compatibility = (version.compareTo(minVersion) >= 0) ? COMPATIBILITY_OK - : COMPATIBILITY_UPDATE; - Map versionInfo = new HashMap(4); - versionInfo.put(ITEM_EXISTS, YES); - versionInfo.put(ITEM_VERSION, version.toString()); - versionInfo.put(ITEM_COMPATIBILITY, compatibility); - versionInfo.put(ITEM_VERSION_OUTPUT, commandResult.toString()); - itemsData.put(app, versionInfo); - // Remove the name from the original map. Eventually, we will be left with the items we could not - // locate in the system - attrItems.remove(app); - } - } - } - // Traverse what we have left in the original map that was created from the attributes and mark all plug-ins as - // 'missing' - Set missingItems = attrItems.keySet(); - for (String item : missingItems) - { - Map versionInfo = new HashMap(4); - versionInfo.put(ITEM_EXISTS, NO); - itemsData.put(item, versionInfo); - } - - // Finally, set the bundle data status into the configuration attribute - configurationStatus.setAttribute(CONFIG_ATTR, JSON.toString(itemsData)); - - configurationStatus.setStatus(ConfigurationStatus.OK); - return configurationStatus; - } - - @Override - public ConfigurationStatus configure(IProgressMonitor progressMonitor, Object attributes) - { - // TODO: Shalom - Right now we do not install directly, but pointing to installation instructions. - return configurationStatus; - } - - /* - * Return only the delegators that supports an application from the apps list and supports the VERSION_COMMAND. This - * method returns a map of delegator supported application name to delegator instance. - */ - private Map getVersionDelegators(String[] apps) - { - Set appsSet = new HashSet(); - for (String app : apps) - { - appsSet.add(app); - } - Set allDelegators = ConfigurationProcessorsRegistry.getInstance() - .getProcessorDelegators(getID()); - Map delegators = new HashMap(); - for (IConfigurationProcessorDelegate delegate : allDelegators) - { - if (appsSet.contains(delegate.getSupportedApplication()) - && delegate.getSupportedCommands().contains(IConfigurationProcessorDelegate.VERSION_COMMAND)) - { - delegators.put(delegate.getSupportedApplication(), delegate); - // Remove the item from the list, so that at the end of this loop we will end up with all the apps that - // did not match to any version delegate. - appsSet.remove(delegate.getSupportedApplication()); - } - } - - // For every app that does not have a delegate, add a special delegate that will use the preferences to try to - // find out the version. - for (String app : appsSet) - { - delegators.put(app, new CachedVersionProcessorDelegate(app)); - } - - return delegators; - } - - /** - * Returns the active working directory according to the last active project in the Project Explorer.
- * The value is taken from the preferences, therefore, this method can also return null if it fails. - * - * @return The active project's working directory (can be null) - */ - protected IPath getActiveWorkingDir() - { - // FIXME - Shalom: Test is. This might not work after the latest changes to the way we save the active project - IPreferencesService preferencesService = Platform.getPreferencesService(); - String activeProjectName = preferencesService.getString(ExplorerPlugin.PLUGIN_ID, - IPreferenceConstants.ACTIVE_PROJECT, null, null); - IProject result = null; - - if (activeProjectName != null) - { - result = ResourcesPlugin.getWorkspace().getRoot().getProject(activeProjectName); - } - if (result == null) - { - return null; - } - return result.getLocation(); - } -} diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/XAMPPInstallProcessor.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/XAMPPInstallProcessor.java deleted file mode 100644 index c71773b03f..0000000000 --- a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/XAMPPInstallProcessor.java +++ /dev/null @@ -1,487 +0,0 @@ -/** - * Aptana Studio - * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. - * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). - * Please see the license.html included with this distribution for details. - * Any modifications to this file must keep this entire header intact. - */ -package com.aptana.portal.ui.dispatch.configurationProcessors; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.SubMonitor; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.window.Window; -import org.eclipse.osgi.util.NLS; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; -import org.eclipse.ui.progress.UIJob; - -import com.aptana.configurations.processor.ConfigurationStatus; -import com.aptana.core.logging.IdeLog; -import com.aptana.core.util.CollectionsUtil; -import com.aptana.ide.core.io.LockUtils; -import com.aptana.portal.ui.PortalUIPlugin; -import com.aptana.portal.ui.dispatch.configurationProcessors.installer.InstallerOptionsDialog; - -/** - * A XAMPP install processor.
- * This class is in charge of downloading and installing XAMPP for Windows operating systems.
- * Note: In case we decide to support something similar for MacOSX and Linux, this processor would probably need - * delegators set up. - * - * @author Shalom Gibly - */ -public class XAMPPInstallProcessor extends InstallerConfigurationProcessor -{ - protected static final String XAMPP_DEFAULT_INSTALL_DIR = "C:\\"; //$NON-NLS-1$ - protected static final String EXECUTE_SETUP_SCRIPT_ATTR = "execute_setup_script"; //$NON-NLS-1$ - private static final String XAMPP_DEFAULT_FOLDER = "xampp\\"; //$NON-NLS-1$ - private static final String XAMPP_CONTROL = "xampp-control.exe"; //$NON-NLS-1$ - private static final String XAMPP = "XAMPP"; //$NON-NLS-1$ - protected static final int XAMPP_INSTALLER_PROCESS_CANCEL_CODE = 255; - private static boolean installationInProgress; - private String installDir; - - /** - * Install XAMPP on the machine.
- * The configuration will grab the installer from the given attributes.
- * We expect an array of attributes with the same structure described at {@link #loadAttributes(Object)}. - * - * @param attributes - * First - A string array of size 1, which contains the URL for the XAMPP installer (.exe). Second - - * (optional) map of additional attributes. - * @see com.aptana.configurations.processor.AbstractConfigurationProcessor#configure(org.eclipse.core.runtime.IProgressMonitor, - * java.lang.Object) - * @see #loadAttributes(Object) - */ - @Override - public ConfigurationStatus configure(IProgressMonitor progressMonitor, Object attributes) - { - // Get a Class lock to avoid multiple installations at the same time even with multiple instances of this - // RubyInstallProcessor - synchronized (this.getClass()) - { - if (installationInProgress) - { - return configurationStatus; - } - installationInProgress = true; - } - if (!Platform.OS_WIN32.equals(Platform.getOS())) - { - String err = "The XAMPP installer processor is designed to work on Windows."; //$NON-NLS-1$ - IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(err)); - applyErrorAttributes(err); - installationInProgress = false; - return configurationStatus; - } - try - { - configurationStatus.removeAttribute(CONFIG_ATTR); - clearErrorAttributes(); - - // Load the installer's attributes - IStatus loadingStatus = loadAttributes(attributes); - if (!loadingStatus.isOK()) - { - String message = loadingStatus.getMessage(); - applyErrorAttributes(message); - IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(message)); - return configurationStatus; - } - - // Check that we got the expected single install URL - if (urls.length != 1) - { - // structure error - String err = NLS.bind(Messages.InstallProcessor_wrongNumberOfInstallLinks, new Object[] { XAMPP, 1, - urls.length }); - applyErrorAttributes(err); - IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(err)); - return configurationStatus; - } - // Try to get the default install directory from the optional attributes - installDir = attributesMap.get(INSTALL_DIR_ATTRIBUTE); - if (installDir == null) - { - installDir = XAMPP_DEFAULT_INSTALL_DIR; - } - // Start the installation... - configurationStatus.setStatus(ConfigurationStatus.PROCESSING); - IStatus status = download(urls, progressMonitor); - if (status.isOK()) - { - status = install(progressMonitor); - } - switch (status.getSeverity()) - { - case IStatus.OK: - case IStatus.INFO: - case IStatus.WARNING: - displayMessageInUIThread(MessageDialog.INFORMATION, - NLS.bind(Messages.InstallProcessor_installerTitle, XAMPP), - NLS.bind(Messages.InstallProcessor_installationSuccessful, XAMPP)); - configurationStatus.setStatus(ConfigurationStatus.OK); - break; - case IStatus.ERROR: - configurationStatus.setStatus(ConfigurationStatus.ERROR); - break; - case IStatus.CANCEL: - configurationStatus.setStatus(ConfigurationStatus.INCOMPLETE); - break; - default: - configurationStatus.setStatus(ConfigurationStatus.UNKNOWN); - } - return configurationStatus; - } - finally - { - synchronized (this.getClass()) - { - installationInProgress = false; - } - } - } - - /** - * Returns the application name. - * - * @return "XAMPP" - */ - protected String getApplicationName() - { - return XAMPP; - } - - /** - * Do the XAMPP installation. - * - * @param progressMonitor - * @return A status indication of the process success or failure. - */ - protected IStatus install(IProgressMonitor progressMonitor) - { - if (CollectionsUtil.isEmpty(downloadedPaths) || CollectionsUtil.getFirstElement(downloadedPaths) == null) - { - String failureMessge = Messages.InstallProcessor_couldNotLocateInstaller; - String err = NLS.bind(Messages.InstallProcessor_failedToInstall, XAMPP); - displayMessageInUIThread(MessageDialog.ERROR, Messages.InstallProcessor_installationErrorTitle, err + ' ' - + failureMessge); - return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, err + ' ' + failureMessge); - } - SubMonitor subMonitor = SubMonitor.convert(progressMonitor, Messages.InstallProcessor_installerProgressInfo, - IProgressMonitor.UNKNOWN); - final Map installationAttributes = new HashMap(); - try - { - subMonitor.beginTask(NLS.bind(Messages.InstallProcessor_installingTaskName, XAMPP), - IProgressMonitor.UNKNOWN); - final String[] installDir = new String[1]; - Job installXAMPPDialog = new UIJob("XAMPP installer options") //$NON-NLS-1$ - { - @Override - public IStatus runInUIThread(IProgressMonitor monitor) - { - XAMPPInstallerOptionsDialog dialog = new XAMPPInstallerOptionsDialog(); - if (dialog.open() == Window.OK) - { - installationAttributes.putAll(dialog.getAttributes()); - return Status.OK_STATUS; - } - return Status.CANCEL_STATUS; - } - }; - installXAMPPDialog.schedule(); - try - { - installXAMPPDialog.join(); - } - catch (InterruptedException e) - { - } - IStatus result = installXAMPPDialog.getResult(); - if (!result.isOK()) - { - return result; - } - - IStatus status = installXAMPP(installationAttributes); - if (!status.isOK()) - { - return status; - } - IdeLog.logInfo(PortalUIPlugin.getDefault(), - "Successfully installed XAMPP into " + installDir[0] + ". XAMPP installation completed."); //$NON-NLS-1$ //$NON-NLS-2$ - // note that we called the finalizeInstallation from the installXAMPP Job. - return Status.OK_STATUS; - } - catch (Exception e) - { - IdeLog.logError(PortalUIPlugin.getDefault(), "Error while installing XAMPP", e); //$NON-NLS-1$ - return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, NLS.bind( - Messages.InstallProcessor_errorWhileInstalling, XAMPP)); - } - finally - { - subMonitor.done(); - } - } - - /** - * Run the XAMPP installer and install XMAPP into the given directory. - * - * @param installationAttributes - * - Attributes map that contains the installation directory and a specification whether to run the XAMPP - * auto-install script. - * @return The status of this installation - */ - protected IStatus installXAMPP(final Map installationAttributes) - { - Job job = new Job(NLS.bind(Messages.InstallProcessor_installerJobName, XAMPP + ' ' - + Messages.InstallProcessor_installerGroupTitle)) - { - @Override - protected IStatus run(IProgressMonitor monitor) - { - try - { - // extract the values from the attributes: - String installDir = (String) installationAttributes.get(InstallerOptionsDialog.INSTALL_DIR_ATTR); - boolean runAutoInstallScript = (Boolean) installationAttributes.get(EXECUTE_SETUP_SCRIPT_ATTR); - - SubMonitor subMonitor = SubMonitor.convert(monitor, IProgressMonitor.UNKNOWN); - subMonitor.beginTask(NLS.bind(Messages.InstallProcessor_installingTaskName, XAMPP), - IProgressMonitor.UNKNOWN); - IdeLog.logInfo(PortalUIPlugin.getDefault(), "Installing XAMPP into " + installDir); //$NON-NLS-1$ - - // Try to get a file lock first, before running the process. This file was just downloaded, so there - // is a chance it's still being held by the OS or by the downloader. - IPath downloadPath = downloadedPaths.get(0); - IStatus fileLockStatus = LockUtils.waitForLockRelease(downloadPath.toOSString(), 10000L); - if (!fileLockStatus.isOK()) - { - return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, NLS.bind( - Messages.InstallProcessor_failedToInstallSeeLog, XAMPP)); - } - // Run the XAMPP installer, as specified in this link: - // http://www.apachefriends.org/en/xampp-windows.html#522 - List command = new ArrayList(4); - command.add(downloadPath.toOSString()); - command.add("-d" + installDir); //$NON-NLS-1$ - command.add("-s2"); //$NON-NLS-1$ - if (runAutoInstallScript) - { - command.add("-spauto"); //$NON-NLS-1$ - } - ProcessBuilder processBuilder = new ProcessBuilder(command); - Process process = processBuilder.start(); - int res = process.waitFor(); - if (res == XAMPP_INSTALLER_PROCESS_CANCEL_CODE) - { - IdeLog.logInfo(PortalUIPlugin.getDefault(), "XAMPP installation cancelled"); //$NON-NLS-1$ - return Status.CANCEL_STATUS; - } - if (res != 0) - { - // We had an error while installing - IdeLog.logError( - PortalUIPlugin.getDefault(), - "Failed to install XAMPP. The XAMPP installer process returned a termination code of " + res); //$NON-NLS-1$ - return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, res, NLS.bind( - Messages.InstallProcessor_installationErrorMessage, XAMPP, XAMPP), null); - } - else if (!new File(installDir).exists()) - { - // Just to be sure that we got everything in place - IdeLog.logError(PortalUIPlugin.getDefault(), - "Failed to install XAMPP. The " + installDir + " directory was not created"); //$NON-NLS-1$ //$NON-NLS-2$ - return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, res, NLS.bind( - Messages.InstallProcessor_installationError_installDirMissing, XAMPP), null); - } - // In case we had the auto-setup script on, open the XAMPP control - if (runAutoInstallScript) - { - openXAMPPConsole(installDir + XAMPP_DEFAULT_FOLDER); - } - finalizeInstallation(installDir + XAMPP_DEFAULT_FOLDER); - return Status.OK_STATUS; - } - catch (Exception e) - { - IdeLog.logError(PortalUIPlugin.getDefault(), e); - return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, NLS.bind( - Messages.InstallProcessor_failedToInstallSeeLog, XAMPP), e); - } - finally - { - monitor.done(); - } - } - }; - // Give it a little delay, just in case the downloader still holds on to the installer file. - job.schedule(1000); - try - { - job.join(); - } - catch (InterruptedException e) - { - IdeLog.logError(PortalUIPlugin.getDefault(), e); - return Status.CANCEL_STATUS; - } - return job.getResult(); - } - - /** - * Opens the XAMPP console right after XAMPP was installed. - * - * @param installDir - */ - protected void openXAMPPConsole(final String installDir) - { - Job job = new Job(Messages.XAMPPInstallProcessor_openXAMPPConsoleJobName) - { - - @Override - protected IStatus run(IProgressMonitor monitor) - { - - try - { - ProcessBuilder processBuilder = new ProcessBuilder(installDir + XAMPP_CONTROL); - // We might stumble into 'Access Denied' errors when running this one. So this will try to - // re-initiate it several times. - int attempts = 5; - long timeOut = 3000L; - Throwable lastException = null; - do - { - if (monitor.isCanceled()) - { - break; - } - try - { - processBuilder.start(); - lastException = null; - break; - } - catch (Throwable t) - { - attempts--; - lastException = t; - } - Thread.sleep(timeOut); - } - while (attempts > 0); - if (lastException != null) - { - IdeLog.logError(PortalUIPlugin.getDefault(), lastException); - } - } - catch (Throwable t) - { - // Just log any error here, but don't display any error message - IdeLog.logError(PortalUIPlugin.getDefault(), t); - } - return Status.OK_STATUS; - } - - }; - job.schedule(3000L); - } - - /** - * Finalize the installation by placing a .aptana file in the installed directory, specifying some properties. - * - * @param installDir - */ - protected void finalizeInstallation(String installDir) - { - super.finalizeInstallation(installDir); - File propertiesFile = new File(installDir, APTANA_PROPERTIES_FILE_NAME); - Properties properties = new Properties(); - properties.put("xampp_install", urls[0]); //$NON-NLS-1$ - FileOutputStream fileOutputStream = null; - try - { - fileOutputStream = new FileOutputStream(propertiesFile); - properties.store(fileOutputStream, NLS.bind(Messages.InstallProcessor_aptanaInstallationComment, XAMPP)); - } - catch (IOException e) - { - IdeLog.logError(PortalUIPlugin.getDefault(), e); - } - finally - { - if (fileOutputStream != null) - { - try - { - fileOutputStream.flush(); - fileOutputStream.close(); - } - catch (IOException e) - { - } - } - } - } - - private class XAMPPInstallerOptionsDialog extends InstallerOptionsDialog - { - private Button executeScriptBt; - - public XAMPPInstallerOptionsDialog() - { - super(Display.getDefault().getActiveShell(), XAMPP); - setTitleImage(PortalUIPlugin.getDefault().getImageRegistry().get(PortalUIPlugin.XAMPP_IMAGE)); - } - - @Override - protected void setAttributes() - { - attributes.put(INSTALL_DIR_ATTR, installDir); - attributes.put(EXECUTE_SETUP_SCRIPT_ATTR, Boolean.TRUE); - } - - /** - * Add the 'Auto-Setup' checkbox. - */ - @Override - protected Composite createInstallerGroupControls(Composite group) - { - Composite control = super.createInstallerGroupControls(group); - executeScriptBt = new Button(group, SWT.CHECK); - executeScriptBt.setText(Messages.XAMPPInstallProcessor_executeXAMPPAutoSetup); - executeScriptBt.setSelection(true); - executeScriptBt.addSelectionListener(new SelectionAdapter() - { - @Override - public void widgetSelected(SelectionEvent e) - { - attributes.put(EXECUTE_SETUP_SCRIPT_ATTR, executeScriptBt.getSelection()); - } - }); - return control; - } - } -} diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/installer/InstallerOptionsDialog.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/installer/InstallerOptionsDialog.java deleted file mode 100644 index 522d90b8b2..0000000000 --- a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/installer/InstallerOptionsDialog.java +++ /dev/null @@ -1,308 +0,0 @@ -/** - * Aptana Studio - * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. - * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). - * Please see the license.html included with this distribution for details. - * Any modifications to this file must keep this entire header intact. - */ -package com.aptana.portal.ui.dispatch.configurationProcessors.installer; - -import java.io.File; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import org.eclipse.jface.dialogs.IDialogConstants; -import org.eclipse.jface.dialogs.IMessageProvider; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.dialogs.TitleAreaDialog; -import org.eclipse.osgi.util.NLS; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.KeyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.DirectoryDialog; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Group; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; - -import com.aptana.core.CoreStrings; -import com.aptana.core.util.PlatformUtil; -import com.aptana.core.util.StringUtil; -import com.aptana.portal.ui.dispatch.configurationProcessors.Messages; - -/** - * A generic implementation for an installation dialog. Through this dialog, the user can input arbitrary data that is - * needed for the specific installer. - * - * @author Shalom Gibly - */ -public abstract class InstallerOptionsDialog extends TitleAreaDialog -{ - public static final String INSTALL_DIR_ATTR = "install_dir"; //$NON-NLS-1$ - protected Map attributes; - protected Text path; - private String installerName; - private boolean createInstallDir; - - /** - * Constructs a new InstallerOptionsDialog - * - * @param parentShell - * @param installerName - */ - public InstallerOptionsDialog(Shell parentShell, String installerName) - { - this(parentShell, installerName, false); - } - - /** - * Constructs a new InstallerOptionsDialog. - * - * @param parentShell - * @param installerName - * @param createInstallDir - * - In case it's true, an input directory that does not exist will be created when the user - * clicks OK. - */ - public InstallerOptionsDialog(Shell parentShell, String installerName, boolean createInstallDir) - { - super(Display.getDefault().getActiveShell()); - this.installerName = installerName; - setBlockOnOpen(true); - setHelpAvailable(false); - attributes = new HashMap(); - setAttributes(); - this.createInstallDir = createInstallDir; - } - - /** - * Returns an unmodifiable Map of the attributes this install dialog is holding. - * - * @return - */ - public Map getAttributes() - { - return Collections.unmodifiableMap(attributes); - } - - /** - * Set attributes that can later be used when creating the dialog area. - * - * @param attributeName - * @param value - */ - protected abstract void setAttributes(); - - /** - * Configure the shell to display a title. - */ - @Override - protected void configureShell(Shell newShell) - { - super.configureShell(newShell); - newShell.setText(Messages.InstallProcessor_installerShellTitle); - } - - @Override - protected Control createDialogArea(Composite parent) - { - Composite composite = (Composite) super.createDialogArea(parent); - // Create a inner composite so we can control the margins - Composite inner = new Composite(composite, SWT.NONE); - inner.setLayoutData(new GridData(GridData.FILL_BOTH)); - GridLayout layout = new GridLayout(); - layout.marginLeft = 4; - layout.marginRight = 4; - layout.marginTop = 4; - layout.marginBottom = 4; - inner.setLayout(layout); - - // TODO - Split this to a method. - Group group = new Group(inner, SWT.NONE); - group.setText(Messages.InstallProcessor_installerGroupTitle); - group.setLayout(new GridLayout()); - GridData layoutData = new GridData(GridData.FILL_BOTH); - group.setLayoutData(layoutData); - - createInstallerGroupControls(group); - createExtendedControls(inner); - setTitle(NLS.bind(Messages.InstallProcessor_installerTitle, installerName)); - return composite; - } - - /** - * Returns the message that will be displayed in the installer dialog. - * - * @return An installer message. - */ - protected String getInstallerMessage() - { - return NLS.bind(Messages.InstallProcessor_installerMessage, installerName); - } - - /** - * Creates the components inside the 'Installer' group.
- * The default creation is only for the installation path. This can be overwritten, or extended, by a subclass. - * - * @param group - * @return A composite. - */ - protected Composite createInstallerGroupControls(Composite group) - { - Label l = new Label(group, SWT.WRAP); - l.setText(getInstallerMessage()); - Composite installLocation = new Composite(group, SWT.NONE); - installLocation.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - installLocation.setLayout(new GridLayout(2, false)); - path = new Text(installLocation, SWT.SINGLE | SWT.BORDER); - path.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - path.setText(attributes.get(INSTALL_DIR_ATTR).toString()); - path.addKeyListener(new KeyListener() - { - public void keyReleased(org.eclipse.swt.events.KeyEvent e) - { - attributes.put(INSTALL_DIR_ATTR, PlatformUtil.expandEnvironmentStrings(path.getText().trim())); - validatePath(); - } - - public void keyPressed(org.eclipse.swt.events.KeyEvent e) - { - attributes.put(INSTALL_DIR_ATTR, PlatformUtil.expandEnvironmentStrings(path.getText().trim())); - validatePath(); - } - }); - Button browse = new Button(installLocation, SWT.PUSH); - browse.setText(StringUtil.ellipsify(CoreStrings.BROWSE)); - browse.addSelectionListener(new SelectionAdapter() - { - @Override - public void widgetSelected(SelectionEvent e) - { - DirectoryDialog dirDialog = new DirectoryDialog(getParentShell()); - String dir = dirDialog.open(); - if (dir != null) - { - path.setText(dir); - attributes.put(INSTALL_DIR_ATTR, dir); - validatePath(); - } - } - }); - validatePath(); - return group; - } - - /* - * (non-Javadoc) - * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) - */ - @Override - protected void createButtonsForButtonBar(Composite parent) - { - super.createButtonsForButtonBar(parent); - validatePath(); - } - - /* - * (non-Javadoc) - * @see org.eclipse.jface.dialogs.Dialog#okPressed() - */ - @Override - protected void okPressed() - { - if (createInstallDir) - { - File f = new File(PlatformUtil.expandEnvironmentStrings(path.getText())); - if (!f.exists() && !f.mkdirs()) - { - // Display an error message about the problem and return here to prevent a dialog close. - MessageDialog.openError(getParentShell(), - Messages.InstallerOptionsDialog_creatingDirectoriesErrorTitle, - Messages.InstallerOptionsDialog_creatingDirectoriesErrorMessage); - return; - } - } - super.okPressed(); - } - - /** - * Validate the path - */ - protected void validatePath() - { - String pathText = path.getText().trim(); - if (pathText.length() == 0) - { - // empty path - setErrorMessage(Messages.InstallerOptionsDialog_emptyPathError); - return; - } - pathText = PlatformUtil.expandEnvironmentStrings(pathText); - if (!new File(pathText).exists()) - { - if (createInstallDir) - { - setMessage(Messages.InstallerOptionsDialog_inputDirectoryWillBeCreated, IMessageProvider.INFORMATION); - } - else - { - // non-existing path - setErrorMessage(Messages.InstallerOptionsDialog_nonExistingPathError); - return; - } - - } - setErrorMessage(null); - } - - /* - * (non-Javadoc) - * @see org.eclipse.jface.dialogs.TitleAreaDialog#setErrorMessage(java.lang.String) - */ - @Override - public void setErrorMessage(String newErrorMessage) - { - super.setErrorMessage(newErrorMessage); - Button button = getButton(IDialogConstants.OK_ID); - if (button != null) - { - button.setEnabled(newErrorMessage == null); - } - } - - /** - * Create extended controls that will appear under the 'Installer' group.
- * The default implementation is empty, and can be sub-classed. - * - * @param parent - * @return A composite. - */ - protected Composite createExtendedControls(Composite parent) - { - // Does nothing special here - return parent; - } - - /** - * Capitalize the word by upper-casing the first letter. - * - * @param word - * @return A capitalized word. - */ - protected static String capitalize(String word) - { - if (word != null && word.length() > 0) - { - return Character.toUpperCase(word.charAt(0)) + word.substring(1); - } - return word; - } -} diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/installer/JavaScriptImporterOptionsDialog.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/installer/JavaScriptImporterOptionsDialog.java deleted file mode 100644 index 9a6f1f89c4..0000000000 --- a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/installer/JavaScriptImporterOptionsDialog.java +++ /dev/null @@ -1,412 +0,0 @@ -/** - * Aptana Studio - * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. - * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). - * Please see the license.html included with this distribution for details. - * Any modifications to this file must keep this entire header intact. - */ -package com.aptana.portal.ui.dispatch.configurationProcessors.installer; - -import java.net.URI; - -import org.eclipse.core.filesystem.URIUtil; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.jface.dialogs.IDialogConstants; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.jface.viewers.ViewerFilter; -import org.eclipse.osgi.util.TextProcessor; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.dialogs.ElementTreeSelectionDialog; -import org.eclipse.ui.model.WorkbenchContentProvider; -import org.eclipse.ui.model.WorkbenchLabelProvider; -import org.eclipse.ui.views.navigator.ResourceComparator; - -import com.aptana.core.CoreStrings; -import com.aptana.core.util.StringUtil; -import com.aptana.portal.ui.PortalUIPlugin; -import com.aptana.portal.ui.dispatch.configurationProcessors.Messages; - -/** - * An import dialog that appears right after we download a JavaScript library through the developer-toolbox.
- * The dialog lets the user choose the project and the location in the project that the JS library will be saved. - * - * @author Shalom Gibly - */ -public class JavaScriptImporterOptionsDialog extends InstallerOptionsDialog -{ - public static final String ACTIVE_PROJECT_ATTR = "active_project"; //$NON-NLS-1$s - - private static final String RAILS_NATURE = "org.radrails.rails.core.railsnature"; //$NON-NLS-1$ - private static final String RAILS_JS_PATH = "/public/javascripts"; //$NON-NLS-1$ - private static final String JS_PATH = "/javascripts"; //$NON-NLS-1$ - private Combo projectsCombo; - private Button useDefaultsButton; - private Text path; - private Label locationLb; - private Button browseBt; - // The final selected location. Set on okPressed. - private String selectedLocation; - - /** - * Constructs a new dialog for importing a downloaded library into a project. - * - * @param parentShell - * @param libraryName - */ - public JavaScriptImporterOptionsDialog(Shell parentShell, String libraryName) - { - super(Display.getDefault().getActiveShell(), capitalize(libraryName)); - setTitleImage(PortalUIPlugin.getDefault().getImageRegistry().get(PortalUIPlugin.JS_IMAGE)); - } - - /** - * Configure the shell to display a title. - */ - @Override - protected void configureShell(Shell newShell) - { - super.configureShell(newShell); - newShell.setText(Messages.InstallProcessor_installerShellTitle); - } - - /** - * Set the attributes for this dialog.
- * By default, the active project is set. - */ - @Override - protected void setAttributes() - { - attributes.put(ACTIVE_PROJECT_ATTR, PortalUIPlugin.getActiveProject()); - } - - /** - * Returns the selected, valid, location for the JavaScript library location. Note that this location might still - * need to be created under the current project. - * - * @return The selected location for the JavaScript library. - */ - public String getSelectedLocation() - { - return selectedLocation; - } - - /* - * (non-Javadoc) - * @see org.eclipse.jface.dialogs.Dialog#okPressed() - */ - @Override - protected void okPressed() - { - selectedLocation = path.getText(); - super.okPressed(); - } - - /* - * (non-Javadoc) - * @see org.eclipse.jface.dialogs.TitleAreaDialog#setErrorMessage(java.lang.String) - */ - @Override - public void setErrorMessage(String newErrorMessage) - { - super.setErrorMessage(newErrorMessage); - Button button = getButton(IDialogConstants.OK_ID); - if (button != null) - { - button.setEnabled(newErrorMessage == null); - } - } - - /* - * (non-Javadoc) - * @see org.eclipse.jface.dialogs.TitleAreaDialog#createContents(org.eclipse.swt.widgets.Composite) - */ - @Override - protected Control createContents(Composite parent) - { - Control c = super.createContents(parent); - validatePath(); - return c; - } - - /** - * Creates the components inside the 'Installer' group.
- * The controls that are added here allow project selection and folder selection under the selected project.
- * - * @param group - * @return A composite. - */ - protected Composite createInstallerGroupControls(Composite group) - { - int columns = 3; - Composite projectGroup = new Composite(group, SWT.NONE); - GridLayout layout = new GridLayout(); - layout.numColumns = columns; - projectGroup.setLayout(layout); - projectGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - Label projectSelectionLable = new Label(projectGroup, SWT.NONE); - projectSelectionLable.setText(Messages.ImportJavaScriptLibraryDialog_projectLable); - projectsCombo = new Combo(projectGroup, SWT.DROP_DOWN | SWT.READ_ONLY); - GridData gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalSpan = 2; - projectsCombo.setLayoutData(gd); - - useDefaultsButton = new Button(projectGroup, SWT.CHECK | SWT.RIGHT); - useDefaultsButton.setText(Messages.ImportJavaScriptLibraryDialog_useDefaultLocation); - useDefaultsButton.setSelection(true); - gd = new GridData(); - gd.horizontalSpan = columns; - useDefaultsButton.setLayoutData(gd); - - createUserPathArea(projectGroup, true); - - useDefaultsButton.addSelectionListener(new SelectionAdapter() - { - public void widgetSelected(SelectionEvent e) - { - boolean useDefaults = useDefaultsButton.getSelection(); - path.setText(TextProcessor.process(getDefaultPath())); - setPathAreaEnabled(!useDefaults); - } - }); - setPathAreaEnabled(false); - initProjectsCombo(projectsCombo); - return group; - } - - /** - * Adds the projects in the workspace and selects the active one (if resolved). - * - * @param combo - */ - private void initProjectsCombo(final Combo combo) - { - IProject[] allProjects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); - for (IProject project : allProjects) - { - if (project.isAccessible()) - { - combo.add(project.getName()); - combo.setData(project.getName(), project); - } - } - if (combo.getItemCount() == 0) - { - return; - } - IProject activeProject = PortalUIPlugin.getActiveProject(); - String activeProjectName = (activeProject != null) ? activeProject.getName() : null; - if (activeProject != null && activeProject.isAccessible()) - { - int index = combo.indexOf(activeProjectName); - combo.select(Math.max(0, index)); - attributes.put(ACTIVE_PROJECT_ATTR, activeProject); - } - else - { - if (combo.getItemCount() > 0) - { - combo.select(0); - attributes.put(ACTIVE_PROJECT_ATTR, combo.getData(combo.getText())); - } - } - path.setText(TextProcessor.process(getDefaultPath())); - - // track the selections from now on - combo.addSelectionListener(new SelectionAdapter() - { - @Override - public void widgetSelected(SelectionEvent e) - { - attributes.put(ACTIVE_PROJECT_ATTR, combo.getData(combo.getText())); - // update the path - path.setText(TextProcessor.process(getDefaultPath())); - } - }); - } - - /** - * Create the area for user entry. - * - * @param composite - * @param defaultEnabled - */ - private void createUserPathArea(Composite composite, boolean defaultEnabled) - { - locationLb = new Label(composite, SWT.NONE); - locationLb.setText(Messages.ImportJavaScriptLibraryDialog_locationLabel); - path = new Text(composite, SWT.BORDER); - GridData data = new GridData(GridData.FILL_HORIZONTAL); - data.widthHint = 250; - path.setLayoutData(data); - - // browse button - browseBt = new Button(composite, SWT.PUSH); - browseBt.setText(StringUtil.ellipsify(CoreStrings.BROWSE)); - browseBt.addSelectionListener(new SelectionAdapter() - { - public void widgetSelected(SelectionEvent event) - { - ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(getShell(), - new WorkbenchLabelProvider(), new WorkbenchContentProvider()); - dialog.setBlockOnOpen(true); - dialog.setAllowMultiple(false); - dialog.setHelpAvailable(false); - dialog.setTitle(Messages.ImportJavaScriptLibraryDialog_folderSelectionDialogTitle); - dialog.setMessage(Messages.ImportJavaScriptLibraryDialog_folderSelectionDialogMessage); - final IProject project = (IProject) attributes.get(ACTIVE_PROJECT_ATTR); - dialog.setInput(ResourcesPlugin.getWorkspace().getRoot()); - dialog.setComparator(new ResourceComparator(ResourceComparator.NAME)); - // Filter out files and other projects - dialog.addFilter(new ViewerFilter() - { - @Override - public boolean select(Viewer viewer, Object parentElement, Object element) - { - if (parentElement instanceof IResource) - { - if (element instanceof IProject) - { - return element.equals(project); - } - IProject parentProject = ((IResource) parentElement).getProject(); - if (!parentProject.equals(project)) - { - return false; - } - if (element instanceof IResource) - { - IResource resource = (IResource) element; - if (resource.isHidden()) - { - return false; - } - if (resource.getLocation().toFile().isDirectory()) - { - return true; - } - } - } - return false; - } - }); - int buttonId = dialog.open(); - if (buttonId == IDialogConstants.OK_ID) - { - IResource resource = (IResource) dialog.getFirstResult(); - path.setText(TextProcessor.process(project.getName() + '/' - + resource.getProjectRelativePath().toString())); - } - } - }); - - path.setText(TextProcessor.process(getDefaultPath())); - - // Validate any user-input changes - path.addModifyListener(new ModifyListener() - { - public void modifyText(ModifyEvent e) - { - validatePath(); - } - }); - } - - /** - * Returns the default JavaScript library installation path for currently selected project. - * - * @return The default path to place the JavaScript library under the selected project. - */ - protected String getDefaultPath() - { - IProject project = (IProject) attributes.get(ACTIVE_PROJECT_ATTR); - if (project == null) - { - return StringUtil.EMPTY; - } - boolean isRails = false; - try - { - isRails = project.hasNature(RAILS_NATURE); - } - catch (CoreException e) - { - } - return project.getName() + (isRails ? RAILS_JS_PATH : JS_PATH); - } - - /** - * Validate the typed path and notify the user on errors. - */ - protected void validatePath() - { - String pathString = path.getText(); - String errorMsg = null; - // Check for empty content/projects list. - if (projectsCombo.getItemCount() == 0) - { - errorMsg = Messages.ImportJavaScriptLibraryDialog_noAccessibleProjectsError; - } - - if (errorMsg == null && pathString.length() == 0) - { - errorMsg = Messages.ImportJavaScriptLibraryDialog_emptyPathError; - } - URI uri = URIUtil.toURI(pathString); - // Check for valid URI - if (errorMsg == null && uri == null) - { - errorMsg = Messages.ImportJavaScriptLibraryDialog_invalidPathError; - } - if (errorMsg == null) - { - // Check that the URI is actually located under the selected project - IProject project = (IProject) attributes.get(ACTIVE_PROJECT_ATTR); - if (project != null) - { - // make sure we add a '/' prefix to the URI path to have this check cross-platform (Windows os returns - // the URI without it). - String projectPath = project.getFullPath().toString(); - String uriPath = uri.getPath(); - if (uriPath != null && !uriPath.startsWith("/")) //$NON-NLS-1$ - { - uriPath = '/' + uriPath; - } - if (uriPath == null || !uriPath.startsWith(projectPath + '/')) - { - errorMsg = Messages.ImportJavaScriptLibraryDialog_wrongProjectRootError; - } - } - } - // set error message - setErrorMessage(errorMsg); - } - - /* - * Set the enablement state of the path area. - * @param enabled - */ - private void setPathAreaEnabled(boolean enabled) - { - locationLb.setEnabled(enabled); - path.setEnabled(enabled); - browseBt.setEnabled(enabled); - } -} diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/messages.properties b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/messages.properties deleted file mode 100644 index deaf32a945..0000000000 --- a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/configurationProcessors/messages.properties +++ /dev/null @@ -1,68 +0,0 @@ -#GEMS -GemsConfigurationProcessor_errorInvokingGemList=Error while invoking 'gem list' -GemsConfigurationProcessor_missingShellError=Could not run the command (missing Shell) -GemsConfigurationProcessor_wrongGemsRequest=Wrong structure of Gems request -#APP INSTALL -ImportJavaScriptLibraryDialog_emptyPathError=The library path cannot be empty -ImportJavaScriptLibraryDialog_folderSelectionDialogMessage=Select the location you wish to import the JavaScript library files to: -ImportJavaScriptLibraryDialog_folderSelectionDialogTitle=Library Folder Selection -ImportJavaScriptLibraryDialog_invalidPathError=The given path is invalid -ImportJavaScriptLibraryDialog_locationLabel=&Location -ImportJavaScriptLibraryDialog_noAccessibleProjectsError=There are no accessible projects in your workspace. Please create or open one first. -ImportJavaScriptLibraryDialog_projectLable=Project: -ImportJavaScriptLibraryDialog_useDefaultLocation=Use &default location -ImportJavaScriptLibraryDialog_wrongProjectRootError=The path is not under the selected project root -InstallerConfigurationProcessor_emptyURLsArrayError=Expected an array of URLs, but got an empty array -InstallerConfigurationProcessor_expectedArrayError=Expected an array of attributes, but got -InstallerConfigurationProcessor_expectedMapError=Expected a Map of extended attributes, but got -InstallerConfigurationProcessor_expectedURLsArrayError=Expected an array of URLs, but got -InstallerConfigurationProcessor_unableToExtractZip=Unable to extract the Zip file.\nSee error log for more details. -InstallProcessor_couldNotLocateInstaller=We could not locate the installer. -InstallProcessor_corruptedZip=The {0} zip might be corrupted. -InstallProcessor_couldNotLocatePackage=We could not locate the {0} package. -InstallProcessor_errorWhileInstalling=Error while installing {0} -InstallProcessor_extractingPackageTaskName=Extracting {0} into {1} -InstallProcessor_failedToInstallSeeLog=Failed to install {0}.\nSee error log for more details -InstallProcessor_failedToInstall=Failed to install {0}. -InstallProcessor_failedToWrite=Failed to write to -InstallProcessor_installationError_installDirMissing=Failed to install {0}. \nWe could not locate the installation directory.\nSee error log for more details. -InstallProcessor_installationErrorMessage=Failed to install {0}. \nThe {1} installer indicated an error has occurred.\nSee error log for more details. -InstallProcessor_installationErrorTitle=Installation Error -InstallProcessor_installerGroupTitle=Installer -InstallProcessor_installerMessage={0} will be installed into the following folder. \nClick OK to install, or select a different folder before you continue. -InstallProcessor_installerProgressInfo=Installing... -InstallProcessor_installerShellTitle=Installer -InstallProcessor_installerTitle={0} Installer -InstallProcessor_extractingJobName=Extracting {0} -InstallProcessor_installingTaskName=Installing {0}... -InstallProcessor_executingTaskName=Executing {0} -InstallProcessor_missingInstallURLs=Missing {0} installation URL attributes -InstallProcessor_installationSuccessful={0} installation was completed successfully -InstallProcessor_installerJobName=Running {0} -InstallProcessor_seeErrorLog=.\nSee error log for more details -InstallProcessor_updatingTaskName=Updating {0} settings -InstallProcessor_InstallForAllUsers=Install for all users -InstallProcessor_wrongNumberOfInstallLinks=Got a wrong number of {0} installation links. Expected {1} links, and got {2} -InstallProcessor_aptanaInstallationComment=Aptana Studio Dev-Toolbox used these locations to install {0}.\nPlease do not delete this file, as we might use it to update your installation from time to time. -InstallerConfigurationProcessor_missingAttributeMap=Missing the {0} attributes map -InstallerConfigurationProcessor_missingDownloadTargets=The download targets URLs were empty.\n See error log for more details. -InstallerOptionsDialog_creatingDirectoriesErrorMessage=Failed creating a directory. \nPlease make sure you have write permissions for the selected path. -InstallerOptionsDialog_creatingDirectoriesErrorTitle=Error Creating Directories -InstallerOptionsDialog_emptyPathError=The selected path is empty -InstallerOptionsDialog_inputDirectoryWillBeCreated=The input directory does not exist and will be created -InstallerOptionsDialog_nonExistingPathError=The selected path does not exist -#JavaScript library installer -JSLibraryInstallProcessor_directoriesCreationFailed=Failed to create directories while importing the JavaScript library.\nSee error log for more details. -JSLibraryInstallProcessor_directorySelection=Directory Selection -JSLibraryInstallProcessor_fileConflictMessage=The target directory already contains ' -JSLibraryInstallProcessor_fileConflictTitle=File Conflict -JSLibraryInstallProcessor_multipleErrorsWhileImportingJS=Some errors occurred while importing the JavaScript library. -JSLibraryInstallProcessor_overwriteQuestion='.\n Would you like to overwrite it? -JSLibraryInstallProcessor_unexpectedNull=Unexpected null project when importing a JavaScript library.\nSee error log for more details. - -#SYSTEM -SystemConfigurationProcessor_missingConfigurationItems=Missing system configuration items attributes -SystemConfigurationProcessor_noShellCommandPath=Could not locate the shell command path -SystemConfigurationProcessor_wrongConfigurationAttributesStructure=Wrong structure of configuration items attributes -XAMPPInstallProcessor_executeXAMPPAutoSetup=Execute XAMPP auto-setup script -XAMPPInstallProcessor_openXAMPPConsoleJobName=Opening the XAMPP console... diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/processorDelegates/CachedVersionProcessorDelegate.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/processorDelegates/CachedVersionProcessorDelegate.java deleted file mode 100644 index dd8d2cf470..0000000000 --- a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/processorDelegates/CachedVersionProcessorDelegate.java +++ /dev/null @@ -1,136 +0,0 @@ -/** - * Aptana Studio - * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. - * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). - * Please see the license.html included with this distribution for details. - * Any modifications to this file must keep this entire header intact. - */ -package com.aptana.portal.ui.dispatch.processorDelegates; - -import java.io.File; -import java.util.Map; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.ProjectScope; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.preferences.DefaultScope; -import org.eclipse.core.runtime.preferences.IEclipsePreferences; -import org.eclipse.core.runtime.preferences.IPreferencesService; -import org.eclipse.core.runtime.preferences.IScopeContext; -import org.eclipse.core.runtime.preferences.InstanceScope; -import org.osgi.service.prefs.BackingStoreException; - -import com.aptana.core.logging.IdeLog; -import com.aptana.core.util.StringUtil; -import com.aptana.jetty.util.epl.ajax.JSON; -import com.aptana.portal.ui.IPortalPreferences; -import com.aptana.portal.ui.PortalUIPlugin; - -/** - * A configuration processor delegate that use the preferences as a cache mechanism for the installed apps versions. - * - * @author Shalom Gibly - */ -public class CachedVersionProcessorDelegate extends BaseVersionProcessor -{ - - private String appName; - - /** - * Constructs a new CachedVersionProcessorDelegate.
- * Unlike other processor delegates, this one is not instantiated through an extension point, as it's being - * allocated per application that does not have a version delegate. So, this instance should be created with the - * application name. This application name will be used to track the cached version preference for that app. - * - * @param appName - */ - public CachedVersionProcessorDelegate(String appName) - { - this.appName = appName; - - } - - @Override - public String getSupportedApplication() - { - return appName; - } - - /** - * The run command for this special delegate looks for a version value cached in the workspace preferences.
- * The version identifier was cached in the preferences when the app was installed through the dev-toolbox. This - * method also tries to verify that the application is still in the cached location. If not, which means it was - * probably removed externally, we remove the cache from the preferences. - * - * @param commandType - * Expecting for the 'version' command. - * @param workingDir - * - Not used in this delegate, and may be null. - */ - @SuppressWarnings("unchecked") - @Override - public Object runCommand(String commandType, IPath workingDir) - { - // We cache the version and the location in the preferences as a JSON string. So, it's pretty easy to maintain. - - IPreferencesService service = Platform.getPreferencesService(); - IScopeContext[] contexts; - IProject project = PortalUIPlugin.getActiveProject(); - if (project != null) - { - contexts = new IScopeContext[] { new ProjectScope(project), DefaultScope.INSTANCE }; - } - else - { - contexts = new IScopeContext[] { InstanceScope.INSTANCE, DefaultScope.INSTANCE }; - } - String versions = service.getString(PortalUIPlugin.PLUGIN_ID, IPortalPreferences.CACHED_VERSIONS_PROPERTY_NAME, - null, contexts); - if (versions == null || versions.equals(StringUtil.EMPTY)) - { - return null; - } - Map> mapping = (Map>) JSON.parse(versions); - Map appVersion = mapping.get(getSupportedApplication().toLowerCase()); - if (appVersion != null) - { - String location = appVersion.get(IPortalPreferences.CACHED_LOCATION_PROPERTY); - String version = appVersion.get(IPortalPreferences.CACHED_VERSION_PROPERTY); - if (location != null) - { - // Verify that this location still exists on that machine. If not, remove it and store it back to the - // preferences. - File localFile = new File(location); - if (!localFile.exists()) - { - mapping.remove(getSupportedApplication().toLowerCase()); - IEclipsePreferences node = null; - if (project != null) - { - node = contexts[0].getNode(PortalUIPlugin.PLUGIN_ID); - } - else - { - node = contexts[1].getNode(PortalUIPlugin.PLUGIN_ID); - } - node.put(IPortalPreferences.CACHED_VERSIONS_PROPERTY_NAME, JSON.toString(mapping)); - try - { - node.flush(); - } - catch (BackingStoreException e) - { - IdeLog.logError(PortalUIPlugin.getDefault(), e); - return null; - } - return version; - } - // We are good to return the cached version - return version; - } - } - return null; - } - -} diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/processorDelegates/RailsVersionProcessor.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/processorDelegates/RailsVersionProcessor.java deleted file mode 100644 index 4c2615a7e4..0000000000 --- a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/processorDelegates/RailsVersionProcessor.java +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Aptana Studio - * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. - * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). - * Please see the license.html included with this distribution for details. - * Any modifications to this file must keep this entire header intact. - */ -package com.aptana.portal.ui.dispatch.processorDelegates; - -/** - * A rails version processor that can get the current rails version in the system - * - * @author Shalom Gibly - */ -public class RailsVersionProcessor extends BaseVersionProcessor -{ - private static final String RAILS = "rails"; //$NON-NLS-1$ - - /** - * @return "rails" - */ - @Override - public String getSupportedApplication() - { - return RAILS; - } -} diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/processorDelegates/RubyVersionProcessor.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/processorDelegates/RubyVersionProcessor.java deleted file mode 100644 index c2320e6b78..0000000000 --- a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/processorDelegates/RubyVersionProcessor.java +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Aptana Studio - * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. - * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). - * Please see the license.html included with this distribution for details. - * Any modifications to this file must keep this entire header intact. - */ -package com.aptana.portal.ui.dispatch.processorDelegates; - -/** - * A Ruby version processor that can get the current Ruby version in the system - * - * @author Shalom Gibly - */ -public class RubyVersionProcessor extends BaseVersionProcessor -{ - private static final String RUBY = "ruby"; //$NON-NLS-1$ - - /** - * @return "ruby" - */ - @Override - public String getSupportedApplication() - { - return RUBY; - } -} diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/processorDelegates/SQLiteVersionProcessor.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/processorDelegates/SQLiteVersionProcessor.java deleted file mode 100644 index 0f7ca89e04..0000000000 --- a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/dispatch/processorDelegates/SQLiteVersionProcessor.java +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Aptana Studio - * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. - * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). - * Please see the license.html included with this distribution for details. - * Any modifications to this file must keep this entire header intact. - */ -package com.aptana.portal.ui.dispatch.processorDelegates; - - -/** - * A SQLite3 version processor that can get the current SQLite3 version in the system - * - * @author Shalom Gibly - */ -public class SQLiteVersionProcessor extends BaseVersionProcessor -{ - private static final String SQLITE = "sqlite3"; //$NON-NLS-1$ - - /** - * @return "sqlite3" - */ - @Override - public String getSupportedApplication() - { - return SQLITE; - } -} diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/internal/Portal.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/internal/Portal.java index ad3ae4be51..a95e3cf57e 100644 --- a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/internal/Portal.java +++ b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/internal/Portal.java @@ -26,10 +26,8 @@ import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.RGB; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; @@ -51,10 +49,7 @@ import com.aptana.portal.ui.IPortalPreferences; import com.aptana.portal.ui.PortalUIPlugin; import com.aptana.portal.ui.browser.AbstractPortalBrowserEditor; -import com.aptana.theme.IThemeManager; -import com.aptana.theme.ThemePlugin; -import com.aptana.ui.util.UIUtils; -import com.aptana.usage.UsagePlugin; +import com.aptana.portal.ui.browser.UIUtils; /** * The portal class is a singleton that controls the portal browser and allows interacting with it. @@ -160,12 +155,12 @@ else if (!isConnected(url)) URL localURL = FileLocator.toFileURL(Portal.class.getResource(BASE_LOCAL_URL)); url = URLUtil.appendParameters(localURL, new String[] { "url", url.toString() }); //$NON-NLS-1$ } - Map parameters = getURLParametersForProject(PortalUIPlugin.getActiveProject()); - if (additionalParameters != null) - { - parameters.putAll(additionalParameters); - } - url = URLUtil.appendParameters(url, parameters, false); +// Map parameters = getURLParametersForProject(PortalUIPlugin.getActiveProject()); +// if (additionalParameters != null) +// { +// parameters.putAll(additionalParameters); +// } + url = URLUtil.appendParameters(url, new HashMap(), false); } catch (IOException e) { @@ -287,6 +282,7 @@ protected URL getDefaultURL() throws IOException return getDefaultURL(new URL(BASE_REMOTE_URL), Portal.class.getResource(BASE_LOCAL_URL)); } + /** * Returns the default URL for the portal.
* In case we have a live Internet connection, return the remote content. Otherwise, return the local content. @@ -359,56 +355,56 @@ protected HttpsURLConnection getConnection(URL httpsURL) throws Exception return con; } - /** - * Build the URL GET parameters that will be appended to the original portal path. - * - * @param activeProject - * @return The GET parameters string - */ - @SuppressWarnings("nls") - protected Map getURLParametersForProject(final IProject activeProject) - { - final Map builder = new HashMap(); - builder.putAll(URLUtil.getDefaultParameters()); - - builder.put("bg", toHex(getThemeManager().getCurrentTheme().getBackground())); - builder.put("fg", toHex(getThemeManager().getCurrentTheme().getForeground())); - - // "chrome" - UIUtils.getDisplay().syncExec(new Runnable() - { - public void run() - { - Color color = PlatformUI.getWorkbench().getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND); - builder.put("ch", toHex(color.getRGB()));// FIXME Grab one of the actual parent widgets and grab it's - // bg? - } - }); - - // project type - builder.put("p", String.valueOf(getProjectType(activeProject))); - - // version control - // builder.append("&vc="); - // builder.append(getVersionControl()); - - // github - // builder.append("&gh="); - // builder.append(hasGithubRemote() ? '1' : '0'); - - // timestamp to force updates to server (bypass browser cache) - builder.put("ts", String.valueOf(System.currentTimeMillis())); - - // guid that relates to a single install of the IDE - builder.put("id", getGUID()); - - // deploy info - builder.putAll(getDeployParam(activeProject)); - - // for debugging output - // builder.append("&debug=1"); - return builder; - } +// /** +// * Build the URL GET parameters that will be appended to the original portal path. +// * +// * @param activeProject +// * @return The GET parameters string +// */ +// @SuppressWarnings("nls") +// protected Map getURLParametersForProject(final IProject activeProject) +// { +// final Map builder = new HashMap(); +// builder.putAll(URLUtil.getDefaultParameters()); +// +// builder.put("bg", toHex(getThemeManager().getCurrentTheme().getBackground())); +// builder.put("fg", toHex(getThemeManager().getCurrentTheme().getForeground())); +// +// // "chrome" +// UIUtils.getDisplay().syncExec(new Runnable() +// { +// public void run() +// { +// Color color = PlatformUI.getWorkbench().getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND); +// builder.put("ch", toHex(color.getRGB()));// FIXME Grab one of the actual parent widgets and grab it's +// // bg? +// } +// }); +// +// // project type +// builder.put("p", String.valueOf(getProjectType(activeProject))); +// +// // version control +// // builder.append("&vc="); +// // builder.append(getVersionControl()); +// +// // github +// // builder.append("&gh="); +// // builder.append(hasGithubRemote() ? '1' : '0'); +// +// // timestamp to force updates to server (bypass browser cache) +// builder.put("ts", String.valueOf(System.currentTimeMillis())); +// +// // guid that relates to a single install of the IDE +//// builder.put("id", getGUID()); +// +// // deploy info +// builder.putAll(getDeployParam(activeProject)); +// +// // for debugging output +// // builder.append("&debug=1"); +// return builder; +// } @SuppressWarnings("nls") protected Map getDeployParam(IProject selectedProject) @@ -440,21 +436,6 @@ protected Map getDeployParam(IProject selectedProject) return builder; } - /** - * Get the theme manager. - * - * @return - */ - protected IThemeManager getThemeManager() - { - return ThemePlugin.getDefault().getThemeManager(); - } - - protected String getGUID() - { - return UsagePlugin.getApplicationId(); - } - protected char getProjectType(IProject selectedProject) { if (selectedProject != null && selectedProject.isAccessible()) diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/internal/command/NewProjectFromTemplateCommandHandler.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/internal/command/NewProjectFromTemplateCommandHandler.java index 6dc1dbea22..2dd9fa4bc9 100644 --- a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/internal/command/NewProjectFromTemplateCommandHandler.java +++ b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/internal/command/NewProjectFromTemplateCommandHandler.java @@ -1,98 +1,47 @@ -/** - * Aptana Studio - * Copyright (c) 2011 by Appcelerator, Inc. All Rights Reserved. - * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). - * Please see the license.html included with this distribution for details. - * Any modifications to this file must keep this entire header intact. - */ package com.aptana.portal.ui.internal.command; -import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IExecutableExtension; -import org.eclipse.jface.wizard.WizardDialog; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.IWorkbenchWizard; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.wizards.IWizardDescriptor; -import org.eclipse.ui.wizards.IWizardRegistry; +import org.eclipse.core.commands.IHandler; +import org.eclipse.core.commands.IHandlerListener; -import com.aptana.projects.wizards.AbstractNewProjectWizard; -import com.aptana.projects.wizards.ProjectTemplateSelectionPage; -import com.aptana.ui.util.UIUtils; - -/** - * Command handler for "com.aptana.portal.ui.command.newProjectFromTemplate". Opens an Aptana/Titanium wizard and - * initializes the project template - * - * @author nle - */ -public class NewProjectFromTemplateCommandHandler extends AbstractHandler +public class NewProjectFromTemplateCommandHandler implements IHandler { - /** - * Execute the new project command. The command returns the created {@link IProject} name when it's done, in case a - * project was created. - * - * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent) - */ - public Object execute(ExecutionEvent event) throws ExecutionException + public void addHandlerListener(IHandlerListener handlerListener) { - String wizardId = event.getParameter(ProjectTemplateSelectionPage.COMMAND_PROJECT_FROM_TEMPLATE_NEW_WIZARD_ID); - String templateName = event - .getParameter(ProjectTemplateSelectionPage.COMMAND_PROJECT_FROM_TEMPLATE_PROJECT_TEMPLATE_NAME); + // TODO Auto-generated method stub + + } - IWizardRegistry wizardRegistry = PlatformUI.getWorkbench().getNewWizardRegistry(); - IWizardDescriptor wizardDescriptor = wizardRegistry.findWizard(wizardId); - if (wizardDescriptor == null) - { - throw new ExecutionException("unknown wizard: " + wizardId); //$NON-NLS-1$ - } + public void dispose() + { + // TODO Auto-generated method stub - try - { - IWorkbenchWizard wizard = wizardDescriptor.createWizard(); - wizard.init(PlatformUI.getWorkbench(), null); + } - if (wizard instanceof IExecutableExtension) - { - ((IExecutableExtension) wizard).setInitializationData(null, - ProjectTemplateSelectionPage.COMMAND_PROJECT_FROM_TEMPLATE_PROJECT_TEMPLATE_NAME, templateName); - } + public Object execute(ExecutionEvent event) throws ExecutionException + { + // TODO Auto-generated method stub + return null; + } - if (wizardDescriptor.canFinishEarly() && !wizardDescriptor.hasPages()) - { - wizard.performFinish(); - return getProject(wizard); - } + public boolean isEnabled() + { + // TODO Auto-generated method stub + return false; + } - Shell parent = UIUtils.getActiveShell(); - WizardDialog dialog = new WizardDialog(parent, wizard); - dialog.create(); - dialog.open(); - return getProject(wizard); - } - catch (CoreException ex) - { - throw new ExecutionException("error creating wizard", ex); //$NON-NLS-1$ - } + public boolean isHandled() + { + // TODO Auto-generated method stub + return false; } - /** - * Returns the created project. - * - * @param wizard - * @return An {@link IProject}, or null. - */ - private IProject getProject(IWorkbenchWizard wizard) + public void removeHandlerListener(IHandlerListener handlerListener) { - if (wizard instanceof AbstractNewProjectWizard) - { - return ((AbstractNewProjectWizard) wizard).getCreatedProject(); - } - return null; + // TODO Auto-generated method stub + } + } diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/internal/startpage/StartPageBrowserEditor.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/internal/startpage/StartPageBrowserEditor.java index 12079df7d3..364cb12519 100644 --- a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/internal/startpage/StartPageBrowserEditor.java +++ b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/internal/startpage/StartPageBrowserEditor.java @@ -24,7 +24,7 @@ public class StartPageBrowserEditor extends AbstractPortalBrowserEditor { public static final String WEB_BROWSER_EDITOR_ID = "com.aptana.portal.ui.browser.startPage"; //$NON-NLS-1$ - public static final String STUDIO_START_PAGE_URL = "http://content.aptana.com/aptana/my_aptana/?content=start"; //$NON-NLS-1$ + public static final String STUDIO_START_PAGE_URL = "https://appc-studio.appcelerator.com/"; //$NON-NLS-1$ private static final String TITLE_IMAGE = "icons/obj16/radrails16.png"; //$NON-NLS-1$ diff --git a/plugins/com.aptana.projects/plugin.xml b/plugins/com.aptana.projects/plugin.xml index 2dd91dc526..4f69a7b3f0 100644 --- a/plugins/com.aptana.projects/plugin.xml +++ b/plugins/com.aptana.projects/plugin.xml @@ -191,14 +191,6 @@
- - - - Date: Thu, 17 Aug 2017 16:22:05 +0800 Subject: [PATCH 2/3] portal UI plugin extended --- com.aptana.portal.ui.extended/.classpath | 7 + com.aptana.portal.ui.extended/.project | 28 + .../.settings/org.eclipse.jdt.core.prefs | 7 + .../META-INF/MANIFEST.MF | 13 + .../build.properties | 4 + .../TemplateActionController.java | 129 +++++ .../ThemeActionController.java | 158 ++++++ .../actionControllers/messages.properties | 8 + .../AbstractBrowserNotification.java | 128 +++++ .../BrowserNotificationProxy.java | 135 +++++ .../ProjectCreationBrowserNotification.java | 67 +++ .../RecentFilesBrowserNotification.java | 144 ++++++ .../TemplatesNotification.java | 126 +++++ .../InstallerConfigurationProcessor.java | 286 ++++++++++ .../JavaScriptLibraryInstallProcessor.java | 269 ++++++++++ .../configurationProcessors/Messages.java | 96 ++++ .../PythonInstallProcessor.java | 429 +++++++++++++++ .../RubyInstallProcessor.java | 391 ++++++++++++++ .../VersionsConfigurationProcessor.java | 207 ++++++++ .../XAMPPInstallProcessor.java | 487 ++++++++++++++++++ .../installer/InstallerOptionsDialog.java | 308 +++++++++++ .../JavaScriptImporterOptionsDialog.java | 412 +++++++++++++++ .../messages.properties | 68 +++ .../BaseVersionProcessor.java | 29 ++ .../CachedVersionProcessorDelegate.java | 136 +++++ .../RailsVersionProcessor.java | 27 + .../RubyVersionProcessor.java | 27 + .../SQLiteVersionProcessor.java | 28 + .../aptana/portal/ui/extended/Activator.java | 50 ++ .../NewProjectFromTemplateCommandHandler.java | 98 ++++ .../command/ShowStartPageCommandHandler.java | 33 ++ .../command/ShowToolboxCommandHandler.java | 34 ++ 32 files changed, 4369 insertions(+) create mode 100644 com.aptana.portal.ui.extended/.classpath create mode 100644 com.aptana.portal.ui.extended/.project create mode 100644 com.aptana.portal.ui.extended/.settings/org.eclipse.jdt.core.prefs create mode 100644 com.aptana.portal.ui.extended/META-INF/MANIFEST.MF create mode 100644 com.aptana.portal.ui.extended/build.properties create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/actionControllers/TemplateActionController.java create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/actionControllers/ThemeActionController.java create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/actionControllers/messages.properties create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/browserNotifications/AbstractBrowserNotification.java create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/browserNotifications/BrowserNotificationProxy.java create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/browserNotifications/ProjectCreationBrowserNotification.java create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/browserNotifications/RecentFilesBrowserNotification.java create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/browserNotifications/TemplatesNotification.java create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/InstallerConfigurationProcessor.java create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/JavaScriptLibraryInstallProcessor.java create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/Messages.java create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/PythonInstallProcessor.java create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/RubyInstallProcessor.java create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/VersionsConfigurationProcessor.java create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/XAMPPInstallProcessor.java create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/installer/InstallerOptionsDialog.java create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/installer/JavaScriptImporterOptionsDialog.java create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/messages.properties create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/processorDelegates/BaseVersionProcessor.java create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/processorDelegates/CachedVersionProcessorDelegate.java create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/processorDelegates/RailsVersionProcessor.java create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/processorDelegates/RubyVersionProcessor.java create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/processorDelegates/SQLiteVersionProcessor.java create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/extended/Activator.java create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/internal/command/NewProjectFromTemplateCommandHandler.java create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/internal/command/ShowStartPageCommandHandler.java create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/internal/command/ShowToolboxCommandHandler.java diff --git a/com.aptana.portal.ui.extended/.classpath b/com.aptana.portal.ui.extended/.classpath new file mode 100644 index 0000000000..eca7bdba8f --- /dev/null +++ b/com.aptana.portal.ui.extended/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/com.aptana.portal.ui.extended/.project b/com.aptana.portal.ui.extended/.project new file mode 100644 index 0000000000..a730ee2859 --- /dev/null +++ b/com.aptana.portal.ui.extended/.project @@ -0,0 +1,28 @@ + + + com.aptana.portal.ui.extended + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/com.aptana.portal.ui.extended/.settings/org.eclipse.jdt.core.prefs b/com.aptana.portal.ui.extended/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..0c68a61dca --- /dev/null +++ b/com.aptana.portal.ui.extended/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/com.aptana.portal.ui.extended/META-INF/MANIFEST.MF b/com.aptana.portal.ui.extended/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..7db376c48d --- /dev/null +++ b/com.aptana.portal.ui.extended/META-INF/MANIFEST.MF @@ -0,0 +1,13 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Core +Bundle-SymbolicName: com.aptana.portal.ui.extended +Bundle-Version: 1.0.0.qualifier +Bundle-Activator: com.aptana.portal.ui.extended.Activator +Bundle-Vendor: APTANA +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Bundle-ActivationPolicy: lazy +Export-Package: com.aptana.portal.ui.dispatch.configurationProcessors, + com.aptana.portal.ui.dispatch.configurationProcessors.installer diff --git a/com.aptana.portal.ui.extended/build.properties b/com.aptana.portal.ui.extended/build.properties new file mode 100644 index 0000000000..34d2e4d2da --- /dev/null +++ b/com.aptana.portal.ui.extended/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/actionControllers/TemplateActionController.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/actionControllers/TemplateActionController.java new file mode 100644 index 0000000000..903aa35621 --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/actionControllers/TemplateActionController.java @@ -0,0 +1,129 @@ +/** + * Aptana Studio + * Copyright (c) 2011 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). + * Please see the license.html included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ +package com.aptana.portal.ui.dispatch.actionControllers; + +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.aptana.configurations.processor.ConfigurationStatus; +import com.aptana.core.projects.templates.IProjectTemplate; +import com.aptana.core.projects.templates.TemplateType; +import com.aptana.core.util.ResourceUtil; +import com.aptana.core.util.StringUtil; +import com.aptana.jetty.util.epl.ajax.JSON; +import com.aptana.projects.ProjectsPlugin; + +/** + * Action controller for Template operations + * + * @author nle + */ +public class TemplateActionController extends AbstractActionController +{ + /** + * Template-Info enum. + */ + public static enum TEMPLATE_INFO + { + ID("id"), //$NON-NLS-1$ + NAME("name"), //$NON-NLS-1$ + DESCRIPTION("description"), //$NON-NLS-1$ + TEMPLATE_TYPE("type"), //$NON-NLS-1$ + IMAGE_URL("image"), //$NON-NLS-1$ + TAG("tag"); //$NON-NLS-1$ + + private String key; + + private TEMPLATE_INFO(String key) + { + this.key = key; + } + + public String toString() + { + return key; + } + }; + + private static final String[] ALL_TYPES = new String[] { TemplateType.PHP.name(), TemplateType.PYTHON.name(), + TemplateType.RAILS.name(), TemplateType.RUBY.name(), TemplateType.TITANIUM_DESKTOP.name(), + TemplateType.TITANIUM_MOBILE.name(), TemplateType.WEB.name() }; + + public void configurationStateChanged(ConfigurationStatus status, Set attributesChanged) + { + } + + /** + * Return the template types + * + * @return + */ + @ControllerAction + public Object getTemplateTypes() + { + return JSON.toString(ALL_TYPES); + } + + /** + * Return the template for give types + * + * @return + */ + @ControllerAction + public Object getTemplates(Object templateTypes) + { + List types = new ArrayList(); + if (!(templateTypes instanceof Object[]) || ((Object[]) templateTypes).length < 1) + { + templateTypes = ALL_TYPES; + } + + for (Object object : (Object[]) templateTypes) + { + if (object instanceof String) + { + TemplateType templateType = TemplateType.valueOf((String) object); + if (templateType != null) + { + types.add(templateType); + } + } + } + + List templates = ProjectsPlugin.getDefault().getTemplatesManager() + .getTemplates(types.toArray(new TemplateType[types.size()])); + List> templateObjects = new ArrayList>(); + + for (IProjectTemplate template : templates) + { + if (template.getId() == null || template.getId().length() == 0) + { + continue; + } + + Map properties = new HashMap(); + properties.put(TEMPLATE_INFO.ID.toString(), template.getId()); + properties.put(TEMPLATE_INFO.NAME.toString(), template.getDisplayName()); + properties.put(TEMPLATE_INFO.DESCRIPTION.toString(), template.getDescription()); + properties.put(TEMPLATE_INFO.TEMPLATE_TYPE.toString(), template.getType().name()); + if (template.getIconURL() != null) + { + URI iconPath = ResourceUtil.resourcePathToURI(template.getIconURL()); + properties.put(TEMPLATE_INFO.IMAGE_URL.toString(), iconPath.toASCIIString()); + } + properties.put(TEMPLATE_INFO.TAG.toString(), StringUtil.join(",", template.getTags())); //$NON-NLS-1$ + templateObjects.add(properties); + } + + return JSON.toString(templateObjects.toArray(new Map[templateObjects.size()])); + } +} diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/actionControllers/ThemeActionController.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/actionControllers/ThemeActionController.java new file mode 100644 index 0000000000..d47c243c0c --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/actionControllers/ThemeActionController.java @@ -0,0 +1,158 @@ +/** + * Aptana Studio + * Copyright (c) 2005-2012 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). + * Please see the license.html included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ +package com.aptana.portal.ui.dispatch.actionControllers; + +import java.text.MessageFormat; +import java.util.Set; + +import org.eclipse.e4.core.contexts.IEclipseContext; +import org.eclipse.e4.ui.css.swt.theme.ITheme; +import org.eclipse.e4.ui.css.swt.theme.IThemeEngine; +import org.eclipse.e4.ui.model.application.MApplication; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.PlatformUI; + +import com.aptana.configurations.processor.ConfigurationStatus; +import com.aptana.core.IFilter; +import com.aptana.core.logging.IdeLog; +import com.aptana.core.util.CollectionsUtil; +import com.aptana.core.util.StringUtil; +import com.aptana.jetty.util.epl.ajax.JSON; +import com.aptana.portal.ui.PortalUIPlugin; +import com.aptana.portal.ui.dispatch.IBrowserNotificationConstants; +import com.aptana.theme.IThemeManager; +import com.aptana.theme.Theme; +import com.aptana.theme.ThemePlugin; + +/** + * Action controller that provides Theme functionalities. + * + * @author Shalom Gibly + */ +public class ThemeActionController extends AbstractActionController +{ + private static final String UNKNOWN = "Unknown"; //$NON-NLS-1$ + private IThemeManager themeManager; + + public ThemeActionController() + { + themeManager = ThemePlugin.getDefault().getThemeManager(); + } + + // ############## Actions ############### + /** + * Returns a list of theme names. + * + *
+	 *   Sample JS code:
+	 *   result = dispatch($H({controller:'portal.themes', action:"getThemes"}).toJSON());
+	 * 
+ */ + @ControllerAction + public Object getThemes() + { + Set themeNames = themeManager.getThemeNames(); + return JSON.toString(themeNames.toArray(new String[themeNames.size()])); + } + + /** + * Returns the active theme name. + * + *
+	 *   Sample JS code:
+	 *   result = dispatch($H({controller:'portal.themes', action:"getActiveTheme"}).toJSON());
+	 * 
+ */ + @ControllerAction + public Object getActiveTheme() + { + Theme currentTheme = themeManager.getCurrentTheme(); + return JSON.toString(currentTheme != null ? currentTheme.getName() : UNKNOWN); + } + + /** + * Set the active theme. + * + *
+	 *   Sample JS code:
+	 *   result = dispatch($H({controller:'portal.themes', action:"setActiveTheme", args:["theme-name"]}).toJSON());
+	 * 
+ */ + @ControllerAction + public Object setActiveTheme(Object attributes) + { + final String themeName = getThemeName(attributes); + if (!StringUtil.isEmpty(themeName)) + { + // FIXME this is a bit of a hack, and assumes we'll have an editor and overall theme with the exact same name + // Set editor theme + Theme theme = themeManager.getTheme(themeName); + themeManager.setCurrentTheme(theme); + + // Also set overall theme + IWorkbench workbench = PlatformUI.getWorkbench(); + MApplication application = (MApplication) workbench.getService(MApplication.class); + IEclipseContext context = application.getContext(); + + IThemeEngine e4ThemeEngine = context.get(IThemeEngine.class); + ITheme selection = CollectionsUtil.find(e4ThemeEngine.getThemes(), new IFilter() + { + + public boolean include(ITheme item) + { + return themeName.equals(item.getLabel()); + } + }); + if (selection != null) + { + e4ThemeEngine.setTheme(selection, true); + } + return IBrowserNotificationConstants.JSON_OK; + } + return IBrowserNotificationConstants.JSON_ERROR; + } + + /* + * (non-Javadoc) + * @see com.aptana.configurations.processor.IConfigurationProcessorListener#configurationStateChanged(com.aptana. + * configurations.processor.ConfigurationStatus, java.util.Set) + */ + public void configurationStateChanged(ConfigurationStatus status, Set attributesChanged) + { + // Nothing to do here... + } + + /** + * Extracts a theme name from the given attributes, and returns a {@link Theme} instance that match it. + * + * @param attributes + * @return A {@link Theme}; null if there is an error, or there is not theme with the given name. + */ + private String getThemeName(Object attributes) + { + if (attributes instanceof Object[]) + { + Object[] arr = (Object[]) attributes; + if (arr.length == 1 && arr[0] != null) + { + return (String) arr[0]; + } + String message = MessageFormat + .format("Wrong argument count passed to ThemeActionController::setActiveTheme. Expected 1 and got {0}", arr.length); //$NON-NLS-1$ + IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(message)); + } + else + { + String message = MessageFormat + .format("Wrong argument type passed to ThemeActionController::setActiveTheme. Expected Object[] and got {0}", //$NON-NLS-1$ + ((attributes == null) ? "null" : attributes.getClass().getName())); //$NON-NLS-1$ + IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(message)); + } + return null; + } +} diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/actionControllers/messages.properties b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/actionControllers/messages.properties new file mode 100644 index 0000000000..726a98b69a --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/actionControllers/messages.properties @@ -0,0 +1,8 @@ +AbstractActionController_invocationError=An error occurred while trying to +GemsActionController_computingGemsJobName=Computing installed gems +ActionController_internalError=Internal Error +ConsoleController_devToolboxConsoleName=Dev Toolbox Console +PluginsActionController_computingInstalledPlugins=Computing installed plug-ins... +PluginsActionController_installNewSoftware=Install New Software... +InstallActionController_installing=Installing... +LaunchActionController_launchingJob=Launcing... diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/browserNotifications/AbstractBrowserNotification.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/browserNotifications/AbstractBrowserNotification.java new file mode 100644 index 0000000000..5f10d10100 --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/browserNotifications/AbstractBrowserNotification.java @@ -0,0 +1,128 @@ +/** + * Aptana Studio + * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). + * Please see the license.html included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ +package com.aptana.portal.ui.dispatch.browserNotifications; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.aptana.portal.ui.dispatch.BrowserNotifier; +import com.aptana.portal.ui.dispatch.IBrowserNotificationConstants; + +/** + * A base class for all browser notification classed. The BrowserNotification register itself as a listener to some + * eclipse event and then notify the target browser editors about any event that is occurring. The notification is done + * through the {@link BrowserNotifier} class. + * + * @author Shalom Gibly + */ +public abstract class AbstractBrowserNotification +{ + protected List notificationTargets; + protected boolean isListening; + + /** + * Constructor + */ + public AbstractBrowserNotification() + { + notificationTargets = new ArrayList(); + } + + /** + * Set the notification targets for this browser notification class. An asterisk (*) sign signals to notify all the + * opened registered browser-editors. + * + * @param targets + * A list of comma separated target ids. + */ + public void setNotificationTargets(String targets) + { + notificationTargets.clear(); + if (targets != null) + { + String[] ids = targets.split(", *"); //$NON-NLS-1$ + for (String id : ids) + { + id = id.trim(); + if (id.equals("*")) { //$NON-NLS-1$ + // in case we have an asterisk, the notification will go to all + // of the registered browser-editors. + notificationTargets.clear(); + break; + } + if (id.length() > 0) + { + notificationTargets.add(id); + } + } + } + } + + /** + * Returns a list of notification targets. An empty list signals that we need to notify any available registered + * browser editor. + * + * @return An unmodifiable notification targets list. + */ + public List getNotificationTargets() + { + return Collections.unmodifiableList(notificationTargets); + } + + /** + * Start this browser notifier. + */ + public abstract void start(); + + /** + * Stop this browser notifier. + */ + public abstract void stop(); + + /** + * Fire a notification for the registered notification targets with the eventId, type and data. + * + * @param eventId + * See {@link IBrowserNotificationConstants} + * @param eventType + * See {@link IBrowserNotificationConstants} + * @param data + * A JSON data (can be null) + * @see IBrowserNotificationConstants + */ + protected void notifyTargets(String eventId, String eventType, String data) + { + notifyTargets(eventId, eventType, data, false); + } + + /** + * Fire a notification for the registered notification targets with the eventId, type and data. + * + * @param eventId + * See {@link IBrowserNotificationConstants} + * @param eventType + * See {@link IBrowserNotificationConstants} + * @param data + * A JSON data (can be null) + * @param notifyInUIThread + * Indicate that the notification should be wrapped in a UI thread. + * @see IBrowserNotificationConstants + */ + protected void notifyTargets(String eventId, String eventType, String data, boolean notifyInUIThread) + { + if (notifyInUIThread) + { + BrowserNotifier.getInstance().notifyBrowserInUIThread(getNotificationTargets(), eventId, eventType, data); + } + else + { + BrowserNotifier.getInstance().notifyBrowser(getNotificationTargets(), eventId, eventType, data); + } + } +} diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/browserNotifications/BrowserNotificationProxy.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/browserNotifications/BrowserNotificationProxy.java new file mode 100644 index 0000000000..bbd9bee3e6 --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/browserNotifications/BrowserNotificationProxy.java @@ -0,0 +1,135 @@ +/** + * Appcelerator Titanium Studio + * Copyright (c) 2013 by Appcelerator, Inc. All Rights Reserved. + * Proprietary and Confidential - This source code is not for redistribution + */ + +package com.aptana.portal.ui.dispatch.browserNotifications; + +import java.util.Collections; +import java.util.List; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; + +import com.aptana.core.logging.IdeLog; +import com.aptana.portal.ui.PortalUIPlugin; + +/** + * Proxy class to the contributors of Browser notifications. + * + * @author pinnamuri + */ +public class BrowserNotificationProxy extends AbstractBrowserNotification +{ + + private IConfigurationElement element; + private AbstractBrowserNotification contributorClass; + private static final String ATT_CLASS = "class"; //$NON-NLS-1$ + private static final String ATT_NOTIFICATION_TARGET = "notificationTarget"; //$NON-NLS-1$ + + public BrowserNotificationProxy(IConfigurationElement element) + { + this.element = element; + } + + @Override + public void start() + { + try + { + loadElement(); + contributorClass.start(); + + } + catch (CoreException e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), e); + } + } + + @Override + public List getNotificationTargets() + { + try + { + loadElement(); + return contributorClass.getNotificationTargets(); + + } + catch (CoreException e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), e); + } + return Collections.emptyList(); + } + + @Override + public void setNotificationTargets(String targets) + { + try + { + loadElement(); + contributorClass.setNotificationTargets(targets); + } + catch (CoreException e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), e); + } + + } + + private synchronized void loadElement() throws CoreException + { + if (contributorClass == null) + { + contributorClass = (AbstractBrowserNotification) element.createExecutableExtension(ATT_CLASS); + contributorClass.setNotificationTargets(element.getAttribute(ATT_NOTIFICATION_TARGET)); + } + } + + @Override + protected void notifyTargets(String eventId, String eventType, String data) + { + try + { + loadElement(); + contributorClass.notifyTargets(eventId, eventType, data); + } + catch (CoreException e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), e); + } + } + + @Override + protected void notifyTargets(String eventId, String eventType, String data, boolean notifyInUIThread) + { + try + { + loadElement(); + contributorClass.notifyTargets(eventId, eventType, data, notifyInUIThread); + } + catch (CoreException e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), e); + } + + } + + @Override + public void stop() + { + try + { + loadElement(); + contributorClass.stop(); + + } + catch (CoreException e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), e); + } + } + +} diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/browserNotifications/ProjectCreationBrowserNotification.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/browserNotifications/ProjectCreationBrowserNotification.java new file mode 100644 index 0000000000..5814839c6c --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/browserNotifications/ProjectCreationBrowserNotification.java @@ -0,0 +1,67 @@ +/** + * Aptana Studio + * Copyright (c) 2012 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). + * Please see the license.html included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ + +package com.aptana.portal.ui.dispatch.browserNotifications; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.ui.progress.UIJob; + +import com.aptana.core.util.EclipseUtil; +import com.aptana.portal.ui.IPortalPreferences; +import com.aptana.portal.ui.PortalUIPlugin; +import com.aptana.portal.ui.dispatch.IBrowserNotificationConstants; + +/** + * A browser notification class that listens to the project creation events and notify those changes. + * + * @author pinnamuri + */ +public class ProjectCreationBrowserNotification extends AbstractBrowserNotification +{ + + private IPropertyChangeListener propertyListener = new IPropertyChangeListener() + { + public void propertyChange(PropertyChangeEvent event) + { + if (event.getProperty().equals(IPortalPreferences.RECENTLY_CREATED_PROJECT)) + { + Job job = new UIJob("Notifying project create event") //$NON-NLS-1$ + { + @Override + public IStatus runInUIThread(IProgressMonitor monitor) + { + // Notify the Portal's observers + notifyTargets(IBrowserNotificationConstants.EVENT_ID_PROJECT_CREATE, + IBrowserNotificationConstants.EVENT_TYPE_CHANGED, (String) null); + return Status.OK_STATUS; + } + }; + EclipseUtil.setSystemForJob(job); + job.schedule(); + } + } + }; + + @Override + public void start() + { + PortalUIPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(propertyListener); + } + + @Override + public void stop() + { + PortalUIPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(propertyListener); + } + +} diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/browserNotifications/RecentFilesBrowserNotification.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/browserNotifications/RecentFilesBrowserNotification.java new file mode 100644 index 0000000000..67c7b307de --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/browserNotifications/RecentFilesBrowserNotification.java @@ -0,0 +1,144 @@ +/** + * Aptana Studio + * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). + * Please see the license.html included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ +package com.aptana.portal.ui.dispatch.browserNotifications; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.ui.IPartListener; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.progress.UIJob; + +import com.aptana.core.util.EclipseUtil; +import com.aptana.portal.ui.PortalUIPlugin; +import com.aptana.portal.ui.dispatch.IBrowserNotificationConstants; + +/** + * A browser notification class that listens to the eclipse editors and notify about changes in the recently opened + * files history. + * + * @author Shalom Gibly + */ +public class RecentFilesBrowserNotification extends AbstractBrowserNotification +{ + private IPartListener partListener; + + /** + * Constructor. + */ + public RecentFilesBrowserNotification() + { + partListener = new PartListener(); + } + + /* + * (non-Javadoc) + * @see com.aptana.portal.dispatch.AbstractBrowserNotification#start() + */ + @Override + public void start() + { + isListening = true; + Job job = new UIJob("register RecentlyOpenedFilesFunction workspace listener") //$NON-NLS-1$ + { + @Override + public IStatus runInUIThread(IProgressMonitor monitor) + { + IWorkbenchWindow window = PortalUIPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow(); + if (window != null) + { + IWorkbenchPage activePage = window.getActivePage(); + if (activePage != null) + { + activePage.addPartListener(partListener); + } + } + return Status.OK_STATUS; + } + }; + EclipseUtil.setSystemForJob(job); + job.schedule(); + } + + /* + * (non-Javadoc) + * @see com.aptana.portal.dispatch.AbstractBrowserNotification#stop() + */ + @Override + public void stop() + { + isListening = false; + Job job = new UIJob("unregister RecentlyOpenedFilesFunction workspace listener") //$NON-NLS-1$ + { + @Override + public IStatus runInUIThread(IProgressMonitor monitor) + { + + IWorkbench workbench = PortalUIPlugin.getDefault().getWorkbench(); + if (!workbench.isClosing()) + { + IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); + if (window != null) + { + IWorkbenchPage activePage = window.getActivePage(); + if (activePage != null) + { + activePage.removePartListener(partListener); + } + } + } + return Status.OK_STATUS; + } + }; + EclipseUtil.setSystemForJob(job); + job.schedule(); + } + + /** + * Listen to the workbench part to trigger a browser update every time a new file is being opened. + */ + private class PartListener implements IPartListener + { + public void partActivated(IWorkbenchPart part) + { + } + + public void partBroughtToTop(IWorkbenchPart part) + { + } + + public void partClosed(IWorkbenchPart part) + { + } + + public void partDeactivated(IWorkbenchPart part) + { + } + + public void partOpened(IWorkbenchPart part) + { + if (!isListening) + { + IWorkbenchPage activePage = PortalUIPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow() + .getActivePage(); + if (activePage != null) + { + activePage.removePartListener(this); + } + return; + } + // Notify the Portal's observers + notifyTargets(IBrowserNotificationConstants.EVENT_ID_RECENT_FILES, + IBrowserNotificationConstants.EVENT_TYPE_CHANGED, (String) null); + } + } +} diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/browserNotifications/TemplatesNotification.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/browserNotifications/TemplatesNotification.java new file mode 100644 index 0000000000..ca2111bd18 --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/browserNotifications/TemplatesNotification.java @@ -0,0 +1,126 @@ +/** + * Aptana Studio + * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). + * Please see the license.html included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ +package com.aptana.portal.ui.dispatch.browserNotifications; + +import java.util.HashMap; +import java.util.Map; + +import com.aptana.jetty.util.epl.ajax.JSON; + +import com.aptana.core.logging.IdeLog; +import com.aptana.core.projects.templates.IProjectTemplate; +import com.aptana.portal.ui.IDebugScopes; +import com.aptana.portal.ui.dispatch.IBrowserNotificationConstants; +import com.aptana.portal.ui.dispatch.actionControllers.TemplateActionController.TEMPLATE_INFO; +import com.aptana.projects.ProjectsPlugin; +import com.aptana.projects.templates.IProjectTemplateListener; + +/** + * A class that notify the portal browser when a new template is loaded. + * + * @author Shalom Gibly + */ +public class TemplatesNotification extends AbstractBrowserNotification +{ + + private IProjectTemplateListener listener; + + /* + * (non-Javadoc) + * @see com.aptana.portal.ui.dispatch.browserNotifications.AbstractBrowserNotification#start() + */ + @Override + public synchronized void start() + { + isListening = true; + ProjectsPlugin.getDefault().getTemplatesManager().addListener(getListener()); + IdeLog.logInfo(ProjectsPlugin.getDefault(), "Template Portal notifier started", IDebugScopes.START_PAGE); //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * @see com.aptana.portal.ui.dispatch.browserNotifications.AbstractBrowserNotification#stop() + */ + @Override + public synchronized void stop() + { + isListening = false; + ProjectsPlugin.getDefault().getTemplatesManager().removeListener(getListener()); + listener = null; + IdeLog.logInfo(ProjectsPlugin.getDefault(), "Template Portal notifier stopped", IDebugScopes.START_PAGE); //$NON-NLS-1$ + } + + /** + * Notify a template addition + * + * @param template + */ + protected void notifyAdd(IProjectTemplate template) + { + IdeLog.logInfo(ProjectsPlugin.getDefault(), "Template added. Notifying portal...", IDebugScopes.START_PAGE); //$NON-NLS-1$ + notifyTargets(IBrowserNotificationConstants.EVENT_ID_TEMPLATES, IBrowserNotificationConstants.EVENT_TYPE_ADDED, + createTemplateInfo(template), true); + } + + /** + * Notify a template removal + * + * @param template + */ + protected void notifyRemoved(IProjectTemplate template) + { + IdeLog.logInfo(ProjectsPlugin.getDefault(), "Template removed. Notifying portal...", IDebugScopes.START_PAGE); //$NON-NLS-1$ + notifyTargets(IBrowserNotificationConstants.EVENT_ID_TEMPLATES, + IBrowserNotificationConstants.EVENT_TYPE_DELETED, createTemplateInfo(template), true); + } + + /** + * Create a JSON template info that will be send as the browser notification data. + * + * @param template + * @return A JSON representation of the template that was added or removed. + */ + protected String createTemplateInfo(IProjectTemplate template) + { + Map templateInfo = new HashMap(); + templateInfo.put(TEMPLATE_INFO.ID.toString(), template.getId()); + templateInfo.put(TEMPLATE_INFO.NAME.toString(), template.getDisplayName()); + templateInfo.put(TEMPLATE_INFO.DESCRIPTION.toString(), template.getDescription()); + templateInfo.put(TEMPLATE_INFO.TEMPLATE_TYPE.toString(), template.getType().name()); + return JSON.toString(templateInfo); + } + + /** + * @return an {@link IProjectTemplateListener} + */ + protected synchronized IProjectTemplateListener getListener() + { + if (listener == null) + { + listener = new IProjectTemplateListener() + { + public void templateAdded(IProjectTemplate template) + { + if (isListening) + { + notifyAdd(template); + } + } + + public void templateRemoved(IProjectTemplate template) + { + if (isListening) + { + notifyRemoved(template); + } + } + }; + } + return listener; + } +} diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/InstallerConfigurationProcessor.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/InstallerConfigurationProcessor.java new file mode 100644 index 0000000000..2e7041ae58 --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/InstallerConfigurationProcessor.java @@ -0,0 +1,286 @@ +/** + * Aptana Studio + * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). + * Please see the license.html included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ +package com.aptana.portal.ui.dispatch.configurationProcessors; + +import java.io.File; +import java.net.URI; +import java.net.URISyntaxException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.preference.IPreferenceStore; +import org.osgi.framework.Version; + +import com.aptana.configurations.processor.AbstractConfigurationProcessor; +import com.aptana.configurations.processor.ConfigurationStatus; +import com.aptana.core.logging.IdeLog; +import com.aptana.core.util.CollectionsUtil; +import com.aptana.core.util.InputStreamGobbler; +import com.aptana.core.util.StringUtil; +import com.aptana.core.util.VersionUtil; +import com.aptana.ide.core.io.downloader.DownloadManager; +import com.aptana.jetty.util.epl.ajax.JSON; +import com.aptana.portal.ui.IPortalPreferences; +import com.aptana.portal.ui.PortalUIPlugin; +import com.aptana.ui.util.UIUtils; + +/** + * Basic, abstract implementation, of a processor that deals with installing software. + * + * @author Shalom Gibly + */ +public abstract class InstallerConfigurationProcessor extends AbstractConfigurationProcessor +{ + protected static final String APTANA_PROPERTIES_FILE_NAME = ".aptana"; //$NON-NLS-1$ + protected static final String NAME_ATTRIBUTE = "name"; //$NON-NLS-1$ + protected static final String INSTALL_DIR_ATTRIBUTE = "install_dir"; //$NON-NLS-1$ + + protected List downloadedPaths; + + /* + * (non-Javadoc) + * @see com.aptana.configurations.processor.AbstractConfigurationProcessor#computeStatus(org.eclipse.core.runtime. + * IProgressMonitor, java.lang.Object) + */ + @Override + public ConfigurationStatus computeStatus(IProgressMonitor progressMonitor, Object attributes) + { + // This one does nothing. We should compute the status in the generic VersionsConfigurationProcessor + return configurationStatus; + } + + /** + * Returns the application's name. + * + * @return The application's name (e.g. XAMPP, Ruby) + */ + protected abstract String getApplicationName(); + + /** + * Download the remote content and store it the temp directory. + * + * @param URLs + * @param progressMonitor + */ + public IStatus download(String[] URLs, IProgressMonitor progressMonitor) + { + if (URLs.length == 0) + { + String err = Messages.InstallerConfigurationProcessor_missingDownloadTargets; + applyErrorAttributes(err); + IdeLog.logError(PortalUIPlugin.getDefault(), + "We expected an array of URLs, but got an empty array.", new Exception(err)); //$NON-NLS-1$ + return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, err); + } + downloadedPaths = null; + DownloadManager downloadManager = new DownloadManager(); + List urlsList = new ArrayList(URLs.length); + for (int i = 0; i < URLs.length; i++) + { + try + { + urlsList.add(new URI(urls[i])); + } + catch (URISyntaxException mue) + { + IdeLog.logError(PortalUIPlugin.getDefault(), mue); + } + } + try + { + downloadManager.addURIs(urlsList); + IStatus status = downloadManager.start(progressMonitor); + if (status.isOK()) + { + downloadedPaths = downloadManager.getContentsLocations(); + } + return status; + } + catch (Exception e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), e); + } + return Status.CANCEL_STATUS; + } + + /** + * Cache the installed application location and version in the preferences. + * + * @param installDir + * - The directory the application was installed to. + * @param versionedFileLocation + * - Can be the URL that we grabbed the installer from, or any other string that contains a version + * information in a form of x.y.z. + * @param appName + * - The application name (e.g. xampp) + */ + @SuppressWarnings("unchecked") + public void cacheVersion(String installDir, String versionedFileLocation, String appName) + + { + IPreferenceStore preferenceStore = PortalUIPlugin.getDefault().getPreferenceStore(); + String versions = preferenceStore.getString(IPortalPreferences.CACHED_VERSIONS_PROPERTY_NAME); + Map> versionsMap = null; + if (versions == null || versions.equals(StringUtil.EMPTY)) + { + versionsMap = new HashMap>(); + } + else + { + versionsMap = (Map>) JSON.parse(versions); + } + Map appVersionMap = new HashMap(); + Version version = VersionUtil.parseVersion(versionedFileLocation); + if (!VersionUtil.isEmpty(version)) + { + appVersionMap.put(IPortalPreferences.CACHED_VERSION_PROPERTY, version.toString()); + appVersionMap.put(IPortalPreferences.CACHED_LOCATION_PROPERTY, installDir); + versionsMap.put(appName.toLowerCase(), appVersionMap); + preferenceStore.setValue(IPortalPreferences.CACHED_VERSIONS_PROPERTY_NAME, JSON.toString(versionsMap)); + } + else + { + IdeLog.logError(PortalUIPlugin.getDefault(), MessageFormat.format( + "Could not cache the location and version for {0}. Install dir: {1}, versionedFileLocation: {2}", //$NON-NLS-1$ + appName, installDir, versionedFileLocation), new Exception()); + } + } + + /** + * Extract the given zip file into the target folder on a Windows machine. + * + * @param sfxZip + * Self extracting 7zip file. + * @param targetFolder + * @return The status of that extraction result. + */ + public static IStatus extractWin(IPath sfxZip, IPath targetFolder) + { + IStatus errorStatus = new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, + Messages.InstallerConfigurationProcessor_unableToExtractZip); + if (!Platform.OS_WIN32.equals(Platform.getOS())) + { + IdeLog.logError( + PortalUIPlugin.getDefault(), + "Unable to extract the Zip file. A Windows OS extractor was called for a non-Windows platform.", new Exception()); //$NON-NLS-1$ + return errorStatus; + } + if (sfxZip == null || targetFolder == null) + { + IdeLog.logError(PortalUIPlugin.getDefault(), "Undefined zip file or target folder", new Exception()); //$NON-NLS-1$ + return errorStatus; + } + File destinationFolder = targetFolder.toFile(); + if (!destinationFolder.exists() && !destinationFolder.mkdirs()) + { + IdeLog.logError(PortalUIPlugin.getDefault(), + "Failed to create destination directory " + destinationFolder, new Exception()); //$NON-NLS-1$ + return errorStatus; + } + // TODO Use ProcessUtil! + ProcessBuilder processBuilder = new ProcessBuilder(sfxZip.toOSString(), "-o" + targetFolder.toOSString(), //$NON-NLS-1$ + "-y", //$NON-NLS-1$ + sfxZip.toOSString()); + processBuilder.directory(destinationFolder); + processBuilder.redirectErrorStream(true); + String output = null; + try + { + Process process = processBuilder.start(); + InputStreamGobbler errorGobbler = new InputStreamGobbler(process.getErrorStream(), "\n", null); //$NON-NLS-1$ + InputStreamGobbler outputGobbler = new InputStreamGobbler(process.getInputStream(), "\n", null); //$NON-NLS-1$ + outputGobbler.start(); + errorGobbler.start(); + process.waitFor(); + outputGobbler.interrupt(); + errorGobbler.interrupt(); + outputGobbler.join(); + errorGobbler.join(); + output = outputGobbler.getResult(); + String errors = errorGobbler.getResult(); + int exitVal = process.exitValue(); + if (exitVal == 0) + { + return Status.OK_STATUS; + } + IdeLog.logError( + PortalUIPlugin.getDefault(), + "Zip extraction failed. The process returned " + exitVal, new Exception("Process output:\n" + errors)); //$NON-NLS-1$ //$NON-NLS-2$ + return errorStatus; + } + catch (Exception e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), e); + return errorStatus; + } + finally + { + if (output != null) + { + IdeLog.logInfo(PortalUIPlugin.getDefault(), output); + } + } + } + + /** + * Display a message dialog in a UI thread. + * + * @param kind + * See {@link MessageDialog} for the types allowed. + * @param title + * @param message + */ + public void displayMessageInUIThread(final int kind, final String title, final String message) + { + UIUtils.showMessageDialogFromBgThread(kind, title, message, null); + } + + /** + * Finalize the installation.
+ * This implementation just marks to delete on exit any downaloaded file. + * + * @param installDir + */ + protected void finalizeInstallation(String installDir) + { + deleteDownloadedPaths(); + // Cache the version and the location of the installed app. + // We assume here that the version of app is specified in the install URL! + if (installDir != null) + { + cacheVersion(installDir, urls[0], getApplicationName()); + } + } + + /** + * Mark the downloaded paths to be deleted on exit. + */ + protected void deleteDownloadedPaths() + { + if (!CollectionsUtil.isEmpty(downloadedPaths)) + { + for (IPath f : downloadedPaths) + { + File toDelete = f.toFile(); + if (toDelete.exists()) + { + toDelete.deleteOnExit(); + } + } + } + } +} diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/JavaScriptLibraryInstallProcessor.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/JavaScriptLibraryInstallProcessor.java new file mode 100644 index 0000000000..a27456518d --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/JavaScriptLibraryInstallProcessor.java @@ -0,0 +1,269 @@ +/** + * Aptana Studio + * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). + * Please see the license.html included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ +package com.aptana.portal.ui.dispatch.configurationProcessors; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.window.Window; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.progress.UIJob; + +import com.aptana.configurations.processor.ConfigurationStatus; +import com.aptana.core.logging.IdeLog; +import com.aptana.core.util.EclipseUtil; +import com.aptana.core.util.IOUtil; +import com.aptana.portal.ui.PortalUIPlugin; +import com.aptana.portal.ui.dispatch.configurationProcessors.installer.JavaScriptImporterOptionsDialog; + +/** + * An installer (import) processor for JavaScript libraries, such as jQuery and Prototype.
+ * This processor download and place the JS library under a custom javascript folder in the selected (or active) + * project. It also allows the use to select the location manually. + * + * @author Shalom Gibly + */ +public class JavaScriptLibraryInstallProcessor extends InstallerConfigurationProcessor +{ + private static final String JS_LIBRARY = "JS Library"; //$NON-NLS-1$ + private static boolean installationInProgress; + private String libraryName; + private IProject targetProject; + + /** + * Returns the JS Library name. + */ + @Override + protected String getApplicationName() + { + return libraryName; + } + + /** + * Install a JavaScript library into a user-specified project.
+ * The configuration will grab the name and the location of the library from the given attributes.
+ * We expect an array of attributes with the same structure described at {@link #loadAttributes(Object)}. + * + * @param attributes + * A non-empty string array, which contains the URLs for the JS library file(s) and an optional Map of + * additional attributes. + * @see com.aptana.configurations.processor.AbstractConfigurationProcessor#configure(org.eclipse.core.runtime.IProgressMonitor, + * java.lang.Object) + * @see #loadAttributes(Object) + */ + @Override + public ConfigurationStatus configure(IProgressMonitor progressMonitor, Object attributes) + { + // Get a Class lock to avoid multiple installations at the same time even with multiple instances of this + // RubyInstallProcessor + synchronized (this.getClass()) + { + if (installationInProgress) + { + return configurationStatus; + } + installationInProgress = true; + } + try + { + configurationStatus.removeAttribute(CONFIG_ATTR); + clearErrorAttributes(); + + // Load the installer's attributes + IStatus loadingStatus = loadAttributes(attributes); + if (!loadingStatus.isOK()) + { + String message = loadingStatus.getMessage(); + applyErrorAttributes(message); + IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(message)); + return configurationStatus; + } + + // Check that we got the expected single install URL + + if (urls.length == 0) + { + // structure error + String err = NLS.bind(Messages.InstallProcessor_wrongNumberOfInstallLinks, new Object[] { JS_LIBRARY, + 1, urls.length }); + applyErrorAttributes(err); + IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(err)); + return configurationStatus; + } + // Try to get the library name from the optional attributes. If it's not there, we log a warning and use a + // default one. + libraryName = attributesMap.get(NAME_ATTRIBUTE); + if (libraryName == null) + { + // just in case + libraryName = JS_LIBRARY; + IdeLog.logWarning(PortalUIPlugin.getDefault(), + "Expected a name attribute for the JS library, but got null."); //$NON-NLS-1$ + } + // Start the installation... + configurationStatus.setStatus(ConfigurationStatus.PROCESSING); + IStatus status = download(urls, progressMonitor); + if (status.isOK()) + { + status = install(progressMonitor); + } + switch (status.getSeverity()) + { + case IStatus.OK: + case IStatus.INFO: + case IStatus.WARNING: + displayMessageInUIThread(MessageDialog.INFORMATION, + NLS.bind(Messages.InstallProcessor_installerTitle, libraryName), + NLS.bind(Messages.InstallProcessor_installationSuccessful, libraryName)); + configurationStatus.setStatus(ConfigurationStatus.OK); + break; + case IStatus.ERROR: + configurationStatus.setStatus(ConfigurationStatus.ERROR); + break; + case IStatus.CANCEL: + configurationStatus.setStatus(ConfigurationStatus.INCOMPLETE); + break; + default: + configurationStatus.setStatus(ConfigurationStatus.UNKNOWN); + } + return configurationStatus; + } + finally + { + synchronized (this.getClass()) + { + installationInProgress = false; + } + } + } + + /** + * Install the library.
+ * The installation will display a selection dialog, displaying the projects in the workspace, and selecting the + * active project by default. It also takes into account the type of the project (nature) when suggesting the + * location to save the JS libraries. + * + * @param progressMonitor + * @return A status indication of the process success or failure. + */ + protected IStatus install(IProgressMonitor progressMonitor) + { + Job job = new UIJob(Messages.JSLibraryInstallProcessor_directorySelection) + { + @Override + public IStatus runInUIThread(IProgressMonitor monitor) + { + JavaScriptImporterOptionsDialog dialog = new JavaScriptImporterOptionsDialog(Display.getDefault() + .getActiveShell(), libraryName); + if (dialog.open() == Window.OK) + { + String selectedLocation = dialog.getSelectedLocation(); + IPath path = Path.fromOSString(selectedLocation); + targetProject = ResourcesPlugin.getWorkspace().getRoot().getProject(path.segment(0)); + // Making sure that the project is not null, although this should never happen + if (targetProject != null) + { + String fullPath = targetProject.getLocation().append(path.removeFirstSegments(1)).toOSString(); + File targetFolder = new File(fullPath); + if (!targetFolder.exists() && !targetFolder.mkdirs()) + { + // could not create the directories needed! + IdeLog.logError( + PortalUIPlugin.getDefault(), + "Failed to create directories when importing JS slibrary!", new Exception("Failed to create '" + fullPath + '\'')); //$NON-NLS-1$ //$NON-NLS-2$ + return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, + Messages.JSLibraryInstallProcessor_directoriesCreationFailed); + } + // Copy the downloaded content into the created directory + List errors = new ArrayList(); + for (IPath f : downloadedPaths) + { + try + { + File sourceLocation = f.toFile(); + File targetLocation = new File(targetFolder, sourceLocation.getName()); + if (targetLocation.exists()) + { + if (!MessageDialog.openQuestion( + Display.getDefault().getActiveShell(), + Messages.JSLibraryInstallProcessor_fileConflictTitle, + Messages.JSLibraryInstallProcessor_fileConflictMessage + + sourceLocation.getName() + + Messages.JSLibraryInstallProcessor_overwriteQuestion)) + { + continue; + } + } + IOUtil.copyFile(sourceLocation, targetLocation); + } + catch (IOException e) + { + errors.add(new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, e.getMessage(), e)); + } + } + if (!errors.isEmpty()) + { + return new MultiStatus(PortalUIPlugin.PLUGIN_ID, 0, errors.toArray(new IStatus[errors + .size()]), Messages.JSLibraryInstallProcessor_multipleErrorsWhileImportingJS, null); + } + // Since we don't cache the installed location for javascript libraries, we pass null here. This + // will only mark for deletion the downloaded content. + finalizeInstallation(null); + } + else + { + IdeLog.logError(PortalUIPlugin.getDefault(), + "Unexpected null project when importing a JS library!", new Exception()); //$NON-NLS-1$ + return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, + Messages.JSLibraryInstallProcessor_unexpectedNull); + } + try + { + targetProject.refreshLocal(IResource.DEPTH_INFINITE, SubMonitor.convert(monitor)); + } + catch (CoreException e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), "Error while refreshing the project.", e); //$NON-NLS-1$ + } + return Status.OK_STATUS; + } + else + { + return Status.CANCEL_STATUS; + } + } + }; + EclipseUtil.setSystemForJob(job); + job.schedule(); + try + { + job.join(); + } + catch (InterruptedException e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), e); + } + return job.getResult(); + } +} diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/Messages.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/Messages.java new file mode 100644 index 0000000000..e3f3a3b609 --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/Messages.java @@ -0,0 +1,96 @@ +/** + * Aptana Studio + * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). + * Please see the license.html included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ +package com.aptana.portal.ui.dispatch.configurationProcessors; + +import org.eclipse.osgi.util.NLS; + +public class Messages extends NLS +{ + + private static final String BUNDLE_NAME = "com.aptana.portal.ui.dispatch.configurationProcessors.messages"; //$NON-NLS-1$ + + public static String GemsConfigurationProcessor_errorInvokingGemList; + public static String GemsConfigurationProcessor_missingShellError; + public static String GemsConfigurationProcessor_wrongGemsRequest; + + public static String ImportJavaScriptLibraryDialog_emptyPathError; + public static String ImportJavaScriptLibraryDialog_folderSelectionDialogMessage; + public static String ImportJavaScriptLibraryDialog_folderSelectionDialogTitle; + public static String ImportJavaScriptLibraryDialog_invalidPathError; + public static String ImportJavaScriptLibraryDialog_locationLabel; + public static String ImportJavaScriptLibraryDialog_noAccessibleProjectsError; + public static String ImportJavaScriptLibraryDialog_projectLable; + public static String ImportJavaScriptLibraryDialog_useDefaultLocation; + public static String ImportJavaScriptLibraryDialog_wrongProjectRootError; + + public static String InstallerConfigurationProcessor_emptyURLsArrayError; + public static String InstallerConfigurationProcessor_expectedArrayError; + public static String InstallerConfigurationProcessor_expectedMapError; + public static String InstallerConfigurationProcessor_expectedURLsArrayError; + public static String InstallerConfigurationProcessor_unableToExtractZip; + + public static String InstallProcessor_couldNotLocateInstaller; + public static String InstallProcessor_corruptedZip; + public static String InstallProcessor_couldNotLocatePackage; + public static String InstallProcessor_errorWhileInstalling; + public static String InstallProcessor_extractingPackageTaskName; + public static String InstallProcessor_failedToInstallSeeLog; + public static String InstallProcessor_failedToInstall; + public static String InstallProcessor_failedToWrite; + public static String InstallProcessor_installationError_installDirMissing; + public static String InstallProcessor_installationErrorMessage; + public static String InstallProcessor_installationErrorTitle; + public static String InstallProcessor_installerGroupTitle; + public static String InstallProcessor_installerMessage; + public static String InstallProcessor_installerProgressInfo; + public static String InstallProcessor_installerShellTitle; + public static String InstallProcessor_installerTitle; + public static String InstallProcessor_extractingJobName; + public static String InstallProcessor_installingTaskName; + public static String InstallProcessor_executingTaskName; + public static String InstallProcessor_missingInstallURLs; + public static String InstallProcessor_installationSuccessful; + public static String InstallProcessor_installerJobName; + public static String InstallProcessor_seeErrorLog; + public static String InstallProcessor_updatingTaskName; + public static String InstallProcessor_InstallForAllUsers; + public static String InstallProcessor_wrongNumberOfInstallLinks; + + public static String InstallerConfigurationProcessor_missingAttributeMap; + public static String InstallerConfigurationProcessor_missingDownloadTargets; + public static String InstallerOptionsDialog_creatingDirectoriesErrorMessage; + public static String InstallerOptionsDialog_creatingDirectoriesErrorTitle; + public static String InstallerOptionsDialog_emptyPathError; + public static String InstallerOptionsDialog_inputDirectoryWillBeCreated; + public static String InstallerOptionsDialog_nonExistingPathError; + + public static String JSLibraryInstallProcessor_directoriesCreationFailed; + public static String JSLibraryInstallProcessor_directorySelection; + public static String JSLibraryInstallProcessor_fileConflictMessage; + public static String JSLibraryInstallProcessor_fileConflictTitle; + public static String JSLibraryInstallProcessor_multipleErrorsWhileImportingJS; + public static String JSLibraryInstallProcessor_overwriteQuestion; + public static String JSLibraryInstallProcessor_unexpectedNull; + + public static String InstallProcessor_aptanaInstallationComment; + public static String SystemConfigurationProcessor_missingConfigurationItems; + public static String SystemConfigurationProcessor_noShellCommandPath; + public static String SystemConfigurationProcessor_wrongConfigurationAttributesStructure; + public static String XAMPPInstallProcessor_executeXAMPPAutoSetup; + public static String XAMPPInstallProcessor_openXAMPPConsoleJobName; + + static + { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() + { + } +} diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/PythonInstallProcessor.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/PythonInstallProcessor.java new file mode 100644 index 0000000000..5b1843c5ba --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/PythonInstallProcessor.java @@ -0,0 +1,429 @@ +/** + * Aptana Studio + * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). + * Please see the license.html included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ +package com.aptana.portal.ui.dispatch.configurationProcessors; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.window.Window; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.progress.UIJob; + +import com.aptana.configurations.processor.ConfigurationStatus; +import com.aptana.core.logging.IdeLog; +import com.aptana.core.util.CollectionsUtil; +import com.aptana.ide.core.io.LockUtils; +import com.aptana.portal.ui.PortalUIPlugin; +import com.aptana.portal.ui.dispatch.configurationProcessors.installer.InstallerOptionsDialog; + +/** + * A Python install processor.
+ * This class is in charge of downloading and installing Python for Windows operating systems.
+ * Note: In case we decide to support something similar for MacOSX and Linux, this processor would probably need + * delegators set up. + * + * @author Shalom Gibly + */ +public class PythonInstallProcessor extends InstallerConfigurationProcessor +{ + protected static final String PYTHON_DEFAULT_INSTALL_DIR = "C:\\Python"; //$NON-NLS-1$ + protected static final String INSTALL_FOR_ALL_USERS_ATTR = "install_for_all"; //$NON-NLS-1$ + private static final String PYTHON = "Python"; //$NON-NLS-1$ + protected static final int PYTHON_INSTALLER_PROCESS_CANCEL_CODE = 1602; + private static boolean installationInProgress; + private String installDir; + + /** + * Install Python on the machine.
+ * The configuration will grab the installer from the given attributes.
+ * We expect an array of attributes with the same structure described at {@link #loadAttributes(Object)}. + * + * @param attributes + * First - A string array of size 1, which contains the URL for the Python installer (.exe). Second - + * (optional) map of additional attributes. + * @see com.aptana.configurations.processor.AbstractConfigurationProcessor#configure(org.eclipse.core.runtime.IProgressMonitor, + * java.lang.Object) + * @see #loadAttributes(Object) + */ + @Override + public ConfigurationStatus configure(IProgressMonitor progressMonitor, Object attributes) + { + // Get a Class lock to avoid multiple installations at the same time even with multiple instances of this + // processor + synchronized (this.getClass()) + { + if (installationInProgress) + { + return configurationStatus; + } + installationInProgress = true; + } + if (!Platform.OS_WIN32.equals(Platform.getOS())) + { + String err = "The Python installer processor is designed to work on Windows."; //$NON-NLS-1$ + IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(err)); + applyErrorAttributes(err); + installationInProgress = false; + return configurationStatus; + } + try + { + configurationStatus.removeAttribute(CONFIG_ATTR); + clearErrorAttributes(); + + // Load the installer's attributes + IStatus loadingStatus = loadAttributes(attributes); + if (!loadingStatus.isOK()) + { + String message = loadingStatus.getMessage(); + applyErrorAttributes(message); + IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(message)); + return configurationStatus; + } + + // Check that we got the expected single install URL + if (urls.length != 1) + { + // structure error + String err = NLS.bind(Messages.InstallProcessor_wrongNumberOfInstallLinks, new Object[] { PYTHON, 1, + urls.length }); + applyErrorAttributes(err); + IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(err)); + return configurationStatus; + } + // Try to get the default install directory from the optional attributes + installDir = attributesMap.get(INSTALL_DIR_ATTRIBUTE); + if (installDir == null) + { + installDir = PYTHON_DEFAULT_INSTALL_DIR; + } + // Start the installation... + configurationStatus.setStatus(ConfigurationStatus.PROCESSING); + IStatus status = download(urls, progressMonitor); + if (status.isOK()) + { + status = install(progressMonitor); + } + switch (status.getSeverity()) + { + case IStatus.OK: + case IStatus.INFO: + case IStatus.WARNING: + displayMessageInUIThread(MessageDialog.INFORMATION, + NLS.bind(Messages.InstallProcessor_installerTitle, PYTHON), + NLS.bind(Messages.InstallProcessor_installationSuccessful, PYTHON)); + configurationStatus.setStatus(ConfigurationStatus.OK); + break; + case IStatus.ERROR: + configurationStatus.setStatus(ConfigurationStatus.ERROR); + break; + case IStatus.CANCEL: + configurationStatus.setStatus(ConfigurationStatus.INCOMPLETE); + break; + default: + configurationStatus.setStatus(ConfigurationStatus.UNKNOWN); + } + return configurationStatus; + } + finally + { + synchronized (this.getClass()) + { + installationInProgress = false; + } + } + } + + /** + * Returns the application name. + * + * @return "PYTHON" + */ + protected String getApplicationName() + { + return PYTHON; + } + + /** + * Do the PYTHON installation. + * + * @param progressMonitor + * @return A status indication of the process success or failure. + */ + protected IStatus install(IProgressMonitor progressMonitor) + { + if (CollectionsUtil.isEmpty(downloadedPaths)) + { + String failureMessge = Messages.InstallProcessor_couldNotLocateInstaller; + String err = NLS.bind(Messages.InstallProcessor_failedToInstall, PYTHON); + displayMessageInUIThread(MessageDialog.ERROR, Messages.InstallProcessor_installationErrorTitle, err + ' ' + + failureMessge); + return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, err + ' ' + failureMessge); + } + SubMonitor subMonitor = SubMonitor.convert(progressMonitor, Messages.InstallProcessor_installerProgressInfo, + IProgressMonitor.UNKNOWN); + final Map installationAttributes = new HashMap(); + try + { + subMonitor.beginTask(NLS.bind(Messages.InstallProcessor_installingTaskName, PYTHON), + IProgressMonitor.UNKNOWN); + final String[] installDir = new String[1]; + Job installPythonDialog = new UIJob("Python installer options") //$NON-NLS-1$ + { + @Override + public IStatus runInUIThread(IProgressMonitor monitor) + { + PythonInstallerOptionsDialog dialog = new PythonInstallerOptionsDialog(); + if (dialog.open() == Window.OK) + { + installationAttributes.putAll(dialog.getAttributes()); + return Status.OK_STATUS; + } + return Status.CANCEL_STATUS; + } + }; + installPythonDialog.schedule(); + try + { + installPythonDialog.join(); + } + catch (InterruptedException e) + { + } + IStatus result = installPythonDialog.getResult(); + if (!result.isOK()) + { + return result; + } + + IStatus status = installPYTHON(installationAttributes); + if (!status.isOK()) + { + return status; + } + IdeLog.logInfo(PortalUIPlugin.getDefault(), MessageFormat.format( + "Successfully installed PYTHON into {0}. PYTHON installation completed.", installDir[0])); //$NON-NLS-1$ + // note that we called the finalizeInstallation from the installPYTHON Job. + return Status.OK_STATUS; + } + catch (Exception e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), "Error while installing PYTHON", e); //$NON-NLS-1$ + return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, NLS.bind( + Messages.InstallProcessor_errorWhileInstalling, PYTHON)); + } + finally + { + subMonitor.done(); + } + } + + /** + * Run the PYTHON installer and install XMAPP into the given directory. + * + * @param installationAttributes + * - Attributes map that contains the installation directory and a specification whether to run the + * PYTHON auto-install script. + * @return The status of this installation + */ + protected IStatus installPYTHON(final Map installationAttributes) + { + Job job = new Job(NLS.bind(Messages.InstallProcessor_installerJobName, PYTHON + ' ' + + Messages.InstallProcessor_installerGroupTitle)) + { + @Override + protected IStatus run(IProgressMonitor monitor) + { + try + { + // extract the values from the attributes: + String installDir = (String) installationAttributes.get(InstallerOptionsDialog.INSTALL_DIR_ATTR); + // This installer requires Windows path slashes style (backslashes) + installDir = installDir.replaceAll("/", "\\\\"); //$NON-NLS-1$ //$NON-NLS-2$ + + SubMonitor subMonitor = SubMonitor.convert(monitor, IProgressMonitor.UNKNOWN); + subMonitor.beginTask(NLS.bind(Messages.InstallProcessor_installingTaskName, PYTHON), + IProgressMonitor.UNKNOWN); + IdeLog.logInfo(PortalUIPlugin.getDefault(), "Installing Python into " + installDir); //$NON-NLS-1$ + + // Try to get a file lock first, before running the process. This file was just downloaded, so there + // is a chance it's still being held by the OS or by the downloader. + IStatus fileLockStatus = LockUtils.waitForLockRelease(downloadedPaths.get(0).toOSString(), 10000L); + if (!fileLockStatus.isOK()) + { + return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, NLS.bind( + Messages.InstallProcessor_failedToInstallSeeLog, PYTHON)); + } + // Run the Python installer, as specified in this link: + // http://www.python.org/download/releases/2.5/msi/ + List command = new ArrayList(4); + command.add("msiexec"); //$NON-NLS-1$ + command.add("/i"); //$NON-NLS-1$ + command.add(downloadedPaths.get(0).toOSString()); + command.add("/qr"); //$NON-NLS-1$ + command.add("TARGETDIR=\"" + installDir + '\"'); //$NON-NLS-1$ + if (Boolean.FALSE.toString().equals(attributesMap.get(INSTALL_FOR_ALL_USERS_ATTR))) + { + command.add("ALLUSERS=0"); //$NON-NLS-1$ + } + else + { + command.add("ALLUSERS=1"); //$NON-NLS-1$ + } + ProcessBuilder processBuilder = new ProcessBuilder(command); + Process process = processBuilder.start(); + int res = process.waitFor(); + if (res == PYTHON_INSTALLER_PROCESS_CANCEL_CODE) + { + IdeLog.logInfo(PortalUIPlugin.getDefault(), "Python installation cancelled"); //$NON-NLS-1$ + return Status.CANCEL_STATUS; + } + if (res != 0) + { + // We had an error while installing + IdeLog.logError( + PortalUIPlugin.getDefault(), + "Failed to install Python. The PYTHON installer process returned a termination code of " + res); //$NON-NLS-1$ + return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, res, NLS.bind( + Messages.InstallProcessor_installationErrorMessage, PYTHON, PYTHON), null); + } + else if (!new File(installDir).exists()) + { + // Just to be sure that we got everything in place + IdeLog.logError( + PortalUIPlugin.getDefault(), + "Failed to install Python. The " + installDir + " directory was not created", (Throwable) null); //$NON-NLS-1$ //$NON-NLS-2$ + return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, res, NLS.bind( + Messages.InstallProcessor_installationError_installDirMissing, PYTHON), null); + } + + finalizeInstallation(installDir); + return Status.OK_STATUS; + } + catch (Exception e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), e.getMessage(), e); + return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, NLS.bind( + Messages.InstallProcessor_failedToInstallSeeLog, PYTHON), e); + } + finally + { + monitor.done(); + } + } + }; + // Give it a little delay, just in case the downloader still holds on to the installer file. + job.schedule(1000); + try + { + job.join(); + } + catch (InterruptedException e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), e.getMessage(), e); + return Status.CANCEL_STATUS; + } + return job.getResult(); + } + + /** + * Finalize the installation by placing a .aptana file in the installed directory, specifying some properties. + * + * @param installDir + */ + protected void finalizeInstallation(String installDir) + { + super.finalizeInstallation(installDir); + File propertiesFile = new File(installDir, APTANA_PROPERTIES_FILE_NAME); + Properties properties = new Properties(); + properties.put("PYTHON_install", urls[0]); //$NON-NLS-1$ + FileOutputStream fileOutputStream = null; + try + { + fileOutputStream = new FileOutputStream(propertiesFile); + properties.store(fileOutputStream, NLS.bind(Messages.InstallProcessor_aptanaInstallationComment, PYTHON)); + } + catch (IOException e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), e); + } + finally + { + if (fileOutputStream != null) + { + try + { + fileOutputStream.flush(); + fileOutputStream.close(); + } + catch (IOException e) + { + } + } + } + } + + private class PythonInstallerOptionsDialog extends InstallerOptionsDialog + { + private Button installForAllUsersBt; + + public PythonInstallerOptionsDialog() + { + super(Display.getDefault().getActiveShell(), PYTHON); + setTitleImage(PortalUIPlugin.getDefault().getImageRegistry().get(PortalUIPlugin.PYTHON_IMAGE)); + } + + @Override + protected void setAttributes() + { + attributes.put(INSTALL_DIR_ATTR, installDir); + attributes.put(INSTALL_FOR_ALL_USERS_ATTR, Boolean.TRUE); + } + + /** + * Add the 'Auto-Setup' checkbox. + */ + @Override + protected Composite createInstallerGroupControls(Composite group) + { + Composite control = super.createInstallerGroupControls(group); + installForAllUsersBt = new Button(group, SWT.CHECK); + installForAllUsersBt.setText(Messages.InstallProcessor_InstallForAllUsers); + installForAllUsersBt.setSelection(true); + installForAllUsersBt.addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetSelected(SelectionEvent e) + { + attributes.put(INSTALL_FOR_ALL_USERS_ATTR, installForAllUsersBt.getSelection()); + } + }); + return control; + } + } +} \ No newline at end of file diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/RubyInstallProcessor.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/RubyInstallProcessor.java new file mode 100644 index 0000000000..a5c1fbbe80 --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/RubyInstallProcessor.java @@ -0,0 +1,391 @@ +/** + * Aptana Studio + * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). + * Please see the license.html included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ +package com.aptana.portal.ui.dispatch.configurationProcessors; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Properties; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.window.Window; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.progress.UIJob; + +import com.aptana.configurations.processor.ConfigurationStatus; +import com.aptana.core.logging.IdeLog; +import com.aptana.core.util.CollectionsUtil; +import com.aptana.ide.core.io.LockUtils; +import com.aptana.portal.ui.PortalUIPlugin; +import com.aptana.portal.ui.dispatch.configurationProcessors.installer.InstallerOptionsDialog; + +/** + * A Ruby install processor.
+ * This class is in charge of downloading and installing Ruby and DevKit for Windows operating systems.
+ * Note: In case we decide to support something similar for MacOSX and Linux, this processor would probably need + * delegators set up. + * + * @author Shalom Gibly + */ +public class RubyInstallProcessor extends InstallerConfigurationProcessor +{ + private static final String RUBY = "Ruby"; //$NON-NLS-1$ + protected static final String RUBY_DEFAULT_INSTALL_DIR = "C:\\Ruby"; //$NON-NLS-1$ + // The process return code for a Ruby installer cancel. + private static final int RUBY_INSTALLER_PROCESS_CANCEL = 5; + private static boolean installationInProgress; + + private String installDir; + + /** + * Install Ruby on the machine.
+ * The configuration will grab the installer and the DevKit from the given attributes.
+ * We expect an array of attributes with the same structure described at {@link #loadAttributes(Object)}. + * + * @param attributes + * An array of strings holding an optional attributes map and an array of rubyinstaller and the devkit + * URLs. + * @see com.aptana.configurations.processor.AbstractConfigurationProcessor#configure(org.eclipse.core.runtime.IProgressMonitor, + * java.lang.Object) + * @see #loadAttributes(Object) + */ + @Override + public ConfigurationStatus configure(IProgressMonitor progressMonitor, Object attributes) + { + // Get a Class lock to avoid multiple installations at the same time even with multiple instances of this + // RubyInstallProcessor + synchronized (this.getClass()) + { + if (installationInProgress) + { + return configurationStatus; + } + installationInProgress = true; + } + if (!Platform.OS_WIN32.equals(Platform.getOS())) + { + String err = "The Ruby installer processor is designed to work on Windows."; //$NON-NLS-1$ + IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(err)); + applyErrorAttributes(err); + installationInProgress = false; + return configurationStatus; + } + try + { + configurationStatus.removeAttribute(CONFIG_ATTR); + clearErrorAttributes(); + + // Load the installer's attributes + IStatus loadingStatus = loadAttributes(attributes); + if (!loadingStatus.isOK()) + { + String message = loadingStatus.getMessage(); + applyErrorAttributes(message); + IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(message)); + return configurationStatus; + } + + // Check that we got the expected two install URLs + // TODO - Once we place DevKit back again, this should hold a value of 2 URLs. + if (urls.length != 1) + { + // structure error + String err = NLS.bind(Messages.InstallProcessor_wrongNumberOfInstallLinks, new Object[] { RUBY, 1, + urls.length }); + applyErrorAttributes(err); + IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(err)); + return configurationStatus; + } + // Try to get the default install directory from the optional attributes + installDir = attributesMap.get(INSTALL_DIR_ATTRIBUTE); + if (installDir == null) + { + installDir = RUBY_DEFAULT_INSTALL_DIR; + } + // Start the installation... + configurationStatus.setStatus(ConfigurationStatus.PROCESSING); + IStatus status = download(urls, progressMonitor); + if (status.isOK()) + { + status = install(progressMonitor); + } + switch (status.getSeverity()) + { + case IStatus.OK: + case IStatus.INFO: + case IStatus.WARNING: + displayMessageInUIThread(MessageDialog.INFORMATION, + NLS.bind(Messages.InstallProcessor_installerTitle, RUBY), + NLS.bind(Messages.InstallProcessor_installationSuccessful, RUBY)); + configurationStatus.setStatus(ConfigurationStatus.OK); + break; + case IStatus.ERROR: + configurationStatus.setStatus(ConfigurationStatus.ERROR); + break; + case IStatus.CANCEL: + configurationStatus.setStatus(ConfigurationStatus.INCOMPLETE); + break; + default: + configurationStatus.setStatus(ConfigurationStatus.UNKNOWN); + } + return configurationStatus; + } + finally + { + synchronized (this.getClass()) + { + installationInProgress = false; + } + } + } + + /** + * Returns the application name. + * + * @return "Ruby" + */ + protected String getApplicationName() + { + return RUBY; + } + + /** + * Install Ruby and DevKit. + * + * @param progressMonitor + * @return + */ + protected IStatus install(IProgressMonitor progressMonitor) + { + if (CollectionsUtil.isEmpty(downloadedPaths) || CollectionsUtil.getFirstElement(downloadedPaths) == null) + { + String failureMessge = Messages.InstallProcessor_couldNotLocateInstaller; + String err = NLS.bind(Messages.InstallProcessor_failedToInstall, RUBY); + displayMessageInUIThread(MessageDialog.ERROR, Messages.InstallProcessor_installationErrorTitle, err + ' ' + + failureMessge); + return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, err + ' ' + failureMessge); + } + SubMonitor subMonitor = SubMonitor.convert(progressMonitor, Messages.InstallProcessor_installerProgressInfo, + IProgressMonitor.UNKNOWN); + try + { + subMonitor + .beginTask(NLS.bind(Messages.InstallProcessor_installingTaskName, RUBY), IProgressMonitor.UNKNOWN); + final IPath[] installDir = new IPath[1]; + Job installRubyDialog = new UIJob("Ruby installer options") //$NON-NLS-1$ + { + @Override + public IStatus runInUIThread(IProgressMonitor monitor) + { + RubyInstallerOptionsDialog dialog = new RubyInstallerOptionsDialog(); + if (dialog.open() == Window.OK) + { + installDir[0] = Path.fromOSString(dialog.getInstallDir()); + return Status.OK_STATUS; + } + return Status.CANCEL_STATUS; + } + }; + installRubyDialog.schedule(); + try + { + installRubyDialog.join(); + } + catch (InterruptedException e) + { + } + IStatus result = installRubyDialog.getResult(); + if (!result.isOK()) + { + return result; + } + + IStatus status = installRuby(installDir[0]); + if (!status.isOK()) + { + return status; + } + IdeLog.logInfo(PortalUIPlugin.getDefault(), "Successfully installed Ruby into " + installDir[0]); //$NON-NLS-1$ + finalizeInstallation(installDir[0]); + return Status.OK_STATUS; + } + catch (Exception e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), "Error while installing Ruby", e); //$NON-NLS-1$ + return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, NLS.bind( + Messages.InstallProcessor_errorWhileInstalling, RUBY)); + } + finally + { + subMonitor.done(); + } + } + + /** + * Run the Ruby installer and install Ruby into the given directory. + * + * @param installDir + * @return The status of this installation + */ + protected IStatus installRuby(final IPath installDir) + { + Job job = new Job(NLS.bind(Messages.InstallProcessor_installerJobName, RUBY + ' ' + + Messages.InstallProcessor_installerGroupTitle)) + { + @Override + protected IStatus run(IProgressMonitor monitor) + { + try + { + SubMonitor subMonitor = SubMonitor.convert(monitor, IProgressMonitor.UNKNOWN); + subMonitor.beginTask(NLS.bind(Messages.InstallProcessor_installingTaskName, RUBY), + IProgressMonitor.UNKNOWN); + IdeLog.logInfo(PortalUIPlugin.getDefault(), "Installing Ruby into " + installDir); //$NON-NLS-1$ + + // Try to get a file lock first, before running the process. This file was just downloaded, so there + // is a chance it's still being held by the OS or by the downloader. + IPath downloadPath = downloadedPaths.get(0); + IStatus fileLockStatus = LockUtils.waitForLockRelease(downloadPath.toOSString(), 10000L); + if (!fileLockStatus.isOK()) + { + return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, NLS.bind( + Messages.InstallProcessor_failedToInstallSeeLog, RUBY)); + } + + ProcessBuilder processBuilder = new ProcessBuilder(downloadPath.toOSString(), + "/silent", "/dir=\"" + installDir.toOSString() + "\"", "/tasks=\"modpath\""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + Process process = processBuilder.start(); + int res = process.waitFor(); + if (res == RUBY_INSTALLER_PROCESS_CANCEL) + { + IdeLog.logInfo(PortalUIPlugin.getDefault(), "Ruby installation cancelled"); //$NON-NLS-1$ + return Status.CANCEL_STATUS; + } + if (res != 0) + { + // We had an error while installing + IdeLog.logError( + PortalUIPlugin.getDefault(), + "Failed to install Ruby. The ruby installer process returned a termination code of " + res); //$NON-NLS-1$ + return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, res, NLS.bind( + Messages.InstallProcessor_installationErrorMessage, RUBY, RUBY), null); + } + else if (!installDir.toFile().exists()) + { + // Just to be sure that we got everything in place + IdeLog.logError(PortalUIPlugin.getDefault(), + "Failed to install Ruby. The " + installDir + " directory was not created"); //$NON-NLS-1$ //$NON-NLS-2$ + return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, res, NLS.bind( + Messages.InstallProcessor_installationError_installDirMissing, RUBY), null); + } + return Status.OK_STATUS; + } + catch (Exception e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), e); + return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, NLS.bind( + Messages.InstallProcessor_failedToInstallSeeLog, RUBY), e); + } + finally + { + monitor.done(); + } + } + }; + // Give it a little delay, just in case the downloader still holds on to the rubyinstaller file. + job.schedule(1000); + try + { + job.join(); + } + catch (InterruptedException e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), e.getMessage(), e); + return Status.CANCEL_STATUS; + } + return job.getResult(); + } + + /** + * Finalize the installation by placing a .aptana file in the installed directory, specifying some properties. + * + * @param installDir + */ + protected void finalizeInstallation(IPath installDir) + { + super.finalizeInstallation(installDir.toOSString()); + File propertiesFile = installDir.append(APTANA_PROPERTIES_FILE_NAME).toFile(); + Properties properties = new Properties(); + properties.put("ruby_install", urls[0]); //$NON-NLS-1$ + FileOutputStream fileOutputStream = null; + try + { + fileOutputStream = new FileOutputStream(propertiesFile); + properties.store(fileOutputStream, + NLS.bind(Messages.InstallProcessor_aptanaInstallationComment, "Ruby & DevKit")); //$NON-NLS-1$ + } + catch (IOException e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), e); + } + finally + { + if (fileOutputStream != null) + { + try + { + fileOutputStream.flush(); + fileOutputStream.close(); + } + catch (IOException e) + { + } + } + } + } + + /** + * Ruby installer dialog.
+ * This dialog only asks for the install directory. + * + * @author Shalom Gibly + */ + private class RubyInstallerOptionsDialog extends InstallerOptionsDialog + { + public RubyInstallerOptionsDialog() + { + super(Display.getDefault().getActiveShell(), RUBY); + setTitleImage(PortalUIPlugin.getDefault().getImageRegistry().get(PortalUIPlugin.RUBY_IMAGE)); + } + + /** + * Returns the installation dir selected in the text field. + * + * @return the installation directory + */ + public String getInstallDir() + { + return attributes.get(INSTALL_DIR_ATTR).toString(); + } + + @Override + protected void setAttributes() + { + attributes.put(INSTALL_DIR_ATTR, installDir); + } + } +} diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/VersionsConfigurationProcessor.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/VersionsConfigurationProcessor.java new file mode 100644 index 0000000000..5fbc0623ab --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/VersionsConfigurationProcessor.java @@ -0,0 +1,207 @@ +/** + * Aptana Studio + * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). + * Please see the license.html included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ +package com.aptana.portal.ui.dispatch.configurationProcessors; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.preferences.IPreferencesService; +import com.aptana.jetty.util.epl.ajax.JSON; +import org.osgi.framework.Version; + +import com.aptana.configurations.processor.AbstractConfigurationProcessor; +import com.aptana.configurations.processor.ConfigurationProcessorsRegistry; +import com.aptana.configurations.processor.ConfigurationStatus; +import com.aptana.configurations.processor.IConfigurationProcessorDelegate; +import com.aptana.core.logging.IdeLog; +import com.aptana.core.util.VersionUtil; +import com.aptana.explorer.ExplorerPlugin; +import com.aptana.explorer.IPreferenceConstants; +import com.aptana.portal.ui.PortalUIPlugin; +import com.aptana.portal.ui.dispatch.processorDelegates.CachedVersionProcessorDelegate; + +/** + * A configuration processor that can identify the versions of some specific applications. The supported applications + * are: + *
    + *
  • ruby
  • + *
  • rails
  • + *
  • git
  • + *
  • sqlite3
  • + *
+ * + * @author Shalom Gibly + */ +public class VersionsConfigurationProcessor extends AbstractConfigurationProcessor +{ + /** + * Compute the versions of the given items in the attributes instance. Items that are not in the supported list of + * programs are set to an 'unknown' state, just as they are not installed.
+ * The computation expects an attributes array with three items - (this + * specific call don't use the installer-URL, but it needs to be there for the Portal's functionalities) + */ + @Override + public ConfigurationStatus computeStatus(IProgressMonitor progressMonitor, Object attributes) + { + configurationStatus.removeAttribute(CONFIG_ATTR); + clearErrorAttributes(); + if (attributes == null || !(attributes instanceof Object[])) + { + String message = Messages.SystemConfigurationProcessor_missingConfigurationItems; + applyErrorAttributes(message); + IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(message)); + return configurationStatus; + } + // Place the array values into a hash. + Object[] attrArray = (Object[]) attributes; + Map attrItems = new HashMap(); + for (Object itemDef : attrArray) + { + Object[] def = null; + if (!(itemDef instanceof Object[]) || (def = (Object[]) itemDef).length != 3) + { + String message = Messages.SystemConfigurationProcessor_wrongConfigurationAttributesStructure; + applyErrorAttributes(message); + IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(message)); + return configurationStatus; + } + // We only use the first two arguments. The third is the installation site URL. + attrItems.put((String) def[0], (String) def[1]); + } + // Do the actual processing + configurationStatus.setStatus(ConfigurationStatus.PROCESSING); + + // For each requested element, check that the item has a processor delegate. + // If it's there, execute the delegate. If not, set the item's state as unknown. + Map> itemsData = new HashMap>(); + String[] apps = attrItems.keySet().toArray(new String[attrItems.size()]); + // This processor should have delegators that do the actual processing of the versions. + // Load the delegators into a new set that we can manipulate. + Map processorDelegators = getVersionDelegators(apps); + for (String app : apps) + { + if (!processorDelegators.containsKey(app)) + { + // We'll deal with these later + continue; + } + IConfigurationProcessorDelegate delegate = processorDelegators.get(app); + Object commandResult = delegate.runCommand(IConfigurationProcessorDelegate.VERSION_COMMAND, + getActiveWorkingDir()); + if (commandResult != null) + { + Version version = VersionUtil.parseVersion(commandResult.toString()); + if (!VersionUtil.isEmpty(version)) + { + Version minVersion = VersionUtil.parseVersion(attrItems.get(app)); + String compatibility = (version.compareTo(minVersion) >= 0) ? COMPATIBILITY_OK + : COMPATIBILITY_UPDATE; + Map versionInfo = new HashMap(4); + versionInfo.put(ITEM_EXISTS, YES); + versionInfo.put(ITEM_VERSION, version.toString()); + versionInfo.put(ITEM_COMPATIBILITY, compatibility); + versionInfo.put(ITEM_VERSION_OUTPUT, commandResult.toString()); + itemsData.put(app, versionInfo); + // Remove the name from the original map. Eventually, we will be left with the items we could not + // locate in the system + attrItems.remove(app); + } + } + } + // Traverse what we have left in the original map that was created from the attributes and mark all plug-ins as + // 'missing' + Set missingItems = attrItems.keySet(); + for (String item : missingItems) + { + Map versionInfo = new HashMap(4); + versionInfo.put(ITEM_EXISTS, NO); + itemsData.put(item, versionInfo); + } + + // Finally, set the bundle data status into the configuration attribute + configurationStatus.setAttribute(CONFIG_ATTR, JSON.toString(itemsData)); + + configurationStatus.setStatus(ConfigurationStatus.OK); + return configurationStatus; + } + + @Override + public ConfigurationStatus configure(IProgressMonitor progressMonitor, Object attributes) + { + // TODO: Shalom - Right now we do not install directly, but pointing to installation instructions. + return configurationStatus; + } + + /* + * Return only the delegators that supports an application from the apps list and supports the VERSION_COMMAND. This + * method returns a map of delegator supported application name to delegator instance. + */ + private Map getVersionDelegators(String[] apps) + { + Set appsSet = new HashSet(); + for (String app : apps) + { + appsSet.add(app); + } + Set allDelegators = ConfigurationProcessorsRegistry.getInstance() + .getProcessorDelegators(getID()); + Map delegators = new HashMap(); + for (IConfigurationProcessorDelegate delegate : allDelegators) + { + if (appsSet.contains(delegate.getSupportedApplication()) + && delegate.getSupportedCommands().contains(IConfigurationProcessorDelegate.VERSION_COMMAND)) + { + delegators.put(delegate.getSupportedApplication(), delegate); + // Remove the item from the list, so that at the end of this loop we will end up with all the apps that + // did not match to any version delegate. + appsSet.remove(delegate.getSupportedApplication()); + } + } + + // For every app that does not have a delegate, add a special delegate that will use the preferences to try to + // find out the version. + for (String app : appsSet) + { + delegators.put(app, new CachedVersionProcessorDelegate(app)); + } + + return delegators; + } + + /** + * Returns the active working directory according to the last active project in the Project Explorer.
+ * The value is taken from the preferences, therefore, this method can also return null if it fails. + * + * @return The active project's working directory (can be null) + */ + protected IPath getActiveWorkingDir() + { + // FIXME - Shalom: Test is. This might not work after the latest changes to the way we save the active project + IPreferencesService preferencesService = Platform.getPreferencesService(); + String activeProjectName = preferencesService.getString(ExplorerPlugin.PLUGIN_ID, + IPreferenceConstants.ACTIVE_PROJECT, null, null); + IProject result = null; + + if (activeProjectName != null) + { + result = ResourcesPlugin.getWorkspace().getRoot().getProject(activeProjectName); + } + if (result == null) + { + return null; + } + return result.getLocation(); + } +} diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/XAMPPInstallProcessor.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/XAMPPInstallProcessor.java new file mode 100644 index 0000000000..c71773b03f --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/XAMPPInstallProcessor.java @@ -0,0 +1,487 @@ +/** + * Aptana Studio + * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). + * Please see the license.html included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ +package com.aptana.portal.ui.dispatch.configurationProcessors; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.window.Window; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.progress.UIJob; + +import com.aptana.configurations.processor.ConfigurationStatus; +import com.aptana.core.logging.IdeLog; +import com.aptana.core.util.CollectionsUtil; +import com.aptana.ide.core.io.LockUtils; +import com.aptana.portal.ui.PortalUIPlugin; +import com.aptana.portal.ui.dispatch.configurationProcessors.installer.InstallerOptionsDialog; + +/** + * A XAMPP install processor.
+ * This class is in charge of downloading and installing XAMPP for Windows operating systems.
+ * Note: In case we decide to support something similar for MacOSX and Linux, this processor would probably need + * delegators set up. + * + * @author Shalom Gibly + */ +public class XAMPPInstallProcessor extends InstallerConfigurationProcessor +{ + protected static final String XAMPP_DEFAULT_INSTALL_DIR = "C:\\"; //$NON-NLS-1$ + protected static final String EXECUTE_SETUP_SCRIPT_ATTR = "execute_setup_script"; //$NON-NLS-1$ + private static final String XAMPP_DEFAULT_FOLDER = "xampp\\"; //$NON-NLS-1$ + private static final String XAMPP_CONTROL = "xampp-control.exe"; //$NON-NLS-1$ + private static final String XAMPP = "XAMPP"; //$NON-NLS-1$ + protected static final int XAMPP_INSTALLER_PROCESS_CANCEL_CODE = 255; + private static boolean installationInProgress; + private String installDir; + + /** + * Install XAMPP on the machine.
+ * The configuration will grab the installer from the given attributes.
+ * We expect an array of attributes with the same structure described at {@link #loadAttributes(Object)}. + * + * @param attributes + * First - A string array of size 1, which contains the URL for the XAMPP installer (.exe). Second - + * (optional) map of additional attributes. + * @see com.aptana.configurations.processor.AbstractConfigurationProcessor#configure(org.eclipse.core.runtime.IProgressMonitor, + * java.lang.Object) + * @see #loadAttributes(Object) + */ + @Override + public ConfigurationStatus configure(IProgressMonitor progressMonitor, Object attributes) + { + // Get a Class lock to avoid multiple installations at the same time even with multiple instances of this + // RubyInstallProcessor + synchronized (this.getClass()) + { + if (installationInProgress) + { + return configurationStatus; + } + installationInProgress = true; + } + if (!Platform.OS_WIN32.equals(Platform.getOS())) + { + String err = "The XAMPP installer processor is designed to work on Windows."; //$NON-NLS-1$ + IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(err)); + applyErrorAttributes(err); + installationInProgress = false; + return configurationStatus; + } + try + { + configurationStatus.removeAttribute(CONFIG_ATTR); + clearErrorAttributes(); + + // Load the installer's attributes + IStatus loadingStatus = loadAttributes(attributes); + if (!loadingStatus.isOK()) + { + String message = loadingStatus.getMessage(); + applyErrorAttributes(message); + IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(message)); + return configurationStatus; + } + + // Check that we got the expected single install URL + if (urls.length != 1) + { + // structure error + String err = NLS.bind(Messages.InstallProcessor_wrongNumberOfInstallLinks, new Object[] { XAMPP, 1, + urls.length }); + applyErrorAttributes(err); + IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(err)); + return configurationStatus; + } + // Try to get the default install directory from the optional attributes + installDir = attributesMap.get(INSTALL_DIR_ATTRIBUTE); + if (installDir == null) + { + installDir = XAMPP_DEFAULT_INSTALL_DIR; + } + // Start the installation... + configurationStatus.setStatus(ConfigurationStatus.PROCESSING); + IStatus status = download(urls, progressMonitor); + if (status.isOK()) + { + status = install(progressMonitor); + } + switch (status.getSeverity()) + { + case IStatus.OK: + case IStatus.INFO: + case IStatus.WARNING: + displayMessageInUIThread(MessageDialog.INFORMATION, + NLS.bind(Messages.InstallProcessor_installerTitle, XAMPP), + NLS.bind(Messages.InstallProcessor_installationSuccessful, XAMPP)); + configurationStatus.setStatus(ConfigurationStatus.OK); + break; + case IStatus.ERROR: + configurationStatus.setStatus(ConfigurationStatus.ERROR); + break; + case IStatus.CANCEL: + configurationStatus.setStatus(ConfigurationStatus.INCOMPLETE); + break; + default: + configurationStatus.setStatus(ConfigurationStatus.UNKNOWN); + } + return configurationStatus; + } + finally + { + synchronized (this.getClass()) + { + installationInProgress = false; + } + } + } + + /** + * Returns the application name. + * + * @return "XAMPP" + */ + protected String getApplicationName() + { + return XAMPP; + } + + /** + * Do the XAMPP installation. + * + * @param progressMonitor + * @return A status indication of the process success or failure. + */ + protected IStatus install(IProgressMonitor progressMonitor) + { + if (CollectionsUtil.isEmpty(downloadedPaths) || CollectionsUtil.getFirstElement(downloadedPaths) == null) + { + String failureMessge = Messages.InstallProcessor_couldNotLocateInstaller; + String err = NLS.bind(Messages.InstallProcessor_failedToInstall, XAMPP); + displayMessageInUIThread(MessageDialog.ERROR, Messages.InstallProcessor_installationErrorTitle, err + ' ' + + failureMessge); + return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, err + ' ' + failureMessge); + } + SubMonitor subMonitor = SubMonitor.convert(progressMonitor, Messages.InstallProcessor_installerProgressInfo, + IProgressMonitor.UNKNOWN); + final Map installationAttributes = new HashMap(); + try + { + subMonitor.beginTask(NLS.bind(Messages.InstallProcessor_installingTaskName, XAMPP), + IProgressMonitor.UNKNOWN); + final String[] installDir = new String[1]; + Job installXAMPPDialog = new UIJob("XAMPP installer options") //$NON-NLS-1$ + { + @Override + public IStatus runInUIThread(IProgressMonitor monitor) + { + XAMPPInstallerOptionsDialog dialog = new XAMPPInstallerOptionsDialog(); + if (dialog.open() == Window.OK) + { + installationAttributes.putAll(dialog.getAttributes()); + return Status.OK_STATUS; + } + return Status.CANCEL_STATUS; + } + }; + installXAMPPDialog.schedule(); + try + { + installXAMPPDialog.join(); + } + catch (InterruptedException e) + { + } + IStatus result = installXAMPPDialog.getResult(); + if (!result.isOK()) + { + return result; + } + + IStatus status = installXAMPP(installationAttributes); + if (!status.isOK()) + { + return status; + } + IdeLog.logInfo(PortalUIPlugin.getDefault(), + "Successfully installed XAMPP into " + installDir[0] + ". XAMPP installation completed."); //$NON-NLS-1$ //$NON-NLS-2$ + // note that we called the finalizeInstallation from the installXAMPP Job. + return Status.OK_STATUS; + } + catch (Exception e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), "Error while installing XAMPP", e); //$NON-NLS-1$ + return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, NLS.bind( + Messages.InstallProcessor_errorWhileInstalling, XAMPP)); + } + finally + { + subMonitor.done(); + } + } + + /** + * Run the XAMPP installer and install XMAPP into the given directory. + * + * @param installationAttributes + * - Attributes map that contains the installation directory and a specification whether to run the XAMPP + * auto-install script. + * @return The status of this installation + */ + protected IStatus installXAMPP(final Map installationAttributes) + { + Job job = new Job(NLS.bind(Messages.InstallProcessor_installerJobName, XAMPP + ' ' + + Messages.InstallProcessor_installerGroupTitle)) + { + @Override + protected IStatus run(IProgressMonitor monitor) + { + try + { + // extract the values from the attributes: + String installDir = (String) installationAttributes.get(InstallerOptionsDialog.INSTALL_DIR_ATTR); + boolean runAutoInstallScript = (Boolean) installationAttributes.get(EXECUTE_SETUP_SCRIPT_ATTR); + + SubMonitor subMonitor = SubMonitor.convert(monitor, IProgressMonitor.UNKNOWN); + subMonitor.beginTask(NLS.bind(Messages.InstallProcessor_installingTaskName, XAMPP), + IProgressMonitor.UNKNOWN); + IdeLog.logInfo(PortalUIPlugin.getDefault(), "Installing XAMPP into " + installDir); //$NON-NLS-1$ + + // Try to get a file lock first, before running the process. This file was just downloaded, so there + // is a chance it's still being held by the OS or by the downloader. + IPath downloadPath = downloadedPaths.get(0); + IStatus fileLockStatus = LockUtils.waitForLockRelease(downloadPath.toOSString(), 10000L); + if (!fileLockStatus.isOK()) + { + return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, NLS.bind( + Messages.InstallProcessor_failedToInstallSeeLog, XAMPP)); + } + // Run the XAMPP installer, as specified in this link: + // http://www.apachefriends.org/en/xampp-windows.html#522 + List command = new ArrayList(4); + command.add(downloadPath.toOSString()); + command.add("-d" + installDir); //$NON-NLS-1$ + command.add("-s2"); //$NON-NLS-1$ + if (runAutoInstallScript) + { + command.add("-spauto"); //$NON-NLS-1$ + } + ProcessBuilder processBuilder = new ProcessBuilder(command); + Process process = processBuilder.start(); + int res = process.waitFor(); + if (res == XAMPP_INSTALLER_PROCESS_CANCEL_CODE) + { + IdeLog.logInfo(PortalUIPlugin.getDefault(), "XAMPP installation cancelled"); //$NON-NLS-1$ + return Status.CANCEL_STATUS; + } + if (res != 0) + { + // We had an error while installing + IdeLog.logError( + PortalUIPlugin.getDefault(), + "Failed to install XAMPP. The XAMPP installer process returned a termination code of " + res); //$NON-NLS-1$ + return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, res, NLS.bind( + Messages.InstallProcessor_installationErrorMessage, XAMPP, XAMPP), null); + } + else if (!new File(installDir).exists()) + { + // Just to be sure that we got everything in place + IdeLog.logError(PortalUIPlugin.getDefault(), + "Failed to install XAMPP. The " + installDir + " directory was not created"); //$NON-NLS-1$ //$NON-NLS-2$ + return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, res, NLS.bind( + Messages.InstallProcessor_installationError_installDirMissing, XAMPP), null); + } + // In case we had the auto-setup script on, open the XAMPP control + if (runAutoInstallScript) + { + openXAMPPConsole(installDir + XAMPP_DEFAULT_FOLDER); + } + finalizeInstallation(installDir + XAMPP_DEFAULT_FOLDER); + return Status.OK_STATUS; + } + catch (Exception e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), e); + return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, NLS.bind( + Messages.InstallProcessor_failedToInstallSeeLog, XAMPP), e); + } + finally + { + monitor.done(); + } + } + }; + // Give it a little delay, just in case the downloader still holds on to the installer file. + job.schedule(1000); + try + { + job.join(); + } + catch (InterruptedException e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), e); + return Status.CANCEL_STATUS; + } + return job.getResult(); + } + + /** + * Opens the XAMPP console right after XAMPP was installed. + * + * @param installDir + */ + protected void openXAMPPConsole(final String installDir) + { + Job job = new Job(Messages.XAMPPInstallProcessor_openXAMPPConsoleJobName) + { + + @Override + protected IStatus run(IProgressMonitor monitor) + { + + try + { + ProcessBuilder processBuilder = new ProcessBuilder(installDir + XAMPP_CONTROL); + // We might stumble into 'Access Denied' errors when running this one. So this will try to + // re-initiate it several times. + int attempts = 5; + long timeOut = 3000L; + Throwable lastException = null; + do + { + if (monitor.isCanceled()) + { + break; + } + try + { + processBuilder.start(); + lastException = null; + break; + } + catch (Throwable t) + { + attempts--; + lastException = t; + } + Thread.sleep(timeOut); + } + while (attempts > 0); + if (lastException != null) + { + IdeLog.logError(PortalUIPlugin.getDefault(), lastException); + } + } + catch (Throwable t) + { + // Just log any error here, but don't display any error message + IdeLog.logError(PortalUIPlugin.getDefault(), t); + } + return Status.OK_STATUS; + } + + }; + job.schedule(3000L); + } + + /** + * Finalize the installation by placing a .aptana file in the installed directory, specifying some properties. + * + * @param installDir + */ + protected void finalizeInstallation(String installDir) + { + super.finalizeInstallation(installDir); + File propertiesFile = new File(installDir, APTANA_PROPERTIES_FILE_NAME); + Properties properties = new Properties(); + properties.put("xampp_install", urls[0]); //$NON-NLS-1$ + FileOutputStream fileOutputStream = null; + try + { + fileOutputStream = new FileOutputStream(propertiesFile); + properties.store(fileOutputStream, NLS.bind(Messages.InstallProcessor_aptanaInstallationComment, XAMPP)); + } + catch (IOException e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), e); + } + finally + { + if (fileOutputStream != null) + { + try + { + fileOutputStream.flush(); + fileOutputStream.close(); + } + catch (IOException e) + { + } + } + } + } + + private class XAMPPInstallerOptionsDialog extends InstallerOptionsDialog + { + private Button executeScriptBt; + + public XAMPPInstallerOptionsDialog() + { + super(Display.getDefault().getActiveShell(), XAMPP); + setTitleImage(PortalUIPlugin.getDefault().getImageRegistry().get(PortalUIPlugin.XAMPP_IMAGE)); + } + + @Override + protected void setAttributes() + { + attributes.put(INSTALL_DIR_ATTR, installDir); + attributes.put(EXECUTE_SETUP_SCRIPT_ATTR, Boolean.TRUE); + } + + /** + * Add the 'Auto-Setup' checkbox. + */ + @Override + protected Composite createInstallerGroupControls(Composite group) + { + Composite control = super.createInstallerGroupControls(group); + executeScriptBt = new Button(group, SWT.CHECK); + executeScriptBt.setText(Messages.XAMPPInstallProcessor_executeXAMPPAutoSetup); + executeScriptBt.setSelection(true); + executeScriptBt.addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetSelected(SelectionEvent e) + { + attributes.put(EXECUTE_SETUP_SCRIPT_ATTR, executeScriptBt.getSelection()); + } + }); + return control; + } + } +} diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/installer/InstallerOptionsDialog.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/installer/InstallerOptionsDialog.java new file mode 100644 index 0000000000..522d90b8b2 --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/installer/InstallerOptionsDialog.java @@ -0,0 +1,308 @@ +/** + * Aptana Studio + * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). + * Please see the license.html included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ +package com.aptana.portal.ui.dispatch.configurationProcessors.installer; + +import java.io.File; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.dialogs.TitleAreaDialog; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.DirectoryDialog; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +import com.aptana.core.CoreStrings; +import com.aptana.core.util.PlatformUtil; +import com.aptana.core.util.StringUtil; +import com.aptana.portal.ui.dispatch.configurationProcessors.Messages; + +/** + * A generic implementation for an installation dialog. Through this dialog, the user can input arbitrary data that is + * needed for the specific installer. + * + * @author Shalom Gibly + */ +public abstract class InstallerOptionsDialog extends TitleAreaDialog +{ + public static final String INSTALL_DIR_ATTR = "install_dir"; //$NON-NLS-1$ + protected Map attributes; + protected Text path; + private String installerName; + private boolean createInstallDir; + + /** + * Constructs a new InstallerOptionsDialog + * + * @param parentShell + * @param installerName + */ + public InstallerOptionsDialog(Shell parentShell, String installerName) + { + this(parentShell, installerName, false); + } + + /** + * Constructs a new InstallerOptionsDialog. + * + * @param parentShell + * @param installerName + * @param createInstallDir + * - In case it's true, an input directory that does not exist will be created when the user + * clicks OK. + */ + public InstallerOptionsDialog(Shell parentShell, String installerName, boolean createInstallDir) + { + super(Display.getDefault().getActiveShell()); + this.installerName = installerName; + setBlockOnOpen(true); + setHelpAvailable(false); + attributes = new HashMap(); + setAttributes(); + this.createInstallDir = createInstallDir; + } + + /** + * Returns an unmodifiable Map of the attributes this install dialog is holding. + * + * @return + */ + public Map getAttributes() + { + return Collections.unmodifiableMap(attributes); + } + + /** + * Set attributes that can later be used when creating the dialog area. + * + * @param attributeName + * @param value + */ + protected abstract void setAttributes(); + + /** + * Configure the shell to display a title. + */ + @Override + protected void configureShell(Shell newShell) + { + super.configureShell(newShell); + newShell.setText(Messages.InstallProcessor_installerShellTitle); + } + + @Override + protected Control createDialogArea(Composite parent) + { + Composite composite = (Composite) super.createDialogArea(parent); + // Create a inner composite so we can control the margins + Composite inner = new Composite(composite, SWT.NONE); + inner.setLayoutData(new GridData(GridData.FILL_BOTH)); + GridLayout layout = new GridLayout(); + layout.marginLeft = 4; + layout.marginRight = 4; + layout.marginTop = 4; + layout.marginBottom = 4; + inner.setLayout(layout); + + // TODO - Split this to a method. + Group group = new Group(inner, SWT.NONE); + group.setText(Messages.InstallProcessor_installerGroupTitle); + group.setLayout(new GridLayout()); + GridData layoutData = new GridData(GridData.FILL_BOTH); + group.setLayoutData(layoutData); + + createInstallerGroupControls(group); + createExtendedControls(inner); + setTitle(NLS.bind(Messages.InstallProcessor_installerTitle, installerName)); + return composite; + } + + /** + * Returns the message that will be displayed in the installer dialog. + * + * @return An installer message. + */ + protected String getInstallerMessage() + { + return NLS.bind(Messages.InstallProcessor_installerMessage, installerName); + } + + /** + * Creates the components inside the 'Installer' group.
+ * The default creation is only for the installation path. This can be overwritten, or extended, by a subclass. + * + * @param group + * @return A composite. + */ + protected Composite createInstallerGroupControls(Composite group) + { + Label l = new Label(group, SWT.WRAP); + l.setText(getInstallerMessage()); + Composite installLocation = new Composite(group, SWT.NONE); + installLocation.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + installLocation.setLayout(new GridLayout(2, false)); + path = new Text(installLocation, SWT.SINGLE | SWT.BORDER); + path.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + path.setText(attributes.get(INSTALL_DIR_ATTR).toString()); + path.addKeyListener(new KeyListener() + { + public void keyReleased(org.eclipse.swt.events.KeyEvent e) + { + attributes.put(INSTALL_DIR_ATTR, PlatformUtil.expandEnvironmentStrings(path.getText().trim())); + validatePath(); + } + + public void keyPressed(org.eclipse.swt.events.KeyEvent e) + { + attributes.put(INSTALL_DIR_ATTR, PlatformUtil.expandEnvironmentStrings(path.getText().trim())); + validatePath(); + } + }); + Button browse = new Button(installLocation, SWT.PUSH); + browse.setText(StringUtil.ellipsify(CoreStrings.BROWSE)); + browse.addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetSelected(SelectionEvent e) + { + DirectoryDialog dirDialog = new DirectoryDialog(getParentShell()); + String dir = dirDialog.open(); + if (dir != null) + { + path.setText(dir); + attributes.put(INSTALL_DIR_ATTR, dir); + validatePath(); + } + } + }); + validatePath(); + return group; + } + + /* + * (non-Javadoc) + * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) + */ + @Override + protected void createButtonsForButtonBar(Composite parent) + { + super.createButtonsForButtonBar(parent); + validatePath(); + } + + /* + * (non-Javadoc) + * @see org.eclipse.jface.dialogs.Dialog#okPressed() + */ + @Override + protected void okPressed() + { + if (createInstallDir) + { + File f = new File(PlatformUtil.expandEnvironmentStrings(path.getText())); + if (!f.exists() && !f.mkdirs()) + { + // Display an error message about the problem and return here to prevent a dialog close. + MessageDialog.openError(getParentShell(), + Messages.InstallerOptionsDialog_creatingDirectoriesErrorTitle, + Messages.InstallerOptionsDialog_creatingDirectoriesErrorMessage); + return; + } + } + super.okPressed(); + } + + /** + * Validate the path + */ + protected void validatePath() + { + String pathText = path.getText().trim(); + if (pathText.length() == 0) + { + // empty path + setErrorMessage(Messages.InstallerOptionsDialog_emptyPathError); + return; + } + pathText = PlatformUtil.expandEnvironmentStrings(pathText); + if (!new File(pathText).exists()) + { + if (createInstallDir) + { + setMessage(Messages.InstallerOptionsDialog_inputDirectoryWillBeCreated, IMessageProvider.INFORMATION); + } + else + { + // non-existing path + setErrorMessage(Messages.InstallerOptionsDialog_nonExistingPathError); + return; + } + + } + setErrorMessage(null); + } + + /* + * (non-Javadoc) + * @see org.eclipse.jface.dialogs.TitleAreaDialog#setErrorMessage(java.lang.String) + */ + @Override + public void setErrorMessage(String newErrorMessage) + { + super.setErrorMessage(newErrorMessage); + Button button = getButton(IDialogConstants.OK_ID); + if (button != null) + { + button.setEnabled(newErrorMessage == null); + } + } + + /** + * Create extended controls that will appear under the 'Installer' group.
+ * The default implementation is empty, and can be sub-classed. + * + * @param parent + * @return A composite. + */ + protected Composite createExtendedControls(Composite parent) + { + // Does nothing special here + return parent; + } + + /** + * Capitalize the word by upper-casing the first letter. + * + * @param word + * @return A capitalized word. + */ + protected static String capitalize(String word) + { + if (word != null && word.length() > 0) + { + return Character.toUpperCase(word.charAt(0)) + word.substring(1); + } + return word; + } +} diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/installer/JavaScriptImporterOptionsDialog.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/installer/JavaScriptImporterOptionsDialog.java new file mode 100644 index 0000000000..9a6f1f89c4 --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/installer/JavaScriptImporterOptionsDialog.java @@ -0,0 +1,412 @@ +/** + * Aptana Studio + * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). + * Please see the license.html included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ +package com.aptana.portal.ui.dispatch.configurationProcessors.installer; + +import java.net.URI; + +import org.eclipse.core.filesystem.URIUtil; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerFilter; +import org.eclipse.osgi.util.TextProcessor; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.dialogs.ElementTreeSelectionDialog; +import org.eclipse.ui.model.WorkbenchContentProvider; +import org.eclipse.ui.model.WorkbenchLabelProvider; +import org.eclipse.ui.views.navigator.ResourceComparator; + +import com.aptana.core.CoreStrings; +import com.aptana.core.util.StringUtil; +import com.aptana.portal.ui.PortalUIPlugin; +import com.aptana.portal.ui.dispatch.configurationProcessors.Messages; + +/** + * An import dialog that appears right after we download a JavaScript library through the developer-toolbox.
+ * The dialog lets the user choose the project and the location in the project that the JS library will be saved. + * + * @author Shalom Gibly + */ +public class JavaScriptImporterOptionsDialog extends InstallerOptionsDialog +{ + public static final String ACTIVE_PROJECT_ATTR = "active_project"; //$NON-NLS-1$s + + private static final String RAILS_NATURE = "org.radrails.rails.core.railsnature"; //$NON-NLS-1$ + private static final String RAILS_JS_PATH = "/public/javascripts"; //$NON-NLS-1$ + private static final String JS_PATH = "/javascripts"; //$NON-NLS-1$ + private Combo projectsCombo; + private Button useDefaultsButton; + private Text path; + private Label locationLb; + private Button browseBt; + // The final selected location. Set on okPressed. + private String selectedLocation; + + /** + * Constructs a new dialog for importing a downloaded library into a project. + * + * @param parentShell + * @param libraryName + */ + public JavaScriptImporterOptionsDialog(Shell parentShell, String libraryName) + { + super(Display.getDefault().getActiveShell(), capitalize(libraryName)); + setTitleImage(PortalUIPlugin.getDefault().getImageRegistry().get(PortalUIPlugin.JS_IMAGE)); + } + + /** + * Configure the shell to display a title. + */ + @Override + protected void configureShell(Shell newShell) + { + super.configureShell(newShell); + newShell.setText(Messages.InstallProcessor_installerShellTitle); + } + + /** + * Set the attributes for this dialog.
+ * By default, the active project is set. + */ + @Override + protected void setAttributes() + { + attributes.put(ACTIVE_PROJECT_ATTR, PortalUIPlugin.getActiveProject()); + } + + /** + * Returns the selected, valid, location for the JavaScript library location. Note that this location might still + * need to be created under the current project. + * + * @return The selected location for the JavaScript library. + */ + public String getSelectedLocation() + { + return selectedLocation; + } + + /* + * (non-Javadoc) + * @see org.eclipse.jface.dialogs.Dialog#okPressed() + */ + @Override + protected void okPressed() + { + selectedLocation = path.getText(); + super.okPressed(); + } + + /* + * (non-Javadoc) + * @see org.eclipse.jface.dialogs.TitleAreaDialog#setErrorMessage(java.lang.String) + */ + @Override + public void setErrorMessage(String newErrorMessage) + { + super.setErrorMessage(newErrorMessage); + Button button = getButton(IDialogConstants.OK_ID); + if (button != null) + { + button.setEnabled(newErrorMessage == null); + } + } + + /* + * (non-Javadoc) + * @see org.eclipse.jface.dialogs.TitleAreaDialog#createContents(org.eclipse.swt.widgets.Composite) + */ + @Override + protected Control createContents(Composite parent) + { + Control c = super.createContents(parent); + validatePath(); + return c; + } + + /** + * Creates the components inside the 'Installer' group.
+ * The controls that are added here allow project selection and folder selection under the selected project.
+ * + * @param group + * @return A composite. + */ + protected Composite createInstallerGroupControls(Composite group) + { + int columns = 3; + Composite projectGroup = new Composite(group, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.numColumns = columns; + projectGroup.setLayout(layout); + projectGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + Label projectSelectionLable = new Label(projectGroup, SWT.NONE); + projectSelectionLable.setText(Messages.ImportJavaScriptLibraryDialog_projectLable); + projectsCombo = new Combo(projectGroup, SWT.DROP_DOWN | SWT.READ_ONLY); + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalSpan = 2; + projectsCombo.setLayoutData(gd); + + useDefaultsButton = new Button(projectGroup, SWT.CHECK | SWT.RIGHT); + useDefaultsButton.setText(Messages.ImportJavaScriptLibraryDialog_useDefaultLocation); + useDefaultsButton.setSelection(true); + gd = new GridData(); + gd.horizontalSpan = columns; + useDefaultsButton.setLayoutData(gd); + + createUserPathArea(projectGroup, true); + + useDefaultsButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + boolean useDefaults = useDefaultsButton.getSelection(); + path.setText(TextProcessor.process(getDefaultPath())); + setPathAreaEnabled(!useDefaults); + } + }); + setPathAreaEnabled(false); + initProjectsCombo(projectsCombo); + return group; + } + + /** + * Adds the projects in the workspace and selects the active one (if resolved). + * + * @param combo + */ + private void initProjectsCombo(final Combo combo) + { + IProject[] allProjects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); + for (IProject project : allProjects) + { + if (project.isAccessible()) + { + combo.add(project.getName()); + combo.setData(project.getName(), project); + } + } + if (combo.getItemCount() == 0) + { + return; + } + IProject activeProject = PortalUIPlugin.getActiveProject(); + String activeProjectName = (activeProject != null) ? activeProject.getName() : null; + if (activeProject != null && activeProject.isAccessible()) + { + int index = combo.indexOf(activeProjectName); + combo.select(Math.max(0, index)); + attributes.put(ACTIVE_PROJECT_ATTR, activeProject); + } + else + { + if (combo.getItemCount() > 0) + { + combo.select(0); + attributes.put(ACTIVE_PROJECT_ATTR, combo.getData(combo.getText())); + } + } + path.setText(TextProcessor.process(getDefaultPath())); + + // track the selections from now on + combo.addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetSelected(SelectionEvent e) + { + attributes.put(ACTIVE_PROJECT_ATTR, combo.getData(combo.getText())); + // update the path + path.setText(TextProcessor.process(getDefaultPath())); + } + }); + } + + /** + * Create the area for user entry. + * + * @param composite + * @param defaultEnabled + */ + private void createUserPathArea(Composite composite, boolean defaultEnabled) + { + locationLb = new Label(composite, SWT.NONE); + locationLb.setText(Messages.ImportJavaScriptLibraryDialog_locationLabel); + path = new Text(composite, SWT.BORDER); + GridData data = new GridData(GridData.FILL_HORIZONTAL); + data.widthHint = 250; + path.setLayoutData(data); + + // browse button + browseBt = new Button(composite, SWT.PUSH); + browseBt.setText(StringUtil.ellipsify(CoreStrings.BROWSE)); + browseBt.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent event) + { + ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(getShell(), + new WorkbenchLabelProvider(), new WorkbenchContentProvider()); + dialog.setBlockOnOpen(true); + dialog.setAllowMultiple(false); + dialog.setHelpAvailable(false); + dialog.setTitle(Messages.ImportJavaScriptLibraryDialog_folderSelectionDialogTitle); + dialog.setMessage(Messages.ImportJavaScriptLibraryDialog_folderSelectionDialogMessage); + final IProject project = (IProject) attributes.get(ACTIVE_PROJECT_ATTR); + dialog.setInput(ResourcesPlugin.getWorkspace().getRoot()); + dialog.setComparator(new ResourceComparator(ResourceComparator.NAME)); + // Filter out files and other projects + dialog.addFilter(new ViewerFilter() + { + @Override + public boolean select(Viewer viewer, Object parentElement, Object element) + { + if (parentElement instanceof IResource) + { + if (element instanceof IProject) + { + return element.equals(project); + } + IProject parentProject = ((IResource) parentElement).getProject(); + if (!parentProject.equals(project)) + { + return false; + } + if (element instanceof IResource) + { + IResource resource = (IResource) element; + if (resource.isHidden()) + { + return false; + } + if (resource.getLocation().toFile().isDirectory()) + { + return true; + } + } + } + return false; + } + }); + int buttonId = dialog.open(); + if (buttonId == IDialogConstants.OK_ID) + { + IResource resource = (IResource) dialog.getFirstResult(); + path.setText(TextProcessor.process(project.getName() + '/' + + resource.getProjectRelativePath().toString())); + } + } + }); + + path.setText(TextProcessor.process(getDefaultPath())); + + // Validate any user-input changes + path.addModifyListener(new ModifyListener() + { + public void modifyText(ModifyEvent e) + { + validatePath(); + } + }); + } + + /** + * Returns the default JavaScript library installation path for currently selected project. + * + * @return The default path to place the JavaScript library under the selected project. + */ + protected String getDefaultPath() + { + IProject project = (IProject) attributes.get(ACTIVE_PROJECT_ATTR); + if (project == null) + { + return StringUtil.EMPTY; + } + boolean isRails = false; + try + { + isRails = project.hasNature(RAILS_NATURE); + } + catch (CoreException e) + { + } + return project.getName() + (isRails ? RAILS_JS_PATH : JS_PATH); + } + + /** + * Validate the typed path and notify the user on errors. + */ + protected void validatePath() + { + String pathString = path.getText(); + String errorMsg = null; + // Check for empty content/projects list. + if (projectsCombo.getItemCount() == 0) + { + errorMsg = Messages.ImportJavaScriptLibraryDialog_noAccessibleProjectsError; + } + + if (errorMsg == null && pathString.length() == 0) + { + errorMsg = Messages.ImportJavaScriptLibraryDialog_emptyPathError; + } + URI uri = URIUtil.toURI(pathString); + // Check for valid URI + if (errorMsg == null && uri == null) + { + errorMsg = Messages.ImportJavaScriptLibraryDialog_invalidPathError; + } + if (errorMsg == null) + { + // Check that the URI is actually located under the selected project + IProject project = (IProject) attributes.get(ACTIVE_PROJECT_ATTR); + if (project != null) + { + // make sure we add a '/' prefix to the URI path to have this check cross-platform (Windows os returns + // the URI without it). + String projectPath = project.getFullPath().toString(); + String uriPath = uri.getPath(); + if (uriPath != null && !uriPath.startsWith("/")) //$NON-NLS-1$ + { + uriPath = '/' + uriPath; + } + if (uriPath == null || !uriPath.startsWith(projectPath + '/')) + { + errorMsg = Messages.ImportJavaScriptLibraryDialog_wrongProjectRootError; + } + } + } + // set error message + setErrorMessage(errorMsg); + } + + /* + * Set the enablement state of the path area. + * @param enabled + */ + private void setPathAreaEnabled(boolean enabled) + { + locationLb.setEnabled(enabled); + path.setEnabled(enabled); + browseBt.setEnabled(enabled); + } +} diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/messages.properties b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/messages.properties new file mode 100644 index 0000000000..deaf32a945 --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/messages.properties @@ -0,0 +1,68 @@ +#GEMS +GemsConfigurationProcessor_errorInvokingGemList=Error while invoking 'gem list' +GemsConfigurationProcessor_missingShellError=Could not run the command (missing Shell) +GemsConfigurationProcessor_wrongGemsRequest=Wrong structure of Gems request +#APP INSTALL +ImportJavaScriptLibraryDialog_emptyPathError=The library path cannot be empty +ImportJavaScriptLibraryDialog_folderSelectionDialogMessage=Select the location you wish to import the JavaScript library files to: +ImportJavaScriptLibraryDialog_folderSelectionDialogTitle=Library Folder Selection +ImportJavaScriptLibraryDialog_invalidPathError=The given path is invalid +ImportJavaScriptLibraryDialog_locationLabel=&Location +ImportJavaScriptLibraryDialog_noAccessibleProjectsError=There are no accessible projects in your workspace. Please create or open one first. +ImportJavaScriptLibraryDialog_projectLable=Project: +ImportJavaScriptLibraryDialog_useDefaultLocation=Use &default location +ImportJavaScriptLibraryDialog_wrongProjectRootError=The path is not under the selected project root +InstallerConfigurationProcessor_emptyURLsArrayError=Expected an array of URLs, but got an empty array +InstallerConfigurationProcessor_expectedArrayError=Expected an array of attributes, but got +InstallerConfigurationProcessor_expectedMapError=Expected a Map of extended attributes, but got +InstallerConfigurationProcessor_expectedURLsArrayError=Expected an array of URLs, but got +InstallerConfigurationProcessor_unableToExtractZip=Unable to extract the Zip file.\nSee error log for more details. +InstallProcessor_couldNotLocateInstaller=We could not locate the installer. +InstallProcessor_corruptedZip=The {0} zip might be corrupted. +InstallProcessor_couldNotLocatePackage=We could not locate the {0} package. +InstallProcessor_errorWhileInstalling=Error while installing {0} +InstallProcessor_extractingPackageTaskName=Extracting {0} into {1} +InstallProcessor_failedToInstallSeeLog=Failed to install {0}.\nSee error log for more details +InstallProcessor_failedToInstall=Failed to install {0}. +InstallProcessor_failedToWrite=Failed to write to +InstallProcessor_installationError_installDirMissing=Failed to install {0}. \nWe could not locate the installation directory.\nSee error log for more details. +InstallProcessor_installationErrorMessage=Failed to install {0}. \nThe {1} installer indicated an error has occurred.\nSee error log for more details. +InstallProcessor_installationErrorTitle=Installation Error +InstallProcessor_installerGroupTitle=Installer +InstallProcessor_installerMessage={0} will be installed into the following folder. \nClick OK to install, or select a different folder before you continue. +InstallProcessor_installerProgressInfo=Installing... +InstallProcessor_installerShellTitle=Installer +InstallProcessor_installerTitle={0} Installer +InstallProcessor_extractingJobName=Extracting {0} +InstallProcessor_installingTaskName=Installing {0}... +InstallProcessor_executingTaskName=Executing {0} +InstallProcessor_missingInstallURLs=Missing {0} installation URL attributes +InstallProcessor_installationSuccessful={0} installation was completed successfully +InstallProcessor_installerJobName=Running {0} +InstallProcessor_seeErrorLog=.\nSee error log for more details +InstallProcessor_updatingTaskName=Updating {0} settings +InstallProcessor_InstallForAllUsers=Install for all users +InstallProcessor_wrongNumberOfInstallLinks=Got a wrong number of {0} installation links. Expected {1} links, and got {2} +InstallProcessor_aptanaInstallationComment=Aptana Studio Dev-Toolbox used these locations to install {0}.\nPlease do not delete this file, as we might use it to update your installation from time to time. +InstallerConfigurationProcessor_missingAttributeMap=Missing the {0} attributes map +InstallerConfigurationProcessor_missingDownloadTargets=The download targets URLs were empty.\n See error log for more details. +InstallerOptionsDialog_creatingDirectoriesErrorMessage=Failed creating a directory. \nPlease make sure you have write permissions for the selected path. +InstallerOptionsDialog_creatingDirectoriesErrorTitle=Error Creating Directories +InstallerOptionsDialog_emptyPathError=The selected path is empty +InstallerOptionsDialog_inputDirectoryWillBeCreated=The input directory does not exist and will be created +InstallerOptionsDialog_nonExistingPathError=The selected path does not exist +#JavaScript library installer +JSLibraryInstallProcessor_directoriesCreationFailed=Failed to create directories while importing the JavaScript library.\nSee error log for more details. +JSLibraryInstallProcessor_directorySelection=Directory Selection +JSLibraryInstallProcessor_fileConflictMessage=The target directory already contains ' +JSLibraryInstallProcessor_fileConflictTitle=File Conflict +JSLibraryInstallProcessor_multipleErrorsWhileImportingJS=Some errors occurred while importing the JavaScript library. +JSLibraryInstallProcessor_overwriteQuestion='.\n Would you like to overwrite it? +JSLibraryInstallProcessor_unexpectedNull=Unexpected null project when importing a JavaScript library.\nSee error log for more details. + +#SYSTEM +SystemConfigurationProcessor_missingConfigurationItems=Missing system configuration items attributes +SystemConfigurationProcessor_noShellCommandPath=Could not locate the shell command path +SystemConfigurationProcessor_wrongConfigurationAttributesStructure=Wrong structure of configuration items attributes +XAMPPInstallProcessor_executeXAMPPAutoSetup=Execute XAMPP auto-setup script +XAMPPInstallProcessor_openXAMPPConsoleJobName=Opening the XAMPP console... diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/processorDelegates/BaseVersionProcessor.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/processorDelegates/BaseVersionProcessor.java new file mode 100644 index 0000000000..0999724520 --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/processorDelegates/BaseVersionProcessor.java @@ -0,0 +1,29 @@ +/** + * Aptana Studio + * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). + * Please see the license.html included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ +package com.aptana.portal.ui.dispatch.processorDelegates; + +import com.aptana.configurations.processor.AbstractProcessorDelegate; + +/** + * A base application version retrieval delegate for applications that use '--version' in order to get their version. + * + * @author Shalom Gibly + */ +public abstract class BaseVersionProcessor extends AbstractProcessorDelegate +{ + private static final String VERSION_COMMAND_SYNTAX = "--version"; //$NON-NLS-1$ + + /** + * Constructs a new BaseVersionProcessor + */ + public BaseVersionProcessor() + { + // Make sure we add the supported commands + supportedCommands.put(VERSION_COMMAND, VERSION_COMMAND_SYNTAX); + } +} diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/processorDelegates/CachedVersionProcessorDelegate.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/processorDelegates/CachedVersionProcessorDelegate.java new file mode 100644 index 0000000000..dd8d2cf470 --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/processorDelegates/CachedVersionProcessorDelegate.java @@ -0,0 +1,136 @@ +/** + * Aptana Studio + * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). + * Please see the license.html included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ +package com.aptana.portal.ui.dispatch.processorDelegates; + +import java.io.File; +import java.util.Map; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ProjectScope; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.preferences.DefaultScope; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.core.runtime.preferences.IPreferencesService; +import org.eclipse.core.runtime.preferences.IScopeContext; +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.osgi.service.prefs.BackingStoreException; + +import com.aptana.core.logging.IdeLog; +import com.aptana.core.util.StringUtil; +import com.aptana.jetty.util.epl.ajax.JSON; +import com.aptana.portal.ui.IPortalPreferences; +import com.aptana.portal.ui.PortalUIPlugin; + +/** + * A configuration processor delegate that use the preferences as a cache mechanism for the installed apps versions. + * + * @author Shalom Gibly + */ +public class CachedVersionProcessorDelegate extends BaseVersionProcessor +{ + + private String appName; + + /** + * Constructs a new CachedVersionProcessorDelegate.
+ * Unlike other processor delegates, this one is not instantiated through an extension point, as it's being + * allocated per application that does not have a version delegate. So, this instance should be created with the + * application name. This application name will be used to track the cached version preference for that app. + * + * @param appName + */ + public CachedVersionProcessorDelegate(String appName) + { + this.appName = appName; + + } + + @Override + public String getSupportedApplication() + { + return appName; + } + + /** + * The run command for this special delegate looks for a version value cached in the workspace preferences.
+ * The version identifier was cached in the preferences when the app was installed through the dev-toolbox. This + * method also tries to verify that the application is still in the cached location. If not, which means it was + * probably removed externally, we remove the cache from the preferences. + * + * @param commandType + * Expecting for the 'version' command. + * @param workingDir + * - Not used in this delegate, and may be null. + */ + @SuppressWarnings("unchecked") + @Override + public Object runCommand(String commandType, IPath workingDir) + { + // We cache the version and the location in the preferences as a JSON string. So, it's pretty easy to maintain. + + IPreferencesService service = Platform.getPreferencesService(); + IScopeContext[] contexts; + IProject project = PortalUIPlugin.getActiveProject(); + if (project != null) + { + contexts = new IScopeContext[] { new ProjectScope(project), DefaultScope.INSTANCE }; + } + else + { + contexts = new IScopeContext[] { InstanceScope.INSTANCE, DefaultScope.INSTANCE }; + } + String versions = service.getString(PortalUIPlugin.PLUGIN_ID, IPortalPreferences.CACHED_VERSIONS_PROPERTY_NAME, + null, contexts); + if (versions == null || versions.equals(StringUtil.EMPTY)) + { + return null; + } + Map> mapping = (Map>) JSON.parse(versions); + Map appVersion = mapping.get(getSupportedApplication().toLowerCase()); + if (appVersion != null) + { + String location = appVersion.get(IPortalPreferences.CACHED_LOCATION_PROPERTY); + String version = appVersion.get(IPortalPreferences.CACHED_VERSION_PROPERTY); + if (location != null) + { + // Verify that this location still exists on that machine. If not, remove it and store it back to the + // preferences. + File localFile = new File(location); + if (!localFile.exists()) + { + mapping.remove(getSupportedApplication().toLowerCase()); + IEclipsePreferences node = null; + if (project != null) + { + node = contexts[0].getNode(PortalUIPlugin.PLUGIN_ID); + } + else + { + node = contexts[1].getNode(PortalUIPlugin.PLUGIN_ID); + } + node.put(IPortalPreferences.CACHED_VERSIONS_PROPERTY_NAME, JSON.toString(mapping)); + try + { + node.flush(); + } + catch (BackingStoreException e) + { + IdeLog.logError(PortalUIPlugin.getDefault(), e); + return null; + } + return version; + } + // We are good to return the cached version + return version; + } + } + return null; + } + +} diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/processorDelegates/RailsVersionProcessor.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/processorDelegates/RailsVersionProcessor.java new file mode 100644 index 0000000000..4c2615a7e4 --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/processorDelegates/RailsVersionProcessor.java @@ -0,0 +1,27 @@ +/** + * Aptana Studio + * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). + * Please see the license.html included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ +package com.aptana.portal.ui.dispatch.processorDelegates; + +/** + * A rails version processor that can get the current rails version in the system + * + * @author Shalom Gibly + */ +public class RailsVersionProcessor extends BaseVersionProcessor +{ + private static final String RAILS = "rails"; //$NON-NLS-1$ + + /** + * @return "rails" + */ + @Override + public String getSupportedApplication() + { + return RAILS; + } +} diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/processorDelegates/RubyVersionProcessor.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/processorDelegates/RubyVersionProcessor.java new file mode 100644 index 0000000000..c2320e6b78 --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/processorDelegates/RubyVersionProcessor.java @@ -0,0 +1,27 @@ +/** + * Aptana Studio + * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). + * Please see the license.html included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ +package com.aptana.portal.ui.dispatch.processorDelegates; + +/** + * A Ruby version processor that can get the current Ruby version in the system + * + * @author Shalom Gibly + */ +public class RubyVersionProcessor extends BaseVersionProcessor +{ + private static final String RUBY = "ruby"; //$NON-NLS-1$ + + /** + * @return "ruby" + */ + @Override + public String getSupportedApplication() + { + return RUBY; + } +} diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/processorDelegates/SQLiteVersionProcessor.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/processorDelegates/SQLiteVersionProcessor.java new file mode 100644 index 0000000000..0f7ca89e04 --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/processorDelegates/SQLiteVersionProcessor.java @@ -0,0 +1,28 @@ +/** + * Aptana Studio + * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). + * Please see the license.html included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ +package com.aptana.portal.ui.dispatch.processorDelegates; + + +/** + * A SQLite3 version processor that can get the current SQLite3 version in the system + * + * @author Shalom Gibly + */ +public class SQLiteVersionProcessor extends BaseVersionProcessor +{ + private static final String SQLITE = "sqlite3"; //$NON-NLS-1$ + + /** + * @return "sqlite3" + */ + @Override + public String getSupportedApplication() + { + return SQLITE; + } +} diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/extended/Activator.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/extended/Activator.java new file mode 100644 index 0000000000..164eb60149 --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/extended/Activator.java @@ -0,0 +1,50 @@ +package com.aptana.portal.ui.extended; + +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "com.aptana.portal.core"; //$NON-NLS-1$ + + // The shared instance + private static Activator plugin; + + /** + * The constructor + */ + public Activator() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + +} diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/internal/command/NewProjectFromTemplateCommandHandler.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/internal/command/NewProjectFromTemplateCommandHandler.java new file mode 100644 index 0000000000..6dc1dbea22 --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/internal/command/NewProjectFromTemplateCommandHandler.java @@ -0,0 +1,98 @@ +/** + * Aptana Studio + * Copyright (c) 2011 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). + * Please see the license.html included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ +package com.aptana.portal.ui.internal.command; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IExecutableExtension; +import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IWorkbenchWizard; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.wizards.IWizardDescriptor; +import org.eclipse.ui.wizards.IWizardRegistry; + +import com.aptana.projects.wizards.AbstractNewProjectWizard; +import com.aptana.projects.wizards.ProjectTemplateSelectionPage; +import com.aptana.ui.util.UIUtils; + +/** + * Command handler for "com.aptana.portal.ui.command.newProjectFromTemplate". Opens an Aptana/Titanium wizard and + * initializes the project template + * + * @author nle + */ +public class NewProjectFromTemplateCommandHandler extends AbstractHandler +{ + + /** + * Execute the new project command. The command returns the created {@link IProject} name when it's done, in case a + * project was created. + * + * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent) + */ + public Object execute(ExecutionEvent event) throws ExecutionException + { + String wizardId = event.getParameter(ProjectTemplateSelectionPage.COMMAND_PROJECT_FROM_TEMPLATE_NEW_WIZARD_ID); + String templateName = event + .getParameter(ProjectTemplateSelectionPage.COMMAND_PROJECT_FROM_TEMPLATE_PROJECT_TEMPLATE_NAME); + + IWizardRegistry wizardRegistry = PlatformUI.getWorkbench().getNewWizardRegistry(); + IWizardDescriptor wizardDescriptor = wizardRegistry.findWizard(wizardId); + if (wizardDescriptor == null) + { + throw new ExecutionException("unknown wizard: " + wizardId); //$NON-NLS-1$ + } + + try + { + IWorkbenchWizard wizard = wizardDescriptor.createWizard(); + wizard.init(PlatformUI.getWorkbench(), null); + + if (wizard instanceof IExecutableExtension) + { + ((IExecutableExtension) wizard).setInitializationData(null, + ProjectTemplateSelectionPage.COMMAND_PROJECT_FROM_TEMPLATE_PROJECT_TEMPLATE_NAME, templateName); + } + + if (wizardDescriptor.canFinishEarly() && !wizardDescriptor.hasPages()) + { + wizard.performFinish(); + return getProject(wizard); + } + + Shell parent = UIUtils.getActiveShell(); + WizardDialog dialog = new WizardDialog(parent, wizard); + dialog.create(); + dialog.open(); + return getProject(wizard); + } + catch (CoreException ex) + { + throw new ExecutionException("error creating wizard", ex); //$NON-NLS-1$ + } + } + + /** + * Returns the created project. + * + * @param wizard + * @return An {@link IProject}, or null. + */ + private IProject getProject(IWorkbenchWizard wizard) + { + if (wizard instanceof AbstractNewProjectWizard) + { + return ((AbstractNewProjectWizard) wizard).getCreatedProject(); + } + return null; + } +} diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/internal/command/ShowStartPageCommandHandler.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/internal/command/ShowStartPageCommandHandler.java new file mode 100644 index 0000000000..21d88b0a96 --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/internal/command/ShowStartPageCommandHandler.java @@ -0,0 +1,33 @@ +/** + * Aptana Studio + * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). + * Please see the license.html included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ +package com.aptana.portal.ui.internal.command; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; + +import com.aptana.portal.ui.internal.startpage.StartPageUtil; + +/** + * A command handler for showing the Studio's start-page. + * + * @author Shalom Gibly + */ +public class ShowStartPageCommandHandler extends AbstractHandler +{ + + /* + * (non-Javadoc) + * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent) + */ + public Object execute(ExecutionEvent event) throws ExecutionException + { + StartPageUtil.showStartPage(true, null); + return null; + } +} diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/internal/command/ShowToolboxCommandHandler.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/internal/command/ShowToolboxCommandHandler.java new file mode 100644 index 0000000000..872b75d0ee --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/internal/command/ShowToolboxCommandHandler.java @@ -0,0 +1,34 @@ +/** + * Aptana Studio + * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). + * Please see the license.html included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ +package com.aptana.portal.ui.internal.command; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; + +import com.aptana.portal.ui.browser.PortalBrowserEditor; +import com.aptana.portal.ui.internal.Portal; + +/** + * A command handler for showing the developer-toolbox from the Help menu. + * + * @author Shalom Gibly + */ +public class ShowToolboxCommandHandler extends AbstractHandler +{ + + /* + * (non-Javadoc) + * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent) + */ + public Object execute(ExecutionEvent event) throws ExecutionException + { + Portal.getInstance().openPortal(null, PortalBrowserEditor.WEB_BROWSER_EDITOR_ID); + return null; + } +} From c4c55e6ce1c567157e4e477af4adbd139525ca8c Mon Sep 17 00:00:00 2001 From: Kondal Kolipaka Date: Fri, 18 Aug 2017 08:31:47 +0800 Subject: [PATCH 3/3] PortalUI extended changes --- .../META-INF/MANIFEST.MF | 17 +- .../JavaScriptImporterOptionsDialog.java | 5 +- .../CachedVersionProcessorDelegate.java | 3 +- .../aptana/portal/ui/extended/Activator.java | 50 ----- .../portal/ui/extended/PortaUIExtended.java | 172 ++++++++++++++++++ .../com/aptana/portal/ui/PortalUIPlugin.java | 106 +---------- 6 files changed, 193 insertions(+), 160 deletions(-) delete mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/extended/Activator.java create mode 100644 com.aptana.portal.ui.extended/src/com/aptana/portal/ui/extended/PortaUIExtended.java diff --git a/com.aptana.portal.ui.extended/META-INF/MANIFEST.MF b/com.aptana.portal.ui.extended/META-INF/MANIFEST.MF index 7db376c48d..ad576a1444 100644 --- a/com.aptana.portal.ui.extended/META-INF/MANIFEST.MF +++ b/com.aptana.portal.ui.extended/META-INF/MANIFEST.MF @@ -3,10 +3,23 @@ Bundle-ManifestVersion: 2 Bundle-Name: Core Bundle-SymbolicName: com.aptana.portal.ui.extended Bundle-Version: 1.0.0.qualifier -Bundle-Activator: com.aptana.portal.ui.extended.Activator +Bundle-Activator: com.aptana.portal.ui.extended.PortaUIExtended Bundle-Vendor: APTANA Require-Bundle: org.eclipse.ui, - org.eclipse.core.runtime + org.eclipse.core.runtime, + com.aptana.portal.ui;visibility:=reexport, + org.eclipse.core.resources, + com.aptana.jetty.util.epl, + org.eclipse.e4.core.contexts, + org.eclipse.e4.ui.css.swt.theme, + org.eclipse.e4.ui.model.workbench, + com.aptana.core, + com.aptana.configurations, + com.aptana.theme, + com.aptana.projects, + com.aptana.core.io, + com.aptana.ui, + com.aptana.explorer Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-ActivationPolicy: lazy Export-Package: com.aptana.portal.ui.dispatch.configurationProcessors, diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/installer/JavaScriptImporterOptionsDialog.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/installer/JavaScriptImporterOptionsDialog.java index 9a6f1f89c4..dedb76078f 100644 --- a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/installer/JavaScriptImporterOptionsDialog.java +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/configurationProcessors/installer/JavaScriptImporterOptionsDialog.java @@ -42,6 +42,7 @@ import com.aptana.core.util.StringUtil; import com.aptana.portal.ui.PortalUIPlugin; import com.aptana.portal.ui.dispatch.configurationProcessors.Messages; +import com.aptana.portal.ui.extended.PortaUIExtended; /** * An import dialog that appears right after we download a JavaScript library through the developer-toolbox.
@@ -93,7 +94,7 @@ protected void configureShell(Shell newShell) @Override protected void setAttributes() { - attributes.put(ACTIVE_PROJECT_ATTR, PortalUIPlugin.getActiveProject()); + attributes.put(ACTIVE_PROJECT_ATTR, PortaUIExtended.getActiveProject()); } /** @@ -211,7 +212,7 @@ private void initProjectsCombo(final Combo combo) { return; } - IProject activeProject = PortalUIPlugin.getActiveProject(); + IProject activeProject = PortaUIExtended.getActiveProject(); String activeProjectName = (activeProject != null) ? activeProject.getName() : null; if (activeProject != null && activeProject.isAccessible()) { diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/processorDelegates/CachedVersionProcessorDelegate.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/processorDelegates/CachedVersionProcessorDelegate.java index dd8d2cf470..df1c8dec42 100644 --- a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/processorDelegates/CachedVersionProcessorDelegate.java +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/dispatch/processorDelegates/CachedVersionProcessorDelegate.java @@ -26,6 +26,7 @@ import com.aptana.jetty.util.epl.ajax.JSON; import com.aptana.portal.ui.IPortalPreferences; import com.aptana.portal.ui.PortalUIPlugin; +import com.aptana.portal.ui.extended.PortaUIExtended; /** * A configuration processor delegate that use the preferences as a cache mechanism for the installed apps versions. @@ -76,7 +77,7 @@ public Object runCommand(String commandType, IPath workingDir) IPreferencesService service = Platform.getPreferencesService(); IScopeContext[] contexts; - IProject project = PortalUIPlugin.getActiveProject(); + IProject project = PortaUIExtended.getActiveProject(); if (project != null) { contexts = new IScopeContext[] { new ProjectScope(project), DefaultScope.INSTANCE }; diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/extended/Activator.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/extended/Activator.java deleted file mode 100644 index 164eb60149..0000000000 --- a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/extended/Activator.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.aptana.portal.ui.extended; - -import org.eclipse.ui.plugin.AbstractUIPlugin; -import org.osgi.framework.BundleContext; - -/** - * The activator class controls the plug-in life cycle - */ -public class Activator extends AbstractUIPlugin { - - // The plug-in ID - public static final String PLUGIN_ID = "com.aptana.portal.core"; //$NON-NLS-1$ - - // The shared instance - private static Activator plugin; - - /** - * The constructor - */ - public Activator() { - } - - /* - * (non-Javadoc) - * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) - */ - public void start(BundleContext context) throws Exception { - super.start(context); - plugin = this; - } - - /* - * (non-Javadoc) - * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) - */ - public void stop(BundleContext context) throws Exception { - plugin = null; - super.stop(context); - } - - /** - * Returns the shared instance - * - * @return the shared instance - */ - public static Activator getDefault() { - return plugin; - } - -} diff --git a/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/extended/PortaUIExtended.java b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/extended/PortaUIExtended.java new file mode 100644 index 0000000000..ec2eb839cc --- /dev/null +++ b/com.aptana.portal.ui.extended/src/com/aptana/portal/ui/extended/PortaUIExtended.java @@ -0,0 +1,172 @@ +package com.aptana.portal.ui.extended; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.preferences.IPreferencesService; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorReference; +import org.eclipse.ui.IViewReference; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +import com.aptana.core.resources.IProjectContext; +import com.aptana.explorer.ExplorerPlugin; +import com.aptana.explorer.IExplorerUIConstants; +import com.aptana.explorer.IPreferenceConstants; + +/** + * The activator class controls the plug-in life cycle + */ +public class PortaUIExtended extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "com.aptana.portal.ui.extended"; //$NON-NLS-1$ + + // The shared instance + private static PortaUIExtended plugin; + + /** + * The constructor + */ + public PortaUIExtended() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static PortaUIExtended getDefault() { + return plugin; + } + + + /** + * Try to resolve and return the last active project in the App Explorer. + * + * @return The active IProject. Can be null if not resolved. + */ + public static IProject getActiveProject() + { + // FIXME: Shalom - This is a modified of a code taken from the com.aptana.explorer plugin. Change this code to + // use a more generic solution for the active project problem once it's implemented. + + // First try and get the active project for the instance of the App Explorer open in the active window + final IProject[] projects = new IProject[1]; + PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() + { + public void run() + { + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) + { + return; + } + IWorkbenchPage page = window.getActivePage(); + if (page == null) + { + return; + } + // First, check the view references. + IViewReference[] refs = page.getViewReferences(); + if (refs == null) + { + return; + } + for (IViewReference ref : refs) + { + if (ref == null || !ref.getId().equals(IExplorerUIConstants.VIEW_ID)) + { + continue; + } + IProjectContext view = (IProjectContext) ref.getPart(false); + if (view == null) + { + continue; + } + IProject activeProject = view.getActiveProject(); + if (activeProject != null) + { + projects[0] = activeProject; + return; + } + } + // If we got to this point, we could not find the SingleProjectView and its active project. + // Try to find the a project by the active editor. + IEditorPart activeEditor = page.getActiveEditor(); + if (activeEditor != null) + { + IResource resource = null; + if (activeEditor.getEditorInput().getPersistable() != null) + { + // it's probably a non-browser editor. + resource = (IResource) activeEditor.getEditorInput().getAdapter(IResource.class); + } + else + { + // look for the first persistable editor input we can find. + IEditorReference[] editorReferences = page.getEditorReferences(); + for (IEditorReference reference : editorReferences) + { + IEditorPart editor = reference.getEditor(false); + if (editor != null) + { + resource = (IResource) editor.getEditorInput().getAdapter(IResource.class); + if (resource != null) + { + break; + } + } + } + } + if (resource != null) + { + projects[0] = ((IResource) resource).getProject(); + return; + } + } + } + }); + if (projects[0] != null) + { + return projects[0]; + } + + // Fall back to using project stored in prefs. + IPreferencesService preferencesService = Platform.getPreferencesService(); + String activeProjectName = preferencesService.getString(ExplorerPlugin.PLUGIN_ID, + IPreferenceConstants.ACTIVE_PROJECT, null, null); + IProject result = null; + + if (activeProjectName != null) + { + result = ResourcesPlugin.getWorkspace().getRoot().getProject(activeProjectName); + } + + return result; + } + +} diff --git a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/PortalUIPlugin.java b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/PortalUIPlugin.java index 7629529c22..c997f17649 100644 --- a/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/PortalUIPlugin.java +++ b/plugins/com.aptana.portal.ui/src/com/aptana/portal/ui/PortalUIPlugin.java @@ -70,111 +70,7 @@ public static PortalUIPlugin getDefault() { return plugin; } -// -// /** -// * Try to resolve and return the last active project in the App Explorer. -// * -// * @return The active IProject. Can be null if not resolved. -// */ -// public static IProject getActiveProject() -// { -// // FIXME: Shalom - This is a modified of a code taken from the com.aptana.explorer plugin. Change this code to -// // use a more generic solution for the active project problem once it's implemented. -// -// // First try and get the active project for the instance of the App Explorer open in the active window -// final IProject[] projects = new IProject[1]; -// PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() -// { -// public void run() -// { -// IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); -// if (window == null) -// { -// return; -// } -// IWorkbenchPage page = window.getActivePage(); -// if (page == null) -// { -// return; -// } -// // First, check the view references. -// IViewReference[] refs = page.getViewReferences(); -// if (refs == null) -// { -// return; -// } -// for (IViewReference ref : refs) -// { -// if (ref == null || !ref.getId().equals(IExplorerUIConstants.VIEW_ID)) -// { -// continue; -// } -// IProjectContext view = (IProjectContext) ref.getPart(false); -// if (view == null) -// { -// continue; -// } -// IProject activeProject = view.getActiveProject(); -// if (activeProject != null) -// { -// projects[0] = activeProject; -// return; -// } -// } -// // If we got to this point, we could not find the SingleProjectView and its active project. -// // Try to find the a project by the active editor. -// IEditorPart activeEditor = page.getActiveEditor(); -// if (activeEditor != null) -// { -// IResource resource = null; -// if (activeEditor.getEditorInput().getPersistable() != null) -// { -// // it's probably a non-browser editor. -// resource = (IResource) activeEditor.getEditorInput().getAdapter(IResource.class); -// } -// else -// { -// // look for the first persistable editor input we can find. -// IEditorReference[] editorReferences = page.getEditorReferences(); -// for (IEditorReference reference : editorReferences) -// { -// IEditorPart editor = reference.getEditor(false); -// if (editor != null) -// { -// resource = (IResource) editor.getEditorInput().getAdapter(IResource.class); -// if (resource != null) -// { -// break; -// } -// } -// } -// } -// if (resource != null) -// { -// projects[0] = ((IResource) resource).getProject(); -// return; -// } -// } -// } -// }); -// if (projects[0] != null) -// { -// return projects[0]; -// } -// -// // Fall back to using project stored in prefs. -// IPreferencesService preferencesService = Platform.getPreferencesService(); -// String activeProjectName = preferencesService.getString(ExplorerPlugin.PLUGIN_ID, -// IPreferenceConstants.ACTIVE_PROJECT, null, null); -// IProject result = null; -// -// if (activeProjectName != null) -// { -// result = ResourcesPlugin.getWorkspace().getRoot().getProject(activeProjectName); -// } -// -// return result; -// } + public static Image getImage(String string) {