Autopsy  4.19.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
ContactArtifactViewer.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2020-2021 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.contentviewers.artifactviewers;
20 
21 import java.awt.Component;
22 import java.awt.GridBagConstraints;
23 import java.awt.GridBagLayout;
24 import java.awt.Insets;
25 import java.awt.event.ActionListener;
26 import java.awt.image.BufferedImage;
27 import java.io.File;
28 import java.io.IOException;
29 import java.util.ArrayList;
30 import java.util.Collection;
31 import java.util.Collections;
32 import java.util.HashMap;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Optional;
36 import java.util.concurrent.CancellationException;
37 import java.util.concurrent.ExecutionException;
38 import java.util.logging.Level;
39 import java.util.stream.Collectors;
40 import javax.imageio.ImageIO;
41 import javax.swing.ImageIcon;
42 import javax.swing.JButton;
43 import javax.swing.JLabel;
44 import javax.swing.JScrollPane;
45 import javax.swing.SwingWorker;
46 import javax.swing.border.EmptyBorder;
47 import org.apache.commons.lang.StringUtils;
48 import org.openide.util.NbBundle;
49 import org.openide.util.lookup.ServiceProvider;
62 import org.sleuthkit.datamodel.AbstractFile;
63 import org.sleuthkit.datamodel.Account;
64 import org.sleuthkit.datamodel.BlackboardArtifact;
65 import org.sleuthkit.datamodel.BlackboardAttribute;
66 import org.sleuthkit.datamodel.CommunicationsManager;
67 import org.sleuthkit.datamodel.Content;
68 import org.sleuthkit.datamodel.InvalidAccountIDException;
69 import org.sleuthkit.datamodel.TskCoreException;
70 
74 @ServiceProvider(service = ArtifactContentViewer.class)
75 public class ContactArtifactViewer extends javax.swing.JPanel implements ArtifactContentViewer {
76 
77  private final static Logger logger = Logger.getLogger(ContactArtifactViewer.class.getName());
78  private static final long serialVersionUID = 1L;
79 
80  private GridBagLayout m_gridBagLayout = new GridBagLayout();
81  private GridBagConstraints m_constraints = new GridBagConstraints();
82 
83  private JLabel personaSearchStatusLabel;
84 
85  private BlackboardArtifact contactArtifact;
86  private String contactName;
87  private String datasourceName;
88 
89  private List<BlackboardAttribute> phoneNumList = new ArrayList<>();
90  private List<BlackboardAttribute> emailList = new ArrayList<>();
91  private List<BlackboardAttribute> nameList = new ArrayList<>();
92  private List<BlackboardAttribute> otherList = new ArrayList<>();
93  private List<BlackboardAttribute> accountAttributesList = new ArrayList<>();
94 
95  private final static String DEFAULT_IMAGE_PATH = "/org/sleuthkit/autopsy/images/defaultContact.png";
96  private final ImageIcon defaultImage;
97 
98  // A list of unique accounts matching the attributes of the contact artifact.
99  private final List<CentralRepoAccount> contactUniqueAccountsList = new ArrayList<>();
100 
101  // A list of all unique personas and their account, found by searching on the
102  // account identifier attributes of the Contact artifact.
103  private final Map<Persona, ArrayList<CentralRepoAccount>> contactUniquePersonasMap = new HashMap<>();
104 
106 
111  initComponents();
112  this.setBorder(new EmptyBorder(ContentViewerDefaults.getPanelInsets()));
113  defaultImage = new ImageIcon(ContactArtifactViewer.class.getResource(DEFAULT_IMAGE_PATH));
114  }
115 
121  @SuppressWarnings("unchecked")
122  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
123  private void initComponents() {
124 
125  setToolTipText(""); // NOI18N
126  setLayout(new java.awt.GridBagLayout());
127  }// </editor-fold>//GEN-END:initComponents
128 
129  @Override
130  public void setArtifact(BlackboardArtifact artifact) {
131  // Reset the panel.
132  resetComponent();
133 
134  if (artifact != null) {
135  try {
136  extractArtifactData(artifact);
137  } catch (TskCoreException ex) {
138  logger.log(Level.SEVERE, String.format("Error getting attributes for artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex);
139  return;
140  }
141  updateView();
142  }
143  this.setLayout(this.m_gridBagLayout);
144  this.revalidate();
145  this.repaint();
146  }
147 
148  @Override
149  public Component getComponent() {
150  // Slap a vertical scrollbar on the panel.
151  return new JScrollPane(this, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
152  }
153 
154  @Override
155  public boolean isSupported(BlackboardArtifact artifact) {
156  return (artifact != null)
157  && (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID());
158  }
159 
167  private void extractArtifactData(BlackboardArtifact artifact) throws TskCoreException {
168 
169  this.contactArtifact = artifact;
170 
171  phoneNumList = new ArrayList<>();
172  emailList = new ArrayList<>();
173  nameList = new ArrayList<>();
174  otherList = new ArrayList<>();
175  accountAttributesList = new ArrayList<>();
176 
177  // Get all the attributes and group them by the section panels they go in
178  for (BlackboardAttribute bba : contactArtifact.getAttributes()) {
179  if (bba.getAttributeType().getTypeName().startsWith("TSK_PHONE")) {
180  phoneNumList.add(bba);
181  accountAttributesList.add(bba);
182  } else if (bba.getAttributeType().getTypeName().startsWith("TSK_EMAIL")) {
183  emailList.add(bba);
184  accountAttributesList.add(bba);
185  } else if (bba.getAttributeType().getTypeName().startsWith("TSK_NAME")) {
186  nameList.add(bba);
187  } else {
188  otherList.add(bba);
189  if (bba.getAttributeType().getTypeName().equalsIgnoreCase("TSK_ID")) {
190  accountAttributesList.add(bba);
191  }
192  }
193  }
194 
195  datasourceName = contactArtifact.getDataSource().getName();
196  }
197 
201  private void updateView() {
202 
203  // Update contact name, image, phone numbers
204  updateContactDetails();
205 
206  // update artifact source panel
207  updateSource();
208 
209  // show a empty Personas panel and kick off a serch for personas
210  initiatePersonasSearch();
211 
212  }
213 
217  @NbBundle.Messages({
218  "ContactArtifactViewer_phones_header=Phone",
219  "ContactArtifactViewer_emails_header=Email",
220  "ContactArtifactViewer_others_header=Other",})
221  private void updateContactDetails() {
222 
223  // update image and name.
224  updateContactImage(m_gridBagLayout, m_constraints);
225  updateContactName(m_gridBagLayout, m_constraints);
226 
227  // update contact attributes sections
228  updateContactMethodSection(phoneNumList, Bundle.ContactArtifactViewer_phones_header(), m_gridBagLayout, m_constraints);
229  updateContactMethodSection(emailList, Bundle.ContactArtifactViewer_emails_header(), m_gridBagLayout, m_constraints);
230  updateContactMethodSection(otherList, Bundle.ContactArtifactViewer_others_header(), m_gridBagLayout, m_constraints);
231  }
232 
240  @NbBundle.Messages({
241  "ContactArtifactViewer.contactImage.text=",})
242  private void updateContactImage(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) {
243  // place the image on the top right corner
244  Insets savedInsets = contactPanelConstraints.insets;
245  contactPanelConstraints.gridy = 0;
246  contactPanelConstraints.gridx = 0;
247  contactPanelConstraints.insets = new Insets(0, 0, ContentViewerDefaults.getLineSpacing(), 0);
248  int prevGridWidth = contactPanelConstraints.gridwidth;
249  contactPanelConstraints.gridwidth = 3;
250  contactPanelConstraints.anchor = GridBagConstraints.LINE_START;
251 
252  javax.swing.JLabel contactImage = new javax.swing.JLabel();
253  contactImage.setIcon(getImageFromArtifact(contactArtifact));
254  contactImage.setText(Bundle.ContactArtifactViewer_contactImage_text());
255 
256  // add image to top left corner of the page.
257  CommunicationArtifactViewerHelper.addComponent(this, contactPanelLayout, contactPanelConstraints, contactImage);
258  CommunicationArtifactViewerHelper.addLineEndGlue(this, contactPanelLayout, contactPanelConstraints);
259  contactPanelConstraints.gridy++;
260 
261  contactPanelConstraints.gridwidth = prevGridWidth;
262  contactPanelConstraints.insets = savedInsets;
263  }
264 
272  @NbBundle.Messages({
273  "ContactArtifactViewer_contactname_unknown=Unknown",})
274  private void updateContactName(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) {
275 
276  boolean foundName = false;
277  for (BlackboardAttribute bba : this.nameList) {
278  if (StringUtils.isEmpty(bba.getValueString()) == false) {
279  contactName = bba.getDisplayString();
280 
281  CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, 0, contactName);
282  foundName = true;
283  break;
284  }
285  }
286  if (foundName == false) {
287  CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, ContentViewerDefaults.getSectionSpacing(), Bundle.ContactArtifactViewer_contactname_unknown());
288  }
289  }
290 
301  private void updateContactMethodSection(List<BlackboardAttribute> sectionAttributesList, String sectionHeader, GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) {
302 
303  // If there are no attributes for this section, do nothing
304  if (sectionAttributesList.isEmpty()) {
305  return;
306  }
307 
308  CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, ContentViewerDefaults.getSectionSpacing(), sectionHeader);
309  for (BlackboardAttribute bba : sectionAttributesList) {
310  CommunicationArtifactViewerHelper.addKey(this, contactPanelLayout, contactPanelConstraints, bba.getAttributeType().getDisplayName());
311  CommunicationArtifactViewerHelper.addValue(this, contactPanelLayout, contactPanelConstraints, bba.getDisplayString());
312  }
313  }
314 
318  @NbBundle.Messages({
319  "ContactArtifactViewer_heading_Source=Source",
320  "ContactArtifactViewer_label_datasource=Data Source",})
321  private void updateSource() {
322  CommunicationArtifactViewerHelper.addHeader(this, this.m_gridBagLayout, m_constraints, ContentViewerDefaults.getSectionSpacing(), Bundle.ContactArtifactViewer_heading_Source());
323  CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_label_datasource());
324  CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, m_constraints, datasourceName);
325  }
326 
332  @NbBundle.Messages({
333  "ContactArtifactViewer_persona_header=Persona",
334  "ContactArtifactViewer_persona_searching=Searching...",
335  "ContactArtifactViewer_cr_disabled_message=Enable Central Repository to view, create and edit personas.",
336  "ContactArtifactViewer_persona_unknown=Unknown"
337  })
338  private void initiatePersonasSearch() {
339 
340  // add a section header
341  JLabel personaHeader = CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, m_constraints, ContentViewerDefaults.getSectionSpacing(), Bundle.ContactArtifactViewer_persona_header());
342 
343  m_constraints.gridy++;
344 
345  // add a status label
346  String personaStatusLabelText = CentralRepository.isEnabled()
347  ? Bundle.ContactArtifactViewer_persona_searching()
348  : Bundle.ContactArtifactViewer_persona_unknown();
349 
350  this.personaSearchStatusLabel = new javax.swing.JLabel();
351  personaSearchStatusLabel.setText(personaStatusLabelText);
352  personaSearchStatusLabel.setFont(ContentViewerDefaults.getMessageFont());
353 
354  m_constraints.gridx = 0;
355  m_constraints.anchor = GridBagConstraints.LINE_START;
356 
357  CommunicationArtifactViewerHelper.addComponent(this, m_gridBagLayout, m_constraints, personaSearchStatusLabel);
358 
360  // Kick off a background task to serach for personas for the contact
361  personaSearchTask = new ContactPersonaSearcherTask(contactArtifact);
362  personaSearchTask.execute();
363  } else {
364  personaHeader.setEnabled(false);
365  personaSearchStatusLabel.setEnabled(false);
366 
367  Insets messageInsets = new Insets(ContentViewerDefaults.getSectionSpacing(), 0, ContentViewerDefaults.getLineSpacing(), 0);
368  CommunicationArtifactViewerHelper.addMessageRow(this, m_gridBagLayout, messageInsets, m_constraints, Bundle.ContactArtifactViewer_cr_disabled_message());
369  m_constraints.gridy++;
370 
371  CommunicationArtifactViewerHelper.addPageEndGlue(this, m_gridBagLayout, this.m_constraints);
372  }
373 
374  }
375 
379  private void updatePersonas() {
380 
381  // Remove the "Searching....." label
382  this.remove(personaSearchStatusLabel);
383 
384  m_constraints.gridx = 0;
385  if (contactUniquePersonasMap.isEmpty()) {
386  // No persona found - show a button to create one.
387  showPersona(null, 0, Collections.emptyList(), this.m_gridBagLayout, this.m_constraints);
388  } else {
389  int matchCounter = 0;
390  for (Map.Entry<Persona, ArrayList<CentralRepoAccount>> entry : contactUniquePersonasMap.entrySet()) {
391  List<CentralRepoAccount> missingAccounts = new ArrayList<>();
392  ArrayList<CentralRepoAccount> personaAccounts = entry.getValue();
393  matchCounter++;
394 
395  // create a list of accounts missing from this persona
396  for (CentralRepoAccount account : contactUniqueAccountsList) {
397  if (personaAccounts.contains(account) == false) {
398  missingAccounts.add(account);
399  }
400  }
401 
402  showPersona(entry.getKey(), matchCounter, missingAccounts, m_gridBagLayout, m_constraints);
403  m_constraints.gridy += 2;
404  }
405  }
406 
407  // add veritcal glue at the end
408  CommunicationArtifactViewerHelper.addPageEndGlue(this, m_gridBagLayout, this.m_constraints);
409 
410  // redraw the panel
411  this.setLayout(this.m_gridBagLayout);
412  this.revalidate();
413  this.repaint();
414  }
415 
428  @NbBundle.Messages({
429  "ContactArtifactViewer_persona_label=Persona ",
430  "ContactArtifactViewer_persona_no_match=No matches found",
431  "ContactArtifactViewer_persona_button_view=View",
432  "ContactArtifactViewer_persona_button_new=Create",
433  "ContactArtifactViewer_persona_match_num=Match ",
434  "ContactArtifactViewer_missing_account_label=Missing contact account",
435  "ContactArtifactViewer_found_all_accounts_label=All accounts found."
436  })
437  private void showPersona(Persona persona, int matchNumber, List<CentralRepoAccount> missingAccountsList, GridBagLayout gridBagLayout, GridBagConstraints constraints) {
438 
439  // save the original insets
440  Insets savedInsets = constraints.insets;
441 
442  // Add a Match X label in col 0.
443  constraints.gridx = 0;
444  javax.swing.JLabel matchNumberLabel = CommunicationArtifactViewerHelper.addKey(this, gridBagLayout, constraints, String.format("%s %d", Bundle.ContactArtifactViewer_persona_match_num(), matchNumber).trim());
445 
446  javax.swing.JLabel personaNameLabel = new javax.swing.JLabel();
447  javax.swing.JButton personaButton = new javax.swing.JButton();
448 
449  String personaName;
450  String personaButtonText;
451  ActionListener personaButtonListener;
452  if (persona != null) {
453  personaName = persona.getName();
454  personaButtonText = Bundle.ContactArtifactViewer_persona_button_view();
455  personaButtonListener = new ViewPersonaButtonListener(this, persona);
456  } else {
457  matchNumberLabel.setVisible(false);
458  personaName = Bundle.ContactArtifactViewer_persona_no_match();
459  personaButtonText = Bundle.ContactArtifactViewer_persona_button_new();
460  personaButtonListener = new CreatePersonaButtonListener(this, new PersonaUIComponents(personaNameLabel, personaButton));
461  }
462 
463  //constraints.gridwidth = 1; // TBD: this may not be needed if we use single panel
464  constraints.gridx++;
465  constraints.insets = new Insets(0, ContentViewerDefaults.getColumnSpacing(), ContentViewerDefaults.getLineSpacing(), 0);
466  constraints.anchor = GridBagConstraints.LINE_START;
467  personaNameLabel.setText(personaName);
468  gridBagLayout.setConstraints(personaNameLabel, constraints);
469  CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, personaNameLabel);
470  //personasPanel.add(personaNameLabel);
471 
472  // Add a Persona action button
473  constraints.gridx++;
474  //constraints.gridwidth = 1;
475  personaButton.setText(personaButtonText);
476  personaButton.addActionListener(personaButtonListener);
477 
478  // Shirnk the button height.
479  personaButton.setMargin(new Insets(0, 5, 0, 5));
480  constraints.insets = new Insets(0, ContentViewerDefaults.getColumnSpacing(), ContentViewerDefaults.getLineSpacing(), 0);
481  constraints.anchor = GridBagConstraints.LINE_START;
482  gridBagLayout.setConstraints(personaButton, constraints);
483  CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, personaButton);
484  CommunicationArtifactViewerHelper.addLineEndGlue(this, gridBagLayout, constraints);
485 
486  constraints.insets = savedInsets;
487 
488  // if we have a persona, indicate if any of the contact's accounts are missing from it.
489  if (persona != null) {
490  if (missingAccountsList.isEmpty()) {
491  constraints.gridy++;
492  constraints.gridx = 1;
493  //constraints.insets = labelInsets;
494 
495  javax.swing.JLabel accountsStatus = new javax.swing.JLabel(Bundle.ContactArtifactViewer_found_all_accounts_label());
496  constraints.insets = new Insets(0, ContentViewerDefaults.getColumnSpacing(), ContentViewerDefaults.getLineSpacing(), 0);
497  constraints.anchor = GridBagConstraints.LINE_START;
498  CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, accountsStatus);
499  constraints.insets = savedInsets;
500 
501  CommunicationArtifactViewerHelper.addLineEndGlue(this, gridBagLayout, constraints);
502  } else {
503  // show missing accounts.
504  for (CentralRepoAccount missingAccount : missingAccountsList) {
505  //constraints.weightx = 0;
506  constraints.gridx = 0;
507  constraints.gridy++;
508 
509  // this needs an extra indent
510  CommunicationArtifactViewerHelper.addKeyAtCol(this, gridBagLayout, constraints, Bundle.ContactArtifactViewer_missing_account_label(), 1);
511  constraints.insets = savedInsets;
512 
513  CommunicationArtifactViewerHelper.addValueAtCol(this, gridBagLayout, constraints, missingAccount.getIdentifier(), 2);
514  }
515  }
516  }
517 
518  // restore insets
519  constraints.insets = savedInsets;
520  }
521 
525  private void resetComponent() {
526 
527  contactArtifact = null;
528  contactName = null;
529  datasourceName = null;
530 
531  contactUniqueAccountsList.clear();
532  contactUniquePersonasMap.clear();
533 
534  phoneNumList.clear();
535  emailList.clear();
536  nameList.clear();
537  otherList.clear();
538  accountAttributesList.clear();
539 
540  if (personaSearchTask != null) {
541  personaSearchTask.cancel(Boolean.TRUE);
542  personaSearchTask = null;
543  }
544 
545  // clear the panel
546  this.removeAll();
547  this.setLayout(null);
548 
549  m_gridBagLayout = new GridBagLayout();
550  m_constraints = new GridBagConstraints();
551 
552  m_constraints.anchor = GridBagConstraints.LINE_START;
553  m_constraints.gridy = 0;
554  m_constraints.gridx = 0;
555  m_constraints.weighty = 0.0;
556  m_constraints.weightx = 0.0; // keep components fixed horizontally.
557  m_constraints.insets = new java.awt.Insets(0, ContentViewerDefaults.getSectionIndent(), 0, 0);
558  m_constraints.fill = GridBagConstraints.NONE;
559 
560  }
561 
570  private ImageIcon getImageFromArtifact(BlackboardArtifact artifact) {
571  ImageIcon imageIcon = defaultImage;
572 
573  if (artifact == null) {
574  return imageIcon;
575  }
576 
577  BlackboardArtifact.ARTIFACT_TYPE artifactType = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
578  if (artifactType != BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT) {
579  return imageIcon;
580  }
581 
582  try {
583  for (Content content : artifact.getChildren()) {
584  if (content instanceof AbstractFile) {
585  AbstractFile file = (AbstractFile) content;
586 
587  try {
588  BufferedImage image = ImageIO.read(new File(file.getLocalAbsPath()));
589  imageIcon = new ImageIcon(image);
590  break;
591  } catch (IOException ex) {
592  // ImageIO.read will throw an IOException if file is not an image
593  // therefore we don't need to report this exception just try
594  // the next file.
595  }
596  }
597  }
598  } catch (TskCoreException ex) {
599  logger.log(Level.WARNING, String.format("Unable to load image for contact: %d", artifact.getId()), ex);
600  }
601 
602  return imageIcon;
603  }
604 
609  private class ContactPersonaSearcherTask extends SwingWorker<Map<Persona, ArrayList<CentralRepoAccount>>, Void> {
610 
611  private final BlackboardArtifact artifact;
612  private final List<CentralRepoAccount> uniqueAccountsList = new ArrayList<>();
613 
620  ContactPersonaSearcherTask(BlackboardArtifact artifact) {
621  this.artifact = artifact;
622  }
623 
624  @Override
625  protected Map<Persona, ArrayList<CentralRepoAccount>> doInBackground() throws Exception {
626 
627  Map<Persona, ArrayList<CentralRepoAccount>> uniquePersonas = new HashMap<>();
628  CommunicationsManager commManager = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager();
629  List<Account> contactAccountsList = commManager.getAccountsRelatedToArtifact(artifact);
630 
631  for (Account account : contactAccountsList) {
632  try {
633  if (isCancelled()) {
634  return new HashMap<>();
635  }
636 
637  // make a list of all unique accounts for this contact
638  if (!account.getAccountType().equals(Account.Type.DEVICE)) {
639  Optional<CentralRepoAccount.CentralRepoAccountType> optCrAccountType = CentralRepository.getInstance().getAccountTypeByName(account.getAccountType().getTypeName());
640  if (optCrAccountType.isPresent()) {
641  CentralRepoAccount crAccount = CentralRepository.getInstance().getAccount(optCrAccountType.get(), account.getTypeSpecificID());
642 
643  if (crAccount != null && uniqueAccountsList.contains(crAccount) == false) {
644  uniqueAccountsList.add(crAccount);
645  }
646  }
647  }
648 
649  Collection<PersonaAccount> personaAccounts = PersonaAccount.getPersonaAccountsForAccount(account);
650  if (personaAccounts != null && !personaAccounts.isEmpty()) {
651  // get personas for the account
652  Collection<Persona> personas
653  = personaAccounts
654  .stream()
656  .collect(Collectors.toList());
657 
658  // make a list of unique personas, along with all their accounts
659  for (Persona persona : personas) {
660  if (uniquePersonas.containsKey(persona) == false) {
661  Collection<CentralRepoAccount> accounts = persona.getPersonaAccounts()
662  .stream()
664  .collect(Collectors.toList());
665 
666  ArrayList<CentralRepoAccount> personaAccountsList = new ArrayList<>(accounts);
667  uniquePersonas.put(persona, personaAccountsList);
668  }
669  }
670  }
671  } catch (InvalidAccountIDException ex) {
672  // Do nothing, the account has an identifier that not an
673  // acceptable format for the cr.
674  }
675  }
676 
677  return uniquePersonas;
678  }
679 
680  @Override
681  protected void done() {
682 
683  Map<Persona, ArrayList<CentralRepoAccount>> personasMap;
684  try {
685  personasMap = super.get();
686 
687  if (this.isCancelled()) {
688  return;
689  }
690 
691  contactUniquePersonasMap.clear();
692  contactUniquePersonasMap.putAll(personasMap);
693  contactUniqueAccountsList.clear();
694  contactUniqueAccountsList.addAll(uniqueAccountsList);
695 
696  updatePersonas();
697 
698  } catch (CancellationException ex) {
699  logger.log(Level.INFO, "Persona searching was canceled."); //NON-NLS
700  } catch (InterruptedException ex) {
701  logger.log(Level.INFO, "Persona searching was interrupted."); //NON-NLS
702  } catch (ExecutionException ex) {
703  logger.log(Level.SEVERE, "Fatal error during Persona search.", ex); //NON-NLS
704  }
705 
706  }
707  }
708 
713  private class PersonaUIComponents {
714 
715  private final JLabel personaNameLabel;
716  private final JButton personaActionButton;
717 
724  PersonaUIComponents(JLabel personaNameLabel, JButton personaActionButton) {
725  this.personaNameLabel = personaNameLabel;
726  this.personaActionButton = personaActionButton;
727  }
728 
734  public JLabel getPersonaNameLabel() {
735  return personaNameLabel;
736  }
737 
743  public JButton getPersonaActionButton() {
744  return personaActionButton;
745  }
746  }
747 
751  private class CreatePersonaButtonListener implements ActionListener {
752 
753  private final Component parentComponent;
755 
761  CreatePersonaButtonListener(Component parentComponent, PersonaUIComponents personaUIComponents) {
762  this.personaUIComponents = personaUIComponents;
763  this.parentComponent = parentComponent;
764  }
765 
766  @NbBundle.Messages({
767  "ContactArtifactViewer_persona_account_justification=Account found in Contact artifact",
768  "# {0} - accountIdentifer",
769  "ContactArtifactViewer_id_not_found_in_cr=Unable to find account(s) associated with contact {0} in the Central Repository."
770  })
771 
772  @Override
773  public void actionPerformed(java.awt.event.ActionEvent evt) {
774  // Launch the Persona Create dialog - do not display immediately
775  PersonaDetailsDialog createPersonaDialog = new PersonaDetailsDialog(parentComponent,
776  PersonaDetailsMode.CREATE, null, new PersonaCreateCallbackImpl(parentComponent, personaUIComponents), false);
777 
778  // Pre populate the persona name and accounts if we have them.
779  PersonaDetailsPanel personaPanel = createPersonaDialog.getDetailsPanel();
780 
781  if (contactName != null) {
782  personaPanel.setPersonaName(contactName);
783  }
784 
785  // pass the list of accounts to the dialog
786  for (CentralRepoAccount account : contactUniqueAccountsList) {
787  personaPanel.addAccount(account, Bundle.ContactArtifactViewer_persona_account_justification(), Persona.Confidence.HIGH);
788  }
789 
790  if (contactName != null && contactUniqueAccountsList.isEmpty()) {
791  createPersonaDialog.setStartupPopupMessage(Bundle.ContactArtifactViewer_id_not_found_in_cr(contactName));
792  }
793 
794  // display the dialog now
795  createPersonaDialog.display();
796  }
797  }
798 
802  private class ViewPersonaButtonListener implements ActionListener {
803 
804  private final Persona persona;
805  private final Component parentComponent;
806 
812  ViewPersonaButtonListener(Component parentComponent, Persona persona) {
813  this.persona = persona;
814  this.parentComponent = parentComponent;
815  }
816 
817  @Override
818  public void actionPerformed(java.awt.event.ActionEvent evt) {
819  new PersonaDetailsDialog(parentComponent,
820  PersonaDetailsMode.VIEW, persona, new PersonaViewCallbackImpl());
821  }
822  }
823 
827  class PersonaCreateCallbackImpl implements PersonaDetailsDialogCallback {
828 
829  private final Component parentComponent;
830  private final PersonaUIComponents personaUIComponents;
831 
837  PersonaCreateCallbackImpl(Component parentComponent, PersonaUIComponents personaUIComponents) {
838  this.parentComponent = parentComponent;
839  this.personaUIComponents = personaUIComponents;
840  }
841 
842  @Override
843  public void callback(Persona persona) {
844  JButton personaButton = personaUIComponents.getPersonaActionButton();
845  if (persona != null) {
846  // update the persona name label with newly created persona,
847  // and change the button to a "View" button
848  personaUIComponents.getPersonaNameLabel().setText(persona.getName());
849  personaUIComponents.getPersonaActionButton().setText(Bundle.ContactArtifactViewer_persona_button_view());
850 
851  // replace action listener with a View button listener
852  for (ActionListener act : personaButton.getActionListeners()) {
853  personaButton.removeActionListener(act);
854  }
855  personaButton.addActionListener(new ViewPersonaButtonListener(parentComponent, persona));
856 
857  }
858 
859  personaButton.getParent().revalidate();
860  personaButton.getParent().repaint();
861  }
862  }
863 
867  class PersonaViewCallbackImpl implements PersonaDetailsDialogCallback {
868 
869  @Override
870  public void callback(Persona persona) {
871  // nothing to do
872  }
873  }
874 
875  // Variables declaration - do not modify//GEN-BEGIN:variables
876  // End of variables declaration//GEN-END:variables
877 }
boolean addAccount(CentralRepoAccount account, String justification, Persona.Confidence confidence)
static Collection< PersonaAccount > getPersonaAccountsForAccount(long accountId)
void showPersona(Persona persona, int matchNumber, List< CentralRepoAccount > missingAccountsList, GridBagLayout gridBagLayout, GridBagConstraints constraints)
CentralRepoAccount getAccount(CentralRepoAccount.CentralRepoAccountType crAccountType, String accountUniqueID)
void updateContactName(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints)
void updateContactImage(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints)
Optional< CentralRepoAccountType > getAccountTypeByName(String accountTypeName)
void updateContactMethodSection(List< BlackboardAttribute > sectionAttributesList, String sectionHeader, GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124

Copyright © 2012-2021 Basis Technology. Generated on: Thu Sep 30 2021
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.