[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[vidalia-svn] r3905: Beginning stages of Message log plugin. Does not compile yet (in vidalia/branches/extension-api/src/vidalia: . MessageLogPlugin NetworkMapPlugin log)



Author: tyree731
Date: 2009-06-28 17:54:14 -0400 (Sun, 28 Jun 2009)
New Revision: 3905

Added:
   vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogFile.cpp
   vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogFile.h
   vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogHeaderView.cpp
   vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogHeaderView.h
   vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogMessageColumnDelegate.cpp
   vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogMessageColumnDelegate.h
   vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogTreeItem.cpp
   vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogTreeItem.h
   vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogTreeWidget.cpp
   vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogTreeWidget.h
   vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/MessageLog.cpp
   vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/MessageLog.h
   vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/MessageLog.ui
Removed:
   vidalia/branches/extension-api/src/vidalia/log/LogFile.cpp
   vidalia/branches/extension-api/src/vidalia/log/LogFile.h
   vidalia/branches/extension-api/src/vidalia/log/LogHeaderView.cpp
   vidalia/branches/extension-api/src/vidalia/log/LogHeaderView.h
   vidalia/branches/extension-api/src/vidalia/log/LogMessageColumnDelegate.cpp
   vidalia/branches/extension-api/src/vidalia/log/LogMessageColumnDelegate.h
   vidalia/branches/extension-api/src/vidalia/log/LogTreeItem.cpp
   vidalia/branches/extension-api/src/vidalia/log/LogTreeItem.h
   vidalia/branches/extension-api/src/vidalia/log/LogTreeWidget.cpp
   vidalia/branches/extension-api/src/vidalia/log/LogTreeWidget.h
   vidalia/branches/extension-api/src/vidalia/log/MessageLog.cpp
   vidalia/branches/extension-api/src/vidalia/log/MessageLog.h
   vidalia/branches/extension-api/src/vidalia/log/MessageLog.ui
Modified:
   vidalia/branches/extension-api/src/vidalia/CMakeLists.txt
   vidalia/branches/extension-api/src/vidalia/MainWindow.cpp
   vidalia/branches/extension-api/src/vidalia/MainWindow.h
   vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/CMakeLists.txt
   vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/MessageLogPlugin.h
   vidalia/branches/extension-api/src/vidalia/NetworkMapPlugin/NetworkMapPlugin.h
Log:
Beginning stages of Message log plugin. Does not compile yet.


Modified: vidalia/branches/extension-api/src/vidalia/CMakeLists.txt
===================================================================
--- vidalia/branches/extension-api/src/vidalia/CMakeLists.txt	2009-06-28 15:53:49 UTC (rev 3904)
+++ vidalia/branches/extension-api/src/vidalia/CMakeLists.txt	2009-06-28 21:54:14 UTC (rev 3905)
@@ -161,22 +161,6 @@
   help/browser/HelpTextBrowser.h
 )
 
-## Message log sources
-set(vidalia_SRCS ${vidalia_SRCS}
-  log/LogFile.cpp
-  log/LogHeaderView.cpp
-  log/LogMessageColumnDelegate.cpp
-  log/LogTreeItem.cpp
-  log/LogTreeWidget.cpp
-  log/MessageLog.cpp
-)
-qt4_wrap_cpp(vidalia_SRCS
-  log/LogFile.h
-  log/LogHeaderView.h
-  log/LogTreeWidget.h
-  log/MessageLog.h
-)
-
 ## Choose the correct tray icon implementation for the current platform
 set(vidalia_SRCS ${vidalia_SRCS} tray/TrayIcon.cpp)
 qt4_wrap_cpp(vidalia_SRCS tray/TrayIcon.h)
@@ -229,7 +213,6 @@
   config/ServerPage.ui
   config/ServicePage.ui
   help/browser/HelpBrowser.ui
-  log/MessageLog.ui
 )
 
 if (USE_MINIUPNPC)

Modified: vidalia/branches/extension-api/src/vidalia/MainWindow.cpp
===================================================================
--- vidalia/branches/extension-api/src/vidalia/MainWindow.cpp	2009-06-28 15:53:49 UTC (rev 3904)
+++ vidalia/branches/extension-api/src/vidalia/MainWindow.cpp	2009-06-28 21:54:14 UTC (rev 3905)
@@ -112,18 +112,18 @@
   _pluginManager->loadPlugins("","");
 
   /* Create all the dialogs of which we only want one instance */
-  _messageLog     = new MessageLog();
   _bandwidthGraph = new BandwidthGraph();
   _configDialog   = new ConfigDialog();
   _menuBar        = 0;
+#if 0
   connect(_messageLog, SIGNAL(helpRequested(QString)),
           this, SLOT(showHelpDialog(QString)));
-#if 0
+
   connect(_netViewer, SIGNAL(helpRequested(QString)),
           this, SLOT(showHelpDialog(QString)));
+#endif
   connect(_configDialog, SIGNAL(helpRequested(QString)),
           this, SLOT(showHelpDialog(QString)));
-#endif
 
   /* Create the actions that will go in the tray menu */
   createActions();
@@ -220,7 +220,6 @@
 MainWindow::~MainWindow()
 {
   _trayIcon.hide();
-  delete _messageLog;
   delete _pluginManager;
   delete _bandwidthGraph;
   delete _configDialog;
@@ -248,8 +247,10 @@
   }
 
   _bandwidthAct->setText(tr("Bandwidth Graph"));
+#if 0
   _messageAct->setText(tr("Message Log"));
   _networkAct->setText(tr("Network Map"));
+#endif
   _controlPanelAct->setText(tr("Control Panel"));
   _helpAct->setText(tr("Help"));
   _newIdentityAct->setText(tr("New Identity"));
@@ -445,11 +446,11 @@
   connect(_bandwidthAct, SIGNAL(triggered()), 
           _bandwidthGraph, SLOT(showWindow()));
 
+#if 0
   _messageAct = new QAction(tr("Message Log"), this);
   connect(_messageAct, SIGNAL(triggered()),
           _messageLog, SLOT(showWindow()));
 
-#if 0
   _networkAct = new QAction(tr("Network Map"), this);
   connect(_networkAct, SIGNAL(triggered()), 
           _netViewer, SLOT(showWindow()));
@@ -478,8 +479,8 @@
   _startStopAct->setIcon(QIcon(IMG_START_TOR_16));
   _exitAct->setIcon(QIcon(IMG_EXIT));
   _bandwidthAct->setIcon(QIcon(IMG_BWGRAPH));
+#if 0
   _messageAct->setIcon(QIcon(IMG_MESSAGELOG));
-#if 0
   _networkAct->setIcon(QIcon(IMG_NETWORK));
 #endif
   _controlPanelAct->setIcon(QIcon(IMG_CONTROL_PANEL));
@@ -511,8 +512,8 @@
   menu->addAction(_startStopAct);
   menu->addSeparator();
   menu->addAction(_bandwidthAct);
+#if 0
   menu->addAction(_messageAct);
-#if 0
   menu->addAction(_networkAct);
 #endif
   menu->addAction(_newIdentityAct);
@@ -543,8 +544,8 @@
    * menubar and get the default shortcuts anyway. */
   _startStopAct->setShortcut(tr("Ctrl+T"));
   _bandwidthAct->setShortcut(tr("Ctrl+B"));
+#if 0
   _messageAct->setShortcut(tr("Ctrl+L"));
-#if 0
   _networkAct->setShortcut(tr("Ctrl+N"));
 #endif
   _helpAct->setShortcut(tr("Ctrl+?"));
@@ -578,8 +579,8 @@
   viewMenu->addAction(_controlPanelAct);
   viewMenu->addSeparator();
   viewMenu->addAction(_bandwidthAct);
+#if 0
   viewMenu->addAction(_messageAct);
-#if 0
   viewMenu->addAction(_networkAct);
 #endif  
 
@@ -1196,9 +1197,11 @@
                   VMessageBox::Ok|VMessageBox::Escape, 
                   VMessageBox::ShowLog|VMessageBox::Default,
                   VMessageBox::Help);
+#if 0
       if (ret == VMessageBox::ShowLog)
         _messageLog->showWindow();  
-      else if (ret == VMessageBox::Help)
+#endif
+      if (ret == VMessageBox::Help)
         showHelpDialog("troubleshooting.torexited");
     }
   }

Modified: vidalia/branches/extension-api/src/vidalia/MainWindow.h
===================================================================
--- vidalia/branches/extension-api/src/vidalia/MainWindow.h	2009-06-28 15:53:49 UTC (rev 3904)
+++ vidalia/branches/extension-api/src/vidalia/MainWindow.h	2009-06-28 21:54:14 UTC (rev 3905)
@@ -24,7 +24,6 @@
 #include "HelperProcess.h"
 #include "TrayIcon.h"
 #include "AboutDialog.h"
-#include "MessageLog.h"
 #include "BandwidthGraph.h"
 #include "ConfigDialog.h"
 #include "HelpBrowser.h"
@@ -231,8 +230,6 @@
   bool _delayedShutdownStarted;
   /** Set to true if Vidalia started its own Tor process. */
   bool _isVidaliaRunningTor;
-  /** A MessageLog object which handles logging Tor messages */
-  MessageLog* _messageLog;
   /** A BandwidthGraph object which handles monitoring Tor bandwidth usage */
   BandwidthGraph* _bandwidthGraph;
   /** A ConfigDialog object which lets the user configure Tor and Vidalia */
@@ -277,9 +274,13 @@
   QAction* _aboutAct;
   QAction* _exitAct;
   QAction* _bandwidthAct;
+#if 0
   QAction* _messageAct;
+#endif
   QAction* _helpAct;
+#if 0
   QAction* _networkAct;
+#endif
   QAction* _newIdentityAct;
 
   Ui::MainWindow ui; /**< Qt Designer generated object. */

Modified: vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/CMakeLists.txt
===================================================================
--- vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/CMakeLists.txt	2009-06-28 15:53:49 UTC (rev 3904)
+++ vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/CMakeLists.txt	2009-06-28 21:54:14 UTC (rev 3905)
@@ -10,13 +10,31 @@
 ##  the terms described in the LICENSE file.
 ##
 
+include_directories(
+  ${CMAKE_CURRENT_BINARY_DIR}
+  ${CMAKE_CURRENT_SOURCE_DIR}  
+)
 
 set(messagelogplugin_SRCS 
   MessageLogPlugin.cpp
+  LogFile.cpp
+  LogHeaderView.cpp
+  LogMessageColumnDelegate.cpp
+  LogTreeItem.cpp
+  LogTreeWidget.cpp
+  MessageLog.cpp
 )
 qt4_wrap_cpp(messagelogplugin_SRCS
   MessageLogPlugin.h
+  LogFile.h
+  LogHeaderView.h
+  LogTreeWidget.h
+  MessageLog.h
 )
 
