Initial checkin of directory structure and source code of the java Activity
authorDavid Schmidt <david__schmidt@users.sourceforge.net>
Sat, 18 Jan 2003 14:37:24 +0000 (14:37 +0000)
committerDavid Schmidt <david__schmidt@users.sourceforge.net>
Sat, 18 Jan 2003 14:37:24 +0000 (14:37 +0000)
Console

20 files changed:
src/java/org/privoxy/activityconsole/ActivityConsole.java [new file with mode: 0644]
src/java/org/privoxy/activityconsole/ActivityConsoleGui.java [new file with mode: 0644]
src/java/org/privoxy/activityconsole/ActivityConsoleGuiUtil.java [new file with mode: 0644]
src/java/org/privoxy/activityconsole/ActivityConsoleResources.java [new file with mode: 0644]
src/java/org/privoxy/activityconsole/BevelArrowIcon.java [new file with mode: 0644]
src/java/org/privoxy/activityconsole/BlankIcon.java [new file with mode: 0644]
src/java/org/privoxy/activityconsole/ColumnRef.java [new file with mode: 0644]
src/java/org/privoxy/activityconsole/Copyright.java [new file with mode: 0644]
src/java/org/privoxy/activityconsole/ServerThread.java [new file with mode: 0644]
src/java/org/privoxy/activityconsole/SortButtonRenderer.java [new file with mode: 0644]
src/java/org/privoxy/activityconsole/SortableTableModel.java [new file with mode: 0644]
src/java/org/privoxy/activityconsole/Stat.java [new file with mode: 0644]
src/java/org/privoxy/activityconsole/StatWidget.java [new file with mode: 0644]
src/java/org/privoxy/activityconsole/StatWidgetThread.java [new file with mode: 0644]
src/java/org/privoxy/activityconsole/StringUtil.java [new file with mode: 0644]
src/java/org/privoxy/activityconsole/TableSorter.java [new file with mode: 0644]
src/java/org/privoxy/activityconsole/acon.bat [new file with mode: 0755]
src/java/org/privoxy/activityconsole/acon.cmd [new file with mode: 0755]
src/java/org/privoxy/activityconsole/acon.manifest [new file with mode: 0644]
src/java/org/privoxy/activityconsole/acon.sh [new file with mode: 0644]

