mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-17 18:17:43 +00:00
Data source summary recent file panel
This commit is contained in:
parent
71a896a494
commit
f8aaa4bc25
@ -0,0 +1,399 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> 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.datasourcesummary.datamodel;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG;
|
||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE;
|
||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_RECENT_OBJECT;
|
||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
|
||||
|
||||
/**
|
||||
* Helper class for getting data for the Recent Files Data Summary tab.
|
||||
*/
|
||||
public class RecentFilesSummary {
|
||||
|
||||
private final static BlackboardAttribute.Type DATETIME_ACCESSED_ATT = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED);
|
||||
private final static BlackboardAttribute.Type DOMAIN_ATT = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN);
|
||||
private final static BlackboardAttribute.Type PATH_ATT = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH);
|
||||
private final static BlackboardAttribute.Type DATETIME_ATT = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
|
||||
private final static BlackboardAttribute.Type ASSOCATED_ATT = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT);
|
||||
private final static BlackboardAttribute.Type EMAIL_FROM_ATT = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_FROM);
|
||||
private final static BlackboardArtifact.Type ASSOCATED_OBJ_ART = new BlackboardArtifact.Type(BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT);
|
||||
|
||||
private static final DateFormat DATETIME_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.getDefault());
|
||||
|
||||
private final SleuthkitCaseProvider provider;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public RecentFilesSummary() {
|
||||
this(SleuthkitCaseProvider.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct object with given SleuthkitCaseProvider
|
||||
*
|
||||
* @param provider SleuthkitCaseProvider provider, cannot be null.
|
||||
*/
|
||||
public RecentFilesSummary(SleuthkitCaseProvider provider) {
|
||||
if (provider == null) {
|
||||
throw new IllegalArgumentException("Unable to construct RecentFileSummary object. SleuthkitCaseProvider cannot be null");
|
||||
}
|
||||
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of the most recently opened documents based on the
|
||||
* TSK_RECENT_OBJECT artifact.
|
||||
*
|
||||
* @param dataSource The data source to query.
|
||||
* @param maxCount The maximum number of results to return, pass 0 to get
|
||||
* a list of all results.
|
||||
*
|
||||
* @return A list RecentFileDetails representing the most recently opened
|
||||
* documents or an empty list if none were found.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public List<RecentFileDetails> getRecentlyOpenedDocuments(DataSource dataSource, int maxCount) throws SleuthkitCaseProviderException, TskCoreException {
|
||||
if (dataSource == null) {
|
||||
throw new IllegalArgumentException("Failed to get recently opened documents given data source was null");
|
||||
}
|
||||
|
||||
List<BlackboardArtifact> artifactList
|
||||
= DataSourceInfoUtilities.getArtifacts(provider.get(),
|
||||
new BlackboardArtifact.Type(TSK_RECENT_OBJECT),
|
||||
dataSource,
|
||||
DATETIME_ATT,
|
||||
DataSourceInfoUtilities.SortOrder.DESCENDING,
|
||||
10);
|
||||
|
||||
List<RecentFileDetails> fileDetails = new ArrayList<>();
|
||||
for (BlackboardArtifact artifact : artifactList) {
|
||||
Long accessedTime = null;
|
||||
String path = "";
|
||||
|
||||
// Get all the attributes in one call.
|
||||
List<BlackboardAttribute> attributeList = artifact.getAttributes();
|
||||
for (BlackboardAttribute attribute : attributeList) {
|
||||
|
||||
if (attribute.getAttributeType().equals(DATETIME_ATT)) {
|
||||
accessedTime = attribute.getValueLong();
|
||||
} else if (attribute.getAttributeType().equals(PATH_ATT)) {
|
||||
path = attribute.getValueString();
|
||||
}
|
||||
|
||||
if (accessedTime != null) {
|
||||
fileDetails.add(new RecentFileDetails(path, accessedTime));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return fileDetails;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of the most recent downloads based on the value of the the
|
||||
* artifact TSK_DATETIME_ACCESSED attribute.
|
||||
*
|
||||
* @param dataSource Data source to query.
|
||||
* @param maxCount Maximum number of results to return, passing 0 will
|
||||
* return all results.
|
||||
*
|
||||
* @return A list of RecentFileDetails objects or empty list if none were
|
||||
* found.
|
||||
*
|
||||
* @throws TskCoreException
|
||||
* @throws SleuthkitCaseProviderException
|
||||
*/
|
||||
public List<RecentDownloadDetails> getRecentDownloads(DataSource dataSource, int maxCount) throws TskCoreException, SleuthkitCaseProviderException {
|
||||
List<BlackboardArtifact> artifactList
|
||||
= DataSourceInfoUtilities.getArtifacts(provider.get(),
|
||||
new BlackboardArtifact.Type(TSK_WEB_DOWNLOAD),
|
||||
dataSource,
|
||||
DATETIME_ACCESSED_ATT,
|
||||
DataSourceInfoUtilities.SortOrder.DESCENDING,
|
||||
maxCount);
|
||||
|
||||
List<RecentDownloadDetails> fileDetails = new ArrayList<>();
|
||||
for (BlackboardArtifact artifact : artifactList) {
|
||||
// Get all the attributes in one call.
|
||||
Long accessedTime = null;
|
||||
String domain = "";
|
||||
String path = "";
|
||||
|
||||
List<BlackboardAttribute> attributeList = artifact.getAttributes();
|
||||
for (BlackboardAttribute attribute : attributeList) {
|
||||
|
||||
if (attribute.getAttributeType().equals(DATETIME_ACCESSED_ATT)) {
|
||||
accessedTime = attribute.getValueLong();
|
||||
} else if (attribute.getAttributeType().equals(DOMAIN_ATT)) {
|
||||
domain = attribute.getValueString();
|
||||
} else if (attribute.getAttributeType().equals(PATH_ATT)) {
|
||||
path = attribute.getValueString();
|
||||
}
|
||||
}
|
||||
if (accessedTime != null) {
|
||||
fileDetails.add(new RecentDownloadDetails(path, accessedTime, domain));
|
||||
}
|
||||
}
|
||||
|
||||
return fileDetails;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of the most recent message attachments.
|
||||
*
|
||||
* @param dataSource Data source to query.
|
||||
* @param maxCount Maximum number of results to return, passing 0 will
|
||||
* return all results.
|
||||
*
|
||||
* @return A list of RecentFileDetails of the most recent attachments.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public List<RecentAttachmentDetails> getRecentAttachments(DataSource dataSource, int maxCount) throws SleuthkitCaseProviderException, TskCoreException {
|
||||
return createListFromMap(buildAttachmentMap(dataSource), maxCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a map of all of the message attachment sorted in date order.
|
||||
*
|
||||
* @param dataSource Data source to query.
|
||||
*
|
||||
* @return Returns a SortedMap of details objects returned in descending
|
||||
* order.
|
||||
*
|
||||
* @throws SleuthkitCaseProviderException
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
private SortedMap<Long, List<RecentAttachmentDetails>> buildAttachmentMap(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException {
|
||||
SleuthkitCase skCase = provider.get();
|
||||
TreeMap<Long, List<RecentAttachmentDetails>> sortedMap = new TreeMap<>();
|
||||
|
||||
List<BlackboardArtifact> associatedArtifacts = skCase.getBlackboard().getArtifacts(ASSOCATED_OBJ_ART.getTypeID(), dataSource.getId());
|
||||
for (BlackboardArtifact artifact : associatedArtifacts) {
|
||||
BlackboardAttribute attribute = artifact.getAttribute(ASSOCATED_ATT);
|
||||
if (attribute == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BlackboardArtifact messageArtifact = skCase.getBlackboardArtifact(attribute.getValueLong());
|
||||
if (isMessageArtifact(messageArtifact)) {
|
||||
Content content = artifact.getParent();
|
||||
if (content instanceof AbstractFile) {
|
||||
String sender;
|
||||
Long date;
|
||||
String path;
|
||||
|
||||
BlackboardAttribute senderAttribute = messageArtifact.getAttribute(EMAIL_FROM_ATT);
|
||||
if (senderAttribute != null) {
|
||||
sender = senderAttribute.getValueString();
|
||||
} else {
|
||||
sender = "";
|
||||
}
|
||||
AbstractFile abstractFile = (AbstractFile) content;
|
||||
date = abstractFile.getCrtime();
|
||||
path = Paths.get(abstractFile.getParentPath(), abstractFile.getName()).toString();
|
||||
|
||||
List<RecentAttachmentDetails> list = sortedMap.get(date);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
sortedMap.put(date, list);
|
||||
}
|
||||
|
||||
list.add(new RecentAttachmentDetails(path, date, sender));
|
||||
}
|
||||
}
|
||||
}
|
||||
return sortedMap.descendingMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a list of detail objects from the given sorted map of the max
|
||||
* size.
|
||||
*
|
||||
* @param sortedMap A Map of attachment details sorted by date.
|
||||
* @param maxCount Maximum number of values to return.
|
||||
*
|
||||
* @return A list of the details of the most recent attachments or empty
|
||||
* list if none where found.
|
||||
*/
|
||||
private List<RecentAttachmentDetails> createListFromMap(SortedMap<Long, List<RecentAttachmentDetails>> sortedMap, int maxCount) {
|
||||
List<RecentAttachmentDetails> fileList = new ArrayList<>();
|
||||
|
||||
for (List<RecentAttachmentDetails> mapList : sortedMap.values()) {
|
||||
if (maxCount == 0 || fileList.size() + mapList.size() <= maxCount) {
|
||||
fileList.addAll(mapList);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (maxCount == fileList.size()) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (RecentAttachmentDetails details : mapList) {
|
||||
if (fileList.size() < maxCount) {
|
||||
fileList.add(details);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fileList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the given artifact a message.
|
||||
*
|
||||
* @param nodeArtifact An artifact that might be a message. Must not be
|
||||
* null.
|
||||
*
|
||||
* @return True if the given artifact is a message artifact
|
||||
*/
|
||||
private boolean isMessageArtifact(BlackboardArtifact nodeArtifact) {
|
||||
final int artifactTypeID = nodeArtifact.getArtifactTypeID();
|
||||
return artifactTypeID == TSK_EMAIL_MSG.getTypeID()
|
||||
|| artifactTypeID == TSK_MESSAGE.getTypeID();
|
||||
}
|
||||
|
||||
/**
|
||||
* General data model object for files object.
|
||||
*/
|
||||
public static class RecentFileDetails {
|
||||
|
||||
private final String path;
|
||||
private final long date;
|
||||
|
||||
/**
|
||||
* Constructor for files with just a path and date.
|
||||
*
|
||||
* @param path File path.
|
||||
* @param date File access date\time in seconds with java epoch
|
||||
*/
|
||||
RecentFileDetails(String path, long date) {
|
||||
this.path = path;
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the formatted date because the JTablePanel render assumes
|
||||
* only string data.
|
||||
*
|
||||
* @return Formatted date time.
|
||||
*/
|
||||
public String getDate() {
|
||||
return DATETIME_FORMAT.format(date * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file path.
|
||||
*
|
||||
* @return The file path.
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Data model for recently downloaded files.
|
||||
*/
|
||||
public static class RecentDownloadDetails extends RecentFileDetails {
|
||||
|
||||
private final String webDomain;
|
||||
|
||||
/**
|
||||
* Constructor for files with just a path and date.
|
||||
*
|
||||
* @param path File path.
|
||||
* @param date File access date\time in seconds with java epoch.
|
||||
* @param webDomain The webdomain from which the file was downloaded.
|
||||
*/
|
||||
RecentDownloadDetails(String path, long date, String webDomain) {
|
||||
super(path, date);
|
||||
this.webDomain = webDomain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the web domain.
|
||||
*
|
||||
* @return The web domain or empty string if not available or
|
||||
* applicable.
|
||||
*/
|
||||
public String getWebDomain() {
|
||||
return webDomain;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Data model for recently attachments.
|
||||
*/
|
||||
public static class RecentAttachmentDetails extends RecentFileDetails {
|
||||
|
||||
private final String sender;
|
||||
|
||||
/**
|
||||
* Constructor for recent download files which have a path, date and
|
||||
* domain value.
|
||||
*
|
||||
* @param path File path.
|
||||
* @param date File crtime.
|
||||
* @param sender The sender of the message from which the
|
||||
* file was attached.
|
||||
*/
|
||||
RecentAttachmentDetails(String path, long date, String sender) {
|
||||
super(path, date);
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the sender of the attached file.
|
||||
*
|
||||
* @return The sender of the attached file or empty string if not
|
||||
* available.
|
||||
*/
|
||||
public String getSender() {
|
||||
return sender;
|
||||
}
|
||||
}
|
||||
}
|
@ -37,3 +37,6 @@ DataSourceSummaryCountsPanel.byCategoryLabel.text=Files by Category
|
||||
DataSourceSummaryCountsPanel.resultsByTypeLabel.text=Results by Type
|
||||
DataSourceSummaryUserActivityPanel.programsRunLabel.text=Recent Programs
|
||||
DataSourceSummaryUserActivityPanel.recentDomainsLabel.text=Recent Domains
|
||||
RecentFilesPanel.openDocsLabel.text=Recently Opened Documents
|
||||
RecentFilesPanel.downloadLabel.text=Recent Downloads
|
||||
RecentFilesPanel.attachmentLabel.text=Recent Attachements
|
||||
|
@ -72,6 +72,7 @@ DataSourceSummaryNode.viewDataSourceAction.text=Go to Data Source
|
||||
DataSourceSummaryTabbedPane_countsTab_title=Counts
|
||||
DataSourceSummaryTabbedPane_detailsTab_title=Details
|
||||
DataSourceSummaryTabbedPane_ingestHistoryTab_title=Ingest History
|
||||
DataSourceSummaryTabbedPane_recentFileTab_title=Recent Files
|
||||
DataSourceSummaryTabbedPane_userActivityTab_title=User Activity
|
||||
DataSourceSummaryUserActivityPanel.programsRunLabel.text=Recent Programs
|
||||
DataSourceSummaryUserActivityPanel.recentDomainsLabel.text=Recent Domains
|
||||
@ -84,4 +85,12 @@ DataSourceSummaryUserActivityPanel_TopProgramsTableModel_count_header=Run Times
|
||||
DataSourceSummaryUserActivityPanel_TopProgramsTableModel_folder_header=Folder
|
||||
DataSourceSummaryUserActivityPanel_TopProgramsTableModel_lastrun_header=Last Run
|
||||
DataSourceSummaryUserActivityPanel_TopProgramsTableModel_name_header=Program
|
||||
RecentFilePanel_col_header_domain=Domain
|
||||
RecentFilePanel_col_header_path=Path
|
||||
RecentFilePanel_col_header_sender=Sender
|
||||
RecentFilePanel_no_open_documents=No recently open documents found.
|
||||
RecentFilesPanel.openDocsLabel.text=Recently Opened Documents
|
||||
RecentFilesPanel.downloadLabel.text=Recent Downloads
|
||||
RecentFilesPanel.attachmentLabel.text=Recent Attachements
|
||||
RecentFilesPanel_col_head_date=Date
|
||||
ViewSummaryInformationAction.name.text=View Summary Information
|
||||
|
@ -35,7 +35,8 @@ import org.sleuthkit.datamodel.DataSource;
|
||||
"DataSourceSummaryTabbedPane_countsTab_title=Counts",
|
||||
"DataSourceSummaryTabbedPane_detailsTab_title=Details",
|
||||
"DataSourceSummaryTabbedPane_userActivityTab_title=User Activity",
|
||||
"DataSourceSummaryTabbedPane_ingestHistoryTab_title=Ingest History"
|
||||
"DataSourceSummaryTabbedPane_ingestHistoryTab_title=Ingest History",
|
||||
"DataSourceSummaryTabbedPane_recentFileTab_title=Recent Files"
|
||||
})
|
||||
public class DataSourceSummaryTabbedPane extends JTabbedPane {
|
||||
|
||||
@ -45,7 +46,8 @@ public class DataSourceSummaryTabbedPane extends JTabbedPane {
|
||||
private final List<Pair<String, BaseDataSourceSummaryPanel>> tabs = Arrays.asList(
|
||||
Pair.of(Bundle.DataSourceSummaryTabbedPane_detailsTab_title(), new DataSourceSummaryDetailsPanel()),
|
||||
Pair.of(Bundle.DataSourceSummaryTabbedPane_countsTab_title(), new DataSourceSummaryCountsPanel()),
|
||||
Pair.of(Bundle.DataSourceSummaryTabbedPane_detailsTab_title(), new DataSourceSummaryUserActivityPanel())
|
||||
Pair.of(Bundle.DataSourceSummaryTabbedPane_userActivityTab_title(), new DataSourceSummaryUserActivityPanel()),
|
||||
Pair.of(Bundle.DataSourceSummaryTabbedPane_recentFileTab_title(), new RecentFilesPanel())
|
||||
);
|
||||
|
||||
private final IngestJobInfoPanel ingestHistoryPanel = new IngestJobInfoPanel();
|
||||
|
92
Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.form
Executable file
92
Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.form
Executable file
@ -0,0 +1,92 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JPanel" name="openedDocPane">
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new JTablePanel<RecentFileDetails>()"/>
|
||||
</AuxValues>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="0" insetsRight="5" anchor="11" weightX="1.0" weightY="1.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="downloadsPane">
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new JTablePanel<RecentDownloadDetails>()"/>
|
||||
</AuxValues>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="0" insetsRight="5" anchor="11" weightX="1.0" weightY="1.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="attachmentsPane">
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new JTablePanel<RecentAttachmentDetails>()"/>
|
||||
</AuxValues>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="5" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="10" insetsRight="5" anchor="11" weightX="1.0" weightY="1.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
|
||||
</Container>
|
||||
<Component class="javax.swing.JLabel" name="openDocsLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties" key="RecentFilesPanel.openDocsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="10" insetsLeft="5" insetsBottom="0" insetsRight="5" anchor="11" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="downloadLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties" key="RecentFilesPanel.downloadLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="15" insetsLeft="5" insetsBottom="0" insetsRight="5" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="attachmentLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties" key="RecentFilesPanel.attachmentLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="4" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="15" insetsLeft="5" insetsBottom="0" insetsRight="5" anchor="11" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
294
Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java
Executable file
294
Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java
Executable file
@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> 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.datasourcesummary.ui;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentAttachmentDetails;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentDownloadDetails;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentFileDetails;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.DefaultCellModel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel.ColumnModel;
|
||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ListTableModel;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
|
||||
/**
|
||||
* Data Source Summary recent files panel.
|
||||
*/
|
||||
public final class RecentFilesPanel extends BaseDataSourceSummaryPanel {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final List<JTablePanel<?>> tablePanelList = new ArrayList<>();
|
||||
private final List<DataFetchWorker.DataFetchComponents<DataSource, ?>> dataFetchComponents = new ArrayList<>();
|
||||
|
||||
private final RecentFilesSummary dataHandler;
|
||||
|
||||
@Messages({
|
||||
"RecentFilesPanel_col_head_date=Date",
|
||||
"RecentFilePanel_col_header_domain=Domain",
|
||||
"RecentFilePanel_col_header_path=Path",
|
||||
"RecentFilePanel_col_header_sender=Sender"
|
||||
})
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public RecentFilesPanel() {
|
||||
this(new RecentFilesSummary());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new form RecentFilesPanel
|
||||
*/
|
||||
public RecentFilesPanel(RecentFilesSummary dataHandler) {
|
||||
this.dataHandler = dataHandler;
|
||||
|
||||
initComponents();
|
||||
initalizeTables();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewDataSource(DataSource dataSource) {
|
||||
// if no data source is present or the case is not open,
|
||||
// set results for tables to null.
|
||||
if (dataSource == null || !Case.isCaseOpen()) {
|
||||
this.dataFetchComponents.forEach((item) -> item.getResultHandler()
|
||||
.accept(DataFetchResult.getSuccessResult(null)));
|
||||
|
||||
} else {
|
||||
// set tables to display loading screen
|
||||
tablePanelList.forEach((table) -> table.showDefaultLoadingMessage());
|
||||
|
||||
// create swing workers to run for each table
|
||||
List<DataFetchWorker<?, ?>> workers = dataFetchComponents
|
||||
.stream()
|
||||
.map((components) -> new DataFetchWorker<>(components, dataSource))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// submit swing workers to run
|
||||
submit(workers);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the data model and columns for the panel tables.
|
||||
*/
|
||||
private void initalizeTables() {
|
||||
initalizeOpenDocsTable();
|
||||
initalizeDownloadTable();
|
||||
initalizeAttchementsTable();
|
||||
}
|
||||
|
||||
@Messages({
|
||||
"RecentFilePanel_no_open_documents=No recently open documents found."
|
||||
})
|
||||
/**
|
||||
* Setup the data model and columns for the recently open table.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void initalizeOpenDocsTable() {
|
||||
List<ColumnModel<RecentFileDetails>> list = Arrays.asList(
|
||||
new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(),
|
||||
(prog) -> {
|
||||
return new DefaultCellModel(prog.getPath());
|
||||
}, 250),
|
||||
new ColumnModel<>(Bundle.RecentFilesPanel_col_head_date(),
|
||||
(prog) -> {
|
||||
return new DefaultCellModel(prog.getDate());
|
||||
}, 80));
|
||||
|
||||
ListTableModel<RecentFileDetails> tableModel = JTablePanel.getTableModel(list);
|
||||
|
||||
JTablePanel<RecentFileDetails> pane = (JTablePanel<RecentFileDetails>) openedDocPane;
|
||||
pane.setModel(tableModel);
|
||||
pane.setColumnModel(JTablePanel.getTableColumnModel(list));
|
||||
tablePanelList.add(pane);
|
||||
|
||||
DataFetchWorker.DataFetchComponents<DataSource, List<RecentFileDetails>> worker
|
||||
= new DataFetchWorker.DataFetchComponents<>(
|
||||
(dataSource) -> dataHandler.getRecentlyOpenedDocuments(dataSource, 10),
|
||||
(result) -> pane.showDataFetchResult(result, JTablePanel.getDefaultErrorMessage(),
|
||||
Bundle.RecentFilePanel_no_open_documents()));
|
||||
|
||||
dataFetchComponents.add(worker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the data model and columns for the recent download table.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void initalizeDownloadTable() {
|
||||
List<ColumnModel<RecentDownloadDetails>> list = Arrays.asList(
|
||||
new ColumnModel<>(Bundle.RecentFilePanel_col_header_domain(),
|
||||
(prog) -> {
|
||||
return new DefaultCellModel(prog.getWebDomain());
|
||||
}, 100),
|
||||
new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(),
|
||||
(prog) -> {
|
||||
return new DefaultCellModel(prog.getPath());
|
||||
}, 250),
|
||||
new ColumnModel<>(Bundle.RecentFilesPanel_col_head_date(),
|
||||
(prog) -> {
|
||||
return new DefaultCellModel(prog.getDate());
|
||||
}, 80));
|
||||
|
||||
ListTableModel<RecentDownloadDetails> tableModel = JTablePanel.getTableModel(list);
|
||||
|
||||
JTablePanel<RecentDownloadDetails> pane = (JTablePanel<RecentDownloadDetails>) downloadsPane;
|
||||
pane.setModel(tableModel);
|
||||
pane.setColumnModel(JTablePanel.getTableColumnModel(list));
|
||||
tablePanelList.add(pane);
|
||||
|
||||
DataFetchWorker.DataFetchComponents<DataSource, List<RecentDownloadDetails>> worker
|
||||
= new DataFetchWorker.DataFetchComponents<>(
|
||||
(dataSource) -> dataHandler.getRecentDownloads(dataSource, 10),
|
||||
(result) -> pane.showDataFetchResult(result, JTablePanel.getDefaultErrorMessage(),
|
||||
Bundle.RecentFilePanel_no_open_documents()));
|
||||
|
||||
dataFetchComponents.add(worker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the data model and columns for the recent attachments.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void initalizeAttchementsTable() {
|
||||
List<ColumnModel<RecentAttachmentDetails>> list = Arrays.asList(
|
||||
new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(),
|
||||
(prog) -> {
|
||||
return new DefaultCellModel(prog.getPath());
|
||||
}, 250),
|
||||
new ColumnModel<>(Bundle.RecentFilesPanel_col_head_date(),
|
||||
(prog) -> {
|
||||
return new DefaultCellModel(prog.getDate());
|
||||
}, 80),
|
||||
new ColumnModel<>(Bundle.RecentFilePanel_col_header_sender(),
|
||||
(prog) -> {
|
||||
return new DefaultCellModel(prog.getSender());
|
||||
}, 150));
|
||||
|
||||
ListTableModel<RecentAttachmentDetails> tableModel = JTablePanel.getTableModel(list);
|
||||
|
||||
JTablePanel<RecentAttachmentDetails> pane = (JTablePanel<RecentAttachmentDetails>) attachmentsPane;
|
||||
pane.setModel(tableModel);
|
||||
pane.setColumnModel(JTablePanel.getTableColumnModel(list));
|
||||
tablePanelList.add(pane);
|
||||
|
||||
DataFetchWorker.DataFetchComponents<DataSource, List<RecentAttachmentDetails>> worker
|
||||
= new DataFetchWorker.DataFetchComponents<>(
|
||||
(dataSource) -> dataHandler.getRecentAttachments(dataSource, 10),
|
||||
(result) -> pane.showDataFetchResult(result, JTablePanel.getDefaultErrorMessage(),
|
||||
Bundle.RecentFilePanel_no_open_documents()));
|
||||
|
||||
dataFetchComponents.add(worker);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
java.awt.GridBagConstraints gridBagConstraints;
|
||||
|
||||
openedDocPane = new JTablePanel<RecentFileDetails>();
|
||||
downloadsPane = new JTablePanel<RecentDownloadDetails>();
|
||||
attachmentsPane = new JTablePanel<RecentAttachmentDetails>();
|
||||
openDocsLabel = new javax.swing.JLabel();
|
||||
downloadLabel = new javax.swing.JLabel();
|
||||
attachmentLabel = new javax.swing.JLabel();
|
||||
|
||||
setLayout(new java.awt.GridBagLayout());
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 1;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
|
||||
gridBagConstraints.weightx = 1.0;
|
||||
gridBagConstraints.weighty = 1.0;
|
||||
gridBagConstraints.insets = new java.awt.Insets(5, 5, 0, 5);
|
||||
add(openedDocPane, gridBagConstraints);
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 3;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
|
||||
gridBagConstraints.weightx = 1.0;
|
||||
gridBagConstraints.weighty = 1.0;
|
||||
gridBagConstraints.insets = new java.awt.Insets(5, 5, 0, 5);
|
||||
add(downloadsPane, gridBagConstraints);
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 5;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
|
||||
gridBagConstraints.weightx = 1.0;
|
||||
gridBagConstraints.weighty = 1.0;
|
||||
gridBagConstraints.insets = new java.awt.Insets(5, 5, 10, 5);
|
||||
add(attachmentsPane, gridBagConstraints);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(openDocsLabel, org.openide.util.NbBundle.getMessage(RecentFilesPanel.class, "RecentFilesPanel.openDocsLabel.text")); // NOI18N
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 0;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
|
||||
gridBagConstraints.insets = new java.awt.Insets(10, 5, 0, 5);
|
||||
add(openDocsLabel, gridBagConstraints);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(downloadLabel, org.openide.util.NbBundle.getMessage(RecentFilesPanel.class, "RecentFilesPanel.downloadLabel.text")); // NOI18N
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 2;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.insets = new java.awt.Insets(15, 5, 0, 5);
|
||||
add(downloadLabel, gridBagConstraints);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(attachmentLabel, org.openide.util.NbBundle.getMessage(RecentFilesPanel.class, "RecentFilesPanel.attachmentLabel.text")); // NOI18N
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 4;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
|
||||
gridBagConstraints.insets = new java.awt.Insets(15, 5, 0, 5);
|
||||
add(attachmentLabel, gridBagConstraints);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JLabel attachmentLabel;
|
||||
private javax.swing.JPanel attachmentsPane;
|
||||
private javax.swing.JLabel downloadLabel;
|
||||
private javax.swing.JPanel downloadsPane;
|
||||
private javax.swing.JLabel openDocsLabel;
|
||||
private javax.swing.JPanel openedDocPane;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
}
|
@ -98,6 +98,7 @@ public class CellModelTableCellRenderer extends DefaultTableCellRenderer {
|
||||
*/
|
||||
public DefaultCellModel(String text) {
|
||||
this.text = text;
|
||||
this.setTooltip(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -231,7 +231,7 @@ public class JTablePanel<T> extends JPanel {
|
||||
.map((colModel) -> colModel.getCellRenderer())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return new DefaultListTableModel<T>(columnRenderers);
|
||||
return new DefaultListTableModel<>(columnRenderers);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -264,26 +264,47 @@ public class JTablePanel<T> extends JPanel {
|
||||
|
||||
private final JScrollPane tableScrollPane;
|
||||
private final Overlay overlayLayer;
|
||||
private final ListTableModel<T> tableModel;
|
||||
private ListTableModel<T> tableModel;
|
||||
private final JTable table;
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
* Panel constructor.
|
||||
*
|
||||
* @param tableModel The model to use for the table.
|
||||
*/
|
||||
public JTablePanel(ListTableModel<T> tableModel) {
|
||||
this.tableModel = tableModel;
|
||||
this.table = new JTable(tableModel);
|
||||
this();
|
||||
setModel(tableModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public JTablePanel() {
|
||||
this.table = new JTable();
|
||||
this.table.getTableHeader().setReorderingAllowed(false);
|
||||
|
||||
this.overlayLayer = new Overlay();
|
||||
this.tableScrollPane = new JScrollPane(table);
|
||||
JLayer<JComponent> dualLayer = new JLayer<JComponent>(tableScrollPane, overlayLayer);
|
||||
JLayer<JComponent> dualLayer = new JLayer<>(tableScrollPane, overlayLayer);
|
||||
setLayout(new BorderLayout());
|
||||
add(dualLayer, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the table model.
|
||||
*
|
||||
* @param tableModel
|
||||
*/
|
||||
public void setModel(ListTableModel<T> tableModel) {
|
||||
if (tableModel == null) {
|
||||
throw new IllegalArgumentException("Null table model passed to setModel");
|
||||
}
|
||||
|
||||
this.tableModel = tableModel;
|
||||
table.setModel(tableModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The underlying JTable's column model.
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user