View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.log4j.chainsaw;
18  
19  import org.apache.log4j.LogManager;
20  import org.apache.log4j.Logger;
21  import org.apache.log4j.chainsaw.helper.SwingHelper;
22  import org.apache.log4j.chainsaw.prefs.SettingsManager;
23  import org.apache.log4j.net.UDPReceiver;
24  import org.apache.log4j.plugins.Receiver;
25  
26  import javax.swing.*;
27  import javax.swing.text.SimpleAttributeSet;
28  import javax.swing.text.StyleConstants;
29  import javax.swing.text.StyledDocument;
30  import java.awt.*;
31  import java.awt.event.ActionEvent;
32  import java.awt.event.ActionListener;
33  import java.awt.event.FocusEvent;
34  import java.awt.event.FocusListener;
35  import java.io.File;
36  import java.net.MalformedURLException;
37  import java.net.URISyntaxException;
38  import java.net.URL;
39  import java.util.List;
40  import java.util.Locale;
41  
42  
43  /**
44   * A panel providing receiver configuration options
45   *
46   * @author Paul Smith
47   */
48  class ReceiverConfigurationPanel extends JPanel {
49      private final Logger logger = LogManager.getLogger(ReceiverConfigurationPanel.class);
50  
51      private final PanelModel panelModel = new PanelModel();
52  
53      //network receiver widgets
54      private JComboBox<String> networkReceiverPortComboBox;
55      private JComboBox<String> networkReceiverClassNameComboBox;
56      private DefaultComboBoxModel<String> networkReceiverClassNameComboBoxModel;
57      private DefaultComboBoxModel<String> networkReceiverPortComboBoxModel;
58  
59      //log4j config receiver widgets
60      private JButton browseLog4jConfigButton;
61      private JTextField log4jConfigURLTextField;
62  
63      //logfile receiver widgets
64      private JButton browseLogFileButton;
65      private JComboBox<String> logFileFormatTypeComboBox;
66  
67      private JComboBox<String> logFileFormatComboBox;
68      private JComboBox<String> logFileFormatTimestampFormatComboBox;
69      private JTextField logFileURLTextField;
70      private DefaultComboBoxModel<String> logFileFormatComboBoxModel;
71      private DefaultComboBoxModel<String> logFileFormatTimestampFormatComboBoxModel;
72  
73      //use existing configuration widgets
74      private JButton browseForAnExistingConfigurationButton;
75      private DefaultComboBoxModel<String> existingConfigurationComboBoxModel;
76      private JComboBox<String> existingConfigurationComboBox;
77  
78      //don't warn again widgets
79      private JCheckBox dontwarnIfNoReceiver;
80  
81      private JButton saveButton;
82      private JButton okButton;
83      private JButton cancelButton;
84  
85      //radiobutton widgets
86      private JRadioButton log4jConfigReceiverRadioButton;
87      private JRadioButton logFileReceiverRadioButton;
88      private JRadioButton networkReceiverRadioButton;
89      private JRadioButton useExistingConfigurationRadioButton;
90      private ButtonGroup buttonGroup;
91  
92      private JPanel lowerPanel;
93  
94      private final JPanel networkReceiverPanel = buildNetworkReceiverPanel();
95      private final JPanel logFileReceiverPanel = buildLogFileReceiverPanel();
96      private final JPanel log4jConfigReceiverPanel = buildLog4jConfigReceiverPanel();
97      private final JPanel useExistingConfigurationPanel = buildUseExistingConfigurationPanel();
98      private final JPanel dontWarnAndOKPanel = buildDontWarnAndOKPanel();
99      private final JPanel bottomDescriptionPanel = buildBottomDescriptionPanel();
100 
101     //set by LogUI to handle hiding of the dialog
102     private ActionListener completionActionListener;
103     //used as frame for file open dialogs
104     private Container dialog;
105 
106     ReceiverConfigurationPanel() {
107         setBorder(BorderFactory.createEmptyBorder(5, 15, 5, 15));
108         setLayout(new GridBagLayout());
109 
110         buttonGroup = new ButtonGroup();
111 
112         lowerPanel = new JPanel(new BorderLayout());
113         lowerPanel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEtchedBorder(), BorderFactory.createEmptyBorder(5, 5, 5, 5)));
114         lowerPanel.setPreferredSize(new Dimension(600, 200));
115         lowerPanel.setMinimumSize(new Dimension(600, 200));
116 
117         int yPos = 0;
118 
119         GridBagConstraints c = new GridBagConstraints();
120         c.gridx = 0;
121         c.gridy = yPos++;
122         c.fill = GridBagConstraints.HORIZONTAL;
123         log4jConfigReceiverRadioButton = new JRadioButton(" Use fileappender entries from a log4j config file ");
124         buttonGroup.add(log4jConfigReceiverRadioButton);
125         add(log4jConfigReceiverRadioButton, c);
126 
127         c = new GridBagConstraints();
128         c.gridx = 0;
129         c.gridy = yPos++;
130         c.fill = GridBagConstraints.HORIZONTAL;
131         logFileReceiverRadioButton = new JRadioButton(" Process a log file ");
132         buttonGroup.add(logFileReceiverRadioButton);
133         add(logFileReceiverRadioButton, c);
134 
135         c = new GridBagConstraints();
136         c.gridx = 0;
137         c.gridy = yPos++;
138         c.fill = GridBagConstraints.HORIZONTAL;
139         networkReceiverRadioButton = new JRadioButton(" Receive events from the network ");
140         buttonGroup.add(networkReceiverRadioButton);
141         add(networkReceiverRadioButton, c);
142 
143         c = new GridBagConstraints();
144         c.gridx = 0;
145         c.gridy = yPos++;
146         c.fill = GridBagConstraints.HORIZONTAL;
147         useExistingConfigurationRadioButton = new JRadioButton(" Use a Chainsaw config file ");
148         buttonGroup.add(useExistingConfigurationRadioButton);
149         add(useExistingConfigurationRadioButton, c);
150 
151         c = new GridBagConstraints();
152         c.gridx = 0;
153         c.gridy = yPos++;
154         c.fill = GridBagConstraints.HORIZONTAL;
155         c.insets = new Insets(10, 10, 10, 0);
156         add(lowerPanel, c);
157 
158         c = new GridBagConstraints();
159         c.gridx = 0;
160         c.gridy = yPos++;
161         c.weightx = 0.5;
162         c.fill = GridBagConstraints.HORIZONTAL;
163         c.insets = new Insets(0, 10, 0, 0);
164         add(dontWarnAndOKPanel, c);
165 
166         c = new GridBagConstraints();
167         c.gridx = 0;
168         c.gridy = yPos++;
169         c.fill = GridBagConstraints.HORIZONTAL;
170         c.insets = new Insets(10, 10, 10, 0);
171         add(bottomDescriptionPanel, c);
172 
173         /**
174          * This listener activates/deactivates certain controls based on the current
175          * state of the options
176          */
177         ActionListener al = e -> updateEnabledState((Component) e.getSource());
178 
179         logFileReceiverRadioButton.addActionListener(al);
180         log4jConfigReceiverRadioButton.addActionListener(al);
181         networkReceiverRadioButton.addActionListener(al);
182         useExistingConfigurationRadioButton.addActionListener(al);
183 
184         buttonGroup.setSelected(log4jConfigReceiverRadioButton.getModel(), true);
185         updateEnabledState(log4jConfigReceiverRadioButton);
186     }
187 
188     private JPanel buildDontWarnAndOKPanel() {
189         JPanel panel = new JPanel(new GridBagLayout());
190 
191         GridBagConstraints c = new GridBagConstraints();
192         c.gridx = 0;
193         c.gridy = 0;
194         c.weightx = 1.0;
195         c.anchor = GridBagConstraints.LINE_START;
196         dontwarnIfNoReceiver = new JCheckBox(" Always start Chainsaw with this configuration ");
197         panel.add(dontwarnIfNoReceiver, c);
198 
199         saveButton = new JButton(" Save configuration as... ");
200         c = new GridBagConstraints();
201         c.fill = GridBagConstraints.HORIZONTAL;
202         c.gridx = 1;
203         c.gridy = 0;
204         c.insets = new Insets(0, 0, 0, 10);
205         panel.add(saveButton, c);
206 
207         okButton = new JButton(" OK ");
208         cancelButton = new JButton(" Cancel ");
209 
210         List<JButton> okCancelButtons = SwingHelper.orderOKCancelButtons(okButton, cancelButton);
211 
212         c = new GridBagConstraints();
213         c.fill = GridBagConstraints.HORIZONTAL;
214         c.gridx = 2;
215         c.gridy = 0;
216         c.insets = new Insets(0, 0, 0, 10);
217         panel.add(okCancelButtons.get(0), c);
218 
219         c = new GridBagConstraints();
220         c.fill = GridBagConstraints.HORIZONTAL;
221         c.gridx = 3;
222         c.gridy = 0;
223         panel.add(okCancelButtons.get(1), c);
224 
225         cancelButton.addActionListener(new ActionListener() {
226             public void actionPerformed(ActionEvent e) {
227                 panelModel.setCancelled(true);
228                 completionActionListener.actionPerformed(new ActionEvent(this, -1, "cancelled"));
229             }
230         });
231 
232         okButton.addActionListener(new ActionListener() {
233             public void actionPerformed(ActionEvent e) {
234                 panelModel.setCancelled(false);
235                 if (logFileFormatComboBox.getSelectedItem() != null && !(logFileFormatComboBox.getSelectedItem().toString().trim().equals(""))) {
236                     panelModel.setLogFormat(logFileFormatComboBox.getSelectedItem().toString());
237                 }
238                 completionActionListener.actionPerformed(new ActionEvent(this, -1, "ok"));
239             }
240         });
241 
242         saveButton.addActionListener(e -> {
243             try {
244                 URL url = browseFile("Choose a path and file name to save", false);
245                 if (url != null) {
246                     File file = new File(url.toURI());
247                     panelModel.setSaveConfigFile(file);
248                 }
249             } catch (Exception ex) {
250                 logger.error(
251                     "Error browsing for log file", ex);
252             }
253         });
254         return panel;
255     }
256 
257     private JPanel buildBottomDescriptionPanel() {
258         JTextPane descriptionTextPane = new JTextPane();
259         StyledDocument doc = descriptionTextPane.getStyledDocument();
260         SimpleAttributeSet center = new SimpleAttributeSet();
261         StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER);
262         doc.setParagraphAttributes(0, doc.getLength(), center, false);
263 
264         descriptionTextPane.setText(" An example configuration file is available from the Welcome tab ");
265         descriptionTextPane.setEditable(false);
266         descriptionTextPane.setOpaque(false);
267         descriptionTextPane.setFont(getFont());
268 
269         JPanel panel = new JPanel(new GridBagLayout());
270 
271         GridBagConstraints c = new GridBagConstraints();
272         c.gridx = 0;
273         c.gridy = 0;
274         c.weightx = 1.0;
275         c.fill = GridBagConstraints.HORIZONTAL;
276 
277         panel.add(descriptionTextPane, c);
278 
279         return panel;
280     }
281 
282     private JPanel buildNetworkReceiverPanel() {
283         networkReceiverPortComboBoxModel = new DefaultComboBoxModel<>();
284         networkReceiverPortComboBoxModel.addElement("4445");
285         networkReceiverPortComboBoxModel.addElement("4560");
286 
287         networkReceiverPortComboBox = new JComboBox<>(networkReceiverPortComboBoxModel);
288         networkReceiverPortComboBox.setEditable(true);
289         networkReceiverPortComboBox.setOpaque(false);
290 
291         networkReceiverClassNameComboBoxModel = new DefaultComboBoxModel<>();
292         networkReceiverClassNameComboBoxModel.addElement(UDPReceiver.class.getName());
293 
294         networkReceiverClassNameComboBox = new JComboBox<>(networkReceiverClassNameComboBoxModel);
295 
296         networkReceiverClassNameComboBox.setEditable(false);
297         networkReceiverClassNameComboBox.setOpaque(false);
298 
299         JPanel panel = new JPanel(new GridBagLayout());
300 
301         GridBagConstraints c = new GridBagConstraints();
302         c.fill = GridBagConstraints.HORIZONTAL;
303         c.weightx = 0.5;
304         c.gridx = 0;
305         c.gridy = 0;
306         c.insets = new Insets(0, 0, 0, 5);
307         panel.add(networkReceiverClassNameComboBox, c);
308 
309         c = new GridBagConstraints();
310         c.fill = GridBagConstraints.HORIZONTAL;
311         c.weightx = 0.5;
312         c.gridx = 1;
313         c.gridy = 0;
314         panel.add(networkReceiverPortComboBox, c);
315 
316         return panel;
317     }
318 
319     private JPanel buildLog4jConfigReceiverPanel() {
320         log4jConfigURLTextField = new JTextField();
321         browseLog4jConfigButton = new JButton(new AbstractAction(" Open File... ") {
322             public void actionPerformed(ActionEvent e) {
323                 try {
324 
325                     URL url = browseConfig();
326 
327                     if (url != null) {
328                         log4jConfigURLTextField.setText(url.toExternalForm());
329                     }
330                 } catch (Exception ex) {
331                     logger.error(
332                         "Error browsing for log4j config file", ex);
333                 }
334             }
335         });
336 
337         browseLog4jConfigButton.setToolTipText(
338             "Shows a File Open dialog to allow you to find a log4j configuration file");
339         JPanel panel = new JPanel(new GridBagLayout());
340         GridBagConstraints c = new GridBagConstraints();
341         c.gridx = 0;
342         c.gridy = 0;
343         c.gridwidth = 2;
344         c.anchor = GridBagConstraints.LINE_START;
345         c.insets = new Insets(0, 0, 5, 0);
346         panel.add(browseLog4jConfigButton, c);
347 
348         c = new GridBagConstraints();
349         c.gridx = 0;
350         c.gridy = 1;
351         c.insets = new Insets(0, 5, 0, 5);
352         panel.add(new JLabel(" log4j configuration file URL "), c);
353 
354         c = new GridBagConstraints();
355         c.gridx = 1;
356         c.gridy = 1;
357         c.weightx = 0.5;
358         c.fill = GridBagConstraints.HORIZONTAL;
359         panel.add(log4jConfigURLTextField, c);
360 
361 
362         return panel;
363     }
364 
365     private JPanel buildLogFileReceiverPanel() {
366         JPanel panel = new JPanel(new GridBagLayout());
367         browseLogFileButton = new JButton(new AbstractAction(" Open File... ") {
368             public void actionPerformed(ActionEvent e) {
369                 try {
370                     URL url = browseFile("Select a log file", true);
371                     if (url != null) {
372                         String item = url.toURI().toString();
373                         logFileURLTextField.setText(item);
374                     }
375                 } catch (Exception ex) {
376                     logger.error(
377                         "Error browsing for log file", ex);
378                 }
379             }
380         });
381 
382         browseLogFileButton.setToolTipText("Shows a File Open dialog to allow you to find a log file");
383         GridBagConstraints c = new GridBagConstraints();
384         c.gridx = 0;
385         c.gridy = 0;
386         c.anchor = GridBagConstraints.LINE_START;
387         c.insets = new Insets(0, 0, 5, 0);
388         panel.add(browseLogFileButton, c);
389 
390         c = new GridBagConstraints();
391         c.gridx = 0;
392         c.gridy = 1;
393         c.anchor = GridBagConstraints.LINE_END;
394         c.insets = new Insets(0, 0, 5, 5);
395         panel.add(new JLabel(" Log file URL "), c);
396         logFileURLTextField = new JTextField();
397         logFileURLTextField.setEditable(true);
398 
399         c = new GridBagConstraints();
400         c.gridx = 1;
401         c.gridy = 1;
402         c.weightx = 1.0;
403         c.gridwidth = 1;
404         c.anchor = GridBagConstraints.LINE_START;
405         c.fill = GridBagConstraints.HORIZONTAL;
406         c.insets = new Insets(0, 0, 5, 0);
407         panel.add(logFileURLTextField, c);
408 
409         c = new GridBagConstraints();
410         c.gridx = 0;
411         c.gridy = 2;
412         c.anchor = GridBagConstraints.LINE_END;
413         c.insets = new Insets(0, 0, 5, 5);
414         panel.add(new JLabel(" Log file format type "), c);
415 
416         DefaultComboBoxModel<String> comboBoxModel = new DefaultComboBoxModel<>();
417         comboBoxModel.addElement("LogFilePatternReceiver LogFormat");
418         comboBoxModel.addElement("PatternLayout format");
419 
420         logFileFormatTypeComboBox = new JComboBox<>(comboBoxModel);
421         logFileFormatTypeComboBox.setOpaque(false);
422 
423         c = new GridBagConstraints();
424         c.gridx = 1;
425         c.gridy = 2;
426         c.anchor = GridBagConstraints.LINE_START;
427         c.insets = new Insets(0, 0, 5, 0);
428         panel.add(logFileFormatTypeComboBox, c);
429 
430         c = new GridBagConstraints();
431         c.gridx = 0;
432         c.gridy = 3;
433         c.anchor = GridBagConstraints.LINE_END;
434         c.insets = new Insets(0, 5, 5, 5);
435         panel.add(new JLabel(" Log file format "), c);
436 
437         logFileFormatComboBoxModel = new DefaultComboBoxModel<>();
438         seedLogFileFormatComboBoxModel();
439         logFileFormatComboBox = new JComboBox<>(logFileFormatComboBoxModel);
440         logFileFormatComboBox.setEditable(true);
441         logFileFormatComboBox.setOpaque(false);
442         logFileFormatComboBox.setSelectedIndex(0);
443 
444         c = new GridBagConstraints();
445         c.gridx = 1;
446         c.gridy = 3;
447         c.weightx = 0.5;
448         c.anchor = GridBagConstraints.LINE_START;
449         c.fill = GridBagConstraints.HORIZONTAL;
450         c.insets = new Insets(0, 0, 5, 0);
451         panel.add(logFileFormatComboBox, c);
452 
453         c = new GridBagConstraints();
454         c.gridx = 0;
455         c.gridy = 4;
456         c.insets = new Insets(0, 5, 5, 5);
457         panel.add(new JLabel(" Log file timestamp format "), c);
458 
459         logFileFormatTimestampFormatComboBoxModel = new DefaultComboBoxModel<>();
460         seedLogFileFormatTimestampComboBoxModel();
461         logFileFormatTimestampFormatComboBox = new JComboBox<>(logFileFormatTimestampFormatComboBoxModel);
462         logFileFormatTimestampFormatComboBox.setEditable(true);
463         logFileFormatTimestampFormatComboBox.setOpaque(false);
464 
465         c = new GridBagConstraints();
466         c.gridx = 1;
467         c.gridy = 4;
468         c.weightx = 0.5;
469         c.fill = GridBagConstraints.HORIZONTAL;
470         c.insets = new Insets(0, 0, 0, 0);
471         panel.add(logFileFormatTimestampFormatComboBox, c);
472 
473         c = new GridBagConstraints();
474         c.gridx = 0;
475         c.gridy = 5;
476         c.gridwidth = 5;
477         c.insets = new Insets(15, 5, 0, 5);
478         panel.add(new JLabel("<html> See PatternLayout or LogFilePatternReceiver JavaDoc for details </html>"), c);
479         return panel;
480     }
481 
482     private void seedLogFileFormatComboBoxModel() {
483         logFileFormatComboBoxModel.addElement("MESSAGE");
484         logFileFormatComboBoxModel.addElement("%p %t %c - %m%n");
485         logFileFormatComboBoxModel.addElement("LEVEL THREAD LOGGER - MESSAGE");
486         logFileFormatComboBoxModel.addElement("%d{ABSOLUTE} %-5p [%c{1}] %m%n");
487         logFileFormatComboBoxModel.addElement("TIMESTAMP LEVEL [LOGGER] MESSAGE");
488     }
489 
490     private void seedLogFileFormatTimestampComboBoxModel() {
491         logFileFormatTimestampFormatComboBoxModel.addElement("yyyy-MM-dd HH:mm:ss,SSS");
492         logFileFormatTimestampFormatComboBoxModel.addElement("yyyyMMdd HH:mm:ss.SSS");
493         logFileFormatTimestampFormatComboBoxModel.addElement("yyyy/MM/dd HH:mm:ss");
494         logFileFormatTimestampFormatComboBoxModel.addElement("dd MMM yyyy HH:mm:ss,SSS");
495         logFileFormatTimestampFormatComboBoxModel.addElement("HH:mm:ss,SSS");
496         logFileFormatTimestampFormatComboBoxModel.addElement("yyyy-MM-ddTHH:mm");
497         logFileFormatTimestampFormatComboBoxModel.addElement("yyyy-MM-ddTHH:mm:ss.SSS");
498     }
499 
500     private JPanel buildUseExistingConfigurationPanel() {
501         existingConfigurationComboBoxModel = new DefaultComboBoxModel<>();
502 
503         existingConfigurationComboBox = new JComboBox<>(existingConfigurationComboBoxModel);
504         existingConfigurationComboBox.setOpaque(false);
505         existingConfigurationComboBox.setToolTipText("Previously loaded configurations can be chosen here");
506         existingConfigurationComboBox.setEditable(true);
507 
508         existingConfigurationComboBox.getEditor().getEditorComponent().addFocusListener(
509             new FocusListener() {
510                 public void focusGained(FocusEvent e) {
511                     selectAll();
512                 }
513 
514                 private void selectAll() {
515                     existingConfigurationComboBox.getEditor().selectAll();
516                 }
517 
518                 public void focusLost(FocusEvent e) {
519                 }
520             });
521 
522         browseForAnExistingConfigurationButton = new JButton(new AbstractAction(" Open File... ") {
523             public void actionPerformed(ActionEvent e) {
524                 try {
525 
526                     URL url = browseConfig();
527 
528                     if (url != null) {
529                         existingConfigurationComboBoxModel.addElement(url.toExternalForm());
530                         existingConfigurationComboBox.getModel().setSelectedItem(
531                             url);
532                     }
533                 } catch (Exception ex) {
534                     logger.error(
535                         "Error browsing for Configuration file", ex);
536                 }
537             }
538         });
539 
540         browseForAnExistingConfigurationButton.setToolTipText(
541             "Shows a File Open dialog to allow you to find a configuration file");
542         JPanel panel = new JPanel(new GridBagLayout());
543         GridBagConstraints c = new GridBagConstraints();
544         c.gridx = 0;
545         c.gridy = 0;
546         c.gridwidth = 2;
547         c.anchor = GridBagConstraints.LINE_START;
548         c.insets = new Insets(0, 0, 5, 0);
549         panel.add(browseForAnExistingConfigurationButton, c);
550 
551         c = new GridBagConstraints();
552         c.gridx = 0;
553         c.gridy = 1;
554         c.insets = new Insets(0, 5, 0, 5);
555         panel.add(new JLabel(" Configuration file URL "), c);
556 
557         c = new GridBagConstraints();
558         c.gridx = 1;
559         c.gridy = 1;
560         c.weightx = 0.5;
561         c.fill = GridBagConstraints.HORIZONTAL;
562         panel.add(existingConfigurationComboBox, c);
563 
564 
565         return panel;
566     }
567 
568     /**
569      * Returns the current Model/state of the chosen options by the user.
570      *
571      * @return model
572      */
573     PanelModel getModel() {
574         return panelModel;
575     }
576 
577     /**
578      * Clients of this panel can configure the ActionListener to be used
579      * when the user presses the OK button, so they can read
580      * back this Panel's model top determine what to do.
581      *
582      * @param actionListener listener which will be notified that ok was selected
583      */
584     void setCompletionActionListener(ActionListener actionListener) {
585         completionActionListener = actionListener;
586     }
587 
588     private void updateEnabledState(Component component) {
589         lowerPanel.removeAll();
590         if (component == useExistingConfigurationRadioButton) {
591             lowerPanel.add(useExistingConfigurationPanel, BorderLayout.NORTH);
592         }
593         if (component == networkReceiverRadioButton) {
594             lowerPanel.add(networkReceiverPanel, BorderLayout.NORTH);
595         }
596         if (component == logFileReceiverRadioButton) {
597             lowerPanel.add(logFileReceiverPanel, BorderLayout.NORTH);
598         }
599         if (component == log4jConfigReceiverRadioButton) {
600             lowerPanel.add(log4jConfigReceiverPanel, BorderLayout.NORTH);
601         }
602         lowerPanel.revalidate();
603         lowerPanel.repaint();
604     }
605 
606     /**
607      * Returns the URL chosen by the user for a Configuration file
608      * or null if they cancelled.
609      */
610     private URL browseConfig() throws MalformedURLException {
611         //hiding and showing the dialog to avoid focus issues with 2 dialogs
612         dialog.setVisible(false);
613         File selectedFile = SwingHelper.promptForFile(dialog, null, "Choose a Chainsaw configuration file", true);
614         URL result = null;
615         if (selectedFile == null) {
616             result = null;
617         }
618         if (selectedFile != null && (!selectedFile.exists() || !selectedFile.canRead())) {
619             result = null;
620         }
621         if (selectedFile != null) {
622             result = selectedFile.toURI().toURL();
623         }
624         EventQueue.invokeLater(() -> dialog.setVisible(true));
625         return result;
626     }
627 
628     /**
629      * Returns the URL chosen by the user for a Configuration file
630      * or null if they cancelled.
631      */
632     private URL browseFile(String title, boolean loadDialog) throws MalformedURLException {
633         //hiding and showing the dialog to avoid focus issues with 2 dialogs
634         dialog.setVisible(false);
635         File selectedFile = SwingHelper.promptForFile(dialog, null, title, loadDialog);
636         URL result = null;
637         if (selectedFile == null) {
638             result = null;
639         }
640         if (selectedFile != null && (!selectedFile.exists() || !selectedFile.canRead())) {
641             result = null;
642         }
643         if (selectedFile != null) {
644             result = selectedFile.toURI().toURL();
645         }
646         EventQueue.invokeLater(() -> dialog.setVisible(true));
647         return result;
648     }
649 
650     public static void main(String[] args) {
651 
652         JFrame frame = new JFrame();
653         frame.getContentPane().add(new ReceiverConfigurationPanel());
654         frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
655         frame.pack();
656         frame.setVisible(true);
657     }
658 
659     /**
660      * @return Returns the dontWarnMeAgain.
661      */
662     public final boolean isDontWarnMeAgain() {
663 
664         return dontwarnIfNoReceiver.isSelected();
665     }
666 
667     public void setDialog(Container dialog) {
668         this.dialog = dialog;
669     }
670 
671     /**
672      * This class represents the model of the chosen options the user
673      * has configured.
674      */
675     class PanelModel {
676 
677         private File file;
678         //default to cancelled
679         private boolean cancelled = true;
680         private String lastLogFormat;
681         private File saveConfigFile;
682 
683         public PanelModel() {
684             file = new File(SettingsManager.getInstance().getSettingsDirectory(), "receiver-config.xml");
685         }
686 
687         boolean isNetworkReceiverMode() {
688 
689             return !cancelled && networkReceiverRadioButton.isSelected();
690         }
691 
692         int getNetworkReceiverPort() {
693 
694             return Integer.parseInt(networkReceiverPortComboBoxModel.getSelectedItem().toString());
695         }
696 
697         Class<? extends Receiver> getNetworkReceiverClass() throws ClassNotFoundException {
698             return Class.forName(networkReceiverClassNameComboBoxModel.getSelectedItem().toString()).asSubclass(Receiver.class);
699         }
700 
701         boolean isLoadConfig() {
702 
703             return !cancelled && useExistingConfigurationRadioButton.isSelected();
704         }
705 
706         boolean isLogFileReceiverConfig() {
707             return !cancelled && logFileReceiverRadioButton.isSelected();
708         }
709 
710         boolean isLog4jConfig() {
711             return !cancelled && log4jConfigReceiverRadioButton.isSelected();
712         }
713 
714         URL getConfigToLoad() {
715 
716             try {
717                 return new URL(existingConfigurationComboBoxModel.getSelectedItem().toString());
718             } catch (MalformedURLException e) {
719                 return null;
720             }
721         }
722 
723         URL getDefaultConfigFileURL() {
724             try {
725                 return file.toURI().toURL();
726             } catch (MalformedURLException e) {
727                 logger.error("Error loading saved configurations by Chainsaw", e);
728             }
729             return null;
730         }
731 
732         File getSaveConfigFile() {
733             return saveConfigFile;
734         }
735 
736         void setSaveConfigFile(File file) {
737             this.saveConfigFile = file;
738         }
739 
740         URL getLogFileURL() {
741             try {
742                 Object item = logFileURLTextField.getText();
743                 if (item != null) {
744                     return new URL(item.toString());
745                 }
746             } catch (MalformedURLException e) {
747                 logger.error("Error retrieving log file URL", e);
748             }
749             return null;
750         }
751 
752         String getLogFormat() {
753             if (cancelled) {
754                 return lastLogFormat;
755             }
756             Object item = logFileFormatComboBox.getSelectedItem();
757             if (item != null) {
758                 return item.toString();
759             }
760             return null;
761         }
762 
763         boolean isPatternLayoutLogFormat() {
764             Object item = logFileFormatTypeComboBox.getSelectedItem();
765             return item != null && item.toString().toLowerCase(Locale.ENGLISH).contains("patternlayout");
766         }
767 
768         String getLogFormatTimestampFormat() {
769             Object item = logFileFormatTimestampFormatComboBox.getSelectedItem();
770             if (item != null) {
771                 return item.toString();
772             }
773 
774             return null;
775         }
776 
777         public void setCancelled(boolean cancelled) {
778             this.cancelled = cancelled;
779         }
780 
781         public void setLogFormat(String lastLogFormat) {
782             this.lastLogFormat = lastLogFormat;
783             logFileFormatComboBoxModel.removeElement(lastLogFormat);
784             logFileFormatComboBoxModel.insertElementAt(lastLogFormat, 0);
785             logFileFormatComboBox.setSelectedIndex(0);
786         }
787 
788         public boolean isCancelled() {
789             return cancelled;
790         }
791 
792         public File getLog4jConfigFile() {
793             try {
794                 URL newConfigurationURL = new URL(log4jConfigURLTextField.getText());
795                 return new File(newConfigurationURL.toURI());
796             } catch (URISyntaxException | MalformedURLException e) {
797                 e.printStackTrace();
798             }
799             return null;
800         }
801     }
802 }