Replaced application-wide preferences automatic configuration URL textfield with editable combobox remembering 10 most-recently used configuration URLs
 - added a browse button to build the configuration file URL
 - manually changing or browsing to an entry and pressing 'ok' button automatically loads the configuration
 - list is persisted & restored on Chainsaw restart
 - MRU count: 10


git-svn-id: https://svn.apache.org/repos/asf/logging/chainsaw/trunk@833850 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModel.java b/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModel.java
index d7d06a7..bf5f94d 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModel.java
@@ -18,6 +18,7 @@
 
 import java.beans.PropertyChangeListener;
 import java.beans.PropertyChangeSupport;
+import java.util.Vector;
 
 
 /**
@@ -50,13 +51,15 @@
     /**
      * If not 'empty', this property will be used as the URL to load log4j configuration at startup
      */
-    private String configurationURL="";
-	  
+    private Vector configurationURLs=new Vector();
+
+    private String configurationURL = "";
     /**
      *    this means for Receivers that require optional jars that can't be delivered
      *    by the Web start classloader, we need to be able to remove the SecurityManager in place
      */
     private boolean okToRemoveSecurityManager = false;
+    private static final int CONFIGURATION_URL_ENTRY_COUNT = 10;
 
     /**
      * @param listener
@@ -185,6 +188,7 @@
       setShowSplash(model.isShowSplash());
       setToolTipDisplayMillis(model.getToolTipDisplayMillis());
       setCyclicBufferSize(model.getCyclicBufferSize());
+      setConfigurationURLs(model.getConfigurationURLs());
       setConfigurationURL(model.getConfigurationURL());
       setLastUsedVersion(model.getLastUsedVersion());
       setOkToRemoveSecurityManager(model.isOkToRemoveSecurityManager());
@@ -234,6 +238,14 @@
       return statusBar;
     }
 
+    public Vector getConfigurationURLs() {
+        return configurationURLs;
+    }
+
+    public void setConfigurationURLs(Vector urls) {
+        configurationURLs = urls;
+    }
+
     /**
      * @param statusBar The statusBar to set.
      */
