IDEA-214862 Update plugins while working with. IDE IDEA-214865 Plugin update notifications

GitOrigin-RevId: 393dadb1fd889fdc1f2f3468f1a5ba5174135c1c
This commit is contained in:
Alexander Lobas
2019-12-27 16:07:31 +00:00
committed by intellij-monorepo-bot
parent 1f57e524db
commit 1668c7446e
6 changed files with 141 additions and 7 deletions
@@ -41,6 +41,13 @@ public final class InstalledPluginsState {
}
}
@NotNull
public Collection<PluginId> getUpdatedPlugins() {
synchronized (myLock) {
return Collections.unmodifiableCollection(myUpdatedPlugins);
}
}
public boolean hasNewerVersion(@NotNull PluginId id) {
synchronized (myLock) {
return !wasUpdated(id) && myOutdatedPlugins.contains(id.getIdString());
@@ -1340,6 +1340,11 @@ public class PluginManagerConfigurable
});
}
public static void showPluginConfigurable(@Nullable Project project, @NotNull IdeaPluginDescriptor... descriptors) {
PluginManagerConfigurable configurable = new PluginManagerConfigurable();
ShowSettingsUtil.getInstance().editConfigurable(project, configurable, () -> configurable.select(descriptors));
}
private enum SortBySearchOption {
Downloads, Name, Rating, Relevance, Updated
}
@@ -300,11 +300,10 @@ public class PluginUpdateDialog extends DialogWrapper {
}
private static Set<String> myIgnoredPluginsWithVersions;
private static final String DISABLED_UPDATE = "plugin_disabled_updates.txt";
@NotNull
private static File getDisabledUpdateFile() {
return new File(PathManager.getConfigPath(), DISABLED_UPDATE);
return new File(PathManager.getConfigPath(), "plugin_disabled_updates.txt");
}
@NotNull
@@ -327,7 +326,7 @@ public class PluginUpdateDialog extends DialogWrapper {
return myIgnoredPluginsWithVersions;
}
private static void ignorePlugins(@NotNull List<IdeaPluginDescriptor> descriptors) {
static void ignorePlugins(@NotNull List<IdeaPluginDescriptor> descriptors) {
Set<String> ignoredPlugins = getIgnoredPlugins();
for (IdeaPluginDescriptor descriptor : descriptors) {
@@ -387,7 +387,7 @@ object UpdateChecker {
showNotification(project, title, "", {
IdeUpdateUsageTriggerCollector.trigger("notification.clicked")
runnable()
}, NotificationUniqueType.PLATFORM)
}, null, NotificationUniqueType.PLATFORM)
}
return
}
@@ -404,10 +404,18 @@ object UpdateChecker {
runnable.invoke()
}
else {
val title = IdeBundle.message("updates.plugins.ready.title.available", ApplicationNamesInfo.getInstance().fullProductName)
val title = IdeBundle.message("updates.plugins.ready.short.title.available")
val plugins = updatedPlugins.joinToString { downloader -> downloader.pluginName }
val message = IdeBundle.message("updates.plugins.ready.message", updatedPlugins.size, plugins)
showNotification(project, title, message, runnable, NotificationUniqueType.PLUGINS)
showNotification(project, title, message, runnable, { notification ->
notification.addAction(object : NotificationAction(
IdeBundle.message(if (updatedPlugins.size == 1) "updates.ignore.update.button" else "updates.ignore.updates.button")) {
override fun actionPerformed(e: AnActionEvent, notification: Notification) {
notification.expire()
PluginUpdateDialog.ignorePlugins(updatedPlugins.map { downloader -> downloader.descriptor })
}
})
}, NotificationUniqueType.PLUGINS)
}
}
@@ -426,7 +434,7 @@ object UpdateChecker {
val title = IdeBundle.message("updates.plugins.ready.title.available", ApplicationNamesInfo.getInstance().fullProductName)
val updates = update.components.joinToString(", ")
val message = IdeBundle.message("updates.external.ready.message", update.components.size, updates)
showNotification(project, title, message, runnable, NotificationUniqueType.EXTERNAL)
showNotification(project, title, message, runnable, null, NotificationUniqueType.EXTERNAL)
}
}
}
@@ -440,6 +448,7 @@ object UpdateChecker {
title: String,
message: String,
action: () -> Unit,
extraBuilder: ((Notification) -> Unit)?,
notificationType: NotificationUniqueType) {
val notification = getNotificationGroup().createNotification(title, XmlStringUtil.wrapInHtml(message), NotificationType.INFORMATION, null)
notification.addAction(object : NotificationAction(IdeBundle.message("updates.notification.update.action")) {
@@ -448,6 +457,7 @@ object UpdateChecker {
action.invoke()
}
})
extraBuilder?.invoke(notification)
notification.whenExpired { ourShownNotifications.remove(notificationType, notification) }
notification.notify(project)
ourShownNotifications.putValue(notificationType, notification)
@@ -2,16 +2,24 @@
package com.intellij.openapi.updateSettings.impl;
import com.intellij.execution.process.ProcessIOExecutorService;
import com.intellij.ide.DataManager;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.InstalledPluginsState;
import com.intellij.ide.plugins.PluginManagerConfigurable;
import com.intellij.ide.plugins.PluginManagerCore;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationAction;
import com.intellij.notification.NotificationListener;
import com.intellij.notification.NotificationType;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.application.*;
import com.intellij.openapi.application.ex.ApplicationInfoEx;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.impl.HTMLEditorProvider;
import com.intellij.openapi.project.Project;
@@ -20,8 +28,11 @@ import com.intellij.openapi.project.ProjectManagerListener;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.updateSettings.UpdateStrategyCustomization;
import com.intellij.openapi.util.BuildNumber;
import com.intellij.openapi.util.ShutDownTracker;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.util.LineSeparator;
import com.intellij.util.concurrency.AppExecutorUtil;
import com.intellij.util.concurrency.NonUrgentExecutor;
import com.intellij.util.messages.MessageBusConnection;
@@ -30,8 +41,13 @@ import org.jdom.JDOMException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.awt.event.InputEvent;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.List;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
@@ -75,6 +91,8 @@ public final class UpdateCheckerComponent implements Runnable {
showWhatsNewNotification(project);
}
showUpdatedPluginsNotification(project);
ProcessIOExecutorService.INSTANCE.execute(() -> UpdateInstaller.cleanupPatch());
});
}
@@ -225,4 +243,97 @@ public final class UpdateCheckerComponent implements Runnable {
UpdateSettings.getInstance().saveLastCheckedInfo();
}
}
private static void showUpdatedPluginsNotification(@NotNull Project project) {
if (ApplicationManager.getApplication().isUnitTestMode()) {
return;
}
ShutDownTracker.getInstance().registerShutdownTask(() -> {
Collection<PluginId> plugins = InstalledPluginsState.getInstance().getUpdatedPlugins();
if (plugins.isEmpty()) {
return;
}
Set<String> list = getUpdatedPlugins();
for (PluginId plugin : plugins) {
list.add(plugin.getIdString());
}
try {
FileUtil.writeToFile(getUpdatedPluginsFile(), StringUtil.join(list, LineSeparator.getSystemLineSeparator().getSeparatorString()));
}
catch (IOException e) {
LOG.warn(e);
}
});
Set<String> list = getUpdatedPlugins();
if (list.isEmpty()) {
return;
}
List<IdeaPluginDescriptor> descriptors = new ArrayList<>();
for (String id : list) {
PluginId pluginId = PluginId.findId(id);
if (pluginId != null) {
IdeaPluginDescriptor descriptor = PluginManagerCore.getPlugin(pluginId);
if (descriptor != null) {
descriptors.add(descriptor);
}
}
}
if (descriptors.isEmpty()) {
return;
}
String title = IdeBundle.message("update.installed.notification.title");
String message = "<html>" + StringUtil.join(descriptors, descriptor -> {
return "<a href='" + descriptor.getPluginId().getIdString() + "'>" + descriptor.getName() + "</a>";
}, ", ") + "</html>";
UpdateChecker.getNotificationGroup().createNotification(title, message, NotificationType.INFORMATION, (notification, event) -> {
String id = event.getDescription();
if (id == null) {
return;
}
PluginId pluginId = PluginId.findId(id);
if (pluginId == null) {
return;
}
IdeaPluginDescriptor descriptor = PluginManagerCore.getPlugin(pluginId);
if (descriptor == null) {
return;
}
InputEvent inputEvent = event.getInputEvent();
Component component = inputEvent == null ? null : inputEvent.getComponent();
DataProvider provider = component == null ? null : DataManager.getDataProvider((JComponent)component);
PluginManagerConfigurable.showPluginConfigurable(provider == null ? null : CommonDataKeys.PROJECT.getData(provider), descriptor);
}).notify(project);
}
@NotNull
private static Set<String> getUpdatedPlugins() {
try {
File file = getUpdatedPluginsFile();
if (file.isFile()) {
List<String> list = FileUtil.loadLines(file);
FileUtil.delete(file);
return new HashSet<>(list);
}
}
catch (IOException e) {
LOG.warn(e);
}
return new HashSet<>();
}
@NotNull
private static File getUpdatedPluginsFile() {
return new File(PathManager.getConfigPath(), ".updated_plugins_list");
}
}
@@ -947,11 +947,13 @@ updates.interim.build=You can use the new version until your subscription expire
updates.new.build.notification.title={0} {1} available
updates.notification.update.action=Update...
updates.ready.message={0} is ready to <a href=\"update\">update</a>.
update.installed.notification.title=Plugin updates installed
updates.external.progress=Fetching available updates for external components
updates.external.ready.message={0,choice,1#Component|2#Components}: {1}
updates.external.error.message=Failed to check for updates to {0}: {1}
updates.plugins.ready.title={0} and plugin updates
updates.plugins.ready.title.available={0} and plugin updates available
updates.plugins.ready.short.title.available=Plugin updates available
updates.plugins.ready.message={0,choice,1#Plugin|2#Plugins}: {1}
updates.no.updates.message=You already have the latest version of {0} and plugins installed.
updates.no.updates.toolbox.message=<html>All plugins are up to date.<br> \