19 package org.sleuthkit.autopsy.corecomponents;
 
   21 import java.awt.image.BufferedImage;
 
   23 import java.io.IOException;
 
   24 import java.lang.management.ManagementFactory;
 
   25 import java.nio.charset.Charset;
 
   26 import java.nio.file.Files;
 
   27 import java.nio.file.Path;
 
   28 import java.util.ArrayList;
 
   29 import java.util.List;
 
   30 import java.util.Optional;
 
   31 import java.util.StringJoiner;
 
   32 import java.util.logging.Level;
 
   33 import javax.imageio.ImageIO;
 
   34 import javax.swing.ImageIcon;
 
   35 import javax.swing.JFileChooser;
 
   36 import javax.swing.JOptionPane;
 
   37 import javax.swing.event.DocumentEvent;
 
   38 import javax.swing.event.DocumentListener;
 
   39 import org.netbeans.spi.options.OptionsPanelController;
 
   40 import org.openide.util.NbBundle;
 
   42 import org.openide.util.NbBundle.Messages;
 
   54     "AutopsyOptionsPanel.invalidImageFile.msg=The selected file was not able to be used as an agency logo.",
 
   55     "AutopsyOptionsPanel.invalidImageFile.title=Invalid Image File",
 
   56     "AutopsyOptionsPanel.memFieldValidationLabel.not64BitInstall.text=JVM memory settings only enabled for 64 bit version",
 
   57     "AutopsyOptionsPanel.memFieldValidationLabel.noValueEntered.text=No value entered",
 
   58     "AutopsyOptionsPanel.memFieldValidationLabel.invalidCharacters.text=Invalid characters, value must be a positive integer",
 
   59     "# {0} - minimumMemory",
 
   60     "AutopsyOptionsPanel.memFieldValidationLabel.underMinMemory.text=Value must be at least {0}GB",
 
   61     "# {0} - systemMemory",
 
   62     "AutopsyOptionsPanel.memFieldValidationLabel.overMaxMemory.text=Value must be less than the total system memory of {0}GB",
 
   63     "AutopsyOptionsPanel.memFieldValidationLabel.developerMode.text=Memory settings are not available while running in developer mode",
 
   64     "AutopsyOptionsPanel.agencyLogoPathFieldValidationLabel.invalidPath.text=Path is not valid.",
 
   65     "AutopsyOptionsPanel.agencyLogoPathFieldValidationLabel.invalidImageSpecified.text=Invalid image file specified.",
 
   66     "AutopsyOptionsPanel.agencyLogoPathFieldValidationLabel.pathNotSet.text=Agency logo path must be set.",
 
   67     "AutopsyOptionsPanel.logNumAlert.invalidInput.text=A positive integer is required here." 
   69 @SuppressWarnings(
"PMD.SingularField") 
 
   70 final class AutopsyOptionsPanel extends javax.swing.JPanel {
 
   72     private static final long serialVersionUID = 1L;
 
   73     private final JFileChooser fileChooser;
 
   74     private final TextFieldListener textFieldListener;
 
   75     private static final String ETC_FOLDER_NAME = 
"etc";
 
   76     private static final String CONFIG_FILE_EXTENSION = 
".conf";
 
   77     private static final long ONE_BILLION = 1000000000L;  
 
   78     private static final int MEGA_IN_GIGA = 1024; 
 
   79     private static final int MIN_MEMORY_IN_GB = 2; 
 
   80     private static final Logger logger = Logger.getLogger(AutopsyOptionsPanel.class.getName());
 
   81     private String initialMemValue = Long.toString(Runtime.getRuntime().maxMemory() / ONE_BILLION);
 
   86     AutopsyOptionsPanel() {
 
   88         fileChooser = 
new JFileChooser();
 
   89         fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
 
   90         fileChooser.setMultiSelectionEnabled(
false);
 
   91         fileChooser.setAcceptAllFileFilterUsed(
false);
 
   92         fileChooser.setFileFilter(
new GeneralFilter(GeneralFilter.GRAPHIC_IMAGE_EXTS, GeneralFilter.GRAPHIC_IMG_DECR));
 
   93         if (!PlatformUtil.is64BitJVM() || Version.getBuildType() == Version.Type.DEVELOPMENT) {
 
   98             memField.setEnabled(
false);
 
   99             solrMaxHeapSpinner.setEnabled(
false);
 
  101         systemMemoryTotal.setText(Long.toString(getSystemMemoryInGB()));
 
  104         solrMaxHeapSpinner.setModel(
new javax.swing.SpinnerNumberModel(UserPreferences.getMaxSolrVMSize(),
 
  105                 512, ((int)getSystemMemoryInGB()) * MEGA_IN_GIGA, 512));
 
  107         textFieldListener = 
new TextFieldListener();
 
  108         agencyLogoPathField.getDocument().addDocumentListener(textFieldListener);
 
  109         logFileCount.setText(String.valueOf(UserPreferences.getLogFileCount()));
 
  118     private long getSystemMemoryInGB() {
 
  119         long memorySize = ((com.sun.management.OperatingSystemMXBean) ManagementFactory
 
  120                 .getOperatingSystemMXBean()).getTotalPhysicalMemorySize();
 
  121         return memorySize / ONE_BILLION;
 
  129     private long getCurrentJvmMaxMemoryInGB() throws IOException {
 
  130         String currentXmx = getCurrentXmxValue();
 
  133         if (currentXmx.length() > 1) {
 
  134             units = currentXmx.charAt(currentXmx.length() - 1);
 
  135             value = Long.parseLong(currentXmx.substring(0, currentXmx.length() - 1));
 
  137             throw new IOException(
"No memory setting found in String: " + currentXmx);
 
  146                 return value / MEGA_IN_GIGA;
 
  148                 throw new IOException(
"Units were not recognized as parsed: " + units);
 
  163     private String getCurrentXmxValue() throws IOException {
 
  165         String currentSetting = 
"";
 
  166         File userConfFile = getUserFolderConfFile();
 
  167         if (!userConfFile.exists()) {
 
  168             settings = getDefaultsFromFileContents(readConfFile(getInstallFolderConfFile()));
 
  170             settings = getDefaultsFromFileContents(readConfFile(userConfFile));
 
  172         for (String option : settings) {
 
  173             if (option.startsWith(
"-J-Xmx")) {
 
  174                 currentSetting = option.replace(
"-J-Xmx", 
"").trim();
 
  177         return currentSetting;
 
  188     private static File getInstallFolderConfFile() throws IOException {
 
  189         String confFileName = UserPreferences.getAppName() + CONFIG_FILE_EXTENSION;
 
  190         String installFolder = PlatformUtil.getInstallPath();
 
  191         File installFolderEtc = 
new File(installFolder, ETC_FOLDER_NAME);
 
  192         File installFolderConfigFile = 
new File(installFolderEtc, confFileName);
 
  193         if (!installFolderConfigFile.exists()) {
 
  194             throw new IOException(
"Conf file could not be found" + installFolderConfigFile.toString());
 
  196         return installFolderConfigFile;
 
  206     private static File getUserFolderConfFile() {
 
  207         String confFileName = UserPreferences.getAppName() + CONFIG_FILE_EXTENSION;
 
  208         File userFolder = PlatformUtil.getUserDirectory();
 
  209         File userEtcFolder = 
new File(userFolder, ETC_FOLDER_NAME);
 
  210         if (!userEtcFolder.exists()) {
 
  211             userEtcFolder.mkdir();
 
  213         return new File(userEtcFolder, confFileName);
 
  224     private void writeEtcConfFile() throws IOException {
 
  225         StringBuilder content = 
new StringBuilder();
 
  226         List<String> confFile = readConfFile(getInstallFolderConfFile());
 
  227         for (String line : confFile) {
 
  228             if (line.contains(
"-J-Xmx")) {
 
  229                 String[] splitLine = line.split(
" ");
 
  230                 StringJoiner modifiedLine = 
new StringJoiner(
" ");
 
  231                 for (String piece : splitLine) {
 
  232                     if (piece.contains(
"-J-Xmx")) {
 
  233                         piece = 
"-J-Xmx" + memField.getText() + 
"g";
 
  235                     modifiedLine.add(piece);
 
  237                 content.append(modifiedLine.toString());
 
  239                 content.append(line);
 
  241             content.append(
"\n");
 
  243         Files.write(getUserFolderConfFile().toPath(), content.toString().getBytes());
 
  255     private static List<String> readConfFile(File configFile) {
 
  256         List<String> lines = 
new ArrayList<>();
 
  257         if (null != configFile) {
 
  258             Path filePath = configFile.toPath();
 
  259             Charset charset = Charset.forName(
"UTF-8");
 
  261                 lines = Files.readAllLines(filePath, charset);
 
  262             } 
catch (IOException e) {
 
  263                 logger.log(Level.SEVERE, 
"Error reading config file contents. {}", configFile.getAbsolutePath());
 
  280     private static String[] getDefaultsFromFileContents(List<String> list) {
 
  281         Optional<String> defaultSettings = list.stream().filter(line -> line.startsWith(
"default_options=")).findFirst();
 
  283         if (defaultSettings.isPresent()) {
 
  284             return defaultSettings.get().replace(
"default_options=", 
"").replaceAll(
"\"", 
"").split(
" ");
 
  286         return new String[]{};
 
  293         String path = ModuleSettings.getConfigSetting(ReportBranding.MODULE_NAME, ReportBranding.AGENCY_LOGO_PATH_PROP);
 
  294         boolean useDefault = (path == null || path.isEmpty());
 
  295         defaultLogoRB.setSelected(useDefault);
 
  296         specifyLogoRB.setSelected(!useDefault);
 
  297         agencyLogoPathField.setEnabled(!useDefault);
 
  298         browseLogosButton.setEnabled(!useDefault);
 
  299         logFileCount.setText(String.valueOf(UserPreferences.getLogFileCount()));
 
  300         solrMaxHeapSpinner.setValue(UserPreferences.getMaxSolrVMSize());
 
  302             updateAgencyLogo(path);
 
  303         } 
catch (IOException ex) {
 
  304             logger.log(Level.WARNING, 
"Error loading image from previously saved agency logo path", ex);
 
  306         if (memField.isEnabled()) {
 
  308                 initialMemValue = Long.toString(getCurrentJvmMaxMemoryInGB());
 
  309             } 
catch (IOException ex) {
 
  310                 logger.log(Level.SEVERE, 
"Can't read current Jvm max memory setting from file", ex);
 
  311                 memField.setEnabled(
false);
 
  313             memField.setText(initialMemValue);
 
  326     private void updateAgencyLogo(String path) 
throws IOException {
 
  327         agencyLogoPathField.setText(path);
 
  328         ImageIcon agencyLogoIcon = 
new ImageIcon();
 
  329         agencyLogoPreview.setText(NbBundle.getMessage(AutopsyOptionsPanel.class, 
"AutopsyOptionsPanel.agencyLogoPreview.text"));
 
  330         if (!agencyLogoPathField.getText().isEmpty()) {
 
  331             File file = 
new File(agencyLogoPathField.getText());
 
  333                 BufferedImage image = ImageIO.read(file); 
 
  335                     throw new IOException(
"Unable to read file as a BufferedImage for file " + file.toString());
 
  337                 agencyLogoIcon = 
new ImageIcon(image.getScaledInstance(64, 64, 4));
 
  338                 agencyLogoPreview.setText(
"");
 
  341         agencyLogoPreview.setIcon(agencyLogoIcon);
 
  342         agencyLogoPreview.repaint();
 
  349         UserPreferences.setLogFileCount(Integer.parseInt(logFileCount.getText()));
 
  350         if (!agencyLogoPathField.getText().isEmpty()) {
 
  351             File file = 
new File(agencyLogoPathField.getText());
 
  353                 ModuleSettings.setConfigSetting(ReportBranding.MODULE_NAME, ReportBranding.AGENCY_LOGO_PATH_PROP, agencyLogoPathField.getText());
 
  356             ModuleSettings.setConfigSetting(ReportBranding.MODULE_NAME, ReportBranding.AGENCY_LOGO_PATH_PROP, 
"");
 
  358         UserPreferences.setMaxSolrVMSize((
int)solrMaxHeapSpinner.getValue());
 
  359         if (memField.isEnabled()) {  
 
  362             } 
catch (IOException ex) {
 
  363                 logger.log(Level.WARNING, 
"Unable to save config file to " + PlatformUtil.getUserDirectory() + 
"\\" + ETC_FOLDER_NAME, ex);
 
  374         boolean valid = 
true;
 
  376         if (!isAgencyLogoPathValid()) {
 
  379         if (!isMemFieldValid()) {
 
  382         if (!isLogNumFieldValid()) {
 
  395     boolean isAgencyLogoPathValid() {
 
  396         boolean valid = 
true;
 
  398         if (defaultLogoRB.isSelected()) {
 
  399             agencyLogoPathFieldValidationLabel.setText(
"");
 
  401             String agencyLogoPath = agencyLogoPathField.getText();
 
  402             if (agencyLogoPath.isEmpty()) {
 
  403                 agencyLogoPathFieldValidationLabel.setText(Bundle.AutopsyOptionsPanel_agencyLogoPathFieldValidationLabel_pathNotSet_text());
 
  406                 File file = 
new File(agencyLogoPathField.getText());
 
  407                 if (file.exists() && file.isFile()) {
 
  410                         image = ImageIO.read(file); 
 
  412                             throw new IOException(
"Unable to read file as a BufferedImage for file " + file.toString());
 
  414                         agencyLogoPathFieldValidationLabel.setText(
"");
 
  415                     } 
catch (IOException | IndexOutOfBoundsException ignored) {
 
  416                         agencyLogoPathFieldValidationLabel.setText(Bundle.AutopsyOptionsPanel_agencyLogoPathFieldValidationLabel_invalidImageSpecified_text());
 
  420                     agencyLogoPathFieldValidationLabel.setText(Bundle.AutopsyOptionsPanel_agencyLogoPathFieldValidationLabel_invalidPath_text());
 
  434     private boolean isMemFieldValid() {
 
  435         String memText = memField.getText();
 
  436         memFieldValidationLabel.setText(
"");
 
  437         if (!PlatformUtil.is64BitJVM()) {
 
  438             memFieldValidationLabel.setText(Bundle.AutopsyOptionsPanel_memFieldValidationLabel_not64BitInstall_text());
 
  442         if (Version.getBuildType() == Version.Type.DEVELOPMENT) {
 
  443             memFieldValidationLabel.setText(Bundle.AutopsyOptionsPanel_memFieldValidationLabel_developerMode_text());
 
  447         if (memText.length() == 0) {
 
  448             memFieldValidationLabel.setText(Bundle.AutopsyOptionsPanel_memFieldValidationLabel_noValueEntered_text());
 
  451         if (memText.replaceAll(
"[^\\d]", 
"").length() != memText.length()) {
 
  452             memFieldValidationLabel.setText(Bundle.AutopsyOptionsPanel_memFieldValidationLabel_invalidCharacters_text());
 
  455         int parsedInt = Integer.parseInt(memText);
 
  456         if (parsedInt < MIN_MEMORY_IN_GB) {
 
  457             memFieldValidationLabel.setText(Bundle.AutopsyOptionsPanel_memFieldValidationLabel_underMinMemory_text(MIN_MEMORY_IN_GB));
 
  460         if (parsedInt > getSystemMemoryInGB()) {
 
  461             memFieldValidationLabel.setText(Bundle.AutopsyOptionsPanel_memFieldValidationLabel_overMaxMemory_text(getSystemMemoryInGB()));
 
  472     private boolean isLogNumFieldValid() {
 
  473         String count = logFileCount.getText();
 
  474         logNumAlert.setText(
"");
 
  476             int count_num = Integer.parseInt(count);
 
  478                 logNumAlert.setText(Bundle.AutopsyOptionsPanel_logNumAlert_invalidInput_text());
 
  481         } 
catch (NumberFormatException e) {
 
  482             logNumAlert.setText(Bundle.AutopsyOptionsPanel_logNumAlert_invalidInput_text());
 
  495             firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
 
  500             firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
 
  505             firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
 
  515     private void initComponents() {
 
  517         fileSelectionButtonGroup = 
new javax.swing.ButtonGroup();
 
  518         displayTimesButtonGroup = 
new javax.swing.ButtonGroup();
 
  519         logoSourceButtonGroup = 
new javax.swing.ButtonGroup();
 
  520         jScrollPane1 = 
new javax.swing.JScrollPane();
 
  521         jPanel1 = 
new javax.swing.JPanel();
 
  522         logoPanel = 
new javax.swing.JPanel();
 
  523         agencyLogoPathField = 
new javax.swing.JTextField();
 
  524         browseLogosButton = 
new javax.swing.JButton();
 
  525         agencyLogoPreview = 
new javax.swing.JLabel();
 
  526         defaultLogoRB = 
new javax.swing.JRadioButton();
 
  527         specifyLogoRB = 
new javax.swing.JRadioButton();
 
  528         agencyLogoPathFieldValidationLabel = 
new javax.swing.JLabel();
 
  529         runtimePanel = 
new javax.swing.JPanel();
 
  530         maxMemoryLabel = 
new javax.swing.JLabel();
 
  531         maxMemoryUnitsLabel = 
new javax.swing.JLabel();
 
  532         totalMemoryLabel = 
new javax.swing.JLabel();
 
  533         systemMemoryTotal = 
new javax.swing.JLabel();
 
  534         restartNecessaryWarning = 
new javax.swing.JLabel();
 
  535         memField = 
new javax.swing.JTextField();
 
  536         memFieldValidationLabel = 
new javax.swing.JLabel();
 
  537         maxMemoryUnitsLabel1 = 
new javax.swing.JLabel();
 
  538         maxLogFileCount = 
new javax.swing.JLabel();
 
  539         logFileCount = 
new javax.swing.JTextField();
 
  540         logNumAlert = 
new javax.swing.JTextField();
 
  541         maxSolrMemoryLabel = 
new javax.swing.JLabel();
 
  542         maxMemoryUnitsLabel2 = 
new javax.swing.JLabel();
 
  543         solrMaxHeapSpinner = 
new javax.swing.JSpinner();
 
  544         solrJVMHeapWarning = 
new javax.swing.JLabel();
 
  546         setPreferredSize(
new java.awt.Dimension(1022, 488));
 
  548         jScrollPane1.setBorder(null);
 
  549         jScrollPane1.setPreferredSize(
new java.awt.Dimension(1022, 407));
 
  551         jPanel1.setPreferredSize(
new java.awt.Dimension(1022, 407));
 
  553         logoPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(
org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, 
"AutopsyOptionsPanel.logoPanel.border.title"))); 
 
  554         logoPanel.setPreferredSize(
new java.awt.Dimension(533, 87));
 
  556         agencyLogoPathField.setText(
org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, 
"AutopsyOptionsPanel.agencyLogoPathField.text")); 
 
  558         org.openide.awt.Mnemonics.setLocalizedText(browseLogosButton, 
org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, 
"AutopsyOptionsPanel.browseLogosButton.text")); 
 
  559         browseLogosButton.addActionListener(
new java.awt.event.ActionListener() {
 
  560             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
  561                 browseLogosButtonActionPerformed(evt);
 
  565         agencyLogoPreview.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
 
  566         org.openide.awt.Mnemonics.setLocalizedText(agencyLogoPreview, 
org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, 
"AutopsyOptionsPanel.agencyLogoPreview.text")); 
 
  567         agencyLogoPreview.setBorder(javax.swing.BorderFactory.createEtchedBorder());
 
  568         agencyLogoPreview.setMaximumSize(
new java.awt.Dimension(64, 64));
 
  569         agencyLogoPreview.setMinimumSize(
new java.awt.Dimension(64, 64));
 
  570         agencyLogoPreview.setPreferredSize(
new java.awt.Dimension(64, 64));
 
  572         logoSourceButtonGroup.add(defaultLogoRB);
 
  573         org.openide.awt.Mnemonics.setLocalizedText(defaultLogoRB, 
org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, 
"AutopsyOptionsPanel.defaultLogoRB.text")); 
 
  574         defaultLogoRB.addActionListener(
new java.awt.event.ActionListener() {
 
  575             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
  576                 defaultLogoRBActionPerformed(evt);
 
  580         logoSourceButtonGroup.add(specifyLogoRB);
 
  581         org.openide.awt.Mnemonics.setLocalizedText(specifyLogoRB, 
org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, 
"AutopsyOptionsPanel.specifyLogoRB.text")); 
 
  582         specifyLogoRB.addActionListener(
new java.awt.event.ActionListener() {
 
  583             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
  584                 specifyLogoRBActionPerformed(evt);
 
  588         agencyLogoPathFieldValidationLabel.setForeground(
new java.awt.Color(255, 0, 0));
 
  589         org.openide.awt.Mnemonics.setLocalizedText(agencyLogoPathFieldValidationLabel, 
org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, 
"AutopsyOptionsPanel.agencyLogoPathFieldValidationLabel.text")); 
 
  591         javax.swing.GroupLayout logoPanelLayout = 
new javax.swing.GroupLayout(logoPanel);
 
  592         logoPanel.setLayout(logoPanelLayout);
 
  593         logoPanelLayout.setHorizontalGroup(
 
  594             logoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  595             .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, logoPanelLayout.createSequentialGroup()
 
  597                 .addGroup(logoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  598                     .addComponent(specifyLogoRB)
 
  599                     .addComponent(defaultLogoRB))
 
  600                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
 
  601                 .addGroup(logoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  602                     .addGroup(logoPanelLayout.createSequentialGroup()
 
  603                         .addComponent(agencyLogoPathField, javax.swing.GroupLayout.PREFERRED_SIZE, 259, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  604                         .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  605                         .addComponent(browseLogosButton))
 
  606                     .addComponent(agencyLogoPathFieldValidationLabel))
 
  607                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
 
  608                 .addComponent(agencyLogoPreview, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  609                 .addContainerGap(456, Short.MAX_VALUE))
 
  611         logoPanelLayout.setVerticalGroup(
 
  612             logoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  613             .addGroup(logoPanelLayout.createSequentialGroup()
 
  615                 .addGroup(logoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
 
  616                     .addComponent(defaultLogoRB)
 
  617                     .addComponent(agencyLogoPathFieldValidationLabel))
 
  618                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  619                 .addGroup(logoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
 
  620                     .addComponent(specifyLogoRB)
 
  621                     .addComponent(agencyLogoPathField)
 
  622                     .addComponent(browseLogosButton)))
 
  623             .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, logoPanelLayout.createSequentialGroup()
 
  624                 .addComponent(agencyLogoPreview, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  625                 .addGap(0, 0, Short.MAX_VALUE))
 
  628         runtimePanel.setBorder(javax.swing.BorderFactory.createTitledBorder(
org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, 
"AutopsyOptionsPanel.runtimePanel.border.title"))); 
 
  630         org.openide.awt.Mnemonics.setLocalizedText(maxMemoryLabel, 
org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, 
"AutopsyOptionsPanel.maxMemoryLabel.text")); 
 
  632         org.openide.awt.Mnemonics.setLocalizedText(maxMemoryUnitsLabel, 
org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, 
"AutopsyOptionsPanel.maxMemoryUnitsLabel.text")); 
 
  634         org.openide.awt.Mnemonics.setLocalizedText(totalMemoryLabel, 
org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, 
"AutopsyOptionsPanel.totalMemoryLabel.text")); 
 
  636         systemMemoryTotal.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);
 
  638         restartNecessaryWarning.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/warning16.png"))); 
 
  639         org.openide.awt.Mnemonics.setLocalizedText(restartNecessaryWarning, 
org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, 
"AutopsyOptionsPanel.restartNecessaryWarning.text")); 
 
  641         memField.setHorizontalAlignment(javax.swing.JTextField.TRAILING);
 
  642         memField.addKeyListener(
new java.awt.event.KeyAdapter() {
 
  643             public void keyReleased(java.awt.event.KeyEvent evt) {
 
  644                 memFieldKeyReleased(evt);
 
  648         memFieldValidationLabel.setForeground(
new java.awt.Color(255, 0, 0));
 
  650         org.openide.awt.Mnemonics.setLocalizedText(maxMemoryUnitsLabel1, 
org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, 
"AutopsyOptionsPanel.maxMemoryUnitsLabel.text")); 
 
  652         org.openide.awt.Mnemonics.setLocalizedText(maxLogFileCount, 
org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, 
"AutopsyOptionsPanel.maxLogFileCount.text")); 
 
  654         logFileCount.setHorizontalAlignment(javax.swing.JTextField.TRAILING);
 
  655         logFileCount.addKeyListener(
new java.awt.event.KeyAdapter() {
 
  656             public void keyReleased(java.awt.event.KeyEvent evt) {
 
  657                 logFileCountKeyReleased(evt);
 
  661         logNumAlert.setEditable(
false);
 
  662         logNumAlert.setFont(logNumAlert.getFont().deriveFont(logNumAlert.getFont().getStyle() & ~java.awt.Font.BOLD, 11));
 
  663         logNumAlert.setForeground(
new java.awt.Color(255, 0, 0));
 
  664         logNumAlert.setText(
org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, 
"AutopsyOptionsPanel.logNumAlert.text")); 
 
  665         logNumAlert.setBorder(null);
 
  667         org.openide.awt.Mnemonics.setLocalizedText(maxSolrMemoryLabel, 
org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, 
"AutopsyOptionsPanel.maxSolrMemoryLabel.text")); 
 
  669         org.openide.awt.Mnemonics.setLocalizedText(maxMemoryUnitsLabel2, 
org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, 
"AutopsyOptionsPanel.maxMemoryUnitsLabel2.text")); 
 
  671         solrMaxHeapSpinner.addChangeListener(
new javax.swing.event.ChangeListener() {
 
  672             public void stateChanged(javax.swing.event.ChangeEvent evt) {
 
  673                 solrMaxHeapSpinnerStateChanged(evt);
 
  677         org.openide.awt.Mnemonics.setLocalizedText(solrJVMHeapWarning, 
org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, 
"AutopsyOptionsPanel.solrJVMHeapWarning.text")); 
 
  679         javax.swing.GroupLayout runtimePanelLayout = 
new javax.swing.GroupLayout(runtimePanel);
 
  680         runtimePanel.setLayout(runtimePanelLayout);
 
  681         runtimePanelLayout.setHorizontalGroup(
 
  682             runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  683             .addGroup(runtimePanelLayout.createSequentialGroup()
 
  685                 .addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  686                     .addGroup(runtimePanelLayout.createSequentialGroup()
 
  687                         .addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  688                             .addComponent(totalMemoryLabel)
 
  689                             .addComponent(maxSolrMemoryLabel)
 
  690                             .addComponent(maxMemoryLabel)
 
  691                             .addComponent(maxLogFileCount))
 
  693                         .addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  694                             .addComponent(logFileCount, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 37, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  695                             .addComponent(solrMaxHeapSpinner, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  696                             .addComponent(memField, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 37, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  697                             .addComponent(systemMemoryTotal, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 37, javax.swing.GroupLayout.PREFERRED_SIZE))
 
  699                         .addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  700                             .addComponent(maxMemoryUnitsLabel1)
 
  701                             .addComponent(maxMemoryUnitsLabel)
 
  702                             .addComponent(maxMemoryUnitsLabel2))
 
  703                         .addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  704                             .addGroup(runtimePanelLayout.createSequentialGroup()
 
  706                                 .addComponent(memFieldValidationLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 478, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  707                                 .addContainerGap(246, Short.MAX_VALUE))
 
  708                             .addGroup(runtimePanelLayout.createSequentialGroup()
 
  710                                 .addComponent(solrJVMHeapWarning, javax.swing.GroupLayout.DEFAULT_SIZE, 717, Short.MAX_VALUE)
 
  711                                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  712                                 .addComponent(logNumAlert)
 
  713                                 .addContainerGap())))
 
  714                     .addComponent(restartNecessaryWarning, javax.swing.GroupLayout.DEFAULT_SIZE, 994, Short.MAX_VALUE)))
 
  717         runtimePanelLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, 
new java.awt.Component[] {maxLogFileCount, maxMemoryLabel, totalMemoryLabel});
 
  719         runtimePanelLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, 
new java.awt.Component[] {logFileCount, memField});
 
  721         runtimePanelLayout.setVerticalGroup(
 
  722             runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  723             .addGroup(runtimePanelLayout.createSequentialGroup()
 
  725                 .addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, 
false)
 
  726                     .addComponent(totalMemoryLabel)
 
  727                     .addComponent(maxMemoryUnitsLabel1)
 
  728                     .addComponent(systemMemoryTotal, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
 
  729                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  730                 .addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  731                     .addComponent(memFieldValidationLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  732                     .addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
 
  733                         .addComponent(maxMemoryLabel)
 
  734                         .addComponent(memField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  735                         .addComponent(maxMemoryUnitsLabel)))
 
  736                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  737                 .addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  738                     .addComponent(logNumAlert, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  739                     .addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
 
  740                         .addComponent(maxSolrMemoryLabel)
 
  741                         .addComponent(maxMemoryUnitsLabel2)
 
  742                         .addComponent(solrMaxHeapSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  743                         .addComponent(solrJVMHeapWarning)))
 
  744                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  745                 .addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
 
  746                     .addComponent(maxLogFileCount)
 
  747                     .addComponent(logFileCount, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
 
  748                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
 
  749                 .addComponent(restartNecessaryWarning)
 
  750                 .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
 
  753         javax.swing.GroupLayout jPanel1Layout = 
new javax.swing.GroupLayout(jPanel1);
 
  754         jPanel1.setLayout(jPanel1Layout);
 
  755         jPanel1Layout.setHorizontalGroup(
 
  756             jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  757             .addGroup(jPanel1Layout.createSequentialGroup()
 
  759                 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  760                     .addComponent(runtimePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  761                     .addComponent(logoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 1010, Short.MAX_VALUE))
 
  764         jPanel1Layout.setVerticalGroup(
 
  765             jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  766             .addGroup(jPanel1Layout.createSequentialGroup()
 
  768                 .addComponent(runtimePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  769                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
 
  770                 .addComponent(logoPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  771                 .addContainerGap(171, Short.MAX_VALUE))
 
  774         jScrollPane1.setViewportView(jPanel1);
 
  776         javax.swing.GroupLayout layout = 
new javax.swing.GroupLayout(
this);
 
  777         this.setLayout(layout);
 
  778         layout.setHorizontalGroup(
 
  779             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  780             .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  782         layout.setVerticalGroup(
 
  783             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  784             .addGroup(layout.createSequentialGroup()
 
  785                 .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  786                 .addGap(0, 0, Short.MAX_VALUE))
 
  790     private void logFileCountKeyReleased(java.awt.event.KeyEvent evt) {
 
  791         String count = logFileCount.getText();
 
  792         if (count.equals(String.valueOf(UserPreferences.getDefaultLogFileCount()))) {
 
  796         firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
 
  799     private void memFieldKeyReleased(java.awt.event.KeyEvent evt) {
 
  800         String memText = memField.getText();
 
  801         if (memText.equals(initialMemValue)) {
 
  805         firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
 
  808     private void specifyLogoRBActionPerformed(java.awt.event.ActionEvent evt) {
 
  809         agencyLogoPathField.setEnabled(
true);
 
  810         browseLogosButton.setEnabled(
true);
 
  812             if (agencyLogoPathField.getText().isEmpty()) {
 
  813                 String path = ModuleSettings.getConfigSetting(ReportBranding.MODULE_NAME, ReportBranding.AGENCY_LOGO_PATH_PROP);
 
  814                 if (path != null && !path.isEmpty()) {
 
  815                     updateAgencyLogo(path);
 
  818         } 
catch (IOException ex) {
 
  819             logger.log(Level.WARNING, 
"Error loading image from previously saved agency logo path.", ex);
 
  821         firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
 
  824     private void defaultLogoRBActionPerformed(java.awt.event.ActionEvent evt) {
 
  825         agencyLogoPathField.setEnabled(
false);
 
  826         browseLogosButton.setEnabled(
false);
 
  828             updateAgencyLogo(
"");
 
  829         } 
catch (IOException ex) {
 
  831             logger.log(Level.SEVERE, 
"Unexpected error occurred while updating the agency logo.", ex);
 
  833         firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
 
  836     private void browseLogosButtonActionPerformed(java.awt.event.ActionEvent evt) {
 
  837         String oldLogoPath = agencyLogoPathField.getText();
 
  838         int returnState = fileChooser.showOpenDialog(
this);
 
  839         if (returnState == JFileChooser.APPROVE_OPTION) {
 
  840             String path = fileChooser.getSelectedFile().getPath();
 
  842                 updateAgencyLogo(path);
 
  843                 firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
 
  844             } 
catch (IOException | IndexOutOfBoundsException ex) {
 
  845                 JOptionPane.showMessageDialog(
this,
 
  846                     NbBundle.getMessage(
this.getClass(),
 
  847                         "AutopsyOptionsPanel.invalidImageFile.msg"),
 
  848                     NbBundle.getMessage(
this.getClass(), 
"AutopsyOptionsPanel.invalidImageFile.title"),
 
  849                     JOptionPane.ERROR_MESSAGE);
 
  851                     updateAgencyLogo(oldLogoPath); 
 
  852                 } 
catch (IOException ex1) {
 
  853                     logger.log(Level.WARNING, 
"Error loading image from previously saved agency logo path", ex1);
 
  859     private void solrMaxHeapSpinnerStateChanged(javax.swing.event.ChangeEvent evt) {
 
  860         int value = (int)solrMaxHeapSpinner.getValue();
 
  861         if (value == UserPreferences.getMaxSolrVMSize()) {
 
  865         firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
 
  869     private javax.swing.JTextField agencyLogoPathField;
 
  870     private javax.swing.JLabel agencyLogoPathFieldValidationLabel;
 
  871     private javax.swing.JLabel agencyLogoPreview;
 
  872     private javax.swing.JButton browseLogosButton;
 
  873     private javax.swing.JRadioButton defaultLogoRB;
 
  874     private javax.swing.ButtonGroup displayTimesButtonGroup;
 
  875     private javax.swing.ButtonGroup fileSelectionButtonGroup;
 
  876     private javax.swing.JPanel jPanel1;
 
  877     private javax.swing.JScrollPane jScrollPane1;
 
  878     private javax.swing.JTextField logFileCount;
 
  879     private javax.swing.JTextField logNumAlert;
 
  880     private javax.swing.JPanel logoPanel;
 
  881     private javax.swing.ButtonGroup logoSourceButtonGroup;
 
  882     private javax.swing.JLabel maxLogFileCount;
 
  883     private javax.swing.JLabel maxMemoryLabel;
 
  884     private javax.swing.JLabel maxMemoryUnitsLabel;
 
  885     private javax.swing.JLabel maxMemoryUnitsLabel1;
 
  886     private javax.swing.JLabel maxMemoryUnitsLabel2;
 
  887     private javax.swing.JLabel maxSolrMemoryLabel;
 
  888     private javax.swing.JTextField memField;
 
  889     private javax.swing.JLabel memFieldValidationLabel;
 
  890     private javax.swing.JLabel restartNecessaryWarning;
 
  891     private javax.swing.JPanel runtimePanel;
 
  892     private javax.swing.JLabel solrJVMHeapWarning;
 
  893     private javax.swing.JSpinner solrMaxHeapSpinner;
 
  894     private javax.swing.JRadioButton specifyLogoRB;
 
  895     private javax.swing.JLabel systemMemoryTotal;
 
  896     private javax.swing.JLabel totalMemoryLabel;
 
void insertUpdate(DocumentEvent e)
void removeUpdate(DocumentEvent e)
void changedUpdate(DocumentEvent e)