+qt4_wrap_ui(messagelogplugin_SRCS
+  MessageLog.ui
+)
+
 add_library(messagelogplugin STATIC  ${messagelogplugin_SRCS})
 target_link_libraries(messagelogplugin ${QT_LIBRARIES})

Copied: vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogFile.cpp (from rev 3904, vidalia/branches/extension-api/src/vidalia/log/LogFile.cpp)
===================================================================
--- vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogFile.cpp	                        (rev 0)
+++ vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogFile.cpp	2009-06-28 21:54:14 UTC (rev 3905)
@@ -0,0 +1,117 @@
+/*
+**  This file is part of Vidalia, and is subject to the license terms in the
+**  LICENSE file, found in the top level directory of this distribution. If you
+**  did not receive the LICENSE file with this file, you may obtain it from the
+**  Vidalia source package distributed by the Vidalia Project at
+**  http://www.vidalia-project.net/. No part of Vidalia, including this file,
+**  may be copied, modified, propagated, or distributed except according to the
+**  terms described in the LICENSE file.
+*/
+
+/*
+** \file LogFile.cpp
+** \version $Id$
+** \brief Logs messages from Tor to a file
+*/
+
+#include "LogFile.h"
+
+#include "stringutil.h"
+
+#include <QDir>
+
+
+/** Default constructor. */
+LogFile::LogFile()
+{
+  _file = 0;
+}
+
+/** Destructor. */
+LogFile::~LogFile()
+{
+  if (_file) {
+    delete _file;
+  }
+}
+
+/** Creates a path to the given log file. */
+bool
+LogFile::createPathToFile(QString filename)
+{
+  QDir dir = QFileInfo(filename).absoluteDir();
+  if (!dir.exists()) {
+    return dir.mkpath(dir.absolutePath());
+  }
+  return true;
+}
+
+/** Opens a log file for writing. */
+bool
+LogFile::open(QString filename, QString *errmsg)
+{
+  QFile *newLogFile;
+ 
+  /* If the file is already open, then no need to open it again */
+  if (_file && _file->isOpen()) {
+    if (_file->fileName() == filename) {
+      return true;
+    }
+  }
+
+  /* Create the path to the log file, if necessary */
+  if (!createPathToFile(filename)) {
+    return err(errmsg, "Unable to create path to log file.");
+  }
+ 
+  /* Try to open the new log file */
+  newLogFile = new QFile(filename);
+  if (!newLogFile->open(QFile::WriteOnly|QIODevice::Append|QIODevice::Text)) {
+    delete newLogFile;
+    return err(errmsg, newLogFile->errorString());
+  }
+ 
+  /* Rotate the new log file in place of the old one */
+  if (_file) {
+    delete _file;
+  }
+  _file = newLogFile;
+  _stream.setDevice(_file);
+  return true;
+}
+
+/** Closes an open log file. */
+void
+LogFile::close()
+{
+  if (_file) {
+    delete _file;
+    _file = 0;
+  }
+}
+
+/** Returns true if the logfile is currently open. */
+bool
+LogFile::isOpen()
+{
+  return (_file && _file->isOpen());
+}
+
+/** Returns the filename of the current log file. */
+QString
+LogFile::filename()
+{
+  return (_file ? _file->fileName() : QString());;
+}
+
+/** Overloaded ostream operator. */
+LogFile&
+LogFile::operator<<(const QString &s)
+{
+  if (_file) {
+    _stream << s;
+    _stream.flush();
+  }
+  return *this;
+}
+

Copied: vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogFile.h (from rev 3904, vidalia/branches/extension-api/src/vidalia/log/LogFile.h)
===================================================================
--- vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogFile.h	                        (rev 0)
+++ vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogFile.h	2009-06-28 21:54:14 UTC (rev 3905)
@@ -0,0 +1,58 @@
+/*
+**  This file is part of Vidalia, and is subject to the license terms in the
+**  LICENSE file, found in the top level directory of this distribution. If you
+**  did not receive the LICENSE file with this file, you may obtain it from the
+**  Vidalia source package distributed by the Vidalia Project at
+**  http://www.vidalia-project.net/. No part of Vidalia, including this file,
+**  may be copied, modified, propagated, or distributed except according to the
+**  terms described in the LICENSE file.
+*/
+
+/*
+** \file LogFile.h
+** \version $Id$ 
+** \brief Logs messages from Tor to a file
+*/
+
+#ifndef _LOGFILE_H
+#define _LOGFILE_H
+
+#include <QFile>
+#include <QObject>
+#include <QString>
+#include <QTextStream>
+
+
+class LogFile : QObject
+{
+  Q_OBJECT
+
+public:
+  /** Default constructor. */
+  LogFile();
+  /** Destructor. */
+  ~LogFile();
+
+  /** Opens a log file for writing. */
+  bool open(QString filename, QString *errmsg = 0);
+  /** Closes an open log file. */
+  void close();
+  
+  /** Returns true if the logfile is currently open. */
+  bool isOpen();
+  /** Returns the filename of the current log file. */
+  QString filename();
+
+  /** Overloaded ostream operator. */
+  LogFile& operator<<(const QString &s);
+  
+private:
+  /** Creates a path to the given log file */
+  bool createPathToFile(QString filename);
+
+  QFile* _file;        /**< The log file. */
+  QTextStream _stream; /**< Stream used to write to the log file. */
+};
+
+#endif
+

Copied: vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogHeaderView.cpp (from rev 3904, vidalia/branches/extension-api/src/vidalia/log/LogHeaderView.cpp)
===================================================================
--- vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogHeaderView.cpp	                        (rev 0)
+++ vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogHeaderView.cpp	2009-06-28 21:54:14 UTC (rev 3905)
@@ -0,0 +1,45 @@
+/*
+**  This file is part of Vidalia, and is subject to the license terms in the
+**  LICENSE file, found in the top level directory of this distribution. If you
+**  did not receive the LICENSE file with this file, you may obtain it from the
+**  Vidalia source package distributed by the Vidalia Project at
+**  http://www.vidalia-project.net/. No part of Vidalia, including this file,
+**  may be copied, modified, propagated, or distributed except according to the
+**  terms described in the LICENSE file.
+*/
+
+/*
+** \file LogHeaderView.cpp
+** \version $Id$
+** \brief Header for the message log QTreeView
+*/
+
+#include "LogHeaderView.h"
+#include "LogTreeWidget.h"
+
+/* Column indices */
+#define COL_TIME  LogTreeWidget::TimeColumn
+#define COL_TYPE  LogTreeWidget::TypeColumn
+#define COL_MESG  LogTreeWidget::MessageColumn
+
+/* Default column widths */
+#define COL_TIME_WIDTH    135
+#define COL_TYPE_WIDTH    70
+
+
+/** Default constructor. */
+LogHeaderView::LogHeaderView(QWidget *parent)
+  : QHeaderView(Qt::Horizontal, parent)
+{
+}
+
+/** Resets all column widths back to their defaults. */
+void
+LogHeaderView::resetColumnWidths()
+{
+  resizeSection(COL_TIME, COL_TIME_WIDTH);
+  resizeSection(COL_TYPE, COL_TYPE_WIDTH);
+  setStretchLastSection(true);
+}
+
+

Copied: vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogHeaderView.h (from rev 3904, vidalia/branches/extension-api/src/vidalia/log/LogHeaderView.h)
===================================================================
--- vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogHeaderView.h	                        (rev 0)
+++ vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogHeaderView.h	2009-06-28 21:54:14 UTC (rev 3905)
@@ -0,0 +1,36 @@
+/*
+**  This file is part of Vidalia, and is subject to the license terms in the
+**  LICENSE file, found in the top level directory of this distribution. If you
+**  did not receive the LICENSE file with this file, you may obtain it from the
+**  Vidalia source package distributed by the Vidalia Project at
+**  http://www.vidalia-project.net/. No part of Vidalia, including this file,
+**  may be copied, modified, propagated, or distributed except according to the
+**  terms described in the LICENSE file.
+*/
+
+/*
+** \file LogHeaderView.h
+** \version $Id$ 
+** \brief Header for the message log QTreeView
+*/
+
+#ifndef _LOGHEADERVIEW_H
+#define _LOGHEADERVIEW_H
+
+#include <QHeaderView>
+
+
+class LogHeaderView : public QHeaderView
+{
+  Q_OBJECT
+
+public:
+  /** Default constructor. */
+  LogHeaderView(QWidget *parent);
+
+  /** Resets all column widths back to their defaults. */
+  void resetColumnWidths();
+};
+
+#endif
+

Copied: vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogMessageColumnDelegate.cpp (from rev 3904, vidalia/branches/extension-api/src/vidalia/log/LogMessageColumnDelegate.cpp)
===================================================================
--- vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogMessageColumnDelegate.cpp	                        (rev 0)
+++ vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogMessageColumnDelegate.cpp	2009-06-28 21:54:14 UTC (rev 3905)
@@ -0,0 +1,39 @@
+/*
+**  This file is part of Vidalia, and is subject to the license terms in the
+**  LICENSE file, found in the top level directory of this distribution. If you
+**  did not receive the LICENSE file with this file, you may obtain it from the
+**  Vidalia source package distributed by the Vidalia Project at
+**  http://www.vidalia-project.net/. No part of Vidalia, including this file,
+**  may be copied, modified, propagated, or distributed except according to the
+**  terms described in the LICENSE file.
+*/
+
+/*
+** \file LogMessageColumnDelegate.cpp
+** \version $Id$
+** \brief Delegate responsible for rendering the log message column
+*/
+
+#include "LogMessageColumnDelegate.h"
+
+
+/** Default constructor. */
+LogMessageColumnDelegate::LogMessageColumnDelegate(QObject *parent)
+  : QItemDelegate(parent)
+{
+}
+
+/** Overrides the default paint() method so that we can prevent Qt from
+ * munging Tor's log messages when using a Right-to-Left layout (e.g. when
+ * viewing Vidalia in Farsi). */
+void
+LogMessageColumnDelegate::paint(QPainter *painter,
+                                const QStyleOptionViewItem &option,
+                                const QModelIndex &index) const
+{
+  QStyleOptionViewItem styleOption = option;  
+  styleOption.direction = Qt::LeftToRight;
+
+  QItemDelegate::paint(painter, styleOption, index);
+}
+

