| /* |
| * Copyright 2000-2014 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.intellij.ide.actions; |
| |
| import com.intellij.ide.BrowserUtil; |
| import com.intellij.ide.IdeBundle; |
| import com.intellij.openapi.actionSystem.AnActionEvent; |
| import com.intellij.openapi.actionSystem.CustomShortcutSet; |
| import com.intellij.openapi.application.ApplicationInfo; |
| import com.intellij.openapi.application.ex.ApplicationInfoEx; |
| import com.intellij.openapi.application.impl.ApplicationInfoImpl; |
| import com.intellij.openapi.ide.CopyPasteManager; |
| import com.intellij.openapi.project.DumbAwareAction; |
| import com.intellij.openapi.ui.popup.JBPopupFactory; |
| import com.intellij.openapi.util.IconLoader; |
| import com.intellij.openapi.util.SystemInfo; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.ui.JBColor; |
| import com.intellij.ui.LicensingFacade; |
| import com.intellij.ui.UI; |
| import com.intellij.ui.awt.RelativePoint; |
| import com.intellij.util.text.DateFormatUtil; |
| import com.intellij.util.ui.UIUtil; |
| import org.jetbrains.annotations.Nullable; |
| |
| import javax.swing.*; |
| import java.awt.*; |
| import java.awt.datatransfer.StringSelection; |
| import java.awt.event.MouseAdapter; |
| import java.awt.event.MouseEvent; |
| import java.awt.event.MouseMotionAdapter; |
| import java.text.SimpleDateFormat; |
| import java.util.ArrayList; |
| import java.util.Calendar; |
| import java.util.List; |
| import java.util.Properties; |
| |
| /** |
| * @author Konstantin Bulenkov |
| */ |
| public class AboutPopup { |
| public void show(@Nullable Window window) { |
| ApplicationInfoEx appInfo = (ApplicationInfoEx)ApplicationInfo.getInstance(); |
| |
| JPanel panel = new JPanel(new BorderLayout()); |
| Icon image = IconLoader.getIcon(appInfo.getAboutImageUrl()); |
| if (appInfo.showLicenseeInfo()) { |
| final InfoSurface infoSurface = new InfoSurface(image); |
| infoSurface.setPreferredSize(new Dimension(image.getIconWidth(), image.getIconHeight())); |
| panel.add(infoSurface, BorderLayout.NORTH); |
| |
| new DumbAwareAction() { |
| @Override |
| public void actionPerformed(AnActionEvent e) { |
| copyInfoToClipboard(infoSurface.getText()); |
| } |
| }.registerCustomShortcutSet(CustomShortcutSet.fromString("meta C", "control C"), panel); |
| } |
| else { |
| panel.add(new JLabel(image), BorderLayout.NORTH); |
| } |
| |
| RelativePoint location; |
| if (window != null) { |
| Rectangle r = window.getBounds(); |
| location = new RelativePoint(window, new Point((r.width - image.getIconWidth()) / 2, (r.height - image.getIconHeight()) / 2)); |
| } |
| else { |
| Rectangle r = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().getBounds(); |
| location = new RelativePoint(new Point((r.width - image.getIconWidth()) / 2, (r.height - image.getIconHeight()) / 2)); |
| } |
| |
| JBPopupFactory.getInstance().createComponentPopupBuilder(panel, panel) |
| .setRequestFocus(true) |
| .setFocusable(true) |
| .setResizable(false) |
| .setMovable(false) |
| .setModalContext(false) |
| .setShowShadow(true) |
| .setShowBorder(false) |
| .setCancelKeyEnabled(true) |
| .setCancelOnClickOutside(true) |
| .setCancelOnOtherWindowOpen(true) |
| .createPopup() |
| .show(location); |
| } |
| |
| private static void copyInfoToClipboard(String text) { |
| try { |
| CopyPasteManager.getInstance().setContents(new StringSelection(text)); |
| } |
| catch (Exception ignore) { } |
| } |
| |
| private static class InfoSurface extends JPanel { |
| private final Color myColor; |
| private final Color myLinkColor; |
| private final Icon myImage; |
| private Font myFont; |
| private Font myBoldFont; |
| private final List<AboutBoxLine> myLines = new ArrayList<AboutBoxLine>(); |
| private StringBuilder myInfo = new StringBuilder(); |
| private final List<Link> myLinks = new ArrayList<Link>(); |
| private Link myActiveLink; |
| |
| public InfoSurface(Icon image) { |
| ApplicationInfoImpl appInfo = (ApplicationInfoImpl)ApplicationInfoEx.getInstanceEx(); |
| |
| myImage = image; |
| //noinspection UseJBColor |
| myColor = Color.white; |
| myLinkColor = appInfo.getAboutLinkColor() != null ? appInfo.getAboutLinkColor() : UI.getColor("link.foreground"); |
| |
| setOpaque(false); |
| setBackground(myColor); |
| |
| Calendar cal = appInfo.getBuildDate(); |
| myLines.add(new AboutBoxLine(appInfo.getFullApplicationName(), true, null)); |
| appendLast(); |
| |
| String buildInfo = IdeBundle.message("about.box.build.number", appInfo.getBuild().asString()); |
| String buildDate = ""; |
| if (appInfo.getBuild().isSnapshot()) { |
| buildDate = new SimpleDateFormat("HH:mm, ").format(cal.getTime()); |
| } |
| buildDate += DateFormatUtil.formatAboutDialogDate(cal.getTime()); |
| buildInfo += IdeBundle.message("about.box.build.date", buildDate); |
| myLines.add(new AboutBoxLine(buildInfo)); |
| appendLast(); |
| |
| myLines.add(new AboutBoxLine("")); |
| |
| LicensingFacade provider = LicensingFacade.getInstance(); |
| if (provider != null) { |
| myLines.add(new AboutBoxLine(provider.getLicensedToMessage(), true, null)); |
| for (String message : provider.getLicenseRestrictionsMessages()) { |
| myLines.add(new AboutBoxLine(message)); |
| } |
| } |
| |
| myLines.add(new AboutBoxLine("")); |
| |
| Properties properties = System.getProperties(); |
| String javaVersion = properties.getProperty("java.runtime.version", properties.getProperty("java.version", "unknown")); |
| String arch = properties.getProperty("os.arch", ""); |
| myLines.add(new AboutBoxLine(IdeBundle.message("about.box.jre", javaVersion, arch))); |
| appendLast(); |
| |
| String vmVersion = properties.getProperty("java.vm.name", "unknown"); |
| String vmVendor = properties.getProperty("java.vendor", "unknown"); |
| myLines.add(new AboutBoxLine(IdeBundle.message("about.box.vm", vmVersion, vmVendor))); |
| appendLast(); |
| |
| String thirdParty = appInfo.getThirdPartySoftwareURL(); |
| if (thirdParty != null) { |
| myLines.add(new AboutBoxLine("")); |
| myLines.add(new AboutBoxLine("")); |
| myLines.add(new AboutBoxLine("Powered by ").keepWithNext()); |
| myLines.add(new AboutBoxLine("open-source software", false, thirdParty).keepWithNext()); |
| } |
| |
| addMouseListener(new MouseAdapter() { |
| @Override |
| public void mousePressed(MouseEvent event) { |
| if (myActiveLink != null) { |
| event.consume(); |
| BrowserUtil.browse(myActiveLink.myUrl); |
| } |
| } |
| }); |
| |
| addMouseMotionListener(new MouseMotionAdapter() { |
| @Override |
| public void mouseMoved(MouseEvent event) { |
| boolean hadLink = (myActiveLink != null); |
| myActiveLink = null; |
| for (Link link : myLinks) { |
| if (link.myRectangle.contains(event.getPoint())) { |
| myActiveLink = link; |
| if (!hadLink) { |
| setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); |
| } |
| break; |
| } |
| } |
| if (hadLink && myActiveLink == null) { |
| setCursor(Cursor.getDefaultCursor()); |
| } |
| } |
| }); |
| } |
| |
| private void appendLast() { |
| myInfo.append(myLines.get(myLines.size() - 1).getText()).append("\n"); |
| } |
| |
| @Override |
| protected void paintChildren(Graphics g) { |
| super.paintChildren(g); |
| |
| Graphics2D g2 = (Graphics2D)g; |
| UIUtil.applyRenderingHints(g); |
| |
| Font labelFont = UIUtil.getLabelFont(); |
| if (SystemInfo.isWindows) { |
| labelFont = new Font("Tahoma", Font.PLAIN, 12); |
| } |
| |
| for (int labelSize = 10; labelSize != 6; labelSize -= 1) { |
| myLinks.clear(); |
| g2.setPaint(myColor); |
| myImage.paintIcon(this, g2, 0, 0); |
| |
| g2.setColor(myColor); |
| TextRenderer renderer = new TextRenderer(0, 165, 398, 120, g2); |
| UIUtil.setupComposite(g2); |
| myFont = labelFont.deriveFont(Font.PLAIN, labelSize); |
| myBoldFont = labelFont.deriveFont(Font.BOLD, labelSize + 1); |
| try { |
| renderer.render(30, 0, myLines); |
| break; |
| } |
| catch (TextRenderer.OverflowException ignore) { } |
| } |
| |
| ApplicationInfo appInfo = ApplicationInfo.getInstance(); |
| Rectangle aboutLogoRect = appInfo.getAboutLogoRect(); |
| if (aboutLogoRect != null) { |
| myLinks.add(new Link(aboutLogoRect, appInfo.getCompanyURL())); |
| } |
| |
| if (appInfo instanceof ApplicationInfoImpl) { |
| g2.setColor(((ApplicationInfoImpl)appInfo).getCopyrightForeground()); |
| if (SystemInfo.isMac) { |
| g2.setFont(UIUtil.getLabelFont(UIUtil.FontSize.MINI)); |
| } |
| else { |
| g2.setFont(new Font("Tahoma", Font.PLAIN, 10)); |
| } |
| } else { |
| g2.setColor(JBColor.BLACK); |
| } |
| g2.drawString("\u00A9 2000\u2013" + Calendar.getInstance().get(Calendar.YEAR) + " JetBrains s.r.o. All rights reserved.", 30, 284); |
| } |
| |
| public String getText() { |
| return myInfo.toString(); |
| } |
| |
| private class TextRenderer { |
| private final int xBase; |
| private final int yBase; |
| private final int w; |
| private final int h; |
| private final Graphics2D g2; |
| |
| private int x = 0; |
| private int y = 0; |
| private FontMetrics fontmetrics; |
| private int fontAscent; |
| private int fontHeight; |
| private Font font; |
| |
| public class OverflowException extends Exception { } |
| |
| public TextRenderer(final int xBase, final int yBase, final int w, final int h, final Graphics2D g2) { |
| this.xBase = xBase; |
| this.yBase = yBase; |
| this.w = w; |
| this.h = h; |
| this.g2 = g2; |
| |
| if (SystemInfo.isWindows) { |
| g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); |
| } |
| } |
| |
| public void render(int indentX, int indentY, List<AboutBoxLine> lines) throws OverflowException { |
| x = indentX; |
| y = indentY; |
| ApplicationInfoEx appInfo = (ApplicationInfoEx)ApplicationInfo.getInstance(); |
| for (AboutBoxLine line : lines) { |
| final String s = line.getText(); |
| setFont(line.isBold() ? myBoldFont : myFont); |
| if (line.getUrl() != null) { |
| g2.setColor(myLinkColor); |
| FontMetrics metrics = g2.getFontMetrics(font); |
| myLinks.add(new Link(new Rectangle(x, yBase + y - fontAscent, metrics.stringWidth(s), fontHeight), line.getUrl())); |
| } |
| else { |
| g2.setColor(appInfo.getAboutForeground()); |
| } |
| renderString(s, indentX); |
| if (!line.isKeepWithNext() && !line.equals(lines.get(lines.size()-1))) { |
| lineFeed(indentX, s); |
| } |
| } |
| } |
| |
| private void renderString(final String s, final int indentX) throws OverflowException { |
| final List<String> words = StringUtil.split(s, " "); |
| for (String word : words) { |
| int wordWidth = fontmetrics.stringWidth(word); |
| if (x + wordWidth >= w) { |
| lineFeed(indentX, word); |
| } |
| else { |
| char c = ' '; |
| final int cW = fontmetrics.charWidth(c); |
| if (x + cW < w) { |
| g2.drawChars(new char[]{c}, 0, 1, xBase + x, yBase + y); |
| x += cW; |
| } |
| } |
| renderWord(word, indentX); |
| } |
| } |
| |
| private void renderWord(final String s, final int indentX) throws OverflowException { |
| for (int j = 0; j != s.length(); ++j) { |
| final char c = s.charAt(j); |
| final int cW = fontmetrics.charWidth(c); |
| if (x + cW >= w) { |
| lineFeed(indentX, s); |
| } |
| g2.drawChars(new char[]{c}, 0, 1, xBase + x, yBase + y); |
| x += cW; |
| } |
| } |
| |
| private void lineFeed(int indent, final String s) throws OverflowException { |
| x = indent; |
| if (s.length() == 0) { |
| y += fontHeight / 3; |
| } |
| else { |
| y += fontHeight; |
| } |
| if (y >= h) { |
| throw new OverflowException(); |
| } |
| } |
| |
| private void setFont(Font font) { |
| this.font = font; |
| fontmetrics = g2.getFontMetrics(font); |
| g2.setFont(font); |
| fontAscent = fontmetrics.getAscent(); |
| fontHeight = fontmetrics.getHeight(); |
| } |
| } |
| |
| private static class AboutBoxLine { |
| private final String myText; |
| private final boolean myBold; |
| private final String myUrl; |
| private boolean myKeepWithNext; |
| |
| public AboutBoxLine(final String text, final boolean bold, final String url) { |
| myText = text; |
| myBold = bold; |
| myUrl = url; |
| } |
| |
| public AboutBoxLine(final String text) { |
| myText = text; |
| myBold = false; |
| myUrl = null; |
| } |
| |
| public String getText() { |
| return myText; |
| } |
| |
| public boolean isBold() { |
| return myBold; |
| } |
| |
| public String getUrl() { |
| return myUrl; |
| } |
| |
| public boolean isKeepWithNext() { |
| return myKeepWithNext; |
| } |
| |
| public AboutBoxLine keepWithNext() { |
| myKeepWithNext = true; |
| return this; |
| } |
| } |
| |
| private static class Link { |
| private final Rectangle myRectangle; |
| private final String myUrl; |
| |
| private Link(Rectangle rectangle, String url) { |
| myRectangle = rectangle; |
| myUrl = url; |
| } |
| } |
| } |
| } |