[ui] common legal notice dialog component

This commit is contained in:
Roman Shevchenko
2018-04-04 17:01:11 +02:00
parent 001f4fa6db
commit 8cb4677ec4
6 changed files with 166 additions and 128 deletions
@@ -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) + "<br/><a href='accept'>Accept</a>&nbsp;&nbsp;<a href='decline'>Decline</a>";
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) + "<br/><a href='accept'>Accept</a>&nbsp;&nbsp;<a href='decline'>Decline</a>";
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.<br/>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(), " - ") + "\".<br/><br/>" +
"<b>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.</b>";
}
}
@@ -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(), " - ") +
"\".<br/><br/>" +
"<b>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.</b>";
}
@Override
protected void doOKAction() {
AcceptedLanguageLevelsSettings.acceptLanguageLevel(myLanguageLevel);
super.doOKAction();
}
}
@@ -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<String, Integer> 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<Action> 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;
}
}
@@ -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
@@ -13,9 +13,7 @@ legal.notice.text=\
<br><br>\
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.\
<br><br>
legal.notice.action.accept=Accept
in violation of applicable laws.
legal.notice.action.reject=Decline and restart
legal.notice.action.postpone=Decide later
@@ -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<String, Any> {
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<CharSequence> { 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<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 = "<div style='margin:5px;'>${IdeaDecompilerBundle.message("legal.notice.text")}</div>"
val panel = JBPanel<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
}
}