diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddBookmarkTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddBookmarkTagAction.java index d6090b2ace..ed9d7953a0 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/AddBookmarkTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddBookmarkTagAction.java @@ -27,10 +27,10 @@ import java.util.Map; import java.util.logging.Level; import javax.swing.AbstractAction; import javax.swing.KeyStroke; -import org.openide.util.NbBundle; import org.openide.util.Utilities; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.TagName; @@ -40,13 +40,12 @@ public class AddBookmarkTagAction extends AbstractAction { public static final KeyStroke BOOKMARK_SHORTCUT = KeyStroke.getKeyStroke(KeyEvent.VK_B, InputEvent.CTRL_MASK); private static final String NO_COMMENT = ""; - private static final String BOOKMARK = NbBundle.getMessage(AddBookmarkTagAction.class, "AddBookmarkTagAction.bookmark.text"); @Override public void actionPerformed(ActionEvent e) { try { Map tagNamesMap = Case.getCurrentCaseThrows().getServices().getTagsManager().getDisplayNamesToTagNamesMap(); - TagName bookmarkTagName = tagNamesMap.get(BOOKMARK); + TagName bookmarkTagName = tagNamesMap.get(TagsManager.getBookmarkTagDisplayName()); /* * Both AddContentTagAction.addTag and diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java index 3709592e62..53cf076c2e 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java @@ -22,6 +22,7 @@ import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -38,6 +39,7 @@ import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TagSet; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; @@ -126,37 +128,35 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup { // Get the current set of tag names. Map tagNamesMap = null; List standardTagNames = TagsManager.getStandardTagNames(); + Map tagSetMenuMap = new HashMap<>(); + List standardTagMenuitems = new ArrayList<>(); try { TagsManager tagsManager = Case.getCurrentCaseThrows().getServices().getTagsManager(); tagNamesMap = new TreeMap<>(tagsManager.getDisplayNamesToTagNamesMap()); - } catch (TskCoreException | NoCurrentCaseException ex) { - Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS - } - // Create a menu item for each of the existing and visible tags. - // Selecting one of these menu items adds a tag with the associated tag name. - List standardTagMenuitems = new ArrayList<>(); - if (null != tagNamesMap && !tagNamesMap.isEmpty()) { - for (Map.Entry entry : tagNamesMap.entrySet()) { - String tagDisplayName = entry.getKey(); - String notableString = entry.getValue().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; - JMenuItem tagNameItem = new JMenuItem(tagDisplayName + notableString); - // for the bookmark tag name only, added shortcut label - if (tagDisplayName.equals(NbBundle.getMessage(AddTagAction.class, "AddBookmarkTagAction.bookmark.text"))) { - tagNameItem.setAccelerator(AddBookmarkTagAction.BOOKMARK_SHORTCUT); - } + // Create a menu item for each of the existing and visible tags. + // Selecting one of these menu items adds a tag with the associated tag name. + if (!tagNamesMap.isEmpty()) { + for (Map.Entry entry : tagNamesMap.entrySet()) { + TagName tagName = entry.getValue(); + TagSet tagSet = tagName.getTagSet(); - tagNameItem.addActionListener((ActionEvent e) -> { - getAndAddTag(entry.getKey(), entry.getValue(), NO_COMMENT); - }); - - // Show custom tags before predefined tags in the menu - if (standardTagNames.contains(tagDisplayName)) { - standardTagMenuitems.add(tagNameItem); - } else { - add(tagNameItem); + // Show custom tags before predefined tags in the menu + if (tagSet != null) { + JMenu menu = tagSetMenuMap.get(tagSet.getName()); + if (menu == null) { + menu = createSubmenuForTagSet(tagSet); + tagSetMenuMap.put(tagSet.getName(), menu); + } + } else if (standardTagNames.contains(tagName.getDisplayName())) { + standardTagMenuitems.add(createMenutItem(tagName)); + } else { + add(createMenutItem(tagName)); + } } } + } catch (TskCoreException | NoCurrentCaseException ex) { + Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS } if (getItemCount() > 0) { @@ -167,6 +167,10 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup { add(menuItem); }); + tagSetMenuMap.values().forEach((menu) -> { + add(menu); + }); + addSeparator(); // Create a "Choose Tag and Comment..." menu item. Selecting this item initiates @@ -197,40 +201,44 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup { } /** - * Method to add to the action listener for each menu item. Allows a tag - * display name to be added to the menu with an action listener without - * having to instantiate a TagName object for it. When the method is - * called, the TagName object is created here if it doesn't already - * exist. + * Build a JMenu for the given TagSet. * - * @param tagDisplayName display name for the tag name - * @param tagName TagName object associated with the tag name, - * may be null - * @param comment comment for the content or artifact tag + * @param tagSet + * + * @return JMenu for the given TagSet */ - private void getAndAddTag(String tagDisplayName, TagName tagName, String comment) { - Case openCase; - try { - openCase = Case.getCurrentCaseThrows(); - } catch (NoCurrentCaseException ex) { - Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS - return; + private JMenu createSubmenuForTagSet(TagSet tagSet) { + JMenu menu = new JMenu(tagSet.getName()); + List tagNameList = tagSet.getTagNames(); + + for (TagName tagName : tagNameList) { + menu.add(createMenutItem(tagName)); } - if (tagName == null) { - try { - tagName = openCase.getServices().getTagsManager().addTagName(tagDisplayName); - } catch (TagsManager.TagNameAlreadyExistsException ex) { - try { - tagName = openCase.getServices().getTagsManager().getDisplayNamesToTagNamesMap().get(tagDisplayName); - } catch (TskCoreException ex1) { - Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, tagDisplayName + " already exists in database but an error occurred in retrieving it.", ex1); //NON-NLS - } - } catch (TskCoreException ex) { - Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex); //NON-NLS - } + return menu; + } + + /** + * Create a menu item for the given TagName. + * + * @param tagName TagName from which to create the menu item. + * + * @return Menu item for given TagName. + */ + private JMenuItem createMenutItem(TagName tagName) { + String tagDisplayName = tagName.getDisplayName(); + String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; + JMenuItem tagNameItem = new JMenuItem(tagDisplayName + notableString); + + if (tagDisplayName.equals(TagsManager.getBookmarkTagDisplayName())) { + tagNameItem.setAccelerator(AddBookmarkTagAction.BOOKMARK_SHORTCUT); } - addTag(tagName, comment); + + tagNameItem.addActionListener((ActionEvent e) -> { + addTag(tagName, NO_COMMENT); + }); + + return tagNameItem; } } } diff --git a/Core/src/org/sleuthkit/autopsy/actions/DeleteFileBlackboardArtifactTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/DeleteFileBlackboardArtifactTagAction.java index ec846567aa..8c7c77652e 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/DeleteFileBlackboardArtifactTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/DeleteFileBlackboardArtifactTagAction.java @@ -40,11 +40,11 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.tags.TagUtils; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.datamodel.TskData; /** * Instances of this Action allow users to delete tags applied to blackboard @@ -194,8 +194,7 @@ public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implem TagName tagName = entry.getValue(); for (BlackboardArtifactTag artifactTag : existingTagsList) { if (tagDisplayName.equals(artifactTag.getName().getDisplayName())) { - String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; - JMenuItem tagNameItem = new JMenuItem(tagDisplayName + notableString); + JMenuItem tagNameItem = new JMenuItem(TagUtils.getDecoratedTagDisplayName(tagName)); tagNameItem.addActionListener((ActionEvent e) -> { deleteTag(tagName, artifactTag, artifact.getArtifactID()); }); diff --git a/Core/src/org/sleuthkit/autopsy/actions/DeleteFileContentTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/DeleteFileContentTagAction.java index f68017de19..cb719e2f0a 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/DeleteFileContentTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/DeleteFileContentTagAction.java @@ -40,11 +40,11 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.tags.TagUtils; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.datamodel.TskData; /** * Instances of this Action allow users to delete tags applied to content. @@ -199,8 +199,7 @@ public class DeleteFileContentTagAction extends AbstractAction implements Presen TagName tagName = entry.getValue(); for (ContentTag contentTag : existingTagsList) { if (tagDisplayName.equals(contentTag.getName().getDisplayName())) { - String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; - JMenuItem tagNameItem = new JMenuItem(tagDisplayName + notableString); + JMenuItem tagNameItem = new JMenuItem(TagUtils.getDecoratedTagDisplayName(tagName)); tagNameItem.addActionListener((ActionEvent e) -> { deleteTag(tagName, contentTag, file.getId()); }); diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java index cf0c27fb27..ba586c7b22 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java @@ -23,6 +23,7 @@ import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.util.ArrayList; +import java.util.HashMap; import java.util.logging.Level; import java.util.List; import java.util.Map; @@ -35,15 +36,17 @@ import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JList; import javax.swing.KeyStroke; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.tags.TagUtils; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.datamodel.TskData; +import org.sleuthkit.datamodel.TagSet; /** * This dialog allows tag assignment with a comment attached. @@ -52,8 +55,6 @@ import org.sleuthkit.datamodel.TskData; public class GetTagNameAndCommentDialog extends JDialog { private static final long serialVersionUID = 1L; - private final List tagNamesList = new ArrayList<>(); - private final List standardTagNamesList = new ArrayList<>(); private TagNameAndComment tagNameAndComment = null; public static class TagNameAndComment { @@ -128,8 +129,7 @@ public class GetTagNameAndCommentDialog extends JDialog { @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { - String status = ((TagName) value).getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; - String newValue = ((TagName) value).getDisplayName() + status; + String newValue = TagUtils.getDecoratedTagDisplayName((TagName) value); return super.getListCellRendererComponent(list, newValue, index, isSelected, cellHasFocus); } }); @@ -150,34 +150,51 @@ public class GetTagNameAndCommentDialog extends JDialog { } ); - // Populate the combo box with the available tag names and save the - // tag name DTOs to be enable to return the one the user selects. - // Tag name DTOs may be null (user tag names that have not been used do - // not exist in the database). try { TagsManager tagsManager = Case.getCurrentCaseThrows().getServices().getTagsManager(); List standardTagNames = TagsManager.getStandardTagNames(); Map tagNamesMap = new TreeMap<>(tagsManager.getDisplayNamesToTagNamesMap()); - + Map> tagSetMap = new TreeMap<>(); + List tagNamesList = new ArrayList<>(); + List standardTagNamesList = new ArrayList<>(); + tagNamesMap.entrySet().stream().map((entry) -> entry.getValue()).forEachOrdered((tagName) -> { - if (standardTagNames.contains(tagName.getDisplayName())) { + TagSet tagSet = null; + try { + tagSet = tagName.getTagSet(); + } catch (TskCoreException ex) { + Logger.getLogger(GetTagNameAndCommentDialog.class + .getName()).log(Level.SEVERE, "Failed to get tag set", ex); //NON-NLS + } + if(tagSet != null) { + if(tagSetMap.get(tagSet.getName()) == null) { + tagSetMap.put(tagSet.getName(), tagSet.getTagNames()); + } + } else if (standardTagNames.contains(tagName.getDisplayName())) { standardTagNamesList.add(tagName); } else { tagNamesList.add(tagName); } }); + + tagNamesList.forEach((tag) -> { + tagCombo.addItem(tag); + }); + + standardTagNamesList.forEach((tag) -> { + tagCombo.addItem(tag); + }); + + tagSetMap.values().forEach((tagNameList)->{ + tagNameList.forEach((tag)->{ + tagCombo.addItem(tag); + }); + }); } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(GetTagNameAndCommentDialog.class .getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS - } - tagNamesList.forEach((tag) -> { - tagCombo.addItem(tag); - }); - - standardTagNamesList.forEach((tag) -> { - tagCombo.addItem(tag); - }); + } // Center and show the dialog box. this.setLocationRelativeTo(this.getOwner()); @@ -310,7 +327,6 @@ public class GetTagNameAndCommentDialog extends JDialog { private void newTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagButtonActionPerformed TagName newTagName = GetTagNameDialog.doDialog(this); if (newTagName != null) { - tagNamesList.add(newTagName); tagCombo.addItem(newTagName); tagCombo.setSelectedItem(newTagName); } diff --git a/Core/src/org/sleuthkit/autopsy/actions/ReplaceTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/ReplaceTagAction.java index 79ca4f4739..09d5d5ba6b 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/ReplaceTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/ReplaceTagAction.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.actions; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -38,6 +39,7 @@ import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.Tag; import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TagSet; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; @@ -60,10 +62,10 @@ abstract class ReplaceTagAction extends AbstractAction implements } /** - * Subclasses of replaceTagAction should not override actionPerformed, - * but instead override replaceTag. - * - * @param event + * Subclasses of replaceTagAction should not override actionPerformed, but + * instead override replaceTag. + * + * @param event */ @Override @SuppressWarnings("NoopMethodInAbstractClass") @@ -77,9 +79,10 @@ abstract class ReplaceTagAction extends AbstractAction implements /** * Method to actually replace the selected tag with the given new tag * - * @param oldTag - the TagName which is being removed from the item + * @param oldTag - the TagName which is being removed from the item * @param newTagName - the TagName which is being added to the itme - * @param comment the comment associated with the tag, empty string for no comment + * @param comment the comment associated with the tag, empty string for + * no comment */ abstract protected void replaceTag(T oldTag, TagName newTagName, String comment); @@ -90,7 +93,6 @@ abstract class ReplaceTagAction extends AbstractAction implements */ abstract Collection getTagsToReplace(); - @Override public JMenuItem getPopupPresenter() { return new ReplaceTagMenu(); @@ -108,60 +110,50 @@ abstract class ReplaceTagAction extends AbstractAction implements super(getActionDisplayName()); final Collection selectedTags = getTagsToReplace(); - + // Get the current set of tag names. Map tagNamesMap = null; List standardTagNames = TagsManager.getStandardTagNames(); - try { - TagsManager tagsManager = Case.getCurrentCaseThrows().getServices().getTagsManager(); - tagNamesMap = new TreeMap<>(tagsManager.getDisplayNamesToTagNamesMap()); - } catch (TskCoreException | NoCurrentCaseException ex) { - Logger.getLogger(ReplaceTagMenu.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS - } - + Map tagSetMenuMap = new HashMap<>(); List standardTagMenuitems = new ArrayList<>(); // Ideally we should'nt allow user to pick a replacement tag that's already been applied to an item // In the very least we don't allow them to pick the same tag as the one they are trying to replace Set existingTagNames = new HashSet<>(); - if (!selectedTags.isEmpty()) { - T firstTag = selectedTags.iterator().next(); - existingTagNames.add(firstTag.getName().getDisplayName()); - } - - if (null != tagNamesMap && !tagNamesMap.isEmpty()) { - for (Map.Entry entry : tagNamesMap.entrySet()) { - String tagDisplayName = entry.getKey(); - String notableString = entry.getValue().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; - JMenuItem tagNameItem = new JMenuItem(tagDisplayName + notableString); - // for the bookmark tag name only, added shortcut label - if (tagDisplayName.equals(NbBundle.getMessage(AddTagAction.class, "AddBookmarkTagAction.bookmark.text"))) { - tagNameItem.setAccelerator(AddBookmarkTagAction.BOOKMARK_SHORTCUT); - } + try { + TagsManager tagsManager = Case.getCurrentCaseThrows().getServices().getTagsManager(); + tagNamesMap = new TreeMap<>(tagsManager.getDisplayNamesToTagNamesMap()); - // Add action to replace the tag - tagNameItem.addActionListener((ActionEvent event) -> { - selectedTags.forEach((oldtag) -> { - replaceTag(oldtag, entry.getValue(), oldtag.getComment()); - }); - }); - - // Don't allow replacing a tag with same tag. - if (existingTagNames.contains(tagDisplayName)) { - tagNameItem.setEnabled(false); - } - - - // Show custom tags before predefined tags in the menu - if (standardTagNames.contains(tagDisplayName)) { - standardTagMenuitems.add(tagNameItem); - } else { - add(tagNameItem); - } + if (!selectedTags.isEmpty()) { + T firstTag = selectedTags.iterator().next(); + existingTagNames.add(firstTag.getName().getDisplayName()); } - } else { - JMenuItem empty = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.noTags")); - empty.setEnabled(false); - add(empty); + + if (!tagNamesMap.isEmpty()) { + for (Map.Entry entry : tagNamesMap.entrySet()) { + TagName tagName = entry.getValue(); + TagSet tagSet = tagName.getTagSet(); + + // Show custom tags before predefined tags in the menu + if (tagSet != null) { + JMenu menu = tagSetMenuMap.get(tagSet.getName()); + if (menu == null) { + menu = createSubmenuForTagSet(tagSet, existingTagNames, selectedTags); + tagSetMenuMap.put(tagSet.getName(), menu); + } + } else if (standardTagNames.contains(tagName.getDisplayName())) { + standardTagMenuitems.add(createMenutItem(tagName, existingTagNames, selectedTags)); + } else { + add(createMenutItem(tagName, existingTagNames, selectedTags)); + } + } + } else { + JMenuItem empty = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.noTags")); + empty.setEnabled(false); + add(empty); + } + + } catch (TskCoreException | NoCurrentCaseException ex) { + Logger.getLogger(ReplaceTagMenu.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS } // @@ -171,7 +163,11 @@ abstract class ReplaceTagAction extends AbstractAction implements standardTagMenuitems.forEach((menuItem) -> { add(menuItem); }); - + + tagSetMenuMap.values().forEach((menuItem) -> { + add(menuItem); + }); + addSeparator(); JMenuItem newTagMenuItem = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.newTag")); newTagMenuItem.addActionListener((ActionEvent event) -> { @@ -183,7 +179,7 @@ abstract class ReplaceTagAction extends AbstractAction implements } }); add(newTagMenuItem); - // Create a "Choose Tag and Comment..." menu item. Selecting this item initiates + // Create a "Choose Tag and Comment..." menu item. Selecting this item initiates // a dialog that can be used to create or select a tag name with an // optional comment and adds a tag with the resulting name. JMenuItem tagAndCommentItem = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.tagAndComment")); @@ -195,7 +191,52 @@ abstract class ReplaceTagAction extends AbstractAction implements }); } }); - add(tagAndCommentItem); + add(tagAndCommentItem); } } + + /** + * Build a JMenu for the given TagSet. + * + * @param tagSet + * + * @return JMenu for the given TagSet + */ + private JMenu createSubmenuForTagSet(TagSet tagSet, Set tagNamesToDisable, Collection selectedTags) { + JMenu menu = new JMenu(tagSet.getName()); + List tagNameList = tagSet.getTagNames(); + + for (TagName tagName : tagNameList) { + menu.add(createMenutItem(tagName, tagNamesToDisable, selectedTags)); + } + + return menu; + } + + /** + * Create a menu item for the given TagName. + * + * @param tagName TagName from which to create the menu item. + * + * @return Menu item for given TagName. + */ + private JMenuItem createMenutItem(TagName tagName, Set tagNamesToDisable, Collection selectedTags) { + String tagDisplayName = tagName.getDisplayName(); + String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; + JMenuItem tagNameItem = new JMenuItem(tagDisplayName + notableString); + + if (tagDisplayName.equals(TagsManager.getBookmarkTagDisplayName())) { + tagNameItem.setAccelerator(AddBookmarkTagAction.BOOKMARK_SHORTCUT); + } + + tagNameItem.addActionListener((ActionEvent e) -> { + selectedTags.forEach((oldtag) -> { + replaceTag(oldtag, tagName, oldtag.getComment()); + }); + }); + + tagNameItem.setEnabled(!tagNamesToDisable.contains(tagDisplayName)); + + return tagNameItem; + } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties index 3df263e1db..833a778637 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties @@ -5,9 +5,9 @@ TagNameDialog.JOptionPane.tagNameIllegalCharacters.message=Tag name may not cont TagNameDialog.JOptionPane.tagNameIllegalCharacters.title=Invalid character in tag name TagNameDialog.JOptionPane.tagNameEmpty.message=The tag name cannot be empty TagNameDialog.JOptionPane.tagNameEmpty.title=Empty tag name -TagOptionsPanel.tagTypesListLabel.text=Tag Names: TagOptionsPanel.deleteTagNameButton.text=Delete Tag TagOptionsPanel.newTagNameButton.text=New Tag +TagOptionsPanel.tagTypesListLabel.text=Tag Names: TagNameDialog.okButton.text=OK TagNameDialog.cancelButton.text=Cancel TagNameDialog.tagNameTextField.text= diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties-MERGED index 5e79318334..6f6c2374fb 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties-MERGED @@ -13,17 +13,17 @@ TagNameDialog.JOptionPane.tagNameIllegalCharacters.message=Tag name may not cont TagNameDialog.JOptionPane.tagNameIllegalCharacters.title=Invalid character in tag name TagNameDialog.JOptionPane.tagNameEmpty.message=The tag name cannot be empty TagNameDialog.JOptionPane.tagNameEmpty.title=Empty tag name +TagOptionsPanel.deleteTagNameButton.text=Delete Tag TagOptionsPanel.descriptionLabel.text=Tag Description: TagOptionsPanel.editTagNameButton.text=Edit Tag TagOptionsPanel.ingestRunningWarningLabel.text=Cannot make changes to existing tags when ingest is running! TagOptionsPanel.isNotableLabel.text=Tag indicates item is notable: +TagOptionsPanel.newTagNameButton.text=New Tag TagOptionsPanel.notableYesOrNoLabel.text= TagOptionsPanel.panelDescriptionTextArea.text=Create and manage tags. Tags can be applied to files and results in the case. Notable tags will cause items tagged with them to be flagged as notable when using a central repository. Changing the status of a tag will only effect items in the current case. TagOptionsPanel.TagNameDialog.tagNameAlreadyExists.message=Tag name must be unique. A tag with this name already exists. TagOptionsPanel.TagNameDialog.tagNameAlreadyExists.title=Duplicate Tag Name TagOptionsPanel.tagTypesListLabel.text=Tag Names: -TagOptionsPanel.deleteTagNameButton.text=Delete Tag -TagOptionsPanel.newTagNameButton.text=New Tag TagNameDialog.okButton.text=OK TagNameDialog.cancelButton.text=Cancel TagNameDialog.tagNameTextField.text= diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle_ja.properties index c173a9e7de..faed43cf50 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle_ja.properties @@ -3,29 +3,21 @@ OptionsCategory_TagNames=TagNames TagNameDefinition.predefTagNames.bookmark.text=\u30d6\u30c3\u30af\u30de\u30fc\u30af TagNameDefinition.predefTagNames.followUp.text=\u30d5\u30a9\u30ed\u30fc\u30a2\u30c3\u30d7 TagNameDefinition.predefTagNames.notableItem.text=\u9855\u8457\u306a\u9805\u76ee -TagNameDialog.descriptionLabel.text=\u8a18\u8ff0: TagNameDialog.editTitle.text=\u30bf\u30b0\u3092\u7de8\u96c6 TagNameDialog.JOptionPane.tagDescriptionIllegalCharacters.message=\u30bf\u30b0\u306e\u8a18\u8ff0\u306b\u30ab\u30f3\u30de(,)\u3084\u30bb\u30df\u30b3\u30ed\u30f3(;)\u3092\u542b\u3081\u3089\u308c\u307e\u305b\u3093 TagNameDialog.JOptionPane.tagDescriptionIllegalCharacters.title=\u30bf\u30b0\u306e\u8a18\u8ff0\u306b\u7121\u52b9\u306a\u6587\u5b57\u304c\u3042\u308a\u307e\u3059 -TagNameDialog.notableCheckbox.text=\u30bf\u30b0\u306f\u9805\u76ee\u304c\u9855\u8457\u3067\u3042\u308b\u3068\u793a\u5506\u3057\u3066\u3044\u307e\u3059\u3002 TagNameDialog.title.text=\u65b0\u898f\u30bf\u30b0 TagNameDialog.JOptionPane.tagNameIllegalCharacters.message=\u30bf\u30b0\u540d\u306b\u6b21\u306e\u8a18\u53f7\u3092\u542b\u3081\u3089\u308c\u307e\u305b\u3093: \\ : * ? " < > | , ; TagNameDialog.JOptionPane.tagNameIllegalCharacters.title=\u30bf\u30b0\u540d\u306b\u7121\u52b9\u306a\u6587\u5b57\u304c\u3042\u308a\u307e\u3059 TagNameDialog.JOptionPane.tagNameEmpty.message=\u30bf\u30b0\u540d\u306f\u7a7a(\u672a\u5165\u529b)\u306e\u72b6\u614b\u306b\u3067\u304d\u307e\u305b\u3093\u3002 TagNameDialog.JOptionPane.tagNameEmpty.title=\u7a7a(\u672a\u5165\u529b)\u306e\u72b6\u614b\u306e\u30bf\u30b0\u540d -TagOptionsPanel.descriptionLabel.text=\u30bf\u30b0\u306e\u8a18\u8ff0: -TagOptionsPanel.editTagNameButton.text=\u30bf\u30b0\u3092\u7de8\u96c6 -TagOptionsPanel.ingestRunningWarningLabel.text=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u5b9f\u884c\u4e2d\u306f\u65e2\u5b58\u306e\u30bf\u30b0\u3092\u5909\u66f4\u3067\u304d\u307e\u305b\u3093! -TagOptionsPanel.isNotableLabel.text=\u30bf\u30b0\u306f\u9805\u76ee\u304c\u9855\u8457\u3067\u3042\u308b\u3068\u793a\u5506\u3057\u3066\u3044\u307e\u3059: -TagOptionsPanel.notableYesOrNoLabel.text= -TagOptionsPanel.panelDescriptionTextArea.text=\u30bf\u30b0\u3092\u4f5c\u6210\u3057\u3066\u7ba1\u7406\u3057\u307e\u3059\u3002\u30bf\u30b0\u3092\u30b1\u30fc\u30b9\u306e\u30d5\u30a1\u30a4\u30eb\u3068\u7d50\u679c\u306b\u9069\u7528\u3067\u304d\u307e\u3059\u3002\u30bb\u30f3\u30c8\u30e9\u30eb\u30fb\u30ec\u30dd\u30b8\u30c8\u30ea\u30fc\u306e\u4f7f\u7528\u4e2d\u3001\u9855\u8457\u306a\u30bf\u30b0\u3067\u30bf\u30b0\u4ed8\u3051\u3055\u308c\u305f\u9805\u76ee\u306b\u9855\u8457\u3068\u30d5\u30e9\u30b0\u304c\u7acb\u3066\u3089\u308c\u307e\u3059\u3002\u30bf\u30b0\u306e\u30b9\u30c6\u30fc\u30bf\u30b9\u5909\u66f4\u306f\u73fe\u5728\u306e\u30b1\u30fc\u30b9\u306e\u9805\u76ee\u306b\u306e\u307f\u5f71\u97ff\u3057\u307e\u3059\u3002 TagOptionsPanel.TagNameDialog.tagNameAlreadyExists.message=\u30bf\u30b0\u540d\u306f\u4e00\u610f\u3067\u306a\u3051\u308c\u3070\u306a\u308a\u307e\u305b\u3093\u3002\u3053\u306e\u540d\u524d\u306e\u30bf\u30b0\u306f\u3059\u3067\u306b\u5b58\u5728\u3057\u307e\u3059\u3002 TagOptionsPanel.TagNameDialog.tagNameAlreadyExists.title=\u30bf\u30b0\u540d\u3092\u8907\u88fd -TagOptionsPanel.tagTypesListLabel.text=\u30bf\u30b0\u540d: +TagsManager.notableTagEnding.text=\ (\u9855\u8457) TagOptionsPanel.deleteTagNameButton.text=\u30bf\u30b0\u3092\u524a\u9664 TagOptionsPanel.newTagNameButton.text=\u65b0\u898f\u30bf\u30b0 +TagOptionsPanel.tagTypesListLabel.text=\u30bf\u30b0\u540d: TagNameDialog.okButton.text=OK TagNameDialog.cancelButton.text=\u53d6\u308a\u6d88\u3057 TagNameDialog.tagNameTextField.text= TagNameDialog.newTagNameLabel.text=\u540d\u524d: -TagsManager.notableTagEnding.text=\ (\u9855\u8457) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java index 7cccbca405..17cff6d900 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java @@ -42,7 +42,7 @@ import org.sleuthkit.datamodel.TskData; * A tag name definition consisting of a display name, description and color. */ @Immutable -final class TagNameDefinition implements Comparable { +final public class TagNameDefinition implements Comparable { private static final Logger LOGGER = Logger.getLogger(TagNameDefinition.class.getName()); @Messages({ @@ -55,39 +55,25 @@ final class TagNameDefinition implements Comparable { private static final String TAG_SETTING_VERSION_KEY = "CustomTagNameVersion"; private static final int TAG_SETTINGS_VERSION = 1; - private static final String CATEGORY_ONE_NAME = "Child Exploitation (Illegal)"; - private static final String CATEGORY_TWO_NAME = "Child Exploitation (Non-Illegal/Age Difficult)"; - private static final String CATEGORY_THREE_NAME = "CGI/Animation (Child Exploitive)"; - private static final String CATEGORY_FOUR_NAME = "Exemplar/Comparison (Internal Use Only)"; - private static final String CATEGORY_FIVE_NAME = "Non-pertinent"; - private final String displayName; private final String description; private final TagName.HTML_COLOR color; private final TskData.FileKnown knownStatus; private static final List STANDARD_TAGS_DEFINITIONS = new ArrayList<>(); - private static final List PROJECT_VIC_TAG_DEFINITIONS = new ArrayList<>(); - private static final List OLD_CATEGORY_TAG_NAMES = new ArrayList<>(); + private static final List OLD_CATEGORY_TAG_NAMES = new ArrayList<>(); static { STANDARD_TAGS_DEFINITIONS.add(new TagNameDefinition(Bundle.TagNameDefinition_predefTagNames_bookmark_text(), "", TagName.HTML_COLOR.NONE, TskData.FileKnown.UNKNOWN)); STANDARD_TAGS_DEFINITIONS.add(new TagNameDefinition(Bundle.TagNameDefinition_predefTagNames_followUp_text(), "", TagName.HTML_COLOR.NONE, TskData.FileKnown.UNKNOWN)); STANDARD_TAGS_DEFINITIONS.add(new TagNameDefinition(Bundle.TagNameDefinition_predefTagNames_notableItem_text(), "", TagName.HTML_COLOR.NONE, TskData.FileKnown.BAD)); - PROJECT_VIC_TAG_DEFINITIONS.add(new TagNameDefinition(CATEGORY_ONE_NAME, "", TagName.HTML_COLOR.RED, TskData.FileKnown.BAD)); - PROJECT_VIC_TAG_DEFINITIONS.add(new TagNameDefinition(CATEGORY_TWO_NAME, "", TagName.HTML_COLOR.LIME, TskData.FileKnown.BAD)); - PROJECT_VIC_TAG_DEFINITIONS.add(new TagNameDefinition(CATEGORY_THREE_NAME, "", TagName.HTML_COLOR.YELLOW, TskData.FileKnown.BAD)); - PROJECT_VIC_TAG_DEFINITIONS.add(new TagNameDefinition(CATEGORY_FOUR_NAME, "", TagName.HTML_COLOR.PURPLE, TskData.FileKnown.UNKNOWN)); - PROJECT_VIC_TAG_DEFINITIONS.add(new TagNameDefinition(CATEGORY_FIVE_NAME, "", TagName.HTML_COLOR.FUCHSIA, TskData.FileKnown.UNKNOWN)); - - OLD_CATEGORY_TAG_NAMES.add("CAT-1: " + CATEGORY_ONE_NAME); - OLD_CATEGORY_TAG_NAMES.add("CAT-2: " + CATEGORY_TWO_NAME); - OLD_CATEGORY_TAG_NAMES.add("CAT-3: " + CATEGORY_THREE_NAME); - OLD_CATEGORY_TAG_NAMES.add("CAT-4: " + CATEGORY_FOUR_NAME); - OLD_CATEGORY_TAG_NAMES.add("CAT-5: " + CATEGORY_FIVE_NAME); + OLD_CATEGORY_TAG_NAMES.add("CAT-1: Child Exploitation (Illegal)"); + OLD_CATEGORY_TAG_NAMES.add("CAT-2: Child Exploitation (Non-Illegal/Age Difficult)"); + OLD_CATEGORY_TAG_NAMES.add("CAT-3: CGI/Animation (Child Exploitive)"); + OLD_CATEGORY_TAG_NAMES.add("CAT-4: Exemplar/Comparison (Internal Use Only)"); + OLD_CATEGORY_TAG_NAMES.add("CAT-5: Non-pertinent"); OLD_CATEGORY_TAG_NAMES.add("CAT-0: Uncategorized"); - } /** @@ -99,17 +85,13 @@ final class TagNameDefinition implements Comparable { * @param color The color for the tag name. * @param status The status denoted by the tag name. */ - TagNameDefinition(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown status) { + public TagNameDefinition(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown status) { this.displayName = displayName; this.description = description; this.color = color; this.knownStatus = status; } - static Collection getProjectVICDefaultDefinitions() { - return Collections.unmodifiableCollection(PROJECT_VIC_TAG_DEFINITIONS); - } - static Collection getStandardTagNameDefinitions() { return Collections.unmodifiableCollection(STANDARD_TAGS_DEFINITIONS); } @@ -121,10 +103,6 @@ final class TagNameDefinition implements Comparable { strList.add(def.getDisplayName()); } - for (TagNameDefinition def : PROJECT_VIC_TAG_DEFINITIONS) { - strList.add(def.getDisplayName()); - } - return strList; } @@ -133,7 +111,7 @@ final class TagNameDefinition implements Comparable { * * @return */ - static String getBookmarkDisplayString() { + static String getBookmarkTagDisplayName() { return Bundle.TagNameDefinition_predefTagNames_bookmark_text(); } @@ -142,7 +120,7 @@ final class TagNameDefinition implements Comparable { * * @return */ - static String getFollowUpDisplayString() { + static String getFollowUpTagDisplayName() { return Bundle.TagNameDefinition_predefTagNames_followUp_text(); } @@ -151,7 +129,7 @@ final class TagNameDefinition implements Comparable { * * @return */ - static String getNotableDisplayString() { + static String getNotableTagDisplayName() { return Bundle.TagNameDefinition_predefTagNames_notableItem_text(); } @@ -160,7 +138,7 @@ final class TagNameDefinition implements Comparable { * * @return The display name. */ - String getDisplayName() { + public String getDisplayName() { return displayName; } @@ -169,7 +147,7 @@ final class TagNameDefinition implements Comparable { * * @return The description. */ - String getDescription() { + public String getDescription() { return description; } @@ -178,7 +156,7 @@ final class TagNameDefinition implements Comparable { * * @return The color. */ - TagName.HTML_COLOR getColor() { + public TagName.HTML_COLOR getColor() { return color; } @@ -187,7 +165,7 @@ final class TagNameDefinition implements Comparable { * * @return a value of TskData.FileKnown which is associated with this tag */ - TskData.FileKnown getKnownStatus() { + public TskData.FileKnown getKnownStatus() { return knownStatus; } @@ -260,7 +238,7 @@ final class TagNameDefinition implements Comparable { try { tagName = caseDb.addOrUpdateTagName(displayName, description, color, knownStatus); } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Error updating non-file object ", ex); + LOGGER.log(Level.SEVERE, "Error saving tag name definition", ex); } return tagName; } @@ -380,8 +358,8 @@ final class TagNameDefinition implements Comparable { List tagStrings = new ArrayList<>(); List standardTags = getStandardTagNames(); for (TagNameDefinition def : definitions) { - if (!standardTags.contains(def.getDisplayName()) && - !OLD_CATEGORY_TAG_NAMES.contains(def.getDisplayName())) { + if (!standardTags.contains(def.getDisplayName()) + && !OLD_CATEGORY_TAG_NAMES.contains(def.getDisplayName())) { tagStrings.add(def.toSettingsFormat()); } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagSetDefinition.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagSetDefinition.java new file mode 100755 index 0000000000..ad11becdff --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagSetDefinition.java @@ -0,0 +1,135 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.casemodule.services; + +import com.google.gson.Gson; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.annotation.concurrent.Immutable; +import java.io.FileFilter; +import java.io.FileReader; +import org.sleuthkit.autopsy.coreutils.PlatformUtil; + +/** + * Definition of a tag set. + */ +@Immutable +final public class TagSetDefinition { + + private final static String FILE_NAME_TEMPLATE = "%s-tag-set.json"; + private final static Path TAGS_USER_CONFIG_DIR = Paths.get(PlatformUtil.getUserConfigDirectory(), "tags"); + + private final String name; + private final List tagNameDefinitionList; + + public TagSetDefinition(String name, List tagNameDefinitionList) { + if (name == null || name.isEmpty()) { + throw new IllegalArgumentException("Invalid parameter passed to TagSetDefinition constructor. TagSet name was null or empty."); + } + + if (tagNameDefinitionList == null || tagNameDefinitionList.isEmpty()) { + throw new IllegalArgumentException("Invalid parameter passed to TagSetDefinition constructor. TagNameDefinition list was null or empty."); + } + + this.name = name; + this.tagNameDefinitionList = tagNameDefinitionList; + } + + /** + * Returns the name of the TagSet. + * + * @return The name of the tag set. + */ + public String getName() { + return name; + } + + /** + * Returns the set's list of TagNameDefinitions. + * + * @return List of TagNameDefinition objects + */ + public List getTagNameDefinitions() { + return Collections.unmodifiableList(tagNameDefinitionList); + } + + /** + * Writes the given TagSetDefinition to a JSON file. If a JSON file for the + * given TagSet already exists it will be replaced with the new definition. + * + * @param tagSetDefinition TagSet to write to a JSON file. + * + * @throws IOException + */ + static synchronized void writeTagSetDefinition(TagSetDefinition tagSetDefinition) throws IOException { + // Create the tags directory if it doesn't exist. + File dir = TAGS_USER_CONFIG_DIR.toFile(); + if (!dir.exists()) { + dir.mkdirs(); + } + + File file = Paths.get(TAGS_USER_CONFIG_DIR.toString(), tagSetDefinition.getFileName()).toFile(); + if (file.exists()) { + file.delete(); + } + + try (FileWriter writer = new FileWriter(file)) { + (new Gson()).toJson(tagSetDefinition, writer); + } + } + + /** + * Returns a list of the defined TagSet objects. + * + * @return A list of TagSetDefinition objects or empty list if none were + * found. + */ + static synchronized List readTagSetDefinitions() throws IOException { + List tagSetList = new ArrayList<>(); + File dir = TAGS_USER_CONFIG_DIR.toFile(); + + if (!dir.exists()) { + return tagSetList; + } + + File[] fileList = dir.listFiles(new TagSetJsonFileFilter()); + Gson gson = new Gson(); + for (File file : fileList) { + try (FileReader reader = new FileReader(file)) { + tagSetList.add(gson.fromJson(reader, TagSetDefinition.class)); + } + } + + return tagSetList; + } + + /** + * Returns the JSON file name for this tag set definition. + * + * @return The file name. + */ + private String getFileName() { + return String.format(FILE_NAME_TEMPLATE, name.replace(" ", "-")); + } + + /** + * A FileFilter for TagSet JSON files. + */ + private static final class TagSetJsonFileFilter implements FileFilter { + + @Override + public boolean accept(File file) { + return file.getName().endsWith("tag-set.json"); + } + + } +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 565d761b47..746bac478c 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -56,6 +56,8 @@ public class TagsManager implements Closeable { private final SleuthkitCase caseDb; private static String DEFAULT_TAG_SET_NAME = "Project VIC"; + + private static final Object lock = new Object(); static { @@ -147,10 +149,11 @@ public class TagsManager implements Closeable { } /** - * Gets the set of display names of notable (TskData.FileKnown.BAD) tag types. - * If a case is not open the list will only include only the user defined - * custom tags. Otherwise the list will include all notable tags. - * @return + * Gets the set of display names of notable (TskData.FileKnown.BAD) tag + * types. If a case is not open the list will only include only the user + * defined custom tags. Otherwise the list will include all notable tags. + * + * @return */ public static List getNotableTagDisplayNames() { List tagDisplayNames = new ArrayList<>(); @@ -159,12 +162,12 @@ public class TagsManager implements Closeable { tagDisplayNames.add(tagDef.getDisplayName()); } } - - try { + + try { TagsManager tagsManager = Case.getCurrentCaseThrows().getServices().getTagsManager(); for (TagName tagName : tagsManager.getAllTagNames()) { - if(tagName.getKnownStatus() == TskData.FileKnown.BAD && - !tagDisplayNames.contains(tagName.getDisplayName())) { + if (tagName.getKnownStatus() == TskData.FileKnown.BAD + && !tagDisplayNames.contains(tagName.getDisplayName())) { tagDisplayNames.add(tagName.getDisplayName()); } } @@ -172,7 +175,7 @@ public class TagsManager implements Closeable { /* * No current case, nothing more to add to the set. */ - } catch(TskCoreException ex) { + } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to get list of TagNames from TagsManager.", ex); } return tagDisplayNames; @@ -206,22 +209,13 @@ public class TagsManager implements Closeable { return tagList; } - /** - * Returns the name of the Category TagSet. - * - * @return Name of category TagSet. - */ - public static String getCategoryTagSetName() { - return DEFAULT_TAG_SET_NAME; - } - /** * Returns the bookmark tag display string. * * @return */ - public static String getBookmarkDisplayString() { - return TagNameDefinition.getBookmarkDisplayString(); + public static String getBookmarkTagDisplayName() { + return TagNameDefinition.getBookmarkTagDisplayName(); } /** @@ -229,8 +223,8 @@ public class TagsManager implements Closeable { * * @return */ - public static String getFollowUpDisplayString() { - return TagNameDefinition.getFollowUpDisplayString(); + public static String getFollowUpTagDisplayName() { + return TagNameDefinition.getFollowUpTagDisplayName(); } /** @@ -238,8 +232,21 @@ public class TagsManager implements Closeable { * * @return */ - public static String getNotableDisplayString() { - return TagNameDefinition.getNotableDisplayString(); + public static String getNotableTagDisplayName() { + return TagNameDefinition.getNotableTagDisplayName(); + } + + /** + * Creates a new TagSetDefinition file. + * + * @param tagSetDef The tag set definition. + * + * @throws IOException + */ + public static void addTagSetDefinition(TagSetDefinition tagSetDef) throws IOException { + synchronized(lock) { + TagSetDefinition.writeTagSetDefinition(tagSetDef); + } } /** @@ -256,26 +263,57 @@ public class TagsManager implements Closeable { try { List setList = taggingMgr.getTagSets(); if (setList.isEmpty()) { - //Assume new case and add Project VIC tags. - - List tagNameList = new ArrayList<>(); - for (TagNameDefinition def : TagNameDefinition.getProjectVICDefaultDefinitions()) { - tagNameList.add(caseDb.addOrUpdateTagName(def.getDisplayName(), def.getDescription(), def.getColor(), def.getKnownStatus())); - } - taggingMgr.addTagSet(DEFAULT_TAG_SET_NAME, tagNameList); - for (TagNameDefinition def : TagNameDefinition.getStandardTagNameDefinitions()) { caseDb.addOrUpdateTagName(def.getDisplayName(), def.getDescription(), def.getColor(), def.getKnownStatus()); } + //Assume new case and add tag sets + for(TagSetDefinition setDef: TagSetDefinition.readTagSetDefinitions()) { + List tagNameList = new ArrayList<>(); + for(TagNameDefinition tagNameDef: setDef.getTagNameDefinitions()) { + tagNameList.add(caseDb.addOrUpdateTagName(tagNameDef.getDisplayName(), tagNameDef.getDescription(), tagNameDef.getColor(), tagNameDef.getKnownStatus())); + } + + if(!tagNameList.isEmpty()) { + taggingMgr.addTagSet(setDef.getName(), tagNameList); + } + } } } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Error updating non-file object ", ex); + LOGGER.log(Level.SEVERE, "Error updating standard tag name and tag set definitions", ex); + } catch(IOException ex) { + LOGGER.log(Level.SEVERE, "Error loading tag set JSON files", ex); } for (TagNameDefinition tagName : TagNameDefinition.getTagNameDefinitions()) { tagName.saveToCase(caseDb); } } + + /** + * Get a list of all tag sets currently in the case database. + * + * @return A list, possibly empty, of TagSet objects. + * + * @throws TskCoreException + */ + public List getAllTagSets() throws TskCoreException { + return caseDb.getTaggingManager().getTagSets(); + } + + /** + * Add a new TagSet to the case database. Tags will be ranked in the order + * which they are passed to this method. + * + * @param name Tag set name. + * @param tagNameList List of TagName in rank order. + * + * @return A new TagSet object. + * + * @throws TskCoreException + */ + public TagSet addTagSet(String name, List tagNameList) throws TskCoreException { + return caseDb.getTaggingManager().addTagSet(name, tagNameList); + } /** * Gets a list of all tag names currently in the case database. @@ -376,39 +414,17 @@ public class TagsManager implements Closeable { /** * Gets a map of tag display names to tag name entries in the case database. - * It has keys for the display names of the standard tag types, the current - * user's custom tag types, and the tags in the case database. The value for - * a given key will be null if the corresponding tag type is defined, but a - * tag name entry has not yet added to the case database. In that case, - * addTagName may be called to add the tag name entry. * - * @return A map of tag display names to possibly null TagName object - * references. + * @return A map of tag display names to TagName object references. * * @throws TskCoreException if there is an error querying the case database. */ public Map getDisplayNamesToTagNamesMap() throws TskCoreException { - /** - * Order is important here. The keys (display names) for the current - * user's custom tag types are added to the map first, with null TagName - * values. If tag name entries exist for those keys, loading of the tag - * names from the database supplies the missing values. Standard tag - * names are added during the initialization of the case database. - * - * Note that creating the map on demand increases the probability that - * the display names of newly added custom tag types and the display - * names of tags added to a multi-user case by other users appear in the - * map. - */ Map tagNames = new HashMap<>(); - Set customTypes = TagNameDefinition.getTagNameDefinitions(); - for (TagNameDefinition tagType : customTypes) { - tagNames.put(tagType.getDisplayName(), null); - } for (TagName tagName : caseDb.getAllTagNames()) { tagNames.put(tagName.getDisplayName(), tagName); } - return new HashMap<>(tagNames); + return tagNames; } /** @@ -425,7 +441,7 @@ public class TagsManager implements Closeable { * @throws TskCoreException If there is an error adding the tag * name to the case database. */ - public synchronized TagName addTagName(String displayName) throws TagNameAlreadyExistsException, TskCoreException { + public TagName addTagName(String displayName) throws TagNameAlreadyExistsException, TskCoreException { return addTagName(displayName, "", TagName.HTML_COLOR.NONE, TskData.FileKnown.UNKNOWN); } @@ -444,7 +460,7 @@ public class TagsManager implements Closeable { * @throws TskCoreException If there is an error adding the tag * name to the case database. */ - public synchronized TagName addTagName(String displayName, String description) throws TagNameAlreadyExistsException, TskCoreException { + public TagName addTagName(String displayName, String description) throws TagNameAlreadyExistsException, TskCoreException { return addTagName(displayName, description, TagName.HTML_COLOR.NONE, TskData.FileKnown.UNKNOWN); } @@ -463,7 +479,7 @@ public class TagsManager implements Closeable { * @throws TskCoreException If there is an error adding the tag * name to the case database. */ - public synchronized TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TagNameAlreadyExistsException, TskCoreException { + public TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TagNameAlreadyExistsException, TskCoreException { return addTagName(displayName, description, color, TskData.FileKnown.UNKNOWN); } @@ -484,21 +500,23 @@ public class TagsManager implements Closeable { * @throws TskCoreException If there is an error adding the tag * name to the case database. */ - public synchronized TagName addTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus) throws TagNameAlreadyExistsException, TskCoreException { - try { - TagName tagName = caseDb.addOrUpdateTagName(displayName, description, color, knownStatus); - Set customTypes = TagNameDefinition.getTagNameDefinitions(); - customTypes.add(new TagNameDefinition(displayName, description, color, knownStatus)); - TagNameDefinition.setTagNameDefinitions(customTypes); - return tagName; - } catch (TskCoreException ex) { - List existingTagNames = caseDb.getAllTagNames(); - for (TagName tagName : existingTagNames) { - if (tagName.getDisplayName().equals(displayName)) { - throw new TagNameAlreadyExistsException(); + public TagName addTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus) throws TagNameAlreadyExistsException, TskCoreException { + synchronized(lock) { + try { + TagName tagName = caseDb.addOrUpdateTagName(displayName, description, color, knownStatus); + Set customTypes = TagNameDefinition.getTagNameDefinitions(); + customTypes.add(new TagNameDefinition(displayName, description, color, knownStatus)); + TagNameDefinition.setTagNameDefinitions(customTypes); + return tagName; + } catch (TskCoreException ex) { + List existingTagNames = caseDb.getAllTagNames(); + for (TagName tagName : existingTagNames) { + if (tagName.getDisplayName().equals(displayName)) { + throw new TagNameAlreadyExistsException(); + } } + throw ex; } - throw ex; } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Bundle.properties-MERGED index 44f4462515..ca1cd14877 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Bundle.properties-MERGED @@ -44,6 +44,7 @@ EamDbUtil.centralRepoConnectionFailed.message=Unable to connect to Central Repos EamDbUtil.centralRepoDisabled.message=\ The Central Repository has been disabled. EamDbUtil.centralRepoUpgradeFailed.message=Failed to upgrade Central Repository. EamDbUtil.exclusiveLockAquisitionFailure.message=Unable to acquire exclusive lock for Central Repository. +Persona.defaultName=Unnamed PostgresEamDb.centralRepoDisabled.message=Central Repository module is not enabled. PostgresEamDb.connectionFailed.message=Error getting connection to database. PostgresEamDb.multiUserLockError.message=Error acquiring database lock diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Persona.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Persona.java index 72a5cf2a0a..2c48021400 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Persona.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Persona.java @@ -27,6 +27,7 @@ import java.util.Collections; import java.util.Objects; import java.util.UUID; import org.apache.commons.lang3.StringUtils; +import org.openide.util.NbBundle; import org.sleuthkit.datamodel.SleuthkitCase; /** @@ -114,9 +115,6 @@ public class Persona { } } - // Persona name to use if no name is specified. - private static final String DEFAULT_PERSONA_NAME = "Unknown"; - // primary key in the Personas table in CR database private final long id; private final String uuidStr; @@ -126,6 +124,11 @@ public class Persona { private final long modifiedDate; private final PersonaStatus status; private final CentralRepoExaminer examiner; + + @NbBundle.Messages("Persona.defaultName=Unnamed") + public static String getDefaultName() { + return Bundle.Persona_defaultName(); + } public long getId() { return id; @@ -240,7 +243,7 @@ public class Persona { String insertClause = " INTO personas (uuid, comment, name, created_date, modified_date, status_id, examiner_id ) " + "VALUES ( '" + uuidStr + "', " + "'" + ((StringUtils.isBlank(comment) ? "" : SleuthkitCase.escapeSingleQuotes(comment))) + "'," - + "'" + ((StringUtils.isBlank(name) ? DEFAULT_PERSONA_NAME : SleuthkitCase.escapeSingleQuotes(name))) + "'," + + "'" + ((StringUtils.isBlank(name) ? getDefaultName() : SleuthkitCase.escapeSingleQuotes(name))) + "'," + timeStampMillis.toString() + "," + timeStampMillis.toString() + "," + status.getStatusId() + "," diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PersonaAlias.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PersonaAlias.java index cdebd7097d..7014e013bd 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PersonaAlias.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PersonaAlias.java @@ -149,7 +149,8 @@ public class PersonaAlias { public static Collection getPersonaAliases(long personaId) throws CentralRepoException { String queryClause = "SELECT pa.id, pa.persona_id, pa.alias, pa.justification, pa.confidence_id, pa.date_added, pa.examiner_id, e.login_name, e.display_name " + "FROM persona_alias as pa " - + "INNER JOIN examiners as e ON e.id = pa.examiner_id "; + + "INNER JOIN examiners as e ON e.id = pa.examiner_id " + + "WHERE pa.persona_id = " + personaId; PersonaAliasesQueryCallback queryCallback = new PersonaAliasesQueryCallback(); CentralRepository.getInstance().executeSelectSQL(queryClause, queryCallback); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PersonaMetadata.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PersonaMetadata.java index 713f00a981..e6fcb5da71 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PersonaMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PersonaMetadata.java @@ -160,8 +160,9 @@ public class PersonaMetadata { static Collection getPersonaMetadata(long personaId) throws CentralRepoException { String queryClause = "SELECT pmd.id, pmd.persona_id, pmd.name, pmd.value, pmd.justification, pmd.confidence_id, pmd.date_added, pmd.examiner_id, e.login_name, e.display_name " + "FROM persona_metadata as pmd " - + "INNER JOIN examiners as e ON e.id = pmd.examiner_id "; - + + "INNER JOIN examiners as e ON e.id = pmd.examiner_id " + + "WHERE pmd.persona_id = " + personaId; + PersonaMetadataQueryCallback queryCallback = new PersonaMetadataQueryCallback(); CentralRepository.getInstance().executeSelectSQL(queryClause, queryCallback); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/persona/AddAccountDialog.form b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/AddAccountDialog.form new file mode 100644 index 0000000000..c9cf66a7cb --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/AddAccountDialog.form @@ -0,0 +1,222 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/persona/AddAccountDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/AddAccountDialog.java new file mode 100644 index 0000000000..9a9146851b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/AddAccountDialog.java @@ -0,0 +1,335 @@ +/* + * Central Repository + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.centralrepository.persona; + +import java.awt.Component; +import java.io.Serializable; +import java.util.Collection; +import java.util.logging.Level; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.ListCellRenderer; +import org.openide.util.NbBundle.Messages; +import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount; +import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount.CentralRepoAccountType; +import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; +import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.centralrepository.datamodel.Persona; +import org.sleuthkit.autopsy.coreutils.Logger; + +/** + * Configuration dialog for adding an account to a persona. + */ +@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives +public class AddAccountDialog extends JDialog { + + private static final Logger logger = Logger.getLogger(AddAccountDialog.class.getName()); + + private static final long serialVersionUID = 1L; + + private final TypeChoiceRenderer TYPE_CHOICE_RENDERER = new TypeChoiceRenderer(); + private final PersonaDetailsPanel pdp; + + /** + * Creates new add account dialog + */ + @Messages({"AddAccountDialog.title.text=Add Account",}) + public AddAccountDialog(PersonaDetailsPanel pdp) { + super((JFrame) WindowManager.getDefault().getMainWindow(), + Bundle.AddAccountDialog_title_text(), + false); + this.pdp = pdp; + + initComponents(); + typeComboBox.setRenderer(TYPE_CHOICE_RENDERER); + display(); + } + + /** + * This class handles displaying and rendering drop down menu for account choices + */ + private class TypeChoiceRenderer extends JLabel implements ListCellRenderer, Serializable { + + private static final long serialVersionUID = 1L; + + @Override + public Component getListCellRendererComponent( + JList list, CentralRepoAccountType value, + int index, boolean isSelected, boolean cellHasFocus) { + setText(value.getAcctType().getDisplayName()); + return this; + } + } + + @Messages({ + "AddAccountDialog_get_types_exception_Title=Central Repository failure", + "AddAccountDialog_get_types_exception_msg=Failed to access central repository", + }) + private CentralRepoAccountType[] getAllAccountTypes() { + Collection allAccountTypes; + try { + allAccountTypes = CentralRepository.getInstance().getAllAccountTypes(); + } catch (CentralRepoException e) { + logger.log(Level.SEVERE, "Failed to access central repository", e); + JOptionPane.showMessageDialog(this, + Bundle.AddAccountDialog_get_types_exception_Title(), + Bundle.AddAccountDialog_get_types_exception_msg(), + JOptionPane.ERROR_MESSAGE); + return new CentralRepoAccountType[0]; + } + return allAccountTypes.toArray(new CentralRepoAccountType[0]); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + settingsPanel = new javax.swing.JPanel(); + identiferLbl = new javax.swing.JLabel(); + identifierTextField = new javax.swing.JTextField(); + typeLbl = new javax.swing.JLabel(); + typeComboBox = new javax.swing.JComboBox<>(); + justificationLbl = new javax.swing.JLabel(); + justificationTextField = new javax.swing.JTextField(); + confidenceLbl = new javax.swing.JLabel(); + confidenceComboBox = new javax.swing.JComboBox<>(); + cancelBtn = new javax.swing.JButton(); + okBtn = new javax.swing.JButton(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setResizable(false); + + settingsPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + + org.openide.awt.Mnemonics.setLocalizedText(identiferLbl, org.openide.util.NbBundle.getMessage(AddAccountDialog.class, "AddAccountDialog.identiferLbl.text")); // NOI18N + + identifierTextField.setText(org.openide.util.NbBundle.getMessage(AddAccountDialog.class, "AddAccountDialog.identifierTextField.text")); // NOI18N + identifierTextField.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + identifierTextFieldActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(typeLbl, org.openide.util.NbBundle.getMessage(AddAccountDialog.class, "AddAccountDialog.typeLbl.text")); // NOI18N + + typeComboBox.setModel(new javax.swing.DefaultComboBoxModel<>(getAllAccountTypes())); + + org.openide.awt.Mnemonics.setLocalizedText(justificationLbl, org.openide.util.NbBundle.getMessage(AddAccountDialog.class, "AddAccountDialog.justificationLbl.text")); // NOI18N + + justificationTextField.setText(org.openide.util.NbBundle.getMessage(AddAccountDialog.class, "AddAccountDialog.justificationTextField.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(confidenceLbl, org.openide.util.NbBundle.getMessage(AddAccountDialog.class, "AddAccountDialog.confidenceLbl.text")); // NOI18N + + confidenceComboBox.setModel(new javax.swing.DefaultComboBoxModel<>(org.sleuthkit.autopsy.centralrepository.datamodel.Persona.Confidence.values())); + + javax.swing.GroupLayout settingsPanelLayout = new javax.swing.GroupLayout(settingsPanel); + settingsPanel.setLayout(settingsPanelLayout); + settingsPanelLayout.setHorizontalGroup( + settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(settingsPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(settingsPanelLayout.createSequentialGroup() + .addComponent(typeLbl) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(typeComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(settingsPanelLayout.createSequentialGroup() + .addComponent(identiferLbl) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(identifierTextField)) + .addGroup(settingsPanelLayout.createSequentialGroup() + .addComponent(confidenceLbl) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(confidenceComboBox, 0, 269, Short.MAX_VALUE)) + .addGroup(settingsPanelLayout.createSequentialGroup() + .addComponent(justificationLbl) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(justificationTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 264, Short.MAX_VALUE))) + .addContainerGap()) + ); + settingsPanelLayout.setVerticalGroup( + settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(settingsPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(identiferLbl) + .addComponent(identifierTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(typeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(typeLbl, javax.swing.GroupLayout.PREFERRED_SIZE, 9, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(justificationLbl) + .addComponent(justificationTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(confidenceLbl) + .addComponent(confidenceComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + org.openide.awt.Mnemonics.setLocalizedText(cancelBtn, org.openide.util.NbBundle.getMessage(AddAccountDialog.class, "AddAccountDialog.cancelBtn.text")); // NOI18N + cancelBtn.setMaximumSize(new java.awt.Dimension(79, 23)); + cancelBtn.setMinimumSize(new java.awt.Dimension(79, 23)); + cancelBtn.setPreferredSize(new java.awt.Dimension(79, 23)); + cancelBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cancelBtnActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(okBtn, org.openide.util.NbBundle.getMessage(AddAccountDialog.class, "AddAccountDialog.okBtn.text")); // NOI18N + okBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + okBtnActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(settingsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addContainerGap(202, Short.MAX_VALUE) + .addComponent(okBtn) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cancelBtn, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap()) + ); + + layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {cancelBtn, okBtn}); + + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(settingsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(okBtn, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(cancelBtn, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + pack(); + }// //GEN-END:initComponents + + private void display() { + this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); + setVisible(true); + } + + @Messages({ + "AddAccountDialog_dup_Title=Account add failure", + "AddAccountDialog_dup_msg=This account is already added to the persona", + "AddAccountDialog_empty_Title=Empty identifier", + "AddAccountDialog_empty_msg=The identifier field cannot be empty", + "AddAccountDialog_search_failure_Title=Account add failure", + "AddAccountDialog_search_failure_msg=Central Repository account search failed", + "AddAccountDialog_search_empty_Title=Account not found", + "AddAccountDialog_search_empty_msg=Account not found for given identifier and type",}) + private void okBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okBtnActionPerformed + if (identifierTextField.getText().isEmpty()) { + JOptionPane.showMessageDialog(this, + Bundle.AddAccountDialog_empty_msg(), + Bundle.AddAccountDialog_empty_Title(), + JOptionPane.ERROR_MESSAGE); + return; + } + Collection candidates; + try { + candidates = CentralRepoAccount.getAccountsWithIdentifier(identifierTextField.getText()); + } catch (CentralRepoException e) { + logger.log(Level.SEVERE, "Failed to access central repository", e); + JOptionPane.showMessageDialog(this, + Bundle.AddAccountDialog_search_failure_msg(), + Bundle.AddAccountDialog_search_failure_Title(), + JOptionPane.ERROR_MESSAGE); + return; + } + if (candidates.isEmpty()) { + JOptionPane.showMessageDialog(this, + Bundle.AddAccountDialog_search_empty_msg(), + Bundle.AddAccountDialog_search_empty_Title(), + JOptionPane.ERROR_MESSAGE); + return; + } + CentralRepoAccount result = null; + for (CentralRepoAccount cand : candidates) { + if (cand.getAccountType().getAcctType().equals( + ((CentralRepoAccountType) typeComboBox.getSelectedItem()).getAcctType())) { + result = cand; + break; + } + } + if (result == null) { + JOptionPane.showMessageDialog(this, + Bundle.AddAccountDialog_search_empty_msg(), + Bundle.AddAccountDialog_search_empty_Title(), + JOptionPane.ERROR_MESSAGE); + return; + } + + if (pdp.addAccount( + result, + justificationTextField.getText(), + (Persona.Confidence) confidenceComboBox.getSelectedItem())) { + dispose(); + } else { + JOptionPane.showMessageDialog(this, + Bundle.AddAccountDialog_dup_msg(), + Bundle.AddAccountDialog_dup_Title(), + JOptionPane.ERROR_MESSAGE); + } + }//GEN-LAST:event_okBtnActionPerformed + + private void cancelBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelBtnActionPerformed + dispose(); + }//GEN-LAST:event_cancelBtnActionPerformed + + private void identifierTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_identifierTextFieldActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_identifierTextFieldActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton cancelBtn; + private javax.swing.JComboBox confidenceComboBox; + private javax.swing.JLabel confidenceLbl; + private javax.swing.JLabel identiferLbl; + private javax.swing.JTextField identifierTextField; + private javax.swing.JLabel justificationLbl; + private javax.swing.JTextField justificationTextField; + private javax.swing.JButton okBtn; + private javax.swing.JPanel settingsPanel; + private javax.swing.JComboBox typeComboBox; + private javax.swing.JLabel typeLbl; + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/persona/AddAliasDialog.form b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/AddAliasDialog.form new file mode 100644 index 0000000000..510a5a116f --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/AddAliasDialog.form @@ -0,0 +1,188 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/persona/AddAliasDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/AddAliasDialog.java new file mode 100644 index 0000000000..da6af4b7c9 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/AddAliasDialog.java @@ -0,0 +1,210 @@ +/* + * Central Repository + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.centralrepository.persona; + +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JOptionPane; +import org.openide.util.NbBundle.Messages; +import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.centralrepository.datamodel.Persona; + +/** + * Configuration dialog for adding aliases to a persona. + */ +@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives +public class AddAliasDialog extends JDialog { + + private static final long serialVersionUID = 1L; + + private final PersonaDetailsPanel pdp; + + /** + * Creates new add alias dialog + */ + @Messages({"AddAliasDialog.title.text=Add Alias",}) + public AddAliasDialog(PersonaDetailsPanel pdp) { + super((JFrame) WindowManager.getDefault().getMainWindow(), + Bundle.AddAliasDialog_title_text(), + false); + this.pdp = pdp; + + initComponents(); + display(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + settingsPanel = new javax.swing.JPanel(); + aliasLbl = new javax.swing.JLabel(); + aliasTextField = new javax.swing.JTextField(); + justificationLbl = new javax.swing.JLabel(); + justificationTextField = new javax.swing.JTextField(); + confidenceLbl = new javax.swing.JLabel(); + confidenceComboBox = new javax.swing.JComboBox<>(); + cancelBtn = new javax.swing.JButton(); + okBtn = new javax.swing.JButton(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setResizable(false); + + settingsPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + + org.openide.awt.Mnemonics.setLocalizedText(aliasLbl, org.openide.util.NbBundle.getMessage(AddAliasDialog.class, "AddAliasDialog.aliasLbl.text")); // NOI18N + + aliasTextField.setText(org.openide.util.NbBundle.getMessage(AddAliasDialog.class, "AddAliasDialog.aliasTextField.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(justificationLbl, org.openide.util.NbBundle.getMessage(AddAliasDialog.class, "AddAliasDialog.justificationLbl.text")); // NOI18N + + justificationTextField.setText(org.openide.util.NbBundle.getMessage(AddAliasDialog.class, "AddAliasDialog.justificationTextField.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(confidenceLbl, org.openide.util.NbBundle.getMessage(AddAliasDialog.class, "AddAliasDialog.confidenceLbl.text")); // NOI18N + + confidenceComboBox.setModel(new javax.swing.DefaultComboBoxModel<>(org.sleuthkit.autopsy.centralrepository.datamodel.Persona.Confidence.values())); + + javax.swing.GroupLayout settingsPanelLayout = new javax.swing.GroupLayout(settingsPanel); + settingsPanel.setLayout(settingsPanelLayout); + settingsPanelLayout.setHorizontalGroup( + settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(settingsPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(settingsPanelLayout.createSequentialGroup() + .addComponent(aliasLbl) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(aliasTextField)) + .addGroup(settingsPanelLayout.createSequentialGroup() + .addComponent(justificationLbl) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(justificationTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 262, Short.MAX_VALUE)) + .addGroup(settingsPanelLayout.createSequentialGroup() + .addComponent(confidenceLbl) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(confidenceComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addContainerGap()) + ); + settingsPanelLayout.setVerticalGroup( + settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(settingsPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(aliasLbl) + .addComponent(aliasTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(justificationTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(justificationLbl)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(confidenceComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(confidenceLbl)) + .addContainerGap()) + ); + + org.openide.awt.Mnemonics.setLocalizedText(cancelBtn, org.openide.util.NbBundle.getMessage(AddAliasDialog.class, "AddAliasDialog.cancelBtn.text_1")); // NOI18N + cancelBtn.setMaximumSize(new java.awt.Dimension(79, 23)); + cancelBtn.setMinimumSize(new java.awt.Dimension(79, 23)); + cancelBtn.setPreferredSize(new java.awt.Dimension(79, 23)); + cancelBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cancelBtnActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(okBtn, org.openide.util.NbBundle.getMessage(AddAliasDialog.class, "AddAliasDialog.okBtn.text_1")); // NOI18N + okBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + okBtnActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(okBtn) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cancelBtn, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + .addComponent(settingsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + + layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {cancelBtn, okBtn}); + + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(settingsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(okBtn) + .addComponent(cancelBtn, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + pack(); + }// //GEN-END:initComponents + + private void display() { + this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); + setVisible(true); + } + + @Messages({ + "AddAliasDialog_dup_Title=Alias add failure", + "AddAliasDialog_dup_msg=This alias has already been added to this persona",}) + private void okBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okBtnActionPerformed + if (pdp.addAlias( + aliasTextField.getText(), + justificationTextField.getText(), + (Persona.Confidence) confidenceComboBox.getSelectedItem())) { + dispose(); + } else { + JOptionPane.showMessageDialog(this, + Bundle.AddAliasDialog_dup_msg(), + Bundle.AddAliasDialog_dup_Title(), + JOptionPane.ERROR_MESSAGE); + } + }//GEN-LAST:event_okBtnActionPerformed + + private void cancelBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelBtnActionPerformed + dispose(); + }//GEN-LAST:event_cancelBtnActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel aliasLbl; + private javax.swing.JTextField aliasTextField; + private javax.swing.JButton cancelBtn; + private javax.swing.JComboBox confidenceComboBox; + private javax.swing.JLabel confidenceLbl; + private javax.swing.JLabel justificationLbl; + private javax.swing.JTextField justificationTextField; + private javax.swing.JButton okBtn; + private javax.swing.JPanel settingsPanel; + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/persona/AddMetadataDialog.form b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/AddMetadataDialog.form new file mode 100644 index 0000000000..b856f6a516 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/AddMetadataDialog.form @@ -0,0 +1,212 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/persona/AddMetadataDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/AddMetadataDialog.java new file mode 100644 index 0000000000..8336e31689 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/AddMetadataDialog.java @@ -0,0 +1,227 @@ +/* + * Central Repository + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.centralrepository.persona; + +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JOptionPane; +import org.openide.util.NbBundle.Messages; +import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.centralrepository.datamodel.Persona; + +/** + * Configuration dialog for adding metadata to a persona. + */ +@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives +public class AddMetadataDialog extends JDialog { + + private static final long serialVersionUID = 1L; + + private final PersonaDetailsPanel pdp; + + /** + * Creates new add metadata dialog + */ + @Messages({"AddMetadataDialog.title.text=Add Metadata",}) + public AddMetadataDialog(PersonaDetailsPanel pdp) { + super((JFrame) WindowManager.getDefault().getMainWindow(), + Bundle.AddMetadataDialog_title_text(), + false); + this.pdp = pdp; + + initComponents(); + display(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + settingsPanel = new javax.swing.JPanel(); + nameLbl = new javax.swing.JLabel(); + nameTextField = new javax.swing.JTextField(); + valueLbl = new javax.swing.JLabel(); + valueTextField = new javax.swing.JTextField(); + justificationLbl = new javax.swing.JLabel(); + justificationTextField = new javax.swing.JTextField(); + confidenceLbl = new javax.swing.JLabel(); + confidenceComboBox = new javax.swing.JComboBox<>(); + cancelBtn = new javax.swing.JButton(); + okBtn = new javax.swing.JButton(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setResizable(false); + + settingsPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + + org.openide.awt.Mnemonics.setLocalizedText(nameLbl, org.openide.util.NbBundle.getMessage(AddMetadataDialog.class, "AddMetadataDialog.nameLbl.text")); // NOI18N + + nameTextField.setText(org.openide.util.NbBundle.getMessage(AddMetadataDialog.class, "AddMetadataDialog.nameTextField.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(valueLbl, org.openide.util.NbBundle.getMessage(AddMetadataDialog.class, "AddMetadataDialog.valueLbl.text")); // NOI18N + + valueTextField.setText(org.openide.util.NbBundle.getMessage(AddMetadataDialog.class, "AddMetadataDialog.valueTextField.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(justificationLbl, org.openide.util.NbBundle.getMessage(AddMetadataDialog.class, "AddMetadataDialog.justificationLbl.text")); // NOI18N + + justificationTextField.setText(org.openide.util.NbBundle.getMessage(AddMetadataDialog.class, "AddMetadataDialog.justificationTextField.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(confidenceLbl, org.openide.util.NbBundle.getMessage(AddMetadataDialog.class, "AddMetadataDialog.confidenceLbl.text")); // NOI18N + + confidenceComboBox.setModel(new javax.swing.DefaultComboBoxModel<>(org.sleuthkit.autopsy.centralrepository.datamodel.Persona.Confidence.values())); + + javax.swing.GroupLayout settingsPanelLayout = new javax.swing.GroupLayout(settingsPanel); + settingsPanel.setLayout(settingsPanelLayout); + settingsPanelLayout.setHorizontalGroup( + settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(settingsPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(settingsPanelLayout.createSequentialGroup() + .addComponent(nameLbl) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(nameTextField)) + .addGroup(settingsPanelLayout.createSequentialGroup() + .addComponent(valueLbl) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(valueTextField)) + .addGroup(settingsPanelLayout.createSequentialGroup() + .addComponent(justificationLbl) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(justificationTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 262, Short.MAX_VALUE)) + .addGroup(settingsPanelLayout.createSequentialGroup() + .addComponent(confidenceLbl) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(confidenceComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addContainerGap()) + ); + settingsPanelLayout.setVerticalGroup( + settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(settingsPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(nameLbl) + .addComponent(nameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(valueLbl) + .addComponent(valueTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(justificationTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(justificationLbl)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(settingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(confidenceComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(confidenceLbl)) + .addContainerGap()) + ); + + org.openide.awt.Mnemonics.setLocalizedText(cancelBtn, org.openide.util.NbBundle.getMessage(AddMetadataDialog.class, "AddMetadataDialog.cancelBtn.text")); // NOI18N + cancelBtn.setMaximumSize(new java.awt.Dimension(79, 23)); + cancelBtn.setMinimumSize(new java.awt.Dimension(79, 23)); + cancelBtn.setPreferredSize(new java.awt.Dimension(79, 23)); + cancelBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cancelBtnActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(okBtn, org.openide.util.NbBundle.getMessage(AddMetadataDialog.class, "AddMetadataDialog.okBtn.text")); // NOI18N + okBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + okBtnActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(okBtn) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cancelBtn, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + .addComponent(settingsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + + layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {cancelBtn, okBtn}); + + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(settingsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(okBtn) + .addComponent(cancelBtn, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + pack(); + }// //GEN-END:initComponents + + private void display() { + this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); + setVisible(true); + } + + @Messages({ + "AddMetadataDialog_dup_Title=Metadata add failure", + "AddMetadataDialog_dup_msg=A metadata entry with this name has already been added to this persona",}) + private void okBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okBtnActionPerformed + if (pdp.addMetadata( + nameTextField.getText(), + valueTextField.getText(), + justificationTextField.getText(), + (Persona.Confidence) confidenceComboBox.getSelectedItem())) { + dispose(); + } else { + JOptionPane.showMessageDialog(this, + Bundle.AddMetadataDialog_dup_msg(), + Bundle.AddMetadataDialog_dup_Title(), + JOptionPane.ERROR_MESSAGE); + } + }//GEN-LAST:event_okBtnActionPerformed + + private void cancelBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelBtnActionPerformed + dispose(); + }//GEN-LAST:event_cancelBtnActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton cancelBtn; + private javax.swing.JComboBox confidenceComboBox; + private javax.swing.JLabel confidenceLbl; + private javax.swing.JLabel justificationLbl; + private javax.swing.JTextField justificationTextField; + private javax.swing.JLabel nameLbl; + private javax.swing.JTextField nameTextField; + private javax.swing.JButton okBtn; + private javax.swing.JPanel settingsPanel; + private javax.swing.JLabel valueLbl; + private javax.swing.JTextField valueTextField; + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties new file mode 100644 index 0000000000..f40bf2c7ca --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties @@ -0,0 +1,55 @@ +CTL_OpenPersonaManager=Persona Manager +CTL_PersonaManagerTopComponentAction=Persona Manager +CTL_PersonaDetailsTopComponent=Persona Details +PersonaManagerTopComponent.createBtn.text=New Persona +PersonaManagerTopComponent.searchBtn.text=Search +PersonaManagerTopComponent.resultsTable.columnModel.title1=Name +PersonaManagerTopComponent.resultsTable.columnModel.title0=ID +PersonaManagerTopComponent.resultsTable.toolTipText= +PersonaManagerTopComponent.searchAccountRadio.text=Account +PersonaManagerTopComponent.searchNameRadio.text=Name +PersonaManagerTopComponent.searchField.text= +AddAccountDialog.cancelBtn.text=Cancel +AddAccountDialog.okBtn.text=OK +PersonaManagerTopComponent.editBtn.text=Edit Persona +PersonaDetailsDialog.cancelBtn.text=Cancel +PersonaDetailsDialog.okBtn.text=OK +PersonaDetailsPanel.deleteCaseBtn.text=Delete +PersonaDetailsPanel.addCaseBtn.text=Add +PersonaDetailsPanel.casesLbl.text=Cases found in: +PersonaDetailsPanel.deleteAliasBtn.text=Delete +PersonaDetailsPanel.addAliasBtn.text=Add +PersonaDetailsPanel.aliasesLabel.text=Aliases: +PersonaDetailsPanel.deleteMetadataBtn.text=Delete +PersonaDetailsPanel.addMetadataBtn.text=Add +PersonaDetailsPanel.metadataLabel.text=Metadata: +PersonaDetailsPanel.deleteAccountBtn.text=Delete +PersonaDetailsPanel.addAccountBtn.text=Add +PersonaDetailsPanel.accountsLbl.text=Accounts: +PersonaDetailsPanel.nameField.text= +PersonaDetailsPanel.nameLbl.text=Name: +AddAliasDialog.accountsLbl.text=Account: +AddAliasDialog.okBtn.text=OK +AddAliasDialog.cancelBtn.text=Cancel +AddMetadataDialog.cancelBtn.text=Cancel +AddMetadataDialog.okBtn.text=OK +AddMetadataDialog.nameLbl.text=Name: +AddMetadataDialog.nameTextField.text= +AddMetadataDialog.valueLbl.text=Value: +AddMetadataDialog.valueTextField.text= +AddMetadataDialog.justificationLbl.text=Justification: +AddMetadataDialog.justificationTextField.text= +AddMetadataDialog.confidenceLbl.text=Confidence: +AddAliasDialog.justificationLbl.text=Justification: +AddAliasDialog.okBtn.text_1=OK +AddAliasDialog.cancelBtn.text_1=Cancel +AddAliasDialog.confidenceLbl.text=Confidence: +AddAliasDialog.justificationTextField.text= +AddAliasDialog.aliasLbl.text=Alias: +AddAliasDialog.aliasTextField.text= +AddAccountDialog.justificationTextField.text= +AddAccountDialog.justificationLbl.text=Justification: +AddAccountDialog.confidenceLbl.text=Confidence: +AddAccountDialog.typeLbl.text=Type: +AddAccountDialog.identiferLbl.text=Identifier: +AddAccountDialog.identifierTextField.text= diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties-MERGED new file mode 100644 index 0000000000..2258c7df21 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties-MERGED @@ -0,0 +1,44 @@ +AddAccountDialog.title.text=Add Account +AddAccountDialog_get_types_exception_msg=Failed to access central repository +AddAccountDialog_get_types_exception_Title=Central Repository failure +AddAccountDialog_validate_id_failure=Account ID must not be empty +AddAccountDialog_validate_id_failure_title=Account ID issue +CTL_OpenPersonaManager=Persona Manager +CTL_PersonaManagerTopComponentAction=Persona Manager +CTL_PersonaDetailsTopComponent=Persona Details +OpenPersonasAction.displayName=Persona Manager +PersonaDetailsPanel_load_exception_msg=Failed to load persona +PersonaDetailsPanel_load_exception_Title=Initialization failure +PersonaDetailsPanel_NameCreate=Create Persona +PersonaDetailsPanel_NameEdit=Edit Persona +PersonaDetailsPanel_NameView=View Persona +PersonaManagerTopComponent.createBtn.text=Create New +PersonaManagerTopComponent.searchBtn.text=Search +PersonaManagerTopComponent.resultsTable.columnModel.title1=Name +PersonaManagerTopComponent.resultsTable.columnModel.title0=ID +PersonaManagerTopComponent.resultsTable.toolTipText= +PersonaManagerTopComponent.searchAccountRadio.text=Account +PersonaManagerTopComponent.searchNameRadio.text=Name +PersonaManagerTopComponent.searchField.text= +PersonaDetailsPanel.deleteMetadataBtn.text=Delete +PersonaDetailsPanel.addMetadataBtn.text=Add +PersonaDetailsPanel.metadataLabel.text=Metadata: +PersonaDetailsPanel.deleteAccountBtn.text=Delete +PersonaDetailsPanel.addAccountBtn.text=Add +PersonaDetailsPanel.accountsLbl.text=Accounts: +PersonaDetailsPanel.nameField.text= +PersonaDetailsPanel.saveBtn.toolTipText= +PersonaDetailsPanel.saveBtn.text=Save Changes +PersonaDetailsPanel.nameLbl.text=Name: +PersonaDetailsPanel.deleteCaseBtn.text=Delete +PersonaDetailsPanel.addCaseBtn.text=Add +PersonaDetailsPanel.casesLbl.text=Cases found in: +PersonaDetailsPanel.deleteAliasBtn.text=Delete +PersonaDetailsPanel.addAliasBtn.text=Add +PersonaDetailsPanel.aliasesLabel.text=Aliases: +AddAccountDialog.cancelBtn.text=Cancel +AddAccountDialog.okBtn.text=OK +PersonaManagerTopComponent.editBtn.text=Edit +PMTopComponent_Name=Persona Manager +PMTopComponent_search_exception_msg=Failed to search personas +PMTopComponent_search_exception_Title=Search failure diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/persona/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/Bundle_ja.properties new file mode 100644 index 0000000000..224ac7c947 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/Bundle_ja.properties @@ -0,0 +1,10 @@ +AddAccountDialog.cancelBtn.text=\u53d6\u308a\u6d88\u3057 +AddAccountDialog.okBtn.text=OK +PersonaDetailsDialog.okBtn.text=OK +PersonaDetailsDialog.cancelBtn.text=\u53d6\u308a\u6d88\u3057 +AddAliasDialog.cancelBtn.text=\u53d6\u308a\u6d88\u3057 +AddAliasDialog.okBtn.text=OK +AddMetadataDialog.okBtn.text=OK +AddMetadataDialog.cancelBtn.text=\u53d6\u308a\u6d88\u3057 +AddAliasDialog.cancelBtn.text_1=\u53d6\u308a\u6d88\u3057 +AddAliasDialog.okBtn.text_1=OK diff --git a/Core/src/org/sleuthkit/autopsy/persona/OpenPersonasAction.java b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/OpenPersonaManagerAction.java similarity index 74% rename from Core/src/org/sleuthkit/autopsy/persona/OpenPersonasAction.java rename to Core/src/org/sleuthkit/autopsy/centralrepository/persona/OpenPersonaManagerAction.java index 157b25d1cc..9d40eeb357 100644 --- a/Core/src/org/sleuthkit/autopsy/persona/OpenPersonasAction.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/OpenPersonaManagerAction.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.persona; +package org.sleuthkit.autopsy.centralrepository.persona; import javax.swing.JMenuItem; import org.openide.awt.ActionID; @@ -28,33 +28,33 @@ import org.openide.util.NbBundle; import org.openide.util.actions.CallableSystemAction; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.coreutils.ThreadConfined; /** - * An Action that opens the Personas window. + * An Action that opens the Persona Search window. */ -@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.persona.Personas") -@ActionRegistration(displayName = "#CTL_OpenPersonas", lazy = false) +@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.centralrepository.persona.OpenPersonaManagerAction") +@ActionRegistration(displayName = "#CTL_OpenPersonaManager", lazy = false) @ActionReferences(value = { @ActionReference(path = "Menu/Tools", position = 105) }) -public final class OpenPersonasAction extends CallableSystemAction { +public final class OpenPersonaManagerAction extends CallableSystemAction { private static final long serialVersionUID = 1L; private final JMenuItem menuItem; - - public OpenPersonasAction() { + public OpenPersonaManagerAction() { menuItem = super.getMenuPresenter(); - this.setEnabled(true); + this.setEnabled(CentralRepository.isEnabled()); } @Override @ThreadConfined(type = ThreadConfined.ThreadType.AWT) public void performAction() { - final TopComponent topComponent = WindowManager.getDefault().findTopComponent("PersonasTopComponent"); + final TopComponent topComponent = WindowManager.getDefault().findTopComponent("PersonaManagerTopComponent"); if (topComponent != null) { if (topComponent.isOpened() == false) { topComponent.open(); @@ -65,7 +65,7 @@ public final class OpenPersonasAction extends CallableSystemAction { } @Override - @NbBundle.Messages("OpenPersonasAction.displayName=Personas") + @NbBundle.Messages("OpenPersonasAction.displayName=Persona Manager") public String getName() { return Bundle.OpenPersonasAction_displayName(); } @@ -85,6 +85,11 @@ public final class OpenPersonasAction extends CallableSystemAction { super.setEnabled(enable); menuItem.setEnabled(enable); } + + @Override + public boolean isEnabled() { + return CentralRepository.isEnabled(); + } @Override public JMenuItem getMenuPresenter() { diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/persona/PersonaDetailsDialog.form b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/PersonaDetailsDialog.form new file mode 100644 index 0000000000..296ad79921 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/PersonaDetailsDialog.form @@ -0,0 +1,90 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/persona/PersonaDetailsDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/PersonaDetailsDialog.java new file mode 100644 index 0000000000..c60f97d260 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/PersonaDetailsDialog.java @@ -0,0 +1,144 @@ +/* + * Central Repository + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.centralrepository.persona; + +import java.awt.Component; +import javax.swing.JDialog; +import javax.swing.JFrame; +import org.openide.util.NbBundle; +import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.centralrepository.datamodel.Persona; + +/** + * Configuration dialog for editing or creating a persona + */ +@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives +public class PersonaDetailsDialog extends JDialog { + + private static final long serialVersionUID = 1L; + + private final PersonaDetailsDialogCallback callback; + + @NbBundle.Messages({ + "PersonaDetailsDialogCreateTitle=Create Persona", + "PersonaDetailsDialogEditTitle=Edit Persona",}) + PersonaDetailsDialog(Component parent, PersonaDetailsMode mode, Persona persona, PersonaDetailsDialogCallback callback) { + super((JFrame) WindowManager.getDefault().getMainWindow(), + mode == PersonaDetailsMode.CREATE ? + Bundle.PersonaDetailsDialogCreateTitle() : + Bundle.PersonaDetailsDialogEditTitle(), + false); + this.callback = callback; + + initComponents(); + + pdp.setMode(parent, mode, persona); + + display(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + cancelBtn = new javax.swing.JButton(); + okBtn = new javax.swing.JButton(); + pdp = new org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsPanel(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setResizable(false); + + org.openide.awt.Mnemonics.setLocalizedText(cancelBtn, org.openide.util.NbBundle.getMessage(PersonaDetailsDialog.class, "PersonaDetailsDialog.cancelBtn.text")); // NOI18N + cancelBtn.setMaximumSize(new java.awt.Dimension(79, 23)); + cancelBtn.setMinimumSize(new java.awt.Dimension(79, 23)); + cancelBtn.setPreferredSize(new java.awt.Dimension(79, 23)); + cancelBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cancelBtnActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(okBtn, org.openide.util.NbBundle.getMessage(PersonaDetailsDialog.class, "PersonaDetailsDialog.okBtn.text")); // NOI18N + okBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + okBtnActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(pdp, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 660, Short.MAX_VALUE) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(okBtn) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cancelBtn, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap()) + ); + + layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {cancelBtn, okBtn}); + + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(pdp, javax.swing.GroupLayout.PREFERRED_SIZE, 564, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(okBtn) + .addComponent(cancelBtn, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) + ); + + pack(); + }// //GEN-END:initComponents + + private void display() { + this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); + setVisible(true); + } + + private void okBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okBtnActionPerformed + Persona ret = pdp.okHandler(); + if (ret != null) { + callback.callback(ret); + dispose(); + } + }//GEN-LAST:event_okBtnActionPerformed + + private void cancelBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelBtnActionPerformed + dispose(); + }//GEN-LAST:event_cancelBtnActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton cancelBtn; + private javax.swing.JButton okBtn; + private org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsPanel pdp; + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/persona/PersonaDetailsDialogCallback.java b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/PersonaDetailsDialogCallback.java new file mode 100644 index 0000000000..49852a91a0 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/PersonaDetailsDialogCallback.java @@ -0,0 +1,29 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.centralrepository.persona; + +import org.sleuthkit.autopsy.centralrepository.datamodel.Persona; + +/** + * This interface allows the client to implement callback methods which the + * PersonaDetailsDialog will call when the "OK" button is pressed. + */ +public interface PersonaDetailsDialogCallback { + void callback(Persona persona); +} diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/persona/PersonaDetailsMode.java b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/PersonaDetailsMode.java new file mode 100644 index 0000000000..646c666b15 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/PersonaDetailsMode.java @@ -0,0 +1,27 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.centralrepository.persona; + +/** + * An enum that represents the mode for the persona details panel + */ + +public enum PersonaDetailsMode { + CREATE, VIEW, EDIT +} diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/persona/PersonaDetailsPanel.form b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/PersonaDetailsPanel.form new file mode 100644 index 0000000000..c4200d166b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/PersonaDetailsPanel.form @@ -0,0 +1,334 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/persona/PersonaDetailsPanel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/PersonaDetailsPanel.java new file mode 100644 index 0000000000..c3567c78db --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/PersonaDetailsPanel.java @@ -0,0 +1,778 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.centralrepository.persona; + +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.logging.Level; +import java.util.stream.Collectors; +import javax.swing.JButton; +import javax.swing.JOptionPane; +import javax.swing.JTable; +import javax.swing.ListSelectionModel; +import javax.swing.event.ListSelectionEvent; +import javax.swing.table.DefaultTableModel; +import org.openide.windows.TopComponent; +import org.openide.util.NbBundle.Messages; +import org.openide.windows.RetainLocation; +import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount; +import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase; +import org.sleuthkit.autopsy.centralrepository.datamodel.Persona; +import org.sleuthkit.autopsy.centralrepository.datamodel.PersonaAccount; +import org.sleuthkit.autopsy.centralrepository.datamodel.PersonaAlias; +import org.sleuthkit.autopsy.centralrepository.datamodel.PersonaMetadata; +import org.sleuthkit.autopsy.coreutils.Logger; + +/** + * JPanel for persona details + */ +@TopComponent.Description(preferredID = "PersonaDetailsTopComponent", persistenceType = TopComponent.PERSISTENCE_NEVER) +@TopComponent.Registration(mode = "personadetails", openAtStartup = false) +@RetainLocation("personadetails") +@SuppressWarnings("PMD.SingularField") +public final class PersonaDetailsPanel extends javax.swing.JPanel { + + private static final long serialVersionUID = 1L; + + private static final Logger logger = Logger.getLogger(PersonaDetailsPanel.class.getName()); + + private PersonaDetailsMode mode; + + // Not-yet-created + private final List accountsToAdd = new ArrayList<>(); + private final List metadataToAdd = new ArrayList<>(); + private final List aliasesToAdd = new ArrayList<>(); + + private Persona currentPersona; + private List currentAccounts = new ArrayList<>(); + private List currentMetadata = new ArrayList<>(); + private List currentAliases = new ArrayList<>(); + private List currentCases = new ArrayList<>(); + + private PersonaDetailsTableModel accountsModel; + private PersonaDetailsTableModel metadataModel; + private PersonaDetailsTableModel aliasesModel; + private PersonaDetailsTableModel casesModel; + + @Messages({ + "PersonaDetailsPanel_NameEdit=Edit Persona", + "PersonaDetailsPanel_NameCreate=Create Persona", + "PersonaDetailsPanel_NameView=View Persona",}) + public PersonaDetailsPanel() { + initComponents(); + clear(); + + // Accounts + addAccountBtn.addActionListener((ActionEvent e) -> { + new AddAccountDialog(this); + }); + deleteAccountBtn.addActionListener((ActionEvent e) -> { + int selectedRow = accountsTable.getSelectedRow(); + if (selectedRow != -1) { + // We're keeping accounts in two separate data structures + if (selectedRow >= currentAccounts.size()) { + accountsToAdd.remove(selectedRow - currentAccounts.size()); + } else { + currentAccounts.remove(selectedRow); + } + updateAccountsTable(); + } + }); + accountsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + accountsTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> { + handleSelectionChange(e, deleteAccountBtn, accountsTable); + }); + + // Metadata + addMetadataBtn.addActionListener((ActionEvent e) -> { + new AddMetadataDialog(this); + }); + deleteMetadataBtn.addActionListener((ActionEvent e) -> { + int selectedRow = metadataTable.getSelectedRow(); + if (selectedRow != -1) { + // We're keeping metadata in two separate data structures + if (selectedRow >= currentMetadata.size()) { + metadataToAdd.remove(selectedRow - currentMetadata.size()); + } else { + currentMetadata.remove(selectedRow); + } + updateMetadataTable(); + } + }); + metadataTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + metadataTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> { + handleSelectionChange(e, deleteMetadataBtn, metadataTable); + }); + + // Aliases + addAliasBtn.addActionListener((ActionEvent e) -> { + new AddAliasDialog(this); + }); + deleteAliasBtn.addActionListener((ActionEvent e) -> { + int selectedRow = aliasesTable.getSelectedRow(); + if (selectedRow != -1) { + // We're keeping aliases in two separate data structures + if (selectedRow >= currentAliases.size()) { + aliasesToAdd.remove(selectedRow - currentAliases.size()); + } else { + currentAliases.remove(selectedRow); + } + updateAliasesTable(); + } + }); + aliasesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + aliasesTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> { + handleSelectionChange(e, deleteAliasBtn, aliasesTable); + }); + } + + private void handleSelectionChange(ListSelectionEvent e, JButton btn, JTable table) { + if (e.getValueIsAdjusting()) { + return; + } + btn.setEnabled(mode != PersonaDetailsMode.VIEW && table.getSelectedRow() != -1); + } + + /** + * A data bucket class for yet-to-be-created PersonaAccount + */ + private class PAccount { + + private final CentralRepoAccount account; + private final String justification; + private final Persona.Confidence confidence; + + PAccount(CentralRepoAccount account, String justification, Persona.Confidence confidence) { + this.account = account; + this.justification = justification; + this.confidence = confidence; + } + } + + boolean accountExists(CentralRepoAccount account) { + for (CentralRepoAccount acc : currentAccounts) { + if (acc.getId() == account.getId()) { + return true; + } + } + for (PAccount acc : accountsToAdd) { + if (acc.account.getId() == account.getId()) { + return true; + } + } + return false; + } + + boolean addAccount(CentralRepoAccount account, String justification, Persona.Confidence confidence) { + if (!accountExists(account)) { + accountsToAdd.add(new PAccount(account, justification, confidence)); + updateAccountsTable(); + return true; + } + return false; + } + + Collection getCurrentAccounts() { + return currentAccounts; + } + + /** + * A data bucket class for yet-to-be-created PersonaMetadata + */ + private class PMetadata { + + private final String name; + private final String value; + private final String justification; + private final Persona.Confidence confidence; + + PMetadata(String name, String value, String justification, Persona.Confidence confidence) { + this.name = name; + this.value = value; + this.justification = justification; + this.confidence = confidence; + } + } + + boolean metadataExists(String name) { + for (PersonaMetadata pm : currentMetadata) { + if (pm.getName().equals(name)) { + return true; + } + } + for (PMetadata pm : metadataToAdd) { + if (pm.name.equals(name)) { + return true; + } + } + return false; + } + + boolean addMetadata(String name, String value, String justification, Persona.Confidence confidence) { + if (!metadataExists(name)) { + metadataToAdd.add(new PMetadata(name, value, justification, confidence)); + updateMetadataTable(); + return true; + } + return false; + } + + /** + * A data bucket class for yet-to-be-created PersonaAlias + */ + private class PAlias { + + private final String alias; + private final String justification; + private final Persona.Confidence confidence; + + PAlias(String alias, String justification, Persona.Confidence confidence) { + this.alias = alias; + this.justification = justification; + this.confidence = confidence; + } + } + + boolean aliasExists(String alias) { + for (PersonaAlias pa : currentAliases) { + if (pa.getAlias().equals(alias)) { + return true; + } + } + for (PAlias pa : aliasesToAdd) { + if (pa.alias.equals(alias)) { + return true; + } + } + return false; + } + + boolean addAlias(String alias, String justification, Persona.Confidence confidence) { + if (!aliasExists(alias)) { + aliasesToAdd.add(new PAlias(alias, justification, confidence)); + updateAliasesTable(); + return true; + } + return false; + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + // //GEN-BEGIN:initComponents + private void initComponents() { + + detailsPanel = new javax.swing.JPanel(); + nameLbl = new javax.swing.JLabel(); + nameField = new javax.swing.JTextField(); + accountsLbl = new javax.swing.JLabel(); + accountsTablePane = new javax.swing.JScrollPane(); + accountsTable = new javax.swing.JTable(); + addAccountBtn = new javax.swing.JButton(); + deleteAccountBtn = new javax.swing.JButton(); + metadataLabel = new javax.swing.JLabel(); + metadataTablePane = new javax.swing.JScrollPane(); + metadataTable = new javax.swing.JTable(); + addMetadataBtn = new javax.swing.JButton(); + deleteMetadataBtn = new javax.swing.JButton(); + aliasesLabel = new javax.swing.JLabel(); + aliasesTablePane = new javax.swing.JScrollPane(); + aliasesTable = new javax.swing.JTable(); + addAliasBtn = new javax.swing.JButton(); + deleteAliasBtn = new javax.swing.JButton(); + casesLbl = new javax.swing.JLabel(); + casesTablePane = new javax.swing.JScrollPane(); + casesTable = new javax.swing.JTable(); + addCaseBtn = new javax.swing.JButton(); + deleteCaseBtn = new javax.swing.JButton(); + + org.openide.awt.Mnemonics.setLocalizedText(nameLbl, org.openide.util.NbBundle.getMessage(PersonaDetailsPanel.class, "PersonaDetailsPanel.nameLbl.text")); // NOI18N + + nameField.setEditable(false); + nameField.setText(org.openide.util.NbBundle.getMessage(PersonaDetailsPanel.class, "PersonaDetailsPanel.nameField.text")); // NOI18N + nameField.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + nameFieldActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(accountsLbl, org.openide.util.NbBundle.getMessage(PersonaDetailsPanel.class, "PersonaDetailsPanel.accountsLbl.text")); // NOI18N + + accountsTable.setModel(new javax.swing.table.DefaultTableModel( + new Object [][] { + {}, + {}, + {}, + {} + }, + new String [] { + + } + )); + accountsTablePane.setViewportView(accountsTable); + + org.openide.awt.Mnemonics.setLocalizedText(addAccountBtn, org.openide.util.NbBundle.getMessage(PersonaDetailsPanel.class, "PersonaDetailsPanel.addAccountBtn.text")); // NOI18N + addAccountBtn.setEnabled(false); + + org.openide.awt.Mnemonics.setLocalizedText(deleteAccountBtn, org.openide.util.NbBundle.getMessage(PersonaDetailsPanel.class, "PersonaDetailsPanel.deleteAccountBtn.text")); // NOI18N + deleteAccountBtn.setEnabled(false); + + org.openide.awt.Mnemonics.setLocalizedText(metadataLabel, org.openide.util.NbBundle.getMessage(PersonaDetailsPanel.class, "PersonaDetailsPanel.metadataLabel.text")); // NOI18N + + metadataTable.setModel(new javax.swing.table.DefaultTableModel( + new Object [][] { + {}, + {}, + {}, + {} + }, + new String [] { + + } + )); + metadataTablePane.setViewportView(metadataTable); + + org.openide.awt.Mnemonics.setLocalizedText(addMetadataBtn, org.openide.util.NbBundle.getMessage(PersonaDetailsPanel.class, "PersonaDetailsPanel.addMetadataBtn.text")); // NOI18N + addMetadataBtn.setEnabled(false); + + org.openide.awt.Mnemonics.setLocalizedText(deleteMetadataBtn, org.openide.util.NbBundle.getMessage(PersonaDetailsPanel.class, "PersonaDetailsPanel.deleteMetadataBtn.text")); // NOI18N + deleteMetadataBtn.setEnabled(false); + + org.openide.awt.Mnemonics.setLocalizedText(aliasesLabel, org.openide.util.NbBundle.getMessage(PersonaDetailsPanel.class, "PersonaDetailsPanel.aliasesLabel.text")); // NOI18N + + aliasesTable.setModel(new javax.swing.table.DefaultTableModel( + new Object [][] { + {}, + {}, + {}, + {} + }, + new String [] { + + } + )); + aliasesTablePane.setViewportView(aliasesTable); + + org.openide.awt.Mnemonics.setLocalizedText(addAliasBtn, org.openide.util.NbBundle.getMessage(PersonaDetailsPanel.class, "PersonaDetailsPanel.addAliasBtn.text")); // NOI18N + addAliasBtn.setEnabled(false); + + org.openide.awt.Mnemonics.setLocalizedText(deleteAliasBtn, org.openide.util.NbBundle.getMessage(PersonaDetailsPanel.class, "PersonaDetailsPanel.deleteAliasBtn.text")); // NOI18N + deleteAliasBtn.setEnabled(false); + + org.openide.awt.Mnemonics.setLocalizedText(casesLbl, org.openide.util.NbBundle.getMessage(PersonaDetailsPanel.class, "PersonaDetailsPanel.casesLbl.text")); // NOI18N + + casesTable.setModel(new javax.swing.table.DefaultTableModel( + new Object [][] { + {}, + {}, + {}, + {} + }, + new String [] { + + } + )); + casesTablePane.setViewportView(casesTable); + + org.openide.awt.Mnemonics.setLocalizedText(addCaseBtn, org.openide.util.NbBundle.getMessage(PersonaDetailsPanel.class, "PersonaDetailsPanel.addCaseBtn.text")); // NOI18N + addCaseBtn.setEnabled(false); + + org.openide.awt.Mnemonics.setLocalizedText(deleteCaseBtn, org.openide.util.NbBundle.getMessage(PersonaDetailsPanel.class, "PersonaDetailsPanel.deleteCaseBtn.text")); // NOI18N + deleteCaseBtn.setEnabled(false); + + javax.swing.GroupLayout detailsPanelLayout = new javax.swing.GroupLayout(detailsPanel); + detailsPanel.setLayout(detailsPanelLayout); + detailsPanelLayout.setHorizontalGroup( + detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(detailsPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(accountsTablePane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 549, Short.MAX_VALUE) + .addGroup(detailsPanelLayout.createSequentialGroup() + .addComponent(nameLbl) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(nameField)) + .addComponent(accountsLbl, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(metadataLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(metadataTablePane, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(aliasesLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(aliasesTablePane) + .addComponent(casesLbl, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(casesTablePane) + .addGroup(detailsPanelLayout.createSequentialGroup() + .addGroup(detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(detailsPanelLayout.createSequentialGroup() + .addComponent(addCaseBtn) + .addGap(18, 18, 18) + .addComponent(deleteCaseBtn)) + .addGroup(detailsPanelLayout.createSequentialGroup() + .addComponent(addAccountBtn) + .addGap(18, 18, 18) + .addComponent(deleteAccountBtn)) + .addGroup(detailsPanelLayout.createSequentialGroup() + .addComponent(addMetadataBtn) + .addGap(18, 18, 18) + .addComponent(deleteMetadataBtn)) + .addGroup(detailsPanelLayout.createSequentialGroup() + .addComponent(addAliasBtn) + .addGap(18, 18, 18) + .addComponent(deleteAliasBtn))) + .addGap(0, 0, Short.MAX_VALUE))) + .addContainerGap()) + ); + detailsPanelLayout.setVerticalGroup( + detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(detailsPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(nameLbl) + .addComponent(nameField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(accountsLbl) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(accountsTablePane, javax.swing.GroupLayout.PREFERRED_SIZE, 56, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(addAccountBtn) + .addComponent(deleteAccountBtn)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(metadataLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(metadataTablePane, javax.swing.GroupLayout.PREFERRED_SIZE, 66, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(deleteMetadataBtn) + .addComponent(addMetadataBtn)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(aliasesLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(aliasesTablePane, javax.swing.GroupLayout.PREFERRED_SIZE, 74, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(deleteAliasBtn) + .addComponent(addAliasBtn)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(casesLbl) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(casesTablePane, javax.swing.GroupLayout.PREFERRED_SIZE, 63, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(addCaseBtn) + .addComponent(deleteCaseBtn)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 561, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(detailsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 559, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(detailsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + private void nameFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nameFieldActionPerformed + + }//GEN-LAST:event_nameFieldActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel accountsLbl; + private javax.swing.JTable accountsTable; + private javax.swing.JScrollPane accountsTablePane; + private javax.swing.JButton addAccountBtn; + private javax.swing.JButton addAliasBtn; + private javax.swing.JButton addCaseBtn; + private javax.swing.JButton addMetadataBtn; + private javax.swing.JLabel aliasesLabel; + private javax.swing.JTable aliasesTable; + private javax.swing.JScrollPane aliasesTablePane; + private javax.swing.JLabel casesLbl; + private javax.swing.JTable casesTable; + private javax.swing.JScrollPane casesTablePane; + private javax.swing.JButton deleteAccountBtn; + private javax.swing.JButton deleteAliasBtn; + private javax.swing.JButton deleteCaseBtn; + private javax.swing.JButton deleteMetadataBtn; + private javax.swing.JPanel detailsPanel; + private javax.swing.JLabel metadataLabel; + private javax.swing.JTable metadataTable; + private javax.swing.JScrollPane metadataTablePane; + private javax.swing.JTextField nameField; + private javax.swing.JLabel nameLbl; + // End of variables declaration//GEN-END:variables + + @Messages({ + "PersonaDetailsPanel_load_exception_Title=Initialization failure", + "PersonaDetailsPanel_load_exception_msg=Failed to load persona",}) + private void loadPersona(Component parent, Persona persona) { + String name; + Collection accounts; + Collection metadata; + Collection aliases; + Collection cases; + try { + name = persona.getName(); + accounts = persona.getPersonaAccounts().stream().map(PersonaAccount::getAccount) + .collect(Collectors.toList()); + metadata = persona.getMetadata(); + aliases = persona.getAliases(); + cases = persona.getCases(); + } catch (CentralRepoException ex) { + logger.log(Level.SEVERE, "Failed to load persona", ex); + JOptionPane.showMessageDialog(parent, + Bundle.PersonaDetailsPanel_load_exception_Title(), + Bundle.PersonaDetailsPanel_load_exception_msg(), + JOptionPane.ERROR_MESSAGE); + return; + } + this.currentPersona = persona; + this.nameField.setText(name); + this.currentAccounts.addAll(accounts); + this.currentMetadata.addAll(metadata); + this.currentAliases.addAll(aliases); + this.currentCases.addAll(cases); + } + + void clear() { + currentPersona = null; + nameField.setText(Persona.getDefaultName()); + currentAccounts = new ArrayList<>(); + currentMetadata = new ArrayList<>(); + currentAliases = new ArrayList<>(); + currentCases = new ArrayList<>(); + accountsToAdd.clear(); + metadataToAdd.clear(); + aliasesToAdd.clear(); + nameField.setEditable(false); + + initializeFields(); + + addAccountBtn.setEnabled(false); + addMetadataBtn.setEnabled(false); + addAliasBtn.setEnabled(false); + addCaseBtn.setEnabled(false); + deleteAccountBtn.setEnabled(false); + deleteMetadataBtn.setEnabled(false); + deleteAliasBtn.setEnabled(false); + deleteCaseBtn.setEnabled(false); + } + + /** + * Table model for persona details + */ + final class PersonaDetailsTableModel extends DefaultTableModel { + + private static final long serialVersionUID = 1L; + + PersonaDetailsTableModel(Object[][] rows, String[] colNames) { + super(rows, colNames); + } + + @Override + public boolean isCellEditable(int row, int column) { + return false; + } + } + + private void updateAccountsTable() { + Object[][] rows = new Object[currentAccounts.size() + accountsToAdd.size()][2]; + int i = 0; + for (CentralRepoAccount acc : currentAccounts) { + rows[i] = new Object[]{ + acc.getAccountType().getAcctType().getDisplayName(), + acc.getIdentifier() + }; + i++; + } + for (PAccount acc : accountsToAdd) { + rows[i] = new Object[]{ + acc.account.getAccountType().getAcctType().getDisplayName(), + acc.account.getIdentifier() + }; + i++; + } + accountsModel = new PersonaDetailsTableModel( + rows, + new String[]{"Type", "Identifier"} + ); + accountsTable.setModel(accountsModel); + + // Formatting + accountsTable.getColumnModel().getColumn(0).setMaxWidth(100); + accountsTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); + } + + private void updateMetadataTable() { + Object[][] rows = new Object[currentMetadata.size() + metadataToAdd.size()][2]; + int i = 0; + for (PersonaMetadata md : currentMetadata) { + rows[i] = new Object[]{md.getName(), md.getValue()}; + i++; + } + for (PMetadata md : metadataToAdd) { + rows[i] = new Object[]{md.name, md.value}; + i++; + } + metadataModel = new PersonaDetailsTableModel( + rows, + new String[]{"Name", "Value"} + ); + metadataTable.setModel(metadataModel); + } + + private void updateAliasesTable() { + Object[][] rows = new Object[currentAliases.size() + aliasesToAdd.size()][1]; + int i = 0; + for (PersonaAlias alias : currentAliases) { + rows[i] = new Object[]{alias.getAlias()}; + i++; + } + for (PAlias alias : aliasesToAdd) { + rows[i] = new Object[]{alias.alias}; + i++; + } + aliasesModel = new PersonaDetailsTableModel( + rows, + new String[]{"Alias"} + ); + aliasesTable.setModel(aliasesModel); + } + + private void updateCasesTable() { + Object[][] rows = new Object[currentCases.size()][1]; + int i = 0; + for (CorrelationCase c : currentCases) { + rows[i] = new Object[]{c.getDisplayName()}; + i++; + } + casesModel = new PersonaDetailsTableModel( + rows, + new String[]{"Case"} + ); + casesTable.setModel(casesModel); + } + + void enableEditUIComponents() { + nameField.setEditable(true); + addAccountBtn.setEnabled(true); + addMetadataBtn.setEnabled(true); + addAliasBtn.setEnabled(true); + //addCaseBtn.setEnabled(true); //todo + } + + void initializeFields() { + updateAccountsTable(); + updateMetadataTable(); + updateAliasesTable(); + updateCasesTable(); + } + + void setMode(Component parent, PersonaDetailsMode mode, Persona persona) { + clear(); + this.mode = mode; + switch (mode) { + case CREATE: + enableEditUIComponents(); + break; + case EDIT: + loadPersona(parent, persona); + enableEditUIComponents(); + break; + case VIEW: + loadPersona(parent, persona); + break; + default: + logger.log(Level.WARNING, "Unsupported mode: {0}", mode); + break; + } + initializeFields(); + } + + @Messages({ + "PersonaDetailsPanel_NotEnoughAccounts_msg=Two or more accounts are necessary to create a persona", + "PersonaDetailsPanel_NotEnoughAccounts_Title=Not enough accounts", + "PersonaDetailsPanel_CentralRepoErr_msg=Failure to write to Central Repository", + "PersonaDetailsPanel_CentralRepoErr_Title=Central Repository failure", + "PersonaDetailsPanel_EmptyName_msg=Persona name cannot be empty", + "PersonaDetailsPanel_EmptyName_Title=Empty persona name",}) + Persona okHandler() { + Persona ret = null; + switch (mode) { + case CREATE: + if (accountsToAdd.size() < 2) { + JOptionPane.showMessageDialog(this, + Bundle.PersonaDetailsPanel_NotEnoughAccounts_msg(), + Bundle.PersonaDetailsPanel_NotEnoughAccounts_Title(), + JOptionPane.ERROR_MESSAGE); + break; + } + if (nameField.getText().isEmpty()) { + JOptionPane.showMessageDialog(this, + Bundle.PersonaDetailsPanel_EmptyName_msg(), + Bundle.PersonaDetailsPanel_EmptyName_Title(), + JOptionPane.ERROR_MESSAGE); + break; + } + try { + PAccount firstAccount = accountsToAdd.get(0); + ret = Persona.createPersonaForAccount(nameField.getText(), + "", Persona.PersonaStatus.ACTIVE, firstAccount.account, + firstAccount.justification, firstAccount.confidence); + for (int i = 1; i < accountsToAdd.size(); i++) { + ret.addAccountToPersona(accountsToAdd.get(i).account, + accountsToAdd.get(i).justification, + accountsToAdd.get(i).confidence); + } + for (PMetadata md : metadataToAdd) { + ret.addMetadata(md.name, md.value, md.justification, md.confidence); + } + for (PAlias pa : aliasesToAdd) { + ret.addAlias(pa.alias, pa.justification, pa.confidence); + } + } catch (CentralRepoException e) { + logger.log(Level.SEVERE, "Failed to access central repository", e); + JOptionPane.showMessageDialog(this, + Bundle.PersonaDetailsPanel_CentralRepoErr_msg(), + Bundle.PersonaDetailsPanel_CentralRepoErr_Title(), + JOptionPane.ERROR_MESSAGE); + break; + } + break; + case EDIT: + // todo implement + break; + default: + logger.log(Level.SEVERE, "Unsupported mode: {0}", mode); + } + return ret; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/persona/PersonaManagerTopComponent.form b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/PersonaManagerTopComponent.form new file mode 100644 index 0000000000..b2bea7dc26 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/PersonaManagerTopComponent.form @@ -0,0 +1,226 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonaManagerTopComponent.resultsTable.columnModel.title0" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> + + + + + + + <ResourceString bundle="org/sleuthkit/autopsy/centralrepository/persona/Bundle.properties" key="PersonaManagerTopComponent.resultsTable.columnModel.title1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/persona/PersonaManagerTopComponent.java b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/PersonaManagerTopComponent.java new file mode 100644 index 0000000000..d076acbce4 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/persona/PersonaManagerTopComponent.java @@ -0,0 +1,347 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.centralrepository.persona; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.logging.Level; +import javax.swing.JOptionPane; +import javax.swing.JTable; +import javax.swing.ListSelectionModel; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.table.DefaultTableModel; +import org.openide.util.NbBundle.Messages; +import org.openide.windows.RetainLocation; +import org.openide.windows.TopComponent; +import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; +import org.sleuthkit.autopsy.centralrepository.datamodel.Persona; +import org.sleuthkit.autopsy.coreutils.Logger; + +/** + * Top component for the Personas tool + * + */ +@TopComponent.Description(preferredID = "PersonaManagerTopComponent", persistenceType = TopComponent.PERSISTENCE_NEVER) +@TopComponent.Registration(mode = "personamanager", openAtStartup = false) +@RetainLocation("personamanager") +@SuppressWarnings("PMD.SingularField") +public final class PersonaManagerTopComponent extends TopComponent { + + private static final Logger logger = Logger.getLogger(PersonaManagerTopComponent.class.getName()); + + private List currentResults = null; + private Persona selectedPersona = null; + + @Messages({ + "PMTopComponent_Name=Persona Manager" + }) + public PersonaManagerTopComponent() { + initComponents(); + setName(Bundle.PMTopComponent_Name()); + executeSearch(); + + searchBtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + executeSearch(); + } + }); + + editBtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + new PersonaDetailsDialog(PersonaManagerTopComponent.this, + PersonaDetailsMode.EDIT, selectedPersona, new EditCallbackImpl()); + } + }); + + createBtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + new PersonaDetailsDialog(PersonaManagerTopComponent.this, + PersonaDetailsMode.CREATE, selectedPersona, new CreateCallbackImpl()); + } + }); + + // Results table + resultsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + resultsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + handleSelectionChange(e); + } + }); + } + + /** + * Callback method for the create mode of the PersonaDetailsDialog + */ + class CreateCallbackImpl implements PersonaDetailsDialogCallback { + @Override + public void callback(Persona persona) { + if (persona != null) { + searchField.setText(""); + executeSearch(); + int newPersonaRow = currentResults.size() - 1; + resultsTable.getSelectionModel().setSelectionInterval(newPersonaRow, newPersonaRow); + handleSelectionChange(); + } + createBtn.setEnabled(true); + } + } + + /** + * Callback method for the edit mode of the PersonaDetailsDialog + */ + class EditCallbackImpl implements PersonaDetailsDialogCallback { + @Override + public void callback(Persona persona) { + createBtn.setEnabled(true); + } + } + + void setPersona(int index) { + Persona persona = currentResults.get(index); + selectedPersona = persona; + //editBtn.setEnabled(true); todo uncomment when we add edit support + } + + /** + * Table model for the persona search results + */ + final class PersonaFilterTableModel extends DefaultTableModel { + + private static final long serialVersionUID = 1L; + + PersonaFilterTableModel(Object[][] rows, String[] colNames) { + super(rows, colNames); + } + + @Override + public boolean isCellEditable(int row, int column) { + return false; + } + } + + private void handleSelectionChange(ListSelectionEvent e) { + if (e.getValueIsAdjusting()) { + return; + } + handleSelectionChange(); + } + + private void handleSelectionChange() { + int selectedRow = resultsTable.getSelectedRow(); + if (selectedRow != -1) { + setPersona(resultsTable.getSelectedRow()); + detailsPanel.setMode(this, PersonaDetailsMode.VIEW, selectedPersona); + } + } + + private void updateResultsTable(Collection results) { + Object[][] rows = new Object[results.size()][2]; + int i = 0; + for (Persona result : results) { + rows[i] = new Object[]{result.getId(), result.getName()}; + i++; + } + PersonaFilterTableModel updatedTableModel = new PersonaFilterTableModel( + rows, + new String[]{"ID", "Name"} + ); + + resultsTable.setModel(updatedTableModel); + currentResults = new ArrayList<>(results); + + // Formatting + resultsTable.getColumnModel().getColumn(0).setMaxWidth(100); + resultsTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); + } + + @Messages({ + "PMTopComponent_search_exception_Title=Search failure", + "PMTopComponent_search_exception_msg=Failed to search personas",}) + private void executeSearch() { + Collection results; + try { + results = Persona.getPersonaByName(searchField.getText()); + } catch (CentralRepoException ex) { + logger.log(Level.SEVERE, "Failed to search personas", ex); + JOptionPane.showMessageDialog(this, + Bundle.PMTopComponent_search_exception_Title(), + Bundle.PMTopComponent_search_exception_msg(), + JOptionPane.ERROR_MESSAGE); + return; + } + + resultsTable.clearSelection(); + updateResultsTable(results); + editBtn.setEnabled(false); + } + + @Override + public void componentOpened() { + super.componentOpened(); + WindowManager.getDefault().setTopComponentFloating(this, true); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + // //GEN-BEGIN:initComponents + private void initComponents() { + + searchButtonGroup = new javax.swing.ButtonGroup(); + jSplitPane1 = new javax.swing.JSplitPane(); + searchPanel = new javax.swing.JPanel(); + searchField = new javax.swing.JTextField(); + searchNameRadio = new javax.swing.JRadioButton(); + searchAccountRadio = new javax.swing.JRadioButton(); + resultsPane = new javax.swing.JScrollPane(); + resultsTable = new javax.swing.JTable(); + searchBtn = new javax.swing.JButton(); + editBtn = new javax.swing.JButton(); + createBtn = new javax.swing.JButton(); + detailsPanel = new org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsPanel(); + + setMinimumSize(new java.awt.Dimension(400, 400)); + + searchField.setText(org.openide.util.NbBundle.getMessage(PersonaManagerTopComponent.class, "PersonaManagerTopComponent.searchField.text")); // NOI18N + + searchButtonGroup.add(searchNameRadio); + searchNameRadio.setSelected(true); + org.openide.awt.Mnemonics.setLocalizedText(searchNameRadio, org.openide.util.NbBundle.getMessage(PersonaManagerTopComponent.class, "PersonaManagerTopComponent.searchNameRadio.text")); // NOI18N + searchNameRadio.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + searchNameRadioActionPerformed(evt); + } + }); + + searchButtonGroup.add(searchAccountRadio); + org.openide.awt.Mnemonics.setLocalizedText(searchAccountRadio, org.openide.util.NbBundle.getMessage(PersonaManagerTopComponent.class, "PersonaManagerTopComponent.searchAccountRadio.text")); // NOI18N + searchAccountRadio.setEnabled(false); + + resultsTable.setToolTipText(org.openide.util.NbBundle.getMessage(PersonaManagerTopComponent.class, "PersonaManagerTopComponent.resultsTable.toolTipText")); // NOI18N + resultsTable.getTableHeader().setReorderingAllowed(false); + resultsPane.setViewportView(resultsTable); + if (resultsTable.getColumnModel().getColumnCount() > 0) { + resultsTable.getColumnModel().getColumn(0).setMaxWidth(25); + resultsTable.getColumnModel().getColumn(0).setHeaderValue(org.openide.util.NbBundle.getMessage(PersonaManagerTopComponent.class, "PersonaManagerTopComponent.resultsTable.columnModel.title0")); // NOI18N + resultsTable.getColumnModel().getColumn(1).setHeaderValue(org.openide.util.NbBundle.getMessage(PersonaManagerTopComponent.class, "PersonaManagerTopComponent.resultsTable.columnModel.title1")); // NOI18N + } + + org.openide.awt.Mnemonics.setLocalizedText(searchBtn, org.openide.util.NbBundle.getMessage(PersonaManagerTopComponent.class, "PersonaManagerTopComponent.searchBtn.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(editBtn, org.openide.util.NbBundle.getMessage(PersonaManagerTopComponent.class, "PersonaManagerTopComponent.editBtn.text")); // NOI18N + editBtn.setEnabled(false); + + org.openide.awt.Mnemonics.setLocalizedText(createBtn, org.openide.util.NbBundle.getMessage(PersonaManagerTopComponent.class, "PersonaManagerTopComponent.createBtn.text")); // NOI18N + createBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + createBtnActionPerformed(evt); + } + }); + + javax.swing.GroupLayout searchPanelLayout = new javax.swing.GroupLayout(searchPanel); + searchPanel.setLayout(searchPanelLayout); + searchPanelLayout.setHorizontalGroup( + searchPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(searchPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(searchPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(searchPanelLayout.createSequentialGroup() + .addComponent(createBtn) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(editBtn) + .addGap(0, 0, Short.MAX_VALUE)) + .addComponent(resultsPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addComponent(searchField) + .addGroup(searchPanelLayout.createSequentialGroup() + .addComponent(searchNameRadio) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(searchAccountRadio) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(searchBtn))) + .addContainerGap()) + ); + searchPanelLayout.setVerticalGroup( + searchPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(searchPanelLayout.createSequentialGroup() + .addContainerGap() + .addComponent(searchField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(searchPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(searchNameRadio) + .addComponent(searchAccountRadio) + .addComponent(searchBtn)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(resultsPane, javax.swing.GroupLayout.DEFAULT_SIZE, 528, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(searchPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(editBtn) + .addComponent(createBtn)) + .addContainerGap()) + ); + + jSplitPane1.setLeftComponent(searchPanel); + jSplitPane1.setRightComponent(detailsPanel); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 692, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 650, Short.MAX_VALUE) + ); + }// //GEN-END:initComponents + + private void searchNameRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchNameRadioActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_searchNameRadioActionPerformed + + private void createBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_createBtnActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_createBtnActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton createBtn; + private org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsPanel detailsPanel; + private javax.swing.JButton editBtn; + private javax.swing.JSplitPane jSplitPane1; + private javax.swing.JScrollPane resultsPane; + private javax.swing.JTable resultsTable; + private javax.swing.JRadioButton searchAccountRadio; + private javax.swing.JButton searchBtn; + private javax.swing.ButtonGroup searchButtonGroup; + private javax.swing.JTextField searchField; + private javax.swing.JRadioButton searchNameRadio; + private javax.swing.JPanel searchPanel; + // End of variables declaration//GEN-END:variables + +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties index fd1be9e4a5..97348e7b56 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties @@ -968,16 +968,11 @@ CallLogArtifactViewer.deviceIdLabel.text=device id CallLogArtifactViewer.localAccountIdLabel.text=local account CallLogArtifactViewer.localAccountLabel.text=Local Account CallLogArtifactViewer.jLabel4.text=Data Source Name -CallLogArtifactViewer.otherRecipientsLabel.text=Other Recipients CallLogArtifactViewer.otherInfoLabel.text=Other Information CallLogArtifactViewer.sourceSectionLabel.text=Source CallLogArtifactViewer.callDetailsLabel.text=Call Details CallLogArtifactViewer.durationLabel.text=Duration.... CallLogArtifactViewer.dateTimeLabel.text=Date/Time..... CallLogArtifactViewer.directionLabel.text=Direction -CallLogArtifactViewer.toOrFromNameLabel.text=Name, if available -CallLogArtifactViewer.personaButton1.text=Persona -CallLogArtifactViewer.toOrFromNumberLabel.text=Number/Id -CallLogArtifactViewer.numberDesignatorLabel.text=To/From CallLogArtifactViewer.onLabel.text=On CallLogArtifactViewer.callLabel.text=call diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.form index 5e3659a137..9f4b429a6c 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.form @@ -11,17 +11,28 @@ - - + + + + + + + + + + + + + + + + + + - - - - - @@ -47,92 +58,50 @@ - - - - - - - - + + + - - - - - - - - + + - + - - - - - - - - - - + + + + - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - - @@ -171,13 +140,6 @@ - - - - - - - @@ -192,68 +154,21 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - - - - - - - - - - - - @@ -323,18 +238,13 @@ - - - - - - + diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java index 4d1a335ad5..b558b72f8a 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/CallLogArtifactViewer.java @@ -42,6 +42,7 @@ import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; import org.openide.util.NbBundle; /** @@ -86,19 +87,13 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac topPanel = new javax.swing.JPanel(); callDetailsPanel = new javax.swing.JPanel(); - toOrFromNumberLabel = new javax.swing.JLabel(); - personaButton1 = new javax.swing.JButton(); - toOrFromNameLabel = new javax.swing.JLabel(); directionLabel = new javax.swing.JLabel(); dateTimeLabel = new javax.swing.JLabel(); durationLabel = new javax.swing.JLabel(); callDetailsLabel = new javax.swing.JLabel(); - numberDesignatorLabel = new javax.swing.JLabel(); onLabel = new javax.swing.JLabel(); callLabel = new javax.swing.JLabel(); - otherRecipientsPanel = new javax.swing.JPanel(); - otherRecipientsListPanel = new javax.swing.JPanel(); - otherRecipientsLabel = new javax.swing.JLabel(); + participantsListPanel = new javax.swing.JPanel(); otherAttributesPanel = new javax.swing.JPanel(); otherInfoLabel = new javax.swing.JLabel(); otherAttributesListPanel = new javax.swing.JPanel(); @@ -112,24 +107,10 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac localAccountIdLabel = new javax.swing.JLabel(); sourceSectionLabel = new javax.swing.JLabel(); - setLayout(new java.awt.BorderLayout()); - topPanel.setLayout(new java.awt.BorderLayout()); callDetailsPanel.setPreferredSize(new java.awt.Dimension(400, 150)); - org.openide.awt.Mnemonics.setLocalizedText(toOrFromNumberLabel, org.openide.util.NbBundle.getMessage(CallLogArtifactViewer.class, "CallLogArtifactViewer.toOrFromNumberLabel.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(personaButton1, org.openide.util.NbBundle.getMessage(CallLogArtifactViewer.class, "CallLogArtifactViewer.personaButton1.text")); // NOI18N - personaButton1.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - personaButton1ActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(toOrFromNameLabel, org.openide.util.NbBundle.getMessage(CallLogArtifactViewer.class, "CallLogArtifactViewer.toOrFromNameLabel.text")); // NOI18N - toOrFromNameLabel.setEnabled(false); - directionLabel.setFont(directionLabel.getFont()); org.openide.awt.Mnemonics.setLocalizedText(directionLabel, org.openide.util.NbBundle.getMessage(CallLogArtifactViewer.class, "CallLogArtifactViewer.directionLabel.text")); // NOI18N @@ -140,12 +121,21 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac callDetailsLabel.setFont(callDetailsLabel.getFont().deriveFont(callDetailsLabel.getFont().getStyle() | java.awt.Font.BOLD)); org.openide.awt.Mnemonics.setLocalizedText(callDetailsLabel, org.openide.util.NbBundle.getMessage(CallLogArtifactViewer.class, "CallLogArtifactViewer.callDetailsLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(numberDesignatorLabel, org.openide.util.NbBundle.getMessage(CallLogArtifactViewer.class, "CallLogArtifactViewer.numberDesignatorLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(onLabel, org.openide.util.NbBundle.getMessage(CallLogArtifactViewer.class, "CallLogArtifactViewer.onLabel.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(callLabel, org.openide.util.NbBundle.getMessage(CallLogArtifactViewer.class, "CallLogArtifactViewer.callLabel.text")); // NOI18N + javax.swing.GroupLayout participantsListPanelLayout = new javax.swing.GroupLayout(participantsListPanel); + participantsListPanel.setLayout(participantsListPanelLayout); + participantsListPanelLayout.setHorizontalGroup( + participantsListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 350, Short.MAX_VALUE) + ); + participantsListPanelLayout.setVerticalGroup( + participantsListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 58, Short.MAX_VALUE) + ); + javax.swing.GroupLayout callDetailsPanelLayout = new javax.swing.GroupLayout(callDetailsPanel); callDetailsPanel.setLayout(callDetailsPanelLayout); callDetailsPanelLayout.setHorizontalGroup( @@ -157,90 +147,40 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac .addGroup(callDetailsPanelLayout.createSequentialGroup() .addGap(25, 25, 25) .addGroup(callDetailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(callDetailsPanelLayout.createSequentialGroup() - .addComponent(onLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(dateTimeLabel) - .addGap(18, 18, 18) - .addComponent(durationLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(callDetailsPanelLayout.createSequentialGroup() .addComponent(directionLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(callLabel)) .addGroup(callDetailsPanelLayout.createSequentialGroup() - .addComponent(numberDesignatorLabel) + .addComponent(onLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(dateTimeLabel) .addGap(18, 18, 18) - .addGroup(callDetailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(toOrFromNameLabel) - .addGroup(callDetailsPanelLayout.createSequentialGroup() - .addComponent(toOrFromNumberLabel) - .addGap(92, 92, 92) - .addComponent(personaButton1))))))) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(durationLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE)))) + .addComponent(participantsListPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(485, Short.MAX_VALUE)) ); callDetailsPanelLayout.setVerticalGroup( callDetailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(callDetailsPanelLayout.createSequentialGroup() - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap() .addComponent(callDetailsLabel) - .addGap(10, 10, 10) - .addGroup(callDetailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(toOrFromNumberLabel) - .addComponent(numberDesignatorLabel) - .addComponent(personaButton1)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(toOrFromNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) + .addComponent(participantsListPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(callDetailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(directionLabel) .addComponent(callLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(callDetailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(durationLabel) + .addComponent(onLabel) .addComponent(dateTimeLabel) - .addComponent(onLabel)) - .addGap(33, 33, 33)) + .addComponent(durationLabel)) + .addGap(20, 20, 20)) ); topPanel.add(callDetailsPanel, java.awt.BorderLayout.PAGE_START); - javax.swing.GroupLayout otherRecipientsListPanelLayout = new javax.swing.GroupLayout(otherRecipientsListPanel); - otherRecipientsListPanel.setLayout(otherRecipientsListPanelLayout); - otherRecipientsListPanelLayout.setHorizontalGroup( - otherRecipientsListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 406, Short.MAX_VALUE) - ); - otherRecipientsListPanelLayout.setVerticalGroup( - otherRecipientsListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 134, Short.MAX_VALUE) - ); - - otherRecipientsLabel.setFont(otherRecipientsLabel.getFont().deriveFont(otherRecipientsLabel.getFont().getStyle() | java.awt.Font.BOLD)); - org.openide.awt.Mnemonics.setLocalizedText(otherRecipientsLabel, org.openide.util.NbBundle.getMessage(CallLogArtifactViewer.class, "CallLogArtifactViewer.otherRecipientsLabel.text")); // NOI18N - - javax.swing.GroupLayout otherRecipientsPanelLayout = new javax.swing.GroupLayout(otherRecipientsPanel); - otherRecipientsPanel.setLayout(otherRecipientsPanelLayout); - otherRecipientsPanelLayout.setHorizontalGroup( - otherRecipientsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(otherRecipientsPanelLayout.createSequentialGroup() - .addGap(25, 25, 25) - .addGroup(otherRecipientsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(otherRecipientsListPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(otherRecipientsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 398, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - otherRecipientsPanelLayout.setVerticalGroup( - otherRecipientsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(otherRecipientsPanelLayout.createSequentialGroup() - .addContainerGap(15, Short.MAX_VALUE) - .addComponent(otherRecipientsLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(otherRecipientsListPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) - ); - - topPanel.add(otherRecipientsPanel, java.awt.BorderLayout.CENTER); - otherInfoLabel.setFont(otherInfoLabel.getFont().deriveFont(otherInfoLabel.getFont().getStyle() | java.awt.Font.BOLD)); org.openide.awt.Mnemonics.setLocalizedText(otherInfoLabel, org.openide.util.NbBundle.getMessage(CallLogArtifactViewer.class, "CallLogArtifactViewer.otherInfoLabel.text")); // NOI18N @@ -279,8 +219,6 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac topPanel.add(otherAttributesPanel, java.awt.BorderLayout.PAGE_END); - add(topPanel, java.awt.BorderLayout.PAGE_START); - bottomPanel.setLayout(new java.awt.BorderLayout()); org.openide.awt.Mnemonics.setLocalizedText(jLabel4, org.openide.util.NbBundle.getMessage(CallLogArtifactViewer.class, "CallLogArtifactViewer.jLabel4.text")); // NOI18N @@ -340,18 +278,28 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac .addContainerGap(22, Short.MAX_VALUE)) ); - bottomPanel.add(localAccountInfoPanel, java.awt.BorderLayout.PAGE_END); + bottomPanel.add(localAccountInfoPanel, java.awt.BorderLayout.NORTH); - add(bottomPanel, java.awt.BorderLayout.PAGE_END); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(topPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 860, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(bottomPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(topPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(bottomPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 297, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); }// //GEN-END:initComponents - private void personaButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_personaButton1ActionPerformed - // TODO add your handling code here: - }//GEN-LAST:event_personaButton1ActionPerformed - private void customizeComponents() { // disable the name label for now. - this.toOrFromNameLabel.setVisible(false); + // this.toOrFromNameLabel.setVisible(false); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JPanel bottomPanel; @@ -368,18 +316,12 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac private javax.swing.JLabel localAccountIdLabel; private javax.swing.JPanel localAccountInfoPanel; private javax.swing.JLabel localAccountLabel; - private javax.swing.JLabel numberDesignatorLabel; private javax.swing.JLabel onLabel; private javax.swing.JPanel otherAttributesListPanel; private javax.swing.JPanel otherAttributesPanel; private javax.swing.JLabel otherInfoLabel; - private javax.swing.JLabel otherRecipientsLabel; - private javax.swing.JPanel otherRecipientsListPanel; - private javax.swing.JPanel otherRecipientsPanel; - private javax.swing.JButton personaButton1; + private javax.swing.JPanel participantsListPanel; private javax.swing.JLabel sourceSectionLabel; - private javax.swing.JLabel toOrFromNameLabel; - private javax.swing.JLabel toOrFromNumberLabel; private javax.swing.JPanel topPanel; // End of variables declaration//GEN-END:variables @@ -412,17 +354,10 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac * @param callLogViewData Call log data to display. */ private void updateView(CallLogViewData callLogViewData) { - if (callLogViewData.getNumberDesignator() != null ) { - this.numberDesignatorLabel.setText(callLogViewData.getNumberDesignator()); - } else { - this.numberDesignatorLabel.setVisible(false); - } - - this.toOrFromNumberLabel.setText(callLogViewData.getNumber()); - - // TBD: Vik-6383 find and display the persona for this account, and a button - this.personaButton1.setVisible(false); - + + // populate call partcipants list. + updateParticipantsPanel(callLogViewData); + if (callLogViewData.getDirection() != null) { this.directionLabel.setText(callLogViewData.getDirection()); } else { @@ -442,9 +377,6 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac this.durationLabel.setVisible(false); } - // Populate other recipients - updateOtherRecipientsPanel(callLogViewData.getOtherRecipients()); - // Populate other attributs panel updateOtherAttributesPanel(callLogViewData.getOtherAttributes()); @@ -463,69 +395,88 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac this.deviceIdLabel.setText(callLogViewData.getDataSourceDeviceId()); } } - /** - * Updates the other recipients panel. - * - * @param otherRecipients List of other recipients, may be null or empty. - */ - private void updateOtherRecipientsPanel(Collection otherRecipients) { + - if (otherRecipients == null || otherRecipients.isEmpty()) { - otherRecipientsPanel.setVisible(false); - return; - } + /** + * Updates the Call participants panel. + * + * @param callLogViewData Call log data to display. + */ + private void updateParticipantsPanel(CallLogViewData callLogViewData) { // create a gridbag layout to show each participant on one line GridBagLayout gridBagLayout = new GridBagLayout(); GridBagConstraints constraints = new GridBagConstraints(); constraints.anchor = GridBagConstraints.FIRST_LINE_START; constraints.gridy = 0; - constraints.insets = new java.awt.Insets(4, 12, 0, 0); - for (String recipient : otherRecipients) { - constraints.fill = GridBagConstraints.NONE; - constraints.weightx = 0; - constraints.gridx = 0; + constraints.insets = new java.awt.Insets(4, 0, 0, 0); + + // show primary sender/receiver + showParticipant(callLogViewData.getNumberDesignator(), callLogViewData.getNumber(), gridBagLayout, constraints ); + constraints.gridy++; + + for (String recipient : callLogViewData.getOtherRecipients()) { + showParticipant(Bundle.CallLogArtifactViewer_number_to(), recipient, gridBagLayout, constraints ); + constraints.gridy++; + } + participantsListPanel.setLayout(gridBagLayout); + participantsListPanel.revalidate(); + } + + /** + * Display a call participant in the view. + * + * @param participantDesignator Label to show - To/From. + * @param accountIdentifier account identifier for the participant. + * @param gridBagLayout + * @param constraints + */ + private void showParticipant(String participantDesignator, String accountIdentifier, GridBagLayout gridBagLayout, GridBagConstraints constraints) { - javax.swing.Box.Filler filler1 = new javax.swing.Box.Filler(new Dimension(25, 0), new Dimension(25, 0), new Dimension(25, 0)); - otherRecipientsListPanel.add(filler1, constraints); + constraints.fill = GridBagConstraints.NONE; + constraints.weightx = 0; + constraints.gridx = 0; - constraints.gridx++; - javax.swing.JLabel toLabel = new javax.swing.JLabel(); - toLabel.setText("To"); + javax.swing.Box.Filler filler1 = new javax.swing.Box.Filler(new Dimension(25, 0), new Dimension(25, 0), new Dimension(25, 0)); + participantsListPanel.add(filler1, constraints); - gridBagLayout.setConstraints(toLabel, constraints); - otherRecipientsListPanel.add(toLabel); - - constraints.gridx++; - - // Add recipients number/Id - javax.swing.JLabel participantNumberLabel = new javax.swing.JLabel(); - participantNumberLabel.setText(recipient); + constraints.gridx++; + javax.swing.JLabel toLabel = new javax.swing.JLabel(); + toLabel.setText(participantDesignator); - gridBagLayout.setConstraints(participantNumberLabel, constraints); - otherRecipientsListPanel.add(participantNumberLabel); + gridBagLayout.setConstraints(toLabel, constraints); + participantsListPanel.add(toLabel); - // TBD Vik-6383 find and display the persona for this account, and a button + constraints.gridx++; + + javax.swing.Box.Filler filler2 = new javax.swing.Box.Filler(new Dimension(5, 0), new Dimension(5, 0), new Dimension(5, 0)); + participantsListPanel.add(filler2, constraints); + + // Add attribute name label + constraints.gridx++; + + // Add recipients number/Id + javax.swing.JLabel participantAccountLabel = new javax.swing.JLabel(); + participantAccountLabel.setText(accountIdentifier); + + gridBagLayout.setConstraints(participantAccountLabel, constraints); + participantsListPanel.add(participantAccountLabel); + + // TBD Vik-6383 find and display the persona for this account, and a button // constraints.gridx += 2; // javax.swing.JButton personaButton = new javax.swing.JButton(); // personaButton.setText("Persona"); // gridBagLayout.setConstraints(personaButton, constraints); // otherParticipantsListPanel.add(personaButton); - // add a filler to take up rest of the space - constraints.gridx++; - constraints.weightx = 1.0; - constraints.fill = GridBagConstraints.HORIZONTAL; - otherRecipientsListPanel.add(new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0))); - constraints.gridy++; - } - otherRecipientsListPanel.setLayout(gridBagLayout); - - otherRecipientsPanel.revalidate(); + // add a filler to take up rest of the space + constraints.gridx++; + constraints.weightx = 1.0; + constraints.fill = GridBagConstraints.HORIZONTAL; + participantsListPanel.add(new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0))); } - /** * Updates the Other Attributes panel with the given list of attributes. * This panel displays any uncommon attributes that might not be shown already. @@ -647,7 +598,7 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac String[] numbers = numberAttr.getValueString().split(","); // create a CallLogViewData with the primary number/id. - callLogViewData = new CallLogViewData(numbers[0]); + callLogViewData = new CallLogViewData(StringUtils.trim(numbers[0])); // set direction callLogViewData.setDirection(direction); @@ -707,7 +658,7 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac if (numbers.length > 1) { otherNumbers = new ArrayList<>(); for (int i = startIdx; i < numbers.length; i++) { - otherNumbers.add(numbers[i]); + otherNumbers.add(StringUtils.trim(numbers[i])); } } @@ -763,7 +714,7 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac BlackboardAttribute endTimeAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_END)); if (endTimeAttr != null) { long endTime = endTimeAttr.getValueLong(); - if (endTime > 0) { + if (endTime > 0 && (endTime - startTime) > 0) { callLogViewData.setDuration(String.format("%d seconds", (endTime - startTime))); } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index aa47872c82..659ee84870 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -39,6 +39,7 @@ import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.autopsy.tags.TagUtils; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; @@ -284,9 +285,9 @@ public class Tags implements AutopsyVisitableItem { public TagNameNode(TagName tagName) { super(Children.create(new TagTypeNodeFactory(tagName), true), Lookups.singleton(NbBundle.getMessage(TagNameNode.class, "TagNameNode.namePlusTags.text", tagName.getDisplayName()))); this.tagName = tagName; - setName(tagName.getDisplayName()); + setName(TagUtils.getDecoratedTagDisplayName(tagName)); updateDisplayName(); - if (tagName.getDisplayName().equals(NbBundle.getMessage(this.getClass(), "TagNameNode.bookmark.text"))) { + if (tagName.getDisplayName().equals(TagsManager.getBookmarkTagDisplayName())) { setIconBaseWithExtension(BOOKMARK_TAG_ICON_PATH); } else { setIconBaseWithExtension(ICON_PATH); @@ -319,7 +320,7 @@ public class Tags implements AutopsyVisitableItem { } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(TagNameNode.class.getName()).log(Level.SEVERE, "Failed to get tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS } - setDisplayName(tagName.getDisplayName() + " \u200E(\u200E" + tagsCount + ")\u200E"); + setDisplayName(TagUtils.getDecoratedTagDisplayName(tagName) + " \u200E(\u200E" + tagsCount + ")\u200E"); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/persona/Bundle.properties b/Core/src/org/sleuthkit/autopsy/persona/Bundle.properties deleted file mode 100644 index 508c0d1370..0000000000 --- a/Core/src/org/sleuthkit/autopsy/persona/Bundle.properties +++ /dev/null @@ -1,15 +0,0 @@ -CTL_OpenPersonas=Personas -CTL_PersonasTopComponentAction=PersonasTopComponent -CTL_PersonasTopComponent=Personas -PersonaDetailsTopComponent.resultNameLbl.text=Name: -PersonaDetailsTopComponent.resultCasesLbl.text=Cases found in: -PersonaDetailsTopComponent.resultAccountsLbl.text=Accounts: -PersonaDetailsTopComponent.resultAliasesLbl.text=Aliases: -PersonaDetailsTopComponent.resultNameField.text=Johnathan Dough -PersonaSearchTopComponent.searchAccountRadio.text=Account -PersonaSearchTopComponent.searchNameRadio.text=Name -PersonaSearchTopComponent.searchField.text= -PersonaSearchTopComponent.searchBtn.text=Search -PersonaSearchTopComponent.filterResultsTable.columnModel.title1=Name -PersonaSearchTopComponent.filterResultsTable.columnModel.title0=ID -PersonaSearchTopComponent.filterResultsTable.toolTipText= diff --git a/Core/src/org/sleuthkit/autopsy/persona/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/persona/Bundle.properties-MERGED deleted file mode 100644 index 1e9b1769d2..0000000000 --- a/Core/src/org/sleuthkit/autopsy/persona/Bundle.properties-MERGED +++ /dev/null @@ -1,5 +0,0 @@ -CTL_OpenPersonas=Personas -CTL_PersonasTopComponentAction=PersonasTopComponent -CTL_PersonasTopComponent=Personas -OpenPersonasAction.displayName=Personas -PTopComponent_Name=Personas diff --git a/Core/src/org/sleuthkit/autopsy/persona/PersonaDetailsTopComponent.form b/Core/src/org/sleuthkit/autopsy/persona/PersonaDetailsTopComponent.form deleted file mode 100644 index fbfd7ded76..0000000000 --- a/Core/src/org/sleuthkit/autopsy/persona/PersonaDetailsTopComponent.form +++ /dev/null @@ -1,230 +0,0 @@ - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - -
-
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- diff --git a/Core/src/org/sleuthkit/autopsy/persona/PersonaDetailsTopComponent.java b/Core/src/org/sleuthkit/autopsy/persona/PersonaDetailsTopComponent.java deleted file mode 100644 index fdc0af6e0d..0000000000 --- a/Core/src/org/sleuthkit/autopsy/persona/PersonaDetailsTopComponent.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2020 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.persona; - -import org.openide.windows.TopComponent; -import org.openide.util.NbBundle.Messages; -import org.openide.windows.RetainLocation; -import org.openide.windows.WindowManager; - -/** - * Top component for persona details - */ -@TopComponent.Description(preferredID = "PersonasTopComponent", persistenceType = TopComponent.PERSISTENCE_NEVER) -@TopComponent.Registration(mode = "personadetails", openAtStartup = false) -@RetainLocation("personadetails") -@SuppressWarnings("PMD.SingularField") -public final class PersonaDetailsTopComponent extends TopComponent { - - @Messages({ - "PDTopComponent_Name=Persona Details" - }) - public PersonaDetailsTopComponent() { - initComponents(); - setName(Bundle.PDTopComponent_Name()); - } - - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - // //GEN-BEGIN:initComponents - private void initComponents() { - - detailsPanel = new javax.swing.JPanel(); - resultNameLbl = new javax.swing.JLabel(); - resultNameField = new javax.swing.JTextField(); - resultAliasesLbl = new javax.swing.JLabel(); - resultAccountsLbl = new javax.swing.JLabel(); - accountsTablePane = new javax.swing.JScrollPane(); - accountsTable = new javax.swing.JTable(); - resultCasesLbl = new javax.swing.JLabel(); - casesListPane = new javax.swing.JScrollPane(); - casesList = new javax.swing.JList<>(); - aliasesListPane = new javax.swing.JScrollPane(); - aliasesList = new javax.swing.JList<>(); - - org.openide.awt.Mnemonics.setLocalizedText(resultNameLbl, org.openide.util.NbBundle.getMessage(PersonaDetailsTopComponent.class, "PersonaDetailsTopComponent.resultNameLbl.text")); // NOI18N - - resultNameField.setEditable(false); - resultNameField.setText(org.openide.util.NbBundle.getMessage(PersonaDetailsTopComponent.class, "PersonaDetailsTopComponent.resultNameField.text")); // NOI18N - resultNameField.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - resultNameFieldActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(resultAliasesLbl, org.openide.util.NbBundle.getMessage(PersonaDetailsTopComponent.class, "PersonaDetailsTopComponent.resultAliasesLbl.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(resultAccountsLbl, org.openide.util.NbBundle.getMessage(PersonaDetailsTopComponent.class, "PersonaDetailsTopComponent.resultAccountsLbl.text")); // NOI18N - - accountsTable.setModel(new javax.swing.table.DefaultTableModel( - new Object [][] { - {"Email", "jdb@yahoo.com"}, - {"Phone", "865-555-5555"}, - {"Twitter", "@jd93.bread"}, - {null, null} - }, - new String [] { - "Type", "Data" - } - ) { - Class[] types = new Class [] { - java.lang.String.class, java.lang.String.class - }; - boolean[] canEdit = new boolean [] { - false, false - }; - - public Class getColumnClass(int columnIndex) { - return types [columnIndex]; - } - - public boolean isCellEditable(int rowIndex, int columnIndex) { - return canEdit [columnIndex]; - } - }); - accountsTablePane.setViewportView(accountsTable); - - org.openide.awt.Mnemonics.setLocalizedText(resultCasesLbl, org.openide.util.NbBundle.getMessage(PersonaDetailsTopComponent.class, "PersonaDetailsTopComponent.resultCasesLbl.text")); // NOI18N - - casesList.setModel(new javax.swing.AbstractListModel() { - String[] strings = { "Investigation 13", "Scene 5" }; - public int getSize() { return strings.length; } - public String getElementAt(int i) { return strings[i]; } - }); - casesListPane.setViewportView(casesList); - - aliasesList.setModel(new javax.swing.AbstractListModel() { - String[] strings = { "J.D.", "Fred Smidge", "Ethan Roseman" }; - public int getSize() { return strings.length; } - public String getElementAt(int i) { return strings[i]; } - }); - aliasesListPane.setViewportView(aliasesList); - - javax.swing.GroupLayout detailsPanelLayout = new javax.swing.GroupLayout(detailsPanel); - detailsPanel.setLayout(detailsPanelLayout); - detailsPanelLayout.setHorizontalGroup( - detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, detailsPanelLayout.createSequentialGroup() - .addContainerGap() - .addGroup(detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(accountsTablePane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) - .addComponent(aliasesListPane) - .addComponent(casesListPane) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, detailsPanelLayout.createSequentialGroup() - .addComponent(resultNameLbl) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(resultNameField, javax.swing.GroupLayout.DEFAULT_SIZE, 447, Short.MAX_VALUE)) - .addComponent(resultAliasesLbl, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(resultAccountsLbl, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(resultCasesLbl, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()) - ); - detailsPanelLayout.setVerticalGroup( - detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(detailsPanelLayout.createSequentialGroup() - .addContainerGap() - .addGroup(detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(resultNameLbl) - .addComponent(resultNameField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(18, 18, 18) - .addComponent(resultAliasesLbl) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(aliasesListPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(resultAccountsLbl) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(accountsTablePane, javax.swing.GroupLayout.PREFERRED_SIZE, 153, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(resultCasesLbl) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(casesListPane, javax.swing.GroupLayout.DEFAULT_SIZE, 118, Short.MAX_VALUE) - .addContainerGap()) - ); - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 505, Short.MAX_VALUE) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) - .addComponent(detailsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE))) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 555, Short.MAX_VALUE) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) - .addComponent(detailsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE))) - ); - }// //GEN-END:initComponents - - private void resultNameFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_resultNameFieldActionPerformed - - }//GEN-LAST:event_resultNameFieldActionPerformed - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JTable accountsTable; - private javax.swing.JScrollPane accountsTablePane; - private javax.swing.JList aliasesList; - private javax.swing.JScrollPane aliasesListPane; - private javax.swing.JList casesList; - private javax.swing.JScrollPane casesListPane; - private javax.swing.JPanel detailsPanel; - private javax.swing.JLabel resultAccountsLbl; - private javax.swing.JLabel resultAliasesLbl; - private javax.swing.JLabel resultCasesLbl; - private javax.swing.JTextField resultNameField; - private javax.swing.JLabel resultNameLbl; - // End of variables declaration//GEN-END:variables - - @Override - public void componentOpened() { - super.componentOpened(); - WindowManager.getDefault().setTopComponentFloating(this, true); - } -} diff --git a/Core/src/org/sleuthkit/autopsy/persona/PersonaSearchTopComponent.form b/Core/src/org/sleuthkit/autopsy/persona/PersonaSearchTopComponent.form deleted file mode 100644 index ec91c8bb53..0000000000 --- a/Core/src/org/sleuthkit/autopsy/persona/PersonaSearchTopComponent.form +++ /dev/null @@ -1,178 +0,0 @@ - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <ResourceString bundle="org/sleuthkit/autopsy/persona/Bundle.properties" key="PersonaSearchTopComponent.filterResultsTable.columnModel.title0" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> - - - - - - - <ResourceString bundle="org/sleuthkit/autopsy/persona/Bundle.properties" key="PersonaSearchTopComponent.filterResultsTable.columnModel.title1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/Core/src/org/sleuthkit/autopsy/persona/PersonaSearchTopComponent.java b/Core/src/org/sleuthkit/autopsy/persona/PersonaSearchTopComponent.java deleted file mode 100644 index 7cf22279db..0000000000 --- a/Core/src/org/sleuthkit/autopsy/persona/PersonaSearchTopComponent.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2020 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.persona; - -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.Collection; -import java.util.Collections; -import javax.swing.JTable; -import javax.swing.ListSelectionModel; -import javax.swing.table.DefaultTableModel; -import org.openide.util.Exceptions; -import org.openide.util.NbBundle.Messages; -import org.openide.windows.RetainLocation; -import org.openide.windows.TopComponent; -import org.openide.windows.WindowManager; -import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; -import org.sleuthkit.autopsy.centralrepository.datamodel.Persona; - -/** - * Top component for the Personas tool - * - */ -@TopComponent.Description(preferredID = "PersonasTopComponent", persistenceType = TopComponent.PERSISTENCE_NEVER) -@TopComponent.Registration(mode = "personasearch", openAtStartup = false) -@RetainLocation("personasearch") -@SuppressWarnings("PMD.SingularField") -public final class PersonaSearchTopComponent extends TopComponent { - - @Messages({ - "PSTopComponent_Name=Persona Search" - }) - public PersonaSearchTopComponent() { - initComponents(); - setName(Bundle.PSTopComponent_Name()); - executeSearch(); - - searchBtn.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - executeSearch(); - } - }); - } - - /** - * Table model for the persona search results - */ - final class PersonaFilterTableModel extends DefaultTableModel { - private static final long serialVersionUID = 1L; - - PersonaFilterTableModel(Object[][] rows, String[] colNames) { - super(rows, colNames); - } - - @Override - public boolean isCellEditable(int row, int column) { - return false; - } - } - - private void updateResultsTable(Collection results) { - Object[][] rows = new Object[results.size()][2]; - int i = 0; - for (Persona result : results) { - rows[i] = new String[]{String.valueOf(result.getId()), result.getName()}; - i++; - } - DefaultTableModel updatedTableModel = new PersonaFilterTableModel( - rows, - new String[]{"ID", "Name"} - ); - - filterResultsTable.setModel(updatedTableModel); - - // Formatting - filterResultsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - filterResultsTable.getColumnModel().getColumn(0).setMaxWidth(100); - filterResultsTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); - } - - private void executeSearch() { - Collection results = Collections.EMPTY_LIST; - try { - results = Persona.getPersonaByName(searchField.getText()); - } catch (CentralRepoException ex) { - Exceptions.printStackTrace(ex); - } - updateResultsTable(results); - } - - @Override - public void componentOpened() { - super.componentOpened(); - WindowManager.getDefault().setTopComponentFloating(this, true); - } - - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - // //GEN-BEGIN:initComponents - private void initComponents() { - - searchButtonGroup = new javax.swing.ButtonGroup(); - searchPanel = new javax.swing.JPanel(); - searchField = new javax.swing.JTextField(); - searchNameRadio = new javax.swing.JRadioButton(); - searchAccountRadio = new javax.swing.JRadioButton(); - filterResultsPane = new javax.swing.JScrollPane(); - filterResultsTable = new javax.swing.JTable(); - searchBtn = new javax.swing.JButton(); - - setMinimumSize(new java.awt.Dimension(400, 400)); - - searchField.setText(org.openide.util.NbBundle.getMessage(PersonaSearchTopComponent.class, "PersonaSearchTopComponent.searchField.text")); // NOI18N - - searchButtonGroup.add(searchNameRadio); - searchNameRadio.setSelected(true); - org.openide.awt.Mnemonics.setLocalizedText(searchNameRadio, org.openide.util.NbBundle.getMessage(PersonaSearchTopComponent.class, "PersonaSearchTopComponent.searchNameRadio.text")); // NOI18N - searchNameRadio.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - searchNameRadioActionPerformed(evt); - } - }); - - searchButtonGroup.add(searchAccountRadio); - org.openide.awt.Mnemonics.setLocalizedText(searchAccountRadio, org.openide.util.NbBundle.getMessage(PersonaSearchTopComponent.class, "PersonaSearchTopComponent.searchAccountRadio.text")); // NOI18N - - filterResultsTable.setToolTipText(org.openide.util.NbBundle.getMessage(PersonaSearchTopComponent.class, "PersonaSearchTopComponent.filterResultsTable.toolTipText")); // NOI18N - filterResultsTable.getTableHeader().setReorderingAllowed(false); - filterResultsPane.setViewportView(filterResultsTable); - if (filterResultsTable.getColumnModel().getColumnCount() > 0) { - filterResultsTable.getColumnModel().getColumn(0).setMaxWidth(25); - filterResultsTable.getColumnModel().getColumn(0).setHeaderValue(org.openide.util.NbBundle.getMessage(PersonaSearchTopComponent.class, "PersonaSearchTopComponent.filterResultsTable.columnModel.title0")); // NOI18N - filterResultsTable.getColumnModel().getColumn(1).setHeaderValue(org.openide.util.NbBundle.getMessage(PersonaSearchTopComponent.class, "PersonaSearchTopComponent.filterResultsTable.columnModel.title1")); // NOI18N - } - - org.openide.awt.Mnemonics.setLocalizedText(searchBtn, org.openide.util.NbBundle.getMessage(PersonaSearchTopComponent.class, "PersonaSearchTopComponent.searchBtn.text")); // NOI18N - - javax.swing.GroupLayout searchPanelLayout = new javax.swing.GroupLayout(searchPanel); - searchPanel.setLayout(searchPanelLayout); - searchPanelLayout.setHorizontalGroup( - searchPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(searchPanelLayout.createSequentialGroup() - .addContainerGap() - .addGroup(searchPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(filterResultsPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) - .addComponent(searchField) - .addGroup(searchPanelLayout.createSequentialGroup() - .addComponent(searchNameRadio) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(searchAccountRadio) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 155, Short.MAX_VALUE) - .addComponent(searchBtn))) - .addContainerGap()) - ); - searchPanelLayout.setVerticalGroup( - searchPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(searchPanelLayout.createSequentialGroup() - .addContainerGap() - .addComponent(searchField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(searchPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(searchNameRadio) - .addComponent(searchAccountRadio) - .addComponent(searchBtn)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(filterResultsPane, javax.swing.GroupLayout.DEFAULT_SIZE, 320, Short.MAX_VALUE) - .addContainerGap()) - ); - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(searchPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(searchPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - ); - }// //GEN-END:initComponents - - private void searchNameRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchNameRadioActionPerformed - // TODO add your handling code here: - }//GEN-LAST:event_searchNameRadioActionPerformed - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JScrollPane filterResultsPane; - private javax.swing.JTable filterResultsTable; - private javax.swing.JRadioButton searchAccountRadio; - private javax.swing.JButton searchBtn; - private javax.swing.ButtonGroup searchButtonGroup; - private javax.swing.JTextField searchField; - private javax.swing.JRadioButton searchNameRadio; - private javax.swing.JPanel searchPanel; - // End of variables declaration//GEN-END:variables - -} diff --git a/Core/src/org/sleuthkit/autopsy/report/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/report/Bundle_ja.properties index 6dde31add8..092b975370 100644 --- a/Core/src/org/sleuthkit/autopsy/report/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/report/Bundle_ja.properties @@ -293,7 +293,6 @@ ReportGenerator.artTableColHdr.osInstallDate.text=\u30a4\u30f3\u30b9\u30c8\u30fc ReportGenerator.errList.failedMakeRptFolder=\u30ec\u30dd\u30fc\u30c8\u30d5\u30a9\u30eb\u30c0\u30fc\u3092\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30ec\u30dd\u30fc\u30c8\u3092\u751f\u6210\u3067\u304d\u306a\u3044\u53ef\u80fd\u6027\u304c\u3042\u308a\u307e\u3059\u3002 ReportGenerator.notifyErr.errsDuringRptGen=\u30ec\u30dd\u30fc\u30c8\u751f\u6210\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f: ReportGenerator.errList.failedGetContentTags=\u30b3\u30f3\u30c6\u30f3\u30c4\u30bf\u30b0\u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002 -ReportGenerator.errList.failedGetBBArtifactTags=\u30d6\u30e9\u30c3\u30af\u30dc\u30fc\u30c9\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u30bf\u30b0\u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002 ReportGenerator.errList.errGetContentFromBBArtifact=\u30ec\u30dd\u30fc\u30c8\u4f5c\u6210\u5bfe\u8c61\u306e\u30d6\u30e9\u30c3\u30af\u30dc\u30fc\u30c9\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u306e\u30b3\u30f3\u30c6\u30f3\u30c4\u3092\u53d6\u5f97\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 ReportGenerator.errList.failedGetBBAttribs=\u30ec\u30dd\u30fc\u30c8\u751f\u6210\u4e2d\u306b\u30d6\u30e9\u30c3\u30af\u30dc\u30fc\u30c9\u5c5e\u6027\u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002 ReportGenerator.errList.failedGetBBArtifacts=\u30ec\u30dd\u30fc\u30c8\u751f\u6210\u4e2d\u306b\u30d6\u30e9\u30c3\u30af\u30dc\u30fc\u30c9\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002 diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle.properties b/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle.properties index 8d6d7e88a1..cdab8b0cfa 100755 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle.properties @@ -169,7 +169,6 @@ ReportGenerator.notifyErr.errsDuringRptGen=Errors during report generation: ReportGenerator.errList.failedGetAllTagsArtifacts=Failed get all possible tag names and artifact types. ReportGenerator.errList.noReportSettings=Report settings have not been configured. ReportGenerator.errList.failedGetContentTags=Failed to get content tags. -ReportGenerator.errList.failedGetBBArtifactTags=Failed to get blackboard artifact tags. ReportGenerator.errList.errGetContentFromBBArtifact=Error while getting content from a blackboard artifact to report on. ReportGenerator.errList.failedGetBBAttribs=Failed to get Blackboard Attributes when generating report. ReportGenerator.errList.failedGetBBArtifacts=Failed to get Blackboard Artifacts when generating report. diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle.properties-MERGED index d36c0f5ca6..14e603e61b 100755 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle.properties-MERGED @@ -7,6 +7,7 @@ PortableCaseTagsListPanel.error.errorLoadingTags=Error loading tags PortableCaseTagsListPanel.error.errorTitle=Error getting tag names for case PortableCaseTagsListPanel.error.noOpenCase=There is no case open ReportGenerator.artTableColHdr.comment=Comment +ReportGenerator.errList.failedGetBBArtifactTags=Failed to get result tags. ReportGenerator.errList.noOpenCase=No open case available. ReportGenerator.tagTable.header.userName=User Name ReportProgressIndicator.cancelledMessage=Report generation cancelled @@ -188,7 +189,6 @@ ReportGenerator.notifyErr.errsDuringRptGen=Errors during report generation: ReportGenerator.errList.failedGetAllTagsArtifacts=Failed get all possible tag names and artifact types. ReportGenerator.errList.noReportSettings=Report settings have not been configured. ReportGenerator.errList.failedGetContentTags=Failed to get content tags. -ReportGenerator.errList.failedGetBBArtifactTags=Failed to get blackboard artifact tags. ReportGenerator.errList.errGetContentFromBBArtifact=Error while getting content from a blackboard artifact to report on. ReportGenerator.errList.failedGetBBAttribs=Failed to get Blackboard Attributes when generating report. ReportGenerator.errList.failedGetBBArtifacts=Failed to get Blackboard Artifacts when generating report. diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle_ja.properties index 5077b78fd1..c278634512 100644 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle_ja.properties @@ -150,7 +150,6 @@ ReportGenerator.errList.coreExceptionWhileGenRptRow=\u30a2\u30fc\u30c6\u30a3\u30 ReportGenerator.errList.errGetContentFromBBArtifact=Blackboard\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u304b\u3089\u30ec\u30dd\u30fc\u30c8\u7528\u306e\u30b3\u30f3\u30c6\u30f3\u30c4\u3092\u53d6\u5f97\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 ReportGenerator.errList.failedGetAbstractFileByID=ID\u306b\u57fa\u3065\u304d\u30a2\u30d6\u30b9\u30c8\u30e9\u30af\u30c8\u30d5\u30a1\u30a4\u30eb\u3092\u53d6\u5f97\u3059\u308b\u306e\u3092\u5931\u6557\u3057\u307e\u3057\u305f ReportGenerator.errList.failedGetBBArtifacts=\u30ec\u30dd\u30fc\u30c8\u751f\u6210\u4e2d\u306bBlackboard\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u306e\u53d6\u5f97\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 -ReportGenerator.errList.failedGetBBArtifactTags=Blackboard\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u30bf\u30b0\u306e\u53d6\u5f97\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 ReportGenerator.errList.failedGetBBAttribs=\u30ec\u30dd\u30fc\u30c8\u751f\u6210\u4e2d\u306bBlackboard\u5c5e\u6027\u306e\u53d6\u5f97\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 ReportGenerator.errList.failedGetContentTags=\u30b3\u30f3\u30c6\u30f3\u30c4\u30bf\u30b0\u306e\u53d6\u5f97\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 ReportGenerator.errList.failedMakeRptFolder=\u30ec\u30dd\u30fc\u30c8\u30d5\u30a9\u30eb\u30c0\u306e\u4f5c\u6210\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002\u30ec\u30dd\u30fc\u30c8\u751f\u6210\u304c\u3067\u304d\u306a\u3044\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002 diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportGenerator.java index a889d4f2a8..3894af6e2e 100644 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportGenerator.java @@ -321,9 +321,16 @@ public class ReportGenerator { TableReportGenerator generator = new TableReportGenerator(tableReportSettings, progressIndicator, tableReport); generator.execute(); tableReport.endReport(); + // finish progress, wrap up - progressIndicator.complete(ReportProgressPanel.ReportStatus.COMPLETE); errorList = generator.getErrorList(); + + // if error list is empty, the operation has completed successfully. If not there is an error + ReportProgressPanel.ReportStatus finalStatus = (errorList == null || errorList.isEmpty()) ? + ReportProgressPanel.ReportStatus.COMPLETE : + ReportProgressPanel.ReportStatus.ERROR; + + progressIndicator.complete(finalStatus); } } diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/TableReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/infrastructure/TableReportGenerator.java index 527301f491..6b8e4a4957 100644 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/TableReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/TableReportGenerator.java @@ -424,6 +424,9 @@ class TableReportGenerator { * Generate the tables for the tagged artifacts */ @SuppressWarnings("deprecation") + @Messages({ + "ReportGenerator.errList.failedGetBBArtifactTags=Failed to get result tags." + }) private void makeBlackboardArtifactTagsTables() { List tags; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/taggedhashes/SaveTaggedHashesToHashDbConfigPanel.java b/Core/src/org/sleuthkit/autopsy/report/modules/taggedhashes/SaveTaggedHashesToHashDbConfigPanel.java index dfd66b64c0..9520b28706 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/taggedhashes/SaveTaggedHashesToHashDbConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/taggedhashes/SaveTaggedHashesToHashDbConfigPanel.java @@ -29,19 +29,19 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.logging.Level; +import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.ListCellRenderer; -import javax.swing.ListModel; -import javax.swing.event.ListDataListener; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager; import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupSettingsPanel; +import org.sleuthkit.autopsy.tags.TagUtils; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -54,9 +54,9 @@ class SaveTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; private List tagNames; - private Map tagNameSelections = new LinkedHashMap<>(); - private TagNamesListModel tagsNamesListModel; - private TagsNamesListCellRenderer tagsNamesRenderer; + private Map tagNameSelections = new LinkedHashMap<>(); + private DefaultListModel tagsNamesListModel = new DefaultListModel<>(); + private TagsNamesListCellRenderer tagsNamesRenderer = new TagsNamesListCellRenderer(); private String selectedHashSetName; private List updateableHashSets = new ArrayList<>(); @@ -67,9 +67,6 @@ class SaveTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { // Set up the tag names JList component to be a collection of check boxes // for selecting tag names. The mouse click listener updates tagNameSelections // to reflect user choices. - //tagNamesListBox.setModel(tagsNamesListModel); - //tagNamesListBox.setCellRenderer(tagsNamesRenderer); - //tagNamesListBox.setVisibleRowCount(-1); tagNamesListBox.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent evt) { @@ -79,13 +76,13 @@ class SaveTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { JList list = (JList) evt.getSource(); int index = list.locationToIndex(evt.getPoint()); if (index > -1) { - String value = tagsNamesListModel.getElementAt(index); - tagNameSelections.put(value, !tagNameSelections.get(value)); + TagName tagName = tagsNamesListModel.getElementAt(index); + tagNameSelections.put(tagName, !tagNameSelections.get(tagName)); list.repaint(); } } }); - + this.jAllTagsCheckBox.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { @@ -96,22 +93,22 @@ class SaveTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { } }); } - + HashesReportModuleSettings getConfiguration() { return new HashesReportModuleSettings(jAllTagsCheckBox.isSelected(), selectedHashSetName); } - + void setConfiguration(HashesReportModuleSettings settings) { // Need to reset tags. User may have opened a different case or // there may not be a case open any more (Command Line wizard). customizeComponents(); - + // update tag selection jAllTagsCheckBox.setSelected(settings.isExportAllTags()); if (settings.isExportAllTags()) { selectAllTags(true); } - + // update hash database selection if (settings.getHashDbName() != null) { populateHashSetComponents(); @@ -119,25 +116,28 @@ class SaveTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { } } - private void customizeComponents() { - populateTagNameComponents(); - - tagsNamesListModel = new TagNamesListModel(); + private void customizeComponents() { + tagsNamesListModel = new DefaultListModel<>(); tagsNamesRenderer = new TagsNamesListCellRenderer(); + populateTagNameComponents(); + tagNamesListBox.setModel(tagsNamesListModel); tagNamesListBox.setCellRenderer(tagsNamesRenderer); tagNamesListBox.setVisibleRowCount(-1); - + populateHashSetComponents(); } private void populateTagNameComponents() { // Get the tag names in use for the current case. tagNames = new ArrayList<>(); - Map updatedTagNameSelections = new LinkedHashMap<>(); + Map updatedTagNameSelections = new LinkedHashMap<>(); try { // There may not be a case open when configuring report modules for Command Line execution tagNames = Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse(); + for (TagName tagName : tagNames) { + tagsNamesListModel.addElement(tagName); + } } catch (TskCoreException ex) { Logger.getLogger(SaveTaggedHashesToHashDbConfigPanel.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); } catch (NoCurrentCaseException ex) { @@ -151,10 +151,10 @@ class SaveTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { // LinkedHashMap so that order is preserved and the tagNames and tagNameSelections // containers are "parallel" containers. for (TagName tagName : tagNames) { - if (tagNameSelections.get(tagName.getDisplayName()) != null && Objects.equals(tagNameSelections.get(tagName.getDisplayName()), Boolean.TRUE)) { - updatedTagNameSelections.put(tagName.getDisplayName(), Boolean.TRUE); + if (tagNameSelections.get(tagName) != null && Objects.equals(tagNameSelections.get(tagName), Boolean.TRUE)) { + updatedTagNameSelections.put(tagName, Boolean.TRUE); } else { - updatedTagNameSelections.put(tagName.getDisplayName(), Boolean.FALSE); + updatedTagNameSelections.put(tagName, Boolean.FALSE); } } tagNameSelections = updatedTagNameSelections; @@ -165,7 +165,7 @@ class SaveTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { // and when the user changes the hash set configuration. hashSetsComboBox.removeAllItems(); selectedHashSetName = ""; - + // Get the updateable hash databases and add their hash set names to the // JComboBox component. updateableHashSets = HashDbManager.getInstance().getUpdateableHashSets(); @@ -187,7 +187,7 @@ class SaveTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { List getSelectedTagNames() { List selectedTagNames = new ArrayList<>(); for (TagName tagName : tagNames) { - if (tagNameSelections.get(tagName.getDisplayName())) { + if (tagNameSelections.get(tagName)) { selectedTagNames.add(tagName); } } @@ -208,41 +208,20 @@ class SaveTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { return null; } - // This class is a list model for the tag names JList component. - private class TagNamesListModel implements ListModel { - - @Override - public int getSize() { - return tagNames.size(); - } - - @Override - public String getElementAt(int index) { - return tagNames.get(index).getDisplayName(); - } - - @Override - public void addListDataListener(ListDataListener l) { - } - - @Override - public void removeListDataListener(ListDataListener l) { - } - } - // This class renders the items in the tag names JList component as JCheckbox components. - private class TagsNamesListCellRenderer extends JCheckBox implements ListCellRenderer { + private class TagsNamesListCellRenderer extends JCheckBox implements ListCellRenderer { + private static final long serialVersionUID = 1L; @Override - public Component getListCellRendererComponent(JList list, String value, int index, boolean isSelected, boolean cellHasFocus) { + public Component getListCellRendererComponent(JList list, TagName value, int index, boolean isSelected, boolean cellHasFocus) { if (value != null) { setEnabled(list.isEnabled()); setSelected(tagNameSelections.get(value)); setFont(list.getFont()); setBackground(list.getBackground()); setForeground(list.getForeground()); - setText(value); + setText(TagUtils.getDecoratedTagDisplayName(value)); return this; } return new JLabel(); @@ -364,7 +343,7 @@ class SaveTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { }//GEN-LAST:event_selectAllButtonActionPerformed private void hashSetsComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_hashSetsComboBoxActionPerformed - selectedHashSetName = (String)hashSetsComboBox.getSelectedItem(); + selectedHashSetName = (String) hashSetsComboBox.getSelectedItem(); }//GEN-LAST:event_hashSetsComboBoxActionPerformed private void deselectAllButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deselectAllButtonActionPerformed @@ -389,7 +368,7 @@ class SaveTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { state = Boolean.FALSE; } for (TagName tagName : tagNames) { - tagNameSelections.put(tagName.getDisplayName(), state); + tagNameSelections.put(tagName, state); } tagNamesListBox.repaint(); } @@ -406,6 +385,6 @@ class SaveTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { private javax.swing.JLabel jLabel2; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JButton selectAllButton; - private javax.swing.JList tagNamesListBox; + private javax.swing.JList tagNamesListBox; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/tags/TagUtils.java b/Core/src/org/sleuthkit/autopsy/tags/TagUtils.java new file mode 100755 index 0000000000..3b63168a07 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/tags/TagUtils.java @@ -0,0 +1,69 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.tags; + +import java.util.logging.Level; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TagSet; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; + +/** + * + * Utility methods for Tags. + */ +public final class TagUtils { + + private static final Logger logger = Logger.getLogger(TagUtils.class.getName()); + + private TagUtils() { + // Intentionally empty constructor; + } + + /** + * Returns a decorated name for the TagName that includes, if available, the + * TagName's TagSet name and notability. + * + * If an exception is throw while trying to retrieve the TagName's TagSet + * the TagSet name will not be included. + * + * @param tagName The TagName value generate name for. + * + * @return The decorated name for the TagName or the TagName display name + * value if an exception occurred. + */ + public static String getDecoratedTagDisplayName(TagName tagName) { + String displayName = tagName.getDisplayName(); + try { + TagSet tagSet = tagName.getTagSet(); + if (tagSet != null) { + displayName = tagSet.getName() + ": " + displayName; + } + } catch (TskCoreException ex) { + logger.log(Level.WARNING, String.format("Failed to get TagSet for TagName (%d)", tagName.getId())); + } + + if (tagName.getKnownStatus() == TskData.FileKnown.BAD) { + displayName += " (Notable)"; + } + + return displayName; + } +} diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoPersonasTest.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoPersonasTest.java index 531a2c01f0..fcfb44e520 100644 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoPersonasTest.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoPersonasTest.java @@ -383,6 +383,129 @@ public class CentralRepoPersonasTest extends TestCase { } } + /** + * Tests Persona alias and metadata. + * + */ + public void testPersonaAliasesAndMetadata() { + + + try { + + // Step 1: Create an account + CentralRepoAccount phoneAccount1 = CentralRepository.getInstance() + .getOrCreateAccount(phoneAccountType, PHONE_NUM_1); + + + // Step 2: Create a Persona for the Account + String comment = "The best dog ever"; + Persona.PersonaStatus status = Persona.PersonaStatus.ACTIVE; + Persona dogPersona = Persona.createPersonaForAccount(DOG_PERSONA_NAME, comment , status, phoneAccount1, "Because I said so", Persona.Confidence.LOW ); + + + // Step 3. Add Persona Aliases + PersonaAlias alias1 = dogPersona.addAlias("Good Boy", "Coz he's is the best dog ever", Persona.Confidence.MEDIUM); + PersonaAlias alias2 = dogPersona.addAlias("WoofWoof", "How many dumb comments can I come up with?", Persona.Confidence.LOW); + + Assert.assertNotNull(alias1); + Assert.assertNotNull(alias2); + + //Step 4: Add Persona metadata + PersonaMetadata metadata1 = dogPersona.addMetadata("Color", "Black", "He's got thick black hair.", Persona.Confidence.MEDIUM); + PersonaMetadata metadata2 = dogPersona.addMetadata("Gender", "Male", "Because...", Persona.Confidence.LOW); + + Assert.assertNotNull(metadata1); + Assert.assertNotNull(metadata2); + + // get all aliases for persona1 + Collection dogAliases1 = dogPersona.getAliases(); + Assert.assertEquals(2, dogAliases1.size()); + for (PersonaAlias alias: dogAliases1) { + //System.out.println(" Dog Alias: "+ alias.getAlias()) ; + Assert.assertFalse(alias.getAlias().isEmpty()); + } + // get all metadata for persona1 + Collection dogMetadataList = dogPersona.getMetadata(); + Assert.assertEquals(2, dogMetadataList.size()); + for (PersonaMetadata md: dogMetadataList) { + //System.out.println(String.format("Metadata: %s : %s", md.getName(), md.getValue())) ; + Assert.assertFalse(md.getName().isEmpty()); + Assert.assertFalse(md.getValue().isEmpty()); + } + + + // Step 5: Create another account + CentralRepoAccount catdogFBAccount = CentralRepository.getInstance() + .getOrCreateAccount(facebookAccountType, FACEBOOK_ID_CATDOG); + + // Add an account to persona + dogPersona.addAccountToPersona(catdogFBAccount, "Looks like dog, barks like a dog...", Persona.Confidence.MEDIUM); + + + // Step 6: Create a Second Persona + + String comment2 = "The fiercest cat alive."; + Persona catPersona = Persona.createPersonaForAccount(CAT_PERSONA_NAME, comment2 , Persona.PersonaStatus.ACTIVE, catdogFBAccount, "Smells like a cat.", Persona.Confidence.LOW ); + Assert.assertNotNull(catPersona); + Assert.assertTrue(catPersona.getName().equalsIgnoreCase(CAT_PERSONA_NAME)); + + + // Add Persona Aliases + PersonaAlias catAlias1 = catPersona.addAlias("CutieKitty", "Because", Persona.Confidence.MEDIUM); + Assert.assertNotNull(catAlias1); + + + //Step 4: Add Persona metadata + PersonaMetadata catMetadata1 = catPersona.addMetadata("Color", "White", "White as snow.", Persona.Confidence.MEDIUM); + PersonaMetadata catMetadata2 = catPersona.addMetadata("Breed", "Persian", "Just Because...", Persona.Confidence.LOW); + PersonaMetadata catMetadata3 = catPersona.addMetadata("Legs", "Four", "I counted", Persona.Confidence.HIGH); + + Assert.assertNotNull(catMetadata1); + Assert.assertNotNull(catMetadata2); + Assert.assertNotNull(catMetadata3); + + + // get all aliases for persona2 + Collection catAliases1 = catPersona.getAliases(); + Assert.assertEquals(1, catAliases1.size()); + for (PersonaAlias alias: dogAliases1) { + //System.out.println("Alias: "+ alias.getAlias()) ; + Assert.assertFalse(alias.getAlias().isEmpty()); + } + // get all metadata for persona2 + Collection catMetadataList = catPersona.getMetadata(); + Assert.assertEquals(3, catMetadataList.size()); + for (PersonaMetadata md: catMetadataList) { + //System.out.println(String.format("Metadata: %s : %s", md.getName(), md.getValue())) ; + Assert.assertFalse(md.getName().isEmpty()); + Assert.assertFalse(md.getValue().isEmpty()); + } + + + // Create a 3rd account and persona + CentralRepoAccount holmesSkypeAccount = CentralRepository.getInstance() + .getOrCreateAccount(skypeAccountType, HOLMES_SKYPE_ID); + + // Create a person for the Skype account + Persona holmesPersona = Persona.createPersonaForAccount(HOLMES_PERSONA_NAME, + "Has a Pipe in his mouth.", Persona.PersonaStatus.ACTIVE, + holmesSkypeAccount, "The name says it all.", Persona.Confidence.LOW); + + // This persona has no aliases or metadata. Verify + // get all aliases for holmesPersona + Collection holmesAliases = holmesPersona.getAliases(); + Assert.assertEquals(0, holmesAliases.size()); + + // get all metadata for holmesPersona + Collection holmesMetadataList = holmesPersona.getMetadata(); + Assert.assertEquals(0, holmesMetadataList.size()); + + + } catch (CentralRepoException ex) { + Assert.fail("Didn't expect an exception here. Exception: " + ex); + } + } + /** * Tests Personas & X_Accounts and X_instances in the context of Case/data source. * There are 4 Cases. diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 9505c22c98..95509c4c16 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -57,7 +57,6 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.casemodule.events.DataSourceDeletedEvent; -import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.History; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; @@ -96,6 +95,8 @@ public final class ImageGalleryController { private static final Logger logger = Logger.getLogger(ImageGalleryController.class.getName()); private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_STARTED, IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_COMPLETED); private static final Set INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED, IngestManager.IngestModuleEvent.FILE_DONE); + + private static String DEFAULT_TAG_SET_NAME = "Project VIC"; /* * The file limit for image gallery. If the selected data source (or all * data sources, if that option is selected) has more than this many files @@ -737,7 +738,7 @@ public final class ImageGalleryController { List tagSetList = getCaseDatabase().getTaggingManager().getTagSets(); if (tagSetList != null && !tagSetList.isEmpty()) { for (TagSet set : tagSetList) { - if (set.getName().equals(TagsManager.getCategoryTagSetName())) { + if (set.getName().equals(getCategoryTagSetName())) { return set; } } @@ -748,6 +749,15 @@ public final class ImageGalleryController { } } + /** + * Returns the name of the category tag set. + * + * @return Tagset name + */ + static String getCategoryTagSetName() { + return DEFAULT_TAG_SET_NAME; + } + /** * A listener for ingest module application events. */ diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryService.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryService.java index 53f9bc386a..176b6e1a44 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryService.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryService.java @@ -18,12 +18,19 @@ */ package org.sleuthkit.autopsy.imagegallery; +import java.util.ArrayList; +import java.util.List; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProviders; import org.sleuthkit.autopsy.appservices.AutopsyService; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.services.TagNameDefinition; import org.sleuthkit.autopsy.progress.ProgressIndicator; +import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TagSet; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; /** * An Autopsy service that creates/opens a local drawables database and @@ -37,6 +44,22 @@ import org.sleuthkit.datamodel.TskCoreException; }) public class ImageGalleryService implements AutopsyService { + private static final String CATEGORY_ONE_NAME = "Child Exploitation (Illegal)"; + private static final String CATEGORY_TWO_NAME = "Child Exploitation (Non-Illegal/Age Difficult)"; + private static final String CATEGORY_THREE_NAME = "CGI/Animation (Child Exploitive)"; + private static final String CATEGORY_FOUR_NAME = "Exemplar/Comparison (Internal Use Only)"; + private static final String CATEGORY_FIVE_NAME = "Non-pertinent"; + + private static final List DEFAULT_CATEGORY_DEFINITION = new ArrayList<>(); + + static { + DEFAULT_CATEGORY_DEFINITION.add(new TagNameDefinition(CATEGORY_ONE_NAME, "", TagName.HTML_COLOR.RED, TskData.FileKnown.BAD)); + DEFAULT_CATEGORY_DEFINITION.add(new TagNameDefinition(CATEGORY_TWO_NAME, "", TagName.HTML_COLOR.LIME, TskData.FileKnown.BAD)); + DEFAULT_CATEGORY_DEFINITION.add(new TagNameDefinition(CATEGORY_THREE_NAME, "", TagName.HTML_COLOR.YELLOW, TskData.FileKnown.BAD)); + DEFAULT_CATEGORY_DEFINITION.add(new TagNameDefinition(CATEGORY_FOUR_NAME, "", TagName.HTML_COLOR.PURPLE, TskData.FileKnown.UNKNOWN)); + DEFAULT_CATEGORY_DEFINITION.add(new TagNameDefinition(CATEGORY_FIVE_NAME, "", TagName.HTML_COLOR.FUCHSIA, TskData.FileKnown.UNKNOWN)); + } + @Override public String getServiceName() { return Bundle.ImageGalleryService_serviceName(); @@ -65,6 +88,22 @@ public class ImageGalleryService implements AutopsyService { ProgressIndicator progress = context.getProgressIndicator(); progress.progress(Bundle.ImageGalleryService_openCaseResources_progressMessage_start()); try { + + // Check to see if the Project VIC tag set exists, if not create a + // tag set using the default tags. + boolean addDefaultTagSet = true; + List tagSets = context.getCase().getServices().getTagsManager().getAllTagSets(); + for (TagSet set : tagSets) { + if (set.getName().equals(ImageGalleryController.getCategoryTagSetName())) { + addDefaultTagSet = false; + break; + } + } + + if (addDefaultTagSet) { + addDefaultTagSet(context.getCase()); + } + ImageGalleryController.createController(context.getCase()); } catch (TskCoreException ex) { throw new AutopsyServiceException("Error opening Image Gallery databases", ex); @@ -88,4 +127,20 @@ public class ImageGalleryService implements AutopsyService { ImageGalleryController.shutDownController(context.getCase()); } + /** + * Add the default category tag set to the case db. + * + * @param skCase Currently open case. + * + * @throws TskCoreException + */ + private void addDefaultTagSet(Case currentCase) throws TskCoreException { + List tagNames = new ArrayList<>(); + for (TagNameDefinition def : DEFAULT_CATEGORY_DEFINITION) { + tagNames.add(currentCase.getSleuthkitCase().addOrUpdateTagName(def.getDisplayName(), def.getDescription(), def.getColor(), def.getKnownStatus())); + } + + currentCase.getServices().getTagsManager().addTagSet(ImageGalleryController.getCategoryTagSetName(), tagNames); + } + } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java index abf2c02586..e75f380a1f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java @@ -75,8 +75,8 @@ public final class DrawableTagsManager { public DrawableTagsManager(ImageGalleryController controller) throws TskCoreException { this.autopsyTagsManager = controller.getCase().getServices().getTagsManager(); - followUpTagName = getTagName(TagsManager.getFollowUpDisplayString()); - bookmarkTagName = getTagName(TagsManager.getBookmarkDisplayString()); + followUpTagName = getTagName(TagsManager.getFollowUpTagDisplayName()); + bookmarkTagName = getTagName(TagsManager.getBookmarkTagDisplayName()); this.controller = controller; compareByDisplayName = new Comparator() { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GuiUtils.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GuiUtils.java index f032698578..4699046655 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GuiUtils.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GuiUtils.java @@ -22,7 +22,9 @@ import java.io.IOException; import java.net.URL; import java.util.logging.Level; import javafx.scene.control.ButtonBase; +import javafx.scene.control.CustomMenuItem; import javafx.scene.control.Dialog; +import javafx.scene.control.Label; import javafx.scene.control.MenuItem; import javafx.scene.image.Image; import javafx.stage.Stage; @@ -65,7 +67,8 @@ public final class GuiUtils { * @return */ public static MenuItem createAutoAssigningMenuItem(ButtonBase button, Action action) { - MenuItem menuItem = ActionUtils.createMenuItem(action); + MenuItem menuItem = new CustomMenuItem(new Label(action.getText(), action.getGraphic())); + ActionUtils.configureMenuItem(action, menuItem); menuItem.setOnAction(actionEvent -> { action.handle(actionEvent); button.setText(action.getText());