@@ -333,9 +345,20 @@
      */
     public final void setConfigurationURL(String configurationURL)
     {
+        //don't add empty entries
+        if (configurationURL == null || configurationURL.trim().equals("")) {
+            return;
+        }
         Object oldValue = this.configurationURL;
-        this.configurationURL = configurationURL;
-        firePropertyChange("configurationURL", oldValue, this.configurationURL);
+        //add entry to MRU list
+        if (!configurationURLs.contains(configurationURL)) {
+          if (configurationURLs.size() == CONFIGURATION_URL_ENTRY_COUNT) {
+              configurationURLs.remove(CONFIGURATION_URL_ENTRY_COUNT - 1);
+          }
+          configurationURLs.add(0, configurationURL);
+        }
+      this.configurationURL = configurationURL;
+      firePropertyChange("configurationURL", oldValue, this.configurationURL);
     }
     /**
      * @return Returns the lastUsedVersion.
diff --git a/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java b/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java
index c581f7f..26201ed 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java
@@ -17,11 +17,14 @@
 
 package org.apache.log4j.chainsaw;
 
+import java.awt.Dimension;
 import java.awt.FlowLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
+import java.io.File;
+import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.Dictionary;
 import java.util.Enumeration;
@@ -31,9 +34,13 @@
 import javax.swing.Box;
 import javax.swing.BoxLayout;
 import javax.swing.ButtonGroup;
+import javax.swing.DefaultComboBoxModel;
 import javax.swing.InputVerifier;
+import javax.swing.JButton;
 import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
 import javax.swing.JComponent;
+import javax.swing.JFileChooser;
 import javax.swing.JFrame;
 import javax.swing.JLabel;
 import javax.swing.JOptionPane;
@@ -67,7 +74,7 @@
   private JTextField identifierExpression;
   private JTextField toolTipDisplayMillis;
   private JTextField cyclicBufferSize;    
-  private final JTextField configurationURL = new JTextField(35);
+  private JComboBox configurationURL;
   private final Logger logger;
 
   ApplicationPreferenceModelPanel(ApplicationPreferenceModel model) {
@@ -77,7 +84,7 @@
     getOkButton().addActionListener(
       new ActionListener() {
         public void actionPerformed(ActionEvent e) {
-          uncommittedPreferenceModel.setConfigurationURL(configurationURL.getText());
+          uncommittedPreferenceModel.setConfigurationURL((String)configurationURL.getSelectedItem());
           uncommittedPreferenceModel.setIdentifierExpression(
             identifierExpression.getText());
             try {
@@ -409,6 +416,11 @@
     private void initComponents() {
       setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
 
+      configurationURL = new JComboBox(new DefaultComboBoxModel(committedPreferenceModel.getConfigurationURLs()));
+      configurationURL.setEditable(true);
+      configurationURL.setPrototypeDisplayValue("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
+      configurationURL.setPreferredSize(new Dimension(375, 25));
+
       identifierExpression = new JTextField(20);
       toolTipDisplayMillis = new JTextField(8);
       cyclicBufferSize = new JTextField(8);
@@ -470,11 +482,50 @@
       p6.add(configurationURL);
       add(p6);
 
-      JPanel p7 = new JPanel(new FlowLayout(FlowLayout.LEFT));
-      p7.add(
+      JButton browseButton = new JButton("Browse");
+      browseButton.addActionListener(new ActionListener()
+      {
+          public void actionPerformed(ActionEvent e)
+          {
+
+              String defaultPath = ".";
+              if (configurationURL.getItemCount() > 0) {
+                File currentConfigurationPath = new File(configurationURL.getSelectedItem().toString()).getParentFile();
+                  defaultPath = currentConfigurationPath.getPath();
+                  //JFileChooser constructor will not navigate to this location unless we remove the prefixing protocol and slash
+                  //at least on winxp
+                  if (defaultPath.toLowerCase().startsWith("file:\\")) {
+                      defaultPath = defaultPath.substring("file:\\".length());
+                  }
+              }
+
+              JFileChooser chooser = new JFileChooser(defaultPath);
+              int result = chooser.showOpenDialog(ApplicationPreferenceModelPanel.this);
+              if (JFileChooser.APPROVE_OPTION == result) {
+                  File f = chooser.getSelectedFile();
+                  try
+                  {
+                      String newConfigurationFile = f.toURI().toURL().toExternalForm();
+                      configurationURL.addItem(newConfigurationFile);
+                      configurationURL.setSelectedItem(newConfigurationFile);
+                  }
+                  catch (MalformedURLException e1)
+                  {
+                      e1.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
+                  }
+              }
+          }
+      });
+
+      JPanel p7 = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+      p7.add(browseButton);
+      add(p7);
+
+      JPanel p8 = new JPanel(new FlowLayout(FlowLayout.LEFT));
+      p8.add(
         new JLabel(
           "Cyclic buffer size change will apply the next time you start Chainsaw"));
-      add(p7);
+      add(p8);
 
       add(Box.createVerticalGlue());
       
@@ -484,12 +535,13 @@
         public boolean verify(JComponent input)
         {
             try {
-                new URL(configurationURL.getText());
+                new URL((String)configurationURL.getSelectedItem());
             } catch (Exception e) {
                 return false;
             }
             return true;
         }});
+        configurationURL.setSelectedItem(committedPreferenceModel.getConfigurationURL());
     }
 
     private void initSliderComponent() {
@@ -643,7 +695,7 @@
 
           public void propertyChange(PropertyChangeEvent evt) {
             String value = evt.getNewValue().toString();
-            configurationURL.setText(value);
+            configurationURL.setSelectedItem(value);
           }});
       confirmExit.addActionListener(
         new ActionListener() {
@@ -673,7 +725,7 @@
       identifierExpression.setText(uncommittedPreferenceModel.getIdentifierExpression());
       toolTipDisplayMillis.setText(uncommittedPreferenceModel.getToolTipDisplayMillis()+"");
       cyclicBufferSize.setText(uncommittedPreferenceModel.getCyclicBufferSize() + "");
-      configurationURL.setText(uncommittedPreferenceModel.getConfigurationURL());
+      configurationURL.setSelectedItem(uncommittedPreferenceModel.getConfigurationURL());
     }
   }
 }
diff --git a/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelSaver.java b/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelSaver.java
index 81268bb..dff04af 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelSaver.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelSaver.java
@@ -4,14 +4,14 @@
 import java.io.FileReader;
 import java.io.FileWriter;
 
+import com.thoughtworks.xstream.XStream;
+import com.thoughtworks.xstream.io.xml.DomDriver;
+
 import org.apache.log4j.chainsaw.prefs.LoadSettingsEvent;
 import org.apache.log4j.chainsaw.prefs.SaveSettingsEvent;
 import org.apache.log4j.chainsaw.prefs.SettingsListener;
 import org.apache.log4j.chainsaw.prefs.SettingsManager;
 
-import com.thoughtworks.xstream.XStream;
-import com.thoughtworks.xstream.io.xml.DomDriver;
-
 /**
  * Helper class that helps delegate the work of loading and saving the  values
  * of the ApplicationPreferenceModel, allowing that class to remain a simple
@@ -37,8 +37,8 @@
 
     public void loadSettings(LoadSettingsEvent event) {
         XStream stream = new XStream(new DomDriver());
+        File file = getApplicationPreferenceXMLFile(SettingsManager.getInstance().getSettingsDirectory());
         try {
-            File file = getApplicationPreferenceXMLFile(SettingsManager.getInstance().getSettingsDirectory());
             if (file.exists()) {
                 FileReader reader = new FileReader(file);
                 ApplicationPreferenceModel loadedModel = (ApplicationPreferenceModel) stream
@@ -49,8 +49,9 @@
         } catch (Exception e) {
 //            TODO exception handling
             e.printStackTrace();
+            //unable to process - delete file 
+            file.delete();
         }
-
     }
 
     public void saveSettings(SaveSettingsEvent event) {
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogUI.java b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
index 610f0b8..0e17dfa 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogUI.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
@@ -373,6 +373,7 @@
     
     Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
 		public void uncaughtException(Thread t, Throwable e) {
+            e.printStackTrace();
 			logger.error("Uncaught exception in thread " + t, e);
 		}
     });
@@ -405,7 +406,7 @@
             }
         }});
 
-    if (config == null) {
+    if (config == null || config.trim().equals("")) {
       logger.info("No auto-configuration file found within the ApplicationPreferenceModel");
     } else {
       logger.info("Using '" + config + "' for auto-configuration");