Copied: vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogMessageColumnDelegate.h (from rev 3904, vidalia/branches/extension-api/src/vidalia/log/LogMessageColumnDelegate.h)
===================================================================
--- vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogMessageColumnDelegate.h	                        (rev 0)
+++ vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogMessageColumnDelegate.h	2009-06-28 21:54:14 UTC (rev 3905)
@@ -0,0 +1,38 @@
+/*
+**  This file is part of Vidalia, and is subject to the license terms in the
+**  LICENSE file, found in the top level directory of this distribution. If you
+**  did not receive the LICENSE file with this file, you may obtain it from the
+**  Vidalia source package distributed by the Vidalia Project at
+**  http://www.vidalia-project.net/. No part of Vidalia, including this file,
+**  may be copied, modified, propagated, or distributed except according to the
+**  terms described in the LICENSE file.
+*/
+
+/*
+** \file LogMessageColumnDelegate.h
+** \version $Id$
+** \brief Delegate responsible for rendering the log message column
+*/
+
+#ifndef _LOGMESSAGECOLUMNDELEGATE_H
+#define _LOGMESSAGECOLUMNDELEGATE_H
+
+#include <QItemDelegate>
+
+
+class LogMessageColumnDelegate : public QItemDelegate
+{
+public:
+  /** Default constructor. */
+  LogMessageColumnDelegate(QObject *parent = 0);
+
+  /** Overrides the default paint() method so that we can prevent Qt from
+   * munging Tor's log messages when using a Right-to-Left layout (e.g. when
+   * viewing Vidalia in Farsi). */
+  virtual void paint(QPainter *painter,
+                     const QStyleOptionViewItem &option,
+                     const QModelIndex &index) const;
+};
+
+#endif
+

Copied: vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogTreeItem.cpp (from rev 3904, vidalia/branches/extension-api/src/vidalia/log/LogTreeItem.cpp)
===================================================================
--- vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogTreeItem.cpp	                        (rev 0)
+++ vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogTreeItem.cpp	2009-06-28 21:54:14 UTC (rev 3905)
@@ -0,0 +1,151 @@
+/*
+**  This file is part of Vidalia, and is subject to the license terms in the
+**  LICENSE file, found in the top level directory of this distribution. If you
+**  did not receive the LICENSE file with this file, you may obtain it from the
+**  Vidalia source package distributed by the Vidalia Project at
+**  http://www.vidalia-project.net/. No part of Vidalia, including this file,
+**  may be copied, modified, propagated, or distributed except according to the
+**  terms described in the LICENSE file.
+*/
+
+/*
+** \file LogTreeItem.cpp
+** \version $Id$
+** \brief Item representing a single message in the message log
+*/
+
+#include "LogTreeItem.h"
+#include "LogTreeWidget.h"
+
+#include "stringutil.h"
+
+/** Defines the format used for displaying the date and time of a log message.*/
+#define DATETIME_FMT  "MMM dd hh:mm:ss.zzz"
+
+/* Column index values */
+#define COL_TIME    LogTreeWidget::TimeColumn
+#define COL_TYPE    LogTreeWidget::TypeColumn
+#define COL_MESG    LogTreeWidget::MessageColumn
+#define ROLE_TYPE   Qt::UserRole
+
+
+/** Default constructor. */
+LogTreeItem::LogTreeItem(LogEvent::Severity type, QString message, 
+                         QDateTime timestamp)
+  : QTreeWidgetItem()
+{
+  static quint32 seqnum = 0;
+  
+  /* Set this message's sequence number */
+  _seqnum = seqnum++;
+  /* Set the item's log time */
+  setTimestamp(timestamp);
+  /* Set the item's severity and appropriate color. */
+  setSeverity(type);
+  /* Set the item's message text. */
+  setMessage(message);
+}
+
+/** Returns a printable string representing the fields of this item. */
+QString
+LogTreeItem::toString() const
+{
+  return QString("%1 [%2] %3\n").arg(text(COL_TIME))
+                                .arg(text(COL_TYPE))
+                                .arg(text(COL_MESG).trimmed());
+}
+
+/** Sets the item's log time. */
+void
+LogTreeItem::setTimestamp(QDateTime timestamp)
+{
+  QString strtime = timestamp.toString(DATETIME_FMT);
+  setText(COL_TIME, strtime);
+  setToolTip(COL_TIME, strtime);
+}
+
+/** Sets the item's severity and the appropriate background color. */
+void
+LogTreeItem::setSeverity(LogEvent::Severity type)
+{
+  /* Change row and text color for serious warnings and errors. */
+  if (type == LogEvent::Error) {
+    /* Critical messages are red with white text. */
+    for (int i = 0; i < 3; i++) {
+      setBackgroundColor(i, Qt::red);
+      setTextColor(i, Qt::white);
+    }
+  } else if (type == LogEvent::Warn) {
+    /* Warning messages are yellow with black text. */
+    for (int i = 0; i < 3; i++) {
+      setBackgroundColor(i, Qt::yellow);
+    }
+  }
+  
+  setTextAlignment(COL_TYPE, Qt::AlignCenter);
+  setText(COL_TYPE, LogEvent::severityToString(type));
+  setData(COL_TYPE, ROLE_TYPE, (uint)type);
+}
+
+/** Sets the item's message text. */
+void
+LogTreeItem::setMessage(QString message)
+{
+  setText(COL_MESG, message);
+  setToolTip(COL_MESG, string_wrap(message, 80, " ", "\r\n"));
+}
+
+/** Returns the severity associated with this log item. */
+LogEvent::Severity
+LogTreeItem::severity() const
+{
+  return (LogEvent::Severity)data(COL_TYPE, ROLE_TYPE).toUInt();
+}
+
+/** Returns the timestamp for this log message. */
+QDateTime
+LogTreeItem::timestamp() const
+{
+  return QDateTime::fromString(text(COL_TIME), DATETIME_FMT);
+}
+
+/** Returns the message for this log item. */
+QString
+LogTreeItem::message() const
+{
+  return text(COL_MESG);
+}
+
+/** Compares <b>other</b> to this log message item based on the current sort
+ * column. */
+bool
+LogTreeItem::operator<(const QTreeWidgetItem &other) const
+{
+  LogTreeItem *that = (LogTreeItem *)&other;
+  int sortColumn = (treeWidget() ? treeWidget()->sortColumn() : COL_TIME);
+   
+  switch (sortColumn) {
+    case COL_TIME:
+      /* Sort chronologically */
+      return (this->_seqnum < that->_seqnum);
+    case COL_TYPE:
+      /* Sort by severity, then chronologically */
+      if (this->severity() == that->severity()) {
+        return (this->_seqnum < that->_seqnum);
+      }
+      /* The comparison is flipped because higher severities have 
+       * lower numeric values */
+      return (this->severity() > that->severity());
+    default:
+      /* Sort by message, then chronologically */
+      QString thisMessage = this->message().toLower();
+      QString thatMessage = that->message().toLower();
+      
+      if (thisMessage == thatMessage) {
+        return (this->_seqnum < that->_seqnum);
+      }
+      return (thisMessage < thatMessage);
+  }
+  return QTreeWidgetItem::operator<(other);
+}
+

Copied: vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogTreeItem.h (from rev 3904, vidalia/branches/extension-api/src/vidalia/log/LogTreeItem.h)
===================================================================
--- vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogTreeItem.h	                        (rev 0)
+++ vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogTreeItem.h	2009-06-28 21:54:14 UTC (rev 3905)
@@ -0,0 +1,62 @@
+/*
+**  This file is part of Vidalia, and is subject to the license terms in the
+**  LICENSE file, found in the top level directory of this distribution. If you
+**  did not receive the LICENSE file with this file, you may obtain it from the
+**  Vidalia source package distributed by the Vidalia Project at
+**  http://www.vidalia-project.net/. No part of Vidalia, including this file,
+**  may be copied, modified, propagated, or distributed except according to the
+**  terms described in the LICENSE file.
+*/
+
+/*
+** \file LogTreeItem.h
+** \version $Id$ 
+** \brief Item representing a single message in the message log
+*/
+
+#ifndef _LOGTREEITEM_H
+#define _LOGTREEITEM_H
+
+#include "LogEvent.h"
+
+#include <QTreeWidgetItem>
+#include <QDateTime>
+#include <QString>
+
+
+class LogTreeItem : public QTreeWidgetItem
+{
+public:
+  /** Default constructor. */
+  LogTreeItem(LogEvent::Severity type, QString message, 
+              QDateTime timestamp = QDateTime::currentDateTime());
+
+  /** Sets the item's log time. */
+  void setTimestamp(QDateTime timestamp);
+  /** Sets the item's severity and appropriate background color. */
+  void setSeverity(LogEvent::Severity type);
+  /** Sets the item's message text. */
+  void setMessage(QString message);
+
+  /** Returns this message's sequence number. */
+  quint32 id() const { return _seqnum; }
+  /** Returns the timestamp for this log message. */
+  QDateTime timestamp() const;
+  /** Returns the severity associated with this log item. */
+  LogEvent::Severity severity() const;
+  /** Returns the message associated with this log item. */
+  QString message() const;
+  
+  /** Returns a printable string representation of the item's contents.*/
+  QString toString() const;
+  /** Compares <b>other</b> to this log message item based on the current sort
+   * column and order. */
+  virtual bool operator<(const QTreeWidgetItem &other) const;
+
+private:
+  quint32 _seqnum;  /**< Sequence number used to disambiguate messages with
+                         the same timestamp. */
+};
+
+#endif
+

