19 package org.sleuthkit.autopsy.discovery.ui;
 
   21 import java.awt.Color;
 
   22 import java.awt.Component;
 
   23 import java.awt.Dimension;
 
   24 import java.awt.Image;
 
   25 import java.awt.GridBagConstraints;
 
   26 import java.awt.Point;
 
   27 import java.awt.event.MouseEvent;
 
   28 import java.util.concurrent.TimeUnit;
 
   29 import javax.swing.ImageIcon;
 
   30 import javax.swing.JComponent;
 
   31 import javax.swing.JLabel;
 
   32 import javax.swing.JList;
 
   33 import javax.swing.ListCellRenderer;
 
   34 import org.openide.util.NbBundle.Messages;
 
   40 final class VideoThumbnailPanel 
extends javax.swing.JPanel implements ListCellRenderer<VideoThumbnailsWrapper> {
 
   42     private static final int GAP_SIZE = 4;
 
   43     private static final Color SELECTION_COLOR = 
new Color(0, 120, 215);
 
   44     private static final int BYTE_UNIT_CONVERSION = 1000;
 
   45     private static final long serialVersionUID = 1L;
 
   46     private static final int MAX_NAME_STRING = 120;
 
   51     @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
 
   52     VideoThumbnailPanel() {
 
   54         this.setFocusable(
true);
 
   63     @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
 
   64     private 
void addThumbnails(VideoThumbnailsWrapper thumbnailWrapper) {
 
   65         imagePanel.removeAll();
 
   66         GridBagConstraints gridBagConstraints = 
new GridBagConstraints();
 
   67         gridBagConstraints.gridx = 0;
 
   68         gridBagConstraints.gridy = 0;
 
   69         gridBagConstraints.anchor = GridBagConstraints.LINE_START;
 
   70         imagePanel.add(
new javax.swing.Box.Filler(
new java.awt.Dimension(GAP_SIZE, 0), 
new java.awt.Dimension(GAP_SIZE, 0), 
new java.awt.Dimension(GAP_SIZE, 32767)), gridBagConstraints);
 
   71         gridBagConstraints.gridy = 1;
 
   72         imagePanel.add(
new javax.swing.Box.Filler(
new java.awt.Dimension(GAP_SIZE, 0), 
new java.awt.Dimension(GAP_SIZE, 0), 
new java.awt.Dimension(GAP_SIZE, 32767)), gridBagConstraints);
 
   73         gridBagConstraints.gridx++;
 
   75         int[] timeStamps = thumbnailWrapper.getTimeStamps();
 
   76         for (Image image : thumbnailWrapper.getThumbnails()) {
 
   77             gridBagConstraints.gridy = 0;
 
   78             imagePanel.add(
new JLabel(
new ImageIcon(image)), gridBagConstraints);
 
   80             gridBagConstraints.gridy = 1;
 
   81             long millis = timeStamps[timeIndex];
 
   82             long hours = TimeUnit.MILLISECONDS.toHours(millis);
 
   83             millis -= TimeUnit.HOURS.toMillis(hours);
 
   84             long minutes = TimeUnit.MILLISECONDS.toMinutes(millis);
 
   85             millis -= TimeUnit.MINUTES.toMillis(minutes);
 
   86             long seconds = TimeUnit.MILLISECONDS.toSeconds(millis);
 
   87             imagePanel.add(
new JLabel(String.format(
"%01d:%02d:%02d", hours, minutes, seconds)), gridBagConstraints);
 
   88             gridBagConstraints.gridx++;
 
   89             gridBagConstraints.gridy = 0;
 
   90             imagePanel.add(
new javax.swing.Box.Filler(
new java.awt.Dimension(GAP_SIZE, 0), 
new java.awt.Dimension(GAP_SIZE, 0), 
new java.awt.Dimension(GAP_SIZE, 32767)), gridBagConstraints);
 
   91             gridBagConstraints.gridy = 1;
 
   92             imagePanel.add(
new javax.swing.Box.Filler(
new java.awt.Dimension(GAP_SIZE, 0), 
new java.awt.Dimension(GAP_SIZE, 0), 
new java.awt.Dimension(GAP_SIZE, 32767)), gridBagConstraints);
 
   93             gridBagConstraints.gridx++;
 
  103     @SuppressWarnings(
"unchecked")
 
  105     private 
void initComponents() {
 
  107         imagePanel = 
new javax.swing.JPanel();
 
  108         fileSizeLabel = 
new javax.swing.JLabel();
 
  109         nameLabel = 
new javax.swing.JLabel();
 
  110         scoreLabel = 
new javax.swing.JLabel();
 
  111         deletedLabel = 
new javax.swing.JLabel();
 
  113         setBorder(javax.swing.BorderFactory.createEtchedBorder());
 
  115         imagePanel.setPreferredSize(
new java.awt.Dimension(776, 115));
 
  116         imagePanel.setLayout(
new java.awt.GridBagLayout());
 
  118         scoreLabel.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/images/red-circle-exclamation.png"))); 
 
  123         deletedLabel.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/images/file-icon-deleted.png"))); 
 
  128         javax.swing.GroupLayout layout = 
new javax.swing.GroupLayout(
this);
 
  129         this.setLayout(layout);
 
  130         layout.setHorizontalGroup(
 
  131             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  132             .addGroup(layout.createSequentialGroup()
 
  134                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  135                     .addComponent(imagePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  136                     .addGroup(layout.createSequentialGroup()
 
  137                         .addComponent(fileSizeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  138                         .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  139                         .addComponent(deletedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  140                         .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  141                         .addComponent(scoreLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
 
  142                     .addComponent(nameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
 
  145         layout.setVerticalGroup(
 
  146             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  147             .addGroup(layout.createSequentialGroup()
 
  149                 .addComponent(nameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  150                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  151                 .addComponent(imagePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  152                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  153                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
 
  154                     .addComponent(deletedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  155                     .addComponent(fileSizeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  156                     .addComponent(scoreLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
 
  163     private javax.swing.JLabel deletedLabel;
 
  164     private javax.swing.JLabel fileSizeLabel;
 
  165     private javax.swing.JPanel imagePanel;
 
  166     private javax.swing.JLabel nameLabel;
 
  167     private javax.swing.JLabel scoreLabel;
 
  170     @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
 
  172         "# {0} - otherInstanceCount",
 
  173         "VideoThumbnailPanel.nameLabel.more.text= and {0} more",
 
  174         "VideoThumbnailPanel.deleted.text=All instances of file are deleted."})
 
  176     public Component getListCellRendererComponent(JList<? extends VideoThumbnailsWrapper> list, VideoThumbnailsWrapper value, 
int index, 
boolean isSelected, 
boolean cellHasFocus) {
 
  177         fileSizeLabel.setText(getFileSizeString(value.getResultFile().getFirstInstance().getSize()));
 
  178         String nameText = value.getResultFile().getFirstInstance().getParentPath() + value.getResultFile().getFirstInstance().getName();
 
  179         if (value.getResultFile().getAllInstances().size() > 1) {
 
  180             nameText += Bundle.VideoThumbnailPanel_nameLabel_more_text(value.getResultFile().getAllInstances().size() - 1);
 
  182         if (nameText.length() > MAX_NAME_STRING) {
 
  183             nameText = 
"..." + nameText.substring(nameText.length() - (MAX_NAME_STRING - 3));
 
  185         nameLabel.setText(nameText);
 
  186         addThumbnails(value);
 
  187         imagePanel.setBackground(isSelected ? SELECTION_COLOR : list.getBackground());
 
  188         DiscoveryUiUtils.setDeletedIcon(value.getResultFile().isDeleted(), deletedLabel);
 
  189         DiscoveryUiUtils.setScoreIcon(value.getResultFile(), scoreLabel);
 
  190         setBackground(isSelected ? SELECTION_COLOR : list.getBackground());
 
  194     @Messages({
"# {0} - fileSize",
 
  196         "VideoThumbnailPanel.sizeLabel.text=Size: {0} {1}",
 
  197         "VideoThumbnailPanel.bytes.text=bytes",
 
  198         "VideoThumbnailPanel.kiloBytes.text=KB",
 
  199         "VideoThumbnailPanel.megaBytes.text=MB",
 
  200         "VideoThumbnailPanel.gigaBytes.text=GB",
 
  201         "VideoThumbnailPanel.terraBytes.text=TB"})
 
  210     private String getFileSizeString(
long bytes) {
 
  212         int unitsSwitchValue = 0;
 
  213         while (size > BYTE_UNIT_CONVERSION && unitsSwitchValue < 4) {
 
  214             size /= BYTE_UNIT_CONVERSION;
 
  218         switch (unitsSwitchValue) {
 
  220                 units = Bundle.VideoThumbnailPanel_kiloBytes_text();
 
  223                 units = Bundle.VideoThumbnailPanel_megaBytes_text();
 
  226                 units = Bundle.VideoThumbnailPanel_gigaBytes_text();
 
  229                 units = Bundle.VideoThumbnailPanel_terraBytes_text();
 
  232                 units = Bundle.VideoThumbnailPanel_bytes_text();
 
  235         return Bundle.VideoThumbnailPanel_sizeLabel_text(size, units);
 
  238     @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
 
  240     public String getToolTipText(MouseEvent event) {
 
  243             Point point = 
event.getPoint();
 
  244             for (Component comp : getComponents()) {
 
  245                 if (DiscoveryUiUtils.isPointOnIcon(comp, point)) {
 
  246                     String toolTip = ((JComponent) comp).getToolTipText();
 
  247                     if (toolTip == null || toolTip.isEmpty()) {