You are viewing a plain text version of this content. The canonical link for it is here.
Posted to general@logging.apache.org by sd...@apache.org on 2010/07/22 08:58:55 UTC

svn commit: r966518 - in /logging/chainsaw/trunk/src/main: java/org/apache/log4j/chainsaw/ java/org/apache/log4j/chainsaw/receivers/ java/org/apache/log4j/chainsaw/vfs/ resources/org/apache/log4j/chainsaw/help/

Author: sdeboy
Date: Thu Jul 22 06:58:54 2010
New Revision: 966518

URL: http://svn.apache.org/viewvc?rev=966518&view=rev
Log:
- Renamed the auto-saved xml configuration to receiver-config.xml
- Replaced 'load chainsaw configuration' menu item to display a new configuration dialog instead of taking the user to the auto-config URL preference
- New configuration dialog provides ability to define a VFSLogFilePatternReceiver (and ability to provide a PatternLayout as the format)
- Shifted the thumbnail bar tooltip down 30 pixels so the tooltip doesn't block the thumbnail under the pointer

Added:
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java   (contents, props changed)
      - copied, changed from r965025, logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/NoReceiversWarningPanel.java
Removed:
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/NoReceiversWarningPanel.java
Modified:
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/FileMenu.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferenceModel.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogUI.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/receivers/ReceiversPanel.java
    logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java
    logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java?rev=966518&r1=966517&r2=966518&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java Thu Jul 22 06:58:54 2010
@@ -169,10 +169,6 @@ public static void main(String[] args) {
     return model;
   }
 
-    public void browseForConfiguration() {
-        generalAllPrefPanel.browseForConfiguration();
-    }
-
     public class VisualsPrefPanel extends BasicPrefPanel {
     private final JRadioButton topPlacement = new JRadioButton("Top");
     private final JRadioButton bottomPlacement = new JRadioButton("Bottom");

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/FileMenu.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/FileMenu.java?rev=966518&r1=966517&r2=966518&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/FileMenu.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/FileMenu.java Thu Jul 22 06:58:54 2010
@@ -65,7 +65,7 @@ class FileMenu extends JMenu {
 
     loadConfigAction = new AbstractAction("Load Chainsaw configuration"){
         public void actionPerformed(ActionEvent actionEvent) {
-            logUI.showApplicationPreferencesBrowse();
+            logUI.showReceiverConfiguration();
         }
     };
 

Added: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java?rev=966518&view=auto
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java (added)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java Thu Jul 22 06:58:54 2010
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.log4j.chainsaw;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.log4j.helpers.OptionConverter;
+import org.apache.log4j.pattern.ClassNamePatternConverter;
+import org.apache.log4j.pattern.FileLocationPatternConverter;
+import org.apache.log4j.pattern.FullLocationPatternConverter;
+import org.apache.log4j.pattern.LevelPatternConverter;
+import org.apache.log4j.pattern.LineLocationPatternConverter;
+import org.apache.log4j.pattern.LineSeparatorPatternConverter;
+import org.apache.log4j.pattern.LiteralPatternConverter;
+import org.apache.log4j.pattern.LoggerPatternConverter;
+import org.apache.log4j.pattern.LoggingEventPatternConverter;
+import org.apache.log4j.pattern.MessagePatternConverter;
+import org.apache.log4j.pattern.MethodLocationPatternConverter;
+import org.apache.log4j.pattern.NDCPatternConverter;
+import org.apache.log4j.pattern.PatternParser;
+import org.apache.log4j.pattern.PropertiesPatternConverter;
+import org.apache.log4j.pattern.RelativeTimePatternConverter;
+import org.apache.log4j.pattern.SequenceNumberPatternConverter;
+import org.apache.log4j.pattern.ThreadPatternConverter;
+
+public class LogFilePatternLayoutBuilder
+{
+    public static String getLogFormatFromPatternLayout(String patternLayout) {
+        String input = OptionConverter.convertSpecialChars(patternLayout);
+        List converters = new ArrayList();
+        List fields = new ArrayList();
+        Map converterRegistry = null;
+
+        PatternParser.parse(input, converters, fields, converterRegistry, PatternParser.getPatternLayoutRules());
+        return getFormatFromConverters(converters);
+    }
+
+    private static String getFormatFromConverters(List converters) {
+        StringBuffer buffer = new StringBuffer();
+        for (Iterator iter = converters.iterator();iter.hasNext();) {
+            LoggingEventPatternConverter converter = (LoggingEventPatternConverter)iter.next();
+            if (converter instanceof MessagePatternConverter) {
+                buffer.append("MESSAGE");
+            } else if (converter instanceof LoggerPatternConverter) {
+                buffer.append("LOGGER");
+            } else if (converter instanceof ClassNamePatternConverter) {
+                buffer.append("CLASS");
+            } else if (converter instanceof RelativeTimePatternConverter) {
+                buffer.append("PROP(RELATIVETIME)");
+            } else if (converter instanceof ThreadPatternConverter) {
+                buffer.append("THREAD");
+            } else if (converter instanceof NDCPatternConverter) {
+                buffer.append("NDC");
+            } else if (converter instanceof LiteralPatternConverter) {
+                LiteralPatternConverter literal = (LiteralPatternConverter)converter;
+                //format shouldn't normally take a null, but we're getting a literal, so passing in the buffer will work
+                literal.format(null, buffer);
+            } else if (converter instanceof SequenceNumberPatternConverter) {
+                buffer.append("PROP(log4jid)");
+            } else if (converter instanceof LevelPatternConverter) {
+                buffer.append("LEVEL");
+            } else if (converter instanceof MethodLocationPatternConverter) {
+                buffer.append("METHOD");
+            } else if (converter instanceof FullLocationPatternConverter) {
+                buffer.append("PROP(locationInfo)");
+            } else if (converter instanceof LineLocationPatternConverter) {
+                buffer.append("LINE");
+            } else if (converter instanceof FileLocationPatternConverter) {
+                buffer.append("FILE");
+            } else if (converter instanceof PropertiesPatternConverter) {
+                PropertiesPatternConverter propertiesConverter = (PropertiesPatternConverter) converter;
+//                String option = propertiesConverter.getOption();
+//                if (option != null && option.length() > 0) {
+//                    buffer.append("PROP(" + option + ")");
+//                } else {
+                    buffer.append("PROP(PROPERTIES)");
+//                }
+            } else if (converter instanceof LineSeparatorPatternConverter) {
+                //done
+            }
+        }
+        return buffer.toString();
+    }
+}

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanel.java?rev=966518&r1=966517&r2=966518&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanel.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanel.java Thu Jul 22 06:58:54 2010
@@ -3564,6 +3564,12 @@ public class LogPanel extends DockablePa
             }
         }
 
