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()) {