19 package org.sleuthkit.autopsy.discovery.ui;
 
   21 import java.awt.Color;
 
   22 import java.awt.Component;
 
   23 import java.awt.Point;
 
   24 import java.awt.event.MouseEvent;
 
   25 import java.time.Instant;
 
   26 import java.time.ZonedDateTime;
 
   27 import java.util.HashSet;
 
   28 import java.util.TimeZone;
 
   30 import javax.swing.ImageIcon;
 
   31 import javax.swing.JComponent;
 
   32 import javax.swing.JList;
 
   33 import javax.swing.ListCellRenderer;
 
   34 import org.openide.util.NbBundle;
 
   42 class DomainSummaryPanel 
extends javax.swing.JPanel implements ListCellRenderer<DomainWrapper> {
 
   44     private static final long serialVersionUID = 1L;
 
   45     private static final Color SELECTION_COLOR = 
new Color(0, 120, 215);
 
   50     @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
 
   51     DomainSummaryPanel() {
 
   53         domainNameLabel.setFont(domainNameLabel.getFont().deriveFont(domainNameLabel.getFont().getStyle(), domainNameLabel.getFont().getSize() + 6));
 
   61     @SuppressWarnings(
"unchecked")
 
   63     private 
void initComponents() {
 
   65         domainNameLabel = 
new javax.swing.JLabel();
 
   66         sampleImageLabel = 
new javax.swing.JLabel();
 
   67         numberOfImagesLabel = 
new javax.swing.JLabel();
 
   68         activityLabel = 
new javax.swing.JLabel();
 
   69         pagesLabel = 
new javax.swing.JLabel();
 
   70         filesDownloadedLabel = 
new javax.swing.JLabel();
 
   71         totalVisitsLabel = 
new javax.swing.JLabel();
 
   72         domainNotabilityLabel = 
new javax.swing.JLabel();
 
   73         categoryLabel = 
new javax.swing.JLabel();
 
   74         knownAccountTypesLabel = 
new javax.swing.JLabel();
 
   76         setBorder(javax.swing.BorderFactory.createEtchedBorder());
 
   78         sampleImageLabel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
 
   79         sampleImageLabel.setIconTextGap(0);
 
   80         sampleImageLabel.setMaximumSize(
new java.awt.Dimension(100, 100));
 
   81         sampleImageLabel.setMinimumSize(
new java.awt.Dimension(100, 100));
 
   82         sampleImageLabel.setPreferredSize(
new java.awt.Dimension(100, 100));
 
   84         org.openide.awt.Mnemonics.setLocalizedText(pagesLabel, 
org.openide.util.NbBundle.getMessage(DomainSummaryPanel.class, 
"DomainSummaryPanel.pagesLabel.text")); 
 
   86         org.openide.awt.Mnemonics.setLocalizedText(filesDownloadedLabel, 
org.openide.util.NbBundle.getMessage(DomainSummaryPanel.class, 
"DomainSummaryPanel.filesDownloadedLabel.text")); 
 
   88         javax.swing.GroupLayout layout = 
new javax.swing.GroupLayout(
this);
 
   89         this.setLayout(layout);
 
   90         layout.setHorizontalGroup(
 
   91             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
   92             .addGroup(layout.createSequentialGroup()
 
   94                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
   95                     .addComponent(domainNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
   96                     .addComponent(pagesLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
   97                     .addGroup(layout.createSequentialGroup()
 
   98                         .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, 
false)
 
   99                             .addComponent(totalVisitsLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  100                             .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, 
false)
 
  101                                 .addComponent(filesDownloadedLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
 
  102                                 .addComponent(activityLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
 
  103                         .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
 
  104                         .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  105                             .addComponent(domainNotabilityLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 295, Short.MAX_VALUE)
 
  106                             .addComponent(categoryLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  107                             .addComponent(knownAccountTypesLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
 
  109                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  110                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, 
false)
 
  111                     .addComponent(numberOfImagesLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  112                     .addComponent(sampleImageLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
 
  116         layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, 
new java.awt.Component[] {activityLabel, filesDownloadedLabel});
 
  118         layout.setVerticalGroup(
 
  119             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  120             .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
 
  122                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  123                     .addGroup(layout.createSequentialGroup()
 
  124                         .addComponent(numberOfImagesLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 17, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  125                         .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  126                         .addComponent(sampleImageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
 
  127                     .addGroup(layout.createSequentialGroup()
 
  128                         .addComponent(domainNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 35, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  129                         .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED, 15, Short.MAX_VALUE)
 
  130                         .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  131                             .addComponent(activityLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 15, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  132                             .addComponent(domainNotabilityLabel, javax.swing.GroupLayout.Alignment.TRAILING))
 
  133                         .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  134                         .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, 
false)
 
  135                             .addComponent(filesDownloadedLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 14, Short.MAX_VALUE)
 
  136                             .addComponent(categoryLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
 
  138                         .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, 
false)
 
  139                             .addComponent(totalVisitsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 14, Short.MAX_VALUE)
 
  140                             .addComponent(knownAccountTypesLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
 
  141                         .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  142                         .addComponent(pagesLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 15, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  147         layout.linkSize(javax.swing.SwingConstants.VERTICAL, 
new java.awt.Component[] {domainNotabilityLabel, totalVisitsLabel});
 
  149         layout.linkSize(javax.swing.SwingConstants.VERTICAL, 
new java.awt.Component[] {activityLabel, filesDownloadedLabel});
 
  155     private javax.swing.JLabel activityLabel;
 
  156     private javax.swing.JLabel categoryLabel;
 
  157     private javax.swing.JLabel domainNameLabel;
 
  158     private javax.swing.JLabel domainNotabilityLabel;
 
  159     private javax.swing.JLabel filesDownloadedLabel;
 
  160     private javax.swing.JLabel knownAccountTypesLabel;
 
  161     private javax.swing.JLabel numberOfImagesLabel;
 
  162     private javax.swing.JLabel pagesLabel;
 
  163     private javax.swing.JLabel sampleImageLabel;
 
  164     private javax.swing.JLabel totalVisitsLabel;
 
  167     @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
 
  168     @NbBundle.Messages({
"# {0} - startDate",
 
  170         "DomainSummaryPanel.activity.text=Activity: {0} to {1}",
 
  171         "DomainSummaryPanel.pages.text=Page views in final 60 days: ",
 
  172         "DomainSummaryPanel.totalPages.text=Total page views: ",
 
  173         "DomainSummaryPanel.downloads.text=Files downloaded: ",
 
  174         "DomainSummaryPanel.notability.text=Previously tagged as notable: ",
 
  175         "DomainSummaryPanel.userRole.text=Account type: ",
 
  176         "DomainSummaryPanel.category.text=Categories: ",
 
  177         "DomainSummaryPanel.loadingImages.text=Loading thumbnail...",
 
  178         "DomainSummaryPanel.no.text=No",
 
  179         "DomainSummaryPanel.yes.text=Yes"})
 
  181     public Component getListCellRendererComponent(JList<? extends DomainWrapper> list, DomainWrapper value, 
int index, 
boolean isSelected, 
boolean cellHasFocus) {
 
  182         domainNameLabel.setText(value.getResultDomain().getDomain());
 
  183         TimeZone timeZone = TimeZoneUtils.getTimeZone();
 
  184         String startDate = formatDate(value.getResultDomain().getActivityStart(), timeZone);
 
  185         String endDate = formatDate(value.getResultDomain().getActivityEnd(), timeZone);
 
  186         String notability = Bundle.DomainSummaryPanel_notability_text();
 
  187         if (value.getResultDomain().getPreviouslyNotableInCR() == SearchData.PreviouslyNotable.PREVIOUSLY_NOTABLE) {
 
  188             notability += Bundle.DomainSummaryPanel_yes_text();
 
  190             notability += Bundle.DomainSummaryPanel_no_text();
 
  192         domainNotabilityLabel.setText(notability);
 
  193         Set<String> webCategories = 
new HashSet<>();
 
  194         webCategories.addAll(value.getResultDomain().getWebCategories());
 
  195         categoryLabel.setText(Bundle.DomainSummaryPanel_category_text() + String.join(
",", webCategories));
 
  196         activityLabel.setText(Bundle.DomainSummaryPanel_activity_text(startDate, endDate));
 
  197         totalVisitsLabel.setText(Bundle.DomainSummaryPanel_totalPages_text() + value.getResultDomain().getTotalPageViews());
 
  198         pagesLabel.setText(Bundle.DomainSummaryPanel_pages_text() + value.getResultDomain().getPageViewsInLast60Days());
 
  199         filesDownloadedLabel.setText(Bundle.DomainSummaryPanel_downloads_text() + value.getResultDomain().getFilesDownloaded());
 
  200         knownAccountTypesLabel.setText(Bundle.DomainSummaryPanel_userRole_text() + value.getResultDomain().getAccountTypes());
 
  201         if (value.getThumbnail() == null) {
 
  202             numberOfImagesLabel.setText(Bundle.DomainSummaryPanel_loadingImages_text());
 
  203             sampleImageLabel.setIcon(null);
 
  205             numberOfImagesLabel.setText(null);
 
  206             sampleImageLabel.setIcon(
new ImageIcon(value.getThumbnail()));
 
  208         setBackground(isSelected ? SELECTION_COLOR : list.getBackground());
 
  220     private String formatDate(
long epochSeconds, TimeZone timeZone) {
 
  221         Instant epochSecondsAsInstant = Instant.ofEpochSecond(epochSeconds);
 
  222         ZonedDateTime dateTime = ZonedDateTime.ofInstant(epochSecondsAsInstant, timeZone.toZoneId());
 
  223         MonthAbbreviation currentCutOffMonth = MonthAbbreviation.fromMonthValue(dateTime.getMonthValue());
 
  224         return String.format(
"%s %02d %04d",
 
  225                 currentCutOffMonth.toString(),
 
  226                 dateTime.getDayOfMonth(), dateTime.getYear());
 
  229     @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
 
  231     public String getToolTipText(MouseEvent event) {
 
  234             Point point = 
event.getPoint();
 
  235             for (Component comp : getComponents()) {
 
  236                 if (DiscoveryUiUtils.isPointOnIcon(comp, point)) {
 
  237                     String toolTip = ((JComponent) comp).getToolTipText();
 
  238                     if (toolTip == null || toolTip.isEmpty()) {