Copied: vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogTreeWidget.cpp (from rev 3904, vidalia/branches/extension-api/src/vidalia/log/LogTreeWidget.cpp)
===================================================================
--- vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogTreeWidget.cpp	                        (rev 0)
+++ vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogTreeWidget.cpp	2009-06-28 21:54:14 UTC (rev 3905)
@@ -0,0 +1,267 @@
+/*
+**  This file is part of Vidalia, and is subject to the license terms in the
+**  LICENSE file, found in the top level directory of this distribution. If you
+**  did not receive the LICENSE file with this file, you may obtain it from the
+**  Vidalia source package distributed by the Vidalia Project at
+**  http://www.vidalia-project.net/. No part of Vidalia, including this file,
+**  may be copied, modified, propagated, or distributed except according to the
+**  terms described in the LICENSE file.
+*/
+
+/*
+** \file LogTreeWidget.cpp
+** \version $Id$
+** \brief Contains a collection of log messages as LogTreeItems
+*/
+
+#include "LogTreeWidget.h"
+#include "LogHeaderView.h"
+#include "LogMessageColumnDelegate.h"
+
+#include <QScrollBar>
+
+
+/** Default constructor. */
+LogTreeWidget::LogTreeWidget(QWidget *parent)
+  : QTreeWidget(parent)
+{
+  setHeader(new LogHeaderView(this));
+
+  /* Tor's log messages are always in English, so stop Qt from futzing with
+   * the message text if we're currently using a non-English RTL layout. */
+  if (layoutDirection() == Qt::RightToLeft) {
+    setItemDelegateForColumn(LogTreeWidget::MessageColumn,
+                             new LogMessageColumnDelegate(this));
+  }
+
+  /* Explicitly default to sorting messages chronologically */
+  sortItems(LogTreeWidget::TimeColumn, Qt::AscendingOrder);
+
+  /* Default to always scrolling to the most recent item added */
+  _scrollOnNewItem = true;
+  setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
+  connect(verticalScrollBar(), SIGNAL(sliderReleased()),
+          this, SLOT(verticalSliderReleased()));
+}
+
+/** Called when the user moves the vertical scrollbar. If the user has the
+ * scrollbar at within one step of its maximum, then always scroll to new
+ * items when added. Otherwise, leave the scrollbar alone since they are
+ * probably looking at something in their history. */
+void
+LogTreeWidget::verticalSliderReleased()
+{
+  QScrollBar *scrollBar = verticalScrollBar();
+  if (header()->sortIndicatorOrder() == Qt::AscendingOrder)
+    _scrollOnNewItem = (scrollBar->value() == scrollBar->maximum());
+  else
+    _scrollOnNewItem = (scrollBar->value() == scrollBar->minimum());
+}
+
+/** Cast a QList of QTreeWidgetItem pointers to a list of LogTreeWidget
+ * pointers. There really must be a better way to do this. */
+QList<LogTreeItem *>
+LogTreeWidget::qlist_cast(QList<QTreeWidgetItem *> inlist)
+{
+  QList<LogTreeItem *> outlist;
+  foreach (QTreeWidgetItem *item, inlist) {
+    outlist << (LogTreeItem *)item;
+  }
+  return outlist;
+}
+
+/** Sorts the list of pointers to log tree items by timestamp. */
+QList<LogTreeItem *>
+LogTreeWidget::qlist_sort(QList<LogTreeItem *> inlist)
+{
+  QMap<quint32, LogTreeItem *> outlist;
+  foreach (LogTreeItem *item, inlist) {
+    outlist.insert(item->id(), item);
+  }
+  return outlist.values();
+}
+
+/** The first time the log tree is shown, we need to set the default column
+ * widths. */
+void
+LogTreeWidget::showEvent(QShowEvent *event)
+{
+  static bool shown = false;
+  QTreeWidget::showEvent(event);
+  if (!shown) {
+    /* Set the default column widths the first time this is shown */
+    ((LogHeaderView *)header())->resetColumnWidths();
+    shown = true;
+  }
+}
+
+/** Clears all items from the message log and resets the counter in the status
+ * bar. */
+void
+LogTreeWidget::clearMessages()
+{
+  /* Clear the messages */
+  _itemHistory.clear();
+  clear();
+}
+
+/** Returns a list of all currently selected items. */
+QStringList
+LogTreeWidget::selectedMessages()
+{
+  QStringList messages;
+  
+  /* Get all selected log items */
+  QList<LogTreeItem *> items = 
+    qlist_cast(selectedItems());
+  
+  /* Format the message items as strings and put them in a list */
+  foreach (LogTreeItem *item, qlist_sort(items)) {
+    messages << item->toString();
+  }
+  return messages;
+}
+
+/** Returns a list of all items in the tree. */
+QStringList
+LogTreeWidget::allMessages()
+{
+  QStringList messages;
+
+  /* Format the message items as strings and put them in a list */
+  foreach (LogTreeItem *item, _itemHistory) {
+    messages << item->toString();
+  }
+  return messages;
+}
+
+/** Returns the number of items currently shown. */
+int
+LogTreeWidget::messageCount()
+{
+  return topLevelItemCount();
+}
+
+/** Sets the maximum number of items in the tree. */
+void
+LogTreeWidget::setMaximumMessageCount(int max)
+{
+  while (max < messageCount() && _itemHistory.size() > 0) {
+    /* If the new max is less than the currently displayed number of 
+     * items, then we'll get rid of some. */
+    int index = indexOfTopLevelItem(_itemHistory.takeFirst());
+    if (index != -1)
+      delete takeTopLevelItem(index);
+  }
+  _maxItemCount = max;
+}
+
+/** Deselects all currently selected items. */
+void
+LogTreeWidget::deselectAll()
+{
+  foreach(QTreeWidgetItem *item, selectedItems()) {
+    setItemSelected(item, false);
+  }
+}
+
+/** Adds a log item to the tree and returns a pointer to the new item. */
+LogTreeItem*
+LogTreeWidget::log(LogEvent::Severity type, QString message)
+{
+  int oldScrollValue;
+  QScrollBar *scrollBar = verticalScrollBar();
+  LogTreeItem *item = new LogTreeItem(type, message);
+
+  /* Remember the current scrollbar position */
+  oldScrollValue = scrollBar->value();
+
+  /* If we need to make room, then make some room */
+  if (messageCount() >= _maxItemCount && _itemHistory.size()) {
+    int index = indexOfTopLevelItem(_itemHistory.takeFirst());
+    if (index != -1)
+      delete takeTopLevelItem(index);
+  }
+
+  /* Add the new message item.
+   * NOTE: We disable sorting, add the new item, and then re-enable sorting
+   *       to force the result to be sorted immediately. Otherwise, the new
+   *       message is not sorted until the message log has focus again. This
+   *       is totally lame.
+   */
+  setSortingEnabled(false);
+  addLogTreeItem(item);
+  setSortingEnabled(true);
+
+  /* The intended vertical scrolling behavior is as follows:
+   *
+   *   1) If the message log is sorted in chronological order, and the user
+   *      previously had the vertical scroll bar at its maximum position, then
+   *      reposition the vertical scroll bar to the new maximum value.
+   *
+   *   2) If the message log is sorted in reverse chronological order, and the
+   *      user previously had the vertical scroll bar at its minimum position,
+   *      then reposition the vertical scroll bar to the new minimum value
+   *      (which is always just 0 anyway).
+   *
+   *   3) If the message log is sorted by severity level or lexicographically
+   *      by log message, or if the user manually repositioned the scroll bar,
+   *      then leave the vertical scroll bar at its previous position.
+   */
+  if (_scrollOnNewItem && sortColumn() == LogTreeWidget::TimeColumn) {
+    if (header()->sortIndicatorOrder() == Qt::AscendingOrder)
+      scrollBar->setValue(scrollBar->maximum());
+    else
+      scrollBar->setValue(scrollBar->minimum());
+  } else {
+    scrollBar->setValue(oldScrollValue);
+  }
+
+  return item;
+}
+
+/** Adds <b>item</b> as a top-level item in the tree. */
+void
+LogTreeWidget::addLogTreeItem(LogTreeItem *item)
+{
+  addTopLevelItem(item);
+  _itemHistory.append(item);
+}
+
+/** Filters the message log based on the given filter. */
+void
+LogTreeWidget::filter(uint filter)
+{
+  int itemsShown = 0;
+  for (int i = _itemHistory.size()-1; i >= 0; i--) {
+    LogTreeItem *item = _itemHistory.at(i);
+    if ((itemsShown < _maxItemCount) && (filter & item->severity())) {
+      itemsShown++;
+    } else {
+      int itemIndex = indexOfTopLevelItem(item);
+      if (itemIndex != -1)
+        delete takeTopLevelItem(itemIndex);
+      _itemHistory.removeAt(i);
+    }
+  }
+}
+
+/** Searches the log for entries that contain the given text. */
+QList<LogTreeItem *>
+LogTreeWidget::find(QString text, bool highlight)
+{
+  QList<LogTreeItem *> items = 
+    qlist_cast(findItems(text, Qt::MatchContains|Qt::MatchWrap, MessageColumn));
+  
+  if (highlight) {
+    /* Deselect all items before highlighting our search results. */
+    deselectAll();
+    foreach (LogTreeItem *item, items) {
+      /* Highlight a matched item */
+      setItemSelected(item, true);
+    }
+  }
+
+  /* Return the results, sorted by timestamp */
+  return qlist_sort(items);
+}

Copied: vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogTreeWidget.h (from rev 3904, vidalia/branches/extension-api/src/vidalia/log/LogTreeWidget.h)
===================================================================
--- vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogTreeWidget.h	                        (rev 0)
+++ vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/LogTreeWidget.h	2009-06-28 21:54:14 UTC (rev 3905)
@@ -0,0 +1,94 @@
+/*
+**  This file is part of Vidalia, and is subject to the license terms in the
+**  LICENSE file, found in the top level directory of this distribution. If you
+**  did not receive the LICENSE file with this file, you may obtain it from the
+**  Vidalia source package distributed by the Vidalia Project at
+**  http://www.vidalia-project.net/. No part of Vidalia, including this file,
+**  may be copied, modified, propagated, or distributed except according to the
+**  terms described in the LICENSE file.
+*/
+
+/*
+** \file LogTreeWidget.h
+** \version $Id$ 
+** \brief Contains a collection of log messages as LogTreeItems
+*/
+
+#ifndef _LOGTREEWIDGET_H
+#define _LOGTREEWIDGET_H
+
+#include "LogTreeItem.h"
+#include "LogEvent.h"
+
+#include <QList>
+#include <QString>
+#include <QStringList>
+#include <QTreeWidget>
+#include <QHeaderView>
+#include <QShowEvent>
+
+
+class LogTreeWidget : public QTreeWidget
+{
+  Q_OBJECT
+
+public:
+  /** Log tree column indices. */
+  enum LogColumns {
+    TimeColumn    = 0, /**< Timestamp column. */
+    TypeColumn    = 1, /**< Message severity type column. */
+    MessageColumn = 2  /**< Message text column. */
+  };
+  
+  /** Default constructor. */
+  LogTreeWidget(QWidget *parent = 0);
+  
+  /** Returns a list of all currently selected messages. */
+  QStringList selectedMessages();
+  /** Returns a list of all messages in the tree. */
+  QStringList allMessages();
+  /** Deselects all currently selected messages. */
+  void deselectAll();
+  
+  /** Returns the number of items currently in the tree. */
+  int messageCount();
+  /** Sets the maximum number of items in the tree. */
+  void setMaximumMessageCount(int max);
+  /** Filters the log according to the specified filter. */
+  void filter(uint filter);
+  
+  /** Adds a log item to the tree. */
+  LogTreeItem* log(LogEvent::Severity type, QString message);
+  
+  /** Searches the log for entries that contain the given text. */
+  QList<LogTreeItem *> find(QString text, bool highlight = true);
+
+public slots:
+  /** Clears all contents on the message log and resets the counter. */
+  void clearMessages();
+
+protected:
+  /** Sets the default, initial column header widths. */
+  void showEvent(QShowEvent *event);
+
+private slots:
+  /** Called when the user moves the vertical scroll bar. */
+  void verticalSliderReleased();
+
+private:
+  /** Adds <b>item</b> as a top-level item in the tree. */
+  void addLogTreeItem(LogTreeItem *item);
+  /** Casts a QList of one pointer type to another. */
+  QList<LogTreeItem *> qlist_cast(QList<QTreeWidgetItem *> inlist);
+  /** Sortrs a QList of pointers to tree items. */
+  QList<LogTreeItem *> qlist_sort(QList<LogTreeItem *> inlist);
+
+  /**< List of pointers to all log message items currently in the tree. */
+  QList<LogTreeItem *> _itemHistory;
+  int _maxItemCount; /**< Maximum number of items in the tree. */
+  bool _scrollOnNewItem; /**< Set to true if we are to scroll to the new item
+                               after adding a message to the log. */
+};
+  
+#endif
+