diff --git a/src/java/org/privoxy/activityconsole/ActivityConsole.java b/src/java/org/privoxy/activityconsole/ActivityConsole.java
new file mode 100644 (file)
index 0000000..f0df73a
--- /dev/null
@@ -0,0 +1,67 @@
+/*********************************************************************
+ *
+ * File        :  $Source$
+ *
+ * Purpose     :  Launch the Activity Console GUI with either the 
+ *                specified listen port or the default if none is 
+ *                specified on the command line.
+ *
+ * Copyright   :  Written by and Copyright (C) 2003 the SourceForge
+ *                Privoxy team. http://www.privoxy.org/
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, or (at
+ *                your option) any later version.
+ *
+ *                This program is distributed in the hope that it will
+ *                be useful, but WITHOUT ANY WARRANTY; without even the
+ *                implied warranty of MERCHANTABILITY or FITNESS FOR A
+ *                PARTICULAR PURPOSE.  See the GNU General Public
+ *                License for more details.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log$
+ *********************************************************************/
+
+package org.privoxy.activityconsole;
+
+/**
+ * Launch the Activity Console GUI with either the specified listen port
+ * or the default if none is specified on the command line.
+ * @author Last Modified By: $Author$
+ * @version $Rev$-$Date$$State$
+ */
+public class ActivityConsole
+{
+  private static final String
+    COPYRIGHT = org.privoxy.activityconsole.Copyright.COPYRIGHT;
+
+  /**
+   * main method; initializes the GUI.
+   *
+   * @String[] args - command line parameters.
+   */
+  public static void main(java.lang.String[] args)
+  {
+    try
+    {
+      ActivityConsoleGui gui = new ActivityConsoleGui(args[0]);
+    }
+    catch (Throwable t)
+    {
+      ActivityConsoleGui gui = new ActivityConsoleGui("8119");
+    }
+  }
+}
diff --git a/src/java/org/privoxy/activityconsole/ActivityConsoleGui.java b/src/java/org/privoxy/activityconsole/ActivityConsoleGui.java
new file mode 100644 (file)
index 0000000..2f85dc3
--- /dev/null
@@ -0,0 +1,629 @@
+/*********************************************************************
+ *
+ * File        :  $Source$
+ *
+ * Purpose     :  Provide the central GUI for displaying Privoxy
+ *                statistics.  It can be contacted either by the
+ *                local machine or other machines in a network and
+ *                display consolidated, tabular statistics.
+ *
+ * Copyright   :  Written by and Copyright (C) 2003 the SourceForge
+ *                Privoxy team. http://www.privoxy.org/
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, or (at
+ *                your option) any later version.
+ *
+ *                This program is distributed in the hope that it will
+ *                be useful, but WITHOUT ANY WARRANTY; without even the
+ *                implied warranty of MERCHANTABILITY or FITNESS FOR A
+ *                PARTICULAR PURPOSE.  See the GNU General Public
+ *                License for more details.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log$
+ *********************************************************************/
+
+package org.privoxy.activityconsole;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+import javax.swing.table.*;
+
+/**
+ * The main Activity Console GUI.
+ * @author Last Modified By: $Author$
+ * @version $Rev$-$Date$$State$
+ */
+public final class ActivityConsoleGui extends JFrame implements ActionListener
+{
+  private static final String
+  COPYRIGHT = org.privoxy.activityconsole.Copyright.COPYRIGHT;
+
+  ActivityConsoleGui parent_;
+  ServerThread _serverThread = null;
+  private ListResourceBundle resStrings = (ListResourceBundle)ListResourceBundle.getBundle("org.privoxy.activityconsole.ActivityConsoleResources");
+
+  JTable _table;
+
+  SortableTableModel _model;
+
+  Vector
+  _tableColumnMap = new Vector();
+
+  JPanel
+  mainPanel = new JPanel(new GridBagLayout());
+
+  JMenuItem _deleteItem, _quitItem, _configItem;
+
+  private DefaultTableCellRenderer _statRenderer = null;
+
+  int _port = 0;
+
+  /**
+   * Constructor of the Activity Console GUI.
+   * @param arg the port to serve connections on - as an int parsed from the String
+   */
+  public ActivityConsoleGui(String arg)
+  {
+    int i;
+
+    addWindowListener(new WindowCloseMonitor());
+
+    JMenuBar menuBar = new JMenuBar();
+
+    JMenu menuFile = new JMenu(resStrings.getString("menuFile"));
+    MenuAction quitAction = new MenuAction(resStrings.getString("menuFileQuit"));
+    JMenu menuEdit = new JMenu(resStrings.getString("menuEdit"));
+    _quitItem = menuFile.add(quitAction);
+    menuBar.add(menuFile);
+    _configItem = menuEdit.add(new MenuAction(resStrings.getString("menuEditConfig")));
+    menuBar.add(menuEdit);
+    _deleteItem = menuEdit.add(new MenuAction(resStrings.getString("menuEditDelete")));
+    menuBar.add(menuEdit);
+    this.setJMenuBar(menuBar);
+    _deleteItem.setEnabled(false);
+
+    try
+    {
+      _port = Integer.parseInt(arg);
+      if (_port < 0)
+        _port = 0;
+    }
+    catch (Throwable t)
+    {
+      _port = 0;
+    }
+
+    /**
+     * The cell renderer for the StatWidget Component - simply returns the component
+     * itself.  Additionally, it has the extra hack of telling the StatWidget where
+     * it is in the table so it can update itself again when it comes time to flash.
+     */
+    _statRenderer = new DefaultTableCellRenderer()
+    {
+      public Component getTableCellRendererComponent(JTable table,
+                                                     Object value,
+                                                     boolean isSelected,
+                                                     boolean hasFocus,
+                                                     int row,
+                                                     int column)
+      {
+        /* Housekeeping: keep track of the row, column and table references as we go */
+        ((StatWidget)value).setRowColTable(row,column,table);
+        return(Component)value;
+      }
+
+      public void setValue(Object value)
+      {
+        Color color = null;
+        try
+        {
+          color = (Color)value;
+        }
+        catch (ClassCastException e)
+        {
+          color = Color.white;
+        }
+        setBackground(color);
+      }
+    };
+
+    Vector data = new Vector();
+    _model = new SortableTableModel(data, getColumnNames());
+    _table = new JTable(_model);
+    _table.setPreferredScrollableViewportSize(new Dimension(800,50));
+    _table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
+    _table.setCellSelectionEnabled(false);
+    _table.setRowSelectionAllowed(false);
+
+    /*
+     * The first column is normal and text-ish - the host address and
+     * port being served (i.e. 127.0.0.1:8118).  The rest need to have statistic
+     * renderers defined.
+     */
+    SortButtonRenderer _headerRenderer = new SortButtonRenderer();
+    TableColumnModel cm = _table.getColumnModel();
+    /* Make the first column twice the width of the others. It shows bigger stuff. */
+    cm.getColumn(0).setPreferredWidth(cm.getColumn(0).getPreferredWidth() * 2);
+    cm.getColumn(0).setHeaderRenderer(_headerRenderer);
+    for (i = 1;i<_model.getColumnCount();i++)
+    {
+      cm.getColumn(i).setPreferredWidth((int)(cm.getColumn(i).getPreferredWidth() * 1));
+      cm.getColumn(i).setCellRenderer(_statRenderer);
+      cm.getColumn(i).setHeaderRenderer(_headerRenderer);
+    }
+
+    JTableHeader header = _table.getTableHeader();
+    header.addMouseListener(new HeaderListener(header,_headerRenderer));
+
+    ListSelectionModel csm = _table.getSelectionModel();
+    csm.addListSelectionListener(new SelectedListener(csm));
+
+    ActivityConsoleGuiUtil.constrain(mainPanel, new JScrollPane(_table),
+                                     1, 1, // X, Y Coordinates
+                                     1, 1, // Grid width, height
+                                     GridBagConstraints.BOTH,  // Fill value
+                                     GridBagConstraints.WEST,  // Anchor value
+                                     1.0,1.0,  // Weight X, Y
+                                     0, 0, 0, 0 ); // Top, left, bottom, right insets
+
+    this.getContentPane().add(mainPanel, BorderLayout.CENTER);
+
+    parent_ = this;
+    this.pack();
+    _table.setPreferredScrollableViewportSize(new Dimension(_table.getWidth(),50));
+    this.pack();
+
+    if (_port > 0)
+    {
+      _serverThread = new ServerThread(this, _port);
+      _serverThread.start();
+    }
+    updateTitle(_port);
+    setBounds(ActivityConsoleGuiUtil.center(this.getSize()));
+    this.show();
+  }
+
+  /**
+   * Updates the title bar with the port currently being served.
+   * @param port the port being served
+   */
+  public void updateTitle(int port)
+  {
+    String title = resStrings.getString("guiTitle");
+
+    title = StringUtil.replaceSubstring(title,"%1",""+port);
+    setTitle(title);
+  }
+
+  public void actionPerformed(ActionEvent e)
+  {
+  }
+
+  class MenuAction extends AbstractAction
+  {
+    public MenuAction(String text)
+    {
+      super(text,null);
+    }
+
+    public MenuAction(String text, Icon icon)
+    {
+      super(text,icon);
+    }
+
+    public void actionPerformed(ActionEvent e)
+    {
+      if (e.getSource() == _quitItem)
+      {
+        parent_.setVisible(false);
+        parent_.dispose();
+        System.exit(0);
+      }
+      else if (e.getSource() == _deleteItem)
+      {
+        deleteAction();
+      }
+      else if (e.getSource() == _configItem)
+      {
+        changeServerAction();
+      }
+    }
+  }
+
+  /**
+   * Asks the user to specify a new port to serve
+   */
+  public void changeServerAction()
+  {
+    int port = -1;
+    String message = resStrings.getString("guiNewPortPrompt");
+    message = StringUtil.replaceSubstring(message,"%1",""+_port);
+
+    String inputValue = JOptionPane.showInputDialog(this,
+                                                    message,
+                                                    resStrings.getString("guiNewPortTitle"),
+                                                    JOptionPane.QUESTION_MESSAGE);
+    if (inputValue != null)
+      try
+      {
+        port = Integer.parseInt(inputValue);
+      }
+      catch (Throwable t)
+      {
+        port = -1;
+      }
+    if (port < 1)
+      JOptionPane.showMessageDialog(null, resStrings.getString("guiNewPortErrorPrompt"), resStrings.getString("guiNewPortErrorTitle"), JOptionPane.ERROR_MESSAGE);
+    else
+    {
+      if (_port != port)
+      {
+        if (_serverThread != null)
+        {
+          _serverThread.doClose();
+          _serverThread.interrupt();
+          _serverThread = null;
+        }
+        _port = port;
+        _serverThread = new ServerThread(parent_, port);
+        _serverThread.start();
+        updateTitle(_port);
+      }
+    }
+  }
+
+  /**
+   * Deletes the "selected" row after seeking confirmation
+   */
+  public void deleteAction()
+  {
+    int numSelections = _table.getSelectedRowCount();
+    int selRow = _table.getSelectedRow();
+    if (numSelections > 0)
+    {
+      if ((selRow > -1) &&
+          (selRow < _table.getRowCount()))
+      {
+        /* Ask for confirmation */
+        String message = resStrings.getString("guiDeleteConfirmPrompt");
+        message = StringUtil.replaceSubstring(message,"%1",(String)_model.getValueAt(selRow,0));
+        int ret = JOptionPane.showConfirmDialog(null,
+                                                message,
+                                                resStrings.getString("guiDeleteConfirmTitle"),
+                                                JOptionPane.YES_NO_OPTION);
+        if (ret == JOptionPane.YES_OPTION)
+        {
+          _model.removeRow(selRow);
+        }
+      }
+    }
+  }
+
+  /**
+   * Retrieves the names of the column headers.  This should be made to read a properties
+   * file. FIXME.
+   * @return Vector the set of column names.  It also has the side-effect of adding
+   * entries to the global column mapping Vector where we map the staus integer identifiers
+   * to the column positions and names.  Should probably fix that too.
+   */
+  public Vector getColumnNames()
+  {
+    Vector names = new Vector();
+
+    names.addElement(resStrings.getString("guiDefaultColumn0"));
+    names.addElement(resStrings.getString("guiDefaultColumn1"));
+    names.addElement(resStrings.getString("guiDefaultColumn2"));
+    names.addElement(resStrings.getString("guiDefaultColumn3"));
+    names.addElement(resStrings.getString("guiDefaultColumn4"));
+    names.addElement(resStrings.getString("guiDefaultColumn5"));
+    names.addElement(resStrings.getString("guiDefaultColumn6"));
+    names.addElement(resStrings.getString("guiDefaultColumn7"));
+    names.addElement(resStrings.getString("guiDefaultColumn8"));
+    names.addElement(resStrings.getString("guiDefaultColumn9"));
+    names.addElement(resStrings.getString("guiDefaultColumn10"));
+
+    _tableColumnMap.addElement(new ColumnRef(resStrings.getString("guiDefaultColumn1"),1));
+    _tableColumnMap.addElement(new ColumnRef(resStrings.getString("guiDefaultColumn2"),2));
+    _tableColumnMap.addElement(new ColumnRef(resStrings.getString("guiDefaultColumn3"),3));
+    _tableColumnMap.addElement(new ColumnRef(resStrings.getString("guiDefaultColumn4"),4));
+    _tableColumnMap.addElement(new ColumnRef(resStrings.getString("guiDefaultColumn5"),5));
+    _tableColumnMap.addElement(new ColumnRef(resStrings.getString("guiDefaultColumn6"),6));
+    _tableColumnMap.addElement(new ColumnRef(resStrings.getString("guiDefaultColumn7"),7));
+    _tableColumnMap.addElement(new ColumnRef(resStrings.getString("guiDefaultColumn8"),8));
+    _tableColumnMap.addElement(new ColumnRef(resStrings.getString("guiDefaultColumn9"),9));
+    _tableColumnMap.addElement(new ColumnRef(resStrings.getString("guiDefaultColumn10"),10));
+
+    return names;
+  }
+
+  /**
+   * Parses a String of statistics coming from Privoxy.
+   * @param line The statistics string sent from Privoxy
+   * @param from the hostname that sent the statistics
+   */
+  public void updateStats(String line, String from)
+  {
+    /*
+     * An example line of data:
+     * 0:8118 1:0 2:0 3:0 4:0 5:0 6:0 7:0 8:0 9:0 10:0
+     */
+    int key, value;
+    String tableKey = "", key_str, value_str, token;
+    StringTokenizer colonToken;
+    StringTokenizer spaceTokens = new StringTokenizer(line);
+    Vector stats = new Vector();
+
+    while (spaceTokens.hasMoreTokens())
+    {
+      token = spaceTokens.nextToken();
+      colonToken = new StringTokenizer(token,":");
+      if (colonToken.hasMoreTokens())
+      {
+        key_str = null; value_str = null;
+        key = -1; value = 0;
+
+        /* First token is the key */
+        key_str = colonToken.nextToken();
+        try
+        {
+          key = Integer.parseInt(key_str);
+        }
+        catch (NumberFormatException n)
+        {
+          key = -1;
+        }
+
+        if ((colonToken.hasMoreTokens()) && (key > -1))
+        {
+          /* Next token, if present, is the value */
+          value_str = colonToken.nextToken();
+          if (key == 0)
+          {
+            /*
+             * The key to the table row is the concatenation of the serving
+             * IP address string, a full colon, and the port string.
+             */
+            tableKey = from + ":" + value_str;
+          }
+          try
+          {
+            value = Integer.parseInt(value_str);
+            stats.addElement((Object)(new Stat(key, value)));
+          }
+          catch (NumberFormatException n)
+          {
+            value = 0;
+          }
+        }
+      }
+    }
+    if ((tableKey.compareTo("") != 0) && (stats.size() > 0))
+    {
+      updateTable(tableKey, stats);
+      stats.removeAllElements();
+    }
+    stats = null;
+  }
+
+  /**
+   * Updates (or creates) a line in the table representing the incoming packet of stats.
+   * @param tableKey Our key to a unique table row: the hostname concatenated with the Privoxy port being served.
+   * @param stats Vector of statistics elements
+   */
+  public void updateTable(String tableKey, Vector stats)
+  {
+    boolean found = false;
+    for (int i = 0; i < _model.getRowCount(); i++)
+    {
+      if (((String)_model.getValueAt(i,_table.convertColumnIndexToView(0))).compareTo(tableKey) == 0)
+      {
+        updateTableEntry(i, stats);
+        found = true;
+      }
+    }
+    /* If we can't find one in the table already... */
+    if (found == false)
+      createTableEntry(tableKey, stats);
+  }
+
+  /**
+   * Creates a line in the table representing the incoming packet of stats.
+   * @param tableKey Our key to a unique table row: the hostname concatenated with the Privoxy port being served.
+   * @param stats Vector of statistics elements
+   */
+  public void createTableEntry(String tableKey, Vector stats)
+  {
+    int i, j;
+    Vector row = new Vector();
+    boolean added = false;
+
+    row.addElement(tableKey);
+
+    /*
+     * If we have a key (in stats) that maps to a key in the _tableColumnMap,
+     * then we add it to the vector destined for the table.
+     */
+    for (i = 0; i < _tableColumnMap.size(); i ++)
+    {
+      for (j = 0; j < stats.size(); j++)
+      {
+        if (((Stat)stats.elementAt(j)).getKey() == ((ColumnRef)_tableColumnMap.elementAt(i)).getKey())
+        {
+          row.addElement(new StatWidget(((Stat)stats.elementAt(j)).getValue(),500));
+          added = true;
+        }
+      }
+      if (added == false)
+      {
+        row.addElement(new StatWidget(0,500));
+      }
+      else
+        added = false;
+    }
+    _model.addRow(row);
+  }
+
+  /**
+   * Updates a line in the table by tweaking the StatWidgets.
+   * @param row the table row if the StatWidget
+   * @param stats The Vector of Stat elements to update the table row with
+   */
+  public void updateTableEntry(int row, Vector stats)
+  {
+    int i, j;
+
+    for (i = 0; i < _tableColumnMap.size(); i ++)
+    {
+      for (j = 0; j < stats.size(); j++)
+      {
+        if (((Stat)stats.elementAt(j)).getKey() == ((ColumnRef)_tableColumnMap.elementAt(i)).getKey())
+        {
+          ((StatWidget)_model.getValueAt(row,i+1)).updateValue(((Stat)stats.elementAt(j)).getValue());
+          stats.removeElementAt(j);
+          break;
+        }
+      }
+    }
+  }
+
+  /**
+   * Worker class to offer a clickable table header for sorting.
+   */
+  class HeaderListener extends MouseAdapter
+  {
+    JTableHeader   header;
+    SortButtonRenderer renderer;
+
+    HeaderListener(JTableHeader header,SortButtonRenderer renderer)
+    {
+      this.header   = header;
+      this.renderer = renderer;
+    }
+
+    public void mousePressed(MouseEvent e)
+    {
+      Point click = e.getPoint();
+      int col = header.columnAtPoint(click);
+      int margin1, margin2;
+      int sortCol = header.getTable().convertColumnIndexToModel(col);
+
+      /* Don't perform the sort if the user is just trying to resize the columns. */
+      margin1 = header.columnAtPoint(new Point(click.x+3,click.y));
+      margin2 = header.columnAtPoint(new Point(click.x-3,click.y));
+      if ((col == margin1) && (col == margin2))
+      {
+        renderer.setPressedColumn(col);
+        renderer.setSelectedColumn(col);
+        header.repaint();
+
+        if (header.getTable().isEditing())
+        {
+          header.getTable().getCellEditor().stopCellEditing();
+        }
+
+        boolean isAscent;
+        if (SortButtonRenderer.DOWN == renderer.getState(col))
+        {
+          isAscent = true;
+        }
+        else
+        {
+          isAscent = false;
+        }
+        ((SortableTableModel)header.getTable().getModel())
+        .sortByColumn(sortCol, isAscent);    
+      }
+    }
+
+    public void mouseReleased(MouseEvent e)
+    {
+      int col = header.columnAtPoint(e.getPoint());
+      renderer.setPressedColumn(-1);                // clear
+      header.repaint();
+    }
+  }
+
+  /**
+   * Worker class to tell the menu when it's OK to delete a row (i.e. when a row gets
+   * selected).  This doesn't work reliably, but it's better than nothing.
+   */
+  public class SelectedListener implements ListSelectionListener
+  {
+    ListSelectionModel model;
+
+    public SelectedListener(ListSelectionModel lsm)
+    {
+      model = lsm;
+    }
+
+    public void valueChanged(ListSelectionEvent lse)
+    {
+      // NOTE - keep this in sync with columnSelectionChanged below...
+      int numSelections = _table.getSelectedRowCount();
+      int selRow = _table.getSelectedRow();
+      if (numSelections > 0)
+      {
+        if ((selRow > -1) &&
+            (selRow < _table.getRowCount()))
+        {
+          _deleteItem.setEnabled(true);
+        }
+        else
+          _deleteItem.setEnabled(false);
+      }
+      else
+        _deleteItem.setEnabled(false);
+    }
+    public void columnSelectionChanged(ListSelectionEvent lse)
+    {
+      // NOTE - keep this in sync with valueChanged above...
+      int numSelections = _table.getSelectedRowCount();
+      int selRow = _table.getSelectedRow();
+      if (numSelections > 0)
+      {
+        if ((selRow > -1) &&
+            (selRow < _table.getRowCount()))
+        {
+          _deleteItem.setEnabled(true);
+        }
+        else
+          _deleteItem.setEnabled(false);
+      }
+      else
+        _deleteItem.setEnabled(false);
+    }
+  }
+
+  /**
+   * Watch for the window closing event.  Dunno why swing doesn't handle this better natively.
+   */
+  public class WindowCloseMonitor extends WindowAdapter
+  {
+    public void windowClosing(WindowEvent e)
+    {
+      Window w = e.getWindow();
+      w.setVisible(false);
+      w.dispose();
+      System.exit(0);
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/java/org/privoxy/activityconsole/ActivityConsoleGuiUtil.java b/src/java/org/privoxy/activityconsole/ActivityConsoleGuiUtil.java
new file mode 100644 (file)
index 0000000..468f832
--- /dev/null
@@ -0,0 +1,207 @@
+/*********************************************************************
+ *
+ * File        :  $Source$
+ *
+ * Purpose     :  Utility functions for GridBag layout and centering
+ *                frames.
+ *
+ * Copyright   :  Written by and Copyright (C) 2003 the SourceForge
+ *                Privoxy team. http://www.privoxy.org/
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, or (at
+ *                your option) any later version.
+ *
+ *                This program is distributed in the hope that it will
+ *                be useful, but WITHOUT ANY WARRANTY; without even the
+ *                implied warranty of MERCHANTABILITY or FITNESS FOR A
+ *                PARTICULAR PURPOSE.  See the GNU General Public
+ *                License for more details.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log$
+ *********************************************************************/
+
+package org.privoxy.activityconsole;
+
+import java.awt.*;
+
+/**
+ * The ActivityConsoleGuiUtil class: Helper routines for the GridBag layout.
+ * @author Last Modified By: $Author$
+ * @version $Rev$-$Date$$State$
+ */
+public class ActivityConsoleGuiUtil 
+{
+  private static final String
+    COPYRIGHT = org.privoxy.activityconsole.Copyright.COPYRIGHT;
+
+  /** constrain - Helper method for setting a componets constraints in a gridbag layout;
+    * takes all of the possible parameters for grid constraints.
+    * @param container  conatiner to add the component to
+    * @param component  component that will be added
+    * @param grid_x x value
+    * @param grid_y y value
+    * @param grid_width grid width for the component
+    * @param grid_height grid height for the component
+    * @param fill fill value
+    * @param anchor anchor value
+    * @param weight_x weight x
+    * @param weight_y weight y
+    * @param top top inset
+    * @param left left inset
+    * @param bottom bottom inset
+    * @param right right inset
+    */
+
+  public static void constrain(Container container,
+                               Component component, 
+                               int grid_x,
+                               int grid_y,
+                               int grid_width,
+                               int grid_height,
+                               int fill,
+                               int anchor,
+                               double weight_x,
+                               double weight_y,
+                               int top,
+                               int left,
+                               int bottom,
+                               int right)
+  {
+    GridBagConstraints c = new GridBagConstraints();
+    c.gridx = grid_x;
+    c.gridy = grid_y;
+    c.gridwidth = grid_width;
+    c.gridheight = grid_height;
+    c.fill = fill;
+    c.anchor = anchor;
+    c.weightx = weight_x;
+    c.weighty = weight_y;
+    if (top+bottom+left+right > 0)
+      c.insets = new Insets(top, left, bottom, right);
+
+    ((GridBagLayout)container.getLayout()).setConstraints(component, c);
+    container.add(component);
+  }
+
+  public static void constrain(Container container,
+                               Component component, 
+                               int grid_x,
+                               int grid_y,
+                               int grid_width,
+                               int grid_height)
+  {
+    constrain(container,
+              component,
+              grid_x,
+              grid_y,
+              grid_width,
+              grid_height,
+              GridBagConstraints.NONE, 
+              GridBagConstraints.NORTHWEST,
+              0.0, 0.0, 0, 0, 0, 0);
+  }
+
+  public static void constrain(Container container,
+                               Component component, 
+                               int grid_x,
+                               int grid_y,
+                               int grid_width,
+                               int grid_height,
+                               int top,
+                               int left,
+                               int bottom,
+                               int right)
+  {
+    constrain(container,
+              component,
+              grid_x,
+              grid_y, 
+              grid_width,
+              grid_height,
+              GridBagConstraints.NONE, 
+              GridBagConstraints.NORTHWEST, 
+              0.0, 0.0, top, left, bottom, right);
+  }
+
+  /** constrainLast - Helper method for setting a componets constraints in a gridbag layout;
+    * takes all of the possible parameters for grid constraints.
+    * @param container  conatiner to add the component to
+    * @param component  component that will be added
+    * @param grid_x x value
+    * @param grid_y y value
+    * @param top top inset
+    * @param left left inset
+    * @param bottom bottom inset
+    * @param right right inset
+    */
+
+  public static void constrainLast(Container container,
+                                   Component component,
+                                   int grid_x,
+                                   int grid_y,
+                                   int top,
+                                   int left,
+                                   int bottom,
+                                   int right)
+  {
+    constrain(container,
+              component,
+              grid_x,
+              grid_y, 
+              GridBagConstraints.REMAINDER,1,
+              GridBagConstraints.HORIZONTAL, 
+              GridBagConstraints.NORTHWEST, 
+              0.0, 0.0, top, left, bottom, right);
+  }
+
+  /** constrain - Helper method for setting a componets constraints in a gridbag layout;
+    * takes all of the possible parameters for grid constraints.
+    * @param container  conatiner to add the component to
+    * @param component  component that will be added
+    * @param int        x value
+    * @param int        y value
+    * @param int        top inset
+    * @param int        left inset
+    * @param int        bottom inset
+    * @param int        right inset
+    */
+
+  public static void constrain(Container container, Component component, 
+                               int grid_x, int grid_y,int top, int left, int bottom, int right)
+  {
+    constrain(container,
+              component,
+              grid_x,
+              grid_y, 
+              1, 1,
+              GridBagConstraints.NONE, 
+              GridBagConstraints.NORTHWEST, 
+              0.0, 0.0, top, left, bottom, right);
+  }
+
+  public static Rectangle center(Dimension dim)
+  {
+    final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+
+    final Rectangle centeredRect =
+    new Rectangle( (screenSize.width  - dim.width)  /2,
+                   (screenSize.height - dim.height) /2,
+                   dim.width,
+                   dim.height);
+    return centeredRect;
+  }
+}
diff --git a/src/java/org/privoxy/activityconsole/ActivityConsoleResources.java b/src/java/org/privoxy/activityconsole/ActivityConsoleResources.java
new file mode 100644 (file)
index 0000000..a614fad
--- /dev/null
@@ -0,0 +1,107 @@
+/*********************************************************************
+ *
+ * File        :  $Source$
+ *
+ * Purpose     :  Default English text for all translatable strings.
+ *
+ * Copyright   :  Written by and Copyright (C) 2003 the SourceForge
+ *                Privoxy team. http://www.privoxy.org/
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, or (at
+ *                your option) any later version.
+ *
+ *                This program is distributed in the hope that it will
+ *                be useful, but WITHOUT ANY WARRANTY; without even the
+ *                implied warranty of MERCHANTABILITY or FITNESS FOR A
+ *                PARTICULAR PURPOSE.  See the GNU General Public
+ *                License for more details.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log$
+ *********************************************************************/
+
+package org.privoxy.activityconsole;
+
+import java.io.Serializable;
+
+/**
+ * The default (English) language resources file for the Activity Console.
+ * @author Last Modified By: $Author$
+ * @version $Rev$-$Date$$State$
+ */
+public class ActivityConsoleResources extends java.util.ListResourceBundle implements Serializable
+{
+  private static final String
+    COPYRIGHT = org.privoxy.activityconsole.Copyright.COPYRIGHT;
+
+  static final Object[][] contents =
+  {
+    {"guiTitle", "Activity Console - serving port %1"},
+    {"menuFile", "File"}, 
+    {"menuFileQuit", "Quit"}, 
+    {"menuEdit", "Edit"},
+    {"menuEditDelete", "Delete selected row"},
+    {"menuEditConfig", "Set port"},
+    {"guiNewPortTitle", "New port"},
+    {"guiNewPortPrompt", "Currently serving port %1.\n\nPlease enter the new port to serve:"},
+    {"guiNewPortErrorTitle", "Alert"},
+    {"guiNewPortErrorPrompt", "New port must be positive."},
+    {"guiDeleteConfirmTitle","Are you sure?"},
+    {"guiDeleteConfirmPrompt","Are you sure you want to delete stats from host %1?"},
+
+    /* Headers and descriptions for statistics columns */
+    {"guiDefaultColumn0","Host:Port"},
+    {"guiDefaultColumn0Description","The host and port that statistics are coming from"},
+    {"guiDefaultColumn1","Request"},
+    {"guiDefaultColumn1Description","The number of requests that flow through the proxy"},
+    {"guiDefaultColumn2","Filter"},
+    {"guiDefaultColumn2Description","The number of filters that have been applied"},
+    {"guiDefaultColumn3","Image"},
+    {"guiDefaultColumn3Description","The number of images that have been blocked"},
+    {"guiDefaultColumn4","De-anim"},
+    {"guiDefaultColumn4Description","The number of GIF images that have been de-animated"},
+    {"guiDefaultColumn5","Cookie"},
+    {"guiDefaultColumn5Description","The number of cookies that have been blocked"},
+    {"guiDefaultColumn6","Referer"},
+    {"guiDefaultColumn6Description","The number of referers blocked"},
+    {"guiDefaultColumn7","ACL"},
+    {"guiDefaultColumn7Description","The number of blocks due to ACL restrictions"},
+    {"guiDefaultColumn8","UA"},
+    {"guiDefaultColumn8Description","The number of times user-agent header was removed"},
+    {"guiDefaultColumn9","FROM"},
+    {"guiDefaultColumn9Description","The number of times the from: header was removed"},
+    {"guiDefaultColumn10","FORWARD"},
+    {"guiDefaultColumn10Description","The number of times the forward header was removed"},
+  };
+
+  /** Returns the contents of this ListBundleResources class.
+   * @see java.util.ListBundleResource
+   * @return Object an Object array containing this classes resources.
+   */
+  protected Object[][] getContents()
+  {
+    return contents;
+  }
+
+  /** Returns the name of the language this class represents.
+   * @return String the name of the language this class represents.
+   */
+
+  public String toString()
+  {
+    return "English";
+  }
+}
diff --git a/src/java/org/privoxy/activityconsole/BevelArrowIcon.java b/src/java/org/privoxy/activityconsole/BevelArrowIcon.java
new file mode 100644 (file)
index 0000000..c430c9a
--- /dev/null
@@ -0,0 +1,202 @@
+/*********************************************************************
+ *
+ * File        :  $Source$
+ *
+ * Purpose     :  Painting details for rendering the beveled arrow icon.
+ *
+ * Copyright   :  Written by and Copyright (C) 2003 the SourceForge
+ *                Privoxy team. http://www.privoxy.org/
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, or (at
+ *                your option) any later version.
+ *
+ *                This program is distributed in the hope that it will
+ *                be useful, but WITHOUT ANY WARRANTY; without even the
+ *                implied warranty of MERCHANTABILITY or FITNESS FOR A
+ *                PARTICULAR PURPOSE.  See the GNU General Public
+ *                License for more details.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log$
+ *********************************************************************/
+
+package org.privoxy.activityconsole;
+
+import java.awt.*;
+import javax.swing.*;
+
+/** 
+ * Painting details for rendering the beveled arrow icon.
+ * @author Last Modified By: $Author$
+ * @version $Rev$-$Date$$State$
+ */
+public class BevelArrowIcon implements Icon
+{
+
+  private static final String
+  COPYRIGHT = org.privoxy.activityconsole.Copyright.COPYRIGHT;
+
+  public static final int UP    = 0;         // direction
+  public static final int DOWN  = 1;
+
+  private static final int DEFAULT_SIZE = 11;
+
+  private Color edge1;
+  private Color edge2;
+  private Color fill;
+  private int size;
+  private int direction;
+
+  public BevelArrowIcon(int direction, boolean isRaisedView, boolean isPressedView)
+  {
+    if (isRaisedView)
+    {
+      if (isPressedView)
+      {
+        init( UIManager.getColor("controlLtHighlight"),
+              UIManager.getColor("controlDkShadow"),
+              UIManager.getColor("controlShadow"),
+              DEFAULT_SIZE, direction);
+      }
+      else
+      {
+        init( UIManager.getColor("controlHighlight"),
+              UIManager.getColor("controlShadow"),
+              UIManager.getColor("control"),
+              DEFAULT_SIZE, direction);
+      }
+    }
+    else
+    {
+      if (isPressedView)
+      {
+        init( UIManager.getColor("controlDkShadow"),
+              UIManager.getColor("controlLtHighlight"),
+              UIManager.getColor("controlShadow"),
+              DEFAULT_SIZE, direction);
+      }
+      else
+      {
+        init( UIManager.getColor("controlShadow"),
+              UIManager.getColor("controlHighlight"),
+              UIManager.getColor("control"),
+              DEFAULT_SIZE, direction);
+      }
+    }
+  }
+
+  public BevelArrowIcon(Color edge1, Color edge2, Color fill,
+                        int size, int direction)
+  {
+    init(edge1, edge2, fill, size, direction);
+  }
+
+
+  public void paintIcon(Component c, Graphics g, int x, int y)
+  {
+    switch (direction)
+    {
+    case DOWN: drawDownArrow(g, x, y); break;
+    case   UP: drawUpArrow(g, x, y);   break;
+    }
+  }
+
+  public int getIconWidth()
+  {
+    return size;
+  }
+
+  public int getIconHeight()
+  {
+    return size;
+  }
+
+
+  private void init(Color edge1, Color edge2, Color fill,
+                    int size, int direction)
+  {
+    this.edge1 = edge1;
+    this.edge2 = edge2;
+    this.fill = fill;
+    this.size = size;
+    this.direction = direction;
+  }
+
+  private void drawDownArrow(Graphics g, int xo, int yo)
+  {
+    g.setColor(edge1);
+    g.drawLine(xo, yo,   xo+size-1, yo);
+    g.drawLine(xo, yo+1, xo+size-3, yo+1);
+    g.setColor(edge2);
+    g.drawLine(xo+size-2, yo+1, xo+size-1, yo+1);
+    int x = xo+1;
+    int y = yo+2;
+    int dx = size-6;      
+    while (y+1 < yo+size)
+    {
+      g.setColor(edge1);
+      g.drawLine(x, y,   x+1, y);
+      g.drawLine(x, y+1, x+1, y+1);
+      if (0 < dx)
+      {
+        g.setColor(fill);
+        g.drawLine(x+2, y,   x+1+dx, y);
+        g.drawLine(x+2, y+1, x+1+dx, y+1);
+      }
+      g.setColor(edge2);
+      g.drawLine(x+dx+2, y,   x+dx+3, y);
+      g.drawLine(x+dx+2, y+1, x+dx+3, y+1);
+      x += 1;
+      y += 2;
+      dx -= 2;     
+    }
+    g.setColor(edge1);
+    g.drawLine(xo+(size/2), yo+size-1, xo+(size/2), yo+size-1); 
+  }
+
+  private void drawUpArrow(Graphics g, int xo, int yo)
+  {
+    g.setColor(edge1);
+    int x = xo+(size/2);
+    g.drawLine(x, yo, x, yo); 
+    x--;
+    int y = yo+1;
+    int dx = 0;
+    while (y+3 < yo+size)
+    {
+      g.setColor(edge1);
+      g.drawLine(x, y,   x+1, y);
+      g.drawLine(x, y+1, x+1, y+1);
+      if (0 < dx)
+      {
+        g.setColor(fill);
+        g.drawLine(x+2, y,   x+1+dx, y);
+        g.drawLine(x+2, y+1, x+1+dx, y+1);
+      }
+      g.setColor(edge2);
+      g.drawLine(x+dx+2, y,   x+dx+3, y);
+      g.drawLine(x+dx+2, y+1, x+dx+3, y+1);
+      x -= 1;
+      y += 2;
+      dx += 2;     
+    }
+    g.setColor(edge1);
+    g.drawLine(xo, yo+size-3,   xo+1, yo+size-3);
+    g.setColor(edge2);
+    g.drawLine(xo+2, yo+size-2, xo+size-1, yo+size-2);
+    g.drawLine(xo, yo+size-1, xo+size, yo+size-1);
+  }
+}
diff --git a/src/java/org/privoxy/activityconsole/BlankIcon.java b/src/java/org/privoxy/activityconsole/BlankIcon.java
new file mode 100644 (file)
index 0000000..a2b5859
--- /dev/null
@@ -0,0 +1,84 @@
+/*********************************************************************
+ *
+ * File        :  $Source$
+ *
+ * Purpose     :  Painting details for rendering a blank icon.
+ *
+ * Copyright   :  Written by and Copyright (C) 2003 the SourceForge
+ *                Privoxy team. http://www.privoxy.org/
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, or (at
+ *                your option) any later version.
+ *
+ *                This program is distributed in the hope that it will
+ *                be useful, but WITHOUT ANY WARRANTY; without even the
+ *                implied warranty of MERCHANTABILITY or FITNESS FOR A
+ *                PARTICULAR PURPOSE.  See the GNU General Public
+ *                License for more details.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log$
+ *********************************************************************/
+
+package org.privoxy.activityconsole;
+
+import java.awt. *;
+import javax.swing. *;
+
+/** 
+ * Painting details for rendering a blank icon.
+ * @author Last Modified By: $Author$
+ * @version $Rev$-$Date$$State$
+ */
+public class BlankIcon implements Icon
+{
+
+  private static final String
+  COPYRIGHT = org.privoxy.activityconsole.Copyright.COPYRIGHT;
+
+  private Color fillColor;
+  private int size;
+
+  public BlankIcon()
+  {
+    this(null, 11);
+  }
+
+  public BlankIcon(Color color, int size)
+  {
+    fillColor = color;
+    this.size = size;    
+  }
+
+  public void paintIcon(Component c, Graphics g, int x, int y)
+  {
+    if (fillColor != null)
+    {
+      g.setColor(fillColor);
+      g.drawRect(x, y, size-1, size-1);
+    }
+  }
+
+  public int getIconWidth()
+  {
+    return size;
+  }
+
+  public int getIconHeight()
+  {
+    return size;
+  }
+}
diff --git a/src/java/org/privoxy/activityconsole/ColumnRef.java b/src/java/org/privoxy/activityconsole/ColumnRef.java
new file mode 100644 (file)
index 0000000..a7743ca
--- /dev/null
@@ -0,0 +1,67 @@
+/*********************************************************************
+ *
+ * File        :  $Source$
+ *
+ * Purpose     :  Provides a mapping between a column's key and its
+ *                description.
+ *
+ * Copyright   :  Written by and Copyright (C) 2003 the SourceForge
+ *                Privoxy team. http://www.privoxy.org/
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, or (at
+ *                your option) any later version.
+ *
+ *                This program is distributed in the hope that it will
+ *                be useful, but WITHOUT ANY WARRANTY; without even the
+ *                implied warranty of MERCHANTABILITY or FITNESS FOR A
+ *                PARTICULAR PURPOSE.  See the GNU General Public
+ *                License for more details.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log$
+ *********************************************************************/
+
+package org.privoxy.activityconsole;
+
+/** 
+ * Provides a mapping between a column's key and its description.
+ * @author Last Modified By: $Author$
+ * @version $Rev$-$Date$$State$
+ */
+public class ColumnRef
+{
+  private static final String
+    COPYRIGHT = org.privoxy.activityconsole.Copyright.COPYRIGHT;
+
+  int _key = -1;
+  String _description = "";
+
+  public ColumnRef(String description, int key)
+  {
+    _description = description;
+    _key = key;
+  }
+
+  public String getDescription()
+  {
+    return _description;
+  }
+
+  public int getKey()
+  {
+    return _key;
+  }
+}
diff --git a/src/java/org/privoxy/activityconsole/Copyright.java b/src/java/org/privoxy/activityconsole/Copyright.java
new file mode 100644 (file)
index 0000000..8fd7935
--- /dev/null
@@ -0,0 +1,48 @@
+/*********************************************************************
+ *
+ * File        :  $Source$
+ *
+ * Purpose     :  Houses the static text of the copyright statement.
+ *
+ * Copyright   :  Written by and Copyright (C) 2003 the SourceForge
+ *                Privoxy team. http://www.privoxy.org/
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, or (at
+ *                your option) any later version.
+ *
+ *                This program is distributed in the hope that it will
+ *                be useful, but WITHOUT ANY WARRANTY; without even the
+ *                implied warranty of MERCHANTABILITY or FITNESS FOR A
+ *                PARTICULAR PURPOSE.  See the GNU General Public
+ *                License for more details.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log$
+ *********************************************************************/
+
+package org.privoxy.activityconsole;
+
+/** 
+ * Houses the static text of the copyright statement.
+ * @author Last Modified By: $Author$
+ * @version $Rev$-$Date$$State$
+ */
+public class Copyright
+{
+  public static final String COPYRIGHT =
+    "Written by and Copyright (C) 2003 the SourceForge"
+   +"Privoxy team. http://www.privoxy.org/";
+}
diff --git a/src/java/org/privoxy/activityconsole/ServerThread.java b/src/java/org/privoxy/activityconsole/ServerThread.java
new file mode 100644 (file)
index 0000000..2748e7b
--- /dev/null
@@ -0,0 +1,130 @@
+/*********************************************************************
+ *
+ * File        :  $Source$
+ *
+ * Purpose     :  Listen on a specified port for status updates from
+ *                Privoxy.  If we get a suitable update, pass it along
+ *                to the GUI for processing.  We need to handle getting
+ *                shut down and restarting on another port gracefully.
+ *
+ * Copyright   :  Written by and Copyright (C) 2003 the SourceForge
+ *                Privoxy team. http://www.privoxy.org/
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, or (at
+ *                your option) any later version.
+ *
+ *                This program is distributed in the hope that it will
+ *                be useful, but WITHOUT ANY WARRANTY; without even the
+ *                implied warranty of MERCHANTABILITY or FITNESS FOR A
+ *                PARTICULAR PURPOSE.  See the GNU General Public
+ *                License for more details.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log$
+ *********************************************************************/
+
+package org.privoxy.activityconsole;
+
+import java.net.*;
+import java.io.*;
+import java.text.*;
+import java.util.*;
+import javax.swing.*;
+
+/** 
+ * Listens on a specified port for status updates from Privoxy. 
+ * @author Last Modified By: $Author$
+ * @version $Rev$-$Date$$State$
+ */
+public class ServerThread extends Thread
+{
+  private static final String
+    COPYRIGHT = org.privoxy.activityconsole.Copyright.COPYRIGHT;
+
+  static ActivityConsoleGui _parent;
+  static int _port;
+  static ServerSocket _serverSocket;
+
+  public ServerThread(ActivityConsoleGui parent, int thePort)
+  {
+    _parent = parent;
+    _port = thePort;
+  }
+
+  public void run()
+  {
+    try
+    {
+      _serverSocket = new ServerSocket(_port);        
+      try
+      {
+        // System.out.println( "ServerThread serving port "+_port+"." );
+        boolean shouldRun = true;
+        while (shouldRun)
+        {
+          Socket theSocket = _serverSocket.accept();
+          if (!Thread.currentThread().interrupted())
+          {
+            BufferedReader in = 
+            new BufferedReader(new InputStreamReader(theSocket.getInputStream()));
+            String line = in.readLine();
+            /* Ensure the line isn't null and it's not way, way too long... */
+            if ((line != null) && (line.length() < 65536))
+            {
+              _parent.updateStats(line,theSocket.getInetAddress().getHostName());
+            }
+            in.close();
+            theSocket.close();
+          }
+          else
+          {
+            shouldRun = false;
+          }
+        }
+        _serverSocket.close();
+        _serverSocket = null;
+      }
+      catch (IOException io)
+      {
+        try
+        {
+          _serverSocket.close();
+          _serverSocket = null;
+        }
+        catch (IOException fred)
+        {
+          _serverSocket = null;
+        }
+      }
+    }
+    catch (IOException io)
+    {
+      System.err.println(io);
+      JOptionPane.showMessageDialog(null, io, "Alert: port "+_port, JOptionPane.ERROR_MESSAGE);
+    }
+  }
+
+  public void doClose()
+  {
+    try
+    {
+      _serverSocket.close();
+    }
+    catch (IOException fred)
+    {
+    }
+  }
+}
diff --git a/src/java/org/privoxy/activityconsole/SortButtonRenderer.java b/src/java/org/privoxy/activityconsole/SortButtonRenderer.java
new file mode 100644 (file)
index 0000000..8c75977
--- /dev/null
@@ -0,0 +1,158 @@
+/*********************************************************************
+ *
+ * File        :  $Source$
+ *
+ * Purpose     :  Swing details of rendering a column header as a button.
+ *
+ * Copyright   :  Written by and Copyright (C) 2003 the SourceForge
+ *                Privoxy team. http://www.privoxy.org/
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, or (at
+ *                your option) any later version.
+ *
+ *                This program is distributed in the hope that it will
+ *                be useful, but WITHOUT ANY WARRANTY; without even the
+ *                implied warranty of MERCHANTABILITY or FITNESS FOR A
+ *                PARTICULAR PURPOSE.  See the GNU General Public
+ *                License for more details.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log$
+ *********************************************************************/
+
+package org.privoxy.activityconsole;
+
+import java.util.*;
+import java.awt.*;
+import javax.swing.*;
+import javax.swing.table.*;
+
+/** 
+ * Swing details of rendering a column header as a button.
+ * @author Last Modified By: $Author$
+ * @version $Rev$-$Date$$State$
+ */
+public class SortButtonRenderer extends JButton implements TableCellRenderer
+{
+
+  private static final String
+  COPYRIGHT = org.privoxy.activityconsole.Copyright.COPYRIGHT;
+
+  public static final int NONE = 0;
+  public static final int DOWN = 1;
+  public static final int UP   = 2;
+
+  int pushedColumn;
+  Hashtable state;
+  JButton downButton,upButton;
+
+  public SortButtonRenderer()
+  {
+    pushedColumn   = -1;
+    state = new Hashtable();
+
+    setMargin(new Insets(0,0,0,0));
+    setHorizontalTextPosition(LEFT);
+    setIcon(new BlankIcon());
+
+    downButton = new JButton();
+    downButton.setMargin(new Insets(0,0,0,0));
+    downButton.setHorizontalTextPosition(LEFT);
+    downButton.setIcon(new BevelArrowIcon(BevelArrowIcon.DOWN, false, false));
+    downButton.setPressedIcon(new BevelArrowIcon(BevelArrowIcon.DOWN, false, true));
+
+    upButton = new JButton();
+    upButton.setMargin(new Insets(0,0,0,0));
+    upButton.setHorizontalTextPosition(LEFT);
+    upButton.setIcon(new BevelArrowIcon(BevelArrowIcon.UP, false, false));
+    upButton.setPressedIcon(new BevelArrowIcon(BevelArrowIcon.UP, false, true));
+
+  }
+
+  public Component getTableCellRendererComponent(JTable table, Object value,
+                                                 boolean isSelected, boolean hasFocus, int row, int column)
+  {
+    JButton button = this;
+    Object obj = state.get(new Integer(column));
+    if (obj != null)
+    {
+      if (((Integer)obj).intValue() == DOWN)
+      {
+        button = downButton;
+      }
+      else
+      {
+        button = upButton;
+      }
+    }
+    button.setText((value ==null) ? "" : value.toString());
+    boolean isPressed = (column == pushedColumn);
+    button.getModel().setPressed(isPressed);
+    button.getModel().setArmed(isPressed);
+    return button;
+  }
+
+  public void setPressedColumn(int col)
+  {
+    pushedColumn = col;
+  }
+
+  public void setSelectedColumn(int col)
+  {
+    if (col < 0) return;
+    Integer value = null;
+    Object obj = state.get(new Integer(col));
+    if (obj == null)
+    {
+      value = new Integer(DOWN);
+    }
+    else
+    {
+      if (((Integer)obj).intValue() == DOWN)
+      {
+        value = new Integer(UP);
+      }
+      else
+      {
+        value = new Integer(DOWN);
+      }
+    }
+    state.clear();
+    state.put(new Integer(col), value);
+  } 
+
+  public int getState(int col)
+  {
+    int retValue;
+    Object obj = state.get(new Integer(col));
+    if (obj == null)
+    {
+      retValue = NONE;
+    }
+    else
+    {
+      if (((Integer)obj).intValue() == DOWN)
+      {
+        retValue = DOWN;
+      }
+      else
+      {
+        retValue = UP;
+      }
+    }
+    return retValue;
+  }
+}
diff --git a/src/java/org/privoxy/activityconsole/SortableTableModel.java b/src/java/org/privoxy/activityconsole/SortableTableModel.java
new file mode 100644 (file)
index 0000000..87a14ec
--- /dev/null
@@ -0,0 +1,112 @@
+/*********************************************************************
+ *
+ * File        :  $Source$
+ *
+ * Purpose     :  Sorting JTable model.
+ *
+ * Copyright   :  Written by and Copyright (C) 2003 the SourceForge
+ *                Privoxy team. http://www.privoxy.org/
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, or (at
+ *                your option) any later version.
+ *
+ *                This program is distributed in the hope that it will
+ *                be useful, but WITHOUT ANY WARRANTY; without even the
+ *                implied warranty of MERCHANTABILITY or FITNESS FOR A
+ *                PARTICULAR PURPOSE.  See the GNU General Public
+ *                License for more details.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log$
+ *********************************************************************/
+
+package org.privoxy.activityconsole;
+
+import java.util.*;
+import java.awt.*;
+import javax.swing.*;
+import javax.swing.table.*;
+
+/** 
+ * Sorting JTable table model.
+ * @author Last Modified By: $Author$
+ * @version $Rev$-$Date$$State$
+ */
+public class SortableTableModel extends DefaultTableModel
+{
+
+  private static final String
+  COPYRIGHT = org.privoxy.activityconsole.Copyright.COPYRIGHT;
+
+  int[] indexes;
+  TableSorter sorter;
+
+  public SortableTableModel()
+  {
+  }
+
+  public SortableTableModel(Vector data, Vector columnNames)
+  {
+    super(data, columnNames);
+  }
+  public Object getValueAt(int row, int col)
+  {
+    int rowIndex = row;
+    if (indexes != null)
+    {
+      rowIndex = indexes[row];
+    }
+    return super.getValueAt(rowIndex, col);
+  }
+
+  public void setValueAt(Object value, int row, int col)
+  {
+    int rowIndex = row;
+    if (indexes != null)
+    {
+      rowIndex = indexes[row];
+    }
+    super.setValueAt(value, rowIndex, col);
+  }
+
+  public void sortByColumn(int column, boolean isAscent)
+  {
+    if (sorter == null)
+    {
+      sorter = new TableSorter(this);
+    }
+    sorter.sort(column, isAscent);   
+    fireTableDataChanged();
+  }
+
+  public int[] getIndexes()
+  {
+    int n = getRowCount();
+    if (indexes != null)
+    {
+      if (indexes.length == n)
+      {
+        return indexes;
+      }
+    }
+    indexes = new int[n];
+    for (int i=0; i<n; i++)
+    {
+      indexes[i] = i;
+    }
+    return indexes;
+  }
+}
diff --git a/src/java/org/privoxy/activityconsole/Stat.java b/src/java/org/privoxy/activityconsole/Stat.java
new file mode 100644 (file)
index 0000000..1a7e282
--- /dev/null
@@ -0,0 +1,66 @@
+/*********************************************************************
+ *
+ * File        :  $Source$
+ *
+ * Purpose     :  A structification of a statistic element: a key
+ *                associated with a value.
+ *
+ * Copyright   :  Written by and Copyright (C) 2003 the SourceForge
+ *                Privoxy team. http://www.privoxy.org/
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, or (at
+ *                your option) any later version.
+ *
+ *                This program is distributed in the hope that it will
+ *                be useful, but WITHOUT ANY WARRANTY; without even the
+ *                implied warranty of MERCHANTABILITY or FITNESS FOR A
+ *                PARTICULAR PURPOSE.  See the GNU General Public
+ *                License for more details.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log$
+ *********************************************************************/
+
+package org.privoxy.activityconsole;
+
+/** 
+ * A structification of a statistic element: a key associated with a value.
+ * @author Last Modified By: $Author$
+ * @version $Rev$-$Date$$State$
+ */
+public class Stat
+{
+  private static final String
+    COPYRIGHT = org.privoxy.activityconsole.Copyright.COPYRIGHT;
+
+  int _key = -1, _value = 0;
+
+  public Stat(int key, int value)
+  {
+    _key = key;
+    _value = value;
+  }
+
+  public int getKey()
+  {
+    return _key;
+  }
+
+  public int getValue()
+  {
+    return _value;
+  }
+}
diff --git a/src/java/org/privoxy/activityconsole/StatWidget.java b/src/java/org/privoxy/activityconsole/StatWidget.java
new file mode 100644 (file)
index 0000000..30e4329
--- /dev/null
@@ -0,0 +1,143 @@
+/*********************************************************************
+ *
+ * File        :  $Source$
+ *
+ * Purpose     :  A graphical element (specifically, a JPanel) that 
+ *                displays a little box of color and a number.  When
+ *                tweaked with a new number, the color changes for a
+ *                set period of time, then resets to the previous 
+ *                color.
+ *
+ * Copyright   :  Written by and Copyright (C) 2003 the SourceForge
+ *                Privoxy team. http://www.privoxy.org/
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, or (at
+ *                your option) any later version.
+ *
+ *                This program is distributed in the hope that it will
+ *                be useful, but WITHOUT ANY WARRANTY; without even the
+ *                implied warranty of MERCHANTABILITY or FITNESS FOR A
+ *                PARTICULAR PURPOSE.  See the GNU General Public
+ *                License for more details.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log$
+ *********************************************************************/
+
+package org.privoxy.activityconsole;
+
+import java.awt.*;
+import javax.swing.*;
+import javax.swing.table.*;
+
+/** 
+ * A graphical element that displays a little box of color and a number.
+ * @author Last Modified By: $Author$
+ * @version $Rev$-$Date$$State$
+ */
+public class StatWidget extends JPanel implements Comparable
+{
+  private static final String
+    COPYRIGHT = org.privoxy.activityconsole.Copyright.COPYRIGHT;
+
+  private JPanel _statusIcon;
+  private JLabel _valueLabel;
+  private int _status;
+  private int _value;
+  private int _row, _col;
+  private JTable _table = null;
+  private StatWidgetThread _thread;
+  Color activityColor = Color.yellow;
+  Color inactivityColor = getBackground().darker();
+
+  public StatWidget(int initialValue, int statusDurationMillis)
+  {
+    _value = initialValue;
+    _statusIcon = new JPanel();
+    _statusIcon.setBackground(inactivityColor);
+    _valueLabel = new JLabel(new Integer(initialValue).toString());
+    this.setLayout(new GridBagLayout());
+    ActivityConsoleGuiUtil.constrain(this, _statusIcon,
+                              1, 1, // X, Y Coordinates
+                              1, 1, // Grid width, height
+                              GridBagConstraints.NONE,  // Fill value
+                              GridBagConstraints.WEST,  // Anchor value
+                              0.0,0.0,  // Weight X, Y
+                              0, 1, 0, 1 ); // Top, left, bottom, right insets
+    ActivityConsoleGuiUtil.constrain(this, _valueLabel,
+                              2, 1, // X, Y Coordinates
+                              1, 1, // Grid width, height
+                              GridBagConstraints.HORIZONTAL,  // Fill value
+                              GridBagConstraints.WEST,  // Anchor value
+                              1.0,0.0,  // Weight X, Y
+                              0, 1, 0, 1 ); // Top, left, bottom, right insets
+    _thread = new StatWidgetThread(this, statusDurationMillis);
+    _thread.start();
+  }
+
+  public void updateValue(int newValue)
+  {
+    if (_value != newValue)
+    {
+      _value = newValue;
+      _valueLabel.setText(new Integer(newValue).toString());
+      _statusIcon.setBackground(activityColor);
+      if (_table != null)
+        ((AbstractTableModel)_table.getModel()).fireTableCellUpdated(_row,_table.convertColumnIndexToModel(_col));
+      _thread.interrupt();
+    }
+  }
+
+  public void setRowColTable(int row, int col, JTable table)
+  {
+    _row = row;
+    _col = col;
+    _table = table;
+  }
+
+  public int getRow()
+  {
+    return _row;
+  }
+
+  public int getCol()
+  {
+    return _col;
+  }
+
+  public int getValue()
+  {
+    return _value;
+  }
+
+  public void timerPop()
+  {
+    _statusIcon.setBackground(inactivityColor);
+    if (_table != null)
+      ((AbstractTableModel)_table.getModel()).fireTableCellUpdated(_row,_table.convertColumnIndexToModel(_col));
+  }
+
+  public int compareTo(Object compare)
+  {
+    int compareValue = ((StatWidget)compare).getValue();
+    if (_value < compareValue)
+      return 1;
+    else if (_value == compareValue)
+      return 0;
+    else
+      return -1;
+  }
+}
diff --git a/src/java/org/privoxy/activityconsole/StatWidgetThread.java b/src/java/org/privoxy/activityconsole/StatWidgetThread.java
new file mode 100644 (file)
index 0000000..2584935
--- /dev/null
@@ -0,0 +1,107 @@
+/*********************************************************************
+ *
+ * File        :  $Source$
+ *
+ * Purpose     :  Part of the StatWidget, the thread that manages the
+ *                timing of the swatch of color.
+ *
+ * Copyright   :  Written by and Copyright (C) 2003 the SourceForge
+ *                Privoxy team. http://www.privoxy.org/
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, or (at
+ *                your option) any later version.
+ *
+ *                This program is distributed in the hope that it will
+ *                be useful, but WITHOUT ANY WARRANTY; without even the
+ *                implied warranty of MERCHANTABILITY or FITNESS FOR A
+ *                PARTICULAR PURPOSE.  See the GNU General Public
+ *                License for more details.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log$
+ *********************************************************************/
+
+package org.privoxy.activityconsole;
+
+import  java.io.*;
+import  java.util.*;
+
+/** 
+ * The thread that manages the timing of the swatch of color of the StatWidget.
+ * @author Last Modified By: $Author$
+ * @version $Rev$-$Date$$State$
+ */
+public class StatWidgetThread extends Thread
+{
+  private static final String
+    COPYRIGHT = org.privoxy.activityconsole.Copyright.COPYRIGHT;
+
+  int _statusDurationMillis = 0;
+  Date _nextUpdate = null;
+  StatWidget _parent = null;
+
+  public StatWidgetThread(StatWidget parent, int statusDurationMillis)
+  {
+    _parent = parent;
+    _statusDurationMillis = statusDurationMillis;
+  }
+
+  public final void run()
+  {
+    boolean snooze = false;
+    int sleepFor;
+
+    while (1==1)
+    {
+      /* Check once before we wait at all, just in case... */
+      if (_nextUpdate != null)
+        snooze = checkTimer();
+      if (snooze == true)
+        sleepFor = _statusDurationMillis;
+      else
+        sleepFor = 540000 + (int)(Math.random() * 60000); /* Sit around for 10 minutes plus or minus a minute */
+      try
+      {
+        sleep(sleepFor);
+        if (_nextUpdate != null)
+          snooze = checkTimer();
+      }
+      catch (Throwable t2)
+      {
+        pulse();
+        snooze = true;
+      }
+    }
+  }
+
+  public void pulse()
+  {
+    _nextUpdate = new Date(new Date().getTime() + _statusDurationMillis);
+  }
+
+  public boolean checkTimer()
+  {
+    boolean returnVal = true;
+    Date now = new Date();
+    if (now.after(_nextUpdate))
+    {
+      _parent.timerPop();
+      _nextUpdate = null;
+      returnVal = false;
+    }
+    return returnVal;
+  }
+}
diff --git a/src/java/org/privoxy/activityconsole/StringUtil.java b/src/java/org/privoxy/activityconsole/StringUtil.java
new file mode 100644 (file)
index 0000000..e453081
--- /dev/null
@@ -0,0 +1,106 @@
+/*********************************************************************
+ *
+ * File        :  $Source$
+ *
+ * Purpose     :  Utility string functions.
+ *
+ * Copyright   :  Written by and Copyright (C) 2003 the SourceForge
+ *                Privoxy team. http://www.privoxy.org/
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, or (at
+ *                your option) any later version.
+ *
+ *                This program is distributed in the hope that it will
+ *                be useful, but WITHOUT ANY WARRANTY; without even the
+ *                implied warranty of MERCHANTABILITY or FITNESS FOR A
+ *                PARTICULAR PURPOSE.  See the GNU General Public
+ *                License for more details.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log$
+ *********************************************************************/
+
+package org.privoxy.activityconsole;
+
+/** 
+ * Utility string functions.
+ * @author Last Modified By: $Author$
+ * @version $Rev$-$Date$$State$
+ */
+class StringUtil
+{
+  private static final String
+    COPYRIGHT = org.privoxy.activityconsole.Copyright.COPYRIGHT;
+
+  /****************************************************************************
+  * This method replaces the preValue with the postValue in the originalString.
+  *
+  * @param originalString the string to have replacements
+  * @param preValue The substring value that the string currently contains
+  * @param postValue The substring value to replace the preValue
+  * @param recursive true if replacements should occur recursively
+  *
+  * @return String representing the substituted value(s)
+  ****************************************************************************/
+  public static final String replaceSubstring( String originalString
+                                               , String preValue
+                                               , String postValue
+                                               , boolean recursive
+                                             )
+  {
+    String finalString = originalString;
+    int previousFind = originalString.length();
+
+    int index = originalString.lastIndexOf(preValue);
+    while (index > -1        &&
+           index < previousFind
+          )
+    {
+      previousFind = index;
+
+      finalString = originalString.substring(0,index)
+                    + postValue
+                    + finalString.substring(index+preValue.length());
+
+      index = finalString.lastIndexOf(preValue,previousFind);
+      if (!recursive)
+      {
+        if (index == previousFind)
+          previousFind--;
+        index = finalString.lastIndexOf(preValue,previousFind);
+      }
+    }
+
+    return finalString;
+  }
+
+  /****************************************************************************
+  * This method replaces the preValue with the postValue in the originalString.
+  *
+  * @param originalString the string to have replacements
+  * @param preValue The substring value that the string currently contains
+  * @param postValue The substring value to replace the preValue
+  *
+  * @return String representing the substituted value(s)
+  ****************************************************************************/
+  public static final String replaceSubstring( String originalString
+                                               , String preValue
+                                               , String postValue
+                                             )
+  {
+    return(replaceSubstring(originalString, preValue, postValue, false));
+  }
+}
diff --git a/src/java/org/privoxy/activityconsole/TableSorter.java b/src/java/org/privoxy/activityconsole/TableSorter.java
new file mode 100644 (file)
index 0000000..8b61f3c
--- /dev/null
@@ -0,0 +1,195 @@
+/*********************************************************************
+ *
+ * File        :  $Source$
+ *
+ * Purpose     :  Sorts JTable rows.
+ *
+ * Copyright   :  Written by and Copyright (C) 2003 the SourceForge
+ *                Privoxy team. http://www.privoxy.org/
+ *
+ *                Based on the Internet Junkbuster originally written
+ *                by and Copyright (C) 1997 Anonymous Coders and
+ *                Junkbusters Corporation.  http://www.junkbusters.com
+ *
+ *                This program is free software; you can redistribute it
+ *                and/or modify it under the terms of the GNU General
+ *                Public License as published by the Free Software
+ *                Foundation; either version 2 of the License, or (at
+ *                your option) any later version.
+ *
+ *                This program is distributed in the hope that it will
+ *                be useful, but WITHOUT ANY WARRANTY; without even the
+ *                implied warranty of MERCHANTABILITY or FITNESS FOR A
+ *                PARTICULAR PURPOSE.  See the GNU General Public
+ *                License for more details.
+ *
+ *                The GNU General Public License should be included with
+ *                this file.  If not, you can view it at
+ *                http://www.gnu.org/copyleft/gpl.html
+ *                or write to the Free Software Foundation, Inc., 59
+ *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Revisions   :
+ *    $Log$
+ *********************************************************************/
+
+package org.privoxy.activityconsole;
+
+import java.awt.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.table.*;
+
+
+/** 
+ * Sorts JTable rows.
+ * @author Last Modified By: $Author$
+ * @version $Rev$-$Date$$State$
+ */
+public class TableSorter
+{
+  private static final String
+  COPYRIGHT = org.privoxy.activityconsole.Copyright.COPYRIGHT;
+
+  SortableTableModel model;
+
+  public TableSorter(SortableTableModel model)
+  {
+    this.model = model;
+  }
+
+
+  //n2 selection
+  public void sort(int column, boolean isAscent)
+  {
+    int n = model.getRowCount();
+    int[] indexes = model.getIndexes();   
+
+    for (int i=0; i<n-1; i++)
+    {
+      int k = i;
+      for (int j=i+1; j<n; j++)
+      {
+        if (isAscent)
+        {
+          if (compare(column, j, k) < 0)
+          {
+            k = j;
+          }
+        }
+        else
+        {
+          if (compare(column, j, k) > 0)
+          {
+            k = j;
+          }
+        }
+      }
+      int tmp = indexes[i];
+      indexes[i] = indexes[k];
+      indexes[k] = tmp;
+    }
+  }
+
+
+  // comparators
+  public int compare(int column, int row1, int row2)
+  {
+    Object o1 = model.getValueAt(row1, column);
+    Object o2 = model.getValueAt(row2, column); 
+    if (o1 == null && o2 == null)
+    {
+      return  0; 
+    }
+    else if (o1 == null)
+    {
+      return -1; 
+    }
+    else if (o2 == null)
+    {
+      return  1; 
+    }
+    else
+    {
+      Class type = model.getColumnClass(column);
+      if (type.getSuperclass() == Number.class)
+      {
+        return compare((Number)o1, (Number)o2);
+      }
+      else if (type == String.class)
+      {
+        return((String)o1).compareTo((String)o2);
+      }
+      else if (type == Date.class)
+      {
+        return compare((Date)o1, (Date)o2);
+      }
+      else if (type == Boolean.class)
+      {
+        return compare((Boolean)o1, (Boolean)o2);
+      }
+      else if (o1 instanceof StatWidget)
+      {
+        return((StatWidget)o1).compareTo((StatWidget)o2);
+      }
+      else
+      {
+        return((String)o1).compareTo((String)o2);
+      }      
+    }
+  }
+
+  public int compare(Number o1, Number o2)
+  {
+    double n1 = o1.doubleValue();
+    double n2 = o2.doubleValue();
+    if (n1 < n2)
+    {
+      return -1;
+    }
+    else if (n1 > n2)
+    {
+      return 1;
+    }
+    else
+    {
+      return 0;
+    }
+  }
+
+  public int compare(Date o1, Date o2)
+  {
+    long n1 = o1.getTime();
+    long n2 = o2.getTime();
+    if (n1 < n2)
+    {
+      return -1;
+    }
+    else if (n1 > n2)
+    {
+      return 1;
+    }
+    else
+    {
+      return 0;
+    }
+  }
+
+  public int compare(Boolean o1, Boolean o2)
+  {
+    boolean b1 = o1.booleanValue();
+    boolean b2 = o2.booleanValue();
+    if (b1 == b2)
+    {
+      return 0;
+    }
+    else if (b1)
+    {
+      return 1;
+    }
+    else
+    {
+      return -1;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/java/org/privoxy/activityconsole/acon.bat b/src/java/org/privoxy/activityconsole/acon.bat
new file mode 100755 (executable)
index 0000000..69b18c7
--- /dev/null
@@ -0,0 +1,40 @@
+@REM /*********************************************************************  
+@REM  *                                                                      
+@REM  * File        :  $Source$                                              
+@REM  *                                                                      
+@REM  * Purpose     :  Start the Privoxy statistics viewer on Win32 platforms
+@REM  *                                                                      
+@REM  * Copyright   :  Written by and Copyright (C) 2003 the SourceForge     
+@REM  *                Privoxy team. http://www.privoxy.org/                 
+@REM  *                                                                      
+@REM  *                Based on the Internet Junkbuster originally written   
+@REM  *                by and Copyright (C) 1997 Anonymous Coders and        
+@REM  *                Junkbusters Corporation.  http://www.junkbusters.com  
+@REM  *                                                                      
+@REM  *                This program is free software; you can redistribute it
+@REM  *                and/or modify it under the terms of the GNU General   
+@REM  *                Public License as published by the Free Software      
+@REM  *                Foundation; either version 2 of the License, or (at   
+@REM  *                your option) any later version.                       
+@REM  *                                                                      
+@REM  *                This program is distributed in the hope that it will  
+@REM  *                be useful, but WITHOUT ANY WARRANTY; without even the 
+@REM  *                implied warranty of MERCHANTABILITY or FITNESS FOR A  
+@REM  *                PARTICULAR PURPOSE.  See the GNU General Public       
+@REM  *                License for more details.                             
+@REM  *                                                                      
+@REM  *                The GNU General Public License should be included with
+@REM  *                this file.  If not, you can view it at                
+@REM  *                http://www.gnu.org/copyleft/gpl.html                  
+@REM  *                or write to the Free Software Foundation, Inc., 59    
+@REM  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+@REM  *                                                                      
+@REM  *********************************************************************/ 
+@REM
+@REM Syntax:
+@REM
+@REM acon [port_to_serve]
+@REM
+@REM - Requires Java 1.2+
+@REM
+@start /B java -classpath "%CLASSPATH%";ActivityConsole.jar org.privoxy.activityconsole.ActivityConsole %1
diff --git a/src/java/org/privoxy/activityconsole/acon.cmd b/src/java/org/privoxy/activityconsole/acon.cmd
new file mode 100755 (executable)
index 0000000..9e2cdf5
--- /dev/null
@@ -0,0 +1,40 @@
+@REM /*********************************************************************  
+@REM  *                                                                      
+@REM  * File        :  $Source$                                              
+@REM  *                                                                      
+@REM  * Purpose     :  Start the Privoxy statistics viewer on OS/2 platforms
+@REM  *                                                                      
+@REM  * Copyright   :  Written by and Copyright (C) 2003 the SourceForge     
+@REM  *                Privoxy team. http://www.privoxy.org/                 
+@REM  *                                                                      
+@REM  *                Based on the Internet Junkbuster originally written   
+@REM  *                by and Copyright (C) 1997 Anonymous Coders and        
+@REM  *                Junkbusters Corporation.  http://www.junkbusters.com  
+@REM  *                                                                      
+@REM  *                This program is free software; you can redistribute it
+@REM  *                and/or modify it under the terms of the GNU General   
+@REM  *                Public License as published by the Free Software      
+@REM  *                Foundation; either version 2 of the License, or (at   
+@REM  *                your option) any later version.                       
+@REM  *                                                                      
+@REM  *                This program is distributed in the hope that it will  
+@REM  *                be useful, but WITHOUT ANY WARRANTY; without even the 
+@REM  *                implied warranty of MERCHANTABILITY or FITNESS FOR A  
+@REM  *                PARTICULAR PURPOSE.  See the GNU General Public       
+@REM  *                License for more details.                             
+@REM  *                                                                      
+@REM  *                The GNU General Public License should be included with
+@REM  *                this file.  If not, you can view it at                
+@REM  *                http://www.gnu.org/copyleft/gpl.html                  
+@REM  *                or write to the Free Software Foundation, Inc., 59    
+@REM  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+@REM  *                                                                      
+@REM  *********************************************************************/ 
+@REM
+@REM Syntax:
+@REM
+@REM acon [port_to_serve]
+@REM
+@REM - Requires Swing (i.e. swingall.jar) in CLASSPATH or Java 1.3+
+@REM
+@start /MIN /C java -classpath %CLASSPATH%;ActivityConsole.jar org.privoxy.activityconsole.ActivityConsole %1
diff --git a/src/java/org/privoxy/activityconsole/acon.manifest b/src/java/org/privoxy/activityconsole/acon.manifest
new file mode 100644 (file)
index 0000000..a742cc4
--- /dev/null
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Created-By: 1.3.1 (IBM Corporation)
+Main-Class: org.privoxy.activityconsole.ActivityConsole
diff --git a/src/java/org/privoxy/activityconsole/acon.sh b/src/java/org/privoxy/activityconsole/acon.sh
new file mode 100644 (file)
index 0000000..9bba555
--- /dev/null
@@ -0,0 +1,40 @@
+# /*********************************************************************  
+#  *                                                                      
+#  * File        :  $Source$                                              
+#  *                                                                      
+#  * Purpose     :  Start the Privoxy statistics viewer on *NIX platforms
+#  *                                                                      
+#  * Copyright   :  Written by and Copyright (C) 2003 the SourceForge     
+#  *                Privoxy team. http://www.privoxy.org/                 
+#  *                                                                      
+#  *                Based on the Internet Junkbuster originally written   
+#  *                by and Copyright (C) 1997 Anonymous Coders and        
+#  *                Junkbusters Corporation.  http://www.junkbusters.com  
+#  *                                                                      
+#  *                This program is free software; you can redistribute it
+#  *                and/or modify it under the terms of the GNU General   
+#  *                Public License as published by the Free Software      
+#  *                Foundation; either version 2 of the License, or (at   
+#  *                your option) any later version.                       
+#  *                                                                      
+#  *                This program is distributed in the hope that it will  
+#  *                be useful, but WITHOUT ANY WARRANTY; without even the 
+#  *                implied warranty of MERCHANTABILITY or FITNESS FOR A  
+#  *                PARTICULAR PURPOSE.  See the GNU General Public       
+#  *                License for more details.                             
+#  *                                                                      
+#  *                The GNU General Public License should be included with
+#  *                this file.  If not, you can view it at                
+#  *                http://www.gnu.org/copyleft/gpl.html                  
+#  *                or write to the Free Software Foundation, Inc., 59    
+#  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#  *                                                                      
+#  *********************************************************************/ 
+#
+# Syntax:
+#
+# ./acon.sh [port_to_serve]
+#
+# - Requires Swing (i.e. swingall.jar) in CLASSPATH or Java 1.2+
+#
+java -classpath $CLASSPATH:ActivityConsole.jar org.privoxy.activityconsole.ActivityConsole $1