diff options
7 files changed, 278 insertions, 55 deletions
diff --git a/google-cloud-tools.iml b/google-cloud-tools.iml index 9126f4b..6d1ab7c 100644 --- a/google-cloud-tools.iml +++ b/google-cloud-tools.iml @@ -54,6 +54,7 @@ </library> </orderEntry> <orderEntry type="module" module-name="google-login" /> + <orderEntry type="module" module-name="bootstrap" /> </component> </module> diff --git a/login/src/com/google/gct/login/ui/GoogleLoginUsersPanel.java b/login/src/com/google/gct/login/ui/GoogleLoginUsersPanel.java index 6536283..a98ce85 100644 --- a/login/src/com/google/gct/login/ui/GoogleLoginUsersPanel.java +++ b/login/src/com/google/gct/login/ui/GoogleLoginUsersPanel.java @@ -59,6 +59,7 @@ public class GoogleLoginUsersPanel extends JPanel implements ListSelectionListen private JButton signOutButton; private JButton addAccountButton; private boolean valueChanged = false; + private boolean ignoreSelection = false; public GoogleLoginUsersPanel() { super(new BorderLayout()); @@ -150,7 +151,7 @@ public class GoogleLoginUsersPanel extends JPanel implements ListSelectionListen // Active user boolean inPlayUrl = usersListCellRenderer.inPlayConsoleUrl(mouseEvent.getPoint(), index); boolean inCloudUrl = usersListCellRenderer.inCloudConsoleUrl(mouseEvent.getPoint(), index); - if(inPlayUrl || inCloudUrl){ + if (inPlayUrl || inCloudUrl) { list.setCursor(new Cursor(Cursor.HAND_CURSOR)); } else { list.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); @@ -223,6 +224,9 @@ public class GoogleLoginUsersPanel extends JPanel implements ListSelectionListen //This method is required by ListSelectionListener. @Override public void valueChanged(ListSelectionEvent e) { + if(ignoreSelection) { + return; + } valueChanged = true; if (e.getValueIsAdjusting() == false) { if (list.getSelectedIndex() == -1) { @@ -235,6 +239,19 @@ public class GoogleLoginUsersPanel extends JPanel implements ListSelectionListen if(!selectedUser.isActiveUser()) { GoogleLogin.getInstance().setActiveUser(selectedUser.getUserEmail()); } + + // Change order of elements in the list so that the + // active user becomes the first element in the list + ignoreSelection = true; + try { + listModel.remove(list.getSelectedIndex()); + listModel.add(0, selectedUser); + + // Re-select the active user + list.setSelectedIndex(0); + } finally { + ignoreSelection = false; + } } } } @@ -258,6 +275,12 @@ public class GoogleLoginUsersPanel extends JPanel implements ListSelectionListen if(listModel.getSize() == 0) { // Add no user panel listModel.addElement(NoUsersListItem.INSTANCE); + } else if ((activeUserIndex != 0) && (activeUserIndex < listModel.getSize())) { + // Change order of elements in the list so that the + // active user becomes the first element in the list + UsersListItem activeUser = (UsersListItem)listModel.remove(activeUserIndex); + listModel.add(0, activeUser); + activeUserIndex = 0; } return activeUserIndex; diff --git a/src/META-INF/plugin.xml b/src/META-INF/plugin.xml index c6bc850..ecba450 100644 --- a/src/META-INF/plugin.xml +++ b/src/META-INF/plugin.xml @@ -110,10 +110,6 @@ </extensions> <actions> - <action id="GoogleCloudTools.InstallClientLibraries" - class="com.google.gct.idea.appengine.gradle.action.InstallClientLibrariesAction" - text="Install Client Libraries" - icon="/icons/cloudEndpoints.png"/> <action id="GoogleCloudTools.GenerateEndpoint" class="com.google.gct.idea.appengine.gradle.action.GenerateEndpointAction" text="Generate Endpoint" diff --git a/src/com/google/gct/idea/appengine/gradle/action/GenerateEndpointAction.java b/src/com/google/gct/idea/appengine/gradle/action/GenerateEndpointAction.java index f442f43..7e236b2 100644 --- a/src/com/google/gct/idea/appengine/gradle/action/GenerateEndpointAction.java +++ b/src/com/google/gct/idea/appengine/gradle/action/GenerateEndpointAction.java @@ -83,6 +83,7 @@ public class GenerateEndpointAction extends AnAction { try { if (!AppEngineUtils.isAppEngineModule(project, module)) { Messages.showErrorDialog(project, "Endpoints can only be generated for App Engine projects.", ERROR_MESSAGE_TITLE); + return; } } catch (FileNotFoundException error) { diff --git a/src/com/google/gct/idea/appengine/gradle/action/InstallClientLibrariesAction.java b/src/com/google/gct/idea/appengine/gradle/action/InstallClientLibrariesAction.java deleted file mode 100644 index c90e040..0000000 --- a/src/com/google/gct/idea/appengine/gradle/action/InstallClientLibrariesAction.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.gct.idea.appengine.gradle.action; - -import com.android.tools.idea.gradle.invoker.GradleInvoker; - -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.LangDataKeys; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.Messages; - -import java.util.Arrays; - -/** - * Action to generate client libraries for an AppEngine endpoints project and copy them to an associated android project - */ -public class InstallClientLibrariesAction extends AnAction { - - private static final String ERROR_MSG_TITLE = "Install Client Libraries"; - - @Override - public void actionPerformed(AnActionEvent e) { - final Project project = e.getProject(); - final Module appEngineModule = e.getData(LangDataKeys.MODULE); - - if (project == null || appEngineModule == null) { - Messages.showErrorDialog(project, "Please select an App Engine module.", ERROR_MSG_TITLE); - return; - } - // TODO : check if module is App Engine Module or not - - GradleInvoker.getInstance(project).executeTasks(Arrays.asList(appEngineModule.getName() + ":appengineEndpointsInstallClientLibs")); - } -} diff --git a/src/com/google/gct/idea/settings/ExportSettings.java b/src/com/google/gct/idea/settings/ExportSettings.java new file mode 100644 index 0000000..6228f25 --- /dev/null +++ b/src/com/google/gct/idea/settings/ExportSettings.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.gct.idea.settings; + +import com.intellij.ide.IdeBundle; +import com.intellij.ide.plugins.IdeaPluginDescriptor; +import com.intellij.ide.plugins.PluginManager; +import com.intellij.ide.plugins.PluginManagerCore; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.components.ExportableApplicationComponent; +import com.intellij.openapi.components.ExportableComponent; +import com.intellij.openapi.components.ServiceBean; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.io.ZipUtil; + + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.*; +import java.util.jar.JarOutputStream; + +/** + * Provides functionality to export the IDEA settings into a specified jar + */ +public class ExportSettings { + // TODO: use ImportSettings.SETTINGS_JAR_MARKER after merge + public static final String SETTINGS_JAR_MARKER = "IntelliJ IDEA Global Settings"; + + public static void doExport(String path) { + final Set<ExportableComponent> exportableComponents = + new HashSet<ExportableComponent>(Arrays.asList(ApplicationManager.getApplication().getComponents(ExportableApplicationComponent.class))); + exportableComponents.addAll(ServiceBean.loadServicesFromBeans(ExportableComponent.EXTENSION_POINT, ExportableComponent.class)); + + if (exportableComponents.isEmpty()) { + return; + } + + Set<File> exportFiles = new HashSet<File>(); + for (final ExportableComponent markedComponent : exportableComponents) { + ContainerUtil.addAll(exportFiles, markedComponent.getExportFiles()); + } + + ApplicationManager.getApplication().saveSettings(); + + final File saveFile = new File(path); + try { + if (saveFile.exists()) { + final int ret = Messages + .showOkCancelDialog(IdeBundle.message("prompt.overwrite.settings.file", FileUtil.toSystemDependentName(saveFile.getPath())), + IdeBundle.message("title.file.already.exists"), Messages.getWarningIcon()); + if (ret != Messages.OK) return; + } + + final JarOutputStream output = new JarOutputStream(new FileOutputStream(saveFile)); + try { + final File configPath = new File(PathManager.getConfigPath()); + final HashSet<String> writtenItemRelativePaths = new HashSet<String>(); + for (File file : exportFiles) { + final String rPath = FileUtil.getRelativePath(configPath, file); + assert rPath != null; + final String relativePath = FileUtil.toSystemIndependentName(rPath); + if (file.exists()) { + ZipUtil.addFileOrDirRecursively(output, saveFile, file, relativePath, null, writtenItemRelativePaths); + } + } + + exportInstalledPlugins(saveFile, output, writtenItemRelativePaths); + + final File magicFile = new File(FileUtil.getTempDirectory(), SETTINGS_JAR_MARKER); + FileUtil.createIfDoesntExist(magicFile); + magicFile.deleteOnExit(); + ZipUtil.addFileToZip(output, magicFile, SETTINGS_JAR_MARKER, writtenItemRelativePaths, null); + } + finally { + output.close(); + } + } + catch (IOException e1) { + Messages.showErrorDialog(IdeBundle.message("error.writing.settings", e1.toString()),IdeBundle.message("title.error.writing.file")); + } + + } + + private static void exportInstalledPlugins(File saveFile, JarOutputStream output, HashSet<String> writtenItemRelativePaths) throws IOException { + final List<String> oldPlugins = new ArrayList<String>(); + for (IdeaPluginDescriptor descriptor : PluginManagerCore.getPlugins()) { + if (!descriptor.isBundled() && descriptor.isEnabled()) { + oldPlugins.add(descriptor.getPluginId().getIdString()); + } + } + if (!oldPlugins.isEmpty()) { + final File tempFile = File.createTempFile("installed", "plugins"); + tempFile.deleteOnExit(); + PluginManagerCore.savePluginsList(oldPlugins, false, tempFile); + ZipUtil.addDirToZipRecursively(output, saveFile, tempFile, "/" + PluginManager.INSTALLED_TXT, null, writtenItemRelativePaths); + } + } +} diff --git a/src/com/google/gct/idea/settings/ImportSettings.java b/src/com/google/gct/idea/settings/ImportSettings.java new file mode 100644 index 0000000..a509fc6 --- /dev/null +++ b/src/com/google/gct/idea/settings/ImportSettings.java @@ -0,0 +1,137 @@ +package com.google.gct.idea.settings; + +import com.google.common.annotations.VisibleForTesting; +import com.intellij.ide.IdeBundle; +import com.intellij.ide.actions.ImportSettingsFilenameFilter; +import com.intellij.ide.plugins.PluginManager; +import com.intellij.ide.startup.StartupActionScriptManager; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ApplicationNamesInfo; +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.application.ex.ApplicationEx; +import com.intellij.openapi.components.ExportableApplicationComponent; +import com.intellij.openapi.components.ExportableComponent; +import com.intellij.openapi.components.ServiceBean; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.updateSettings.impl.UpdateSettings; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.util.io.ZipUtil; + +import java.io.File; +import java.io.IOException; +import java.util.*; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; + +/** + * Provides functionality to update IDEA setting from a jar containing new settings + */ +public class ImportSettings { + private static final String DIALOG_TITLE = "Setting Synchronization"; + public static final String SETTINGS_JAR_MARKER = "IntelliJ IDEA Global Settings"; + + /** + * Parse and update the IDEA settings in the jar at <code>path</code>. + * Note: This function might require a restart of the application. + * @param path The location of the jar with the new IDEA settings. + */ + public static void doImport(String path) { + final File saveFile = new File(path); + try { + if (!saveFile.exists()) { + Messages.showErrorDialog(IdeBundle.message("error.cannot.find.file", presentableFileName(saveFile)), DIALOG_TITLE); + return; + } + + // What is this file used for? + final ZipEntry magicEntry = new ZipFile(saveFile).getEntry(SETTINGS_JAR_MARKER); + if (magicEntry == null) { + Messages.showErrorDialog("The file " + presentableFileName(saveFile) + " contains no settings to import", + DIALOG_TITLE); + return; + } + + final ArrayList<ExportableComponent> registeredComponents = new ArrayList<ExportableComponent>( + Arrays.asList(ApplicationManager.getApplication().getComponents(ExportableApplicationComponent.class))); + registeredComponents.addAll(ServiceBean.loadServicesFromBeans(ExportableComponent.EXTENSION_POINT, ExportableComponent.class)); + + List<ExportableComponent> storedComponents = getComponentsStored(saveFile, registeredComponents); + + Set<String> relativeNamesToExtract = new HashSet<String>(); + for (final ExportableComponent aComponent : storedComponents) { + final File[] exportFiles = aComponent.getExportFiles(); + for (File exportFile : exportFiles) { + final File configPath = new File(PathManager.getConfigPath()); + final String rPath = FileUtil.getRelativePath(configPath, exportFile); + assert rPath != null; + final String relativePath = FileUtil.toSystemIndependentName(rPath); + relativeNamesToExtract.add(relativePath); + } + } + + relativeNamesToExtract.add(PluginManager.INSTALLED_TXT); + + final File tempFile = new File(PathManager.getPluginTempPath() + "/" + saveFile.getName()); + FileUtil.copy(saveFile, tempFile); + File outDir = new File(PathManager.getConfigPath()); + final ImportSettingsFilenameFilter filenameFilter = new ImportSettingsFilenameFilter(relativeNamesToExtract); + StartupActionScriptManager.ActionCommand unzip = new StartupActionScriptManager.UnzipCommand(tempFile, outDir, filenameFilter); + StartupActionScriptManager.addActionCommand(unzip); + + // remove temp file + StartupActionScriptManager.ActionCommand deleteTemp = new StartupActionScriptManager.DeleteCommand(tempFile); + StartupActionScriptManager.addActionCommand(deleteTemp); + + UpdateSettings.getInstance().forceCheckForUpdateAfterRestart(); + + String key = ApplicationManager.getApplication().isRestartCapable() + ? "message.settings.imported.successfully.restart" + : "message.settings.imported.successfully"; + final int ret = Messages.showOkCancelDialog(IdeBundle.message(key, + ApplicationNamesInfo.getInstance().getProductName(), + ApplicationNamesInfo.getInstance().getFullProductName()), + IdeBundle.message("title.restart.needed"), Messages.getQuestionIcon()); + if (ret == Messages.OK) { + ((ApplicationEx)ApplicationManager.getApplication()).restart(true); + } + } + catch (ZipException e1) { + Messages.showErrorDialog( + "Error reading file " + presentableFileName(saveFile) + ".\\nThere was " + e1.getMessage(), + DIALOG_TITLE); + } + catch (IOException e1) { + Messages.showErrorDialog(IdeBundle.message("error.reading.settings.file.2", presentableFileName(saveFile), e1.getMessage()), + DIALOG_TITLE); + } + } + + private static String presentableFileName(final File file) { + return "'" + FileUtil.toSystemDependentName(file.getPath()) + "'"; + } + + private static List<ExportableComponent> getComponentsStored(File zipFile, + ArrayList<ExportableComponent> registeredComponents) + throws IOException { + final File configPath = new File(PathManager.getConfigPath()); + + final ArrayList<ExportableComponent> components = new ArrayList<ExportableComponent>(); + for (ExportableComponent component : registeredComponents) { + final File[] exportFiles = component.getExportFiles(); + for (File exportFile : exportFiles) { + final String rPath = FileUtil.getRelativePath(configPath, exportFile); + assert rPath != null; + String relativePath = FileUtil.toSystemIndependentName(rPath); + if (exportFile.isDirectory()) relativePath += "/"; + if (ZipUtil.isZipContainsEntry(zipFile, relativePath)) { + components.add(component); + break; + } + } + } + return components; + } +} |