Copied: vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/MessageLog.cpp (from rev 3904, vidalia/branches/extension-api/src/vidalia/log/MessageLog.cpp)
===================================================================
--- vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/MessageLog.cpp	                        (rev 0)
+++ vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/MessageLog.cpp	2009-06-28 21:54:14 UTC (rev 3905)
@@ -0,0 +1,428 @@
+/*
+**  This file is part of Vidalia, and is subject to the license terms in the
+**  LICENSE file, found in the top level directory of this distribution. If you
+**  did not receive the LICENSE file with this file, you may obtain it from the
+**  Vidalia source package distributed by the Vidalia Project at
+**  http://www.vidalia-project.net/. No part of Vidalia, including this file,
+**  may be copied, modified, propagated, or distributed except according to the
+**  terms described in the LICENSE file.
+*/
+
+/*
+** \file MessageLog.cpp
+** \version $Id$
+** \brief Displays log messages and message log settings
+*/
+
+#include "MessageLog.h"
+#include "Vidalia.h"
+#include "VMessageBox.h"
+
+#include "html.h"
+
+#include <QMessageBox>
+#include <QFileDialog>
+#include <QInputDialog>
+#include <QMessageBox>
+#include <QClipboard>
+
+/* Message log settings */
+#define SETTING_MSG_FILTER          "MessageFilter"
+#define SETTING_MAX_MSG_COUNT       "MaxMsgCount"
+#define SETTING_ENABLE_LOGFILE      "EnableLogFile"
+#define SETTING_LOGFILE             "LogFile"
+#define DEFAULT_MSG_FILTER \
+  (LogEvent::Error|LogEvent::Warn|LogEvent::Notice)
+#define DEFAULT_MAX_MSG_COUNT       50
+#define DEFAULT_ENABLE_LOGFILE      false
+#if defined(Q_OS_WIN32)
+
+/** Default location of the log file to which log messages will be written. */
+#define DEFAULT_LOGFILE \
+  (win32_program_files_folder()+"\\Tor\\tor-log.txt")
+#else
+#define DEFAULT_LOGFILE       (QDir::homePath() + "/.tor/tor-log.txt")
+#endif
+
+#define ADD_TO_FILTER(f,v,b)  (f = ((b) ? ((f) | (v)) : ((f) & ~(v))))
+
+
+/** Constructor. The constructor will load the message log's settings from
+ * VidaliSettings and register for log events according to the most recently
+ * set severity filter. 
+ * \param torControl A TorControl object used to register for log events.
+ * \param parent The parent widget of this MessageLog object.
+ * \param flags Any desired window creation flags. 
+ */
+MessageLog::MessageLog(QWidget *parent)
+: VidaliaPanel(parent)
+{
+  /* Invoke Qt Designer generated QObject setup routine */
+  ui.setupUi(this);
+
+  /* Create necessary Message Log QObjects */
+  _torControl = Vidalia::torControl();
+ 
+  /* Bind events to actions */
+  createActions();
+
+  /* Set tooltips for necessary widgets */
+  setToolTips();
+  
+  /* Load the message log's stored settings */
+  loadSettings();
+
+  /* Sort in ascending chronological order */ 
+  ui.lstMessages->sortItems(LogTreeWidget::TimeColumn, 
+                            Qt::AscendingOrder);
+}
+
+/** Default Destructor. Simply frees up any memory allocated for member
+ * variables. */
+MessageLog::~MessageLog()
+{
+  _torControl->setLogEvents(0, this);
+  _logFile.close();
+}
+
+/** Binds events (signals) to actions (slots). */
+void
+MessageLog::createActions()
+{
+  connect(ui.actionSave_Selected, SIGNAL(triggered()), 
+      this, SLOT(saveSelected()));
+  
+  connect(ui.actionSave_All, SIGNAL(triggered()), 
+      this, SLOT(saveAll()));
+  
+  connect(ui.actionCopy, SIGNAL(triggered()),
+      this, SLOT(copy()));
+
+  connect(ui.actionFind, SIGNAL(triggered()),
+      this, SLOT(find()));
+
+  connect(ui.actionHelp, SIGNAL(triggered()),
+      this, SLOT(help()));
+  
+  connect(ui.btnSaveSettings, SIGNAL(clicked()),
+      this, SLOT(saveSettings()));
+
+  connect(ui.btnCancelSettings, SIGNAL(clicked()),
+      this, SLOT(cancelChanges()));
+
+  connect(ui.btnBrowse, SIGNAL(clicked()),
+      this, SLOT(browse()));
+
+#if defined(Q_WS_MAC)
+  ui.actionHelp->setShortcut(QString("Ctrl+?"));
+#endif
+  ui.actionClose->setShortcut(QString("Esc"));
+  Vidalia::createShortcut("Ctrl+W", this, ui.actionClose, SLOT(trigger()));
+}
+
+/** Set tooltips for Message Filter checkboxes in code because they are long
+ * and Designer wouldn't let us insert newlines into the text. */
+void
+MessageLog::setToolTips()
+{
+  ui.chkTorErr->setToolTip(tr("Messages that appear when something has \n"
+                              "gone very wrong and Tor cannot proceed."));
+  ui.chkTorWarn->setToolTip(tr("Messages that only appear when \n"
+                               "something has gone wrong with Tor."));
+  ui.chkTorNote->setToolTip(tr("Messages that appear infrequently \n"
+                               "during normal Tor operation and are \n"
+                               "not considered errors, but you may \n"
+                               "care about."));
+  ui.chkTorInfo->setToolTip(tr("Messages that appear frequently \n"
+                               "during normal Tor operation."));
+  ui.chkTorDebug->setToolTip(tr("Hyper-verbose messages primarily of \n"
+                                "interest to Tor developers.")); 
+}
+
+/** Called when the user changes the UI translation. */
+void
+MessageLog::retranslateUi()
+{
+  ui.retranslateUi(this);
+  setToolTips();
+}
+
+/** Loads the saved Message Log settings */
+void
+MessageLog::loadSettings()
+{
+  /* Set Max Count widget */
+  uint maxMsgCount = getSetting(SETTING_MAX_MSG_COUNT,
+                                DEFAULT_MAX_MSG_COUNT).toUInt();
+  ui.spnbxMaxCount->setValue(maxMsgCount);
+  ui.lstMessages->setMaximumMessageCount(maxMsgCount);
+
+  /* Set whether or not logging to file is enabled */
+  _enableLogging = getSetting(SETTING_ENABLE_LOGFILE,
+                              DEFAULT_ENABLE_LOGFILE).toBool();
+  QString logfile = getSetting(SETTING_LOGFILE,
+                               DEFAULT_LOGFILE).toString();
+  ui.lineFile->setText(QDir::convertSeparators(logfile));
+  rotateLogFile(logfile);
+  ui.chkEnableLogFile->setChecked(_logFile.isOpen());
+
+  /* Set the checkboxes accordingly */
+  _filter = getSetting(SETTING_MSG_FILTER, DEFAULT_MSG_FILTER).toUInt();
+  ui.chkTorErr->setChecked(_filter & LogEvent::Error);
+  ui.chkTorWarn->setChecked(_filter & LogEvent::Warn);
+  ui.chkTorNote->setChecked(_filter & LogEvent::Notice);
+  ui.chkTorInfo->setChecked(_filter & LogEvent::Info);
+  ui.chkTorDebug->setChecked(_filter & LogEvent::Debug);
+  registerLogEvents();
+ 
+  /* Filter the message log */
+  QApplication::setOverrideCursor(Qt::WaitCursor);
+  ui.lstMessages->filter(_filter);
+  QApplication::restoreOverrideCursor();
+}
+
+/** Attempts to register the selected message filter with Tor and displays an
+ * error if setting the events fails. */
+void
+MessageLog::registerLogEvents()
+{
+  QString errmsg;
+  _filter = getSetting(SETTING_MSG_FILTER, DEFAULT_MSG_FILTER).toUInt();
+  if (!_torControl->setLogEvents(_filter, this, &errmsg)) {
+    VMessageBox::warning(this, tr("Error Setting Filter"),
+      p(tr("Vidalia was unable to register for Tor's log events.")) + p(errmsg),
+      VMessageBox::Ok);
+  }
+}
+
+/** Opens a log file if necessary, or closes it if logging is disabled. If a
+ * log file is already opened and a new filename is specified, then the log
+ * file will be rotated to the new filename. In the case that the new filename
+ * can not be openend, the old file will remain open and writable. */
+bool
+MessageLog::rotateLogFile(QString filename)
+{
+  QString errmsg;
+  if (_enableLogging) {
+    if (!_logFile.open(filename, &errmsg)) {
+      VMessageBox::warning(this, tr("Error Opening Log File"),
+        p(tr("Vidalia was unable to open the specified log file."))+p(errmsg),
+        VMessageBox::Ok);
+      return false;
+    }
+  } else {
+    /* Close the log file. */
+    _logFile.close();
+  }
+  return true;
+}
+
+/** Saves the Message Log settings, adjusts the message list if required, and
+ * then hides the settings frame. */
+void
+MessageLog::saveSettings()
+{
+  /* Update the logging status */
+  _enableLogging = ui.chkEnableLogFile->isChecked();
+  if (_enableLogging && ui.lineFile->text().isEmpty()) {
+    /* The user chose to enable logging messages to a file, but didn't specify
+     * a log filename. */
+    VMessageBox::warning(this, tr("Log Filename Required"),
+      p(tr("You must enter a filename to be able to save log "
+           "messages to a file.")), VMessageBox::Ok);
+    return;
+  }
+  if (rotateLogFile(ui.lineFile->text())) {
+    saveSetting(SETTING_LOGFILE, ui.lineFile->text());
+    saveSetting(SETTING_ENABLE_LOGFILE, _logFile.isOpen());
+  }
+  ui.lineFile->setText(QDir::convertSeparators(ui.lineFile->text()));
+  ui.chkEnableLogFile->setChecked(_logFile.isOpen());
+
+  /* Update the maximum displayed item count */
+  saveSetting(SETTING_MAX_MSG_COUNT, ui.spnbxMaxCount->value());
+  ui.lstMessages->setMaximumMessageCount(ui.spnbxMaxCount->value());
+  
+  /* Save message filter and refilter the list */
+  uint filter = 0;
+  ADD_TO_FILTER(filter, LogEvent::Error, ui.chkTorErr->isChecked());
+  ADD_TO_FILTER(filter, LogEvent::Warn, ui.chkTorWarn->isChecked());
+  ADD_TO_FILTER(filter, LogEvent::Notice, ui.chkTorNote->isChecked());
+  ADD_TO_FILTER(filter, LogEvent::Info, ui.chkTorInfo->isChecked());
+  ADD_TO_FILTER(filter, LogEvent::Debug, ui.chkTorDebug->isChecked());
+  saveSetting(SETTING_MSG_FILTER, filter);
+  registerLogEvents();
+  
+  /* Filter the message log */
+  QApplication::setOverrideCursor(Qt::WaitCursor);
+  ui.lstMessages->filter(_filter);
+  QApplication::restoreOverrideCursor();
+   
+  /* Hide the settings frame and reset toggle button*/
+  ui.actionSettings->toggle(); 
+}
+
+/** Simply restores the previously saved settings and hides the settings
+ * frame. */
+void 
+MessageLog::cancelChanges()
+{
+  /* Hide the settings frame and reset toggle button */
+  ui.actionSettings->toggle();
+  /* Reload the settings */
+  loadSettings();
+}
+
+/** Called when the user clicks "Browse" to select a new log file. */
+void
+MessageLog::browse()
+{
+  /* Strangely, QFileDialog returns a non seperator converted path. */
+  QString filename = QDir::convertSeparators(
+                          QFileDialog::getSaveFileName(this,
+                              tr("Select Log File"), "tor-log.txt"));
+  if (!filename.isEmpty()) {
+    ui.lineFile->setText(filename);
+  }
+}
+
+/** Saves the given list of items to a file.
+ * \param items A list of log message items to save. 
+ */
+void
+MessageLog::save(QStringList messages)
+{
+  if (!messages.size()) {
+    return;
+  }
+
+  QString fileName = QFileDialog::getSaveFileName(this,
+                          tr("Save Log Messages"),
+                          "VidaliaLog-" + 
+                          QDateTime::currentDateTime().toString("MM.dd.yyyy")
+                          + ".txt", tr("Text Files (*.txt)"));
+  
+  /* If the choose to save */
+  if (!fileName.isEmpty()) {
+    LogFile logFile;
+    QString errmsg;
+    
+    /* If can't write to file, show error message */
+    if (!logFile.open(fileName, &errmsg)) {
+      VMessageBox::warning(this, tr("Vidalia"),
+                           p(tr("Cannot write file %1\n\n%2."))
+                                                .arg(fileName)
+                                                .arg(errmsg),
+                           VMessageBox::Ok);
+      return;
+    }
+   
+    /* Write out the message log to the file */
+    QApplication::setOverrideCursor(Qt::WaitCursor);
+    foreach (QString msg, messages) {
+      logFile << msg;
+    }
+    QApplication::restoreOverrideCursor();
+  }
+}
+
+/** Saves currently selected messages to a file. */
+void
+MessageLog::saveSelected()
+{
+  save(ui.lstMessages->selectedMessages());
+}
+
+/** Saves all shown messages to a file. */
+void
+MessageLog::saveAll()
+{
+  save(ui.lstMessages->allMessages());
+}
+
+/** Copies contents of currently selected messages to the 'clipboard'. */
+void
+MessageLog::copy()
+{
+  QString contents = ui.lstMessages->selectedMessages().join("");
+  if (!contents.isEmpty()) {
+    /* Copy the selected messages to the clipboard */
+    QApplication::clipboard()->setText(contents);
+  }
+}
+
+/** Prompts the user for a search string. If the search string is not found in
+ * any of the currently displayed log entires, then a message will be
+ * displayed for the user informing them that no matches were found. 
+ * \sa search()
+ */
+void
+MessageLog::find()
+{
+  bool ok;
+  QString text = QInputDialog::getText(this, tr("Find in Message Log"),
+                  tr("Find:"), QLineEdit::Normal, QString(), &ok);
+  
+  if (ok && !text.isEmpty()) {
+    /* Search for the user-specified text */
+    QList<LogTreeItem *> results = ui.lstMessages->find(text);
+    if (!results.size()) {
+      VMessageBox::information(this, tr("Not Found"), 
+                               p(tr("Search found 0 matches.")), 
+                               VMessageBox::Ok);
+    } else {
+      /* Set the focus to the first match */
+      ui.lstMessages->scrollToItem(results.at(0));
+    }
+  }
+}
+
+/** Writes a message to the Message History and tags it with
+ * the proper date, time and type.
+ * \param type The message's severity type.
+ * \param message The log message to be added.
+ */
+void 
+MessageLog::log(LogEvent::Severity type, QString message)
+{
+  /* Only add the message if it's not being filtered out */
+  if (_filter & (uint)type) {
+    /* Add the message to the list and scroll to it if necessary. */
+    LogTreeItem *item = ui.lstMessages->log(type, message); 
+   
+    /* This is a workaround to force Qt to update the statusbar text (if any
+     * is currently displayed) to reflect the new message added. */
+    QString currStatusTip = ui.statusbar->currentMessage();
+    if (!currStatusTip.isEmpty()) {
+      currStatusTip = ui.lstMessages->statusTip();
+      ui.statusbar->showMessage(currStatusTip);
+    }
+    
+    /* If we're saving log messages to a file, go ahead and do that now */
+    if (_enableLogging) {
+      _logFile << item->toString();
+    }
+  }
+}
+
+/** Custom event handler. Checks if the event is a log event. If it is, then
+ * it will write the message to the message log. 
+ * \param event The custom log event. 
+ */
+void
+MessageLog::customEvent(QEvent *event)
+{
+  if (event->type() == CustomEventType::LogEvent) {
+    LogEvent *e = (LogEvent *)event;
+    log(e->severity(), e->message());
+    e->accept();
+  }
+}
+
+/** Displays help information about the message log. */
+void
+MessageLog::help()
+{
+  emit helpRequested("log");
+}
+

