From 8cb4677ec457d89971aee44175134d993d260f34 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 4 Apr 2018 17:00:52 +0200 Subject: [PATCH] [ui] common legal notice dialog component --- .../java/AcceptedLanguageLevelsSettings.java | 40 ++++-- .../intellij/pom/java/LegalNoticeDialog.java | 61 --------- .../ui/components/LegalNoticeDialog.java | 118 ++++++++++++++++++ .../src/messages/CommonBundle.properties | 2 + .../plugin/src/messages/Decompiler.properties | 4 +- .../java/decompiler/IdeaDecompiler.kt | 69 ++-------- 6 files changed, 166 insertions(+), 128 deletions(-) delete mode 100644 java/java-impl/src/com/intellij/pom/java/LegalNoticeDialog.java create mode 100644 platform/platform-impl/src/com/intellij/ui/components/LegalNoticeDialog.java diff --git a/java/java-impl/src/com/intellij/pom/java/AcceptedLanguageLevelsSettings.java b/java/java-impl/src/com/intellij/pom/java/AcceptedLanguageLevelsSettings.java index bb7cf6c84020..fec689dd1eff 100644 --- a/java/java-impl/src/com/intellij/pom/java/AcceptedLanguageLevelsSettings.java +++ b/java/java-impl/src/com/intellij/pom/java/AcceptedLanguageLevelsSettings.java @@ -12,7 +12,10 @@ import com.intellij.openapi.roots.LanguageLevelModuleExtensionImpl; import com.intellij.openapi.roots.LanguageLevelProjectExtension; import com.intellij.openapi.startup.StartupActivity; import com.intellij.openapi.startup.StartupManager; +import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.ui.components.LegalNoticeDialog; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; import com.intellij.util.xmlb.XmlSerializerUtil; @@ -65,7 +68,7 @@ public class AcceptedLanguageLevelsSettings implements PersistentStateComponent< return LanguageLevel.HIGHEST.compareTo(languageLevel) >= 0 || getSettings().acceptedNames.contains(languageLevel.name()); } - public static void acceptLanguageLevel(LanguageLevel languageLevel) { + private static void acceptLanguageLevel(LanguageLevel languageLevel) { getSettings().acceptedNames.add(languageLevel.name()); } @@ -98,21 +101,32 @@ public class AcceptedLanguageLevelsSettings implements PersistentStateComponent< } /** - * Show legal dialog and set highest accepted level if dialog is rejected + * Shows a legal notice dialog and downgrades to the highest accepted level if the dialog is rejected. * * @return {@code null} if level was rejected */ public static LanguageLevel checkAccepted(Component parent, LanguageLevel level) { - return level == null || isLanguageLevelAccepted(level) || new LegalNoticeDialog(parent, level).showAndGet() ? level : null; + return level == null || isLanguageLevelAccepted(level) || showDialog(parent, level) ? level : null; } - private static Notification createNotification(LanguageLevel l, Project project) { - String content = LegalNoticeDialog.getLegalNotice(l) + "
Accept  Decline"; + private static boolean showDialog(Component parent, LanguageLevel level) { + int result = LegalNoticeDialog.build(EXPERIMENTAL_FEATURE_ALERT, getLegalNotice(level)).withParent(parent).show(); + if (result == DialogWrapper.OK_EXIT_CODE) { + acceptLanguageLevel(level); + return true; + } + else { + return false; + } + } + + private static Notification createNotification(LanguageLevel level, Project project) { + String content = getLegalNotice(level) + "
Accept  Decline"; return NOTIFICATION_GROUP.createNotification( - LegalNoticeDialog.EXPERIMENTAL_FEATURE_ALERT, content, NotificationType.WARNING, (notification, event) -> { + EXPERIMENTAL_FEATURE_ALERT, content, NotificationType.WARNING, (notification, event) -> { if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { switch (event.getDescription()) { - case "accept": acceptLanguageLevel(l); break; + case "accept": acceptLanguageLevel(level); break; case "decline": decreaseLanguageLevel(project); break; } notification.expire(); @@ -122,7 +136,7 @@ public class AcceptedLanguageLevelsSettings implements PersistentStateComponent< private static void decreaseLanguageLevel(Project project) { String message = UIUtil.toHtml("Support for experimental features was rejected.
Language levels would be decreased accordingly"); - Messages.showErrorDialog(project, message, LegalNoticeDialog.EXPERIMENTAL_FEATURE_ALERT); + Messages.showErrorDialog(project, message, EXPERIMENTAL_FEATURE_ALERT); WriteAction.run(() -> { LanguageLevel highestAcceptedLevel = getHighestAcceptedLevel(); @@ -141,4 +155,14 @@ public class AcceptedLanguageLevelsSettings implements PersistentStateComponent< } }); } + + private static final String EXPERIMENTAL_FEATURE_ALERT = "Experimental Feature Alert"; + + private static String getLegalNotice(LanguageLevel level) { + return + "You must accept the terms of legal notice of the beta Java specification to enable support for " + + "\"" + StringUtil.substringAfter(level.getPresentableText(), " - ") + "\".

" + + "The implementation of an early-draft specification developed under the Java Community Process (JCP) " + + "is made available for testing and evaluation purposes only and is not compatible with any specification of the JCP."; + } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/pom/java/LegalNoticeDialog.java b/java/java-impl/src/com/intellij/pom/java/LegalNoticeDialog.java deleted file mode 100644 index ad41c85cbc0b..000000000000 --- a/java/java-impl/src/com/intellij/pom/java/LegalNoticeDialog.java +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2000-2018 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.pom.java; - -import com.intellij.icons.AllIcons; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.ui.components.JBLabel; -import com.intellij.util.ui.JBUI; -import com.intellij.util.ui.UIUtil; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.awt.*; - -class LegalNoticeDialog extends DialogWrapper { - static final String EXPERIMENTAL_FEATURE_ALERT = "Experimental Feature Alert"; - private final LanguageLevel myLanguageLevel; - - public LegalNoticeDialog(Component parentComponent, LanguageLevel languageLevel) { - super(parentComponent, false); - myLanguageLevel = languageLevel; - setTitle(EXPERIMENTAL_FEATURE_ALERT); - init(); - setOKButtonText("Accept"); - setCancelButtonText("Decline"); - pack(); - } - - @Nullable - @Override - protected JComponent createCenterPanel() { - JPanel panel = new JPanel(new BorderLayout()); - JPanel iconPanel = new JPanel(new BorderLayout()); - iconPanel.add(new JBLabel(AllIcons.General.WarningDialog), BorderLayout.NORTH); - iconPanel.setBorder(JBUI.Borders.emptyRight(2)); - panel.add(iconPanel, BorderLayout.WEST); - JEditorPane message = new JEditorPane(); - message.setEditorKit(UIUtil.getHTMLEditorKit()); - message.setEditable(false); - message.setBackground(UIUtil.getOptionPaneBackground()); - message.setPreferredSize(JBUI.size(500, 100)); - message.setText(UIUtil.toHtml(getLegalNotice(myLanguageLevel))); - panel.add(message, BorderLayout.CENTER); - return panel; - } - - static String getLegalNotice(LanguageLevel languageLevel) { - return - "You must accept the terms of legal notice of the beta Java specification to enable support for \"" + - StringUtil.substringAfter(languageLevel.getPresentableText(), " - ") + - "\".

" + - "The implementation of an early-draft specification developed under the Java Community Process (JCP) " + - "is made available for testing and evaluation purposes only and is not compatible with any specification of the JCP."; - } - - @Override - protected void doOKAction() { - AcceptedLanguageLevelsSettings.acceptLanguageLevel(myLanguageLevel); - super.doOKAction(); - } -} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ui/components/LegalNoticeDialog.java b/platform/platform-impl/src/com/intellij/ui/components/LegalNoticeDialog.java new file mode 100644 index 000000000000..88a60f2b27e0 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ui/components/LegalNoticeDialog.java @@ -0,0 +1,118 @@ +// Copyright 2000-2018 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.ui.components; + +import com.intellij.CommonBundle; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.util.Pair; +import com.intellij.ui.Gray; +import com.intellij.util.ui.JBUI; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import javax.swing.border.CompoundBorder; +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +import static com.intellij.openapi.util.Pair.pair; + +public final class LegalNoticeDialog extends DialogWrapper { + public static final class Builder { + private final String title; + private final String message; + private Project project; + private Component parent; + private String cancelText; + private Pair customAction; + + private Builder(String title, String message) { + this.title = title; + this.message = message; + } + + public Builder withParent(Project project) { + this.project = project; + return this; + } + + public Builder withParent(Component parent) { + this.parent = parent; + return this; + } + + public Builder withCancelText(@NotNull @Nls String text) { + cancelText = text; + return this; + } + + public Builder withCustomAction(@NotNull @Nls String text, int exitCode) { + assert exitCode >= DialogWrapper.NEXT_USER_EXIT_CODE; + customAction = pair(text, exitCode); + return this; + } + + public int show() { + LegalNoticeDialog dialog = new LegalNoticeDialog(this); + dialog.show(); + return dialog.getExitCode(); + } + } + + public static Builder build(@NotNull @Nls(capitalization = Nls.Capitalization.Title) String title, + @NotNull @Nls(capitalization = Nls.Capitalization.Sentence) String message) { + return new Builder(title, message); + } + + private final Builder myBuilder; + private JComponent myFocusedComponent; + + private LegalNoticeDialog(Builder builder) { + super(builder.project, builder.parent, true, IdeModalityType.PROJECT); + myBuilder = builder; + setTitle(builder.title); + setOKButtonText(CommonBundle.message("button.accept")); + setCancelButtonText(builder.cancelText != null ? builder.cancelText : CommonBundle.message("button.decline")); + init(); + pack(); + } + + @Override + protected JComponent createCenterPanel() { + JPanel iconPanel = new JPanel(new BorderLayout()); + iconPanel.add(new JBLabel(AllIcons.General.WarningDialog), BorderLayout.NORTH); + + JEditorPane messageArea = new JEditorPane(); + messageArea.setEditorKit(UIUtil.getHTMLEditorKit()); + messageArea.setEditable(false); + messageArea.setPreferredSize(JBUI.size(500, 100)); + messageArea.setBorder(new CompoundBorder(BorderFactory.createLineBorder(Gray._200), JBUI.Borders.empty(3))); + messageArea.setText(UIUtil.toHtml(myBuilder.message)); + myFocusedComponent = messageArea; + + JPanel panel = new JPanel(new BorderLayout(JBUI.scale(3), 0)); + panel.add(iconPanel, BorderLayout.WEST); + panel.add(messageArea, BorderLayout.CENTER); + return panel; + } + + @NotNull + @Override + protected Action[] createActions() { + List actions = new ArrayList<>(); + actions.add(getOKAction()); + if (myBuilder.customAction != null) { + actions.add(new DialogWrapperExitAction(myBuilder.customAction.first, myBuilder.customAction.second)); + } + actions.add(getCancelAction()); + return actions.toArray(new Action[0]); + } + + @Override + public JComponent getPreferredFocusedComponent() { + return myFocusedComponent; + } +} \ No newline at end of file diff --git a/platform/platform-resources-en/src/messages/CommonBundle.properties b/platform/platform-resources-en/src/messages/CommonBundle.properties index d71ded1d3e7c..bf94ecd0f3ea 100644 --- a/platform/platform-resources-en/src/messages/CommonBundle.properties +++ b/platform/platform-resources-en/src/messages/CommonBundle.properties @@ -44,6 +44,8 @@ close.action.name=Close button.edit=Edit button.remove=Remove button.remove.r=&Remove +button.accept=Accept +button.decline=Decline title.settings=Settings title.settings.mac=Preferences diff --git a/plugins/java-decompiler/plugin/src/messages/Decompiler.properties b/plugins/java-decompiler/plugin/src/messages/Decompiler.properties index 6af5a1347816..9a3d5d22f82e 100644 --- a/plugins/java-decompiler/plugin/src/messages/Decompiler.properties +++ b/plugins/java-decompiler/plugin/src/messages/Decompiler.properties @@ -13,9 +13,7 @@ legal.notice.text=\

\ Using JetBrains Decompiler is entirely optional. Licensor does neither encourage nor condone \ the use of JetBrains Decompiler, and disclaims any liability for Licensee's use of JetBrains Decompiler \ - in violation of applicable laws.\ -

-legal.notice.action.accept=Accept + in violation of applicable laws. legal.notice.action.reject=Decline and restart legal.notice.action.postpone=Decide later diff --git a/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/IdeaDecompiler.kt b/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/IdeaDecompiler.kt index bb8d6f69631c..4a8c430dd47f 100644 --- a/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/IdeaDecompiler.kt +++ b/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/IdeaDecompiler.kt @@ -3,7 +3,6 @@ package org.jetbrains.java.decompiler import com.intellij.application.options.CodeStyle import com.intellij.execution.filters.LineNumbersMapping -import com.intellij.icons.AllIcons import com.intellij.ide.highlighter.JavaFileType import com.intellij.ide.plugins.PluginManagerCore import com.intellij.ide.util.PropertiesComponent @@ -15,7 +14,6 @@ import com.intellij.openapi.fileEditor.FileEditorManagerListener import com.intellij.openapi.fileTypes.StdFileTypes import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.openapi.progress.ProgressManager -import com.intellij.openapi.project.Project import com.intellij.openapi.ui.DialogWrapper import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.registry.Registry @@ -27,27 +25,19 @@ import com.intellij.psi.PsiJavaModule import com.intellij.psi.PsiPackage import com.intellij.psi.compiled.ClassFileDecompilers import com.intellij.psi.impl.compiled.ClsFileImpl -import com.intellij.ui.Gray -import com.intellij.ui.components.JBLabel -import com.intellij.ui.components.JBPanel +import com.intellij.ui.components.LegalNoticeDialog import com.intellij.util.ArrayUtil import com.intellij.util.containers.ContainerUtil -import com.intellij.util.ui.JBUI -import com.intellij.util.ui.UIUtil import org.jetbrains.java.decompiler.main.decompiler.BaseDecompiler import org.jetbrains.java.decompiler.main.extern.IBytecodeProvider import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences import org.jetbrains.java.decompiler.main.extern.IResultSaver -import java.awt.BorderLayout import java.io.File import java.io.IOException import java.util.* import java.util.concurrent.Callable import java.util.concurrent.Future import java.util.jar.Manifest -import javax.swing.BorderFactory -import javax.swing.JComponent -import javax.swing.JEditorPane class IdeaDecompiler : ClassFileDecompilers.Light() { companion object { @@ -55,6 +45,9 @@ class IdeaDecompiler : ClassFileDecompilers.Light() { private const val LEGAL_NOTICE_KEY = "decompiler.legal.notice.accepted" + private const val POSTPONE_EXIT_CODE = DialogWrapper.CANCEL_EXIT_CODE + private const val DECLINE_EXIT_CODE = DialogWrapper.NEXT_USER_EXIT_CODE + private fun getOptions(): Map { val options = CodeStyle.getDefaultSettings().getIndentOptions(JavaFileType.INSTANCE) val indent = StringUtil.repeat(" ", options.INDENT_SIZE) @@ -92,9 +85,13 @@ class IdeaDecompiler : ClassFileDecompilers.Light() { if (!myLegalNoticeAccepted && file.fileType === StdFileTypes.CLASS && ClassFileDecompilers.find(file) === this@IdeaDecompiler) { myFutures[file] = app.executeOnPooledThread(Callable { decompile(file) }) - val dialog = LegalNoticeDialog(source.project, file) - dialog.show() - when (dialog.exitCode) { + val title = IdeaDecompilerBundle.message("legal.notice.title", StringUtil.last(file.path, 40, true)) + val message = IdeaDecompilerBundle.message("legal.notice.text") + val result = LegalNoticeDialog.build(title, message) + .withCancelText(IdeaDecompilerBundle.message("legal.notice.action.postpone")) + .withCustomAction(IdeaDecompilerBundle.message("legal.notice.action.reject"), DECLINE_EXIT_CODE) + .show() + when (result) { DialogWrapper.OK_EXIT_CODE -> { PropertiesComponent.getInstance().setValue(LEGAL_NOTICE_KEY, true) myLegalNoticeAccepted = true @@ -107,13 +104,13 @@ class IdeaDecompiler : ClassFileDecompilers.Light() { connection.disconnect() } - LegalNoticeDialog.DECLINE_EXIT_CODE -> { + DECLINE_EXIT_CODE -> { myFutures.remove(file)?.cancel(true) PluginManagerCore.disablePlugin("org.jetbrains.java.decompiler") ApplicationManagerEx.getApplicationEx().restart(true) } - LegalNoticeDialog.POSTPONE_EXIT_CODE -> { + POSTPONE_EXIT_CODE -> { myFutures.remove(file)?.cancel(true) } } @@ -236,44 +233,4 @@ class IdeaDecompiler : ClassFileDecompilers.Light() { return -1 } } - - private class LegalNoticeDialog(project: Project, file: VirtualFile) : DialogWrapper(project) { - companion object { - const val POSTPONE_EXIT_CODE = DialogWrapper.CANCEL_EXIT_CODE - const val DECLINE_EXIT_CODE = DialogWrapper.NEXT_USER_EXIT_CODE - } - - private var myMessage: JEditorPane? = null - - init { - title = IdeaDecompilerBundle.message("legal.notice.title", StringUtil.last(file.path, 40, true)) - setOKButtonText(IdeaDecompilerBundle.message("legal.notice.action.accept")) - setCancelButtonText(IdeaDecompilerBundle.message("legal.notice.action.postpone")) - init() - pack() - } - - override fun createCenterPanel(): JComponent? { - val iconPanel = JBPanel>(BorderLayout()) - iconPanel.add(JBLabel(AllIcons.General.WarningDialog), BorderLayout.NORTH) - - val message = JEditorPane() - myMessage = message - message.editorKit = UIUtil.getHTMLEditorKit() - message.isEditable = false - message.preferredSize = JBUI.size(500, 100) - message.border = BorderFactory.createLineBorder(Gray._200) - message.text = "
${IdeaDecompilerBundle.message("legal.notice.text")}
" - - val panel = JBPanel>(BorderLayout(JBUI.scale(10), 0)) - panel.add(iconPanel, BorderLayout.WEST) - panel.add(message, BorderLayout.CENTER) - return panel - } - - override fun createActions() = - arrayOf(okAction, DialogWrapperExitAction(IdeaDecompilerBundle.message("legal.notice.action.reject"), DECLINE_EXIT_CODE), cancelAction) - - override fun getPreferredFocusedComponent() = myMessage - } } \ No newline at end of file