+        public Point getToolTipLocation(MouseEvent event)
+        {
+            //shift tooltip down so the the pointer doesn't cover up events below the current mouse location
+            return new Point(event.getX(), event.getY() + 30);
+        }
+
         private void drawEvent(Color newColor, int verticalLocation, int eventHeight, Graphics g, int x, int width) {
 //            System.out.println("painting: - color: " + newColor + ", verticalLocation: " + verticalLocation + ", eventHeight: " + eventHeight);
             //center drawing at vertical location

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferenceModel.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferenceModel.java?rev=966518&r1=966517&r2=966518&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferenceModel.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferenceModel.java Thu Jul 22 06:58:54 2010
@@ -122,7 +122,8 @@ public class LogPanelPreferenceModel imp
   private TableColumn findColumnByHeader(List list, String header) {
 	  for (Iterator iter = list.iterator();iter.hasNext();) {
 		  TableColumn c = (TableColumn)iter.next();
-		  if (c.getHeaderValue().equals(header)) {
+          //columns may have changed - header may not exist
+		  if (c != null && c.getHeaderValue() != null && c.getHeaderValue().equals(header)) {
 			  return c;
 		  }
 	  }

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogUI.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogUI.java?rev=966518&r1=966517&r2=966518&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogUI.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/LogUI.java Thu Jul 22 06:58:54 2010
@@ -105,6 +105,7 @@ import org.apache.log4j.chainsaw.prefs.S
 import org.apache.log4j.chainsaw.prefs.SettingsListener;
 import org.apache.log4j.chainsaw.prefs.SettingsManager;
 import org.apache.log4j.chainsaw.receivers.ReceiversPanel;
+import org.apache.log4j.chainsaw.vfs.VFSLogFilePatternReceiver;
 import org.apache.log4j.net.SocketNodeEventListener;
 import org.apache.log4j.plugins.Plugin;
 import org.apache.log4j.plugins.PluginEvent;
@@ -1038,7 +1039,7 @@ public class LogUI extends JFrame implem
         && applicationPreferenceModel.isShowNoReceiverWarning()) {
       EventQueue.invokeLater(new Runnable() {
           public void run() {
-              showNoReceiversWarningPanel();
+              showReceiverConfigurationPanel();
           }
       });
     }
@@ -1385,34 +1386,51 @@ public class LogUI extends JFrame implem
   }
 
   /**
-   * Displays a warning dialog about having no Receivers defined and allows the
-   * user to choose some options for configuration
+   * Displays a dialog which will provide options for selecting a configuratino
    */
-  private void showNoReceiversWarningPanel() {
-    final NoReceiversWarningPanel noReceiversWarningPanel =
-      new NoReceiversWarningPanel();
+  private void showReceiverConfigurationPanel() {
+    final ReceiverConfigurationPanel receiverConfigurationPanel =
+      new ReceiverConfigurationPanel();
 
     final SettingsListener sl =
       new SettingsListener() {
         public void loadSettings(LoadSettingsEvent event) {
-          int size = event.asInt("SavedConfigs.Size");
-          Object[] configs = new Object[size];
+          if (event.getSetting("SavedConfigs.Size") != null) {
+              int configSize = event.asInt("SavedConfigs.Size");
+              Object[] configs = new Object[configSize];
 
-          for (int i = 0; i < size; i++) {
-            configs[i] = event.getSetting("SavedConfigs." + i);
+              for (int i = 0; i < configSize; i++) {
+                configs[i] = event.getSetting("SavedConfigs." + i);
+              }
+
+              receiverConfigurationPanel.getModel().setRememberedConfigs(configs);
           }
 
-          noReceiversWarningPanel.getModel().setRememberedConfigs(configs);
+          if (event.getSetting("SavedLayouts.Size") != null) {
+              int layoutSize = event.asInt("SavedLayouts.Size");
+              Object[] layouts = new Object[layoutSize];
+
+              for (int i = 0; i < layoutSize; i++) {
+                layouts[i] = event.getSetting("SavedLayouts." + i);
+              }
+              receiverConfigurationPanel.getModel().setRememberedLayouts(layouts);
+          }
         }
 
         public void saveSettings(SaveSettingsEvent event) {
-          Object[] configs =
-            noReceiversWarningPanel.getModel().getRememberedConfigs();
+          Object[] configs = receiverConfigurationPanel.getModel().getRememberedConfigs();
           event.saveSetting("SavedConfigs.Size", configs.length);
 
           for (int i = 0; i < configs.length; i++) {
             event.saveSetting("SavedConfigs." + i, configs[i].toString());
           }
+          Object[] layouts = receiverConfigurationPanel.getModel().getRememberedLayouts();
+          event.saveSetting("SavedLayouts.Size", layouts.length);
+
+          for (int i = 0; i < layouts.length; i++) {
+            //the layout is an object, not a string (containing timestamp format, pattern & pattern type)
+            event.saveSetting("SavedLayouts." + i, layouts[i]);
+          }
         }
       };
 
@@ -1427,19 +1445,19 @@ public class LogUI extends JFrame implem
       new Runnable() {
         public void run() {
           final JDialog dialog = new JDialog(LogUI.this, true);
-          dialog.setTitle("Warning: You have no Receivers defined...");
+          dialog.setTitle("Load events into Chainsaw");
           dialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
 
           dialog.setResizable(false);
 
-          noReceiversWarningPanel.setOkActionListener(
+          receiverConfigurationPanel.setOkActionListener(
             new ActionListener() {
               public void actionPerformed(ActionEvent e) {
                 dialog.setVisible(false);
               }
             });
 
-          dialog.getContentPane().add(noReceiversWarningPanel);
+          dialog.getContentPane().add(receiverConfigurationPanel);
 
           dialog.pack();
 
@@ -1449,29 +1467,27 @@ public class LogUI extends JFrame implem
             (screenSize.height / 2) - (dialog.getHeight() / 2));
 
           dialog.setVisible(true);
-          applicationPreferenceModel.setShowNoReceiverWarning(!noReceiversWarningPanel.isDontWarnMeAgain());
+          applicationPreferenceModel.setShowNoReceiverWarning(!receiverConfigurationPanel.isDontWarnMeAgain());
+          URL configURL = null;
 
-          if (noReceiversWarningPanel.getModel().isManualMode()) {
-            applicationPreferenceModel.setReceivers(true);
-          } else if (noReceiversWarningPanel.getModel().isSimpleReceiverMode()) {
-            int port = noReceiversWarningPanel.getModel().getSimplePort();
-            Class receiverClass =
-              noReceiversWarningPanel.getModel().getSimpleReceiverClass();
+          if (receiverConfigurationPanel.getModel().isNetworkReceiverMode()) {
+            int port = receiverConfigurationPanel.getModel().getNetworkReceiverPort();
+            Class receiverClass = receiverConfigurationPanel.getModel().getNetworkReceiverClass();
 
             try {
-              Receiver simpleReceiver = (Receiver) receiverClass.newInstance();
-              simpleReceiver.setName("Simple Receiver");
+              Receiver networkReceiver = (Receiver) receiverClass.newInstance();
+              networkReceiver.setName(receiverClass.getSimpleName() + "-" + port);
 
               Method portMethod =
-                simpleReceiver.getClass().getMethod(
+                networkReceiver.getClass().getMethod(
                   "setPort", new Class[] { int.class });
               portMethod.invoke(
-                simpleReceiver, new Object[] { new Integer(port) });
+                networkReceiver, new Object[] { new Integer(port) });
 
-              simpleReceiver.setThreshold(Level.TRACE);
+              networkReceiver.setThreshold(Level.TRACE);
 
-              pluginRegistry.addPlugin(simpleReceiver);
-              simpleReceiver.activateOptions();
+              pluginRegistry.addPlugin(networkReceiver);
+              networkReceiver.activateOptions();
               receiversPanel.updateReceiverTreeInDispatchThread();
             } catch (Exception e) {
               MessageCenter.getInstance().getLogger().error(
@@ -1479,33 +1495,61 @@ public class LogUI extends JFrame implem
               MessageCenter.getInstance().getLogger().info(
                 "An error occurred creating your Receiver");
             }
-          } else if (noReceiversWarningPanel.getModel().isLoadConfig() ||
-                  noReceiversWarningPanel.getModel().isLoadSavedConfigs()) {
-            final URL url;
-            if (noReceiversWarningPanel.getModel().isLoadSavedConfigs()) {
-                url = noReceiversWarningPanel.getModel().getSavedConfigToLoad();
+          } else if (receiverConfigurationPanel.getModel().isLoadConfig() ||
+                  receiverConfigurationPanel.getModel().isLoadSavedConfigs()) {
+            if (receiverConfigurationPanel.getModel().isLoadSavedConfigs()) {
+                configURL = receiverConfigurationPanel.getModel().getSavedConfigToLoad();
             } else {
-                url = noReceiversWarningPanel.getModel().getConfigToLoad();
+                configURL = receiverConfigurationPanel.getModel().getConfigToLoad();
             }
+          } else if (receiverConfigurationPanel.getModel().isLogFileReceiverConfig()) {
+            try {
+                URL fileURL = receiverConfigurationPanel.getModel().getLogFileURL();
+                if (fileURL != null) {
+                    VFSLogFilePatternReceiver fileReceiver = new VFSLogFilePatternReceiver();
+                    fileReceiver.setName(fileURL.getFile());
+                    fileReceiver.setAutoReconnect(true);
+                    fileReceiver.setContainer(LogUI.this);
+                    fileReceiver.setAppendNonMatches(true);
+                    fileReceiver.setFileURL(fileURL.toURI().toString());
+                    fileReceiver.setTailing(true);
+                    if (receiverConfigurationPanel.getModel().isPatternLayoutLogFormat()) {
+                        fileReceiver.setLogFormat(LogFilePatternLayoutBuilder.getLogFormatFromPatternLayout(receiverConfigurationPanel.getModel().getLogFormat()));
+                    } else {
+                        fileReceiver.setLogFormat(receiverConfigurationPanel.getModel().getLogFormat());
+                    }
+                    fileReceiver.setTimestampFormat(receiverConfigurationPanel.getModel().getLogFormatTimestampFormat());
+                    fileReceiver.setThreshold(Level.TRACE);
 
-            if (url != null) {
+                    pluginRegistry.addPlugin(fileReceiver);
+                    fileReceiver.activateOptions();
+                    receiversPanel.updateReceiverTreeInDispatchThread();
+                }
+            } catch (Exception e) {
+                MessageCenter.getInstance().getLogger().error(
+                  "Error creating Receiver", e);
+                MessageCenter.getInstance().getLogger().info(
+                  "An error occurred creating your Receiver");
+            }
+          }
+            if (configURL != null) {
               MessageCenter.getInstance().getLogger().debug(
-                "Initialiazing Log4j with " + url.toExternalForm());
-
+                "Initialiazing Log4j with " + configURL.toExternalForm());
+              final URL finalURL = configURL;
               new Thread(
                 new Runnable() {
                   public void run() {
-                    if (noReceiversWarningPanel.isDontWarnMeAgain()) {
-                        applicationPreferenceModel.setConfigurationURL(url.toExternalForm());
-                    }                                                                        
-                    loadConfigurationUsingPluginClassLoader(url);
+                    if (receiverConfigurationPanel.isDontWarnMeAgain()) {
+                        applicationPreferenceModel.setConfigurationURL(finalURL.toExternalForm());
+                    }
+                    loadConfigurationUsingPluginClassLoader(finalURL);
 
 
                     receiversPanel.updateReceiverTreeInDispatchThread();
                   }
                 }).start();
             }
-          }
+
         }
       });
   }
@@ -1550,10 +1594,8 @@ public class LogUI extends JFrame implem
     preferencesFrame.setVisible(true);
   }
 
-  public void showApplicationPreferencesBrowse() {
-      applicationPreferenceModelPanel.updateModel();
-      preferencesFrame.setVisible(true);
-      applicationPreferenceModelPanel.browseForConfiguration();
+  public void showReceiverConfiguration() {
+      showReceiverConfigurationPanel();
   }
 
   public void showAboutBox() {

Copied: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java (from r965025, logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/NoReceiversWarningPanel.java)
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java?p2=logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java&p1=logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/NoReceiversWarningPanel.java&r1=965025&r2=966518&rev=966518&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/NoReceiversWarningPanel.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java Thu Jul 22 06:58:54 2010
@@ -17,10 +17,9 @@
 package org.apache.log4j.chainsaw;
 
 import java.awt.Component;
-import java.awt.Dimension;
 import java.awt.GridBagConstraints;
 import java.awt.GridBagLayout;
-import java.awt.GridLayout;
+import java.awt.Insets;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.FocusEvent;
@@ -28,10 +27,12 @@ import java.awt.event.FocusListener;
 import java.io.File;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
 import javax.swing.AbstractAction;
 import javax.swing.BorderFactory;
-import javax.swing.Box;
-import javax.swing.BoxLayout;
 import javax.swing.ButtonGroup;
 import javax.swing.DefaultComboBoxModel;
 import javax.swing.DefaultListCellRenderer;
@@ -46,422 +47,528 @@ import javax.swing.JPanel;
 import javax.swing.JRadioButton;
 import javax.swing.JTextPane;
 import javax.swing.SwingUtilities;
-import javax.swing.event.ListDataEvent;
-import javax.swing.event.ListDataListener;
 import javax.swing.filechooser.FileFilter;
+
 import org.apache.log4j.LogManager;
 import org.apache.log4j.Logger;
 import org.apache.log4j.chainsaw.prefs.SettingsManager;
-import org.apache.log4j.net.PortBased;
-import org.apache.log4j.net.SocketAppender;
-import org.apache.log4j.net.SocketHubReceiver;
 import org.apache.log4j.net.SocketReceiver;
+import org.apache.log4j.net.UDPReceiver;
 
 
 /**
- * A dialog panel to inform the user that they do not have
- * Receiver's defined, and prompting them to either
- * load a Log4j Log file, search for a Log4j configuration file
- * or use the GUI to define the Receivers
+ * A panel providing receiver configuration options
  *
  * @author Paul Smith
  */
-class NoReceiversWarningPanel extends JPanel {
-
-    private final JComboBox previousConfigs = new JComboBox();
+class ReceiverConfigurationPanel extends JPanel {
+    private final Logger logger = LogManager.getLogger(ReceiverConfigurationPanel.class);
 
-    private final JRadioButton simpleReceiver = new JRadioButton(
-            "Define a ");
+    private final PanelModel panelModel = new PanelModel();
 
-    private final JRadioButton justLoadingFile = new JRadioButton(
-            "I'm fine thanks, don't worry");
-    private final JRadioButton searchOption = new JRadioButton(
-            "Use an existing receiver configuration file...");
-    private final JRadioButton chainsawSavedConfigOption = new JRadioButton(
-            "Use most recent configuration defined through the Receiver configuration panel");
-    private final JRadioButton manualOption = new JRadioButton(
-            "Define receivers through the Receiver configuration panel (configuration saved on exit)");
-    private final JButton okButton = new JButton(" OK ");
-    private final PanelModel model = new PanelModel();
-    final DefaultComboBoxModel configModel = new DefaultComboBoxModel();
-
-    final DefaultComboBoxModel simpleReceiverModel = new DefaultComboBoxModel();
-    final DefaultComboBoxModel simplePortModel = new DefaultComboBoxModel();
-
-    private boolean dontWarnMeAgain = false;
-    
-    private final Logger logger = LogManager.getLogger(NoReceiversWarningPanel.class);
+    //network receiver widgets
+    private JComboBox networkReceiverPortComboBox;
+    private JComboBox networkReceiverClassNameComboBox;
+    private DefaultComboBoxModel networkReceiverClassNameComboBoxModel;
+    private DefaultComboBoxModel networkReceiverPortComboBoxModel;
+
+    //logfile receiver widgets
+    private JButton browseLogFileButton;
+    private JComboBox logFileFormatTypeComboBox;
+
+    private JComboBox logFileFormatComboBox;
+    private JComboBox logFileFormatTimestampFormatComboBox;
+    private JComboBox logFileURLComboBox;
+    private DefaultComboBoxModel logFileFormatComboBoxModel;
+    private DefaultComboBoxModel logFileFormatTimestampFormatComboBoxModel;
+    private DefaultComboBoxModel logFileURLComboBoxModel;
+
+    //use existing configuration widgets
+    private JButton browseForAnExistingConfigurationButton;
+    private DefaultComboBoxModel existingConfigurationComboBoxModel;
+    private JComboBox existingConfigurationComboBox;
+
+    //don't warn again widgets
+    private JCheckBox dontwarnIfNoReceiver;
+
+    //ok button
+    private JButton okButton;
+
+    //radiobutton widgets
+    private JRadioButton logFileReceiverRadioButton;
+    private JRadioButton networkReceiverRadioButton;
+    private JRadioButton doNothingRadioButton;
+    private JRadioButton useExistingConfigurationRadioButton;
+    private JRadioButton useAutoSavedConfigRadioButton;
+    private ButtonGroup buttonGroup;
+
+    ReceiverConfigurationPanel() {
+        JPanel topDescriptionPanel = buildTopDescriptionPanel();
+        JPanel networkReceiverPanel = buildNetworkReceiverPanel();
+        JPanel logFileReceiverPanel = buildLogFileReceiverPanel();
+        JPanel useExistingConfigurationPanel = buildUseExistingConfigurationPanel();
+        JPanel dontWarnAndOKPanel = buildDontWarnAndOKPanel();
+        JPanel bottomDescriptionPanel = buildBottomDescriptionPanel();
 
-    NoReceiversWarningPanel() {
-        initComponents();
-    }
-
-    /**
-     * Returns the current Model/state of the chosen options by the user.
-     * @return
-     */
-    PanelModel getModel() {
+        buttonGroup = new ButtonGroup();
 
-        return model;
-    }
+        setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
 
-    /**
-     * Clients of this panel can configure the ActionListener to be used
-     * when the user presses the OK button, so they can read
-     * back this Panel's model top determine what to do.
-     * @param actionListener
-     */
-    void setOkActionListener(ActionListener actionListener) {
-        okButton.addActionListener(actionListener);
-    }
-
-    /**
-     * Sets up all the GUI components for this paenl
-     */
-    private void initComponents() {
         setLayout(new GridBagLayout());
 
-        GridBagConstraints gc = new GridBagConstraints();
-
-        setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
-
-        gc.gridx = 1;
-        gc.fill = GridBagConstraints.BOTH;
-        gc.weightx = 1.0;
-        gc.weighty = 1.0;
+        GridBagConstraints c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 0;
+        c.fill = GridBagConstraints.HORIZONTAL;
+        c.insets = new Insets(0, 0, 10, 0);
+        add(topDescriptionPanel, c);
+
+        c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 1;
+        c.fill = GridBagConstraints.HORIZONTAL;
+        logFileReceiverRadioButton = new JRadioButton("Load events from a regular log file (and continue to tail the file)");
+        buttonGroup.add(logFileReceiverRadioButton);
+        add(logFileReceiverRadioButton, c);
+
+        c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 2;
+        c.weightx = 0.5;
+        c.fill = GridBagConstraints.HORIZONTAL;
+        c.insets = new Insets(0, 20, 20, 0);
+        add(logFileReceiverPanel, c);
+
+        c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 3;
+        c.fill = GridBagConstraints.HORIZONTAL;
+        networkReceiverRadioButton = new JRadioButton("Receive events from the network");
+        buttonGroup.add(networkReceiverRadioButton);
+        add(networkReceiverRadioButton, c);
+
+        c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 4;
+        c.weightx = 0.5;
+        c.fill = GridBagConstraints.HORIZONTAL;
+        c.insets = new Insets(0, 20, 20, 0);
+        add(networkReceiverPanel, c);
+
+        c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 5;
+        c.fill = GridBagConstraints.HORIZONTAL;
+        useExistingConfigurationRadioButton = new JRadioButton("Use an existing Chainsaw configuration file...");
+        buttonGroup.add(useExistingConfigurationRadioButton);
+        add(useExistingConfigurationRadioButton, c);
+
+        c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 6;
+        c.weightx = 0.5;
+        c.fill = GridBagConstraints.HORIZONTAL;
+        c.insets = new Insets(0, 20, 20, 0);
+        add(useExistingConfigurationPanel, c);
+
+        c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 7;
+        c.fill = GridBagConstraints.HORIZONTAL;
+        c.insets = new Insets(0, 0, 20, 0);
+        useAutoSavedConfigRadioButton = new JRadioButton("Use last used/auto-saved configuration from $HOME/.chainsaw/receiver-config.xml");
+        buttonGroup.add(useAutoSavedConfigRadioButton);
+        add(useAutoSavedConfigRadioButton, c);
+
+        c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 9;
+        c.fill = GridBagConstraints.HORIZONTAL;
+        doNothingRadioButton = new JRadioButton("I'm fine thanks, don't worry");
+        buttonGroup.add(doNothingRadioButton);
+        add(doNothingRadioButton, c);
+
+        c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 10;
+        c.weightx = 0.5;
+        c.fill = GridBagConstraints.HORIZONTAL;
+        c.insets = new Insets(0, 20, 20, 0);
+        add(dontWarnAndOKPanel, c);
+
+        c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 11;
+        c.fill = GridBagConstraints.HORIZONTAL;
+        add(bottomDescriptionPanel, c);
 
-        JTextPane description = new JTextPane();
-        description.setText("To load events into Chainsaw, a 'receiver' configuration must be provided.\n\n" +
-                "NOTE: An example receiver configuration is available from the Welcome tab ('view example receiver configuration')");
-        description.setEditable(false);
-        description.setOpaque(false);
-        description.setFont(getFont());
+        /**
+         * This listener activates/deactivates certain controls based on the current
+         * state of the options
+         */
+        ActionListener al = new ActionListener() {
+                public void actionPerformed(ActionEvent e) {
+                    updateEnabledState((Component)e.getSource());
+                }
+            };
 
-        add(description, gc);
+        logFileReceiverRadioButton.addActionListener(al);
+        networkReceiverRadioButton.addActionListener(al);
+        doNothingRadioButton.addActionListener(al);
+        useExistingConfigurationRadioButton.addActionListener(al);
+        useAutoSavedConfigRadioButton.addActionListener(al);
+
+        //set 'do nothing' as default
+        buttonGroup.setSelected(doNothingRadioButton.getModel(), true);
+        updateEnabledState(doNothingRadioButton);
+    }
 
-        gc.weightx = 0;
-        gc.weighty = 0;
-        gc.gridy = GridBagConstraints.RELATIVE;
-        add(Box.createVerticalStrut(20), gc);
+    private JPanel buildTopDescriptionPanel() {
+        JPanel panel = new JPanel(new GridBagLayout());
 
-        JPanel optionpanel = new JPanel();
-        optionpanel.setLayout(new GridLayout(5, 1, 3, 3));
-        optionpanel.setBackground(getBackground());
-        optionpanel.setBorder(BorderFactory.createEtchedBorder());
+        GridBagConstraints c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 0;
+        c.weightx = 1.0;
+        c.fill = GridBagConstraints.HORIZONTAL;
+        JTextPane descriptionTextPane = new JTextPane();
+        descriptionTextPane.setText("Specify the source of events to process or load a Chainsaw configuration file\nAn example configuration file is available from the Welcome tab");
+        descriptionTextPane.setEditable(false);
+        descriptionTextPane.setOpaque(false);
+        descriptionTextPane.setFont(getFont());
+        panel.add(descriptionTextPane, c);
+        return panel;
+    }
 
-        final ButtonGroup optionGroup = new ButtonGroup();
+    private JPanel buildDontWarnAndOKPanel() {
+        JPanel panel = new JPanel(new GridBagLayout());
 
-        simpleReceiver.setToolTipText(
-            "Creates one of the standard Receivers on one of the standard port");
-        simpleReceiver.setMnemonic('p');
+        GridBagConstraints c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 0;
+        c.weightx = 1.0;
+        c.anchor = GridBagConstraints.LINE_END;
+        dontwarnIfNoReceiver = new JCheckBox("Don't show this again");
+        panel.add(dontwarnIfNoReceiver, c);
+
+        c = new GridBagConstraints();
+        c.fill = GridBagConstraints.HORIZONTAL;
+        c.gridx = 1;
+        c.gridy = 0;
+        okButton = new JButton(" OK ");
+        panel.add(okButton, c);
 
-        searchOption.setToolTipText(
-            "Allows you to choose a Log4J Configuration file that contains Receiver definitions");
+        return panel;
+    }
 
-        searchOption.setMnemonic('S');
-        
-        chainsawSavedConfigOption.setToolTipText(
-             "Allows you to load Receiver definitions saved by Chainsaw previously");
+    private JPanel buildBottomDescriptionPanel() {
+        JTextPane descriptionTextPane = new JTextPane();
+        descriptionTextPane.setText("The active receiver configuration is auto-saved on exit to $HOME/.chainsaw/receiver-config.xml");
+        descriptionTextPane.setEditable(false);
+        descriptionTextPane.setOpaque(false);
+        descriptionTextPane.setFont(getFont());
+
+        JPanel panel = new JPanel(new GridBagLayout());
+
+        GridBagConstraints c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 0;
+        c.weightx = 1.0;
+        c.fill = GridBagConstraints.HORIZONTAL;
 
-        chainsawSavedConfigOption.setMnemonic('C');
+        panel.add(descriptionTextPane, c);
 
+        return panel;
+    }
 
-        manualOption.setToolTipText(
-            "Opens the Receivers panel so you can define them via a GUI");
+    private JPanel buildNetworkReceiverPanel() {
+        networkReceiverPortComboBoxModel = new DefaultComboBoxModel();
+        networkReceiverPortComboBoxModel.addElement("4445");
+        networkReceiverPortComboBoxModel.addElement("4560");
 
-        manualOption.setMnemonic('m');
+        networkReceiverPortComboBox = new JComboBox(networkReceiverPortComboBoxModel);
+        networkReceiverPortComboBox.setEditable(true);
+        networkReceiverPortComboBox.setOpaque(false);
+        networkReceiverPortComboBox.setBackground(getBackground());
 
-        justLoadingFile.setToolTipText(
-            "Use this if you just want to view a Log4J Log file stored somewhere");
+        networkReceiverClassNameComboBoxModel = new DefaultComboBoxModel();
+        networkReceiverClassNameComboBoxModel.addElement(SocketReceiver.class);
+        networkReceiverClassNameComboBoxModel.addElement(UDPReceiver.class);
 
-        justLoadingFile.setMnemonic('I');
+        networkReceiverClassNameComboBox = new JComboBox(networkReceiverClassNameComboBoxModel);
 
-//    searchOption.setOpaque(false);
-        manualOption.setOpaque(false);
-        justLoadingFile.setOpaque(false);
+        networkReceiverClassNameComboBox.setEditable(false);
 
-        optionGroup.add(searchOption);
-        optionGroup.add(chainsawSavedConfigOption);
-        optionGroup.add(manualOption);
-        optionGroup.add(justLoadingFile);
-        optionGroup.add(simpleReceiver);
+        networkReceiverClassNameComboBox.setRenderer(new DefaultListCellRenderer() {
+            public Component getListCellRendererComponent(JList list,
+                Object value, int index, boolean isSelected,
+                boolean cellHasFocus) {
 
-        chainsawSavedConfigOption.setEnabled(getModel().isChinsawConfigFileExists());
+                Component component = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
 
-        gc.gridy = GridBagConstraints.RELATIVE;
+                if (value instanceof Class) {
+                    Class receiverClass = (Class) value;
+                    JLabel cellLabel = (JLabel) component;
+                    String shortenedName = receiverClass.getName().substring(receiverClass.getName().lastIndexOf('.') + 1);
+                    cellLabel.setText(shortenedName);
+                }
 
+                return component;
+            }
+        });
 
-        configModel.removeAllElements();
+        JPanel panel = new JPanel(new GridBagLayout());
 
-        previousConfigs.setModel(configModel);
-        previousConfigs.setOpaque(false);
-        previousConfigs.setBackground(getBackground());
-        previousConfigs.setToolTipText(
-            "Previously loaded configurations can be chosen here");
+        GridBagConstraints c = new GridBagConstraints();
+        c.fill = GridBagConstraints.HORIZONTAL;
+        c.weightx = 0.5;
+        c.gridx = 0;
+        c.gridy = 0;
+        panel.add(networkReceiverClassNameComboBox, c);
+
+        c = new GridBagConstraints();
+        c.fill = GridBagConstraints.HORIZONTAL;
+        c.weightx = 0.5;
+        c.gridx = 1;
+        c.gridy = 0;
+        panel.add(networkReceiverPortComboBox, c);
 
-        previousConfigs.setEditable(true);
+        return panel;
+    }
 
-        previousConfigs.getModel().addListDataListener(new ListDataListener() {
-                private void validateUrl() {
-                    okButton.setEnabled(isValidConfigURL());
+    private JPanel buildLogFileReceiverPanel() {
+        JPanel panel = new JPanel(new GridBagLayout());
+        browseLogFileButton = new JButton(new AbstractAction(" Find a log file ") {
+            public void actionPerformed(ActionEvent e) {
+                try {
+
+                    URL url = browseLogFile();
+                    if (url != null) {
+                        String item = url.toURI().toString();
+                        logFileURLComboBoxModel.addElement(item);
+                        logFileURLComboBox.setSelectedItem(item);
+                    }
+                } catch (Exception ex) {
+                    logger.error(
+                        "Error browsing for log file", ex);
                 }
+            }
+        });
 
-                public void contentsChanged(ListDataEvent e) {
-                    validateUrl();
-                }
+        browseLogFileButton.setToolTipText("Shows a File Open dialog to allow you to find a log file");
+        GridBagConstraints c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 0;
+        c.anchor = GridBagConstraints.LINE_START;
+        panel.add(browseLogFileButton, c);
+
+        c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 1;
+        c.anchor = GridBagConstraints.LINE_END;
+        c.insets = new Insets(0, 0, 0, 5);
+        panel.add(new JLabel("Log file URL"), c);
+        logFileURLComboBoxModel = new DefaultComboBoxModel();
+        logFileURLComboBox = new JComboBox(logFileURLComboBoxModel);
+        logFileURLComboBox.setEditable(true);
+        logFileURLComboBox.setOpaque(false);
+        logFileURLComboBox.setBackground(getBackground());
+
+        c = new GridBagConstraints();
+        c.gridx = 1;
+        c.gridy = 1;
+        c.weightx = 1.0;
+        c.gridwidth = 1;
+        c.anchor = GridBagConstraints.LINE_START;
+        c.fill = GridBagConstraints.HORIZONTAL;
+        panel.add(logFileURLComboBox, c);
+
+        c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 2;
+        c.anchor = GridBagConstraints.LINE_END;
+        c.insets = new Insets(0, 0, 0, 5);
+        panel.add(new JLabel("Log file format type"), c);
+
+        DefaultComboBoxModel comboBoxModel = new DefaultComboBoxModel();
+        comboBoxModel.addElement("PatternLayout format");
+        comboBoxModel.addElement("LogFilePatternReceiver LogFormat");
+
+        logFileFormatTypeComboBox = new JComboBox(comboBoxModel);
+        logFileFormatTypeComboBox.setOpaque(false);
+        logFileFormatTypeComboBox.setBackground(getBackground());
+
+        c = new GridBagConstraints();
+        c.gridx = 1;
+        c.gridy = 2;
+        c.anchor = GridBagConstraints.LINE_START;
+        panel.add(logFileFormatTypeComboBox, c);
+
+        c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 3;
+        c.anchor = GridBagConstraints.LINE_END;
+        c.insets = new Insets(0, 5, 0, 5);
+        panel.add(new JLabel("Log file format"), c);
+
+        logFileFormatComboBoxModel = new DefaultComboBoxModel();
+        logFileFormatComboBox = new JComboBox(logFileFormatComboBoxModel);
+        logFileFormatComboBox.setEditable(true);
+        logFileFormatComboBox.setOpaque(false);
+        logFileFormatComboBox.setBackground(getBackground());
+
+        c = new GridBagConstraints();
+        c.gridx = 1;
+        c.gridy = 3;
+        c.weightx = 0.5;
+        c.anchor = GridBagConstraints.LINE_START;
+        c.fill = GridBagConstraints.HORIZONTAL;
+        panel.add(logFileFormatComboBox, c);
+
+        c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 4;
+        c.insets = new Insets(0, 5, 0, 5);
+        panel.add(new JLabel("Log file timestamp format"), c);
+
+        logFileFormatTimestampFormatComboBoxModel = new DefaultComboBoxModel();
+        seedLogFileFormatTimestampComboBoxModel();
+        logFileFormatTimestampFormatComboBox = new JComboBox(logFileFormatTimestampFormatComboBoxModel);
+        logFileFormatTimestampFormatComboBox.setEditable(true);
+        logFileFormatTimestampFormatComboBox.setOpaque(false);
+        logFileFormatTimestampFormatComboBox.setBackground(getBackground());
+        c = new GridBagConstraints();
+        c.gridx = 1;
+        c.gridy = 4;
+        c.weightx = 0.5;
+        c.fill = GridBagConstraints.HORIZONTAL;
+        panel.add(logFileFormatTimestampFormatComboBox, c);
+
+        DateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss,SSS");
+        c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 5;
+        c.gridwidth=5;
+        c.insets = new Insets(5, 5, 0, 5);
+        panel.add(new JLabel("Timestamps parsed using Java's SimpleDateFormat - use yyyy.MM.dd HH:mm:ss,SSS to parse " +  dateFormat.format(new Date())), c);
+        return panel;
+    }
 
-                public void intervalAdded(ListDataEvent e) {
-                    validateUrl();
-                }
+    private void seedLogFileFormatTimestampComboBoxModel()
+    {
+        logFileFormatTimestampFormatComboBoxModel.addElement("yyyy-MM-dd HH:mm:ss,SSS");
+        logFileFormatTimestampFormatComboBoxModel.addElement("yyyyMMdd HH:mm:ss.SSS");
+        logFileFormatTimestampFormatComboBoxModel.addElement("yyyy/MM/dd HH:mm:ss");
+        logFileFormatTimestampFormatComboBoxModel.addElement("dd MMM yyyy HH:mm:ss,SSS");
+        logFileFormatTimestampFormatComboBoxModel.addElement("HH:mm:ss,SSS");
+        logFileFormatTimestampFormatComboBoxModel.addElement("yyyy-MM-ddTHH:mm");
+        logFileFormatTimestampFormatComboBoxModel.addElement("yyyy-MM-ddTHH:mm:ss.SSS");
+    }
 
-                public void intervalRemoved(ListDataEvent e) {
-                    validateUrl();
-                }
-            });
+    private JPanel buildUseExistingConfigurationPanel() {
+        existingConfigurationComboBoxModel = new DefaultComboBoxModel();
 
-        previousConfigs.setMaximumSize(new Dimension(200,
-                (int) previousConfigs.getPreferredSize().getHeight()));
-        previousConfigs.setPreferredSize(previousConfigs.getMaximumSize());
-        previousConfigs.getEditor().getEditorComponent().addFocusListener(
+        existingConfigurationComboBox = new JComboBox(existingConfigurationComboBoxModel);
+        existingConfigurationComboBox.setOpaque(false);
+        existingConfigurationComboBox.setBackground(getBackground());
+        existingConfigurationComboBox.setToolTipText("Previously loaded configurations can be chosen here");
+        existingConfigurationComboBox.setEditable(true);
+
+        existingConfigurationComboBox.getEditor().getEditorComponent().addFocusListener(
             new FocusListener() {
                 public void focusGained(FocusEvent e) {
                     selectAll();
                 }
 
                 private void selectAll() {
-                    previousConfigs.getEditor().selectAll();
+                    existingConfigurationComboBox.getEditor().selectAll();
                 }
 
                 public void focusLost(FocusEvent e) {
                 }
             });
 
-        final JButton searchButton = new JButton(new AbstractAction(
-                    " Browse... ") {
+        browseForAnExistingConfigurationButton = new JButton(new AbstractAction(" Find an existing configuration ") {
                     public void actionPerformed(ActionEvent e) {
-
                         try {
 
-                            URL url = browseForConfig();
+                            URL url = browseConfig();
 
                             if (url != null) {
                                 getModel().configUrl = url;
-                                configModel.addElement(url);
-                                previousConfigs.getModel().setSelectedItem(
+                                existingConfigurationComboBoxModel.addElement(url);
+                                existingConfigurationComboBox.getModel().setSelectedItem(
                                     url);
                             }
                         } catch (Exception ex) {
                             logger.error(
-                                "Error browswing for Configuration file", ex);
+                                "Error browsing for Configuration file", ex);
                         }
                     }
                 });
 
-        searchButton.setToolTipText(
+        browseForAnExistingConfigurationButton.setToolTipText(
             "Shows a File Open dialog to allow you to find a configuration file");
+        JPanel panel = new JPanel(new GridBagLayout());
+        GridBagConstraints c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 0;
+        c.gridwidth = 2;
+        c.anchor = GridBagConstraints.LINE_START;
+        panel.add(browseForAnExistingConfigurationButton, c);
+
+        c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 1;
+        c.insets = new Insets(0, 5, 0, 5);
+        panel.add(new JLabel("Configuration file URL"), c);
+
+        c = new GridBagConstraints();
+        c.gridx = 1;
+        c.gridy = 1;
+        c.weightx = 0.5;
+        c.fill = GridBagConstraints.HORIZONTAL;
+        panel.add(existingConfigurationComboBox, c);
 
 
-        simplePortModel.addElement(new PortBased() {
-
-                private void unsupported() {
-                    throw new UnsupportedOperationException(
-                        "Should not be used in this context");
-                }
-
-                public String getName() {
-                    unsupported();
-
-                    return null;
-                }
-
-                public boolean isActive() {
-                    unsupported();
-
-                    return false;
-                }
-
-                public int getPort() {
-
-                    return 4445;
-                }
-
-                public String toString() {
-
-                    return getPort() + " (Old style/standard Chainsaw port)";
-                }
-            });
-
-        simplePortModel.addElement(new PortBased() {
-
-                private void unsupported() {
-                    throw new UnsupportedOperationException(
-                        "Should not be used in this context");
-                }
-
-                public String getName() {
-                    unsupported();
-
-                    return null;
-                }
-
-                public boolean isActive() {
-                    unsupported();
-
-                    return false;
-                }
-
-                public int getPort() {
-
-                    return SocketAppender.DEFAULT_PORT;
-                }
-
-                public String toString() {
-
-                    return getPort() + " (Default SocketAppender port)";
-                }
-            });
-
-        JPanel simpleSocketPanel = new JPanel();
-        simpleSocketPanel.setLayout(new BoxLayout(simpleSocketPanel, BoxLayout.X_AXIS));
-
-        simpleSocketPanel.add(simpleReceiver);
-        simpleSocketPanel.add(Box.createHorizontalStrut(5));
-
-        final JComboBox socketCombo = new JComboBox(simplePortModel);
-
-
-        simpleReceiverModel.addElement(SocketReceiver.class);
-        simpleReceiverModel.addElement(SocketHubReceiver.class);
-
-        final JComboBox receiverCombo = new JComboBox(simpleReceiverModel);
-        receiverCombo.setEditable(false);
-        receiverCombo.setRenderer(new DefaultListCellRenderer() {
-                public Component getListCellRendererComponent(JList list,
-                    Object value, int index, boolean isSelected,
-                    boolean cellHasFocus) {
-
-                    Component c = super.getListCellRendererComponent(list,
-                            value, index, isSelected, cellHasFocus);
-
-                    if (value instanceof Class) {
-
-                        Class receiverClass = (Class) value;
-                        JLabel cellLabel = (JLabel) c;
-                        String shortenedName = receiverClass.getName()
-                            .substring(
-                                receiverClass.getName().lastIndexOf('.') + 1);
-                        cellLabel.setText(shortenedName);
-                    }
-
-                    return c;
-                }
-
-            });
-
-        simpleSocketPanel.add(receiverCombo);
-        simpleSocketPanel.add(Box.createHorizontalStrut(5));
-        simpleSocketPanel.add(new JLabel(" on port "));
-        simpleSocketPanel.add(Box.createHorizontalStrut(5));
-        simpleSocketPanel.add(socketCombo);
-
-        /**
-         * This listener activates/deactivates certain controls based on the current
-         * state of the options
-         */
-        ActionListener al = new ActionListener() {
-                public void actionPerformed(ActionEvent e) {
-                    previousConfigs.setEnabled(e.getSource() == searchOption);
-                    searchButton.setEnabled(e.getSource() == searchOption);
-                    socketCombo.setEnabled(e.getSource() == simpleReceiver);
-                    receiverCombo.setEnabled(e.getSource() == simpleReceiver);
-
-                    if (optionGroup.isSelected(searchOption.getModel())) {
-                        okButton.setEnabled(isValidConfigURL());
-                    } else {
-                        okButton.setEnabled(true);
-                    }
-                }
-            };
-
-        searchOption.addActionListener(al);
-        chainsawSavedConfigOption.addActionListener(al);
-        manualOption.addActionListener(al);
-        justLoadingFile.addActionListener(al);
-        simpleReceiver.addActionListener(al);
-
-        justLoadingFile.doClick();
-
-        JPanel searchOptionPanel = new JPanel(new GridBagLayout());
-
-        searchOptionPanel.setOpaque(false);
-
-        GridBagConstraints searchGCC = new GridBagConstraints();
-
-        searchGCC.fill = GridBagConstraints.HORIZONTAL;
-        searchGCC.gridx = 1;
-        searchGCC.weightx = 0.0;
-        searchGCC.anchor = GridBagConstraints.WEST;
-        searchOptionPanel.add(searchOption, searchGCC);
-
-        searchGCC.fill = GridBagConstraints.NONE;
-        searchGCC.weightx = 1.0;
-        searchGCC.gridx = 2;
-        searchOptionPanel.add(Box.createHorizontalStrut(5), searchGCC);
-
-        searchGCC.gridx = 3;
-        searchGCC.weightx = 0.0;
-        searchOptionPanel.add(previousConfigs, searchGCC);
-
-        searchGCC.weightx = 0.0;
-        searchGCC.gridx = 4;
-        searchOptionPanel.add(Box.createHorizontalStrut(5), searchGCC);
-        searchGCC.gridx = 5;
-        searchOptionPanel.add(searchButton, searchGCC);
-
-//    searchGCC.gridx = 6;
-//    searchGCC.fill = GridBagConstraints.HORIZONTAL;
-//    searchGCC.weightx = 1.0;
-//    searchOptionPanel.add(Box.createHorizontalGlue(), searchGCC);
-
-
-        optionpanel.add(justLoadingFile);
-        optionpanel.add(simpleSocketPanel);
-        optionpanel.add(searchOptionPanel);
-        optionpanel.add(chainsawSavedConfigOption);
-        optionpanel.add(manualOption);
-
-        add(optionpanel, gc);
-
-        gc.gridy = GridBagConstraints.RELATIVE;
-        gc.weightx = 0;
-        gc.fill = GridBagConstraints.NONE;
-        gc.anchor = GridBagConstraints.SOUTHEAST;
-
-        add(Box.createVerticalStrut(20), gc);
-
-        okButton.setMnemonic('O');
-
-        final JCheckBox dontwarnIfNoReceiver = new JCheckBox(
-                "Don't show me this again");
-        JPanel okPanel = new JPanel();
+        return panel;
+    }
 
-        okPanel.add(dontwarnIfNoReceiver);
-        okPanel.add(okButton);
-        add(okPanel, gc);
+    /**
+     * Returns the current Model/state of the chosen options by the user.
+     * @return model
+     */
+    PanelModel getModel() {
+        return panelModel;
+    }
 
-        okButton.addActionListener(new ActionListener() {
+    /**
+     * Clients of this panel can configure the ActionListener to be used
+     * when the user presses the OK button, so they can read
+     * back this Panel's model top determine what to do.
+     * @param actionListener listener which will be notified that ok was selected
+     */
+    void setOkActionListener(ActionListener actionListener) {
+        okButton.addActionListener(actionListener);
+    }
 
-                public void actionPerformed(ActionEvent e) {
-                    dontWarnMeAgain = dontwarnIfNoReceiver.isSelected();
-                }
-            });
+    private void updateEnabledState(Component component) {
+        existingConfigurationComboBox.setEnabled(component == useExistingConfigurationRadioButton);
+        browseForAnExistingConfigurationButton.setEnabled(component == useExistingConfigurationRadioButton);
+        networkReceiverPortComboBox.setEnabled(component == networkReceiverRadioButton);
+        networkReceiverClassNameComboBox.setEnabled(component == networkReceiverRadioButton);
+        browseLogFileButton.setEnabled(component == logFileReceiverRadioButton);
+        logFileURLComboBox.setEnabled(component == logFileReceiverRadioButton);
+        logFileFormatTypeComboBox.setEnabled(component == logFileReceiverRadioButton);
+        logFileFormatComboBox.setEnabled(component == logFileReceiverRadioButton);
+        logFileFormatTimestampFormatComboBox.setEnabled(component == logFileReceiverRadioButton);
     }
 
     /**
      * Returns the URL chosen by the user for a Configuration file
      * or null if they cancelled.
      */
-    private URL browseForConfig() throws MalformedURLException {
+    private URL browseConfig() throws MalformedURLException {
 
         JFileChooser chooser = new JFileChooser();
         chooser.setDialogTitle("Use an existing receiver configuration file...");
@@ -498,31 +605,33 @@ class NoReceiversWarningPanel extends JP
     }
 
     /**
-     * Determions if the Configuration URL is a valid url.
+     * Returns the URL chosen by the user for a Configuration file
+     * or null if they cancelled.
      */
-    private boolean isValidConfigURL() {
+    private URL browseLogFile() throws MalformedURLException {
 
-        if (previousConfigs.getSelectedItem() == null) {
-
-            return false;
-        }
+        JFileChooser chooser = new JFileChooser();
+        chooser.setDialogTitle("Browse for a log file...");
+        chooser.setDialogType(JFileChooser.OPEN_DIALOG);
+        chooser.showOpenDialog(this);
 
-        String urlString = previousConfigs.getSelectedItem().toString();
+        File selectedFile = chooser.getSelectedFile();
 
-        try {
-            getModel().configUrl = new URL(urlString);
+        if (selectedFile == null) {
+            return null;
+        }
 
-            return true;
-        } catch (Exception ex) {
+        if (!selectedFile.exists() || !selectedFile.canRead()) {
+            return null;
         }
 
-        return false;
+        return chooser.getSelectedFile().toURI().toURL();
     }
 
     public static void main(String[] args) {
 
         JFrame frame = new JFrame();
-        frame.getContentPane().add(new NoReceiversWarningPanel());
+        frame.getContentPane().add(new ReceiverConfigurationPanel());
         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         frame.pack();
         frame.setVisible(true);
@@ -533,7 +642,7 @@ class NoReceiversWarningPanel extends JP
      */
     public final boolean isDontWarnMeAgain() {
 
-        return dontWarnMeAgain;
+        return dontwarnIfNoReceiver.isSelected();
     }
 
     /**
@@ -547,50 +656,44 @@ class NoReceiversWarningPanel extends JP
         private File file;
 
         public PanelModel(){
-            file = new File(SettingsManager.getInstance().getSettingsDirectory(), "receiver-configs.xml");
-        }
-
-        boolean isLoadLogFile() {
-
-            return justLoadingFile.isSelected();
+            file = new File(SettingsManager.getInstance().getSettingsDirectory(), "receiver-config.xml");
         }
 
-        boolean isSimpleReceiverMode() {
+        boolean isNetworkReceiverMode() {
 
-            return simpleReceiver.isSelected();
+            return networkReceiverRadioButton.isSelected();
         }
 
-        int getSimplePort() {
+        int getNetworkReceiverPort() {
 
-            return ((PortBased) simplePortModel.getSelectedItem()).getPort();
+            return Integer.parseInt(networkReceiverPortComboBoxModel.getSelectedItem().toString());
         }
 
-        Class getSimpleReceiverClass() {
+        Class getNetworkReceiverClass() {
 
-            return (Class) simpleReceiverModel.getSelectedItem();
+            return (Class) networkReceiverClassNameComboBoxModel.getSelectedItem();
         }
 
         boolean isLoadConfig() {
 
-            return searchOption.isSelected();
+            return useExistingConfigurationRadioButton.isSelected();
         }
 
         boolean isLoadSavedConfigs() {
 
-            return chainsawSavedConfigOption.isSelected();
+            return useAutoSavedConfigRadioButton.isSelected();
         }
 
-        boolean isManualMode() {
-
-            return manualOption.isSelected();
+        boolean isLogFileReceiverConfig() {
+            return logFileReceiverRadioButton.isSelected();
         }
 
         public Object[] getRememberedConfigs() {
 
-            Object[] urls = new Object[configModel.getSize()];
+            Object[] urls = new Object[existingConfigurationComboBoxModel.getSize()];
 
-            for (int i = 0; i < configModel.getSize(); i++) {
-                urls[i] = configModel.getElementAt(i);
+            for (int i = 0; i < existingConfigurationComboBoxModel.getSize(); i++) {
+                urls[i] = existingConfigurationComboBoxModel.getElementAt(i);
             }
 
             return urls;
@@ -599,10 +702,10 @@ class NoReceiversWarningPanel extends JP
         public void setRememberedConfigs(final Object[] configs) {
             SwingUtilities.invokeLater(new Runnable() {
                     public void run() {
-                        configModel.removeAllElements();
+                        existingConfigurationComboBoxModel.removeAllElements();
 
                         for (int i = 0; i < configs.length; i++) {
-                            configModel.addElement(configs[i]);
+                            existingConfigurationComboBoxModel.addElement(configs[i]);
                         }
                     }
                 });
@@ -613,12 +716,6 @@ class NoReceiversWarningPanel extends JP
             return configUrl;
         }
 
-        boolean isChinsawConfigFileExists(){
-
-            return file.exists();
-
-        }
-
         URL getSavedConfigToLoad() {
             try {
                 if (file.exists()){
@@ -627,9 +724,59 @@ class NoReceiversWarningPanel extends JP
                     logger.debug("No configuration file found");
                 }
             } catch (MalformedURLException e) {
-                logger.error("Error laoding saved configurations by Chainsaw", e);
+                logger.error("Error loading saved configurations by Chainsaw", e);
             }
             return null;
         }
+
+        URL getLogFileURL() {
+            try
+            {
+                Object item = logFileURLComboBox.getSelectedItem();
+                if (item != null) {
+                    return new URL(item.toString());
+                }
+            }
+            catch (MalformedURLException e)
+            {
+                logger.error("Error retrieving log file URL", e);
+            }
+            return null;
+        }
+
+        String getLogFormat() {
+            Object item = logFileFormatComboBox.getSelectedItem();
+            if (item != null) {
+                return item.toString();
+            }
+            return null;
+        }
+
+        boolean isPatternLayoutLogFormat() {
+            Object item = logFileFormatTypeComboBox.getSelectedItem();
+            return item != null && item.toString().toLowerCase().contains("patternlayout");
+        }
+
+        String getLogFormatTimestampFormat() {
+            Object item = logFileFormatTimestampFormatComboBox.getSelectedItem();
+            if (item != null) {
+                return item.toString();
+            }
+
+            return null;
+        }
+
+        public void setRememberedLayouts(Object[] layouts)
+        {
+            //TODO: implement
+            //add an entry to the logformat, formattype and timestamp fields
+
+        }
+
+        public Object[] getRememberedLayouts()
+        {
+            //TODO: implement
+            return new Object[0];
+        }
     }
 }

Propchange: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/receivers/ReceiversPanel.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/receivers/ReceiversPanel.java?rev=966518&r1=966517&r2=966518&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/receivers/ReceiversPanel.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/receivers/ReceiversPanel.java Thu Jul 22 06:58:54 2010
@@ -62,6 +62,7 @@ import javax.swing.event.TreeWillExpandL
 import javax.swing.tree.DefaultMutableTreeNode;
 import javax.swing.tree.ExpandVetoException;
 import javax.swing.tree.TreePath;
+import javax.xml.transform.OutputKeys;
 import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.Transformer;
 import javax.xml.transform.stream.StreamResult;
@@ -641,11 +642,19 @@ public class ReceiversPanel extends JPan
     */
 
   public void saveSettings(SaveSettingsEvent event){
-      List pluginList = pluginRegistry.getPlugins();
-
+      List fullPluginList = pluginRegistry.getPlugins();
+      List pluginList = new ArrayList();
+      for (Iterator iter = fullPluginList.iterator();iter.hasNext();) {
+          Plugin thisPlugin = (Plugin)iter.next();
+          if (thisPlugin instanceof Receiver) {
+              pluginList.add(thisPlugin);
+          }
+      }
+      //remove everything that isn't a receiver..otherwise, we'd create an empty config file
       try {
-          if (pluginList.size() != 0) {
-              File file = new File(SettingsManager.getInstance().getSettingsDirectory(), "receiver-configs.xml");
+          if (pluginList.size() > 0) {
+              //we programmatically register the ZeroConf plugin in the plugin registry
+              File file = new File(SettingsManager.getInstance().getSettingsDirectory(), "receiver-config.xml");
               DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
               factory.setNamespaceAware(true);
               DocumentBuilder builder = factory.newDocumentBuilder();
@@ -673,7 +682,11 @@ public class ReceiversPanel extends JPan
 
                   for (int j = 0; j < list.size(); j++) {
                       PropertyDescriptor d = (PropertyDescriptor) list.get(j);
-
+                      //don't serialize the loggerRepository property for subclasses of componentbase..
+                      //easier to change this than tweak componentbase right now..
+                      if (d.getReadMethod().getName().equals("getLoggerRepository")) {
+                          continue;
+                      }
                       Object o = d.getReadMethod().invoke(receiver, new Object[] {} );
                       if (o != null) {
                           Element paramElement = document.createElement("param");
@@ -689,6 +702,8 @@ public class ReceiversPanel extends JPan
 
               TransformerFactory transformerFactory = TransformerFactory.newInstance();
               Transformer transformer = transformerFactory.newTransformer();
+              transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+              transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
               DOMSource source = new DOMSource(rootElement);
               FileOutputStream stream = new FileOutputStream(file);
               StreamResult result = new StreamResult(stream);

Modified: logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java?rev=966518&r1=966517&r2=966518&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java (original)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java Thu Jul 22 06:58:54 2010
@@ -242,9 +242,9 @@ public class VFSLogFilePatternReceiver e
       //on receiver restart, only prompt for credentials if we don't already have them
       if (promptForUserInfo && getFileURL().indexOf("@") == -1) {
     	  /*
-    	  if promptforuserinfo is true, wait for a reference to the container 
+    	  if promptforuserinfo is true, wait for a reference to the container
     	  (via the VisualReceiver callback).
-    	  
+
     	  We need to display a login dialog on top of the container, so we must then
     	  wait until the container has been added to a frame
     	  */
@@ -260,18 +260,22 @@ public class VFSLogFilePatternReceiver e
     			  } catch (InterruptedException ie){}
     		  }
     	  }
-    	      	  
+
     	  Frame containerFrame1;
-    	  synchronized(waitForContainerLock) {
-    		  //loop until the container has a frame
-    		  while ((containerFrame1 = (Frame)SwingUtilities.getAncestorOfClass(Frame.class, container)) == null) {
-    			  try {
-    				  waitForContainerLock.wait(1000);
-    				  getLogger().debug("waiting for container's frame to be available");
-    			  } catch (InterruptedException ie) {}
-    		  }
-    	  }
-    	  		final Frame containerFrame = containerFrame1;
+          if (container instanceof Frame) {
+              containerFrame1 = (Frame)container;
+          } else {
+              synchronized(waitForContainerLock) {
+                  //loop until the container has a frame
+                  while ((containerFrame1 = (Frame)SwingUtilities.getAncestorOfClass(Frame.class, container)) == null) {
+                      try {
+                          waitForContainerLock.wait(1000);
+                          getLogger().debug("waiting for container's frame to be available");
+                      } catch (InterruptedException ie) {}
+                  }
+              }
+          }
+            final Frame containerFrame = containerFrame1;
     	  	  //create the dialog
     	  	  SwingUtilities.invokeLater(new Runnable() {
     	  		public void run() {

Modified: logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html?rev=966518&r1=966517&r2=966518&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html (original)
+++ logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html Thu Jul 22 06:58:54 2010
@@ -10,6 +10,11 @@
 <b>NOTE:</b> The mechanism and format used to persist settings in Chainsaw is subject to change.  If you are experiencing problems displaying events in Chainsaw, please delete everything in the $user.dir/.chainsaw directory and restart Chainsaw.
 <br>
 <h1>2.1</h1>
+<h2>21 Jul 2010</h2>
+<ul>
+<li>Rewrote initial configuration screen with new ability to define a file receiver from the dialog (and provide a PatternLayout as the format) </li>
+<li>Renamed auto-save xml configuration to receiver-config.xml (in $HOME/.chainsaw)</li>
+</ul>
 <h2>25 Jun 2010</h2>
 <ul>
 <li>Added new log panel feature: 'clear table expression' (define an expression that will automatically clear the table)</li>