Copied: vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/MessageLog.h (from rev 3904, vidalia/branches/extension-api/src/vidalia/log/MessageLog.h)
===================================================================
--- vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/MessageLog.h	                        (rev 0)
+++ vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/MessageLog.h	2009-06-28 21:54:14 UTC (rev 3905)
@@ -0,0 +1,100 @@
+/*
+**  This file is part of Vidalia, and is subject to the license terms in the
+**  LICENSE file, found in the top level directory of this distribution. If you
+**  did not receive the LICENSE file with this file, you may obtain it from the
+**  Vidalia source package distributed by the Vidalia Project at
+**  http://www.vidalia-project.net/. No part of Vidalia, including this file,
+**  may be copied, modified, propagated, or distributed except according to the
+**  terms described in the LICENSE file.
+*/
+
+/*
+** \file MessageLog.h
+** \version $Id$
+** \brief Displays log messages and message log settings
+*/
+
+#ifndef _MESSAGELOG_H
+#define _MESSAGELOG_H
+
+#include "ui_MessageLog.h"
+#include "VidaliaWindow.h"
+#include "LogFile.h"
+#include "LogTreeItem.h"
+#include "TorControl.h"
+#include "VidaliaSettings.h"
+
+#include <QMainWindow>
+#include <QStringList>
+#include <QResizeEvent>
+
+
+class MessageLog : public VidaliaPanel
+{
+  Q_OBJECT
+
+public:
+  /** Default constructor **/
+  MessageLog(QWidget *parent = 0);
+  /** Default destructor **/
+  ~MessageLog();
+  
+protected:
+  /** Called to deliver custom event types */
+  void customEvent(QEvent *event);
+  /** Called when the user changes the UI translation. */
+  virtual void retranslateUi();
+
+private slots:
+  /** Called when the user triggers the save all action **/
+  void saveAll();
+  /** Called when the user triggers save selected action **/
+  void saveSelected();
+  /** Called when the user triggers the copy action **/
+  void copy();
+  /** Called when the user triggers the find action. This will search
+   * through all currently displayed log entries for text specified by the
+   * user, highlighting the entries that contain a match. */
+  void find();
+  /** Called when user saves settings **/
+  void saveSettings();
+  /** Called when user cancels changed settings **/
+  void cancelChanges();
+  /** Called when the user clicks "Browse" to select a new log file. */
+  void browse();
+  /** Called when the user clicks "Help" to see help info about the log. */
+  void help();
+
+private:  
+  /** Create and bind actions to events **/
+  void createActions();
+  /** Set Tool Tips for various widgets **/
+  void setToolTips();
+  /** Loads the saved Message Log settings **/
+  void loadSettings();
+  /** Registers the current message filter with Tor */
+  void registerLogEvents();
+  /** Saves the given list of items to a file */
+  void save(QStringList messages);
+  /** Adds the passed message to the message log as the specified type **/
+  void log(LogEvent::Severity, QString msg);
+  /** Rotates the log file based on the filename and the current logging status. */
+  bool rotateLogFile(QString filename);
+
+  /** A pointer to a TorControl object, used to register for log events */
+  TorControl* _torControl;
+  /** A VidaliaSettings object that handles getting/saving settings **/
+  VidaliaSettings* _settings;
+  /** Stores the current message filter */
+  uint _filter;
+  /** Set to true if we will log all messages to a file. */  	 
+  bool _enableLogging;  
+  /* The log file used to store log messages. */
+  LogFile _logFile;
+
+  /** Qt Designer generatated QObject **/
+  Ui::MessageLog ui;
+};
+
+#endif
+

