19 package org.sleuthkit.autopsy.casemodule.services;
21 import java.awt.EventQueue;
22 import java.beans.PropertyChangeEvent;
23 import java.beans.PropertyChangeListener;
24 import java.util.HashSet;
26 import java.util.TreeSet;
27 import java.util.logging.Level;
28 import javax.swing.DefaultListModel;
29 import javax.swing.JOptionPane;
30 import javax.swing.event.ListSelectionEvent;
31 import org.netbeans.spi.options.OptionsPanelController;
32 import org.openide.util.NbBundle;
33 import org.openide.util.NbBundle.Messages;
45 @SuppressWarnings(
"PMD.SingularField")
46 final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel {
48 private static final long serialVersionUID = 1L;
49 private static final TagName.HTML_COLOR DEFAULT_COLOR = TagName.HTML_COLOR.NONE;
50 private final DefaultListModel<TagNameDefinition> tagTypesListModel;
51 private Set<TagNameDefinition> tagTypes;
52 private IngestJobEventPropertyChangeListener ingestJobEventsListener;
53 private Set<String> updatedStatusTags;
59 tagTypesListModel =
new DefaultListModel<>();
60 tagTypes =
new TreeSet<>(TagNameDefinition.getTagNameDefinitions());
61 updatedStatusTags =
new HashSet<>();
63 customizeComponents();
66 @Messages({
"TagOptionsPanel.panelDescriptionTextArea.text=Create and manage tags. "
67 +
"Tags can be applied to files and results in the case. Notable tags will cause "
68 +
"items tagged with them to be flagged as notable when using a central repository. "
69 +
"Changing the status of a tag will only effect items in the current case.",
70 "TagOptionsPanel.ingestRunningWarningLabel.text=Cannot make changes to existing tags when ingest is running!",
71 "TagOptionsPanel.descriptionLabel.text=Tag Description:",
72 "TagOptionsPanel.notableYesOrNoLabel.text=",
73 "TagOptionsPanel.isNotableLabel.text=Tag indicates item is notable: ",
74 "TagOptionsPanel.editTagNameButton.text=Edit Tag"})
76 private void customizeComponents() {
77 tagNamesList.setModel(tagTypesListModel);
78 tagNamesList.addListSelectionListener((ListSelectionEvent event) -> {
81 addIngestJobEventsListener();
90 private void addIngestJobEventsListener() {
91 ingestJobEventsListener =
new IngestJobEventPropertyChangeListener();
92 IngestManager.getInstance().addIngestJobEventListener(ingestJobEventsListener);
100 @SuppressWarnings(
"unchecked")
102 private
void initComponents() {
104 jPanel1 =
new javax.swing.JPanel();
105 jScrollPane2 =
new javax.swing.JScrollPane();
106 jSplitPane1 =
new javax.swing.JSplitPane();
107 modifyTagTypesListPanel =
new javax.swing.JPanel();
108 tagTypesListLabel =
new javax.swing.JLabel();
109 TagNameScrollPane =
new javax.swing.JScrollPane();
110 tagNamesList =
new javax.swing.JList<>();
111 newTagNameButton =
new javax.swing.JButton();
112 deleteTagNameButton =
new javax.swing.JButton();
113 editTagNameButton =
new javax.swing.JButton();
114 panelDescriptionScrollPane =
new javax.swing.JScrollPane();
115 panelDescriptionTextArea =
new javax.swing.JTextArea();
116 tagTypesAdditionalPanel =
new javax.swing.JPanel();
117 descriptionLabel =
new javax.swing.JLabel();
118 descriptionScrollPane =
new javax.swing.JScrollPane();
119 descriptionTextArea =
new javax.swing.JTextArea();
120 isNotableLabel =
new javax.swing.JLabel();
121 notableYesOrNoLabel =
new javax.swing.JLabel();
122 ingestRunningWarningLabel =
new javax.swing.JLabel();
124 jPanel1.setPreferredSize(
new java.awt.Dimension(750, 490));
126 jScrollPane2.setPreferredSize(
new java.awt.Dimension(750, 490));
128 jSplitPane1.setDividerLocation(450);
129 jSplitPane1.setDividerSize(1);
130 jSplitPane1.setPreferredSize(
new java.awt.Dimension(748, 488));
132 org.openide.awt.Mnemonics.setLocalizedText(tagTypesListLabel,
org.openide.util.NbBundle.getMessage(TagOptionsPanel.class,
"TagOptionsPanel.tagTypesListLabel.text"));
134 tagNamesList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
135 TagNameScrollPane.setViewportView(tagNamesList);
137 newTagNameButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/images/add-tag.png")));
138 org.openide.awt.Mnemonics.setLocalizedText(newTagNameButton,
org.openide.util.NbBundle.getMessage(TagOptionsPanel.class,
"TagOptionsPanel.newTagNameButton.text"));
139 newTagNameButton.setMaximumSize(
new java.awt.Dimension(111, 25));
140 newTagNameButton.setMinimumSize(
new java.awt.Dimension(111, 25));
141 newTagNameButton.setPreferredSize(
new java.awt.Dimension(111, 25));
142 newTagNameButton.addActionListener(
new java.awt.event.ActionListener() {
143 public void actionPerformed(java.awt.event.ActionEvent evt) {
144 newTagNameButtonActionPerformed(evt);
148 deleteTagNameButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/images/delete-tag.png")));
149 org.openide.awt.Mnemonics.setLocalizedText(deleteTagNameButton,
org.openide.util.NbBundle.getMessage(TagOptionsPanel.class,
"TagOptionsPanel.deleteTagNameButton.text"));
150 deleteTagNameButton.setMaximumSize(
new java.awt.Dimension(111, 25));
151 deleteTagNameButton.setMinimumSize(
new java.awt.Dimension(111, 25));
152 deleteTagNameButton.setPreferredSize(
new java.awt.Dimension(111, 25));
153 deleteTagNameButton.addActionListener(
new java.awt.event.ActionListener() {
154 public void actionPerformed(java.awt.event.ActionEvent evt) {
155 deleteTagNameButtonActionPerformed(evt);
159 editTagNameButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/images/edit-tag.png")));
160 org.openide.awt.Mnemonics.setLocalizedText(editTagNameButton,
org.openide.util.NbBundle.getMessage(TagOptionsPanel.class,
"TagOptionsPanel.editTagNameButton.text"));
161 editTagNameButton.setMaximumSize(
new java.awt.Dimension(111, 25));
162 editTagNameButton.setMinimumSize(
new java.awt.Dimension(111, 25));
163 editTagNameButton.setPreferredSize(
new java.awt.Dimension(111, 25));
164 editTagNameButton.addActionListener(
new java.awt.event.ActionListener() {
165 public void actionPerformed(java.awt.event.ActionEvent evt) {
166 editTagNameButtonActionPerformed(evt);
170 panelDescriptionTextArea.setEditable(
false);
171 panelDescriptionTextArea.setBackground(
new java.awt.Color(240, 240, 240));
172 panelDescriptionTextArea.setColumns(20);
173 panelDescriptionTextArea.setFont(
new java.awt.Font(
"Tahoma", 0, 11));
174 panelDescriptionTextArea.setLineWrap(
true);
175 panelDescriptionTextArea.setRows(3);
176 panelDescriptionTextArea.setText(
org.openide.util.NbBundle.getMessage(TagOptionsPanel.class,
"TagOptionsPanel.panelDescriptionTextArea.text"));
177 panelDescriptionTextArea.setWrapStyleWord(
true);
178 panelDescriptionTextArea.setFocusable(
false);
179 panelDescriptionTextArea.setOpaque(
false);
180 panelDescriptionScrollPane.setViewportView(panelDescriptionTextArea);
182 javax.swing.GroupLayout modifyTagTypesListPanelLayout =
new javax.swing.GroupLayout(modifyTagTypesListPanel);
183 modifyTagTypesListPanel.setLayout(modifyTagTypesListPanelLayout);
184 modifyTagTypesListPanelLayout.setHorizontalGroup(
185 modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
186 .addGroup(modifyTagTypesListPanelLayout.createSequentialGroup()
188 .addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
189 .addComponent(tagTypesListLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
190 .addGroup(modifyTagTypesListPanelLayout.createSequentialGroup()
191 .addComponent(newTagNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, 123, javax.swing.GroupLayout.PREFERRED_SIZE)
192 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
193 .addComponent(editTagNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
194 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
195 .addComponent(deleteTagNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, 136, javax.swing.GroupLayout.PREFERRED_SIZE))
196 .addComponent(TagNameScrollPane)
197 .addComponent(panelDescriptionScrollPane))
201 modifyTagTypesListPanelLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL,
new java.awt.Component[] {deleteTagNameButton, editTagNameButton, newTagNameButton});
203 modifyTagTypesListPanelLayout.setVerticalGroup(
204 modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
205 .addGroup(modifyTagTypesListPanelLayout.createSequentialGroup()
207 .addComponent(panelDescriptionScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 65, javax.swing.GroupLayout.PREFERRED_SIZE)
208 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
209 .addComponent(tagTypesListLabel)
210 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
211 .addComponent(TagNameScrollPane)
212 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
213 .addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
214 .addComponent(newTagNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
215 .addComponent(editTagNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
216 .addComponent(deleteTagNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
220 modifyTagTypesListPanelLayout.linkSize(javax.swing.SwingConstants.VERTICAL,
new java.awt.Component[] {deleteTagNameButton, editTagNameButton, newTagNameButton});
222 jSplitPane1.setLeftComponent(modifyTagTypesListPanel);
224 org.openide.awt.Mnemonics.setLocalizedText(descriptionLabel,
org.openide.util.NbBundle.getMessage(TagOptionsPanel.class,
"TagOptionsPanel.descriptionLabel.text"));
226 descriptionTextArea.setEditable(
false);
227 descriptionTextArea.setBackground(
new java.awt.Color(240, 240, 240));
228 descriptionTextArea.setColumns(20);
229 descriptionTextArea.setFont(
new java.awt.Font(
"Tahoma", 0, 11));
230 descriptionTextArea.setLineWrap(
true);
231 descriptionTextArea.setRows(5);
232 descriptionTextArea.setWrapStyleWord(
true);
233 descriptionTextArea.setFocusable(
false);
234 descriptionTextArea.setOpaque(
false);
235 descriptionScrollPane.setViewportView(descriptionTextArea);
237 org.openide.awt.Mnemonics.setLocalizedText(isNotableLabel,
org.openide.util.NbBundle.getMessage(TagOptionsPanel.class,
"TagOptionsPanel.isNotableLabel.text"));
239 org.openide.awt.Mnemonics.setLocalizedText(notableYesOrNoLabel,
org.openide.util.NbBundle.getMessage(TagOptionsPanel.class,
"TagOptionsPanel.notableYesOrNoLabel.text"));
241 ingestRunningWarningLabel.setFont(ingestRunningWarningLabel.getFont().deriveFont(ingestRunningWarningLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11));
242 ingestRunningWarningLabel.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/modules/filetypeid/warning16.png")));
243 org.openide.awt.Mnemonics.setLocalizedText(ingestRunningWarningLabel,
org.openide.util.NbBundle.getMessage(TagOptionsPanel.class,
"TagOptionsPanel.ingestRunningWarningLabel.text"));
245 javax.swing.GroupLayout tagTypesAdditionalPanelLayout =
new javax.swing.GroupLayout(tagTypesAdditionalPanel);
246 tagTypesAdditionalPanel.setLayout(tagTypesAdditionalPanelLayout);
247 tagTypesAdditionalPanelLayout.setHorizontalGroup(
248 tagTypesAdditionalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
249 .addGroup(tagTypesAdditionalPanelLayout.createSequentialGroup()
251 .addGroup(tagTypesAdditionalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
252 .addComponent(descriptionScrollPane)
253 .addGroup(tagTypesAdditionalPanelLayout.createSequentialGroup()
254 .addGroup(tagTypesAdditionalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
255 .addComponent(descriptionLabel)
256 .addGroup(tagTypesAdditionalPanelLayout.createSequentialGroup()
257 .addComponent(isNotableLabel)
258 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
259 .addComponent(notableYesOrNoLabel))
260 .addComponent(ingestRunningWarningLabel))
261 .addGap(0, 0, Short.MAX_VALUE)))
264 tagTypesAdditionalPanelLayout.setVerticalGroup(
265 tagTypesAdditionalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
266 .addGroup(tagTypesAdditionalPanelLayout.createSequentialGroup()
268 .addComponent(descriptionLabel)
269 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
270 .addComponent(descriptionScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
271 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
272 .addGroup(tagTypesAdditionalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
273 .addComponent(isNotableLabel)
274 .addComponent(notableYesOrNoLabel))
275 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 311, Short.MAX_VALUE)
276 .addComponent(ingestRunningWarningLabel)
280 jSplitPane1.setRightComponent(tagTypesAdditionalPanel);
282 jScrollPane2.setViewportView(jSplitPane1);
284 javax.swing.GroupLayout jPanel1Layout =
new javax.swing.GroupLayout(jPanel1);
285 jPanel1.setLayout(jPanel1Layout);
286 jPanel1Layout.setHorizontalGroup(
287 jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
288 .addGroup(jPanel1Layout.createSequentialGroup()
290 .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
293 jPanel1Layout.setVerticalGroup(
294 jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
295 .addGroup(jPanel1Layout.createSequentialGroup()
297 .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
301 javax.swing.GroupLayout layout =
new javax.swing.GroupLayout(
this);
302 this.setLayout(layout);
303 layout.setHorizontalGroup(
304 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
305 .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
307 layout.setVerticalGroup(
308 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
309 .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
313 @Messages({
"TagOptionsPanel.TagNameDialog.tagNameAlreadyExists.message=Tag name must be unique. A tag with this name already exists.",
314 "TagOptionsPanel.TagNameDialog.tagNameAlreadyExists.title=Duplicate Tag Name"})
316 private void newTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {
317 TagNameDialog dialog =
new TagNameDialog();
318 TagNameDialog.BUTTON_PRESSED result = dialog.getResult();
319 if (result == TagNameDialog.BUTTON_PRESSED.OK) {
320 TskData.FileKnown status = dialog.isTagNotable() ? TskData.FileKnown.BAD : TskData.FileKnown.UNKNOWN;
321 TagNameDefinition newTagType =
new TagNameDefinition(dialog.getTagName(), dialog.getTagDesciption(), DEFAULT_COLOR, status);
325 if (!tagTypes.contains(newTagType)) {
326 tagTypes.add(newTagType);
327 updateTagNamesListModel();
328 tagNamesList.setSelectedValue(newTagType,
true);
330 firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
332 JOptionPane.showMessageDialog(
this,
333 NbBundle.getMessage(TagOptionsPanel.class,
"TagOptionsPanel.TagNameDialog.tagNameAlreadyExists.message"),
334 NbBundle.getMessage(TagOptionsPanel.class,
"TagOptionsPanel.TagNameDialog.tagNameAlreadyExists.title"),
335 JOptionPane.INFORMATION_MESSAGE);
340 private void deleteTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {
341 TagNameDefinition tagName = tagNamesList.getSelectedValue();
342 tagTypes.remove(tagName);
343 updateTagNamesListModel();
345 firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
349 private void editTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {
350 TagNameDefinition originalTagName = tagNamesList.getSelectedValue();
351 TagNameDialog dialog =
new TagNameDialog(originalTagName);
352 TagNameDialog.BUTTON_PRESSED result = dialog.getResult();
353 if (result == TagNameDialog.BUTTON_PRESSED.OK) {
354 TskData.FileKnown status = dialog.isTagNotable() ? TskData.FileKnown.BAD : TskData.FileKnown.UNKNOWN;
355 TagNameDefinition newTagType =
new TagNameDefinition(dialog.getTagName(), dialog.getTagDesciption(), DEFAULT_COLOR, status);
359 tagTypes.remove(originalTagName);
360 tagTypes.add(newTagType);
361 updateTagNamesListModel();
362 tagNamesList.setSelectedValue(newTagType,
true);
364 firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
365 if (originalTagName.getKnownStatus() != newTagType.getKnownStatus() && Case.isCaseOpen()) {
366 updatedStatusTags.add(newTagType.getDisplayName());
372 private javax.swing.JScrollPane TagNameScrollPane;
373 private javax.swing.JButton deleteTagNameButton;
374 private javax.swing.JLabel descriptionLabel;
375 private javax.swing.JScrollPane descriptionScrollPane;
376 private javax.swing.JTextArea descriptionTextArea;
377 private javax.swing.JButton editTagNameButton;
378 private javax.swing.JLabel ingestRunningWarningLabel;
379 private javax.swing.JLabel isNotableLabel;
380 private javax.swing.JPanel jPanel1;
381 private javax.swing.JScrollPane jScrollPane2;
382 private javax.swing.JSplitPane jSplitPane1;
383 private javax.swing.JPanel modifyTagTypesListPanel;
384 private javax.swing.JButton newTagNameButton;
385 private javax.swing.JLabel notableYesOrNoLabel;
386 private javax.swing.JScrollPane panelDescriptionScrollPane;
387 private javax.swing.JTextArea panelDescriptionTextArea;
389 private javax.swing.JPanel tagTypesAdditionalPanel;
390 private javax.swing.JLabel tagTypesListLabel;
396 private void updateTagNamesListModel() {
397 tagTypesListModel.clear();
398 for (TagNameDefinition tagName : tagTypes) {
399 tagTypesListModel.addElement(tagName);
408 tagTypes =
new TreeSet<>(TagNameDefinition.getTagNameDefinitions());
409 updateTagNamesListModel();
417 public void store() {
418 TagNameDefinition.setTagNameDefinitions(tagTypes);
419 sendStatusChangedEvents();
422 void cancelChanges() {
423 updatedStatusTags.clear();
426 private void sendStatusChangedEvents() {
427 for (String modifiedTagDisplayName : updatedStatusTags) {
430 Case.getCurrentCaseThrows().notifyTagDefinitionChanged(modifiedTagDisplayName);
431 }
catch (NoCurrentCaseException ex) {
432 Logger.getLogger(TagOptionsPanel.class.getName()).log(Level.SEVERE,
"Exception while getting open case.", ex);
435 updatedStatusTags.clear();
442 private void updatePanel() {
443 boolean ingestIsRunning = IngestManager.getInstance().isIngestRunning();
448 ingestRunningWarningLabel.setVisible(ingestIsRunning);
449 boolean isSelected = tagNamesList.getSelectedIndex() != -1;
450 boolean enableEdit = !ingestIsRunning && isSelected;
451 editTagNameButton.setEnabled(enableEdit);
452 boolean enableDelete = enableEdit && !TagNameDefinition.getStandardTagNames().contains(tagNamesList.getSelectedValue().getDisplayName());
453 deleteTagNameButton.setEnabled(enableDelete);
455 descriptionTextArea.setText(tagNamesList.getSelectedValue().getDescription());
456 if (tagNamesList.getSelectedValue().getKnownStatus() == TskData.FileKnown.BAD) {
457 notableYesOrNoLabel.setText(
"Yes");
459 notableYesOrNoLabel.setText(
"No");
462 descriptionTextArea.setText(
"");
463 notableYesOrNoLabel.setText(
"");
471 @SuppressWarnings(
"FinalizeDeclaration")
472 protected
void finalize() throws Throwable {
473 IngestManager.getInstance().removeIngestJobEventListener(ingestJobEventsListener);
484 EventQueue.invokeLater(
new Runnable() {
void propertyChange(PropertyChangeEvent evt)