From 88f279ae7fd7e5e7d92458dc2af10e9826efacff Mon Sep 17 00:00:00 2001 From: "Dmitry.Krasilschikov" Date: Mon, 7 Oct 2019 15:20:50 +0300 Subject: [PATCH] IDEA-223967 new update dialog GitOrigin-RevId: 7d330d57cd10c6e4e8a2aa7298715129b3bf7e37 --- .../impl/AbstractUpdateDialog.java | 2 +- .../updateSettings/impl/UpdateInfoDialog.java | 158 +++++------------- .../updateSettings/impl/UpdateInfoPanel.form | 124 -------------- .../updateSettings/impl/UpdateInfoPanelUI.kt | 137 +++++++++++++++ .../src/messages/IdeBundle.properties | 2 +- 5 files changed, 178 insertions(+), 245 deletions(-) delete mode 100644 platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateInfoPanel.form create mode 100644 platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateInfoPanelUI.kt diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/AbstractUpdateDialog.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/AbstractUpdateDialog.java index cdb5a4d6ac2e..94e03a63b04c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/AbstractUpdateDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/AbstractUpdateDialog.java @@ -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); diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateInfoDialog.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateInfoDialog.java index 89ca28fe3711..101435577984 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateInfoDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateInfoDialog.java @@ -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 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 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 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()); - } } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateInfoPanel.form b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateInfoPanel.form deleted file mode 100644 index 6e604796c39e..000000000000 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateInfoPanel.form +++ /dev/null @@ -1,124 +0,0 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateInfoPanelUI.kt b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateInfoPanelUI.kt new file mode 100644 index 000000000000..0321bf65d09c --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateInfoPanelUI.kt @@ -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?, + 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 = """$cssFontDeclaration$updateHighlightsContent""" + } + .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

" + newBuildInfo.buttons.filter { !it.isDownload || patches == null && testPatch == null } + .joinToString("
") { "${it.name}" } + } + + 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") + } +} \ No newline at end of file diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties index b0e97262287d..ca6e050020b5 100644 --- a/platform/platform-resources-en/src/messages/IdeBundle.properties +++ b/platform/platform-resources-en/src/messages/IdeBundle.properties @@ -996,7 +996,7 @@ updates.no.updates.unknown.message=All plugins are up to date.
\ {0} updates are managed externally by {1}. updates.plugins.ready.header=Plugins from configured hosts are ready to update.
\ Check plugins you want to update. -updates.configure.label=
Configure 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#'
'} {1} updates.download.and.restart.button=Up&date and Restart updates.apply.manually.button=Up&date Manually