Copied: vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/MessageLog.ui (from rev 3904, vidalia/branches/extension-api/src/vidalia/log/MessageLog.ui)
===================================================================
--- vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/MessageLog.ui	                        (rev 0)
+++ vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/MessageLog.ui	2009-06-28 21:54:14 UTC (rev 3905)
@@ -0,0 +1,715 @@
+<ui version="4.0" >
+ <author></author>
+ <comment></comment>
+ <exportmacro></exportmacro>
+ <class>MessageLog</class>
+ <widget class="QMainWindow" name="MessageLog" >
+  <property name="geometry" >
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>698</width>
+    <height>625</height>
+   </rect>
+  </property>
+  <property name="contextMenuPolicy" >
+   <enum>Qt::NoContextMenu</enum>
+  </property>
+  <property name="windowTitle" >
+   <string>Message Log</string>
+  </property>
+  <property name="windowIcon" >
+   <iconset resource="..\res\vidalia.qrc" >:/images/32x32/format-justify-fill.png</iconset>
+  </property>
+  <property name="statusTip" >
+   <string/>
+  </property>
+  <property name="autoFillBackground" >
+   <bool>true</bool>
+  </property>
+  <widget class="QWidget" name="centralwidget" >
+   <layout class="QVBoxLayout" >
+    <property name="margin" >
+     <number>9</number>
+    </property>
+    <property name="spacing" >
+     <number>6</number>
+    </property>
+    <item>
+     <widget class="LogTreeWidget" name="lstMessages" >
+      <property name="contextMenuPolicy" >
+       <enum>Qt::NoContextMenu</enum>
+      </property>
+      <property name="autoFillBackground" >
+       <bool>false</bool>
+      </property>
+      <property name="alternatingRowColors" >
+       <bool>true</bool>
+      </property>
+      <property name="selectionMode" >
+       <enum>QAbstractItemView::ExtendedSelection</enum>
+      </property>
+      <property name="rootIsDecorated" >
+       <bool>false</bool>
+      </property>
+      <property name="uniformRowHeights" >
+       <bool>true</bool>
+      </property>
+      <property name="itemsExpandable" >
+       <bool>false</bool>
+      </property>
+      <property name="sortingEnabled" >
+       <bool>true</bool>
+      </property>
+      <column>
+       <property name="text" >
+        <string>Time</string>
+       </property>
+      </column>
+      <column>
+       <property name="text" >
+        <string>Type</string>
+       </property>
+      </column>
+      <column>
+       <property name="text" >
+        <string>Message</string>
+       </property>
+      </column>
+     </widget>
+    </item>
+    <item>
+     <widget class="QFrame" name="frmSettings" >
+      <property name="enabled" >
+       <bool>true</bool>
+      </property>
+      <property name="sizePolicy" >
+       <sizepolicy>
+        <hsizetype>0</hsizetype>
+        <vsizetype>0</vsizetype>
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <property name="minimumSize" >
+       <size>
+        <width>520</width>
+        <height>183</height>
+       </size>
+      </property>
+      <property name="maximumSize" >
+       <size>
+        <width>520</width>
+        <height>183</height>
+       </size>
+      </property>
+      <property name="contextMenuPolicy" >
+       <enum>Qt::NoContextMenu</enum>
+      </property>
+      <property name="visible" >
+       <bool>false</bool>
+      </property>
+      <property name="frameShape" >
+       <enum>QFrame::StyledPanel</enum>
+      </property>
+      <property name="frameShadow" >
+       <enum>QFrame::Raised</enum>
+      </property>
+      <layout class="QGridLayout" >
+       <property name="margin" >
+        <number>3</number>
+       </property>
+       <property name="spacing" >
+        <number>3</number>
+       </property>
+       <item row="0" column="2" >
+        <layout class="QHBoxLayout" >
+         <property name="margin" >
+          <number>0</number>
+         </property>
+         <property name="spacing" >
+          <number>6</number>
+         </property>
+         <item>
+          <spacer>
+           <property name="orientation" >
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" >
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item>
+          <layout class="QVBoxLayout" >
+           <property name="margin" >
+            <number>0</number>
+           </property>
+           <property name="spacing" >
+            <number>6</number>
+           </property>
+           <item>
+            <widget class="QPushButton" name="btnSaveSettings" >
+             <property name="contextMenuPolicy" >
+              <enum>Qt::NoContextMenu</enum>
+             </property>
+             <property name="toolTip" >
+              <string>Saves the current Message Log settings</string>
+             </property>
+             <property name="text" >
+              <string>Save Settings</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QPushButton" name="btnCancelSettings" >
+             <property name="minimumSize" >
+              <size>
+               <width>90</width>
+               <height>0</height>
+              </size>
+             </property>
+             <property name="contextMenuPolicy" >
+              <enum>Qt::NoContextMenu</enum>
+             </property>
+             <property name="toolTip" >
+              <string>Cancels changes made to settings</string>
+             </property>
+             <property name="text" >
+              <string>Cancel</string>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </item>
+        </layout>
+       </item>
+       <item rowspan="2" row="0" column="0" >
+        <widget class="QGroupBox" name="groupBox" >
+         <property name="contextMenuPolicy" >
+          <enum>Qt::NoContextMenu</enum>
+         </property>
+         <property name="title" >
+          <string>Message Filter</string>
+         </property>
+         <layout class="QVBoxLayout" >
+          <property name="margin" >
+           <number>9</number>
+          </property>
+          <property name="spacing" >
+           <number>6</number>
+          </property>
+          <item>
+           <widget class="QCheckBox" name="chkTorErr" >
+            <property name="contextMenuPolicy" >
+             <enum>Qt::NoContextMenu</enum>
+            </property>
+            <property name="toolTip" >
+             <string/>
+            </property>
+            <property name="whatsThis" >
+             <string/>
+            </property>
+            <property name="text" >
+             <string>Error</string>
+            </property>
+            <property name="icon" >
+             <iconset resource="..\res\vidalia.qrc">:/images/16x16/emblem-important.png</iconset>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QCheckBox" name="chkTorWarn" >
+            <property name="contextMenuPolicy" >
+             <enum>Qt::NoContextMenu</enum>
+            </property>
+            <property name="toolTip" >
+             <string/>
+            </property>
+            <property name="text" >
+             <string>Warning</string>
+            </property>
+            <property name="icon" >
+             <iconset resource="..\res\vidalia.qrc">:/images/16x16/dialog-warning.png</iconset>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QCheckBox" name="chkTorNote" >
+            <property name="contextMenuPolicy" >
+             <enum>Qt::NoContextMenu</enum>
+            </property>
+            <property name="toolTip" >
+             <string/>
+            </property>
+            <property name="text" >
+             <string>Notice</string>
+            </property>
+            <property name="icon" >
+             <iconset resource="..\res\vidalia.qrc">:/images/16x16/preferences-desktop-notification.png</iconset>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QCheckBox" name="chkTorInfo" >
+            <property name="contextMenuPolicy" >
+             <enum>Qt::NoContextMenu</enum>
+            </property>
+            <property name="toolTip" >
+             <string/>
+            </property>
+            <property name="text" >
+             <string>Info</string>
+            </property>
+            <property name="icon" >
+             <iconset resource="..\res\vidalia.qrc">:/images/16x16/dialog-information.png</iconset>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QCheckBox" name="chkTorDebug" >
+            <property name="contextMenuPolicy" >
+             <enum>Qt::NoContextMenu</enum>
+            </property>
+            <property name="toolTip" >
+             <string/>
+            </property>
+            <property name="text" >
+             <string>Debug</string>
+            </property>
+            <property name="icon" >
+             <iconset resource="..\res\vidalia.qrc">:/images/16x16/applications-system.png</iconset>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item row="0" column="1" >
+        <widget class="QGroupBox" name="groupBox_3" >
+         <property name="contextMenuPolicy" >
+          <enum>Qt::NoContextMenu</enum>
+         </property>
+         <property name="title" >
+          <string>Message Log History</string>
+         </property>
+         <layout class="QHBoxLayout" >
+          <property name="margin" >
+           <number>9</number>
+          </property>
+          <property name="spacing" >
+           <number>6</number>
+          </property>
+          <item>
+           <widget class="QSpinBox" name="spnbxMaxCount" >
+            <property name="minimumSize" >
+             <size>
+              <width>50</width>
+              <height>0</height>
+             </size>
+            </property>
+            <property name="contextMenuPolicy" >
+             <enum>Qt::NoContextMenu</enum>
+            </property>
+            <property name="toolTip" >
+             <string>Number of messages to display in the message log window</string>
+            </property>
+            <property name="maximum" >
+             <number>99999</number>
+            </property>
+            <property name="minimum" >
+             <number>1</number>
+            </property>
+            <property name="alignment" >
+             <set>Qt::AlignRight</set>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QLabel" name="lblMessageCount" >
+            <property name="contextMenuPolicy" >
+             <enum>Qt::NoContextMenu</enum>
+            </property>
+            <property name="text" >
+             <string>messages</string>
+            </property>
+            <property name="textFormat" >
+             <enum>Qt::AutoText</enum> 
+            </property>
+            <property name="alignment" >
+             <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item row="1" column="1" colspan="2" >
+        <widget class="QGroupBox" name="groupBox_2" >
+         <property name="contextMenuPolicy" >
+          <enum>Qt::NoContextMenu</enum>
+         </property>
+         <property name="title" >
+          <string>Always Save New Log Messages</string>
+         </property>
+         <layout class="QGridLayout" >
+          <property name="margin" >
+           <number>6</number>
+          </property>
+          <property name="spacing" >
+           <number>6</number>
+          </property>
+          <item row="1" column="1" >
+           <widget class="QPushButton" name="btnBrowse" >
+            <property name="contextMenuPolicy" >
+             <enum>Qt::NoContextMenu</enum>
+            </property>
+            <property name="text" >
+             <string>Browse</string>
+            </property>
+            <property name="enabled" >
+             <bool>false</bool>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="0" >
+           <widget class="QLineEdit" name="lineFile" >
+            <property name="enabled" >
+             <bool>false</bool>
+            </property>
+            <property name="contextMenuPolicy" >
+             <enum>Qt::NoContextMenu</enum>
+            </property>
+           </widget>
+          </item>
+          <item row="0" column="0" >
+           <widget class="QCheckBox" name="chkEnableLogFile" >
+            <property name="contextMenuPolicy" >
+             <enum>Qt::NoContextMenu</enum>
+            </property>
+            <property name="toolTip" >
+             <string>Enable automatically saving all new log messages to a file</string>
+            </property>
+            <property name="text" >
+             <string>Automatically save new log messages to a file</string>
+            </property>
+            <property name="checked" >
+             <bool>false</bool>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QStatusBar" name="statusbar" >
+   <property name="geometry" >
+    <rect>
+     <x>0</x>
+     <y>603</y>
+     <width>698</width>
+     <height>22</height>
+    </rect>
+   </property>
+  </widget>
+  <widget class="QToolBar" name="toolBar" >
+   <property name="contextMenuPolicy" >
+    <enum>Qt::NoContextMenu</enum>
+   </property>
+   <property name="movable" >
+    <bool>false</bool>
+   </property>
+   <property name="orientation" >
+    <enum>Qt::Horizontal</enum>
+   </property>
+   <property name="toolButtonStyle" >
+    <enum>Qt::ToolButtonTextUnderIcon</enum>
+   </property>
+   <attribute name="toolBarArea" >
+    <number>4</number>
+   </attribute>
+   <addaction name="actionSave_All" />
+   <addaction name="actionSave_Selected" />
+   <addaction name="separator" />
+   <addaction name="actionCopy" />
+   <addaction name="actionSelect_All" />
+   <addaction name="actionClear" />
+   <addaction name="actionFind" />
+   <addaction name="separator" />
+   <addaction name="actionSettings" />
+   <addaction name="actionHelp" />
+   <addaction name="actionClose" />
+  </widget>
+  <action name="actionMessage_Filters" >
+   <property name="text" >
+    <string>Message Filters...</string>
+   </property>
+   <property name="statusTip" >
+    <string>Set message filters</string>
+   </property>
+   <property name="shortcut" >
+    <string/>
+   </property>
+  </action>
+  <action name="actionHistory_Size" >
+   <property name="text" >
+    <string>History Size...</string>
+   </property>
+   <property name="statusTip" >
+    <string>Set maximum number of messages to display</string>
+   </property>
+  </action>
+  <action name="actionClear" >
+   <property name="icon" >
+    <iconset resource="..\res\vidalia.qrc" >:/images/32x32/edit-clear.png</iconset>
+   </property>
+   <property name="text" >
+    <string>Clear</string>
+   </property>
+   <property name="iconText" >
+    <string>Clear</string>
+   </property>
+   <property name="statusTip" >
+    <string>Clear all messages from the Message Log (Ctrl+E)</string>
+   </property>
+   <property name="shortcut" >
+    <string>Ctrl+E</string>
+   </property>
+  </action>
+  <action name="actionCopy" >
+   <property name="icon" >
+    <iconset resource="..\res\vidalia.qrc" >:/images/32x32/edit-copy.png</iconset>
+   </property>
+   <property name="text" >
+    <string>Copy</string>
+   </property>
+   <property name="iconText" >
+    <string>Copy</string>
+   </property>
+   <property name="toolTip" >
+    <string>Copy</string>
+   </property>
+   <property name="statusTip" >
+    <string>Copy the selected messages to the clipboard (Ctrl+C)</string>
+   </property>
+   <property name="shortcut" >
+    <string>Ctrl+C</string>
+   </property>
+  </action>
+  <action name="actionSelect_All" >
+   <property name="icon" >
+    <iconset resource="..\res\vidalia.qrc" >:/images/32x32/edit-select-all.png</iconset>
+   </property>
+   <property name="text" >
+    <string>Select All</string>
+   </property>
+   <property name="iconText" >
+    <string>Select All</string>
+   </property>
+   <property name="statusTip" >
+    <string>Select all messages (Ctrl+A)</string>
+   </property>
+   <property name="shortcut" >
+    <string>Ctrl+A</string>
+   </property>
+  </action>
+  <action name="actionSave_All" >
+   <property name="icon" >
+    <iconset resource="..\res\vidalia.qrc" >:/images/32x32/document-save-all.png</iconset>
+   </property>
+   <property name="text" >
+    <string>Save All</string>
+   </property>
+   <property name="statusTip" >
+    <string>Save all messages to a file</string>
+   </property>
+  </action>
+  <action name="actionSave_Selected" >
+   <property name="icon" >
+    <iconset resource="..\res\vidalia.qrc" >:/images/32x32/document-save.png</iconset>
+   </property>
+   <property name="text" >
+    <string>Save Selected</string>
+   </property>
+   <property name="statusTip" >
+    <string>Save selected messages to a file</string>
+   </property>
+  </action>
+  <action name="actionSettings" >
+   <property name="checkable" >
+    <bool>true</bool>
+   </property>
+   <property name="icon" >
+    <iconset resource="..\res\vidalia.qrc" >:/images/32x32/preferences-other.png</iconset>
+   </property>
+   <property name="text" >
+    <string>Settings</string>
+   </property>
+   <property name="statusTip" >
+    <string>Adjust Message Log Settings</string>
+   </property>
+   <property name="shortcut" >
+    <string>Ctrl+T</string>
+   </property>
+  </action>
+  <action name="actionHelp" >
+   <property name="icon" >
+    <iconset resource="..\res\vidalia.qrc" >:/images/32x32/system-help.png</iconset>
+   </property>
+   <property name="text" >
+    <string>Help</string>
+   </property>
+   <property name="statusTip" >
+    <string>Show the help browser</string>
+   </property>
+   <property name="shortcut" >
+    <string>F1</string>
+   </property>
+  </action>
+  <action name="actionClose" >
+   <property name="icon" >
+    <iconset resource="..\res\vidalia.qrc" >:/images/32x32/window-close.png</iconset>
+   </property>
+   <property name="text" >
+    <string>Close</string>
+   </property>
+   <property name="statusTip" >
+    <string>Close the Message Log</string>
+   </property>
+   <property name="shortcut" >
+    <string>Esc</string>
+   </property>
+  </action>
+  <action name="actionFind" >
+   <property name="icon" >
+    <iconset resource="..\res\vidalia.qrc" >:/images/32x32/edit-find.png</iconset>
+   </property>
+   <property name="text" >
+    <string>Find</string>
+   </property>
+   <property name="iconText" >
+    <string>Find</string>
+   </property>
+   <property name="statusTip" >
+    <string>Find all messages containing the search text (Ctrl+F)</string>
+   </property>
+   <property name="shortcut" >
+    <string>Ctrl+F</string>
+   </property>
+  </action>
+ </widget>
+ <pixmapfunction></pixmapfunction>
+ <customwidgets>
+  <customwidget>
+   <class>LogTreeWidget</class>
+   <extends>QTreeWidget</extends>
+   <header>LogTreeWidget.h</header>
+   <container>0</container>
+   <pixmap></pixmap>
+  </customwidget>
+ </customwidgets>
+ <resources>
+  <include location="../res/vidalia.qrc" />
+ </resources>
+ <connections>
+  <connection>
+   <sender>actionClose</sender>
+   <signal>triggered()</signal>
+   <receiver>MessageLog</receiver>
+   <slot>close()</slot>
+   <hints>
+    <hint type="sourcelabel" >
+     <x>-1</x>
+     <y>-1</y>
+    </hint>
+    <hint type="destinationlabel" >
+     <x>407</x>
+     <y>378</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>actionClear</sender>
+   <signal>triggered()</signal>
+   <receiver>lstMessages</receiver>
+   <slot>clear()</slot>
+   <hints>
+    <hint type="sourcelabel" >
+     <x>-1</x>
+     <y>-1</y>
+    </hint>
+    <hint type="destinationlabel" >
+     <x>407</x>
+     <y>393</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>actionSelect_All</sender>
+   <signal>triggered()</signal>
+   <receiver>lstMessages</receiver>
+   <slot>selectAll()</slot>
+   <hints>
+    <hint type="sourcelabel" >
+     <x>-1</x>
+     <y>-1</y>
+    </hint>
+    <hint type="destinationlabel" >
+     <x>407</x>
+     <y>393</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>actionSettings</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>frmSettings</receiver>
+   <slot>setVisible(bool)</slot>
+   <hints>
+    <hint type="sourcelabel" >
+     <x>-1</x>
+     <y>-1</y>
+    </hint>
+    <hint type="destinationlabel" >
+     <x>407</x>
+     <y>393</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>chkEnableLogFile</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>lineFile</receiver>
+   <slot>setEnabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel" >
+     <x>373</x>
+     <y>491</y>
+    </hint>
+    <hint type="destinationlabel" >
+     <x>348</x>
+     <y>516</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>actionClear</sender>
+   <signal>triggered()</signal>
+   <receiver>lstMessages</receiver>
+   <slot>clearMessages()</slot>
+  </connection>
+  <connection>
+   <sender>chkEnableLogFile</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>btnBrowse</receiver>
+   <slot>setEnabled(bool)</slot>
+  </connection>
+ </connections>
+</ui>

