Autopsy  4.15.0
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 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.concurrent.CancellationException;
36 import java.util.concurrent.ExecutionException;
37 import java.util.logging.Level;
38 import java.util.stream.Collectors;
39 import javax.imageio.ImageIO;
40 import javax.swing.ImageIcon;
41 import javax.swing.JButton;
42 import javax.swing.JLabel;
43 import javax.swing.JScrollPane;
44 import javax.swing.SwingWorker;
45 import org.apache.commons.lang.StringUtils;
46 import org.openide.util.NbBundle;
47 import org.openide.util.lookup.ServiceProvider;
59 import org.sleuthkit.datamodel.AbstractFile;
60 import org.sleuthkit.datamodel.Account;
61 import org.sleuthkit.datamodel.BlackboardArtifact;
62 import org.sleuthkit.datamodel.BlackboardAttribute;
63 import org.sleuthkit.datamodel.CommunicationsManager;
64 import org.sleuthkit.datamodel.Content;
65 import org.sleuthkit.datamodel.TskCoreException;
66 
70 @ServiceProvider(service = ArtifactContentViewer.class)
71 public class ContactArtifactViewer extends javax.swing.JPanel implements ArtifactContentViewer {
72 
73  private final static Logger logger = Logger.getLogger(ContactArtifactViewer.class.getName());
74  private static final long serialVersionUID = 1L;
75 
76  private GridBagLayout m_gridBagLayout = new GridBagLayout();
77  private GridBagConstraints m_constraints = new GridBagConstraints();
78 
79  private JLabel personaSearchStatusLabel;
80 
81  private BlackboardArtifact contactArtifact;
82  private String contactName;
83  private String datasourceName;
84 
85  private List<BlackboardAttribute> phoneNumList = new ArrayList<>();
86  private List<BlackboardAttribute> emailList = new ArrayList<>();
87  private List<BlackboardAttribute> nameList = new ArrayList<>();
88  private List<BlackboardAttribute> otherList = new ArrayList<>();
89  private List<BlackboardAttribute> accountAttributesList = new ArrayList<>();
90 
91  private final static String DEFAULT_IMAGE_PATH = "/org/sleuthkit/autopsy/images/defaultContact.png";
92  private final ImageIcon defaultImage;
93 
94  // A list of unique accounts matching the attributes of the contact artifact.
95  private final List<CentralRepoAccount> contactUniqueAccountsList = new ArrayList<>();
96 
97  // A list of all unique personas and their account, found by searching on the
98  // account identifier attributes of the Contact artifact.
99  private final Map<Persona, ArrayList<CentralRepoAccount>> contactUniquePersonasMap = new HashMap<>();
100 
102 
107  initComponents();
108 
109  defaultImage = new ImageIcon(ContactArtifactViewer.class.getResource(DEFAULT_IMAGE_PATH));
110  }
111 
117  @SuppressWarnings("unchecked")
118  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
119  private void initComponents() {
120 
121  setToolTipText(""); // NOI18N
122  setLayout(new java.awt.GridBagLayout());
123  }// </editor-fold>//GEN-END:initComponents
124 
125  @Override
126  public void setArtifact(BlackboardArtifact artifact) {
127  // Reset the panel.
128  resetComponent();
129 
130  if (artifact == null) {
131  return;
132  }
133 
134  try {
135  extractArtifactData(artifact);
136  } catch (TskCoreException ex) {
137  logger.log(Level.SEVERE, String.format("Error getting attributes for artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex);
138  return;
139  }
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 
166  private void extractArtifactData(BlackboardArtifact artifact) throws TskCoreException {
167 
168  this.contactArtifact = artifact;
169 
170  phoneNumList = new ArrayList<>();
171  emailList = new ArrayList<>();
172  nameList = new ArrayList<>();
173  otherList = new ArrayList<>();
174  accountAttributesList = new ArrayList<>();
175 
176  // Get all the attributes and group them by the section panels they go in
177  for (BlackboardAttribute bba : contactArtifact.getAttributes()) {
178  if (bba.getAttributeType().getTypeName().startsWith("TSK_PHONE")) {
179  phoneNumList.add(bba);
180  accountAttributesList.add(bba);
181  } else if (bba.getAttributeType().getTypeName().startsWith("TSK_EMAIL")) {
182  emailList.add(bba);
183  accountAttributesList.add(bba);
184  } else if (bba.getAttributeType().getTypeName().startsWith("TSK_NAME")) {
185  nameList.add(bba);
186  } else {
187  otherList.add(bba);
188  if (bba.getAttributeType().getTypeName().equalsIgnoreCase("TSK_ID")) {
189  accountAttributesList.add(bba);
190  }
191  }
192  }
193 
194  datasourceName = contactArtifact.getDataSource().getName();
195  }
196 
200  private void updateView() {
201 
202  // Update contact name, image, phone numbers
203  updateContactDetails();
204 
205  // update artifact source panel
206  updateSource();
207 
208  // show a empty Personas panel and kick off a serch for personas
209  initiatePersonasSearch();
210 
211  }
212 
216  @NbBundle.Messages({
217  "ContactArtifactViewer_phones_header=Phone",
218  "ContactArtifactViewer_emails_header=Email",
219  "ContactArtifactViewer_others_header=Other",})
220  private void updateContactDetails() {
221 
222  // update image and name.
223  updateContactImage(m_gridBagLayout, m_constraints);
224  updateContactName(m_gridBagLayout, m_constraints);
225 
226  // update contact attributes sections
227  updateContactMethodSection(phoneNumList, Bundle.ContactArtifactViewer_phones_header(), m_gridBagLayout, m_constraints);
228  updateContactMethodSection(emailList, Bundle.ContactArtifactViewer_emails_header(), m_gridBagLayout, m_constraints);
229  updateContactMethodSection(otherList, Bundle.ContactArtifactViewer_others_header(), m_gridBagLayout, m_constraints);
230  }
231 
239  @NbBundle.Messages({
240  "ContactArtifactViewer.contactImage.text=",})
241  private void updateContactImage(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) {
242  // place the image on the top right corner
243  Insets savedInsets = contactPanelConstraints.insets;
244  contactPanelConstraints.gridy = 0;
245  contactPanelConstraints.gridx = 0;
246  contactPanelConstraints.insets = new Insets(0, 0, 0, 0);
247 
248  javax.swing.JLabel contactImage = new javax.swing.JLabel();
249  contactImage.setIcon(getImageFromArtifact(contactArtifact));
250  contactImage.setText(Bundle.ContactArtifactViewer_contactImage_text());
251 
252  // add image to top left corner of the page.
253  CommunicationArtifactViewerHelper.addComponent(this, contactPanelLayout, contactPanelConstraints, contactImage);
254  CommunicationArtifactViewerHelper.addLineEndGlue(this, contactPanelLayout, contactPanelConstraints);
255  contactPanelConstraints.gridy++;
256 
257  contactPanelConstraints.insets = savedInsets;
258  }
259 
267  @NbBundle.Messages({
268  "ContactArtifactViewer_contactname_unknown=Unknown",})
269  private void updateContactName(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) {
270 
271  boolean foundName = false;
272  for (BlackboardAttribute bba : this.nameList) {
273  if (StringUtils.isEmpty(bba.getValueString()) == false) {
274  contactName = bba.getDisplayString();
275 
276  CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, contactName);
277  foundName = true;
278  break;
279  }
280  }
281  if (foundName == false) {
282  CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, Bundle.ContactArtifactViewer_contactname_unknown());
283  }
284  }
285 
296  @NbBundle.Messages({
297  "ContactArtifactViewer_plural_suffix=s",})
298  private void updateContactMethodSection(List<BlackboardAttribute> sectionAttributesList, String sectionHeader, GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) {
299 
300  // If there are no attributes for this section, do nothing
301  if (sectionAttributesList.isEmpty()) {
302  return;
303  }
304 
305  String sectionHeaderString = sectionHeader;
306  if (sectionAttributesList.size() > 1) {
307  sectionHeaderString = sectionHeaderString.concat(Bundle.ContactArtifactViewer_plural_suffix());
308  }
309  CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, sectionHeaderString);
310  for (BlackboardAttribute bba : sectionAttributesList) {
311  CommunicationArtifactViewerHelper.addKey(this, contactPanelLayout, contactPanelConstraints, bba.getAttributeType().getDisplayName());
312  CommunicationArtifactViewerHelper.addValue(this, contactPanelLayout, contactPanelConstraints, bba.getDisplayString());
313  }
314  }
315 
319  @NbBundle.Messages({
320  "ContactArtifactViewer_heading_Source=Source",
321  "ContactArtifactViewer_label_datasource=Data Source",})
322  private void updateSource() {
323  CommunicationArtifactViewerHelper.addHeader(this, this.m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_heading_Source());
324  CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_label_datasource());
325  CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, m_constraints, datasourceName);
326  }
327 
333  @NbBundle.Messages({
334  "ContactArtifactViewer_persona_header=Persona",
335  "ContactArtifactViewer_persona_searching=Searching...",
336  "ContactArtifactViewer_cr_disabled_message=Enable Central Repository to view, create and edit personas.",
337  "ContactArtifactViewer_persona_unknown=Unknown"
338  })
339  private void initiatePersonasSearch() {
340 
341  // add a section header
342  JLabel personaHeader = CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_persona_header());
343 
344  m_constraints.gridy++;
345 
346  // add a status label
347  String personaStatusLabelText = CentralRepository.isEnabled()
348  ? Bundle.ContactArtifactViewer_persona_searching()
349  : Bundle.ContactArtifactViewer_persona_unknown();
350 
351  this.personaSearchStatusLabel = new javax.swing.JLabel();
352  personaSearchStatusLabel.setText(personaStatusLabelText);
353 
354  m_constraints.gridx = 0;
355 
356  CommunicationArtifactViewerHelper.addComponent(this, m_gridBagLayout, m_constraints, personaSearchStatusLabel);
357 
359  // Kick off a background task to serach for personas for the contact
360  personaSearchTask = new ContactPersonaSearcherTask(contactArtifact);
361  personaSearchTask.execute();
362  } else {
363  personaHeader.setEnabled(false);
364  personaSearchStatusLabel.setEnabled(false);
365 
366  CommunicationArtifactViewerHelper.addBlankLine(this, m_gridBagLayout, m_constraints);
367  m_constraints.gridy++;
368  CommunicationArtifactViewerHelper.addMessageRow(this, m_gridBagLayout, 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  // some label are indented 2x to appear indented w.r.t column above
443  Insets extraIndentInsets = new java.awt.Insets(0, 2 * CommunicationArtifactViewerHelper.LEFT_INSET, 0, 0);
444 
445  // Add a Match X label in col 0.
446  constraints.gridx = 0;
447  javax.swing.JLabel matchNumberLabel = CommunicationArtifactViewerHelper.addKey(this, gridBagLayout, constraints, String.format("%s %d", Bundle.ContactArtifactViewer_persona_match_num(), matchNumber));
448 
449  javax.swing.JLabel personaNameLabel = new javax.swing.JLabel();
450  javax.swing.JButton personaButton = new javax.swing.JButton();
451 
452  String personaName;
453  String personaButtonText;
454  ActionListener personaButtonListener;
455  if (persona != null) {
456  personaName = persona.getName();
457  personaButtonText = Bundle.ContactArtifactViewer_persona_button_view();
458  personaButtonListener = new ViewPersonaButtonListener(this, persona);
459  } else {
460  matchNumberLabel.setVisible(false);
461  personaName = Bundle.ContactArtifactViewer_persona_no_match();
462  personaButtonText = Bundle.ContactArtifactViewer_persona_button_new();
463  personaButtonListener = new CreatePersonaButtonListener(this, new PersonaUIComponents(personaNameLabel, personaButton));
464  }
465 
466  //constraints.gridwidth = 1; // TBD: this may not be needed if we use single panel
467  constraints.gridx++;
468  personaNameLabel.setText(personaName);
469  gridBagLayout.setConstraints(personaNameLabel, constraints);
470  CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, personaNameLabel);
471  //personasPanel.add(personaNameLabel);
472 
473  // Add a Persona action button
474  constraints.gridx++;
475  //constraints.gridwidth = 1;
476  personaButton.setText(personaButtonText);
477  personaButton.addActionListener(personaButtonListener);
478 
479  // Shirnk the button height.
480  personaButton.setMargin(new Insets(0, 5, 0, 5));
481  gridBagLayout.setConstraints(personaButton, constraints);
482  CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, personaButton);
483  CommunicationArtifactViewerHelper.addLineEndGlue(this, gridBagLayout, constraints);
484 
485  constraints.insets = savedInsets;
486 
487  // if we have a persona, indicate if any of the contact's accounts are missing from it.
488  if (persona != null) {
489  if (missingAccountsList.isEmpty()) {
490  constraints.gridy++;
491  constraints.gridx = 1;
492  //constraints.insets = labelInsets;
493 
494  javax.swing.JLabel accountsStatus = new javax.swing.JLabel(Bundle.ContactArtifactViewer_found_all_accounts_label());
495  constraints.insets = extraIndentInsets;
496  CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, accountsStatus);
497  constraints.insets = savedInsets;
498 
499  CommunicationArtifactViewerHelper.addLineEndGlue(this, gridBagLayout, constraints);
500  } else {
501  // show missing accounts.
502  for (CentralRepoAccount missingAccount : missingAccountsList) {
503  //constraints.weightx = 0;
504  constraints.gridx = 0;
505  constraints.gridy++;
506 
507  // this needs an extra indent
508  constraints.insets = extraIndentInsets;
509  CommunicationArtifactViewerHelper.addKeyAtCol(this, gridBagLayout, constraints, Bundle.ContactArtifactViewer_missing_account_label(), 1);
510  constraints.insets = savedInsets;
511 
512  CommunicationArtifactViewerHelper.addValueAtCol(this, gridBagLayout, constraints, missingAccount.getIdentifier(), 2);
513  }
514  }
515  }
516 
517  // restore insets
518  constraints.insets = savedInsets;
519  }
520 
524  private void resetComponent() {
525 
526  contactArtifact = null;
527  contactName = null;
528  datasourceName = null;
529 
530  contactUniqueAccountsList.clear();
531  contactUniquePersonasMap.clear();
532 
533  phoneNumList.clear();
534  emailList.clear();
535  nameList.clear();
536  otherList.clear();
537  accountAttributesList.clear();
538 
539  if (personaSearchTask != null) {
540  personaSearchTask.cancel(Boolean.TRUE);
541  personaSearchTask = null;
542  }
543 
544  // clear the panel
545  this.removeAll();
546  this.setLayout(null);
547 
548  m_gridBagLayout = new GridBagLayout();
549  m_constraints = new GridBagConstraints();
550 
551  m_constraints.anchor = GridBagConstraints.FIRST_LINE_START;
552  m_constraints.gridy = 0;
553  m_constraints.gridx = 0;
554  m_constraints.weighty = 0.0;
555  m_constraints.weightx = 0.0; // keep components fixed horizontally.
556  m_constraints.insets = new java.awt.Insets(0, CommunicationArtifactViewerHelper.LEFT_INSET, 0, 0);
557  m_constraints.fill = GridBagConstraints.NONE;
558 
559  }
560 
569  private ImageIcon getImageFromArtifact(BlackboardArtifact artifact) {
570  ImageIcon imageIcon = defaultImage;
571 
572  if (artifact == null) {
573  return imageIcon;
574  }
575 
576  BlackboardArtifact.ARTIFACT_TYPE artifactType = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
577  if (artifactType != BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT) {
578  return imageIcon;
579  }
580 
581  try {
582  for (Content content : artifact.getChildren()) {
583  if (content instanceof AbstractFile) {
584  AbstractFile file = (AbstractFile) content;
585 
586  try {
587  BufferedImage image = ImageIO.read(new File(file.getLocalAbsPath()));
588  imageIcon = new ImageIcon(image);
589  break;
590  } catch (IOException ex) {
591  // ImageIO.read will throw an IOException if file is not an image
592  // therefore we don't need to report this exception just try
593  // the next file.
594  }
595  }
596  }
597  } catch (TskCoreException ex) {
598  logger.log(Level.WARNING, String.format("Unable to load image for contact: %d", artifact.getId()), ex);
599  }
600 
601  return imageIcon;
602  }
603 
608  private class ContactPersonaSearcherTask extends SwingWorker<Map<Persona, ArrayList<CentralRepoAccount>>, Void> {
609 
610  private final BlackboardArtifact artifact;
611  private final List<CentralRepoAccount> uniqueAccountsList = new ArrayList<>();
612 
619  ContactPersonaSearcherTask(BlackboardArtifact artifact) {
620  this.artifact = artifact;
621  }
622 
623  @Override
624  protected Map<Persona, ArrayList<CentralRepoAccount>> doInBackground() throws Exception {
625 
626  Map<Persona, ArrayList<CentralRepoAccount>> uniquePersonas = new HashMap<>();
627 
628  CommunicationsManager commManager = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager();
629  List<Account> contactAccountsList = commManager.getAccountsRelatedToArtifact(artifact);
630 
631  for (Account account : contactAccountsList) {
632  if (isCancelled()) {
633  return new HashMap<>();
634  }
635 
636  Collection<PersonaAccount> personaAccounts = PersonaAccount.getPersonaAccountsForAccount(account);
637  if (personaAccounts != null && !personaAccounts.isEmpty()) {
638 
639  // look for unique accounts
640  Collection<CentralRepoAccount> accountCandidates
641  = personaAccounts
642  .stream()
644  .collect(Collectors.toList());
645  for (CentralRepoAccount crAccount : accountCandidates) {
646  if (uniqueAccountsList.contains(crAccount) == false) {
647  uniqueAccountsList.add(crAccount);
648  }
649  }
650 
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  }
672 
673  return uniquePersonas;
674  }
675 
676  @Override
677  protected void done() {
678 
679  Map<Persona, ArrayList<CentralRepoAccount>> personasMap;
680  try {
681  personasMap = super.get();
682 
683  if (this.isCancelled()) {
684  return;
685  }
686 
687  contactUniquePersonasMap.clear();
688  contactUniquePersonasMap.putAll(personasMap);
689  contactUniqueAccountsList.clear();
690  contactUniqueAccountsList.addAll(uniqueAccountsList);
691 
692  updatePersonas();
693 
694  } catch (CancellationException ex) {
695  logger.log(Level.INFO, "Persona searching was canceled."); //NON-NLS
696  } catch (InterruptedException ex) {
697  logger.log(Level.INFO, "Persona searching was interrupted."); //NON-NLS
698  } catch (ExecutionException ex) {
699  logger.log(Level.SEVERE, "Fatal error during Persona search.", ex); //NON-NLS
700  }
701 
702  }
703  }
704 
709  private class PersonaUIComponents {
710 
711  private final JLabel personaNameLabel;
712  private final JButton personaActionButton;
713 
720  PersonaUIComponents(JLabel personaNameLabel, JButton personaActionButton) {
721  this.personaNameLabel = personaNameLabel;
722  this.personaActionButton = personaActionButton;
723  }
724 
730  public JLabel getPersonaNameLabel() {
731  return personaNameLabel;
732  }
733 
739  public JButton getPersonaActionButton() {
740  return personaActionButton;
741  }
742  }
743 
747  private class CreatePersonaButtonListener implements ActionListener {
748 
749  private final Component parentComponent;
751 
757  CreatePersonaButtonListener(Component parentComponent, PersonaUIComponents personaUIComponents) {
758  this.personaUIComponents = personaUIComponents;
759  this.parentComponent = parentComponent;
760  }
761 
762  @NbBundle.Messages({
763  "ContactArtifactViewer_persona_account_justification=Account found in Contact artifact"
764  })
765 
766  @Override
767  public void actionPerformed(java.awt.event.ActionEvent evt) {
768  // Launch the Persona Create dialog - do not display immediately
769  PersonaDetailsDialog createPersonaDialog = new PersonaDetailsDialog(parentComponent,
770  PersonaDetailsMode.CREATE, null, new PersonaCreateCallbackImpl(parentComponent, personaUIComponents), false);
771 
772  // Pre populate the persona name and accounts if we have them.
773  PersonaDetailsPanel personaPanel = createPersonaDialog.getDetailsPanel();
774 
775  if (contactName != null) {
776  personaPanel.setPersonaName(contactName);
777  }
778 
779  // pass the list of accounts to the dialog
780  for (CentralRepoAccount account : contactUniqueAccountsList) {
781  personaPanel.addAccount(account, Bundle.ContactArtifactViewer_persona_account_justification(), Persona.Confidence.HIGH);
782  }
783 
784  // display the dialog now
785  createPersonaDialog.display();
786  }
787  }
788 
792  private class ViewPersonaButtonListener implements ActionListener {
793 
794  private final Persona persona;
795  private final Component parentComponent;
796 
802  ViewPersonaButtonListener(Component parentComponent, Persona persona) {
803  this.persona = persona;
804  this.parentComponent = parentComponent;
805  }
806 
807  @Override
808  public void actionPerformed(java.awt.event.ActionEvent evt) {
809  new PersonaDetailsDialog(parentComponent,
810  PersonaDetailsMode.VIEW, persona, new PersonaViewCallbackImpl());
811  }
812  }
813 
817  class PersonaCreateCallbackImpl implements PersonaDetailsDialogCallback {
818 
819  private final Component parentComponent;
820  private final PersonaUIComponents personaUIComponents;
821 
827  PersonaCreateCallbackImpl(Component parentComponent, PersonaUIComponents personaUIComponents) {
828  this.parentComponent = parentComponent;
829  this.personaUIComponents = personaUIComponents;
830  }
831 
832  @Override
833  public void callback(Persona persona) {
834  JButton personaButton = personaUIComponents.getPersonaActionButton();
835  if (persona != null) {
836  // update the persona name label with newly created persona,
837  // and change the button to a "View" button
838  personaUIComponents.getPersonaNameLabel().setText(persona.getName());
839  personaUIComponents.getPersonaActionButton().setText(Bundle.ContactArtifactViewer_persona_button_view());
840 
841  // replace action listener with a View button listener
842  for (ActionListener act : personaButton.getActionListeners()) {
843  personaButton.removeActionListener(act);
844  }
845  personaButton.addActionListener(new ViewPersonaButtonListener(parentComponent, persona));
846 
847  }
848 
849  personaButton.getParent().revalidate();
850  personaButton.getParent().repaint();
851  }
852  }
853 
857  class PersonaViewCallbackImpl implements PersonaDetailsDialogCallback {
858 
859  @Override
860  public void callback(Persona persona) {
861  // nothing to do
862  }
863  }
864 
865  // Variables declaration - do not modify//GEN-BEGIN:variables
866  // End of variables declaration//GEN-END:variables
867 }
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)
void updateContactName(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints)
void updateContactImage(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints)
void updateContactMethodSection(List< BlackboardAttribute > sectionAttributesList, String sectionHeader, GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124

Copyright © 2012-2020 Basis Technology. Generated on: Mon Jul 6 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.