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 panelDescriptionScrollPane.setViewportView(panelDescriptionTextArea);
181 javax.swing.GroupLayout modifyTagTypesListPanelLayout =
new javax.swing.GroupLayout(modifyTagTypesListPanel);
182 modifyTagTypesListPanel.setLayout(modifyTagTypesListPanelLayout);
183 modifyTagTypesListPanelLayout.setHorizontalGroup(
184 modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
185 .addGroup(modifyTagTypesListPanelLayout.createSequentialGroup()
187 .addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
188 .addComponent(tagTypesListLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
189 .addGroup(modifyTagTypesListPanelLayout.createSequentialGroup()
190 .addComponent(newTagNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, 123, javax.swing.GroupLayout.PREFERRED_SIZE)
191 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
192 .addComponent(editTagNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
193 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
194 .addComponent(deleteTagNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, 136, javax.swing.GroupLayout.PREFERRED_SIZE))
195 .addComponent(TagNameScrollPane)
196 .addComponent(panelDescriptionScrollPane))
200 modifyTagTypesListPanelLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL,
new java.awt.Component[] {deleteTagNameButton, editTagNameButton, newTagNameButton});
202 modifyTagTypesListPanelLayout.setVerticalGroup(
203 modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
204 .addGroup(modifyTagTypesListPanelLayout.createSequentialGroup()
206 .addComponent(panelDescriptionScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 65, javax.swing.GroupLayout.PREFERRED_SIZE)
207 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
208 .addComponent(tagTypesListLabel)
209 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
210 .addComponent(TagNameScrollPane)
211 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
212 .addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
213 .addComponent(newTagNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
214 .addComponent(editTagNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
215 .addComponent(deleteTagNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
219 modifyTagTypesListPanelLayout.linkSize(javax.swing.SwingConstants.VERTICAL,
new java.awt.Component[] {deleteTagNameButton, editTagNameButton, newTagNameButton});
221 jSplitPane1.setLeftComponent(modifyTagTypesListPanel);
223 org.openide.awt.Mnemonics.setLocalizedText(descriptionLabel,
org.openide.util.NbBundle.getMessage(TagOptionsPanel.class,
"TagOptionsPanel.descriptionLabel.text"));
225 descriptionTextArea.setEditable(
false);
226 descriptionTextArea.setBackground(
new java.awt.Color(240, 240, 240));
227 descriptionTextArea.setColumns(20);
228 descriptionTextArea.setFont(
new java.awt.Font(
"Tahoma", 0, 11));
229 descriptionTextArea.setLineWrap(
true);
230 descriptionTextArea.setRows(5);
231 descriptionTextArea.setWrapStyleWord(
true);
232 descriptionTextArea.setFocusable(
false);
233 descriptionScrollPane.setViewportView(descriptionTextArea);
235 org.openide.awt.Mnemonics.setLocalizedText(isNotableLabel,
org.openide.util.NbBundle.getMessage(TagOptionsPanel.class,
"TagOptionsPanel.isNotableLabel.text"));
237 org.openide.awt.Mnemonics.setLocalizedText(notableYesOrNoLabel,
org.openide.util.NbBundle.getMessage(TagOptionsPanel.class,
"TagOptionsPanel.notableYesOrNoLabel.text"));
239 ingestRunningWarningLabel.setFont(ingestRunningWarningLabel.getFont().deriveFont(ingestRunningWarningLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11));
240 ingestRunningWarningLabel.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/modules/filetypeid/warning16.png")));
241 org.openide.awt.Mnemonics.setLocalizedText(ingestRunningWarningLabel,
org.openide.util.NbBundle.getMessage(TagOptionsPanel.class,
"TagOptionsPanel.ingestRunningWarningLabel.text"));
243 javax.swing.GroupLayout tagTypesAdditionalPanelLayout =
new javax.swing.GroupLayout(tagTypesAdditionalPanel);
244 tagTypesAdditionalPanel.setLayout(tagTypesAdditionalPanelLayout);
245 tagTypesAdditionalPanelLayout.setHorizontalGroup(
246 tagTypesAdditionalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
247 .addGroup(tagTypesAdditionalPanelLayout.createSequentialGroup()
249 .addGroup(tagTypesAdditionalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
250 .addComponent(descriptionScrollPane)
251 .addGroup(tagTypesAdditionalPanelLayout.createSequentialGroup()
252 .addGroup(tagTypesAdditionalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
253 .addComponent(descriptionLabel)
254 .addGroup(tagTypesAdditionalPanelLayout.createSequentialGroup()
255 .addComponent(isNotableLabel)
256 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
257 .addComponent(notableYesOrNoLabel))
258 .addComponent(ingestRunningWarningLabel))
259 .addGap(0, 0, Short.MAX_VALUE)))
262 tagTypesAdditionalPanelLayout.setVerticalGroup(
263 tagTypesAdditionalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
264 .addGroup(tagTypesAdditionalPanelLayout.createSequentialGroup()
266 .addComponent(descriptionLabel)
267 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
268 .addComponent(descriptionScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
269 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
270 .addGroup(tagTypesAdditionalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
271 .addComponent(isNotableLabel)
272 .addComponent(notableYesOrNoLabel))
273 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 311, Short.MAX_VALUE)
274 .addComponent(ingestRunningWarningLabel)
278 jSplitPane1.setRightComponent(tagTypesAdditionalPanel);
280 jScrollPane2.setViewportView(jSplitPane1);
282 javax.swing.GroupLayout jPanel1Layout =
new javax.swing.GroupLayout(jPanel1);
283 jPanel1.setLayout(jPanel1Layout);
284 jPanel1Layout.setHorizontalGroup(
285 jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
286 .addGroup(jPanel1Layout.createSequentialGroup()
288 .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
291 jPanel1Layout.setVerticalGroup(
292 jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
293 .addGroup(jPanel1Layout.createSequentialGroup()
295 .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
299 javax.swing.GroupLayout layout =
new javax.swing.GroupLayout(
this);
300 this.setLayout(layout);
301 layout.setHorizontalGroup(
302 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
303 .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
305 layout.setVerticalGroup(
306 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
307 .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
311 @Messages({
"TagOptionsPanel.TagNameDialog.tagNameAlreadyExists.message=Tag name must be unique. A tag with this name already exists.",
312 "TagOptionsPanel.TagNameDialog.tagNameAlreadyExists.title=Duplicate Tag Name"})
314 private void newTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {
315 TagNameDialog dialog =
new TagNameDialog();
316 TagNameDialog.BUTTON_PRESSED result = dialog.getResult();
317 if (result == TagNameDialog.BUTTON_PRESSED.OK) {
318 TskData.FileKnown status = dialog.isTagNotable() ? TskData.FileKnown.BAD : TskData.FileKnown.UNKNOWN;
319 TagNameDefinition newTagType =
new TagNameDefinition(dialog.getTagName(), dialog.getTagDesciption(), DEFAULT_COLOR, status);
323 if (!tagTypes.contains(newTagType)) {
324 tagTypes.add(newTagType);
325 updateTagNamesListModel();
326 tagNamesList.setSelectedValue(newTagType,
true);
328 firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
330 JOptionPane.showMessageDialog(
this,
331 NbBundle.getMessage(TagOptionsPanel.class,
"TagOptionsPanel.TagNameDialog.tagNameAlreadyExists.message"),
332 NbBundle.getMessage(TagOptionsPanel.class,
"TagOptionsPanel.TagNameDialog.tagNameAlreadyExists.title"),
333 JOptionPane.INFORMATION_MESSAGE);
338 private void deleteTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {
339 TagNameDefinition tagName = tagNamesList.getSelectedValue();
340 tagTypes.remove(tagName);
341 updateTagNamesListModel();
343 firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
347 private void editTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {
348 TagNameDefinition originalTagName = tagNamesList.getSelectedValue();
349 TagNameDialog dialog =
new TagNameDialog(originalTagName);
350 TagNameDialog.BUTTON_PRESSED result = dialog.getResult();
351 if (result == TagNameDialog.BUTTON_PRESSED.OK) {
352 TskData.FileKnown status = dialog.isTagNotable() ? TskData.FileKnown.BAD : TskData.FileKnown.UNKNOWN;
353 TagNameDefinition newTagType =
new TagNameDefinition(dialog.getTagName(), dialog.getTagDesciption(), DEFAULT_COLOR, status);
357 tagTypes.remove(originalTagName);
358 tagTypes.add(newTagType);
359 updateTagNamesListModel();
360 tagNamesList.setSelectedValue(newTagType,
true);
362 firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
363 if (originalTagName.getKnownStatus() != newTagType.getKnownStatus() && Case.isCaseOpen()) {
364 updatedStatusTags.add(newTagType.getDisplayName());
370 private javax.swing.JScrollPane TagNameScrollPane;
371 private javax.swing.JButton deleteTagNameButton;
372 private javax.swing.JLabel descriptionLabel;
373 private javax.swing.JScrollPane descriptionScrollPane;
374 private javax.swing.JTextArea descriptionTextArea;
375 private javax.swing.JButton editTagNameButton;
376 private javax.swing.JLabel ingestRunningWarningLabel;
377 private javax.swing.JLabel isNotableLabel;
378 private javax.swing.JPanel jPanel1;
379 private javax.swing.JScrollPane jScrollPane2;
380 private javax.swing.JSplitPane jSplitPane1;
381 private javax.swing.JPanel modifyTagTypesListPanel;
382 private javax.swing.JButton newTagNameButton;
383 private javax.swing.JLabel notableYesOrNoLabel;
384 private javax.swing.JScrollPane panelDescriptionScrollPane;
385 private javax.swing.JTextArea panelDescriptionTextArea;
387 private javax.swing.JPanel tagTypesAdditionalPanel;
388 private javax.swing.JLabel tagTypesListLabel;
394 private void updateTagNamesListModel() {
395 tagTypesListModel.clear();
396 for (TagNameDefinition tagName : tagTypes) {
397 tagTypesListModel.addElement(tagName);
406 tagTypes =
new TreeSet<>(TagNameDefinition.getTagNameDefinitions());
407 updateTagNamesListModel();
415 public void store() {
416 TagNameDefinition.setTagNameDefinitions(tagTypes);
417 sendStatusChangedEvents();
420 void cancelChanges() {
421 updatedStatusTags.clear();
424 private void sendStatusChangedEvents() {
425 for (String modifiedTagDisplayName : updatedStatusTags) {
428 Case.getCurrentCaseThrows().notifyTagDefinitionChanged(modifiedTagDisplayName);
429 }
catch (NoCurrentCaseException ex) {
430 Logger.getLogger(TagOptionsPanel.class.getName()).log(Level.SEVERE,
"Exception while getting open case.", ex);
433 updatedStatusTags.clear();
440 private void updatePanel() {
441 boolean ingestIsRunning = IngestManager.getInstance().isIngestRunning();
446 ingestRunningWarningLabel.setVisible(ingestIsRunning);
447 boolean isSelected = tagNamesList.getSelectedIndex() != -1;
448 boolean enableEdit = !ingestIsRunning && isSelected;
449 editTagNameButton.setEnabled(enableEdit);
450 boolean enableDelete = enableEdit && !TagNameDefinition.getStandardTagNames().contains(tagNamesList.getSelectedValue().getDisplayName());
451 deleteTagNameButton.setEnabled(enableDelete);
453 descriptionTextArea.setText(tagNamesList.getSelectedValue().getDescription());
454 if (tagNamesList.getSelectedValue().getKnownStatus() == TskData.FileKnown.BAD) {
455 notableYesOrNoLabel.setText(
"Yes");
457 notableYesOrNoLabel.setText(
"No");
460 descriptionTextArea.setText(
"");
461 notableYesOrNoLabel.setText(
"");
469 @SuppressWarnings(
"FinalizeDeclaration")
470 protected
void finalize() throws Throwable {
471 IngestManager.getInstance().removeIngestJobEventListener(ingestJobEventsListener);
482 EventQueue.invokeLater(
new Runnable() {
void propertyChange(PropertyChangeEvent evt)