Modified: vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/MessageLogPlugin.h
===================================================================
--- vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/MessageLogPlugin.h	2009-06-28 15:53:49 UTC (rev 3904)
+++ vidalia/branches/extension-api/src/vidalia/MessageLogPlugin/MessageLogPlugin.h	2009-06-28 21:54:14 UTC (rev 3905)
@@ -17,6 +17,8 @@
 #ifndef _MESSAGELOGPLUGIN_H
 #define _MESSAGELOGPLUGIN_H
 
+#include "MessageLog.h"
+
 #include <QObject>
 
 #include <vidalia/VidaliaPluginInterface.h>
@@ -30,7 +32,17 @@
   MessageLogPlugin();
   ~MessageLogPlugin();
 
+  VidaliaPanel* panel();
+
   QString pluginHumanName() const;
+
+private:
+  /** Bit of hackery to work around static plugin system. Can not instantiate a 
+   * VidaliaPanel while qApp doesn't exist. */
+  void init();
+
+  /** The message log object. */
+  MessageLog* _messageLog;
 };
 
 #endif

Modified: vidalia/branches/extension-api/src/vidalia/NetworkMapPlugin/NetworkMapPlugin.h
===================================================================
--- vidalia/branches/extension-api/src/vidalia/NetworkMapPlugin/NetworkMapPlugin.h	2009-06-28 15:53:49 UTC (rev 3904)
+++ vidalia/branches/extension-api/src/vidalia/NetworkMapPlugin/NetworkMapPlugin.h	2009-06-28 21:54:14 UTC (rev 3905)
@@ -34,14 +34,14 @@
   NetworkMapPlugin();
   ~NetworkMapPlugin();
 
-  /** Bit of hackery to work around static plugin system. Can not instantiate a VidaliaPanel while qApp doesn't exist. */
-  void init();
-
   /** Returns the vidalia panel to be displayed in the main window. */
   VidaliaPanel* panel();
   /** Returns the human readable plugin name for adding and removing plugins. */
   QString pluginHumanName() const;
 private:
+  /** Bit of hackery to work around static plugin system. Can not instantiate a 
+   * VidaliaPanel while qApp doesn't exist. */
+  void init();
   /** The network map object. */
   NetViewer* _netViewer;
 };