19 package org.sleuthkit.autopsy.casemodule;
22 import java.nio.file.Paths;
23 import java.util.Calendar;
24 import java.util.SimpleTimeZone;
25 import java.util.TimeZone;
26 import java.util.logging.Level;
27 import javax.swing.JFileChooser;
28 import javax.swing.JPanel;
29 import org.openide.util.NbBundle;
38 "LocalDiskPanel.errorMessage.noOpenCaseTitle=No open case available",
39 "LocalDiskPanel.errorMessage.noOpenCaseBody=LocalDiskPanel listener couldn't get the open case.",
40 "LocalDiskPanel.imageWriterError.directoryNotExist=Error - directory does not exist",
41 "LocalDiskPanel.imageWriterError.emptyPath=Error - enter path for VHD",
42 "LocalDiskPanel.imageWriterError.isDirectory=Error - VHD path is a directory",
43 "LocalDiskPanel.imageWriterError.fileExists=Error - VHD path already exists",
44 "LocalDiskPanel.moduleErrorMessage.title=Module Error",
45 "LocalDiskPanel.moduleErrorMessage.body=A module caused an error listening to LocalDiskPanel updates. See log to determine which module. Some data could be incomplete.",
46 "LocalDiskPanel.localDiskMessage.unspecified=Unspecified"
52 final class LocalDiskPanel extends JPanel {
54 private static final Logger logger = Logger.getLogger(LocalDiskPanel.class.getName());
55 private static final String[] SECTOR_SIZE_CHOICES = {
"Auto Detect",
"512",
"1024",
"2048",
"4096"};
56 private static LocalDiskPanel instance;
57 private static final long serialVersionUID = 1L;
58 private LocalDisk localDisk;
59 private boolean enableNext =
false;
60 private final JFileChooser fc =
new JFileChooser();
69 createSectorSizeList();
75 static synchronized LocalDiskPanel getDefault() {
76 if (instance == null) {
77 instance =
new LocalDiskPanel();
82 @SuppressWarnings(
"unchecked")
83 private
void customInit() {
84 imageWriterErrorLabel.setVisible(
false);
85 imageWriterErrorLabel.setText(
"");
86 if (!PlatformUtil.isWindowsOS()) {
87 copyImageCheckbox.setSelected(
false);
88 copyImageCheckbox.setEnabled(
false);
90 pathTextField.setEnabled(copyImageCheckbox.isSelected());
91 browseButton.setEnabled(copyImageCheckbox.isSelected());
92 changeDatabasePathCheckbox.setEnabled(copyImageCheckbox.isSelected());
100 @SuppressWarnings(
"unchecked")
102 private
void initComponents() {
104 timeZoneLabel =
new javax.swing.JLabel();
105 timeZoneComboBox =
new javax.swing.JComboBox<>();
106 noFatOrphansCheckbox =
new javax.swing.JCheckBox();
107 descLabel =
new javax.swing.JLabel();
108 copyImageCheckbox =
new javax.swing.JCheckBox();
109 pathTextField =
new javax.swing.JTextField();
110 browseButton =
new javax.swing.JButton();
111 jLabel1 =
new javax.swing.JLabel();
112 imageWriterErrorLabel =
new javax.swing.JLabel();
113 changeDatabasePathCheckbox =
new javax.swing.JCheckBox();
114 sectorSizeLabel =
new javax.swing.JLabel();
115 sectorSizeComboBox =
new javax.swing.JComboBox<>();
116 selectDiskButton =
new javax.swing.JButton();
117 localDiskLabel =
new javax.swing.JLabel();
118 localDiskNameTextField =
new javax.swing.JTextField();
120 setMinimumSize(
new java.awt.Dimension(0, 420));
121 setPreferredSize(
new java.awt.Dimension(485, 410));
123 timeZoneLabel.setFont(timeZoneLabel.getFont().deriveFont(timeZoneLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11));
124 org.openide.awt.Mnemonics.setLocalizedText(timeZoneLabel,
org.openide.util.NbBundle.getMessage(LocalDiskPanel.class,
"LocalDiskPanel.timeZoneLabel.text"));
126 timeZoneComboBox.setFont(timeZoneComboBox.getFont().deriveFont(timeZoneComboBox.getFont().getStyle() & ~java.awt.Font.BOLD, 11));
127 timeZoneComboBox.setMaximumRowCount(30);
129 noFatOrphansCheckbox.setFont(noFatOrphansCheckbox.getFont().deriveFont(noFatOrphansCheckbox.getFont().getStyle() & ~java.awt.Font.BOLD, 11));
130 org.openide.awt.Mnemonics.setLocalizedText(noFatOrphansCheckbox,
org.openide.util.NbBundle.getMessage(LocalDiskPanel.class,
"LocalDiskPanel.noFatOrphansCheckbox.text"));
131 noFatOrphansCheckbox.setToolTipText(
org.openide.util.NbBundle.getMessage(LocalDiskPanel.class,
"LocalDiskPanel.noFatOrphansCheckbox.toolTipText"));
133 descLabel.setFont(descLabel.getFont().deriveFont(descLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11));
134 org.openide.awt.Mnemonics.setLocalizedText(descLabel,
org.openide.util.NbBundle.getMessage(LocalDiskPanel.class,
"LocalDiskPanel.descLabel.text"));
136 org.openide.awt.Mnemonics.setLocalizedText(copyImageCheckbox,
org.openide.util.NbBundle.getMessage(LocalDiskPanel.class,
"LocalDiskPanel.copyImageCheckbox.text"));
137 copyImageCheckbox.addActionListener(
new java.awt.event.ActionListener() {
138 public void actionPerformed(java.awt.event.ActionEvent evt) {
139 copyImageCheckboxActionPerformed(evt);
143 pathTextField.setText(
org.openide.util.NbBundle.getMessage(LocalDiskPanel.class,
"LocalDiskPanel.pathTextField.text"));
144 pathTextField.addKeyListener(
new java.awt.event.KeyAdapter() {
145 public void keyReleased(java.awt.event.KeyEvent evt) {
146 pathTextFieldKeyReleased(evt);
150 org.openide.awt.Mnemonics.setLocalizedText(browseButton,
org.openide.util.NbBundle.getMessage(LocalDiskPanel.class,
"LocalDiskPanel.browseButton.text"));
151 browseButton.addActionListener(
new java.awt.event.ActionListener() {
152 public void actionPerformed(java.awt.event.ActionEvent evt) {
153 browseButtonActionPerformed(evt);
157 org.openide.awt.Mnemonics.setLocalizedText(jLabel1,
org.openide.util.NbBundle.getMessage(LocalDiskPanel.class,
"LocalDiskPanel.jLabel1.text"));
159 imageWriterErrorLabel.setFont(imageWriterErrorLabel.getFont().deriveFont(imageWriterErrorLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11));
160 imageWriterErrorLabel.setForeground(
new java.awt.Color(255, 0, 0));
161 org.openide.awt.Mnemonics.setLocalizedText(imageWriterErrorLabel,
org.openide.util.NbBundle.getMessage(LocalDiskPanel.class,
"LocalDiskPanel.imageWriterErrorLabel.text"));
163 org.openide.awt.Mnemonics.setLocalizedText(changeDatabasePathCheckbox,
org.openide.util.NbBundle.getMessage(LocalDiskPanel.class,
"LocalDiskPanel.changeDatabasePathCheckbox.text"));
165 org.openide.awt.Mnemonics.setLocalizedText(sectorSizeLabel,
org.openide.util.NbBundle.getMessage(LocalDiskPanel.class,
"LocalDiskPanel.sectorSizeLabel.text"));
167 org.openide.awt.Mnemonics.setLocalizedText(selectDiskButton,
org.openide.util.NbBundle.getMessage(LocalDiskPanel.class,
"LocalDiskPanel.selectDiskButton.text"));
168 selectDiskButton.addActionListener(
new java.awt.event.ActionListener() {
169 public void actionPerformed(java.awt.event.ActionEvent evt) {
170 selectDiskButtonActionPerformed(evt);
174 org.openide.awt.Mnemonics.setLocalizedText(localDiskLabel,
org.openide.util.NbBundle.getMessage(LocalDiskPanel.class,
"LocalDiskPanel.localDiskLabel.text"));
176 localDiskNameTextField.setEditable(
false);
178 javax.swing.GroupLayout layout =
new javax.swing.GroupLayout(
this);
179 this.setLayout(layout);
180 layout.setHorizontalGroup(
181 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
182 .addGroup(layout.createSequentialGroup()
183 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
184 .addGroup(layout.createSequentialGroup()
185 .addComponent(localDiskLabel)
186 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
187 .addComponent(localDiskNameTextField)
188 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
189 .addComponent(selectDiskButton))
190 .addGroup(layout.createSequentialGroup()
191 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
192 .addGroup(layout.createSequentialGroup()
193 .addComponent(timeZoneLabel)
194 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
195 .addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 275, javax.swing.GroupLayout.PREFERRED_SIZE))
196 .addComponent(noFatOrphansCheckbox)
197 .addComponent(copyImageCheckbox)
198 .addGroup(layout.createSequentialGroup()
200 .addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 342, javax.swing.GroupLayout.PREFERRED_SIZE)
201 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
202 .addComponent(browseButton))
203 .addGroup(layout.createSequentialGroup()
205 .addComponent(sectorSizeLabel)
206 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
207 .addComponent(sectorSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
208 .addGroup(layout.createSequentialGroup()
210 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
211 .addComponent(descLabel)
212 .addComponent(changeDatabasePathCheckbox)
213 .addGroup(layout.createSequentialGroup()
215 .addComponent(jLabel1))
216 .addComponent(imageWriterErrorLabel))))
217 .addGap(0, 39, Short.MAX_VALUE)))
220 layout.setVerticalGroup(
221 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
222 .addGroup(layout.createSequentialGroup()
223 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
224 .addComponent(localDiskLabel)
225 .addComponent(selectDiskButton)
226 .addComponent(localDiskNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
228 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
229 .addComponent(timeZoneLabel)
230 .addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
232 .addComponent(noFatOrphansCheckbox)
233 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
234 .addComponent(descLabel)
236 .addComponent(copyImageCheckbox)
237 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
238 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
239 .addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
240 .addComponent(browseButton))
242 .addComponent(changeDatabasePathCheckbox)
243 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
244 .addComponent(jLabel1)
245 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
246 .addComponent(imageWriterErrorLabel)
248 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
249 .addComponent(sectorSizeLabel)
250 .addComponent(sectorSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
251 .addContainerGap(127, Short.MAX_VALUE))
255 private void copyImageCheckboxActionPerformed(java.awt.event.ActionEvent evt) {
256 pathTextField.setEnabled(copyImageCheckbox.isSelected());
257 browseButton.setEnabled(copyImageCheckbox.isSelected());
258 changeDatabasePathCheckbox.setEnabled(copyImageCheckbox.isSelected());
262 private void pathTextFieldKeyReleased(java.awt.event.KeyEvent evt) {
266 private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {
267 String oldText = pathTextField.getText();
269 File currentFile =
new File(oldText);
270 if ((currentFile.getParentFile() != null) && (currentFile.getParentFile().exists())) {
271 fc.setSelectedFile(currentFile);
274 int retval = fc.showOpenDialog(
this);
275 if (retval == JFileChooser.APPROVE_OPTION) {
276 String path = fc.getSelectedFile().getPath();
277 pathTextField.setText(path);
282 private void selectDiskButtonActionPerformed(java.awt.event.ActionEvent evt) {
283 LocalDiskSelectionDialog selectionDialog =
new LocalDiskSelectionDialog();
284 selectionDialog.display();
285 LocalDisk selectedLocalDisk = selectionDialog.getLocalDiskSelection();
286 if (selectedLocalDisk != null) {
287 localDisk = selectedLocalDisk;
288 localDiskNameTextField.setText(selectedLocalDisk.getName());
292 setPotentialImageWriterPath(localDisk);
293 firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(),
false,
true);
294 }
catch (NoCurrentCaseException ex) {
295 logger.log(Level.SEVERE,
"Exception while getting open case.", ex);
296 MessageNotifyUtil.Notify.show(Bundle.LocalDiskPanel_errorMessage_noOpenCaseTitle(),
297 Bundle.LocalDiskPanel_errorMessage_noOpenCaseBody(),
298 MessageNotifyUtil.MessageType.ERROR);
299 }
catch (Exception ex) {
300 logger.log(Level.SEVERE,
"LocalDiskPanel listener threw exception", ex);
301 MessageNotifyUtil.Notify.show(Bundle.LocalDiskPanel_moduleErrorMessage_title(),
302 Bundle.LocalDiskPanel_moduleErrorMessage_body(),
303 MessageNotifyUtil.MessageType.ERROR);
309 private javax.swing.JButton browseButton;
310 private javax.swing.JCheckBox changeDatabasePathCheckbox;
311 private javax.swing.JCheckBox copyImageCheckbox;
312 private javax.swing.JLabel descLabel;
313 private javax.swing.JLabel imageWriterErrorLabel;
314 private javax.swing.JLabel jLabel1;
315 private javax.swing.JLabel localDiskLabel;
316 private javax.swing.JTextField localDiskNameTextField;
317 private javax.swing.JCheckBox noFatOrphansCheckbox;
318 private javax.swing.JTextField pathTextField;
319 private javax.swing.JComboBox<String> sectorSizeComboBox;
320 private javax.swing.JLabel sectorSizeLabel;
321 private javax.swing.JButton selectDiskButton;
322 private javax.swing.JComboBox<String> timeZoneComboBox;
323 private javax.swing.JLabel timeZoneLabel;
326 private void fireUpdateEvent() {
328 firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(),
false,
true);
329 }
catch (Exception e) {
330 logger.log(Level.SEVERE,
"LocalDiskPanel listener threw exception", e);
331 MessageNotifyUtil.Notify.show(Bundle.LocalDiskPanel_moduleErrorMessage_title(),
332 Bundle.LocalDiskPanel_moduleErrorMessage_body(),
333 MessageNotifyUtil.MessageType.ERROR);
340 void resetLocalDiskSelection() {
342 localDiskNameTextField.setText(Bundle.LocalDiskPanel_localDiskMessage_unspecified());
351 String getContentPath() {
352 if (localDisk != null) {
353 return localDisk.getPath();
364 int getSectorSize() {
365 int sectorSizeSelectionIndex = sectorSizeComboBox.getSelectedIndex();
367 if (sectorSizeSelectionIndex == 0) {
371 return Integer.valueOf((String) sectorSizeComboBox.getSelectedItem());
374 String getTimeZone() {
375 String tz = timeZoneComboBox.getSelectedItem().toString();
376 return tz.substring(tz.indexOf(
")") + 2).trim();
380 boolean getNoFatOrphans() {
381 return noFatOrphansCheckbox.isSelected();
384 private static String getDefaultImageWriterFolder() throws NoCurrentCaseException {
385 return Paths.get(Case.getOpenCase().getModuleDirectory(),
"Image Writer").toString();
388 private void setPotentialImageWriterPath(LocalDisk disk)
throws NoCurrentCaseException {
390 File subDirectory = Paths.get(getDefaultImageWriterFolder()).toFile();
391 if (!subDirectory.exists()) {
392 subDirectory.mkdirs();
395 String path = disk.getName();
399 path = path.replaceAll(
"[^0-9A-Za-z _()]",
"");
400 if (path.isEmpty() || path.startsWith(
" ")) {
401 path =
"localDisk" + path;
404 path +=
" " + System.currentTimeMillis();
406 pathTextField.setText(Paths.get(getDefaultImageWriterFolder(), path).toString());
409 private boolean imageWriterPathIsValid() {
410 if ((!copyImageCheckbox.isSelected()) || localDisk == null) {
411 imageWriterErrorLabel.setVisible(
false);
412 imageWriterErrorLabel.setText(
"");
416 if (pathTextField.getText().isEmpty()) {
417 imageWriterErrorLabel.setVisible(
true);
418 imageWriterErrorLabel.setText(Bundle.LocalDiskPanel_imageWriterError_emptyPath());
422 File f =
new File(pathTextField.getText());
423 if (((f.getParentFile() != null) && (!f.getParentFile().exists()))
424 || (f.getParentFile() == null)) {
425 imageWriterErrorLabel.setVisible(
true);
426 imageWriterErrorLabel.setText(Bundle.LocalDiskPanel_imageWriterError_directoryNotExist());
429 if (f.isDirectory()) {
430 imageWriterErrorLabel.setVisible(
true);
431 imageWriterErrorLabel.setText(Bundle.LocalDiskPanel_imageWriterError_isDirectory());
435 imageWriterErrorLabel.setVisible(
true);
436 imageWriterErrorLabel.setText(Bundle.LocalDiskPanel_imageWriterError_fileExists());
439 imageWriterErrorLabel.setVisible(
false);
440 imageWriterErrorLabel.setText(
"");
444 boolean getImageWriterEnabled() {
445 return copyImageCheckbox.isSelected();
448 ImageWriterSettings getImageWriterSettings() {
449 return new ImageWriterSettings(pathTextField.getText(), changeDatabasePathCheckbox.isSelected());
458 boolean validatePanel() {
459 if (!imageWriterPathIsValid()) {
469 public void createTimeZoneList() {
471 String[] ids = SimpleTimeZone.getAvailableIDs();
472 for (String
id : ids) {
473 TimeZone zone = TimeZone.getTimeZone(
id);
474 int offset = zone.getRawOffset() / 1000;
475 int hour = offset / 3600;
476 int minutes = (offset % 3600) / 60;
477 String item = String.format(
"(GMT%+d:%02d) %s", hour, minutes,
id);
488 timeZoneComboBox.addItem(item);
491 TimeZone thisTimeZone = Calendar.getInstance().getTimeZone();
492 int thisOffset = thisTimeZone.getRawOffset() / 1000;
493 int thisHour = thisOffset / 3600;
494 int thisMinutes = (thisOffset % 3600) / 60;
495 String formatted = String.format(
"(GMT%+d:%02d) %s", thisHour, thisMinutes, thisTimeZone.getID());
498 timeZoneComboBox.setSelectedItem(formatted);
506 private void createSectorSizeList() {
507 for (String choice : SECTOR_SIZE_CHOICES) {
508 sectorSizeComboBox.addItem(choice);
510 sectorSizeComboBox.setSelectedIndex(0);