mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-252419 Quick Access Menu to Themes, Plugins, Keymaps and IDE/Plugin updates
GitOrigin-RevId: fc66de1f90999e421870545817cadc33c27214fc
This commit is contained in:
committed by
intellij-monorepo-bot
parent
0fafd5eeb7
commit
0c2028d2e5
@@ -0,0 +1,5 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="16" height="16" rx="8" fill="#EDA200"/>
|
||||
<rect x="8.80005" y="4.8" width="7.2" height="1.6" transform="rotate(90 8.80005 4.8)" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 4L12 8L4 8L8 4Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 346 B |
@@ -0,0 +1,5 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="16" height="16" rx="8" fill="#F0A732"/>
|
||||
<rect x="8.80005" y="4.8" width="7.2" height="1.6" transform="rotate(90 8.80005 4.8)" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 4L12 8L4 8L8 4Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 346 B |
@@ -0,0 +1,5 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="16" height="16" rx="8" fill="#389FD6"/>
|
||||
<rect x="8.80005" y="4.8" width="7.2" height="1.6" transform="rotate(90 8.80005 4.8)" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 4L12 8L4 8L8 4Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 346 B |
@@ -0,0 +1,5 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="16" height="16" rx="8" fill="#3592C4"/>
|
||||
<rect x="8.80005" y="4.8" width="7.2" height="1.6" transform="rotate(90 8.80005 4.8)" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 4L12 8L4 8L8 4Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 346 B |
@@ -2403,8 +2403,19 @@ wsl.linux.distribution.label=Linux &distribution:
|
||||
wsl.no.available.distributions=No available distributions
|
||||
|
||||
name.variable=File name entered in the dialog
|
||||
action.plugins.text=Plugins...
|
||||
settings.entry.point.tooltip=IDE and Project Settings
|
||||
settings.entry.point.update.tooltip=Updates available. IDE and Project Settings
|
||||
settings.entry.point.update.ide.action=Download {0} {1}
|
||||
settings.entry.point.update.plugin.action=Update {0} Plugin...
|
||||
settings.entry.point.update.plugins.action=Update Plugins...
|
||||
settings.entry.point.update.plugins.more.action=and {0} more
|
||||
template.file.name=Template to generate file name and path
|
||||
template.file.name.optional=Template to generate file name and path (optional)
|
||||
updates.settings.show.editor=Show What's New in the editor after an IDE update
|
||||
plugin.version.bundled=bundled
|
||||
commit.step.user.cancelled=User cancelled
|
||||
laf.action.install.theme=Install Theme...
|
||||
keymap.action.configure.keymap=Configure Keymap...
|
||||
keymap.action.install.keymap=Install Keymap...
|
||||
settings.entry.point.got.it.popup=Quickly access the main IDE and project settings, and execute commands.
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.intellij.notification;
|
||||
* @author spleaner
|
||||
*/
|
||||
public enum NotificationType {
|
||||
IDE_UPDATE,
|
||||
INFORMATION,
|
||||
WARNING,
|
||||
ERROR
|
||||
|
||||
@@ -15,7 +15,7 @@ public interface WelcomeScreenTab {
|
||||
* @return component presents list item on the {@link WelcomeScreen} tab view
|
||||
*/
|
||||
@NotNull
|
||||
JComponent getKeyComponent();
|
||||
JComponent getKeyComponent(@NotNull JList<? extends WelcomeScreenTab> list);
|
||||
|
||||
/**
|
||||
* @return component shown when related key component is selected
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
package com.intellij.ide.actions;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
||||
@@ -10,7 +11,9 @@ import com.intellij.openapi.keymap.KeymapManager;
|
||||
import com.intellij.openapi.keymap.ex.KeymapManagerEx;
|
||||
import com.intellij.openapi.keymap.impl.KeymapManagerImpl;
|
||||
import com.intellij.openapi.keymap.impl.KeymapManagerImplKt;
|
||||
import com.intellij.openapi.keymap.impl.ui.KeymapPanel;
|
||||
import com.intellij.openapi.keymap.impl.ui.KeymapSchemeManager;
|
||||
import com.intellij.openapi.options.ShowSettingsUtil;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -28,6 +31,14 @@ public final class QuickChangeKeymapAction extends QuickSwitchSchemeAction {
|
||||
for (Keymap keymap : list) {
|
||||
addKeymapAction(group, manager, current, keymap);
|
||||
}
|
||||
group.addSeparator();
|
||||
group.add(new DumbAwareAction(IdeBundle.message("keymap.action.configure.keymap")) {
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
ShowSettingsUtil.getInstance().showSettingsDialog(e.getProject(), KeymapPanel.class);
|
||||
}
|
||||
});
|
||||
group.add(new ShowPluginsWithSearchOptionAction(IdeBundle.message("keymap.action.install.keymap"), "/tag:Keymap"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
package com.intellij.ide.actions;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.ide.ui.LafManager;
|
||||
import com.intellij.ide.ui.LafManagerListener;
|
||||
import com.intellij.ide.ui.laf.darcula.DarculaInstaller;
|
||||
@@ -27,6 +28,7 @@ import javax.swing.*;
|
||||
public class QuickChangeLookAndFeel extends QuickSwitchSchemeAction {
|
||||
private UIManager.LookAndFeelInfo initialLaf;
|
||||
private final Alarm switchAlarm = new Alarm();
|
||||
private boolean myLafActionSelection;
|
||||
|
||||
@Override
|
||||
protected void fillActions(Project project, @NotNull DefaultActionGroup group, @NotNull DataContext dataContext) {
|
||||
@@ -37,6 +39,9 @@ public class QuickChangeLookAndFeel extends QuickSwitchSchemeAction {
|
||||
for (UIManager.LookAndFeelInfo lf : lfs) {
|
||||
group.add(new LafChangeAction(lf, initialLaf == lf));
|
||||
}
|
||||
|
||||
group.addSeparator();
|
||||
group.add(new ShowPluginsWithSearchOptionAction(IdeBundle.message("laf.action.install.theme"), "/tag:Theme"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -44,14 +49,17 @@ public class QuickChangeLookAndFeel extends QuickSwitchSchemeAction {
|
||||
switchAlarm.cancelAllRequests();
|
||||
if (Registry.is("ide.instant.theme.switch")) {
|
||||
popup.addListSelectionListener(event -> {
|
||||
JList list = (JList)event.getSource();
|
||||
Object item = list.getSelectedValue();
|
||||
Object item = ((JList)event.getSource()).getSelectedValue();
|
||||
if (item instanceof AnActionHolder) {
|
||||
switchAlarm.cancelAllRequests();
|
||||
switchAlarm.addRequest(() -> {
|
||||
LafChangeAction action = (LafChangeAction)((AnActionHolder)item).getAction();
|
||||
switchLafAndUpdateUI(LafManager.getInstance(), action.myLookAndFeelInfo, false);
|
||||
}, Registry.get("ide.instant.theme.switch.delay").asInteger());
|
||||
AnAction anAction = ((AnActionHolder)item).getAction();
|
||||
myLafActionSelection = anAction instanceof LafChangeAction;
|
||||
if (myLafActionSelection) {
|
||||
switchAlarm.cancelAllRequests();
|
||||
switchAlarm.addRequest(() -> {
|
||||
LafChangeAction action = (LafChangeAction)anAction;
|
||||
switchLafAndUpdateUI(LafManager.getInstance(), action.myLookAndFeelInfo, false);
|
||||
}, Registry.get("ide.instant.theme.switch.delay").asInteger());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -59,7 +67,7 @@ public class QuickChangeLookAndFeel extends QuickSwitchSchemeAction {
|
||||
popup.addListener(new JBPopupListener() {
|
||||
@Override
|
||||
public void onClosed(@NotNull LightweightWindowEvent event) {
|
||||
if (Registry.is("ide.instant.theme.switch") && !event.isOk()) {
|
||||
if (Registry.is("ide.instant.theme.switch") && !event.isOk() && myLafActionSelection) {
|
||||
switchLafAndUpdateUI(LafManager.getInstance(), initialLaf, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,483 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ide.actions;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.ide.plugins.IdeaPluginDescriptor;
|
||||
import com.intellij.ide.plugins.PluginManagerCore;
|
||||
import com.intellij.ide.plugins.PluginStateListener;
|
||||
import com.intellij.ide.plugins.PluginStateManager;
|
||||
import com.intellij.ide.plugins.newui.PluginUpdatesService;
|
||||
import com.intellij.ide.ui.UISettings;
|
||||
import com.intellij.ide.ui.UISettingsListener;
|
||||
import com.intellij.ide.util.PropertiesComponent;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.actionSystem.ex.CustomComponentAction;
|
||||
import com.intellij.openapi.actionSystem.ex.TooltipDescriptionProvider;
|
||||
import com.intellij.openapi.actionSystem.impl.ActionButton;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ApplicationNamesInfo;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.extensions.PluginId;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.ui.popup.*;
|
||||
import com.intellij.openapi.updateSettings.impl.CheckForUpdateResult;
|
||||
import com.intellij.openapi.updateSettings.impl.PluginDownloader;
|
||||
import com.intellij.openapi.updateSettings.impl.PluginUpdateDialog;
|
||||
import com.intellij.openapi.updateSettings.impl.UpdateInfoDialog;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.wm.*;
|
||||
import com.intellij.openapi.wm.impl.status.IdeStatusBarImpl;
|
||||
import com.intellij.openapi.wm.impl.status.widget.StatusBarWidgetsManager;
|
||||
import com.intellij.ui.GotItTooltip;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.ui.update.UiNotifyConnector;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Alexander Lobas
|
||||
*/
|
||||
public class SettingsEntryPointAction extends AnAction implements DumbAware, RightAlignedToolbarAction, AnAction.TransparentUpdate,
|
||||
TooltipDescriptionProvider, CustomComponentAction {
|
||||
private Icon myIcon;
|
||||
|
||||
public SettingsEntryPointAction() {
|
||||
initPluginsListeners();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull JComponent createCustomComponent(@NotNull Presentation presentation, @NotNull String place) {
|
||||
ActionButton button = new ActionButton(this, presentation, place, ActionToolbar.DEFAULT_MINIMUM_BUTTON_SIZE);
|
||||
|
||||
UiNotifyConnector.doWhenFirstShown(button, () -> {
|
||||
Disposable disposable = Disposer.newDisposable();
|
||||
|
||||
Balloon balloon = createGotItTooltip(disposable).showAt(Balloon.Position.below, button, component -> {
|
||||
PropertiesComponent.getInstance().setValue(GotItTooltip.PROPERTY_PREFIX + ".settings.entry.point", "0");
|
||||
return new Point(component.getWidth() / 2, component.getHeight());
|
||||
});
|
||||
|
||||
if (balloon == null) {
|
||||
Disposer.dispose(disposable);
|
||||
}
|
||||
else {
|
||||
new MyListener(button.getParent(), balloon, disposable);
|
||||
}
|
||||
});
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
private static class MyListener extends ComponentAdapter implements HierarchyListener {
|
||||
private final Component myComponent;
|
||||
private final Balloon myBalloon;
|
||||
private final Disposable myDisposable;
|
||||
|
||||
private MyListener(@NotNull Component component, @NotNull Balloon balloon, @NotNull Disposable disposable) {
|
||||
myComponent = component;
|
||||
myBalloon = balloon;
|
||||
myDisposable = disposable;
|
||||
|
||||
myComponent.addComponentListener(this);
|
||||
myComponent.addHierarchyListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentResized(ComponentEvent e) {
|
||||
handle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentMoved(ComponentEvent e) {
|
||||
handle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentHidden(ComponentEvent e) {
|
||||
handle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hierarchyChanged(HierarchyEvent e) {
|
||||
handle();
|
||||
}
|
||||
|
||||
private void handle() {
|
||||
if (myComponent.isShowing() && !myBalloon.isDisposed()) {
|
||||
myBalloon.revalidate();
|
||||
}
|
||||
else {
|
||||
myComponent.removeComponentListener(this);
|
||||
myComponent.removeHierarchyListener(this);
|
||||
Disposer.dispose(myDisposable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
myIcon = AllIcons.General.GearPlain;
|
||||
// XXX update toolbar action
|
||||
|
||||
ListPopup popup = createMainPopup(e.getDataContext());
|
||||
popup.addListener(new JBPopupListener() {
|
||||
@Override
|
||||
public void onClosed(@NotNull LightweightWindowEvent event) {
|
||||
myIcon = null;
|
||||
// XXX update toolbar action
|
||||
}
|
||||
});
|
||||
|
||||
InputEvent inputEvent = e.getInputEvent();
|
||||
if (inputEvent == null) {
|
||||
popup.showInFocusCenter();
|
||||
}
|
||||
else {
|
||||
Component component = inputEvent.getComponent();
|
||||
if (component instanceof ActionButtonComponent) {
|
||||
popup.showUnderneathOf(component);
|
||||
}
|
||||
else {
|
||||
popup.showInCenterOf(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(@NotNull AnActionEvent e) {
|
||||
Presentation presentation = e.getPresentation();
|
||||
presentation.setDescription(SettingsEntryPointAction::getActionTooltip);
|
||||
presentation.setIcon(myIcon == null ? getActionIcon() : myIcon);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static ListPopup createMainPopup(@NotNull DataContext context) {
|
||||
DefaultActionGroup group = new DefaultActionGroup();
|
||||
|
||||
if (myPlatformUpdateInfo != null) {
|
||||
group.add(new DumbAwareAction(IdeBundle.message("settings.entry.point.update.ide.action",
|
||||
ApplicationNamesInfo.getInstance().getFullProductName(),
|
||||
myPlatformUpdateInfo.getNewBuild().getVersion()),
|
||||
null, AllIcons.Ide.Notification.IdeUpdate) {
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
if (myPlatformUpdateInfo.getPatches() == null ||
|
||||
(!SystemInfo.isWindows && !Files.isWritable(Paths.get(PathManager.getHomePath())))) {
|
||||
new UpdateInfoDialog(myPlatformUpdateInfo.getUpdatedChannel(), myPlatformUpdateInfo.getNewBuild(), null, true, null,
|
||||
myIncompatiblePlugins).show();
|
||||
}
|
||||
else {
|
||||
CheckForUpdateResult platformUpdateInfo = myPlatformUpdateInfo;
|
||||
newPlatformUpdate(null, null);
|
||||
|
||||
ActionCallback callback = new ActionCallback().doWhenRejected(() -> {
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
newPlatformUpdate(platformUpdateInfo, null);
|
||||
}, ModalityState.any());
|
||||
});
|
||||
|
||||
UpdateInfoDialog.downloadPatchAndRestart(platformUpdateInfo.getNewBuild(), platformUpdateInfo.getUpdatedChannel(),
|
||||
platformUpdateInfo.getPatches(), null, null, callback);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (myUpdatedPlugins != null) {
|
||||
int size = myUpdatedPlugins.size();
|
||||
|
||||
String name = size == 1
|
||||
? IdeBundle.message("settings.entry.point.update.plugin.action", myUpdatedPlugins.iterator().next().getPluginName())
|
||||
: IdeBundle.message("settings.entry.point.update.plugins.action");
|
||||
group.add(new DumbAwareAction(name, null, AllIcons.Ide.Notification.PluginUpdate) {
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
new PluginUpdateDialog(e.getProject(), myUpdatedPlugins, myCustomRepositoryPlugins).show();
|
||||
}
|
||||
});
|
||||
if (size > 1) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
int count = 0;
|
||||
|
||||
for (PluginDownloader plugin : myUpdatedPlugins) {
|
||||
if (result.length() > 0) {
|
||||
result.append(", ");
|
||||
}
|
||||
result.append(plugin.getPluginName());
|
||||
count++;
|
||||
if (count == 2) {
|
||||
int delta = size - count;
|
||||
if (delta > 0) {
|
||||
result.append(" ").append(IdeBundle.message("settings.entry.point.update.plugins.more.action", delta));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@NlsSafe String actionName = result.toString();
|
||||
group.add(new AnAction(actionName) {
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(@NotNull AnActionEvent e) {
|
||||
e.getPresentation().setEnabled(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
group.addSeparator();
|
||||
|
||||
ActionGroup templateGroup = (ActionGroup)ActionManager.getInstance().getAction("SettingsEntryPointGroup");
|
||||
for (AnAction child : templateGroup.getChildren(null)) {
|
||||
group.add(child);
|
||||
}
|
||||
|
||||
return JBPopupFactory.getInstance().createActionGroupPopup(null, group, context, JBPopupFactory.ActionSelectionAid.MNEMONICS, true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static GotItTooltip createGotItTooltip(@NotNull Disposable disposable) {
|
||||
return new GotItTooltip("settings.entry.point", IdeBundle.message("settings.entry.point.got.it.popup"), disposable);
|
||||
}
|
||||
|
||||
private static PluginUpdatesService myUpdatesService;
|
||||
private static PluginStateListener myPluginStateListener;
|
||||
|
||||
private static void initPluginsListeners() {
|
||||
if (myUpdatesService == null) {
|
||||
myUpdatesService = PluginUpdatesService.connectWithUpdates(descriptors -> {
|
||||
List<PluginDownloader> downloaders = new ArrayList<>();
|
||||
try {
|
||||
for (IdeaPluginDescriptor descriptor : descriptors) {
|
||||
downloaders.add(PluginDownloader.createDownloader(descriptor));
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
PluginManagerCore.getLogger().error(e);
|
||||
}
|
||||
newPluginsUpdate(downloaders.isEmpty() ? null : downloaders, null);
|
||||
});
|
||||
}
|
||||
if (myPluginStateListener == null) {
|
||||
PluginStateManager.addStateListener(myPluginStateListener = new PluginStateListener() {
|
||||
@Override
|
||||
public void install(@NotNull IdeaPluginDescriptor descriptor) {
|
||||
if (myUpdatedPlugins != null) {
|
||||
PluginId pluginId = descriptor.getPluginId();
|
||||
List<PluginDownloader> updatedPlugins =
|
||||
ContainerUtil.filter(myUpdatedPlugins, downloader -> !pluginId.equals(downloader.getId()));
|
||||
if (myUpdatedPlugins.size() != updatedPlugins.size()) {
|
||||
newPluginsUpdate(updatedPlugins.isEmpty() ? null : updatedPlugins, myCustomRepositoryPlugins);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninstall(@NotNull IdeaPluginDescriptor descriptor) {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static CheckForUpdateResult myPlatformUpdateInfo;
|
||||
private static Collection<IdeaPluginDescriptor> myIncompatiblePlugins;
|
||||
|
||||
private static Collection<PluginDownloader> myUpdatedPlugins;
|
||||
private static Collection<IdeaPluginDescriptor> myCustomRepositoryPlugins;
|
||||
|
||||
public static void newPlatformUpdate(@Nullable CheckForUpdateResult platformUpdateInfo,
|
||||
@Nullable Collection<IdeaPluginDescriptor> incompatiblePlugins) {
|
||||
myPlatformUpdateInfo = platformUpdateInfo;
|
||||
myIncompatiblePlugins = incompatiblePlugins;
|
||||
updateAction();
|
||||
}
|
||||
|
||||
public static void newPluginsUpdate(@Nullable Collection<PluginDownloader> updatedPlugins,
|
||||
@Nullable Collection<IdeaPluginDescriptor> customRepositoryPlugins) {
|
||||
myUpdatedPlugins = updatedPlugins;
|
||||
myCustomRepositoryPlugins = customRepositoryPlugins;
|
||||
updateAction();
|
||||
}
|
||||
|
||||
private static void updateAction() {
|
||||
if (isAvailableInStatusBar()) {
|
||||
updateWidgets();
|
||||
}
|
||||
// XXX update toolbar action
|
||||
}
|
||||
|
||||
private static @NotNull @Nls String getActionTooltip() {
|
||||
return myPlatformUpdateInfo == null && myUpdatedPlugins == null
|
||||
? IdeBundle.message("settings.entry.point.tooltip")
|
||||
: IdeBundle.message("settings.entry.point.update.tooltip");
|
||||
}
|
||||
|
||||
private static @NotNull Icon getActionIcon() {
|
||||
if (myPlatformUpdateInfo != null) {
|
||||
return AllIcons.Ide.Notification.IdeUpdate;
|
||||
}
|
||||
if (myUpdatedPlugins != null) {
|
||||
return AllIcons.Ide.Notification.PluginUpdate;
|
||||
}
|
||||
return AllIcons.General.GearPlain;
|
||||
}
|
||||
|
||||
private static UISettingsListener mySettingsListener;
|
||||
|
||||
private static void initUISettingsListener() {
|
||||
if (mySettingsListener == null) {
|
||||
mySettingsListener = uiSettings -> updateWidgets();
|
||||
ApplicationManager.getApplication().getMessageBus().connect().subscribe(UISettingsListener.TOPIC, mySettingsListener);
|
||||
}
|
||||
}
|
||||
|
||||
private static void updateWidgets() {
|
||||
for (Project project : ProjectManager.getInstance().getOpenProjects()) {
|
||||
project.getService(StatusBarWidgetsManager.class).updateWidget(StatusBarManager.class);
|
||||
IdeFrame frame = WindowManager.getInstance().getIdeFrame(project);
|
||||
if (frame != null) {
|
||||
StatusBar statusBar = frame.getStatusBar();
|
||||
if (statusBar != null) {
|
||||
statusBar.updateWidget(WIDGET_ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isAvailableInStatusBar() {
|
||||
initUISettingsListener();
|
||||
|
||||
UISettings settings = UISettings.getInstance();
|
||||
return !settings.getShowMainToolbar() && !settings.getShowToolbarInNavigationBar();
|
||||
}
|
||||
|
||||
private static final String WIDGET_ID = "settingsEntryPointWidget";
|
||||
|
||||
public static class StatusBarManager implements StatusBarWidgetFactory {
|
||||
@Override
|
||||
public @NonNls @NotNull String getId() {
|
||||
return WIDGET_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nls @NotNull String getDisplayName() {
|
||||
return IdeBundle.message("settings.entry.point.tooltip");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull Project project) {
|
||||
return isAvailableInStatusBar();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull StatusBarWidget createWidget(@NotNull Project project) {
|
||||
return new MyStatusBarWidget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disposeWidget(@NotNull StatusBarWidget widget) {
|
||||
Disposer.dispose(widget);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeEnabledOn(@NotNull StatusBar statusBar) {
|
||||
return isAvailableInStatusBar();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConfigurable() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyStatusBarWidget implements StatusBarWidget, StatusBarWidget.IconPresentation {
|
||||
private StatusBar myStatusBar;
|
||||
private Icon myIcon;
|
||||
|
||||
private MyStatusBarWidget() {
|
||||
initPluginsListeners();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNls @NotNull String ID() {
|
||||
return WIDGET_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void install(@NotNull StatusBar statusBar) {
|
||||
myStatusBar = statusBar;
|
||||
|
||||
JComponent component = ((IdeStatusBarImpl)statusBar).getWidgetComponent(WIDGET_ID);
|
||||
if (component != null) {
|
||||
createGotItTooltip(this).showAt(Balloon.Position.above, component, c -> new Point(c.getWidth() / 2, 0));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable WidgetPresentation getPresentation() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable @NlsContexts.Tooltip String getTooltipText() {
|
||||
return getActionTooltip();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Consumer<MouseEvent> getClickConsumer() {
|
||||
return event -> {
|
||||
myIcon = AllIcons.General.GearPlain;
|
||||
myStatusBar.updateWidget(WIDGET_ID);
|
||||
|
||||
Component component = event.getComponent();
|
||||
ListPopup popup = createMainPopup(DataManager.getInstance().getDataContext(component));
|
||||
popup.addListener(new JBPopupListener() {
|
||||
@Override
|
||||
public void beforeShown(@NotNull LightweightWindowEvent event) {
|
||||
Point location = component.getLocationOnScreen();
|
||||
Dimension size = popup.getSize();
|
||||
popup.setLocation(new Point(location.x + component.getWidth() - size.width, location.y - size.height));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClosed(@NotNull LightweightWindowEvent event) {
|
||||
myIcon = null;
|
||||
myStatusBar.updateWidget(WIDGET_ID);
|
||||
}
|
||||
});
|
||||
popup.show(component);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Icon getIcon() {
|
||||
return myIcon == null ? getActionIcon() : myIcon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ide.actions;
|
||||
|
||||
import com.intellij.ide.plugins.PluginManagerConfigurable;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.options.ShowSettingsUtil;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Alexander Lobas
|
||||
*/
|
||||
public class ShowPluginsWithSearchOptionAction extends DumbAwareAction {
|
||||
private final String mySearchOption;
|
||||
|
||||
public ShowPluginsWithSearchOptionAction(@NotNull @Nls String text, @NotNull String searchOption) {
|
||||
super(text);
|
||||
mySearchOption = searchOption;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
ShowSettingsUtil.getInstance().showSettingsDialog(e.getProject(), PluginManagerConfigurable.class, c -> c.enableSearch(mySearchOption));
|
||||
}
|
||||
}
|
||||
@@ -132,6 +132,8 @@ public class PluginManagerConfigurable
|
||||
|
||||
private Collection<IdeaPluginDescriptor> myInitUpdates;
|
||||
|
||||
private String myLaterSearchQuery;
|
||||
|
||||
public PluginManagerConfigurable(@Nullable Project project) {
|
||||
myPluginModel = new MyPluginModel(project);
|
||||
}
|
||||
@@ -203,7 +205,7 @@ public class PluginManagerConfigurable
|
||||
if (myInitUpdates != null) {
|
||||
callback.accept(myInitUpdates.size());
|
||||
}
|
||||
myPluginUpdatesService = PluginUpdatesService.connectConfigurable(callback);
|
||||
myPluginUpdatesService = PluginUpdatesService.connectWithCounter(callback);
|
||||
myPluginModel.setPluginUpdatesService(myPluginUpdatesService);
|
||||
|
||||
boolean selectInstalledTab = !ContainerUtil.isEmpty(myInitUpdates);
|
||||
@@ -236,6 +238,14 @@ public class PluginManagerConfigurable
|
||||
myInstalledTab.setSearchQuery("/outdated");
|
||||
}
|
||||
|
||||
if (myLaterSearchQuery != null) {
|
||||
Runnable search = enableSearch(myLaterSearchQuery);
|
||||
if (search != null) {
|
||||
ApplicationManager.getApplication().invokeLater(search, ModalityState.any());
|
||||
}
|
||||
myLaterSearchQuery = null;
|
||||
}
|
||||
|
||||
return myCardPanel;
|
||||
}
|
||||
|
||||
@@ -893,7 +903,7 @@ public class PluginManagerConfigurable
|
||||
myPluginModel.addEnabledGroup(group);
|
||||
}
|
||||
|
||||
myPluginUpdatesService.connectInstalled(updates -> {
|
||||
myPluginUpdatesService.calculateUpdates(updates -> {
|
||||
if (ContainerUtil.isEmpty(updates)) {
|
||||
clearUpdates(myInstalledPanel);
|
||||
clearUpdates(myInstalledSearchPanel.getPanel());
|
||||
@@ -1157,6 +1167,10 @@ public class PluginManagerConfigurable
|
||||
};
|
||||
|
||||
myPluginModel.setCancelInstallCallback(descriptor -> {
|
||||
if (myInstalledSearchPanel == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
PluginsGroup group = myInstalledSearchPanel.getGroup();
|
||||
|
||||
if (group.ui != null && group.ui.findComponent(descriptor) != null) {
|
||||
@@ -1721,6 +1735,10 @@ public class PluginManagerConfigurable
|
||||
@Nullable
|
||||
@Override
|
||||
public Runnable enableSearch(String option) {
|
||||
if (myTabHeaderComponent == null) {
|
||||
myLaterSearchQuery = option;
|
||||
return null;
|
||||
}
|
||||
if (StringUtil.isEmpty(option) && (myTabHeaderComponent.getSelectionTab() == MARKETPLACE_TAB || myInstalledSearchPanel.isEmpty())) {
|
||||
return null;
|
||||
}
|
||||
@@ -1770,4 +1788,4 @@ public class PluginManagerConfigurable
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-14
@@ -44,14 +44,12 @@ public class PluginManagerConfigurableTreeRenderer extends AncestorListenerAdapt
|
||||
@Nullable UnnamedConfigurable configurable,
|
||||
boolean selected) {
|
||||
if (myTree == null) {
|
||||
myService = PluginUpdatesService.connectTreeRenderer(this);
|
||||
myService = PluginUpdatesService.connectWithCounter(this);
|
||||
tree.addAncestorListener(this);
|
||||
myTree = tree;
|
||||
}
|
||||
|
||||
Icon icon = DynamicBundle.LanguageBundleEP.EP_NAME.hasAnyExtensions() ?
|
||||
AllIcons.General.LocalizationSettings :
|
||||
null;
|
||||
Icon icon = DynamicBundle.LanguageBundleEP.EP_NAME.hasAnyExtensions() ? AllIcons.General.LocalizationSettings : null;
|
||||
if (icon == null && myCountValue == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -61,16 +59,11 @@ public class PluginManagerConfigurableTreeRenderer extends AncestorListenerAdapt
|
||||
myExtraLabel.setIcon(icon);
|
||||
myExtraLabel.setBackground(myCountLabel.getBackground());
|
||||
|
||||
Component component = icon == null ?
|
||||
myCountLabel :
|
||||
myCountValue == null ?
|
||||
myExtraLabel :
|
||||
myPanel;
|
||||
Component component = icon == null ? myCountLabel : myCountValue == null ? myExtraLabel : myPanel;
|
||||
boolean isPanel = component == myPanel;
|
||||
|
||||
return Pair.create(
|
||||
component,
|
||||
(renderer, bounds, text, right, textBaseline) -> {
|
||||
component, (renderer, bounds, text, right, textBaseline) -> {
|
||||
Dimension size = renderer.getPreferredSize();
|
||||
int preferredWidth = size.width;
|
||||
int preferredHeight = size.height;
|
||||
@@ -101,9 +94,7 @@ public class PluginManagerConfigurableTreeRenderer extends AncestorListenerAdapt
|
||||
}
|
||||
|
||||
private int getPreferredShift(boolean isPanel) {
|
||||
return isPanel ?
|
||||
getHGap() + myExtraLabel.getPreferredSize().width / 2 :
|
||||
0;
|
||||
return isPanel ? getHGap() + myExtraLabel.getPreferredSize().width / 2 : 0;
|
||||
}
|
||||
|
||||
private static int getHGap() {
|
||||
|
||||
+109
-130
@@ -13,7 +13,6 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
@@ -25,124 +24,109 @@ import java.util.function.Consumer;
|
||||
*/
|
||||
public class PluginUpdatesService {
|
||||
private static final List<PluginUpdatesService> SERVICES = new ArrayList<>();
|
||||
private static final Object ourLock = new Object();
|
||||
private static Collection<IdeaPluginDescriptor> myCache;
|
||||
private static boolean myPrepared;
|
||||
private static boolean myPreparing;
|
||||
private static boolean myReset;
|
||||
|
||||
private Consumer<? super Integer> myTreeCallback;
|
||||
private Consumer<? super Integer> myTabCallback;
|
||||
private Consumer<? super Collection<IdeaPluginDescriptor>> myInstalledPanelCallback;
|
||||
private Consumer<? super Collection<IdeaPluginDescriptor>> myUpdatePanelCallback;
|
||||
private Consumer<? super Integer> myCountCallback;
|
||||
private Consumer<? super Collection<IdeaPluginDescriptor>> myUpdateCallback;
|
||||
|
||||
@NotNull
|
||||
public static PluginUpdatesService connectTreeRenderer(@NotNull Consumer<? super Integer> callback) {
|
||||
checkAccess();
|
||||
|
||||
public static PluginUpdatesService connectWithCounter(@NotNull Consumer<? super Integer> callback) {
|
||||
PluginUpdatesService service = new PluginUpdatesService();
|
||||
SERVICES.add(service);
|
||||
service.myTreeCallback = callback;
|
||||
service.myCountCallback = callback;
|
||||
|
||||
if (myPrepared) {
|
||||
callback.accept(getCount());
|
||||
}
|
||||
else {
|
||||
calculateUpdates();
|
||||
synchronized (ourLock) {
|
||||
SERVICES.add(service);
|
||||
|
||||
if (myPrepared) {
|
||||
callback.accept(getCount());
|
||||
return service;
|
||||
}
|
||||
}
|
||||
|
||||
calculateUpdates();
|
||||
return service;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PluginUpdatesService connectConfigurable(@NotNull Consumer<? super Integer> callback) {
|
||||
checkAccess();
|
||||
|
||||
public static PluginUpdatesService connectWithUpdates(@NotNull Consumer<? super Collection<IdeaPluginDescriptor>> callback) {
|
||||
PluginUpdatesService service = new PluginUpdatesService();
|
||||
SERVICES.add(service);
|
||||
service.myTabCallback = callback;
|
||||
service.myUpdateCallback = callback;
|
||||
|
||||
if (myPrepared) {
|
||||
callback.accept(getCount());
|
||||
}
|
||||
else {
|
||||
calculateUpdates();
|
||||
synchronized (ourLock) {
|
||||
SERVICES.add(service);
|
||||
|
||||
if (myPrepared) {
|
||||
callback.accept(myCache);
|
||||
}
|
||||
}
|
||||
|
||||
return service;
|
||||
}
|
||||
|
||||
public void connectInstalled(@NotNull Consumer<? super Collection<IdeaPluginDescriptor>> callback) {
|
||||
checkAccess();
|
||||
myInstalledPanelCallback = callback;
|
||||
|
||||
if (myPrepared) {
|
||||
callback.accept(myCache);
|
||||
}
|
||||
else {
|
||||
calculateUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
public void calculateUpdates(@NotNull Consumer<? super Collection<IdeaPluginDescriptor>> callback) {
|
||||
checkAccess();
|
||||
myUpdatePanelCallback = callback;
|
||||
synchronized (ourLock) {
|
||||
myUpdateCallback = callback;
|
||||
|
||||
if (myPrepared) {
|
||||
callback.accept(myCache);
|
||||
}
|
||||
else {
|
||||
calculateUpdates();
|
||||
if (myPrepared) {
|
||||
callback.accept(myCache);
|
||||
return;
|
||||
}
|
||||
}
|
||||
calculateUpdates();
|
||||
}
|
||||
|
||||
public void finishUpdate(@NotNull IdeaPluginDescriptor descriptor) {
|
||||
checkAccess();
|
||||
|
||||
if (!myPrepared || myCache == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Iterator<IdeaPluginDescriptor> I = myCache.iterator(); I.hasNext(); ) {
|
||||
IdeaPluginDescriptor downloadedDescriptor = I.next();
|
||||
|
||||
if (downloadedDescriptor.equals(descriptor)) {
|
||||
I.remove();
|
||||
|
||||
Integer countValue = getCount();
|
||||
for (PluginUpdatesService service : SERVICES) {
|
||||
service.runCountCallbacks(countValue);
|
||||
}
|
||||
|
||||
synchronized (ourLock) {
|
||||
if (!myPrepared || myCache == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Iterator<IdeaPluginDescriptor> I = myCache.iterator(); I.hasNext(); ) {
|
||||
IdeaPluginDescriptor downloadedDescriptor = I.next();
|
||||
|
||||
if (downloadedDescriptor.equals(descriptor)) {
|
||||
I.remove();
|
||||
|
||||
Integer countValue = getCount();
|
||||
for (PluginUpdatesService service : SERVICES) {
|
||||
service.runCountCallbacks(countValue);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void finishUpdate() {
|
||||
checkAccess();
|
||||
synchronized (ourLock) {
|
||||
if (!myPrepared || myCache == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!myPrepared || myCache == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Integer countValue = getCount();
|
||||
for (PluginUpdatesService service : SERVICES) {
|
||||
service.runCountCallbacks(countValue);
|
||||
Integer countValue = getCount();
|
||||
for (PluginUpdatesService service : SERVICES) {
|
||||
service.runCountCallbacks(countValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void recalculateUpdates() {
|
||||
checkAccess();
|
||||
synchronized (ourLock) {
|
||||
for (PluginUpdatesService service : SERVICES) {
|
||||
service.runAllCallbacks(0);
|
||||
}
|
||||
|
||||
for (PluginUpdatesService service : SERVICES) {
|
||||
service.runAllCallbacks(0);
|
||||
}
|
||||
|
||||
if (myPreparing) {
|
||||
resetUpdates();
|
||||
}
|
||||
else {
|
||||
calculateUpdates();
|
||||
if (myPreparing) {
|
||||
resetUpdates();
|
||||
}
|
||||
else {
|
||||
calculateUpdates();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,28 +135,30 @@ public class PluginUpdatesService {
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
checkAccess();
|
||||
dispose(this);
|
||||
}
|
||||
|
||||
private static void dispose(@NotNull PluginUpdatesService service) {
|
||||
SERVICES.remove(service);
|
||||
synchronized (ourLock) {
|
||||
SERVICES.remove(service);
|
||||
|
||||
if (SERVICES.isEmpty()) {
|
||||
myCache = null;
|
||||
myPrepared = false;
|
||||
myPreparing = false;
|
||||
if (SERVICES.isEmpty()) {
|
||||
myCache = null;
|
||||
myPrepared = false;
|
||||
myPreparing = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isNeedUpdate(@NotNull IdeaPluginDescriptor descriptor) {
|
||||
checkAccess();
|
||||
|
||||
PluginId pluginId = descriptor.getPluginId();
|
||||
if (myPrepared && myCache != null) {
|
||||
for (IdeaPluginDescriptor downloader : myCache) {
|
||||
if (pluginId.equals(downloader.getPluginId())) {
|
||||
return true;
|
||||
|
||||
synchronized (ourLock) {
|
||||
if (myPrepared && myCache != null) {
|
||||
for (IdeaPluginDescriptor downloader : myCache) {
|
||||
if (pluginId.equals(downloader.getPluginId())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -182,43 +168,46 @@ public class PluginUpdatesService {
|
||||
|
||||
@Nullable
|
||||
public static Collection<IdeaPluginDescriptor> getUpdates() {
|
||||
checkAccess();
|
||||
return !myPrepared || myPreparing || myCache == null ? null : myCache;
|
||||
synchronized (ourLock) {
|
||||
return !myPrepared || myPreparing || myCache == null ? null : myCache;
|
||||
}
|
||||
}
|
||||
|
||||
private static void calculateUpdates() {
|
||||
if (myPreparing) {
|
||||
return;
|
||||
synchronized (ourLock) {
|
||||
if (myPreparing) {
|
||||
return;
|
||||
}
|
||||
myPreparing = true;
|
||||
myCache = null;
|
||||
}
|
||||
myPreparing = true;
|
||||
myCache = null;
|
||||
|
||||
ApplicationManager.getApplication().executeOnPooledThread(() -> {
|
||||
UpdateChecker.CheckPluginsUpdateResult updates = UpdateChecker.checkPluginsUpdate(new EmptyProgressIndicator());
|
||||
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
checkAccess();
|
||||
synchronized (ourLock) {
|
||||
myPreparing = false;
|
||||
|
||||
myPreparing = false;
|
||||
if (myReset) {
|
||||
myReset = false;
|
||||
calculateUpdates();
|
||||
return;
|
||||
}
|
||||
|
||||
if (myReset) {
|
||||
myReset = false;
|
||||
calculateUpdates();
|
||||
return;
|
||||
}
|
||||
myPrepared = true;
|
||||
List<IdeaPluginDescriptor> cache = new ArrayList<>();
|
||||
Collection<PluginDownloader> availableUpdates = updates.getAvailableUpdates();
|
||||
if (availableUpdates != null) {
|
||||
cache.addAll(ContainerUtil.map(availableUpdates, (downloader -> downloader.getDescriptor())));
|
||||
}
|
||||
cache.addAll(ContainerUtil.map(updates.getAvailableDisabledUpdates(), (downloader -> downloader.getDescriptor())));
|
||||
myCache = cache;
|
||||
|
||||
myPrepared = true;
|
||||
List<IdeaPluginDescriptor> cache = new ArrayList<>();
|
||||
Collection<PluginDownloader> availableUpdates = updates.getAvailableUpdates();
|
||||
if (availableUpdates != null) {
|
||||
cache.addAll(ContainerUtil.map(availableUpdates, (downloader -> downloader.getDescriptor())));
|
||||
}
|
||||
cache.addAll(ContainerUtil.map(updates.getAvailableDisabledUpdates(), (downloader -> downloader.getDescriptor())));
|
||||
myCache = cache;
|
||||
|
||||
Integer countValue = getCount();
|
||||
for (PluginUpdatesService service : SERVICES) {
|
||||
service.runAllCallbacks(countValue);
|
||||
Integer countValue = getCount();
|
||||
for (PluginUpdatesService service : SERVICES) {
|
||||
service.runAllCallbacks(countValue);
|
||||
}
|
||||
}
|
||||
}, ModalityState.any());
|
||||
});
|
||||
@@ -227,20 +216,14 @@ public class PluginUpdatesService {
|
||||
private void runAllCallbacks(@Nullable Integer countValue) {
|
||||
runCountCallbacks(countValue);
|
||||
|
||||
if (myInstalledPanelCallback != null) {
|
||||
myInstalledPanelCallback.accept(myCache);
|
||||
}
|
||||
if (myUpdatePanelCallback != null) {
|
||||
myUpdatePanelCallback.accept(myCache);
|
||||
if (myUpdateCallback != null) {
|
||||
myUpdateCallback.accept(myCache);
|
||||
}
|
||||
}
|
||||
|
||||
private void runCountCallbacks(@Nullable Integer countValue) {
|
||||
if (myTreeCallback != null) {
|
||||
myTreeCallback.accept(countValue);
|
||||
}
|
||||
if (myTabCallback != null) {
|
||||
myTabCallback.accept(countValue);
|
||||
if (myCountCallback != null) {
|
||||
myCountCallback.accept(countValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,8 +231,4 @@ public class PluginUpdatesService {
|
||||
private static Integer getCount() {
|
||||
return myCache == null ? null : myCache.size();
|
||||
}
|
||||
|
||||
private static void checkAccess() {
|
||||
assert SwingUtilities.isEventDispatchThread();
|
||||
}
|
||||
}
|
||||
@@ -260,7 +260,7 @@ final class EventLogConsole {
|
||||
final NotificationType type = notification.getType();
|
||||
TextAttributesKey key = type == NotificationType.ERROR
|
||||
? ConsoleViewContentType.LOG_ERROR_OUTPUT_KEY
|
||||
: type == NotificationType.INFORMATION
|
||||
: type == NotificationType.INFORMATION || type == NotificationType.IDE_UPDATE
|
||||
? ConsoleViewContentType.NORMAL_OUTPUT_KEY
|
||||
: ConsoleViewContentType.LOG_WARNING_OUTPUT_KEY;
|
||||
|
||||
|
||||
+8
-3
@@ -62,7 +62,7 @@ public final class NotificationCollector {
|
||||
boolean isExpandable) {
|
||||
List<EventPair<?>> data = createNotificationData(notification.getGroupId(), notification.id, notification.displayId);
|
||||
data.add(DISPLAY_TYPE.with(displayType));
|
||||
data.add(SEVERITY.with(notification.getType()));
|
||||
data.add(SEVERITY.with(getType(notification)));
|
||||
data.add(IS_EXPANDABLE.with(isExpandable));
|
||||
SHOWN.log(project, data);
|
||||
}
|
||||
@@ -71,16 +71,21 @@ public final class NotificationCollector {
|
||||
@NotNull Notification notification) {
|
||||
List<EventPair<?>> data = createNotificationData(notification.getGroupId(), notification.id, notification.displayId);
|
||||
data.add(DISPLAY_TYPE.with(NotificationDisplayType.TOOL_WINDOW));
|
||||
data.add(SEVERITY.with(notification.getType()));
|
||||
data.add(SEVERITY.with(getType(notification)));
|
||||
SHOWN.log(project, data);
|
||||
}
|
||||
|
||||
public void logNotificationLoggedInEventLog(@NotNull Project project, @NotNull Notification notification) {
|
||||
List<EventPair<?>> data = createNotificationData(notification.getGroupId(), notification.id, notification.displayId);
|
||||
data.add(SEVERITY.with(notification.getType()));
|
||||
data.add(SEVERITY.with(getType(notification)));
|
||||
LOGGED.log(project, data);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static NotificationType getType(@NotNull Notification notification) {
|
||||
return notification.getType() == NotificationType.IDE_UPDATE ? NotificationType.INFORMATION : notification.getType();
|
||||
}
|
||||
|
||||
public void logNotificationBalloonClosedByUser(@Nullable String notificationId,
|
||||
@Nullable String notificationDisplayId,
|
||||
@Nullable String groupId) {
|
||||
|
||||
+5
-3
@@ -121,6 +121,7 @@ public class IdeNotificationArea extends JLabel implements CustomStatusBarWidget
|
||||
case ERROR:
|
||||
return forToolWindow ? AllIcons.Toolwindows.ErrorEvents : AllIcons.Ide.Notification.ErrorEvents;
|
||||
case INFORMATION:
|
||||
case IDE_UPDATE:
|
||||
return forToolWindow ? AllIcons.Toolwindows.InfoEvents : AllIcons.Ide.Notification.InfoEvents;
|
||||
}
|
||||
}
|
||||
@@ -131,14 +132,15 @@ public class IdeNotificationArea extends JLabel implements CustomStatusBarWidget
|
||||
public static NotificationType getMaximumType(List<? extends Notification> notifications) {
|
||||
NotificationType result = null;
|
||||
for (Notification notification : notifications) {
|
||||
if (NotificationType.ERROR == notification.getType()) {
|
||||
NotificationType type = notification.getType();
|
||||
if (NotificationType.ERROR == type) {
|
||||
return NotificationType.ERROR;
|
||||
}
|
||||
|
||||
if (NotificationType.WARNING == notification.getType()) {
|
||||
if (NotificationType.WARNING == type) {
|
||||
result = NotificationType.WARNING;
|
||||
}
|
||||
else if (result == null && NotificationType.INFORMATION == notification.getType()) {
|
||||
else if (result == null && (NotificationType.INFORMATION == type || NotificationType.IDE_UPDATE == type)) {
|
||||
result = NotificationType.INFORMATION;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -59,7 +59,7 @@ public class PluginUpdateDialog extends DialogWrapper {
|
||||
|
||||
public PluginUpdateDialog(@Nullable Project project,
|
||||
@NotNull Collection<PluginDownloader> updatedPlugins,
|
||||
@NotNull Collection<IdeaPluginDescriptor> customRepositoryPlugins) {
|
||||
@Nullable Collection<IdeaPluginDescriptor> customRepositoryPlugins) {
|
||||
super(true);
|
||||
setTitle(IdeBundle.message("dialog.title.plugin.updates"));
|
||||
|
||||
@@ -82,7 +82,7 @@ public class PluginUpdateDialog extends DialogWrapper {
|
||||
@Override
|
||||
@NotNull
|
||||
protected Collection<IdeaPluginDescriptor> getCustomRepoPlugins() {
|
||||
return customRepositoryPlugins;
|
||||
return customRepositoryPlugins == null ? super.getCustomRepoPlugins() : customRepositoryPlugins;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+30
-33
@@ -3,6 +3,7 @@ package com.intellij.openapi.updateSettings.impl
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting
|
||||
import com.intellij.ide.IdeBundle
|
||||
import com.intellij.ide.actions.SettingsEntryPointAction
|
||||
import com.intellij.ide.externalComponents.ExternalComponentManager
|
||||
import com.intellij.ide.plugins.*
|
||||
import com.intellij.ide.plugins.marketplace.BrokenPluginsService
|
||||
@@ -29,7 +30,6 @@ import com.intellij.openapi.util.Pair.pair
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.openapi.wm.impl.welcomeScreen.WelcomeFrame
|
||||
import com.intellij.openapi.wm.impl.welcomeScreen.WelcomeFrameUpdater
|
||||
import com.intellij.reference.SoftReference
|
||||
import com.intellij.util.Urls
|
||||
import com.intellij.util.concurrency.AppExecutorUtil
|
||||
@@ -120,9 +120,7 @@ object UpdateChecker {
|
||||
val fromSettings = customSettings != null
|
||||
|
||||
ProgressManager.getInstance().run(object : Task.Backgroundable(project, IdeBundle.message("updates.checking.progress"), true) {
|
||||
override fun run(indicator: ProgressIndicator) = doUpdateAndShowResult(getProject(), !fromSettings,
|
||||
fromSettings || WelcomeFrame.getInstance() != null, true,
|
||||
settings, indicator, null)
|
||||
override fun run(indicator: ProgressIndicator) = doUpdateAndShowResult(getProject(), !fromSettings, fromSettings, true, settings, indicator, null)
|
||||
|
||||
override fun isConditionalModal(): Boolean = fromSettings
|
||||
override fun shouldStartInBackground(): Boolean = !fromSettings
|
||||
@@ -557,6 +555,8 @@ object UpdateChecker {
|
||||
runnable.invoke()
|
||||
}
|
||||
else {
|
||||
SettingsEntryPointAction.newPlatformUpdate(checkForUpdateResult, checkPluginsUpdateResult.incompatiblePlugins)
|
||||
|
||||
IdeUpdateUsageTriggerCollector.trigger("notification.shown")
|
||||
val title = IdeBundle.message("updates.new.build.notification.title", ApplicationNamesInfo.getInstance().fullProductName,
|
||||
newBuild.version)
|
||||
@@ -583,33 +583,32 @@ object UpdateChecker {
|
||||
}
|
||||
// don't show notification if all updated plugins is disabled
|
||||
else if (updatedPlugins.size != updatedPlugins.count { downloader -> PluginManagerCore.isDisabled(downloader.id) }) {
|
||||
SettingsEntryPointAction.newPluginsUpdate(updatedPlugins, checkPluginsUpdateResult.customRepositoryPlugins)
|
||||
|
||||
val runnable = { PluginManagerConfigurable.showPluginConfigurable(project, updatedPlugins.map { it.descriptor }) }
|
||||
|
||||
val ideFrame = WelcomeFrame.getInstance()
|
||||
if (ideFrame is WelcomeFrameUpdater) {
|
||||
ideFrame.showPluginUpdates(runnable)
|
||||
}
|
||||
else {
|
||||
val names = updatedPlugins.joinToString { downloader -> StringUtil.wrapWithDoubleQuote(downloader.pluginName) }
|
||||
val title = if (updatedPlugins.size == 1) IdeBundle.message("updates.plugin.ready.short.title.available", names) else IdeBundle.message("updates.plugins.ready.short.title.available")
|
||||
val message = if (updatedPlugins.size == 1) "" else names
|
||||
showNotification(project, title, message, runnable, { notification ->
|
||||
notification.actions[0].templatePresentation.text = IdeBundle.message("plugin.settings.link.title")
|
||||
val text = if (updatedPlugins.size == 1) IdeBundle.message("plugins.configurable.update.button") else IdeBundle.message("plugin.manager.update.all")
|
||||
notification.actions.add(0, object : NotificationAction(text) {
|
||||
override fun actionPerformed(e: AnActionEvent, notification: Notification) {
|
||||
notification.expire()
|
||||
PluginUpdateDialog.runUpdateAll(updatedPlugins, e.getData(PlatformDataKeys.CONTEXT_COMPONENT) as JComponent?)
|
||||
}
|
||||
})
|
||||
notification.addAction(object : NotificationAction(IdeBundle.message("updates.ignore.updates.link", updatedPlugins.size)) {
|
||||
override fun actionPerformed(e: AnActionEvent, notification: Notification) {
|
||||
notification.expire()
|
||||
PluginUpdateDialog.ignorePlugins(updatedPlugins.map { downloader -> downloader.descriptor })
|
||||
}
|
||||
})
|
||||
}, NotificationUniqueType.PLUGINS, "plugins.update.available")
|
||||
}
|
||||
val names = updatedPlugins.joinToString { downloader -> StringUtil.wrapWithDoubleQuote(downloader.pluginName) }
|
||||
val title = if (updatedPlugins.size == 1) IdeBundle.message("updates.plugin.ready.short.title.available", names)
|
||||
else IdeBundle.message("updates.plugins.ready.short.title.available")
|
||||
val message = if (updatedPlugins.size == 1) "" else names
|
||||
|
||||
showNotification(project, title, message, runnable, { notification ->
|
||||
notification.actions[0].templatePresentation.text = IdeBundle.message("plugin.settings.link.title")
|
||||
val text = if (updatedPlugins.size == 1) IdeBundle.message("plugins.configurable.update.button")
|
||||
else IdeBundle.message("plugin.manager.update.all")
|
||||
notification.actions.add(0, object : NotificationAction(text) {
|
||||
override fun actionPerformed(e: AnActionEvent, notification: Notification) {
|
||||
notification.expire()
|
||||
PluginUpdateDialog.runUpdateAll(updatedPlugins, e.getData(PlatformDataKeys.CONTEXT_COMPONENT) as JComponent?)
|
||||
}
|
||||
})
|
||||
notification.addAction(object : NotificationAction(IdeBundle.message("updates.ignore.updates.link", updatedPlugins.size)) {
|
||||
override fun actionPerformed(e: AnActionEvent, notification: Notification) {
|
||||
notification.expire()
|
||||
PluginUpdateDialog.ignorePlugins(updatedPlugins.map { downloader -> downloader.descriptor })
|
||||
}
|
||||
})
|
||||
}, NotificationUniqueType.PLUGINS, "plugins.update.available")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -647,9 +646,6 @@ object UpdateChecker {
|
||||
}
|
||||
|
||||
private fun canEnableNotifications(): Boolean {
|
||||
if (WelcomeFrame.getInstance() is WelcomeFrameUpdater) {
|
||||
return true
|
||||
}
|
||||
return NotificationsConfigurationImpl.getInstanceImpl().SHOW_BALLOONS && NotificationsConfigurationImpl.getSettings(
|
||||
getNotificationGroup().displayId).displayType != NotificationDisplayType.NONE
|
||||
}
|
||||
@@ -662,7 +658,8 @@ object UpdateChecker {
|
||||
notificationType: NotificationUniqueType,
|
||||
notificationDisplayId: String) {
|
||||
val content = if (message.isEmpty()) "" else XmlStringUtil.wrapInHtml(message)
|
||||
val notification = getNotificationGroup().createNotification(title, content, NotificationType.INFORMATION, null, notificationDisplayId)
|
||||
val type = if (notificationType == NotificationUniqueType.PLATFORM) NotificationType.IDE_UPDATE else NotificationType.INFORMATION
|
||||
val notification = getNotificationGroup().createNotification(title, content, type, null, notificationDisplayId)
|
||||
notification.collapseActionsDirection = Notification.CollapseActionsDirection.KEEP_LEFTMOST
|
||||
notification.addAction(object : NotificationAction(IdeBundle.message("updates.notification.update.action")) {
|
||||
override fun actionPerformed(e: AnActionEvent, notification: Notification) {
|
||||
|
||||
+32
-11
@@ -20,6 +20,7 @@ import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.ActionCallback;
|
||||
import com.intellij.openapi.util.NlsContexts;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
@@ -48,7 +49,7 @@ import static com.intellij.openapi.util.Pair.pair;
|
||||
/**
|
||||
* @author pti
|
||||
*/
|
||||
final class UpdateInfoDialog extends AbstractUpdateDialog {
|
||||
public final class UpdateInfoDialog extends AbstractUpdateDialog {
|
||||
private final UpdateChannel myUpdatedChannel;
|
||||
private final Collection<PluginDownloader> myUpdatedPlugins;
|
||||
private final BuildInfo myNewBuild;
|
||||
@@ -58,7 +59,7 @@ final class UpdateInfoDialog extends AbstractUpdateDialog {
|
||||
private final File myTestPatch;
|
||||
private final AbstractAction myWhatsNewAction;
|
||||
|
||||
UpdateInfoDialog(@NotNull UpdateChannel channel,
|
||||
public UpdateInfoDialog(@NotNull UpdateChannel channel,
|
||||
@NotNull BuildInfo newBuild,
|
||||
@Nullable UpdateChain patches,
|
||||
boolean enableLink,
|
||||
@@ -213,30 +214,46 @@ final class UpdateInfoDialog extends AbstractUpdateDialog {
|
||||
}
|
||||
|
||||
private void downloadPatchAndRestart() {
|
||||
boolean updatePlugins = !ContainerUtil.isEmpty(myUpdatedPlugins);
|
||||
if (updatePlugins && !new PluginUpdateInfoDialog(myUpdatedPlugins).showAndGet()) {
|
||||
if (!ContainerUtil.isEmpty(myUpdatedPlugins) && !new PluginUpdateInfoDialog(myUpdatedPlugins).showAndGet()) {
|
||||
return; // update cancelled
|
||||
}
|
||||
downloadPatchAndRestart(myNewBuild, myUpdatedChannel, myPatches, myTestPatch, myUpdatedPlugins, null);
|
||||
}
|
||||
|
||||
public static void downloadPatchAndRestart(@NotNull BuildInfo newBuild,
|
||||
@NotNull UpdateChannel updatedChannel,
|
||||
@NotNull UpdateChain patches,
|
||||
@Nullable File testPatch,
|
||||
@Nullable Collection<PluginDownloader> updatedPlugins,
|
||||
@Nullable ActionCallback callback) {
|
||||
new Task.Backgroundable(null, IdeBundle.message("update.preparing"), true, PerformInBackgroundOption.DEAF) {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
String[] command;
|
||||
try {
|
||||
if (myTestPatch != null) {
|
||||
command = UpdateInstaller.preparePatchCommand(myTestPatch, indicator);
|
||||
if (testPatch != null) {
|
||||
command = UpdateInstaller.preparePatchCommand(testPatch, indicator);
|
||||
}
|
||||
else {
|
||||
List<File> files = UpdateInstaller.downloadPatchChain(myPatches.getChain(), indicator);
|
||||
List<File> files = UpdateInstaller.downloadPatchChain(patches.getChain(), indicator);
|
||||
command = UpdateInstaller.preparePatchCommand(files, indicator);
|
||||
}
|
||||
}
|
||||
catch (ProcessCanceledException e) { throw e; }
|
||||
catch (ProcessCanceledException e) {
|
||||
if (callback != null) {
|
||||
callback.setRejected();
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
Logger.getInstance(UpdateInstaller.class).warn(e);
|
||||
|
||||
if (callback != null) {
|
||||
callback.setRejected();
|
||||
}
|
||||
|
||||
String title = IdeBundle.message("updates.notification.title", ApplicationNamesInfo.getInstance().getFullProductName());
|
||||
String downloadUrl = UpdateInfoPanel.downloadUrl(myNewBuild, myUpdatedChannel);
|
||||
String downloadUrl = UpdateInfoPanel.downloadUrl(newBuild, updatedChannel);
|
||||
String message = IdeBundle.message("update.downloading.patch.error", e.getMessage(), downloadUrl);
|
||||
UpdateChecker.getNotificationGroup().createNotification(
|
||||
title, message, NotificationType.ERROR, NotificationListener.URL_OPENING_LISTENER, "ide.patch.download.failed").notify(null);
|
||||
@@ -244,8 +261,12 @@ final class UpdateInfoDialog extends AbstractUpdateDialog {
|
||||
return;
|
||||
}
|
||||
|
||||
if (updatePlugins) {
|
||||
UpdateInstaller.installPluginUpdates(myUpdatedPlugins, indicator);
|
||||
if (!ContainerUtil.isEmpty(updatedPlugins)) {
|
||||
UpdateInstaller.installPluginUpdates(updatedPlugins, indicator);
|
||||
}
|
||||
|
||||
if (callback != null) {
|
||||
callback.setDone();
|
||||
}
|
||||
|
||||
if (ApplicationManager.getApplication().isRestartCapable()) {
|
||||
|
||||
+3
-47
@@ -37,7 +37,6 @@ import com.intellij.ui.*;
|
||||
import com.intellij.ui.components.JBList;
|
||||
import com.intellij.ui.components.JBTextField;
|
||||
import com.intellij.ui.components.labels.ActionLink;
|
||||
import com.intellij.ui.components.labels.LinkLabel;
|
||||
import com.intellij.ui.components.panels.NonOpaquePanel;
|
||||
import com.intellij.ui.mac.TouchbarDataKeys;
|
||||
import com.intellij.ui.scale.JBUIScale;
|
||||
@@ -70,7 +69,7 @@ import java.util.List;
|
||||
/**
|
||||
* @author Konstantin Bulenkov
|
||||
*/
|
||||
public class FlatWelcomeFrame extends JFrame implements IdeFrame, Disposable, AccessibleContextAccessor, WelcomeFrameUpdater {
|
||||
public class FlatWelcomeFrame extends JFrame implements IdeFrame, Disposable, AccessibleContextAccessor {
|
||||
@SuppressWarnings("StaticNonFinalField")
|
||||
public static boolean USE_TABBED_WELCOME_SCREEN = Boolean.parseBoolean(SystemProperty.get("use.tabbed.welcome.screen", "true"));
|
||||
|
||||
@@ -232,9 +231,8 @@ public class FlatWelcomeFrame extends JFrame implements IdeFrame, Disposable, Ac
|
||||
return pair.second;
|
||||
}
|
||||
|
||||
private final class FlatWelcomeScreen extends AbstractWelcomeScreen implements WelcomeFrameUpdater {
|
||||
private final class FlatWelcomeScreen extends AbstractWelcomeScreen {
|
||||
private final DefaultActionGroup myTouchbarActions = new DefaultActionGroup();
|
||||
private LinkLabel<Object> myUpdatePluginsLink;
|
||||
private boolean inDnd;
|
||||
|
||||
FlatWelcomeScreen() {
|
||||
@@ -352,14 +350,7 @@ public class FlatWelcomeFrame extends JFrame implements IdeFrame, Disposable, Ac
|
||||
ActionPanel actionPanel = createQuickStartActionPanel();
|
||||
panel.add(actionPanel, BorderLayout.CENTER);
|
||||
myTouchbarActions.addAll(actionPanel.getActions());
|
||||
panel.add(createUpdatesSettingsAndDocs(), BorderLayout.SOUTH);
|
||||
return panel;
|
||||
}
|
||||
|
||||
private JComponent createUpdatesSettingsAndDocs() {
|
||||
JPanel panel = new NonOpaquePanel(new BorderLayout());
|
||||
panel.add(createUpdatePluginsLink(), BorderLayout.WEST);
|
||||
panel.add(createSettingsAndDocsPanel(FlatWelcomeFrame.this), BorderLayout.EAST);
|
||||
panel.add(createSettingsAndDocsPanel(FlatWelcomeFrame.this), BorderLayout.SOUTH);
|
||||
return panel;
|
||||
}
|
||||
|
||||
@@ -469,27 +460,6 @@ public class FlatWelcomeFrame extends JFrame implements IdeFrame, Disposable, Ac
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private JComponent createUpdatePluginsLink() {
|
||||
myUpdatePluginsLink = new LinkLabel<>(IdeBundle.message("updates.plugins.welcome.screen.link.message"), null);
|
||||
myUpdatePluginsLink.setVisible(false);
|
||||
|
||||
NonOpaquePanel wrap = new NonOpaquePanel(myUpdatePluginsLink);
|
||||
wrap.setBorder(JBUI.Borders.empty(0, 10, 8, 11));
|
||||
return wrap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showPluginUpdates(@NotNull Runnable callback) {
|
||||
myUpdatePluginsLink.setListener((__, ___) -> callback.run(), null);
|
||||
myUpdatePluginsLink.setVisible(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hidePluginUpdates() {
|
||||
myUpdatePluginsLink.setListener(null, null);
|
||||
myUpdatePluginsLink.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
protected void extendActionsGroup(JPanel panel) {
|
||||
@@ -498,20 +468,6 @@ public class FlatWelcomeFrame extends JFrame implements IdeFrame, Disposable, Ac
|
||||
protected void onFirstActionShown(@NotNull Component action) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showPluginUpdates(@NotNull Runnable callback) {
|
||||
if (myScreen instanceof WelcomeFrameUpdater) {
|
||||
((WelcomeFrameUpdater)myScreen).showPluginUpdates(callback);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hidePluginUpdates() {
|
||||
if (myScreen instanceof WelcomeFrameUpdater) {
|
||||
((WelcomeFrameUpdater)myScreen).hidePluginUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public BalloonLayout getBalloonLayout() {
|
||||
|
||||
+41
@@ -2,11 +2,14 @@
|
||||
package com.intellij.openapi.wm.impl.welcomeScreen;
|
||||
|
||||
import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.ide.plugins.CountComponent;
|
||||
import com.intellij.ide.plugins.InstalledPluginsState;
|
||||
import com.intellij.ide.plugins.PluginManagerConfigurable;
|
||||
import com.intellij.ide.plugins.newui.PluginUpdatesService;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.util.NlsSafe;
|
||||
import com.intellij.openapi.wm.WelcomeScreenTab;
|
||||
import com.intellij.openapi.wm.WelcomeTabFactory;
|
||||
import com.intellij.ui.AncestorListenerAdapter;
|
||||
@@ -14,11 +17,13 @@ import com.intellij.ui.JBColor;
|
||||
import com.intellij.util.ui.JBDimension;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.UI;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.util.ui.components.BorderLayoutPanel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.AncestorEvent;
|
||||
import java.awt.*;
|
||||
|
||||
public class PluginsTabFactory implements WelcomeTabFactory {
|
||||
private static final Logger LOG = Logger.getInstance(PluginsTabFactory.class);
|
||||
@@ -26,6 +31,42 @@ public class PluginsTabFactory implements WelcomeTabFactory {
|
||||
@Override
|
||||
public @NotNull WelcomeScreenTab createWelcomeTab(@NotNull Disposable parentDisposable) {
|
||||
return new TabbedWelcomeScreen.DefaultWelcomeScreenTab(IdeBundle.message("welcome.screen.plugins.title"), WelcomeScreenEventCollector.TabType.TabNavPlugins) {
|
||||
private PluginUpdatesService myService;
|
||||
private final CountComponent myCountLabel = new CountComponent();
|
||||
private JList<? extends WelcomeScreenTab> myList;
|
||||
|
||||
{
|
||||
myKeyComponent.setBorder(JBUI.Borders.empty(8, 0, 8, 8));
|
||||
myKeyComponent.add(myCountLabel, BorderLayout.EAST);
|
||||
myCountLabel.setVisible(false);
|
||||
|
||||
UIUtil.invokeLaterIfNeeded(() -> {
|
||||
myService = PluginUpdatesService.connectWithCounter(countValue -> {
|
||||
@NlsSafe String text = countValue == null || countValue <= 0 ? null : countValue.toString();
|
||||
myCountLabel.setText(text);
|
||||
myCountLabel.setVisible(text != null);
|
||||
if (myList != null) {
|
||||
myList.repaint();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull JComponent getKeyComponent(@NotNull JList<? extends WelcomeScreenTab> list) {
|
||||
if (myList == null) {
|
||||
list.addAncestorListener(new AncestorListenerAdapter() {
|
||||
@Override
|
||||
public void ancestorRemoved(AncestorEvent event) {
|
||||
if (myService != null) {
|
||||
myService.dispose();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
myList = list;
|
||||
return super.getKeyComponent(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JComponent buildComponent() {
|
||||
|
||||
+3
-4
@@ -131,7 +131,7 @@ public final class TabbedWelcomeScreen extends AbstractWelcomeScreen {
|
||||
int index,
|
||||
boolean isSelected,
|
||||
boolean cellHasFocus) {
|
||||
JComponent keyComponent = value.getKeyComponent();
|
||||
JComponent keyComponent = value.getKeyComponent(list);
|
||||
JPanel wrappedPanel = JBUI.Panels.simplePanel(keyComponent);
|
||||
UIUtil.setBackgroundRecursively(wrappedPanel, isSelected ? UIUtil.getListSelectionBackground(cellHasFocus): getMainTabListBackground());
|
||||
UIUtil.setForegroundRecursively(wrappedPanel, UIUtil.getListForeground(isSelected, cellHasFocus));
|
||||
@@ -143,8 +143,7 @@ public final class TabbedWelcomeScreen extends AbstractWelcomeScreen {
|
||||
}
|
||||
|
||||
public abstract static class DefaultWelcomeScreenTab implements WelcomeScreenTab, Accessible {
|
||||
|
||||
private final JComponent myKeyComponent;
|
||||
protected final JComponent myKeyComponent;
|
||||
private JComponent myAssociatedComponent;
|
||||
private final JBLabel myLabel;
|
||||
private final WelcomeScreenEventCollector.TabType myType;
|
||||
@@ -162,7 +161,7 @@ public final class TabbedWelcomeScreen extends AbstractWelcomeScreen {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JComponent getKeyComponent() {
|
||||
public JComponent getKeyComponent(@NotNull JList<? extends WelcomeScreenTab> list) {
|
||||
return myKeyComponent;
|
||||
}
|
||||
|
||||
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.wm.impl.welcomeScreen;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Alexander Lobas
|
||||
*/
|
||||
public interface WelcomeFrameUpdater {
|
||||
void showPluginUpdates(@NotNull Runnable callback);
|
||||
|
||||
void hidePluginUpdates();
|
||||
}
|
||||
+3
-1
@@ -307,7 +307,9 @@ public final class WelcomeScreenComponentFactory {
|
||||
Topics.subscribe(WelcomeBalloonLayoutImpl.BALLOON_NOTIFICATION_TOPIC, parentDisposable, types -> {
|
||||
if (!types.isEmpty()) {
|
||||
NotificationType type = Collections.max(types);
|
||||
actionLink.setIcon(IdeNotificationArea.createIconWithNotificationCount(panel, type, types.size(), false));
|
||||
actionLink.setIcon(type == NotificationType.IDE_UPDATE
|
||||
? AllIcons.Ide.Notification.IdeUpdate
|
||||
: IdeNotificationArea.createIconWithNotificationCount(panel, type, types.size(), false));
|
||||
}
|
||||
panel.setVisible(!types.isEmpty());
|
||||
});
|
||||
|
||||
@@ -1171,6 +1171,7 @@
|
||||
<statusBarWidgetFactory id="fatalErrorWidget" implementation="com.intellij.openapi.wm.impl.status.FatalErrorWidgetFactory" order="after notificationsWidget"/>
|
||||
<statusBarWidgetFactory id="writeActionWidget" implementation="com.intellij.openapi.wm.impl.status.WriteThreadIndicatorWidgetFactory" order="after fatalErrorWidget"/>
|
||||
<statusBarWidgetFactory id="memoryUsageWidget" implementation="com.intellij.openapi.wm.impl.status.MemoryIndicatorWidgetFactory" order="last"/>
|
||||
<statusBarWidgetFactory id="settingsEntryPointWidget" implementation="com.intellij.ide.actions.SettingsEntryPointAction$StatusBarManager" order="last"/>
|
||||
|
||||
<fileIndentOptionsProvider implementation="com.intellij.psi.codeStyle.DetectableIndentOptionsProvider" order="last"/>
|
||||
<lang.formatter.restriction implementation="com.intellij.formatting.ExcludedFileFormattingRestriction"/>
|
||||
|
||||
@@ -501,8 +501,8 @@
|
||||
<separator/>
|
||||
<reference id="NavBarToolBarOthers"/>
|
||||
<separator/>
|
||||
<reference ref="RunAnything"/>
|
||||
<reference ref="SearchEverywhere"/>
|
||||
<reference ref="SettingsEntryPoint"/>
|
||||
</group>
|
||||
|
||||
|
||||
|
||||
@@ -165,6 +165,7 @@
|
||||
</action>
|
||||
<action id="OpenElementInNewWindow" class="com.intellij.ide.actions.OpenElementInNewWindowAction" />
|
||||
<action id="SearchEverywhere" class="com.intellij.ide.actions.SearchEverywhereAction" icon="AllIcons.Actions.Find"/>
|
||||
<action id="SettingsEntryPoint" class="com.intellij.ide.actions.SettingsEntryPointAction" icon="AllIcons.General.GearPlain"/>
|
||||
|
||||
<action id="RunAnything" icon="AllIcons.Actions.Run_anything" class="com.intellij.ide.actions.runAnything.RunAnythingAction"/>
|
||||
|
||||
@@ -808,12 +809,10 @@
|
||||
<reference ref="Back"/>
|
||||
<reference ref="Forward"/>
|
||||
<separator/>
|
||||
<group id="MainToolBarSettings">
|
||||
<reference ref="ShowSettings"/>
|
||||
</group>
|
||||
<group id="MainToolBarSettings"/>
|
||||
<separator/>
|
||||
<reference ref="RunAnything"/>
|
||||
<reference ref="SearchEverywhere"/>
|
||||
<reference ref="SettingsEntryPoint"/>
|
||||
</group>
|
||||
|
||||
<group id="NavBarVcsGroup"/>
|
||||
@@ -1353,5 +1352,16 @@
|
||||
</group>
|
||||
|
||||
<action class="com.intellij.diagnostic.ResetWindowsDefenderNotification" id="ResetWindowsDefenderNotification"/>
|
||||
|
||||
<group id="SettingsEntryPointGroup">
|
||||
<reference id="RunAnything"/>
|
||||
<separator/>
|
||||
<reference id="ShowSettings"/>
|
||||
<reference id="WelcomeScreen.Plugins"/>
|
||||
<separator/>
|
||||
<reference id="ChangeLaf"/>
|
||||
<reference id="ChangeKeymap"/>
|
||||
<reference id="ChangeView"/>
|
||||
</group>
|
||||
</actions>
|
||||
</idea-plugin>
|
||||
|
||||
@@ -584,8 +584,10 @@ public class AllIcons {
|
||||
/** 16x16 */ public static final @NotNull Icon ExpandHover = load("ide/notification/expandHover.svg", -6923529455314709892L, 0);
|
||||
/** 16x16 */ public static final @NotNull Icon Gear = load("ide/notification/gear.svg", -6517441912232259723L, 0);
|
||||
/** 16x16 */ public static final @NotNull Icon GearHover = load("ide/notification/gearHover.svg", 8529034088585467841L, 0);
|
||||
/** 16x16 */ public static final @NotNull Icon IdeUpdate = load("ide/notification/ideUpdate.svg", -5687507774382455241L, 2);
|
||||
/** 16x16 */ public static final @NotNull Icon InfoEvents = load("ide/notification/infoEvents.svg", 8320605274562923160L, 2);
|
||||
/** 16x16 */ public static final @NotNull Icon NoEvents = load("ide/notification/noEvents.svg", -5934625381114731420L, 2);
|
||||
/** 16x16 */ public static final @NotNull Icon PluginUpdate = load("ide/notification/pluginUpdate.svg", 7670193732028920558L, 2);
|
||||
/** 16x16 */ public static final @NotNull Icon WarningEvents = load("ide/notification/warningEvents.svg", -7338122458505861009L, 2);
|
||||
}
|
||||
|
||||
|
||||
@@ -341,7 +341,7 @@
|
||||
<reference ref="Vcs.ShowTabbedFileHistory"/>
|
||||
<reference ref="ChangesView.Revert"/>
|
||||
<separator/>
|
||||
<add-to-group group-id="MainToolBarSettings" relative-to-action="ShowSettings" anchor="before"/>
|
||||
<add-to-group group-id="MainToolBarSettings"/>
|
||||
</group>
|
||||
|
||||
<group id="VcsNavBarToolbarActions">
|
||||
|
||||
@@ -37,8 +37,7 @@
|
||||
<action id="ShowProjectStructureSettings" class="com.intellij.ide.actions.ShowStructureSettingsAction"
|
||||
icon="AllIcons.General.ProjectStructure">
|
||||
<add-to-group group-id="FileMainSettingsGroup" anchor="after" relative-to-action="ShowSettings"/>
|
||||
<add-to-group group-id="MainToolBarSettings" anchor="after" relative-to-action="ShowSettings"/>
|
||||
<add-to-group group-id="NavBarToolBar" relative-to-action="NavBarToolBarOthers" anchor="after"/>
|
||||
<add-to-group group-id="SettingsEntryPointGroup" anchor="before" relative-to-action="ShowSettings"/>
|
||||
</action>
|
||||
<action id="TemplateProjectStructure" class="com.intellij.ide.actions.TemplateProjectStructureAction">
|
||||
<add-to-group group-id="FileSettingsGroup" anchor="last"/>
|
||||
|
||||
Reference in New Issue
Block a user