IDEA-223967 new update dialog

GitOrigin-RevId: 7d330d57cd10c6e4e8a2aa7298715129b3bf7e37
This commit is contained in:
Dmitry.Krasilschikov
2019-10-07 13:03:29 +00:00
committed by intellij-monorepo-bot
parent cdd700404c
commit 88f279ae7f
5 changed files with 178 additions and 245 deletions
@@ -20,7 +20,7 @@ import java.awt.*;
* @author anna
*/
public abstract class AbstractUpdateDialog extends DialogWrapper {
private final boolean myEnableLink;
protected final boolean myEnableLink;
protected AbstractUpdateDialog(boolean enableLink) {
super(true);
@@ -2,7 +2,6 @@
package com.intellij.openapi.updateSettings.impl;
import com.intellij.execution.CommandLineUtil;
import com.intellij.ide.BrowserUtil;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.util.PropertiesComponent;
@@ -17,17 +16,12 @@ import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.BuildNumber;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.BrowserHyperlinkListener;
import com.intellij.ui.JBColor;
import com.intellij.ui.LicensingFacade;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.scale.JBUIScale;
import com.intellij.util.SystemProperties;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.text.DateFormatUtil;
@@ -47,8 +41,6 @@ import java.util.*;
import static com.intellij.openapi.updateSettings.impl.UpdateCheckerComponent.SELF_UPDATE_STARTED_FOR_BUILD_PROPERTY;
import static com.intellij.openapi.util.Pair.pair;
import static javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER;
import static javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED;
/**
* @author pti
@@ -74,7 +66,6 @@ class UpdateInfoDialog extends AbstractUpdateDialog {
myNewBuild = newBuild;
myPatches = patches;
myWriteProtected = myPatches != null && !SystemInfo.isWindows && !Files.isWritable(Paths.get(PathManager.getHomePath()));
getCancelAction().putValue(DEFAULT_ACTION, Boolean.TRUE);
myLicenseInfo = initLicensingInfo(myUpdatedChannel, myNewBuild);
myTestPatch = null;
init();
@@ -93,7 +84,7 @@ class UpdateInfoDialog extends AbstractUpdateDialog {
myNewBuild = newBuild;
myPatches = patches;
myWriteProtected = false;
myLicenseInfo = null;
myLicenseInfo = initLicensingInfo(myUpdatedChannel, myNewBuild);
myTestPatch = patchFile;
init();
setTitle("[TEST] " + getTitle());
@@ -130,37 +121,27 @@ class UpdateInfoDialog extends AbstractUpdateDialog {
@Override
protected JComponent createCenterPanel() {
return new UpdateInfoPanel().myPanel;
return UpdateInfoPanelUI.INSTANCE
.createPanel(myNewBuild, myPatches, myTestPatch, myWriteProtected, myLicenseInfo, myEnableLink, myUpdatedChannel);
}
@NotNull
@Override
protected Action[] createActions() {
List<Action> actions = new ArrayList<>();
protected DialogStyle getStyle() {
return DialogStyle.COMPACT;
}
if (myPatches != null || myTestPatch != null) {
boolean canRestart = ApplicationManager.getApplication().isRestartCapable();
actions.add(new AbstractAction(IdeBundle.message(canRestart ? "updates.download.and.restart.button" : "updates.apply.manually.button")) {
{
setEnabled(!myWriteProtected);
}
@Override
protected JComponent createSouthPanel() {
JComponent component = super.createSouthPanel();
component.setBorder(JBUI.Borders.empty(8, 12));
return component;
}
@Override
public void actionPerformed(ActionEvent e) {
close(OK_EXIT_CODE);
downloadPatchAndRestart();
}
});
}
List<ButtonInfo> buttons = myNewBuild.getButtons();
for (ButtonInfo info : buttons) {
if (!info.isDownload() || myPatches == null && myTestPatch == null) {
actions.add(new ButtonAction(info));
}
}
actions.add(new AbstractAction(IdeBundle.message("updates.ignore.update.button")) {
@NotNull
@Override
protected Action[] createLeftSideActions() {
return ContainerUtil.ar(new AbstractAction(IdeBundle.message("updates.ignore.update.button")) {
@Override
public void actionPerformed(ActionEvent e) {
String build = myNewBuild.getNumber().asStringWithoutProductCode();
@@ -168,9 +149,32 @@ class UpdateInfoDialog extends AbstractUpdateDialog {
doCancelAction();
}
});
}
@NotNull
@Override
protected Action[] createActions() {
List<Action> actions = new ArrayList<>();
actions.add(getCancelAction());
if (myPatches != null || myTestPatch != null) {
boolean canRestart = ApplicationManager.getApplication().isRestartCapable();
AbstractAction updateButton =
new AbstractAction(IdeBundle.message(canRestart ? "updates.download.and.restart.button" : "updates.apply.manually.button")) {
{
setEnabled(!myWriteProtected);
}
@Override
public void actionPerformed(ActionEvent e) {
close(OK_EXIT_CODE);
downloadPatchAndRestart();
}
};
updateButton.putValue(DEFAULT_ACTION, Boolean.TRUE);
actions.add(updateButton);
}
return actions.toArray(new Action[0]);
}
@@ -269,88 +273,4 @@ class UpdateInfoDialog extends AbstractUpdateDialog {
IdeUpdateUsageTriggerCollector.trigger( "dialog.manual.patch.prepared");
ApplicationManager.getApplication().invokeLater(() -> Messages.showInfoMessage(message, title));
}
private static class ButtonAction extends AbstractAction {
private final ButtonInfo myInfo;
private ButtonAction(@NotNull ButtonInfo info) {
super(info.getName());
myInfo = info;
}
@Override
public void actionPerformed(ActionEvent e) {
if (myInfo.isDownload()) {
IdeUpdateUsageTriggerCollector.trigger( "dialog.download.clicked");
}
BrowserUtil.browse(IdeUrlTrackingParametersProvider.getInstance().augmentUrl(myInfo.getUrl()));
}
}
private class UpdateInfoPanel {
private JPanel myPanel;
private JEditorPane myUpdateMessage;
private JBLabel myCurrentVersion;
private JBLabel myNewVersion;
private JBLabel myPatchLabel;
private JBLabel myPatchInfo;
private JEditorPane myMessageArea;
private JEditorPane myLicenseArea;
private JBScrollPane myScrollPane;
UpdateInfoPanel() {
ApplicationInfo appInfo = ApplicationInfo.getInstance();
ApplicationNamesInfo appNames = ApplicationNamesInfo.getInstance();
String message = myNewBuild.getMessage();
if (StringUtil.isEmptyOrSpaces(message)) {
String url = downloadUrl();
message = IdeBundle.message("updates.new.version.available", appNames.getFullProductName(), url);
}
configureMessageArea(myUpdateMessage, message, null, BrowserHyperlinkListener.INSTANCE);
myCurrentVersion.setText(formatVersion(appInfo.getFullVersion(), appInfo.getBuild()));
myNewVersion.setText(formatVersion(myNewBuild.getVersion(), myNewBuild.getNumber()));
if (myPatches != null && !StringUtil.isEmptyOrSpaces(myPatches.getSize())) {
myPatchInfo.setText(myPatches.getSize() + " MB");
}
else if (myTestPatch != null) {
myPatchInfo.setText(Math.max(1, myTestPatch.length() >> 20) + " MB");
}
else {
myPatchLabel.setVisible(false);
myPatchInfo.setVisible(false);
}
if (myWriteProtected) {
message = IdeBundle.message("updates.write.protected", appNames.getProductName(), PathManager.getHomePath());
configureMessageArea(myMessageArea, message, JBColor.RED, null);
}
else {
configureMessageArea(myMessageArea);
}
if (myLicenseInfo != null) {
configureMessageArea(myLicenseArea, myLicenseInfo.first, myLicenseInfo.second, null);
}
}
private void createUIComponents() {
myUpdateMessage = new JEditorPane("text/html", "") {
@Override
public Dimension getPreferredScrollableViewportSize() {
Dimension size = super.getPreferredScrollableViewportSize();
size.height = Math.min(size.height, JBUIScale.scale(400));
return size;
}
};
myScrollPane = new JBScrollPane(myUpdateMessage, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_NEVER);
myScrollPane.setBorder(JBUI.Borders.empty());
}
}
private static String formatVersion(String versionString, BuildNumber build) {
return IdeBundle.message("updates.version.info", versionString, build.asStringWithoutProductCode());
}
}
@@ -1,124 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.openapi.updateSettings.impl.UpdateInfoDialog.UpdateInfoPanel">
<grid id="27dc6" binding="myPanel" layout-manager="GridBagLayout">
<constraints>
<xy x="20" y="20" width="500" height="470"/>
</constraints>
<properties/>
<border type="empty">
<size top="0" left="5" bottom="0" right="5"/>
</border>
<children>
<grid id="d6625" layout-manager="GridLayoutManager" row-count="5" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="10" left="0" bottom="10" right="0"/>
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
<gridbag weightx="1.0" weighty="0.0"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="6ab75" class="com.intellij.ui.components.JBLabel">
<constraints>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text resource-bundle="messages/IdeBundle" key="updates.current.version"/>
</properties>
</component>
<component id="d276e" class="com.intellij.ui.components.JBLabel" binding="myCurrentVersion">
<constraints>
<grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="X.Y (build XXX.YYY)"/>
</properties>
</component>
<component id="5a935" class="com.intellij.ui.components.JBLabel">
<constraints>
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text resource-bundle="messages/IdeBundle" key="updates.available.version"/>
</properties>
</component>
<component id="ef80e" class="com.intellij.ui.components.JBLabel" binding="myNewVersion">
<constraints>
<grid row="3" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="X.Y (build XXX.YYY)"/>
</properties>
</component>
<component id="f145c" class="com.intellij.ui.components.JBLabel" binding="myPatchLabel">
<constraints>
<grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text resource-bundle="messages/IdeBundle" key="updates.patch.label"/>
</properties>
</component>
<component id="b16ba" class="com.intellij.ui.components.JBLabel" binding="myPatchInfo">
<constraints>
<grid row="4" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="XX MB"/>
</properties>
</component>
<hspacer id="2c1a8">
<constraints>
<grid row="2" column="2" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
</hspacer>
<scrollpane id="b5edb" class="com.intellij.ui.components.JBScrollPane" binding="myScrollPane" custom-create="true">
<constraints>
<grid row="0" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="2" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<horizontalScrollBarPolicy value="31"/>
</properties>
<border type="none"/>
<children/>
</scrollpane>
</children>
</grid>
<component id="63ccb" class="javax.swing.JEditorPane" binding="myMessageArea">
<constraints>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false">
<preferred-size width="150" height="50"/>
</grid>
<gridbag weightx="0.0" weighty="0.0"/>
</constraints>
<properties>
<contentType value="text/html"/>
</properties>
</component>
<vspacer id="c963e">
<constraints>
<grid row="5" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
<gridbag weightx="0.0" weighty="0.0"/>
</constraints>
</vspacer>
<vspacer id="d89a6">
<constraints>
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
<gridbag top="5" left="0" bottom="0" right="0" weightx="0.0" weighty="0.0"/>
</constraints>
</vspacer>
<component id="f5ccc" class="javax.swing.JEditorPane" binding="myLicenseArea">
<constraints>
<grid row="4" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false">
<preferred-size width="150" height="50"/>
</grid>
<gridbag weightx="0.0" weighty="0.0"/>
</constraints>
<properties>
<contentType value="text/html"/>
<editable value="false"/>
<opaque value="false"/>
</properties>
</component>
</children>
</grid>
</form>
@@ -0,0 +1,137 @@
// Copyright 2000-2019 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.updateSettings.impl
import com.intellij.ide.IdeBundle
import com.intellij.openapi.application.ApplicationInfo
import com.intellij.openapi.application.ApplicationNamesInfo
import com.intellij.openapi.application.IdeUrlTrackingParametersProvider
import com.intellij.openapi.application.PathManager
import com.intellij.openapi.options.ShowSettingsUtil
import com.intellij.openapi.ui.VerticalFlowLayout
import com.intellij.openapi.util.Pair
import com.intellij.openapi.util.text.StringUtil
import com.intellij.ui.BrowserHyperlinkListener
import com.intellij.ui.JBColor
import com.intellij.ui.ScrollPaneFactory
import com.intellij.ui.SimpleTextAttributes
import com.intellij.ui.components.JBLabel
import com.intellij.ui.components.labels.LinkLabel
import com.intellij.util.ui.JBUI
import com.intellij.util.ui.UIUtil
import java.awt.BorderLayout
import java.awt.Color
import java.awt.FlowLayout
import java.io.File
import javax.swing.JEditorPane
import javax.swing.JPanel
import kotlin.math.max
object UpdateInfoPanelUI {
private const val MB_UNITS = "MB"
private const val PATCH_SIZE_IS = "Patch size is"
private val FROM_TO_PATCHES_REGEXP: Regex = "from \\d+ to (\\d+)".toRegex()
private val DIVIDER_COLOR = JBColor(0xd9d9d9, 0x515151)
fun createPanel(newBuild: BuildInfo,
patches: UpdateChain?,
testPatch: File?,
writeProtected: Boolean,
licenseInfo: Pair<String, Color>?,
enableLink: Boolean,
updatedChannel: UpdateChannel): JPanel {
val panel = JPanel(BorderLayout())
val appInfo = ApplicationInfo.getInstance()
val appNames = ApplicationNamesInfo.getInstance()
val updateHighlightsComponent = object : JEditorPane("text/html", "") {}
.also {
val cssFontDeclaration = UIUtil.getCssFontDeclaration(UIUtil.getLabelFont(), null, null, null)
val updateHighlightsContent = updateHighlightsContent(appNames, patches, testPatch, newBuild, updatedChannel)
it.text = """<html><head>$cssFontDeclaration</head><body>$updateHighlightsContent</body></html>"""
}
.also { it.caretPosition = 0 }
.also { it.isEditable = false }
.also { it.border = JBUI.Borders.empty(8, 12) }
.also { it.addHyperlinkListener(BrowserHyperlinkListener.INSTANCE) }
val updateHighlightsScrollPane = ScrollPaneFactory.createScrollPane(updateHighlightsComponent, true)
.also { it.border = JBUI.Borders.customLine(DIVIDER_COLOR, 0, 0, 1, 0) }
val updatingVersionAndPatches = JBLabel()
.also { it.border = JBUI.Borders.empty() }
.also { it.foreground = SimpleTextAttributes.GRAY_ITALIC_ATTRIBUTES.fgColor }
.also {
val patchSize = calculatePatchSize(patches, testPatch)
it.text = """Updating ${appInfo.fullVersion} to ${newBuild.version} (${newBuild.number}).$patchSize"""
}
val updatingInfoPanel = JPanel(FlowLayout(FlowLayout.LEFT, 2, 0))
.also { it.add(updatingVersionAndPatches, BorderLayout.WEST) }
.also { getSettingsLink(panel, writeProtected, enableLink, appNames)?.let { link -> it.add(link) } }
val infoPanel = JPanel(VerticalFlowLayout(0, 0))
.also { it.border = JBUI.Borders.empty(8, 12) }
if (licenseInfo != null) {
infoPanel.add(JBLabel(licenseInfo.first).also { label -> label.foreground = licenseInfo.second })
}
infoPanel.add(updatingInfoPanel)
panel.add(updateHighlightsScrollPane, BorderLayout.CENTER)
panel.add(infoPanel, BorderLayout.SOUTH)
return panel
}
private fun getSettingsLink(panel: JPanel, writeProtected: Boolean, enableLink: Boolean, appNames: ApplicationNamesInfo): LinkLabel<*>? {
if (!enableLink) {
return null
}
return if (writeProtected) {
getConfigLink(panel, IdeBundle.message("updates.write.protected", appNames.productName, PathManager.getHomePath()))
.also { it.foreground = JBColor.RED }
}
else {
getConfigLink(panel, IdeBundle.message("updates.configure.label"))
}
}
private fun getConfigLink(panel: JPanel, text: String?): LinkLabel<*> {
return LinkLabel.create(text) { ShowSettingsUtil.getInstance().editConfigurable(panel, UpdateSettingsConfigurable(false)) }
}
private fun getPatchesText(patches: UpdateChain?, testPatch: File?): String? {
return if (patches != null && !StringUtil.isEmptyOrSpaces(patches.size)) {
patches.size
}
else if (testPatch != null) {
max(1, testPatch.length() shr 20).toString()
} else null
}
private fun updateHighlightsContent(appNames: ApplicationNamesInfo,
patches: UpdateChain?,
testPatch: File?,
newBuildInfo: BuildInfo,
updateChannel: UpdateChannel): String {
var message = newBuildInfo.message
if (message.isBlank()) {
message = IdeBundle.message("updates.new.version.available", appNames.fullProductName, downloadUrl(newBuildInfo, updateChannel))
}
return "$message<br><br>" + newBuildInfo.buttons.filter { !it.isDownload || patches == null && testPatch == null }
.joinToString("<br>") { "<a href=\"${it.url}\">${it.name}</href>" }
}
private fun calculatePatchSize(patchesChain: UpdateChain?, testPatch: File?): String {
val patchesSize = getPatchesText(patchesChain, testPatch)
return FROM_TO_PATCHES_REGEXP.matchEntire(patchesSize?: return "")?.let { " $PATCH_SIZE_IS about ${it.groupValues[1]} $MB_UNITS." }
?: " $PATCH_SIZE_IS $patchesSize."
}
private fun downloadUrl(newBuildInfo: BuildInfo, updateChannel: UpdateChannel): String {
return IdeUrlTrackingParametersProvider.getInstance().augmentUrl(
newBuildInfo.downloadUrl ?: newBuildInfo.blogPost ?: updateChannel.url ?: "https://www.jetbrains.com")
}
}
@@ -996,7 +996,7 @@ updates.no.updates.unknown.message=<html>All plugins are up to date.<br> \
{0} updates are managed externally by {1}.</html>
updates.plugins.ready.header=<html><b>Plugins from configured hosts are ready to update.</b><br> \
Check plugins you want to update.</html>
updates.configure.label=<b><a href=\"updates\">Configure</a></b> automatic updates.
updates.configure.label=Configure updates...
updates.incompatible.plugins.found={0,choice,1#Plugin|2#Plugins} incompatible with the new build found:{0,choice,1#' '|2#'<br/>'} {1}
updates.download.and.restart.button=Up&date and Restart
updates.apply.manually.button=Up&date Manually