/* * Copyright 2013-2014 Urs Wolfer * Copyright 2000-2011 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.urswolfer.intellij.plugin.gerrit.ui; import com.google.common.collect.Lists; import com.google.gerrit.extensions.common.*; import com.intellij.ide.BrowserUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.changes.issueLinks.IssueLinkHtmlRenderer; import com.intellij.ui.components.JBScrollPane; import com.intellij.util.text.DateFormatUtil; import com.intellij.util.ui.UIUtil; import com.intellij.vcsUtil.UIVcsUtil; import com.urswolfer.intellij.plugin.gerrit.util.TextToHtml; import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; import java.awt.*; import java.text.DecimalFormat; import java.util.List; import java.util.Map; /** * Parts based on: * git4idea.history.wholeTree.GitLogDetailsPanel * * @author Urs Wolfer */ public class GerritChangeDetailsPanel { private final static String NOTHING_SELECTED = "nothingSelected"; private final static String LOADING = "loading"; private final static String DATA = "data"; private final static String MULTIPLE_SELECTED = "multiple_selected"; private final static ThreadLocal<DecimalFormat> APPROVAL_VALUE_FORMAT = new ThreadLocal<DecimalFormat>() { @Override protected DecimalFormat initialValue() { return new DecimalFormat("+#;-#"); } }; private final JPanel panel; private final MyPresentationData presentationData; private final JEditorPane jEditorPane; public GerritChangeDetailsPanel(final Project project) { panel = new JPanel(new CardLayout()); panel.add(UIVcsUtil.errorPanel("Nothing selected", false), NOTHING_SELECTED); panel.add(UIVcsUtil.errorPanel("Loading...", false), LOADING); panel.add(UIVcsUtil.errorPanel("Several commits selected", false), MULTIPLE_SELECTED); presentationData = new MyPresentationData(project); final JPanel wrapper = new JPanel(new BorderLayout()); jEditorPane = new JEditorPane(UIUtil.HTML_MIME, ""); jEditorPane.setPreferredSize(new Dimension(150, 100)); jEditorPane.setEditable(false); jEditorPane.setBackground(UIUtil.getComboBoxDisabledBackground()); jEditorPane.addHyperlinkListener(new HyperlinkListener() { @Override public void hyperlinkUpdate(HyperlinkEvent e) { GerritChangeDetailsPanel.this.handleHyperlinkEvent(e); } }); final JBScrollPane tableScroll = new JBScrollPane(jEditorPane); tableScroll.setBorder(null); jEditorPane.setBorder(null); wrapper.add(tableScroll, SwingConstants.CENTER); jEditorPane.setBackground(UIUtil.getTableBackground()); wrapper.setBackground(UIUtil.getTableBackground()); panel.add(wrapper, DATA); ((CardLayout) panel.getLayout()).show(panel, NOTHING_SELECTED); } public void severalSelected() { ((CardLayout) panel.getLayout()).show(panel, MULTIPLE_SELECTED); } public void nothingSelected() { ((CardLayout) panel.getLayout()).show(panel, NOTHING_SELECTED); } public void loading() { ((CardLayout) panel.getLayout()).show(panel, LOADING); } public void setData(@NotNull final ChangeInfo changeInfo) { presentationData.setCommit(changeInfo); ((CardLayout) panel.getLayout()).show(panel, DATA); changeDetailsText(); } private void handleHyperlinkEvent(HyperlinkEvent e) { if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { BrowserUtil.browse(e.getURL()); } } private void changeDetailsText() { if (presentationData.isReady()) { jEditorPane.setText(presentationData.getText()); panel.revalidate(); panel.repaint(); jEditorPane.setCaretPosition(0); } } public JPanel getComponent() { return panel; } private static class MyPresentationData { private String startPattern; private final String endPattern = "</table></body></html>"; private final Project project; private MyPresentationData(final Project project) { this.project = project; } public void setCommit(final ChangeInfo changeInfo) { StringBuilder stringBuilder = new StringBuilder(); addMetaData(changeInfo, stringBuilder); addLabels(changeInfo, stringBuilder); addMessages(changeInfo, stringBuilder); startPattern = stringBuilder.toString(); } private void addMetaData(ChangeInfo changeInfo, StringBuilder sb) { final String comment = IssueLinkHtmlRenderer.formatTextWithLinks(project, changeInfo.subject); sb.append("<html><head>").append(UIUtil.getCssFontDeclaration(UIUtil.getLabelFont())) .append("</head><body><table>") .append("<tr valign=\"top\"><td><i>Change-Id:</i></td><td><b>").append(changeInfo.changeId).append("</b></td></tr>") .append("<tr valign=\"top\"><td><i>Change #:</i></td><td><b>").append(changeInfo._number).append("</b></td></tr>") .append("<tr valign=\"top\"><td><i>Owner:</i></td><td>").append(changeInfo.owner != null ? changeInfo.owner.name : "").append("</td></tr>") .append("<tr valign=\"top\"><td><i>Project:</i></td><td>").append(changeInfo.project).append("</td></tr>") .append("<tr valign=\"top\"><td><i>Branch:</i></td><td>").append(changeInfo.branch).append("</td></tr>") .append("<tr valign=\"top\"><td><i>Topic:</i></td><td>").append(changeInfo.topic != null ? changeInfo.topic : "").append("</td></tr>") .append("<tr valign=\"top\"><td><i>Uploaded:</i></td><td>") .append(changeInfo.created != null ? DateFormatUtil.formatPrettyDateTime(changeInfo.created) : "") .append("</td></tr>") .append("<tr valign=\"top\"><td><i>Updated:</i></td><td>") .append(changeInfo.updated != null ? DateFormatUtil.formatPrettyDateTime(changeInfo.updated) : "") .append("</td></tr>") .append("<tr valign=\"top\"><td><i>Status:</i></td><td>").append(changeInfo.status).append("</td></tr>") .append("<tr valign=\"top\"><td><i>Description:</i></td><td><b>").append(comment).append("</b></td></tr>"); } private void addLabels(ChangeInfo changeInfo, StringBuilder sb) { if (changeInfo.labels != null) { List<ApprovalInfo> ccAccounts = null; for (Map.Entry<String, LabelInfo> labelInfoEntry : changeInfo.labels.entrySet()) { sb.append("<tr valign=\"top\"><td><i>").append(labelInfoEntry.getKey()).append(":</i></td><td>"); List<ApprovalInfo> all = labelInfoEntry.getValue().all; if (ccAccounts == null) { if (all != null) { ccAccounts = Lists.newArrayList(all); } else { ccAccounts = Lists.newArrayList(); } } if (all != null) { for (ApprovalInfo approvalInfo : all) { if (approvalInfo.value != null && approvalInfo.value != 0) { sb.append("<b>").append(approvalInfo.name).append("</b>").append(": "); sb.append(APPROVAL_VALUE_FORMAT.get().format(approvalInfo.value)).append("<br/>"); ccAccounts.remove(approvalInfo); // remove accounts from CC which are already listed in a review section } } } sb.append("</td></tr>"); } if (ccAccounts != null) { sb.append("<tr valign=\"top\"><td><i>").append("CC").append(":</i></td><td>"); for (ApprovalInfo approvalInfo : ccAccounts) { sb.append("<b>").append(approvalInfo.name).append("</b>").append("<br/>"); } } } } private void addMessages(ChangeInfo changeInfo, StringBuilder sb) { if (changeInfo.messages != null && changeInfo.messages.size() > 0) { sb.append("<tr valign=\"top\"><td><i>Comments:</i></td><td>"); for (ChangeMessageInfo changeMessageInfo : changeInfo.messages) { AccountInfo author = changeMessageInfo.author; if (author != null && author.name != null) { sb.append("<b>").append(author.name).append("</b>"); if (changeMessageInfo.date != null) { sb.append(" (").append(DateFormatUtil.formatPrettyDateTime(changeMessageInfo.date)).append(')'); } sb.append(": "); } sb.append(TextToHtml.textToHtml(changeMessageInfo.message)).append("<br/>"); } sb.append("</td></tr>"); } } public boolean isReady() { return startPattern != null; } public String getText() { return startPattern + endPattern; } } }