Merged changes from branch "sput" r50:55 back into trunk.
authorManuel Nickschas <sputnick@quassel-irc.org>
Mon, 12 Feb 2007 18:14:53 +0000 (18:14 +0000)
committerManuel Nickschas <sputnick@quassel-irc.org>
Mon, 12 Feb 2007 18:14:53 +0000 (18:14 +0000)
This includes my work of the past few months, most notably a pretty complete rework
of the buffer management and much other GUI code, as well as our new ChatWidget which is
now functional enough to be used. Probably most of the GUI code now looks quite different.

There have also been many cleanups, the obsolete network/ directory is being removed,
and I have started to document some things.

30 files changed:
CMakeLists.txt
Doxyfile
Quassel.kdevelop.filelist
dev-notes/builtin_cmds.obsolete.cpp [moved from network/builtin_cmds.cpp with 95% similarity]
dev-notes/paulk-mainwindow.ui [moved from gui/mainwindow.ui with 100% similarity]
gui/CMakeLists.txt
gui/buffer.cpp
gui/buffer.h
gui/channelwidget.cpp [deleted file]
gui/channelwidget.h [deleted file]
gui/chatwidget.cpp [new file with mode: 0644]
gui/chatwidget.h [new file with mode: 0644]
gui/mainwin.cpp
gui/mainwin.h
gui/settings.cpp [moved from network/buffer.cpp with 89% similarity]
gui/settings.h [moved from network/builtin_handlers.cpp with 76% similarity]
gui/style.cpp [new file with mode: 0644]
gui/style.h [moved from network/buffer.h with 74% similarity]
gui/ui/bufferwidget.ui
gui/ui/mainwin.ui
gui/ui/settingsdlg.ui
main/main_gui.cpp
main/main_mono.cpp
network/CMakeLists.txt [deleted file]
network/cmdcodes.h [deleted file]
network/server.cpp [deleted file]
network/server.h [deleted file]
plugins/plugin.h [new file with mode: 0644]
templates/cpp
templates/h

index d08682e..9f80077 100644 (file)
@@ -24,6 +24,8 @@ IF(NOT BUILD_MONO AND NOT BUILD_CORE AND NOT BUILD_GUI)
   MESSAGE(FATAL_ERROR "\nYou have not selected which parts of Quassel I should build. Aborting.\nRun 'cmake <path> -DBUILD=<part>', where <part> contains one or more of 'core', 'gui' or 'monolithic', or 'all' to build everything.\n")
 ENDIF(NOT BUILD_MONO AND NOT BUILD_CORE AND NOT BUILD_GUI)
 
+SET(CMAKE_BUILD_TYPE Debug)
+
 # Define files
 SET(quassel_mono_SRCS main/main_mono.cpp)
 SET(quassel_core_SRCS main/main_core.cpp)
@@ -36,7 +38,7 @@ SET(SDIRS "")
 FOREACH(dir ${quassel_DIRS})
   SET(SDIRS ${SDIRS} "${CMAKE_CURRENT_SOURCE_DIR}/${dir}")
 ENDFOREACH(dir)
-INCLUDE_DIRECTORIES(${SDIRS})
+INCLUDE_DIRECTORIES(${SDIRS} plugins)
 INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
 
 # We need Qt4 support.
index 127f3f5..0272fd8 100644 (file)
--- a/Doxyfile
+++ b/Doxyfile
@@ -1,4 +1,4 @@
-# Doxyfile 1.4.1-KDevelop
+# Doxyfile 1.5.1-KDevelop
 
 #---------------------------------------------------------------------------
 # Project related configuration options
@@ -22,21 +22,23 @@ ABBREVIATE_BRIEF       = "The $name class" \
                          a \
                          an \
                          the
-ALWAYS_DETAILED_SEC    = YES
+ALWAYS_DETAILED_SEC    = NO
 INLINE_INHERITED_MEMB  = YES
 FULL_PATH_NAMES        = NO
 STRIP_FROM_PATH        = /
-STRIP_FROM_INC_PATH    = 
+STRIP_FROM_INC_PATH    = /home/sputnick/devel/local-quassel/
 SHORT_NAMES            = YES
 JAVADOC_AUTOBRIEF      = NO
 MULTILINE_CPP_IS_BRIEF = NO
 DETAILS_AT_TOP         = YES
 INHERIT_DOCS           = YES
-DISTRIBUTE_GROUP_DOC   = NO
+SEPARATE_MEMBER_PAGES  = NO
 TAB_SIZE               = 8
 ALIASES                = 
 OPTIMIZE_OUTPUT_FOR_C  = NO
 OPTIMIZE_OUTPUT_JAVA   = NO
+BUILTIN_STL_SUPPORT    = NO
+DISTRIBUTE_GROUP_DOC   = YES
 SUBGROUPING            = YES
 #---------------------------------------------------------------------------
 # Build related configuration options
@@ -80,7 +82,10 @@ WARN_LOGFILE           =
 #---------------------------------------------------------------------------
 # configuration options related to the input files
 #---------------------------------------------------------------------------
-INPUT                  = /home/sputnick/shared/Development/quassel/
+INPUT                  = gui \
+                         main \
+                         core \
+                         plugins
 FILE_PATTERNS          = *.c \
                          *.cc \
                          *.cxx \
@@ -137,7 +142,7 @@ EXAMPLE_RECURSIVE      = NO
 IMAGE_PATH             = 
 INPUT_FILTER           = 
 FILTER_PATTERNS        = 
-FILTER_SOURCE_FILES    = NO
+FILTER_SOURCE_FILES    = YES
 #---------------------------------------------------------------------------
 # configuration options related to source browsing
 #---------------------------------------------------------------------------
@@ -146,6 +151,8 @@ INLINE_SOURCES         = NO
 STRIP_CODE_COMMENTS    = YES
 REFERENCED_BY_RELATION = YES
 REFERENCES_RELATION    = YES
+REFERENCES_LINK_SOURCE = YES
+USE_HTAGS              = NO
 VERBATIM_HEADERS       = YES
 #---------------------------------------------------------------------------
 # configuration options related to the alphabetical class index
@@ -226,11 +233,11 @@ PERLMOD_MAKEVAR_PREFIX =
 #---------------------------------------------------------------------------
 # Configuration options related to the preprocessor   
 #---------------------------------------------------------------------------
-ENABLE_PREPROCESSING   = NO
-MACRO_EXPANSION        = NO
+ENABLE_PREPROCESSING   = YES
+MACRO_EXPANSION        = YES
 EXPAND_ONLY_PREDEF     = NO
-SEARCH_INCLUDES        = NO
-INCLUDE_PATH           = 
+SEARCH_INCLUDES        = YES
+INCLUDE_PATH           = /usr/include/qt4
 INCLUDE_FILE_PATTERNS  = 
 PREDEFINED             = 
 EXPAND_AS_DEFINED      = 
@@ -257,6 +264,7 @@ TEMPLATE_RELATIONS     = NO
 INCLUDE_GRAPH          = YES
 INCLUDED_BY_GRAPH      = YES
 CALL_GRAPH             = NO
+CALLER_GRAPH           = NO
 GRAPHICAL_HIERARCHY    = YES
 DIRECTORY_GRAPH        = YES
 DOT_IMAGE_FORMAT       = png
index 5cc32b4..be3867f 100644 (file)
@@ -70,3 +70,7 @@ main/message.h
 gui/ui/bufferwidget.ui
 core/server.cpp
 core/server.h
+gui/chatwidget.cpp
+gui/chatwidget.h
+gui/style.cpp
+gui/style.h
similarity index 95%
rename from network/builtin_cmds.cpp
rename to dev-notes/builtin_cmds.obsolete.cpp
index 5927469..5a9acf6 100644 (file)
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
 
-/* THIS CODE IS OBSOLETE! */
+#error THIS CODE IS OBSOLETE!
 
-#include <QtGlobal>
-//#include "message.h"
-#include "cmdcodes.h"
+/* We are keeping this for further reference only.
+ * This method of defining server commands sucked, but at least we have a quite complete list
+ * of commands here.
+ */
 
 /** This macro marks strings as translateable for Qt's linguist tools */
 #define _(str) QT_TR_NOOP(str)
  *  Named commands have a negative enum value.
  */
 
-/** \NOTE: Function handlers _must_ be global functions or static methods! */
-
-/** Set handler addresses to 0 to use the default (server) handler. */
-
 BuiltinCmd builtins[] = {
   { CMD_ADMIN, "admin", _("Get information about the administrator of a server."),
     _("[server]"), _("server: Server"), 0, 0 },
index 8bc8b4b..a9b27aa 100644 (file)
@@ -1,11 +1,11 @@
-SET(gui_SRCS channelwidgetinput.cpp mainwin.cpp serverlist.cpp buffer.cpp
-             identities.cpp coreconnectdlg.cpp guiproxy.cpp networkview.cpp)
-SET(gui_HDRS )
-SET(gui_MOCS channelwidgetinput.h mainwin.h serverlist.h identities.h coreconnectdlg.h
-             guiproxy.h networkview.h buffer.h)
+SET(gui_SRCS chatwidget.cpp channelwidgetinput.cpp mainwin.cpp serverlist.cpp buffer.cpp
+             identities.cpp coreconnectdlg.cpp guiproxy.cpp networkview.cpp style.cpp settings.cpp)
+SET(gui_HDRS style.h)
+SET(gui_MOCS chatwidget.h channelwidgetinput.h mainwin.h serverlist.h identities.h coreconnectdlg.h
+             guiproxy.h networkview.h buffer.h settings.h)
 SET(gui_UICS identitiesdlg.ui identitieseditdlg.ui networkeditdlg.ui mainwin.ui
              nickeditdlg.ui serverlistdlg.ui servereditdlg.ui coreconnectdlg.ui ircwidget.ui
-             networkview.ui bufferwidget.ui)
+             networkview.ui bufferwidget.ui settingsdlg.ui)
 
 # This prepends ui/ to the UIC names, so we don't have to do this ourselves.
 FOREACH(ui ${gui_UICS})
index 3892ee9..751da80 100644 (file)
 
 #include "buffer.h"
 #include "util.h"
+#include "chatwidget.h"
 
 Buffer::Buffer(QString netname, QString bufname) {
   networkName = netname;
   bufferName = bufname;
 
   widget = 0;
+  chatWidget = 0;
+  contentsWidget = 0;
   active = false;
 }
 
 Buffer::~Buffer() {
   delete widget;
+  delete chatWidget;
 }
 
 void Buffer::setActive(bool a) {
@@ -49,21 +53,30 @@ void Buffer::userInput(QString msg) {
   emit userInput(networkName, bufferName, msg);
 }
 
+/* FIXME do we need this? */
 void Buffer::scrollToEnd() {
   if(!widget) return;
-  widget->scrollToEnd();
+  //widget->scrollToEnd();
 }
 
 QWidget * Buffer::showWidget(QWidget *parent) {
+
   if(widget) {
-    widget->scrollToEnd();
     return qobject_cast<QWidget*>(widget);
   }
-  widget = new BufferWidget(networkName, bufferName, isActive(), ownNick, contents, parent); 
+
+  if(!contentsWidget) {
+    contentsWidget = new ChatWidgetContents(networkName, bufferName, 0);
+    contentsWidget->hide();
+    /* FIXME do we need this? */
+    for(int i = 0; i < contents.count(); i++) {
+      contentsWidget->appendMsg(contents[i]);
+    }
+  }
+  contentsWidget->hide();
+  widget = new BufferWidget(networkName, bufferName, isActive(), ownNick, contentsWidget, this, parent);
   widget->setTopic(topic);
   widget->updateNickList(nicks);
-  //widget->renderContents();
-  //widget->scrollToEnd();
   connect(widget, SIGNAL(userInput(QString)), this, SLOT(userInput(QString)));
   return qobject_cast<QWidget*>(widget);
 }
@@ -73,6 +86,10 @@ void Buffer::hideWidget() {
   widget = 0;
 }
 
+void Buffer::deleteWidget() {
+  widget = 0;
+}
+
 QWidget * Buffer::getWidget() {
   return qobject_cast<QWidget*>(widget);
 }
@@ -112,12 +129,19 @@ void Buffer::setOwnNick(QString nick) {
 
 /****************************************************************************************/
 
-BufferWidget::BufferWidget(QString netname, QString bufname, bool act, QString own, QList<Message> cont, QWidget *parent) : QWidget(parent) {
+
+
+/****************************************************************************************/
+
+BufferWidget::BufferWidget(QString netname, QString bufname, bool act, QString own, ChatWidgetContents *contents, Buffer *pBuf, QWidget *parent) : QWidget(parent) {
   ui.setupUi(this);
   networkName = netname;
   bufferName = bufname;
   active = act;
-  contents = cont;
+  parentBuffer = pBuf;
+
+  ui.chatWidget->init(netname, bufname, contents);
+
   ui.ownNick->clear();
   ui.ownNick->addItem(own);
   if(bufname.isEmpty()) {
@@ -130,30 +154,15 @@ BufferWidget::BufferWidget(QString netname, QString bufname, bool act, QString o
   connect(ui.nickTree, SIGNAL(itemCollapsed(QTreeWidgetItem *)), this, SLOT(itemExpansionChanged(QTreeWidgetItem*)));
   connect(ui.inputEdit, SIGNAL(returnPressed()), this, SLOT(enterPressed()));
 
-  ui.chatWidget->setFocusProxy(ui.inputEdit);
-  ui.chatWidget->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
-
   opsExpanded = voicedExpanded = usersExpanded = true;
 
-  // Define standard colors
-  stdCol = "black";
-  inactiveCol = "grey";
-  noticeCol = "darkblue";
-  serverCol = "darkblue";
-  errorCol = "red";
-  joinCol = "green";
-  quitCol = "firebrick";
-  partCol = "firebrick";
-  kickCol = "firebrick";
-  nickCol = "magenta";
-
-  int i = contents.count() - 100;
-  if(i < 0) i = 0;
-  for(int j = 0; j < i; j++) contents.removeAt(0);
-  show();
-  renderContents();
+  ui.chatWidget->setFocusProxy(ui.inputEdit);
   updateTitle();
-  //show();
+}
+
+BufferWidget::~BufferWidget() {
+  ui.chatWidget->takeWidget();   /* remove ownership so the chatwidget contents does not get destroyed */
+  parentBuffer->deleteWidget();  /* make sure the parent buffer knows we are gone */
 }
 
 void BufferWidget::updateTitle() {
@@ -173,100 +182,13 @@ void BufferWidget::enterPressed() {
 void BufferWidget::setActive(bool act) {
   if(act != active) {
     active = act;
-    renderContents();
+    //renderContents();
     //scrollToEnd();
   }
 }
 
-void BufferWidget::renderContents() {
-  QString html;
-  //html = "<style type=\"text/css\">"
-  //    ".test { background-color:#339933 }"
-  //    "</style>";
-  for(int i = 0; i < contents.count(); i++) {
-    html += htmlFromMsg(contents[i]);
-  }
-  //ui.chatWidget->clear();
-  hide();
-  ui.chatWidget->setHtml(html); show();
-  //ui.chatWidget->insertHtml("<div />");  // <-- bug that would not reset the scrollbar sizes...
-  scrollToEnd();
-}
-
-void BufferWidget::scrollToEnd() {
-  QScrollBar *sb = ui.chatWidget->verticalScrollBar();
-  sb->setValue(sb->maximum());
-  //qDebug() << bufferName << "scrolled" << sb->value() << sb->maximum();
-}
-
-QString BufferWidget::htmlFromMsg(Message msg) {
-  QString s, n;
-  QString c = stdCol;
-  QString user = userFromMask(msg.sender);
-  QString host = hostFromMask(msg.sender);
-  QString nick = nickFromMask(msg.sender);
-  switch(msg.type) {
-    case Message::Plain:
-      c = stdCol; n = QString("&lt;%1&gt;").arg(nick); s = msg.text;
-      break;
-    case Message::Server:
-      c = serverCol; s = msg.text;
-      break;
-    case Message::Error:
-      c = errorCol; s = msg.text;
-      break;
-    case Message::Join:
-      c = joinCol;
-      s = QString(tr("--> %1 (%2@%3) has joined %4")).arg(nick).arg(user).arg(host).arg(bufferName);
-      break;
-    case Message::Part:
-      c = partCol;
-      s = QString(tr("<-- %1 (%2@%3) has left %4")).arg(nick).arg(user).arg(host).arg(bufferName);
-      if(!msg.text.isEmpty()) s = QString("%1 (%2)").arg(s).arg(msg.text);
-      break;
-    case Message::Kick:
-      { c = kickCol;
-        QString victim = msg.text.section(" ", 0, 0);
-        if(victim == ui.ownNick->currentText()) victim = tr("you");
-        QString kickmsg = msg.text.section(" ", 1);
-        s = QString(tr("--> %1 has kicked %2 from %3")).arg(nick).arg(victim).arg(bufferName);
-        if(!kickmsg.isEmpty()) s = QString("%1 (%2)").arg(s).arg(kickmsg);
-      }
-      break;
-    case Message::Quit:
-      c = quitCol;
-      s = QString(tr("<-- %1 (%2@%3) has quit")).arg(nick).arg(user).arg(host);
-      if(!msg.text.isEmpty()) s = QString("%1 (%2)").arg(s).arg(msg.text);
-      break;
-    case Message::Nick:
-      c = nickCol;
-      if(nick == msg.text) s = QString(tr("<-> You are now known as %1")).arg(msg.text);
-      else s = QString(tr("<-> %1 is now known as %2")).arg(nick).arg(msg.text);
-      break;
-    case Message::Mode:
-      c = serverCol;
-      if(nick.isEmpty()) s = tr("*** User mode: %1").arg(msg.text);
-      else s = tr("*** Mode %1 by %2").arg(msg.text).arg(nick);
-      break;
-    default:
-      c = stdCol; n = QString("[%1]").arg(msg.sender); s = msg.text;
-      break;
-  }
-  if(!active) c = inactiveCol;
-  s.replace('&', "&amp;"); s.replace('<', "&lt;"); s.replace('>', "&gt;");
-  QString html = QString("<table cellspacing=0 cellpadding=0><tr>"
-      "<td width=50><div style=\"color:%2;\">[%1]</div></td>")
-      .arg(msg.timeStamp.toLocalTime().toString("hh:mm:ss")).arg("darkblue");
-  if(!n.isEmpty())
-    html += QString("<td width=100><div align=right style=\"white-space:pre;margin-left:6px;color:%2;\">%1</div></td>")
-        .arg(n).arg("royalblue");
-  html += QString("<td><div style=\"white-space:pre-wrap;margin-left:6px;color:%2;\">%1</div></td>""</tr></table>").arg(s).arg(c);
-  return html;
-}
-
 void BufferWidget::displayMsg(Message msg) {
-  contents.append(msg);
-  ui.chatWidget->append(htmlFromMsg(msg));
+  ui.chatWidget->appendMsg(msg);
 }
 
 void BufferWidget::setOwnNick(QString nick) {
index 5df19aa..4ef1112 100644 (file)
 #include "global.h"
 #include "message.h"
 
+class ChatWidget;
+class ChatWidgetContents;
 class BufferWidget;
 
+//!\brief Encapsulates the contents of a single channel, query or server status context.
+/** A Buffer maintains a list of existing nicks and their status. New messages can be appended using
+ * displayMsg(). A buffer displays its contents by way of a BufferWidget, which can be shown
+ * (and created on demand) by calling showWidget().
+ */
 class Buffer : public QObject {
   Q_OBJECT
 
@@ -60,6 +67,7 @@ class Buffer : public QObject {
 
     QWidget * showWidget(QWidget *parent = 0);
     void hideWidget();
+    void deleteWidget();
 
     void scrollToEnd();
 
@@ -69,6 +77,8 @@ class Buffer : public QObject {
   private:
     bool active;
     BufferWidget *widget;
+    ChatWidget *chatWidget;
+    ChatWidgetContents *contentsWidget;
     VarMap nicks;
     QString topic;
     QString ownNick;
@@ -77,23 +87,30 @@ class Buffer : public QObject {
     QList<Message> contents;
 };
 
+//!\brief Displays the contents of a Buffer.
+/** A BufferWidget usually includes a topic line, a nicklist, the chat itself, and an input line.
+ * For server buffers or queries, there is of course no nicklist.
+ * The contents of the chat is rendered by a ChatWidget.
+ */
 class BufferWidget : public QWidget {
   Q_OBJECT
 
   public:
-    BufferWidget(QString netname, QString bufname, bool active, QString ownNick, QList<Message> contents, QWidget *parent = 0);
+    BufferWidget(QString netname, QString bufname, bool active, QString ownNick, ChatWidgetContents *contents, Buffer *parentBuffer, QWidget *parent = 0);
+    ~BufferWidget();
 
     void setActive(bool act = true);
+
   signals:
     void userInput(QString);
 
+  protected:
+
   public slots:
     void displayMsg(Message);
     void updateNickList(VarMap nicks);
     void setOwnNick(QString ownNick);
     void setTopic(QString topic);
-    void renderContents();
-    void scrollToEnd();
 
   private slots:
     void enterPressed();
@@ -102,17 +119,14 @@ class BufferWidget : public QWidget {
 
   private:
     Ui::BufferWidget ui;
+    Buffer *parentBuffer;
     bool active;
-    QList<Message> contents;
 
-    QString stdCol, errorCol, noticeCol, joinCol, quitCol, partCol, kickCol, serverCol, nickCol, inactiveCol;
-    QString CSS;
     QString networkName;
     QString bufferName;
 
     bool opsExpanded, voicedExpanded, usersExpanded;
 
-    QString htmlFromMsg(Message);
 };
 
 #endif
diff --git a/gui/channelwidget.cpp b/gui/channelwidget.cpp
deleted file mode 100644 (file)
index 8aeb592..0000000
+++ /dev/null
@@ -1,335 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005 by The Quassel Team                                *
- *   devel@quassel-irc.org                                                 *
- *                                                                         *
- *   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.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
- ***************************************************************************/
-
-#include "channelwidget.h"
-#include "guiproxy.h"
-#include "global.h"
-#include "util.h"
-
-#include <QtGui>
-#include <iostream>
-
-ChannelWidget::ChannelWidget(QString netname, QString bufname, QString own, QWidget *parent) : QWidget(parent) {
-  ui.setupUi(this);
-  _networkName = netname;
-  _bufferName = bufname;
-  ui.ownNick->clear();
-  ui.ownNick->addItem(own);
-  if(bufname.isEmpty()) {
-    // Server Buffer
-    ui.nickTree->hide();
-    ui.topicEdit->hide();
-    ui.chanSettingsButton->hide();
-  }
-  connect(ui.nickTree, SIGNAL(itemExpanded(QTreeWidgetItem *)), this, SLOT(itemExpansionChanged(QTreeWidgetItem*)));
-  connect(ui.nickTree, SIGNAL(itemCollapsed(QTreeWidgetItem *)), this, SLOT(itemExpansionChanged(QTreeWidgetItem*)));
-  connect(ui.inputEdit, SIGNAL(returnPressed()), this, SLOT(enterPressed()));
-  connect(this, SIGNAL(nickListChanged(QStringList)), ui.inputEdit, SLOT(updateNickList(QStringList)));
-  ui.inputEdit->setFocus();
-
-  opsExpanded = voicedExpanded = usersExpanded = true;
-
-  // Define standard colors
-  stdCol = "black";
-  noticeCol = "darkblue";
-  serverCol = "darkblue";
-  errorCol = "red";
-  joinCol = "green";
-  quitCol = "firebrick";
-  partCol = "firebrick";
-  kickCol = "firebrick";
-  nickCol = "magenta";
-
-  completer = 0;
-}
-
-void ChannelWidget::enterPressed() {
-  QStringList lines = ui.inputEdit->text().split('\n', QString::SkipEmptyParts);
-  foreach(QString msg, lines) {
-    if(msg.isEmpty()) continue;
-    emit sendInput(networkName(), bufferName(), msg);
-  }
-  ui.inputEdit->clear();
-}
-
-void ChannelWidget::recvMessage(Message msg) {
-  QString s, n;
-  QString c = stdCol;
-  QString user = userFromMask(msg.sender);
-  QString host = hostFromMask(msg.sender);
-  QString nick = nickFromMask(msg.sender);
-  switch(msg.type) {
-    case Message::Msg:
-      c = stdCol; n = QString("&lt;%1&gt;").arg(nick); s = msg.msg;
-      break;
-    case Message::Server:
-      c = serverCol; s = msg.msg;
-      break;
-    case Message::Error:
-      c = errorCol; s = msg.msg;
-      break;
-    case Message::Join:
-      c = joinCol;
-      s = QString(tr("--> %1 (%2@%3) has joined %4")).arg(nick).arg(user).arg(host).arg(bufferName());
-      break;
-    case Message::Part:
-      c = partCol;
-      s = QString(tr("<-- %1 (%2@%3) has left %4")).arg(nick).arg(user).arg(host).arg(bufferName());
-      if(!msg.msg.isEmpty()) s = QString("%1 (%2)").arg(s).arg(msg.msg);
-      break;
-    case Message::Kick:
-      { c = kickCol;
-        QString victim = msg.msg.section(" ", 0, 0);
-        if(victim == ui.ownNick->currentText()) victim = tr("you");
-        QString kickmsg = msg.msg.section(" ", 1);
-        s = QString(tr("--> %1 has kicked %2 from %3")).arg(nick).arg(victim).arg(bufferName());
-        if(!kickmsg.isEmpty()) s = QString("%1 (%2)").arg(s).arg(kickmsg);
-      }
-      break;
-    case Message::Quit:
-      c = quitCol;
-      s = QString(tr("<-- %1 (%2@%3) has quit")).arg(nick).arg(user).arg(host);
-      if(!msg.msg.isEmpty()) s = QString("%1 (%2)").arg(s).arg(msg.msg);
-      break;
-    case Message::Nick:
-      c = nickCol;
-      if(nick == msg.msg) s = QString(tr("<-> You are now known as %1")).arg(msg.msg);
-      else s = QString(tr("<-> %1 is now known as %2")).arg(nick).arg(msg.msg);
-      break;
-    case Message::Mode:
-      c = serverCol;
-      if(nick.isEmpty()) s = tr("*** User mode: %1").arg(msg.msg);
-      else s = tr("*** Mode %1 by %2").arg(msg.msg).arg(nick);
-      break;
-    default:
-      c = stdCol; n = QString("[%1]").arg(msg.sender); s = msg.msg;
-      break;
-  }
-  s.replace('&', "&amp;"); s.replace('<', "&lt;"); s.replace('>', "&gt;");
-  QString html = QString("<table cellspacing=0 cellpadding=0><tr>"
-      "<td width=50><div style=\"color:%2;\">[%1]</div></td>")
-      .arg(msg.timeStamp.toLocalTime().toString("hh:mm:ss")).arg("darkblue");
-  if(!n.isEmpty())
-    html += QString("<td width=150><div align=right style=\"white-space:pre;margin-left:6px;color:%2;\">%1</div></td>")
-        .arg(n).arg("royalblue");
-  html += QString("<td><div style=\"white-space:pre-wrap;margin-left:6px;color:%2;\">%1</div></td>""</tr></table>").arg(s).arg(c);
-  ui.chatWidget->append(html); // qDebug() << html;
-  //ui.chatWidget->append(QString("<table border=1 cellspacing=0 cellpadding=0><tr><td>%1</td><td width=100 style=border-right-width:1px;><div style=margin-left:8px; margin-right:8px;>%2</div></td><td style=color:firebrick>&nbsp;%3</td></tr></table>")
-      //.arg(msg.timeStamp.toLocalTime().toString("hh:mm:ss")).arg(nick).arg(s));
-  ui.chatWidget->ensureCursorVisible();
-}
-
-void ChannelWidget::recvStatusMsg(QString msg) {
-  ui.chatWidget->insertPlainText(QString("[STATUS] %1").arg(msg));
-  ui.chatWidget->ensureCursorVisible();
-}
-
-void ChannelWidget::setTopic(QString topic) {
-  ui.topicEdit->setText(topic);
-}
-
-void ChannelWidget::setNicks(QStringList nicks) {
-
-
-}
-
-void ChannelWidget::addNick(QString nick, VarMap props) {
-  nicks[nick] = props;
-  updateNickList();
-  if(completer) delete completer;
-  completer = new QCompleter(nicks.keys());
-  ui.inputEdit->setCompleter(completer);
-}
-
-void ChannelWidget::updateNick(QString nick, VarMap props) {
-  nicks[nick] = props;
-  updateNickList();
-}
-
-void ChannelWidget::renameNick(QString oldnick, QString newnick) {
-  QVariant v = nicks.take(oldnick);
-  nicks[newnick] = v;
-  updateNickList();
-}
-
-void ChannelWidget::removeNick(QString nick) {
-  nicks.remove(nick);
-  updateNickList();
-}
-
-void ChannelWidget::setOwnNick(QString nick) {
-  ui.ownNick->clear();
-  ui.ownNick->addItem(nick);
-}
-
-void ChannelWidget::updateNickList() {
-  ui.nickTree->clear();
-  if(nicks.count() != 1) ui.nickTree->setHeaderLabel(tr("%1 Users").arg(nicks.count()));
-  else ui.nickTree->setHeaderLabel(tr("1 User"));
-  QTreeWidgetItem *ops = new QTreeWidgetItem();
-  QTreeWidgetItem *voiced = new QTreeWidgetItem();
-  QTreeWidgetItem *users = new QTreeWidgetItem();
-  // To sort case-insensitive, we have to put all nicks in a map which is sorted by (lowercase) key...
-  QMap<QString, QString> sorted;
-  foreach(QString n, nicks.keys()) { sorted[n.toLower()] = n; }
-  foreach(QString n, sorted.keys()) {
-    QString nick = sorted[n];
-    QString mode = nicks[nick].toMap()["Channels"].toMap()[bufferName()].toMap()["Mode"].toString();
-    if(mode.contains('o')) { new QTreeWidgetItem(ops, QStringList(QString("@%1").arg(nick))); }
-    else if(mode.contains('v')) { new QTreeWidgetItem(voiced, QStringList(QString("+%1").arg(nick))); }
-    else new QTreeWidgetItem(users, QStringList(nick));
-  }
-  if(ops->childCount()) {
-    ops->setText(0, tr("%1 Operators").arg(ops->childCount()));
-   ui.nickTree->addTopLevelItem(ops);
-    ops->setExpanded(opsExpanded);
-  } else delete ops;
-  if(voiced->childCount()) {
-    voiced->setText(0, tr("%1 Voiced").arg(voiced->childCount()));
-    ui.nickTree->addTopLevelItem(voiced);
-    voiced->setExpanded(voicedExpanded);
-  } else delete voiced;
-  if(users->childCount()) {
-    users->setText(0, tr("%1 Users").arg(users->childCount()));
-    ui.nickTree->addTopLevelItem(users);
-    users->setExpanded(usersExpanded);
-  } else delete users;
-}
-
-void ChannelWidget::itemExpansionChanged(QTreeWidgetItem *item) {
-  if(item->child(0)->text(0).startsWith('@')) opsExpanded = item->isExpanded();
-  else if(item->child(0)->text(0).startsWith('+')) voicedExpanded = item->isExpanded();
-  else usersExpanded = item->isExpanded();
-}
-
-/**********************************************************************************************/
-
-
-IrcWidget::IrcWidget(QWidget *parent) : QWidget(parent) {
-  ui.setupUi(this);
-  ui.tabWidget->removeTab(0);
-
-  connect(guiProxy, SIGNAL(csDisplayMsg(QString, QString, Message)), this, SLOT(recvMessage(QString, QString, Message)));
-  connect(guiProxy, SIGNAL(csDisplayStatusMsg(QString, QString)), this, SLOT(recvStatusMsg(QString, QString)));
-  connect(guiProxy, SIGNAL(csTopicSet(QString, QString, QString)), this, SLOT(setTopic(QString, QString, QString)));
-  connect(guiProxy, SIGNAL(csSetNicks(QString, QString, QStringList)), this, SLOT(setNicks(QString, QString, QStringList)));
-  connect(guiProxy, SIGNAL(csNickAdded(QString, QString, VarMap)), this, SLOT(addNick(QString, QString, VarMap)));
-  connect(guiProxy, SIGNAL(csNickRemoved(QString, QString)), this, SLOT(removeNick(QString, QString)));
-  connect(guiProxy, SIGNAL(csNickRenamed(QString, QString, QString)), this, SLOT(renameNick(QString, QString, QString)));
-  connect(guiProxy, SIGNAL(csNickUpdated(QString, QString, VarMap)), this, SLOT(updateNick(QString, QString, VarMap)));
-  connect(guiProxy, SIGNAL(csOwnNickSet(QString, QString)), this, SLOT(setOwnNick(QString, QString)));
-  connect(this, SIGNAL(sendInput( QString, QString, QString )), guiProxy, SLOT(gsUserInput(QString, QString, QString)));
-}
-
-ChannelWidget * IrcWidget::getBuffer(QString net, QString buf) {
-  QString key = net + buf;
-  if(!buffers.contains(key)) {
-    ChannelWidget *cw = new ChannelWidget(net, buf, ownNick[net]);
-    connect(cw, SIGNAL(sendInput(QString, QString, QString)), this, SLOT(userInput(QString, QString, QString)));
-    ui.tabWidget->addTab(cw, net+buf);
-    ui.tabWidget->setCurrentWidget(cw);
-    cw->setFocus();
-    buffers[key] = cw;
-  }
-  return buffers[key];
-}
-
-
-void IrcWidget::recvMessage(QString net, QString buf, Message msg) {
-  ChannelWidget *cw = getBuffer(net, buf);
-  cw->recvMessage(msg);
-}
-
-void IrcWidget::recvStatusMsg(QString net, QString msg) {
-  recvMessage(net, "", Message(Message::Server, QString("[STATUS] %1").arg(msg)));
-
-}
-
-void IrcWidget::userInput(QString net, QString buf, QString msg) {
-  emit sendInput(net, buf, msg);
-}
-
-void IrcWidget::setTopic(QString net, QString buf, QString topic) {
-  ChannelWidget *cw = getBuffer(net, buf);
-  cw->setTopic(topic);
-}
-
-void IrcWidget::setNicks(QString net, QString buf, QStringList nicks) {
-  ChannelWidget *cw = getBuffer(net, buf);
-  cw->setNicks(nicks);
-}
-
-void IrcWidget::addNick(QString net, QString nick, VarMap props) {
-  VarMap netnicks = nicks[net].toMap();
-  netnicks[nick] = props;
-  nicks[net] = netnicks;
-  VarMap chans = props["Channels"].toMap();
-  QStringList c = chans.keys();
-  foreach(QString bufname, c) {
-    getBuffer(net, bufname)->addNick(nick, props);
-  }
-}
-
-void IrcWidget::renameNick(QString net, QString oldnick, QString newnick) {
-  VarMap netnicks = nicks[net].toMap();
-  qDebug() << "renNICK:"<<oldnick<<newnick;
-  Q_ASSERT(netnicks.contains(oldnick));
-  QStringList chans = netnicks[oldnick].toMap()["Channels"].toMap().keys(); qDebug() << "l:" << chans;
-  foreach(QString c, chans) {
-    qDebug() << net << c;
-    getBuffer(net, c)->renameNick(oldnick, newnick);
-  }
-  QVariant v = netnicks.take(oldnick);
-  netnicks[newnick] = v;
-  nicks[net] = netnicks;
-}
-
-void IrcWidget::updateNick(QString net, QString nick, VarMap props) {
-  QStringList oldchans = nicks[net].toMap()[nick].toMap()["Channels"].toMap().keys();
-  QStringList newchans = props["Channels"].toMap().keys();
-  foreach(QString c, newchans) {
-    if(oldchans.contains(c)) getBuffer(net, c)->updateNick(nick, props);
-    else getBuffer(net, c)->addNick(nick, props);
-  }
-  foreach(QString c, oldchans) {
-    if(!newchans.contains(c)) getBuffer(net, c)->removeNick(nick);
-  }
-  VarMap netnicks = nicks[net].toMap();
-  netnicks[nick] = props;
-  nicks[net] = netnicks;
-}
-
-void IrcWidget::removeNick(QString net, QString nick) {
-  VarMap chans = nicks[net].toMap()[nick].toMap()["Channels"].toMap();
-  foreach(QString bufname, chans.keys()) {
-    getBuffer(net, bufname)->removeNick(nick);
-  }
-  VarMap netnicks = nicks[net].toMap();
-  netnicks.remove(nick);
-  nicks[net] = netnicks;
-}
-
-void IrcWidget::setOwnNick(QString net, QString nick) {
-  ownNick[net] = nick;
-  foreach(ChannelWidget *cw, buffers.values()) {
-    if(cw->networkName() == net) cw->setOwnNick(nick);
-  }
-}
-
diff --git a/gui/channelwidget.h b/gui/channelwidget.h
deleted file mode 100644 (file)
index 936cf5f..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005 by The Quassel Team                                *
- *   devel@quassel-irc.org                                                 *
- *                                                                         *
- *   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.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
- ***************************************************************************/
-
-#ifndef _CHANNELWIDGET_H_
-#define _CHANNELWIDGET_H_
-
-#include "ui_channelwidget.h"
-#include "ui_ircwidget.h"
-
-#include "global.h"
-#include "message.h"
-
-class ChannelWidget : public QWidget {
-  Q_OBJECT
-
-  public:
-    ChannelWidget(QString netname, QString bufname, QString ownNick, QWidget *parent = 0);
-
-    QString bufferName() { return _bufferName; }
-    QString networkName() { return _networkName; }
-
-  signals:
-    void sendInput(QString, QString, QString);
-    void nickListChanged(QStringList);
-
-  public slots:
-    void recvMessage(Message);
-    void recvStatusMsg(QString msg);
-    void setTopic(QString);
-    void setNicks(QStringList);
-    void addNick(QString nick, VarMap props);
-    void renameNick(QString oldnick, QString newnick);
-    void removeNick(QString nick);
-    void updateNick(QString nick, VarMap props);
-    void setOwnNick(QString nick);
-
-
-  private slots:
-    void enterPressed();
-    void updateNickList();
-
-    void itemExpansionChanged(QTreeWidgetItem *);
-
-  private:
-    Ui::ChannelWidget ui;
-
-    QString stdCol, errorCol, noticeCol, joinCol, quitCol, partCol, kickCol, serverCol, nickCol;
-    QString CSS;
-    QString _networkName;
-    QString _bufferName;
-    VarMap nicks;
-
-    QCompleter *completer;
-
-    bool opsExpanded, voicedExpanded, usersExpanded;
-};
-
-/** Temporary widget for displaying a set of ChannelWidgets. */
-class IrcWidget : public QWidget {
-  Q_OBJECT
-
-  public:
-    IrcWidget(QWidget *parent = 0);
-
-  public slots:
-    void recvMessage(QString network, QString buffer, Message message);
-    void recvStatusMsg(QString network, QString message);
-    void setTopic(QString, QString, QString);
-    void setNicks(QString, QString, QStringList);
-    void addNick(QString net, QString nick, VarMap props);
-    void removeNick(QString net, QString nick);
-    void renameNick(QString net, QString oldnick, QString newnick);
-    void updateNick(QString net, QString nick, VarMap props);
-    void setOwnNick(QString net, QString nick);
-
-  signals:
-    void sendInput(QString network, QString buffer, QString message);
-
-  private slots:
-    void userInput(QString, QString, QString);
-
-  private:
-    Ui::IrcWidget ui;
-    QHash<QString, ChannelWidget *> buffers;
-    VarMap nicks;
-    QHash<QString, QString> ownNick;
-
-    ChannelWidget * getBuffer(QString net, QString buf);
-};
-
-#endif
diff --git a/gui/chatwidget.cpp b/gui/chatwidget.cpp
new file mode 100644 (file)
index 0000000..03a9d1f
--- /dev/null
@@ -0,0 +1,577 @@
+/***************************************************************************
+ *   Copyright (C) 2005-07 by The Quassel Team                             *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   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.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#include "util.h"
+#include "style.h"
+#include "chatwidget.h"
+#include <QtGui>
+#include <QtCore>
+
+ChatWidget::ChatWidget(QWidget *parent) : QScrollArea(parent) {
+  setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+  setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
+  setAlignment(Qt::AlignLeft | Qt::AlignTop);
+
+}
+
+void ChatWidget::init(QString netname, QString bufname, ChatWidgetContents *contentsWidget) {
+  networkName = netname;
+  bufferName = bufname;
+  //setAlignment(Qt::AlignBottom);
+  contents = contentsWidget;
+  setWidget(contents);
+  //setWidgetResizable(true);
+  //contents->setWidth(contents->sizeHint().width());
+  contents->setFocusProxy(this);
+  //contents->show();
+  //setAlignment(Qt::AlignBottom);
+}
+
+ChatWidget::~ChatWidget() {
+
+}
+
+void ChatWidget::clear() {
+  //contents->clear();
+}
+
+void ChatWidget::appendMsg(Message msg) {
+  contents->appendMsg(msg);
+  //qDebug() << "appending" << msg.text;
+
+}
+
+void ChatWidget::resizeEvent(QResizeEvent *event) {
+  //qDebug() << bufferName << isVisible() << event->size();
+  contents->setWidth(event->size().width());
+  //setAlignment(Qt::AlignBottom);
+  QScrollArea::resizeEvent(event);
+}
+
+/*************************************************************************************/
+
+ChatWidgetContents::ChatWidgetContents(QString net, QString buf, QWidget *parent) : QWidget(parent) {
+  networkName = net;
+  bufferName = buf;
+  layoutTimer = new QTimer(this);
+  layoutTimer->setSingleShot(true);
+  connect(layoutTimer, SIGNAL(timeout()), this, SLOT(triggerLayout()));
+
+  setBackgroundRole(QPalette::Base);
+  setFont(QFont("Fixed"));
+
+  ycoords.append(0);
+  tsWidth = 90;
+  senderWidth = 100;
+  //textWidth = 400;
+  computePositions();
+  //setFixedWidth((int)(tsWidth + senderWidth + textWidth + 20));
+  setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+  setMouseTracking(true);
+  mouseMode = Normal;
+  selectionMode = NoSelection;
+
+  doLayout = false;
+}
+
+ChatWidgetContents::~ChatWidgetContents() {
+  delete layoutTimer;
+  foreach(ChatLine *l, lines) {
+    delete l;
+  }
+}
+
+QSize ChatWidgetContents::sizeHint() const {
+  //qDebug() << size();
+  return size();
+}
+
+void ChatWidgetContents::paintEvent(QPaintEvent *event) {
+  QPainter painter(this);
+  qreal top = event->rect().top();
+  qreal bot = top + event->rect().height();
+  int idx = yToLineIdx(top);
+  if(idx < 0) return;
+  for(int i = idx; i < lines.count() ; i++) {
+    lines[i]->draw(&painter, QPointF(0, ycoords[i]));
+    if(ycoords[i+1] > bot) return;
+  }
+}
+
+void ChatWidgetContents::appendMsg(Message msg) {
+  ChatLine *line = new ChatLine(msg, networkName, bufferName);
+  qreal h = line->layout(tsWidth, senderWidth, textWidth);
+  ycoords.append(h + ycoords[ycoords.count() - 1]);
+  setFixedHeight((int)ycoords[ycoords.count()-1]);
+  lines.append(line);
+  update();
+  return;
+
+}
+
+void ChatWidgetContents::clear() {
+
+
+}
+
+//!\brief Computes the different x position vars for given tsWidth and senderWidth.
+void ChatWidgetContents::computePositions() {
+  senderX = tsWidth + Style::sepTsSender();
+  textX = senderX + senderWidth + Style::sepSenderText();
+  tsGrabPos = tsWidth + (int)Style::sepTsSender()/2;
+  senderGrabPos = senderX + senderWidth + (int)Style::sepSenderText()/2;
+  textWidth = size().width() - textX;
+}
+
+void ChatWidgetContents::setWidth(qreal w) {
+  textWidth = (int)w - (Style::sepTsSender() + Style::sepSenderText()) - tsWidth - senderWidth;
+  setFixedWidth((int)w);
+  layout();
+}
+
+//!\brief Trigger layout (used by layoutTimer only).
+/** This method is triggered by the layoutTimer. Layout the widget if it has been postponed earlier.
+ */
+void ChatWidgetContents::triggerLayout() {
+  layout(true);
+}
+
+//!\brief Layout the widget.
+/** The contents of the widget is re-layouted completely. Since this could take a while if the widget
+ * is huge, we don't want to trigger the layout procedure too often (causing layout calls to pile up).
+ * We use a timer that ensures layouting is only done if the last one has finished.
+ */
+void ChatWidgetContents::layout(bool timer) {
+  if(layoutTimer->isActive()) {
+    // Layouting too fast. We set a flag though, so that a final layout is done when the timer runs out.
+    doLayout = true;
+    return;
+  }
+  if(timer && !doLayout) return; // Only check doLayout if we have been triggered by the timer!
+  qreal y = 0;
+  for(int i = 0; i < lines.count(); i++) {
+    qreal h = lines[i]->layout(tsWidth, senderWidth, textWidth);
+    ycoords[i+1] = h + ycoords[i];
+  }
+  setFixedHeight((int)ycoords[ycoords.count()-1]);
+  update();
+  doLayout = false; // Clear previous layout requests
+  layoutTimer->start(50); // Minimum time until we start the next layout
+}
+
+int ChatWidgetContents::yToLineIdx(qreal y) {
+  if(y >= ycoords[ycoords.count()-1]) ycoords.count()-1;
+  if(ycoords.count() <= 1) return 0;
+  int uidx = 0;
+  int oidx = ycoords.count() - 1;
+  int idx;
+  while(1) {
+    if(uidx == oidx - 1) return uidx;
+    idx = (uidx + oidx) / 2;
+    if(ycoords[idx] > y) oidx = idx;
+    else uidx = idx;
+  }
+}
+
+void ChatWidgetContents::mousePressEvent(QMouseEvent *event) {
+  if(event->button() == Qt::LeftButton) {
+    dragStartPos = event->pos();
+    dragStartMode = Normal;
+    switch(mouseMode) {
+      case Normal:
+        if(mousePos == OverTsSep) {
+          dragStartMode = DragTsSep;
+          setCursor(Qt::ClosedHandCursor);
+        } else if(mousePos == OverTextSep) {
+          dragStartMode = DragTextSep;
+          setCursor(Qt::ClosedHandCursor);
+        } else {
+          dragStartLine = yToLineIdx(event->pos().y());
+          dragStartCursor = lines[dragStartLine]->posToCursor(QPointF(event->pos().x(), event->pos().y()-ycoords[dragStartLine]));
+        }
+        mouseMode = Pressed;
+        break;
+    }
+  }
+}
+
+void ChatWidgetContents::mouseReleaseEvent(QMouseEvent *event) {
+  if(event->button() == Qt::LeftButton) {
+    dragStartPos = QPoint();
+    if(mousePos == OverTsSep || mousePos == OverTextSep) setCursor(Qt::OpenHandCursor);
+    else setCursor(Qt::ArrowCursor);
+
+    switch(mouseMode) {
+      case Pressed:
+        mouseMode = Normal;
+        clearSelection();
+        break;
+      case MarkText:
+        mouseMode = Normal;
+        selectionMode = TextSelected;
+        selectionLine = dragStartLine;
+        selectionStart = qMin(dragStartCursor, curCursor);
+        selectionEnd = qMax(dragStartCursor, curCursor);
+        // TODO Make X11SelectionMode configurable!
+        QApplication::clipboard()->setText(selectionToString());
+        break;
+      case MarkLines:
+        mouseMode = Normal;
+        selectionMode = LinesSelected;
+        selectionStart = qMin(dragStartLine, curLine);
+        selectionEnd = qMax(dragStartLine, curLine);
+        // TODO Make X11SelectionMode configurable!
+        QApplication::clipboard()->setText(selectionToString());
+        break;
+      default:
+        mouseMode = Normal;
+    }
+  }
+}
+
+//!\brief React to mouse movements over the ChatWidget.
+/** This is called by Qt whenever the mouse moves. Here we have to do most of the mouse handling,
+ * such as changing column widths, marking text or initiating drag & drop.
+ */
+void ChatWidgetContents::mouseMoveEvent(QMouseEvent *event) {
+  // Set some basic properties of the current position
+  int x = event->pos().x();
+  int y = event->pos().y();
+  MousePos oldpos = mousePos;
+  if(x >= tsGrabPos - 3 && x <= tsGrabPos + 3) mousePos = OverTsSep;
+  else if(x >= senderGrabPos - 3 && x <= senderGrabPos + 3) mousePos = OverTextSep;
+  else mousePos = None;
+
+  // Pass 1: Do whatever we can before switching mouse mode (if at all).
+  switch(mouseMode) {
+    // No special mode. Set mouse cursor if appropriate.
+    case Normal:
+      if(oldpos != mousePos) {
+        if(mousePos == OverTsSep || mousePos == OverTextSep) setCursor(Qt::OpenHandCursor);
+        else setCursor(Qt::ArrowCursor);
+      }
+      break;
+    // Left button pressed. Might initiate marking or drag & drop if we moved past the drag distance.
+    case Pressed:
+      if(!dragStartPos.isNull() && (dragStartPos - event->pos()).manhattanLength() >= QApplication::startDragDistance()) {
+        // Moving a column separator?
+        if(dragStartMode == DragTsSep) mouseMode = DragTsSep;
+        else if(dragStartMode == DragTextSep) mouseMode = DragTextSep;
+        // Nope. Check if we are over a selection to start drag & drop.
+        else if(dragStartMode == Normal) {
+          bool dragdrop = false;
+          if(selectionMode == TextSelected) {
+            int l = yToLineIdx(y);
+            if(selectionLine == l) {
+              int p = lines[l]->posToCursor(QPointF(x, y - ycoords[l]));
+              if(p >= selectionStart && p <= selectionEnd) dragdrop = true;
+            }
+          } else if(selectionMode == LinesSelected) {
+            int l = yToLineIdx(y);
+            if(l >= selectionStart && l <= selectionEnd) dragdrop = true;
+          }
+          // Ok, so just start drag & drop if appropriate.
+          if(dragdrop) {
+            QDrag *drag = new QDrag(this);
+            QMimeData *mimeData = new QMimeData;
+            mimeData->setText(selectionToString());
+            drag->setMimeData(mimeData);
+            drag->start();
+            mouseMode = Normal;
+          // Otherwise, clear the selection and start text marking!
+          } else {
+            clearSelection();
+            if(dragStartCursor < 0) { mouseMode = MarkLines; curLine = -1; }
+            else mouseMode = MarkText;
+          }
+        }
+      }
+      break;
+    case DragTsSep:
+      break;
+    case DragTextSep:
+      break;
+  }
+  // Pass 2: Some mouse modes need work after being set...
+  if(mouseMode == DragTsSep && x < size().width() - Style::sepSenderText() - senderWidth - 10) {
+    // Drag first column separator
+    int foo = Style::sepTsSender()/2;
+    tsWidth = qMax(x, foo) - foo;
+    computePositions();
+    layout();
+  } else if(mouseMode == DragTextSep && x < size().width() - 10) {
+    // Drag second column separator
+    int foo = tsWidth + Style::sepTsSender() + Style::sepSenderText()/2;
+    senderWidth = qMax(x, foo) - foo;
+    computePositions();
+    layout();
+  } else if(mouseMode == MarkText) {
+    // Change currently marked text
+    curLine = yToLineIdx(y);
+    int c = lines[curLine]->posToCursor(QPointF(x, y - ycoords[curLine]));
+    if(curLine == dragStartLine && c >= 0) {
+      if(c != curCursor) {
+        curCursor = c;
+        lines[curLine]->setSelection(ChatLine::Partial, dragStartCursor, c);
+        update();
+      }
+    } else {
+      mouseMode = MarkLines;
+      selectionStart = qMin(curLine, dragStartLine); selectionEnd = qMax(curLine, dragStartLine);
+      for(int i = selectionStart; i <= selectionEnd; i++) lines[i]->setSelection(ChatLine::Full);
+      update();
+    }
+  } else if(mouseMode == MarkLines) {
+    // Line marking
+    int l = yToLineIdx(y);
+    if(l != curLine) {
+      selectionStart = qMin(l, dragStartLine); selectionEnd = qMax(l, dragStartLine);
+      if(curLine >= 0 && curLine < selectionStart) {
+        for(int i = curLine; i < selectionStart; i++) lines[i]->setSelection(ChatLine::None);
+      } else if(curLine > selectionEnd) {
+        for(int i = selectionEnd+1; i <= curLine; i++) lines[i]->setSelection(ChatLine::None);
+      } else if(selectionStart < curLine && l < curLine) {
+          for(int i = selectionStart; i < curLine; i++) lines[i]->setSelection(ChatLine::Full);
+      } else if(curLine < selectionEnd && l > curLine) {
+        for(int i = curLine+1; i <= selectionEnd; i++) lines[i]->setSelection(ChatLine::Full);
+      }
+      curLine = l;
+      update();
+    }
+  }
+}
+
+//!\brief Clear current text selection.
+void ChatWidgetContents::clearSelection() {
+  if(selectionMode == TextSelected) {
+    lines[selectionLine]->setSelection(ChatLine::None);
+  } else if(selectionMode == LinesSelected) {
+    for(int i = selectionStart; i <= selectionEnd; i++) {
+      lines[i]->setSelection(ChatLine::None);
+    }
+  }
+  selectionMode = NoSelection;
+  update();
+}
+
+//!\brief Convert current selection to human-readable string.
+QString ChatWidgetContents::selectionToString() {
+  //TODO Make selection format configurable!
+  if(selectionMode == NoSelection) return "";
+  if(selectionMode == LinesSelected) {
+    QString result;
+    for(int l = selectionStart; l <= selectionEnd; l++) {
+      result += QString("[%1] %2 %3\n").arg(lines[l]->getTimeStamp().toLocalTime().toString("hh:mm:ss"))
+          .arg(lines[l]->getSender()).arg(lines[l]->getText());
+    }
+    return result;
+  }
+  // selectionMode == TextSelected
+  return lines[selectionLine]->getText().mid(selectionStart, selectionEnd - selectionStart);
+}
+
+/************************************************************************************/
+
+//!\brief Construct a ChatLine object from a message.
+/**
+ * \param m The message to be layouted and rendered
+ * \param net The network name
+ * \param buf The buffer name
+ */ 
+ChatLine::ChatLine(Message m, QString net, QString buf) : QObject() {
+  hght = 0;
+  networkName = net;
+  bufferName = buf;
+  msg = m;
+  selectionMode = None;
+  formatMsg(msg);
+
+}
+
+ChatLine::~ChatLine() {
+
+}
+
+void ChatLine::formatMsg(Message msg) {
+  QString user = userFromMask(msg.sender);
+  QString host = hostFromMask(msg.sender);
+  QString nick = nickFromMask(msg.sender);
+  QString text = Style::mircToInternal(msg.text);
+
+  QString c = tr("%DT[%1]").arg(msg.timeStamp.toLocalTime().toString("hh:mm:ss"));
+  QString s, t;
+  switch(msg.type) {
+    case Message::Plain:
+      s = tr("%DS<%1>").arg(nick); t = tr("%D0%1").arg(text); break;
+    case Message::Server:
+      s = tr("%Ds*"); t = tr("%Ds%1").arg(text); break;
+    case Message::Error:
+      s = tr("%De*"); t = tr("%De%1").arg(text); break;
+    case Message::Join:
+      s = tr("%Dj-->"); t = tr("%Dj%DN%1%DN %DH(%2@%3)%DH has joined %DC%4%DC").arg(nick, user, host, bufferName); break;
+    case Message::Part:
+      s = tr("%Dp<--"); t = tr("%Dp%DN%1%DN %DH(%2@%3)%DH has left %DC%4%DC").arg(nick, user, host, bufferName);
+      if(!text.isEmpty()) t = QString("%1 (%2)").arg(t).arg(text);
+      break;
+    case Message::Quit:
+      s = tr("%Dq<--"); t = tr("%Dq%DN%1%DN %DH(%2@%3)%DH has quit").arg(nick, user, host);
+      if(!text.isEmpty()) t = QString("%1 (%2)").arg(t).arg(text);
+      break;
+    case Message::Kick:
+      { s = tr("%Dk<-*");
+        QString victim = text.section(" ", 0, 0);
+        //if(victim == ui.ownNick->currentText()) victim = tr("you");
+        QString kickmsg = text.section(" ", 1);
+        t = tr("%Dk%DN%1%DN has kicked %DN%2%DN from %DC%3%DC").arg(nick).arg(victim).arg(bufferName);
+        if(!kickmsg.isEmpty()) t = QString("%1 (%2)").arg(t).arg(kickmsg);
+      }
+      break;
+    case Message::Nick:
+      s = tr("%Dr<->");
+      if(nick == msg.text) t = tr("You are now known as %DN%1%DN").arg(msg.text);
+      else t = tr("%DN%1%DN is now known as %DN%2%DN").arg(nick, msg.text);
+      break;
+    case Message::Mode:
+      s = tr("%Dm***");
+      if(nick.isEmpty()) t = tr("User mode: %DM%1%DM").arg(msg.text);
+      else t = tr("Mode %DM%1%DM by %DN%2%DN").arg(msg.text, nick);
+      break;
+    default:
+      s = tr("%De%1").arg(msg.sender);
+      t = tr("%De[%1]").arg(msg.text);
+  }
+  QTextOption tsOption, senderOption, textOption;
+  tsFormatted = Style::internalToFormatted(c);
+  senderFormatted = Style::internalToFormatted(s);
+  textFormatted = Style::internalToFormatted(t);
+  tsLayout.setText(tsFormatted.text); tsLayout.setAdditionalFormats(tsFormatted.formats);
+  tsOption.setWrapMode(QTextOption::NoWrap);
+  tsLayout.setTextOption(tsOption);
+  senderLayout.setText(senderFormatted.text); senderLayout.setAdditionalFormats(senderFormatted.formats);
+  senderOption.setAlignment(Qt::AlignRight); senderOption.setWrapMode(QTextOption::ManualWrap);
+  senderLayout.setTextOption(senderOption);
+  textLayout.setText(textFormatted.text); textLayout.setAdditionalFormats(textFormatted.formats);
+  textOption.setWrapMode(QTextOption::WrapAnywhere); // seems to do what we want, apparently
+  textLayout.setTextOption(textOption);
+}
+
+//!\brief Return the cursor position for the given coordinate pos.
+/**
+ * \param pos The position relative to the ChatLine
+ * \return The cursor position, or -2 for timestamp, or -1 for sender
+ */
+int ChatLine::posToCursor(QPointF pos) {
+  if(pos.x() < tsWidth + (int)Style::sepTsSender()/2) return -2;
+  qreal textStart = tsWidth + Style::sepTsSender() + senderWidth + Style::sepSenderText();
+  if(pos.x() < textStart) return -1;
+  for(int l = textLayout.lineCount() - 1; l >=0; l--) {
+    QTextLine line = textLayout.lineAt(l);
+    if(pos.y() >= line.position().y()) {
+      int p = line.xToCursor(pos.x() - textStart, QTextLine::CursorOnCharacter);
+      return p;
+    }
+  }
+}
+
+void ChatLine::setSelection(SelectionMode mode, int start, int end) {
+  selectionMode = mode;
+  tsFormat.clear(); senderFormat.clear(); textFormat.clear();
+  QPalette pal = QApplication::palette();
+  QTextLayout::FormatRange tsSel, senderSel, textSel;
+  switch (mode) {
+    case None:
+      break;
+    case Partial:
+      selectionStart = qMin(start, end); selectionEnd = qMax(start, end);
+      textSel.format.setForeground(pal.brush(QPalette::HighlightedText));
+      textSel.format.setBackground(pal.brush(QPalette::Highlight));
+      textSel.start = selectionStart;
+      textSel.length = selectionEnd - selectionStart;
+      textFormat.append(textSel);
+      break;
+    case Full:
+      tsSel.format.setForeground(pal.brush(QPalette::HighlightedText));
+      tsSel.start = 0; tsSel.length = tsLayout.text().length(); tsFormat.append(tsSel);
+      senderSel.format.setForeground(pal.brush(QPalette::HighlightedText));
+      senderSel.start = 0; senderSel.length = senderLayout.text().length(); senderFormat.append(senderSel);
+      textSel.format.setForeground(pal.brush(QPalette::HighlightedText));
+      textSel.start = 0; textSel.length = textLayout.text().length(); textFormat.append(textSel);
+      break;
+  }
+}
+
+QDateTime ChatLine::getTimeStamp() {
+  return msg.timeStamp;
+}
+
+QString ChatLine::getSender() {
+  return senderLayout.text();
+}
+
+QString ChatLine::getText() {
+  return textLayout.text();
+}
+
+qreal ChatLine::layout(qreal tsw, qreal senderw, qreal textw) {
+  tsWidth = tsw; senderWidth = senderw; textWidth = textw;
+  QTextLine tl;
+  tsLayout.beginLayout();
+  tl = tsLayout.createLine();
+  tl.setLineWidth(tsWidth);
+  tl.setPosition(QPointF(0, 0));
+  tsLayout.endLayout();
+
+  senderLayout.beginLayout();
+  tl = senderLayout.createLine();
+  tl.setLineWidth(senderWidth);
+  tl.setPosition(QPointF(0, 0));
+  senderLayout.endLayout();
+
+  qreal h = 0;
+  textLayout.beginLayout();
+  while(1) {
+    tl = textLayout.createLine();
+    if(!tl.isValid()) break;
+    tl.setLineWidth(textWidth);
+    tl.setPosition(QPointF(0, h));
+    h += tl.height();
+  }
+  textLayout.endLayout();
+  hght = h;
+  return h;
+}
+
+//!\brief Draw ChatLine on the given QPainter at the given position.
+void ChatLine::draw(QPainter *p, const QPointF &pos) {
+  QPalette pal = QApplication::palette();
+  if(selectionMode == Full) {
+    p->setPen(Qt::NoPen);
+    p->setBrush(pal.brush(QPalette::Highlight));
+    p->drawRect(QRectF(pos, QSizeF(tsWidth + Style::sepTsSender() + senderWidth + Style::sepSenderText() + textWidth, height())));
+  } else if(selectionMode == Partial) {
+
+  }
+  p->setClipRect(QRectF(pos, QSizeF(tsWidth, height())));
+  tsLayout.draw(p, pos, tsFormat);
+  p->setClipRect(QRectF(pos + QPointF(tsWidth + Style::sepTsSender(), 0), QSizeF(senderWidth, height())));
+  senderLayout.draw(p, pos + QPointF(tsWidth + Style::sepTsSender(), 0), senderFormat);
+  p->setClipping(false);
+  textLayout.draw(p, pos + QPointF(tsWidth + Style::sepTsSender() + senderWidth + Style::sepSenderText(), 0), textFormat);
+}
diff --git a/gui/chatwidget.h b/gui/chatwidget.h
new file mode 100644 (file)
index 0000000..93ee117
--- /dev/null
@@ -0,0 +1,182 @@
+/***************************************************************************
+ *   Copyright (C) 2005/06 by The Quassel Team                             *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   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.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#ifndef _CHATWIDGET_H_
+#define _CHATWIDGET_H_
+
+#include "style.h"
+#include "message.h"
+#include <QtGui>
+
+class ChatWidgetContents;
+
+//!\brief Scroll area showing part of the chat messages for a given buffer.
+/** The contents of the scroll area, i.e. a widget of type ChatWidgetContents,
+ * needs to be provided by calling init(). We don't create this widget ourselves, because
+ * while a ChatWidget will be destroyed and recreated quite often (for example when switching
+ * buffers), there ususally is no need to re-render its content every time (which can be time-consuming).
+ * Before a ChatWidget is destroyed, it gives up its ownership of its contents, referring responsibility
+ * back to where it came from.
+ *
+ * Because we use this as a custom widget in Qt Designer, we cannot use a constructor that takes custom
+ * parameters. Instead, it is mandatory to call init() before using this widget.
+ */
+class ChatWidget : public QScrollArea {
+  Q_OBJECT
+
+  public:
+    ChatWidget(QWidget *parent = 0);
+    ~ChatWidget();
+    void init(QString net, QString buf, ChatWidgetContents *contents);
+
+  public slots:
+    void clear();
+    void appendMsg(Message);
+
+  protected:
+    void resizeEvent(QResizeEvent *event);
+
+  private:
+    QString networkName, bufferName;
+    ChatWidgetContents *contents;
+};
+
+class ChatLine;
+
+//!\brief Renders the complete contents of a Buffer.
+/** Usually, this widget is used within a scroll
+ * area. Because Qt's rich-text rendering engine is much too slow for our purposes, we do everything
+ * except for the actual glyph painting ourselves. While this makes managing text quite cumbersome
+ * (we cannot, for example, use any of Qt's text editing, selecting or layouting features), it is
+ * also orders of magnitudes faster than any of the usual methods.
+ */
+class ChatWidgetContents : public QWidget {
+  Q_OBJECT
+
+  public:
+    ChatWidgetContents(QString net, QString buf, QWidget *parent = 0);
+    ~ChatWidgetContents();
+    //int heightForWidth(int w) const;
+    virtual QSize sizeHint() const;
+
+  public slots:
+    void clear();
+    void appendMsg(Message);
+    void setWidth(qreal);
+
+  protected:
+    virtual void paintEvent(QPaintEvent *event);
+
+  protected slots:
+    virtual void mousePressEvent(QMouseEvent *event);
+    virtual void mouseReleaseEvent(QMouseEvent *event);
+    virtual void mouseMoveEvent(QMouseEvent *event);
+
+  private slots:
+    void layout(bool timer = false);
+    void triggerLayout();
+
+  private:
+    enum SelectionMode { NoSelection, TextSelected, LinesSelected };
+    enum MouseMode { Normal, Pressed, DragTsSep, DragTextSep, MarkText, MarkLines };
+    enum MousePos { None, OverTsSep, OverTextSep, OverUrl };
+    MouseMode mouseMode;
+    MousePos mousePos;
+    QPoint dragStartPos;
+    MouseMode dragStartMode;
+    int dragStartLine;
+    int dragStartCursor;
+    int curCursor;
+    int curLine;
+    SelectionMode selectionMode;
+    int selectionStart, selectionEnd, selectionLine;
+    QString networkName, bufferName;
+    QTimer *layoutTimer;
+    bool doLayout;
+
+    QList<ChatLine *> lines;
+    QList<qreal> ycoords;
+
+    int senderX;
+    int textX;
+    int tsWidth;
+    int senderWidth;
+    int textWidth;
+    int tsGrabPos;     ///< X-Position for changing the timestamp width
+    int senderGrabPos;
+    void computePositions();
+
+    qreal width;
+    qreal height;
+    qreal y;
+
+    int yToLineIdx(qreal y);
+    void clearSelection();
+    QString selectionToString();
+};
+
+//!\brief Containing the layout and providing the rendering of a single message.
+/** A ChatLine takes a Message object,
+ * formats it (by turning the various message types into a human-readable form and afterwards pumping it through
+ * our Style engine), and stores it as a number of QTextLayouts representing the three fields of a chat line
+ * (timestamp, sender and text). These layouts already include any rendering information such as font,
+ * color, or selected characters. By calling layout(), they can be quickly layouted to fit a given set of field widths.
+ * Afterwards, they can quickly be painted whenever necessary.
+ *
+ * By separating the complex and slow task of interpreting and formatting Message objects (which happens exactly once
+ * per message) from the actual layouting and painting, we gain a lot of speed compared to the standard Qt rendering
+ * functions.
+ */
+class ChatLine : public QObject {
+  Q_OBJECT
+
+  public:
+    ChatLine(Message message, QString networkName, QString bufferName);
+    ~ChatLine();
+
+    qreal layout(qreal tsWidth, qreal nickWidth, qreal textWidth);
+    qreal height() { return hght; }
+    int posToCursor(QPointF pos);
+    void draw(QPainter *p, const QPointF &pos);
+
+    enum SelectionMode { None, Partial, Full };
+    void setSelection(SelectionMode, int start = 0, int end = 0);
+    QDateTime getTimeStamp();
+    QString getSender();
+    QString getText();
+  private:
+    qreal hght;
+    Message msg;
+    QString networkName, bufferName;
+    //QString ts, nick, text;
+    qreal tsWidth, senderWidth, textWidth;
+    QTextLayout tsLayout;
+    QTextLayout senderLayout;
+    QTextLayout textLayout;
+    QVector<QTextLayout::FormatRange> tsFormat, senderFormat, textFormat;
+    Style::StringFormats tsFormatted, senderFormatted, textFormatted;
+
+    SelectionMode selectionMode;
+    int selectionStart, selectionEnd;
+    void formatMsg(Message);
+};
+
+
+#endif
index dd1fcb9..e9fe9e4 100644 (file)
@@ -30,6 +30,7 @@
 #include "networkview.h"
 #include "serverlist.h"
 #include "coreconnectdlg.h"
+#include "settings.h"
 
 MainWin::MainWin() : QMainWindow() {
   ui.setupUi(this);
@@ -45,8 +46,8 @@ MainWin::MainWin() : QMainWindow() {
   move(s.value("MainWinPos", QPoint(50, 50)).toPoint());
   s.endGroup();
 
-  workspace = new QWorkspace(this);
-  setCentralWidget(workspace);
+  //workspace = new QWorkspace(this);
+  //setCentralWidget(workspace);
   statusBar()->showMessage(tr("Waiting for core..."));
 
   netView = new NetworkView("", this);
@@ -77,6 +78,8 @@ MainWin::MainWin() : QMainWindow() {
 
   serverListDlg = new ServerListDlg(this);
   serverListDlg->setVisible(serverListDlg->showOnStartup());
+  settingsDlg = new SettingsDlg(this);
+  settingsDlg->setVisible(false);
   setupMenus();
 
   // replay backlog
@@ -112,6 +115,8 @@ MainWin::MainWin() : QMainWindow() {
 void MainWin::setupMenus() {
   connect(ui.actionNetworkList, SIGNAL(triggered()), this, SLOT(showServerList()));
   connect(ui.actionEditIdentities, SIGNAL(triggered()), serverListDlg, SLOT(editIdentities()));
+  connect(ui.actionSettingsDlg, SIGNAL(triggered()), this, SLOT(showSettingsDlg()));
+  ui.actionSettingsDlg->setEnabled(false);
 }
 
 void MainWin::showServerList() {
@@ -121,6 +126,10 @@ void MainWin::showServerList() {
   serverListDlg->show();
 }
 
+void MainWin::showSettingsDlg() {
+  settingsDlg->show();
+}
+
 void MainWin::closeEvent(QCloseEvent *event)
 {
   //if (userReallyWantsToQuit()) {
@@ -145,13 +154,14 @@ void MainWin::showBuffer(QString net, QString buf) {
   QWidget *old = widget;
   widget = b->showWidget(this);
   if(widget == old) return;
-  workspace->addWindow(widget);
-  widget->showMaximized();
-  if(old) { old->close(); old->setParent(this); }
-  workspace->setActiveWindow(widget);
-  //widget->setFocus();
+  //workspace->addWindow(widget);
+  //widget->show();
+  setCentralWidget(widget);
+  widget->show();
+  //workspace->setActiveWindow(widget);
+  widget->setFocus();
   //workspace->setFocus();
-  //widget->activateWindow();
+  widget->activateWindow();
   widget->setFocus(Qt::MouseFocusReason);
   focusNextChild();
   //workspace->tile();
@@ -172,7 +182,7 @@ void MainWin::networkDisconnected(QString net) {
     Buffer *b = getBuffer(net, buf);
     b->displayMsg(Message::server(buf, tr("Server disconnected.")));
     b->setActive(false);
-    
+
   }
   connected[net] = false;
 }
index d899695..2d2516a 100644 (file)
@@ -31,7 +31,13 @@ class ServerListDlg;
 class CoreConnectDlg;
 class NetworkView;
 class Buffer;
+class SettingsDlg;
 
+//!\brief The main window and central object of Quassel GUI.
+/** In addition to displaying the main window including standard stuff like a menubar,
+ * dockwidgets and of course the chat window, this class also stores all data it
+ * receives from the core, and it maintains a list of all known nicks.
+ */
 class MainWin : public QMainWindow {
   Q_OBJECT
 
@@ -61,6 +67,7 @@ class MainWin : public QMainWindow {
     void setOwnNick(QString net, QString nick);
 
     void showServerList();
+    void showSettingsDlg();
 
     void showBuffer(QString net, QString buf);
 
@@ -77,6 +84,7 @@ class MainWin : public QMainWindow {
 
     ServerListDlg *serverListDlg;
     CoreConnectDlg *coreConnectDlg;
+    SettingsDlg *settingsDlg;
 
     QString currentNetwork, currentBuffer;
     QHash<QString, QHash<QString, Buffer*> > buffers;
similarity index 89%
rename from network/buffer.cpp
rename to gui/settings.cpp
index d0b500a..a4efaea 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005/06 by The Quassel Team                             *
+ *   Copyright (C) 2005-07 by The Quassel Team                             *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
 
-/* OBSOLETE */
-
-#include "buffer.h"
-/*
-Buffer::Buffer(QString n) {
-  _name = n;
-
+#include "settings.h"
 
+SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) {
+  ui.setupUi(this);
 
 }
-
-*/
\ No newline at end of file
similarity index 76%
rename from network/builtin_handlers.cpp
rename to gui/settings.h
index 86a41fc..ed9be0e 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005/06 by The Quassel Team                             *
+ *   Copyright (C) 2005-07 by The Quassel Team                             *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
 
-#include "message.h"
+#ifndef _SETTINGS_H_
+#define _SETTINGS_H_
 
+#include <QtGui>
+#include "ui_settingsdlg.h"
+
+#include "plugin.h"
+
+class SettingsDlg : public QDialog {
+  Q_OBJECT
+  public:
+    SettingsDlg(QWidget *parent = 0);
+    void registerSettingsPage(SettingsInterface *);
+    void unregisterSettingsPage(SettingsInterface *);
+
+
+  private:
+    Ui::SettingsDlg ui;
+
+
+};
+
+#endif
diff --git a/gui/style.cpp b/gui/style.cpp
new file mode 100644 (file)
index 0000000..8837872
--- /dev/null
@@ -0,0 +1,256 @@
+/***************************************************************************
+ *   Copyright (C) 2005-07 by The Quassel Team                             *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   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.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#include "style.h"
+
+void Style::init() {
+   // Colors (mIRC standard)
+  colors["00"] = QColor("white");
+  colors["01"] = QColor("black");
+  colors["02"] = QColor("navy");
+  colors["03"] = QColor("green");
+  colors["04"] = QColor("red");
+  colors["05"] = QColor("maroon");
+  colors["06"] = QColor("purple");
+  colors["07"] = QColor("orange");
+  colors["08"] = QColor("yellow");
+  colors["09"] = QColor("lime");
+  colors["10"] = QColor("teal");
+  colors["11"] = QColor("aqua");
+  colors["12"] = QColor("royalblue");
+  colors["13"] = QColor("fuchsia");
+  colors["14"] = QColor("grey");
+  colors["15"] = QColor("silver");
+
+  QTextCharFormat def;
+  //def.setFont(QFont("Lucida Mono"));
+  formats["default"] = def;
+
+  // %B - 0x02 - bold
+  QTextCharFormat bold;
+  bold.setFontWeight(QFont::Bold);
+  formats["%B"] = bold;
+
+  // %O - 0x0f - plain
+  formats["%O"] = QTextCharFormat();
+
+  // %R - 0x12 - reverse
+  // -- - 0x16 - reverse
+  // (no format)
+
+  // %S - 0x1d - italic
+  QTextCharFormat italic;
+  italic.setFontItalic(true);
+  formats["%S"] = italic;
+
+  // %U - 0x1f - underline
+  QTextCharFormat underline;
+  underline.setFontUnderline(true);
+  formats["%U"] = underline;
+
+  // %C - 0x03 - mIRC colors
+  for(uint i = 0; i < 16; i++) {
+    QString idx = QString("%1").arg(i, (int)2, (int)10, (QChar)'0');
+    QString fg = QString("%C%1").arg(idx);
+    QString bg = QString("%C,%1").arg(idx);
+    QTextCharFormat fgf; fgf.setForeground(QBrush(colors[idx])); formats[fg] = fgf;
+    QTextCharFormat bgf; bgf.setBackground(QBrush(colors[idx])); formats[bg] = bgf;
+  }
+
+  // Internal formats - %D<char>
+  // %D0 - plain msg
+  QTextCharFormat plainMsg;
+  plainMsg.setForeground(QBrush("black"));
+  formats["%D0"] = plainMsg;
+  // %Dn - notice
+  QTextCharFormat notice;
+  notice.setForeground(QBrush("navy"));
+  formats["%Dn"] = notice;
+  // %Ds - server msg
+  QTextCharFormat server;
+  server.setForeground(QBrush("navy"));
+  formats["%Ds"] = server;
+  // %De - error msg
+  QTextCharFormat error;
+  error.setForeground(QBrush("red"));
+  formats["%De"] = error;
+  // %Dj - join
+  QTextCharFormat join;
+  join.setForeground(QBrush("green"));
+  formats["%Dj"] = join;
+  // %Dp - part
+  QTextCharFormat part;
+  part.setForeground(QBrush("firebrick"));
+  formats["%Dp"] = part;
+  // %Dq - quit
+  QTextCharFormat quit;
+  quit.setForeground(QBrush("firebrick"));
+  formats["%Dq"] = quit;
+  // %Dk - kick
+  QTextCharFormat kick;
+  kick.setForeground(QBrush("firebrick"));
+  formats["%Dk"] = kick;
+  // %Dr - nick rename
+  QTextCharFormat nren;
+  nren.setForeground(QBrush("magenta"));
+  formats["%Dr"] = nren;
+  // %Dm - mode change
+  QTextCharFormat mode;
+  mode.setForeground(QBrush("steelblue"));
+  formats["%Dm"] = mode;
+
+  // %DT - timestamp
+  QTextCharFormat ts;
+  ts.setForeground(QBrush("grey"));
+  formats["%DT"] = ts;
+  // %DS - sender
+  QTextCharFormat sender;
+  sender.setAnchor(true);
+  sender.setForeground(QBrush("navy"));
+  formats["%DS"] = sender;
+  // %DN - nickname
+  QTextCharFormat nick;
+  nick.setAnchor(true);
+  nick.setFontWeight(QFont::Bold);
+  formats["%DN"] = nick;
+  // %DH - hostmask
+  QTextCharFormat hostmask;
+  hostmask.setFontItalic(true);
+  formats["%DH"] = hostmask;
+  // %DC - channame
+  QTextCharFormat channel;
+  channel.setAnchor(true);
+  channel.setFontWeight(QFont::Bold);
+  formats["%DC"] = channel;
+  // %DM - modeflags
+  QTextCharFormat flags;
+  flags.setFontWeight(QFont::Bold);
+  formats["%DM"] = flags;
+
+}
+
+QString Style::mircToInternal(QString mirc) {
+  mirc.replace('%', "%%");      // escape % just to be sure
+  mirc.replace('\x02', "%B");
+  mirc.replace('\x03', "%C");
+  mirc.replace('\x0f', "%O");
+  mirc.replace('\x12', "%R");
+  mirc.replace('\x16', "%R");
+  mirc.replace('\x1d', "%S");
+  mirc.replace('\x1f', "%U");
+  return mirc;
+}
+
+/** Returns a string stripped of format codes, and a list of FormatRange objects
+ *  describing the formats of the string.
+ * \param s string in internal format (% style format codes)
+ */ 
+Style::StringFormats Style::internalToFormatted(QString s) {
+  QHash<QString, int> toggles;
+  QString p;
+  StringFormats sf;
+  QTextLayout::FormatRange rng;
+  rng.format = formats["default"]; rng.start = 0; rng.length = -1; sf.formats.append(rng);
+  toggles["default"] = sf.formats.count() - 1;
+  int i, j;
+  for(i = 0, j = 0; i < s.length(); i++) {
+    if(s[i] != '%') { p += s[i]; j++; continue; }
+    i++;
+    if(s[i] == '%') { p += '%'; j++; continue; }
+    else if(s[i] == 'C') {
+      if(!s[i+1].isDigit() && s[i+1] != ',') {
+        if(toggles.contains("bg")) {
+          sf.formats[toggles["bg"]].length = j - sf.formats[toggles["bg"]].start;
+          toggles.remove("bg");
+        }
+      }
+      if(s[i+1].isDigit() || s[i+1] != ',') {
+        if(toggles.contains("fg")) {
+          sf.formats[toggles["fg"]].length = j - sf.formats[toggles["fg"]].start;
+          toggles.remove("fg");
+        }
+        if(s[i+1].isDigit()) {
+          QString n(s[++i]);
+          if(s[i+1].isDigit()) n += s[++i];
+          int num = n.toInt() & 0xf;
+          n = QString("%C%1").arg(num, (int)2, (int)10, (QChar)'0');
+          //qDebug() << n << formats[n].foreground();
+          QTextLayout::FormatRange range; 
+          range.format = formats[n]; range.start = j; range.length = -1; sf.formats.append(range);
+          toggles["fg"] = sf.formats.count() - 1;
+        }
+      }
+      if(s[i+1] == ',') {
+        if(toggles.contains("bg")) {
+          sf.formats[toggles["bg"]].length = j - sf.formats[toggles["bg"]].start;
+          toggles.remove("bg");
+        }
+        i++;
+        if(s[i+1].isDigit()) {
+          QString n(s[++i]);
+          if(s[i+1].isDigit()) n += s[++i];
+          int num = n.toInt() & 0xf;
+          n = QString("%C,%1").arg(num, (int)2, (int)10, (QChar)'0');
+          QTextLayout::FormatRange range;
+          range.format = formats[n]; range.start = j; range.length = -1;
+          sf.formats.append(range);
+          toggles["bg"] = sf.formats.count() - 1;
+        }
+      }
+    } else if(s[i] == 'O') {
+      foreach(QString key, toggles.keys()) {
+        sf.formats[toggles[key]].length = j - sf.formats[toggles[key]].start;
+        toggles.remove(key);
+      }
+
+    } else if(s[i] == 'R') {
+      // TODO implement reverse formatting
+
+    } else {
+      // all others are toggles
+      QString key = "%"; key += s[i];
+      if(s[i] == 'D') key += s[i+1];
+      if(formats.contains(key)) {
+        if(s[i] == 'D') i++;
+        if(toggles.contains(key)) {
+          sf.formats[toggles[key]].length = j - sf.formats[toggles[key]].start;
+          toggles.remove(key);
+        } else {
+          QTextLayout::FormatRange range;
+          range.format = formats[key]; range.start = j; range.length = -1;
+          sf.formats.append(range);
+          toggles[key] = sf.formats.count() -1;
+        }
+      } else {
+        // unknown format
+        p += '%'; p += s[i]; j+=2;
+      }
+    }
+  }
+  foreach(int idx, toggles.values()) {
+    sf.formats[idx].length = j - sf.formats[idx].start;
+  }
+  sf.text = p;
+  return sf;
+}
+
+QHash<QString, QTextCharFormat> Style::formats;
+QHash<QString, QColor> Style::colors;
+
similarity index 74%
rename from network/buffer.h
rename to gui/style.h
index 8429cfc..19c3be6 100644 (file)
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
 
-/* THIS CODE IS OBSOLETE, PENDING REMOVAL */
-
-#ifndef _BUFFER_OLD_H_
-#define _BUFFER_OLD_H_
+#ifndef _STYLE_H_
+#define _STYLE_H_
 
 #include <QtCore>
+#include <QtGui>
 
-class Buffer_old : public QObject {
-  Q_OBJECT
+class Style {
 
   public:
-    Buffer(QString name);
+    static void init();
 
-    QString name() { return _name; }
-    QString topic() { return _topic; }
+    struct StringFormats {
+      QString text;
+      QList<QTextLayout::FormatRange> formats;
+    };
 
-  public slots:
-    //void setNicks(QStringList nicks);
-    //void addNick(QString nick);
-    //void removeNick(QString nick);
+    static QString mircToInternal(QString);
+    //static QString internalToMirc(QString);
+    static StringFormats internalToFormatted(QString);
+    static int sepTsSender() { return 10; }
+    static int sepSenderText() { return 10; }
 
-  signals:
 
   private:
-    QString _name;
-    QString _topic;
-    QStringList nicks;
+    static QHash<QString, QTextCharFormat> formats;
+    static QHash<QString, QColor> colors;
 
 };
 
-
-
 #endif
index b3bab0d..854d491 100644 (file)
@@ -31,7 +31,7 @@
   </property>
   <layout class="QVBoxLayout" >
    <property name="margin" >
-    <number>1</number>
+    <number>9</number>
    </property>
    <property name="spacing" >
     <number>6</number>
    </item>
    <item>
     <widget class="QSplitter" name="splitter" >
-     <property name="sizePolicy" >
-      <sizepolicy>
-       <hsizetype>7</hsizetype>
-       <vsizetype>5</vsizetype>
-       <horstretch>0</horstretch>
-       <verstretch>0</verstretch>
-      </sizepolicy>
-     </property>
-     <property name="lineWidth" >
-      <number>1</number>
-     </property>
      <property name="orientation" >
       <enum>Qt::Horizontal</enum>
      </property>
-     <widget class="QTextBrowser" name="chatWidget" >
+     <widget class="ChatWidget" native="1" name="chatWidget" >
       <property name="sizePolicy" >
        <sizepolicy>
-        <hsizetype>7</hsizetype>
+        <hsizetype>5</hsizetype>
         <vsizetype>5</vsizetype>
-        <horstretch>4</horstretch>
+        <horstretch>6</horstretch>
         <verstretch>0</verstretch>
        </sizepolicy>
       </property>
-      <property name="font" >
-       <font>
-        <family>Bitstream Vera Sans Mono</family>
-        <pointsize>8</pointsize>
-        <weight>50</weight>
-        <bold>false</bold>
-       </font>
-      </property>
-      <property name="html" >
-       <string>&lt;html>&lt;head>&lt;meta name="qrichtext" content="1" />&lt;style type="text/css">
-p, li { white-space: pre-wrap; }
-&lt;/style>&lt;/head>&lt;body style=" font-family:'Bitstream Vera Sans Mono'; font-size:8pt; font-weight:400; font-style:normal; text-decoration:none;">
-&lt;p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Nimbus Mono L';">&lt;/p>&lt;/body>&lt;/html></string>
-      </property>
      </widget>
      <widget class="QTreeWidget" name="nickTree" >
       <property name="sizePolicy" >
@@ -252,6 +227,11 @@ p, li { white-space: pre-wrap; }
   </layout>
  </widget>
  <customwidgets>
+  <customwidget>
+   <class>ChatWidget</class>
+   <extends>QWidget</extends>
+   <header>chatwidget.h</header>
+  </customwidget>
   <customwidget>
    <class>ChannelWidgetInput</class>
    <extends>QLineEdit</extends>
@@ -264,7 +244,6 @@ p, li { white-space: pre-wrap; }
   <tabstop>nickTree</tabstop>
   <tabstop>topicEdit</tabstop>
   <tabstop>chanSettingsButton</tabstop>
-  <tabstop>chatWidget</tabstop>
  </tabstops>
  <resources/>
  <connections/>
index 152f3bd..32f9fa8 100644 (file)
      <x>0</x>
      <y>0</y>
      <width>800</width>
-     <height>29</height>
+     <height>32</height>
     </rect>
    </property>
-   <widget class="QMenu" name="menuViews" >
-    <property name="title" >
-     <string>Views</string>
-    </property>
-   </widget>
-   <widget class="QMenu" name="menuHelp" >
-    <property name="title" >
-     <string>Help</string>
-    </property>
-   </widget>
    <widget class="QMenu" name="menuConnection" >
     <property name="title" >
      <string>Connection</string>
     <addaction name="separator" />
     <addaction name="actionQuit" />
    </widget>
+   <widget class="QMenu" name="menuViews" >
+    <property name="title" >
+     <string>Views</string>
+    </property>
+   </widget>
    <widget class="QMenu" name="menuSettings" >
     <property name="title" >
      <string>Settings</string>
     </property>
+    <addaction name="separator" />
     <addaction name="actionEditIdentities" />
+    <addaction name="separator" />
+    <addaction name="separator" />
+    <addaction name="actionSettingsDlg" />
+   </widget>
+   <widget class="QMenu" name="menuHelp" >
+    <property name="title" >
+     <string>Help</string>
+    </property>
    </widget>
    <addaction name="menuConnection" />
-   <addaction name="menuSettings" />
    <addaction name="menuViews" />
+   <addaction name="menuSettings" />
    <addaction name="menuHelp" />
   </widget>
   <widget class="QStatusBar" name="statusbar" />
     <string>Edit Identities...</string>
    </property>
   </action>
+  <action name="actionSettingsDlg" >
+   <property name="text" >
+    <string>Configure Quassel...</string>
+   </property>
+   <property name="shortcut" >
+    <string>F7</string>
+   </property>
+  </action>
  </widget>
  <resources/>
  <connections>
index dd7af10..771012a 100644 (file)
@@ -1,18 +1,18 @@
 <ui version="4.0" >
- <class>SettingsDialog</class>
- <widget class="QDialog" name="SettingsDialog" >
+ <class>SettingsDlg</class>
+ <widget class="QDialog" name="SettingsDlg" >
   <property name="geometry" >
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>700</width>
-    <height>577</height>
+    <width>848</width>
+    <height>514</height>
    </rect>
   </property>
   <property name="windowTitle" >
-   <string>Settings</string>
+   <string>Dialog</string>
   </property>
-  <layout class="QHBoxLayout" >
+  <layout class="QVBoxLayout" >
    <property name="margin" >
     <number>9</number>
    </property>
     <number>6</number>
    </property>
    <item>
-    <widget class="QTreeWidget" name="treeWidget" >
-     <property name="sizePolicy" >
-      <sizepolicy>
-       <hsizetype>4</hsizetype>
-       <vsizetype>7</vsizetype>
-       <horstretch>1</horstretch>
-       <verstretch>0</verstretch>
-      </sizepolicy>
-     </property>
-     <column>
-      <property name="text" >
-       <string>Settings</string>
-      </property>
-     </column>
-     <item>
-      <property name="text" >
-       <string>General</string>
-      </property>
-     </item>
-     <item>
-      <property name="text" >
-       <string>Appearance</string>
-      </property>
-     </item>
-     <item>
-      <property name="text" >
-       <string>Connection</string>
-      </property>
-     </item>
-     <item>
-      <property name="text" >
-       <string>Plugins</string>
-      </property>
-     </item>
-    </widget>
-   </item>
-   <item>
-    <layout class="QVBoxLayout" >
+    <layout class="QHBoxLayout" >
      <property name="margin" >
       <number>0</number>
      </property>
       <number>6</number>
      </property>
      <item>
-      <widget class="QStackedWidget" name="stackedWidget" >
+      <widget class="QTreeWidget" name="settingsTree" >
        <property name="sizePolicy" >
         <sizepolicy>
          <hsizetype>5</hsizetype>
-         <vsizetype>5</vsizetype>
-         <horstretch>4</horstretch>
+         <vsizetype>7</vsizetype>
+         <horstretch>0</horstretch>
          <verstretch>0</verstretch>
         </sizepolicy>
        </property>
-       <widget class="QWidget" name="page" />
-       <widget class="QWidget" name="page_2" />
+       <column>
+        <property name="text" >
+         <string>Settings</string>
+        </property>
+       </column>
       </widget>
      </item>
      <item>
-      <widget class="QDialogButtonBox" name="buttonBox" >
-       <property name="orientation" >
-        <enum>Qt::Horizontal</enum>
+      <widget class="QFrame" name="settingsFrame" >
+       <property name="sizePolicy" >
+        <sizepolicy>
+         <hsizetype>3</hsizetype>
+         <vsizetype>5</vsizetype>
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
        </property>
-       <property name="standardButtons" >
-        <set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok|QDialogButtonBox::RestoreDefaults</set>
+       <property name="frameShape" >
+        <enum>QFrame::StyledPanel</enum>
+       </property>
+       <property name="frameShadow" >
+        <enum>QFrame::Raised</enum>
        </property>
       </widget>
      </item>
     </layout>
    </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox" >
+     <property name="orientation" >
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons" >
+      <set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
   </layout>
  </widget>
  <resources/>
@@ -97,7 +81,7 @@
   <connection>
    <sender>buttonBox</sender>
    <signal>accepted()</signal>
-   <receiver>SettingsDialog</receiver>
+   <receiver>SettingsDlg</receiver>
    <slot>accept()</slot>
    <hints>
     <hint type="sourcelabel" >
   <connection>
    <sender>buttonBox</sender>
    <signal>rejected()</signal>
-   <receiver>SettingsDialog</receiver>
+   <receiver>SettingsDlg</receiver>
    <slot>reject()</slot>
    <hints>
     <hint type="sourcelabel" >
index b6e15b0..3ee9f9f 100644 (file)
@@ -23,6 +23,7 @@
 #include <QtGui>
 #include <QApplication>
 
+#include "style.h"
 #include "global.h"
 #include "guiproxy.h"
 #include "coreconnectdlg.h"
@@ -42,6 +43,8 @@ int main(int argc, char **argv) {
   global = new Global();
   guiProxy = new GUIProxy();
 
+  Style::init();
+
   MainWin mainWin;
   int exitCode = app.exec();
   delete guiProxy;
index 9384294..268f3c1 100644 (file)
@@ -23,6 +23,7 @@
 #include <QApplication>
 
 #include "core.h"
+#include "style.h"
 #include "global.h"
 #include "guiproxy.h"
 #include "coreproxy.h"
@@ -42,6 +43,8 @@ int main(int argc, char **argv) {
   guiProxy = new GUIProxy();
   coreProxy = new CoreProxy();
 
+  Style::init();
+
   MainWin mainWin;
   mainWin.show();
   int exitCode = app.exec();
diff --git a/network/CMakeLists.txt b/network/CMakeLists.txt
deleted file mode 100644 (file)
index 693eced..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-SET(network_SRCS server.cpp)
-SET(network_HDRS)
-SET(network_MOCS server.h)
-
-QT4_WRAP_CPP(_MOC ${network_MOCS})
-ADD_LIBRARY(network ${_MOC} ${network_SRCS} ${network_HDRS})
diff --git a/network/cmdcodes.h b/network/cmdcodes.h
deleted file mode 100644 (file)
index 7f9625f..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005/06 by The Quassel Team                             *
- *   devel@quassel-irc.org                                                 *
- *                                                                         *
- *   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.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
- ***************************************************************************/
-
-/* THIS CODE IS OBSOLETE! */
-
-#ifndef _CMDCODES_H_
-#define _CMDCODES_H_
-
-/** Contains numeric codes for the named commands. These are _negative_ in the message object. */
-enum CmdCodes {
-  CMD_ADMIN = 1, CMD_AME, CMD_AMSG, CMD_AWAY, CMD_BAN, CMD_CTCP, CMD_CYCLE, CMD_DEHALFOP, CMD_DEOP, CMD_DEVOICE,
-  CMD_DIE, CMD_ERROR, CMD_HALFOP, CMD_INFO, CMD_INVITE, CMD_ISON, CMD_JOIN, CMD_KICK, CMD_KICKBAN, CMD_KILL, CMD_LINKS,
-  CMD_LIST, CMD_LUSERS, CMD_ME, CMD_MODE, CMD_MOTD, CMD_MSG, CMD_NAMES, CMD_NICK, CMD_NOTICE, CMD_OP, CMD_OPER,
-  CMD_PART, CMD_PING, CMD_PONG, CMD_PRIVMSG, CMD_QUERY, CMD_QUIT, CMD_QUOTE, CMD_REHASH, CMD_RESTART, CMD_SERVICE,
-  CMD_SERVLIST, CMD_SQUERY, CMD_SQUIT, CMD_STATS, CMD_SUMMON, CMD_TIME, CMD_TOPIC, CMD_TRACE, CMD_UNBAN, CMD_USERHOST,
-  CMD_USERS, CMD_VERSION, CMD_VOICE, CMD_WALLOPS, CMD_WHO, CMD_WHOIS, CMD_WHOWAS,
-  CMD_USERDEFINED
-};
-
-
-
-#endif
diff --git a/network/server.cpp b/network/server.cpp
deleted file mode 100644 (file)
index ffc9054..0000000
+++ /dev/null
@@ -1,619 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005/06 by The Quassel Team                             *
- *   devel@quassel-irc.org                                                 *
- *                                                                         *
- *   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.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
- ***************************************************************************/
-
-/* OBSOLETE CODE, MOVED TO core/ */
-
-#error "obsolete code"
-
-#include "util.h"
-#include "global.h"
-#include "server.h"
-#include "cmdcodes.h"
-#include "message.h"
-
-#include <QMetaObject>
-#include <QDateTime>
-
-Server::Server(QString net) : network(net) {
-
-}
-
-Server::~Server() {
-
-}
-
-void Server::run() {
-  connect(&socket, SIGNAL(connected()), this, SLOT(socketConnected()));
-  connect(&socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
-  connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)));
-  connect(&socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(socketStateChanged(QAbstractSocket::SocketState)));
-  connect(&socket, SIGNAL(readyRead()), this, SLOT(socketHasData()));
-
-  exec();
-}
-
-void Server::connectToIrc(QString net) {
-  if(net != network) return; // not me!
-  networkSettings = global->getData("Networks").toMap()[net].toMap();
-  identity = global->getData("Identities").toMap()[networkSettings["Identity"].toString()].toMap();
-  QList<QVariant> servers = networkSettings["Servers"].toList();
-  QString host = servers[0].toMap()["Address"].toString();
-  quint16 port = servers[0].toMap()["Port"].toUInt();
-  displayStatusMsg(QString("Connecting to %1:%2...").arg(host).arg(port));
-  socket.connectToHost(host, port);
-}
-
-void Server::disconnectFromIrc(QString net) {
-  if(net != network) return; // not me!
-  socket.disconnectFromHost();
-}
-
-void Server::socketHasData() {
-  while(socket.canReadLine()) {
-    QString s = socket.readLine().trimmed();
-    qDebug() << "Read: " << s;
-    emit recvRawServerMsg(s);
-    //Message *msg = Message::createFromServerString(this, s);
-    handleServerMsg(s);
-  }
-}
-
-void Server::socketError( QAbstractSocket::SocketError err ) {
-  //qDebug() << "Socket Error!";
-  //emit error(err);
-}
-
-void Server::socketConnected( ) {
-  putRawLine(QString("NICK :%1").arg(identity["NickList"].toStringList()[0]));
-  putRawLine(QString("USER %1 8 * :%2").arg(identity["Ident"].toString()).arg(identity["RealName"].toString()));
-}
-
-void Server::socketDisconnected( ) {
-  //qDebug() << "Socket disconnected!";
-  emit disconnected();
-}
-
-void Server::socketStateChanged(QAbstractSocket::SocketState state) {
-  //qDebug() << "Socket state changed: " << state;
-}
-
-QString Server::updateNickFromMask(QString mask) {
-  QString user = userFromMask(mask);
-  QString host = hostFromMask(mask);
-  QString nick = nickFromMask(mask);
-  if(nicks.contains(nick) && !user.isEmpty() && !host.isEmpty()) {
-    VarMap n = nicks[nick].toMap();
-    if(n["User"].toString() != user || n["Host"].toString() != host) {
-      if(!n["User"].toString().isEmpty() || !n["Host"].toString().isEmpty())
-        qWarning(QString("Strange: Hostmask for nick %1 has changed!").arg(nick).toAscii());
-      n["User"] = user; n["Host"] = host;
-      nicks[nick] = n;
-      emit nickUpdated(network, nick, n);
-    }
-  }
-  return nick;
-}
-
-void Server::userInput(QString net, QString buf, QString msg) {
-  if(net != network) return; // not me!
-  //msg = msg.trimmed(); // remove whitespace from start and end
-  if(msg.isEmpty()) return;
-  if(!msg.startsWith('/')) {
-    msg = QString("/SAY ") + msg;
-  }
-  handleUserInput(buf, msg);
-}
-
-void Server::putRawLine(QString s) {
-  qDebug() << "SentRaw: " << s;
-  s += "\r\n";
-  socket.write(s.toAscii());
-}
-
-void Server::putCmd(QString cmd, QStringList params, QString prefix) {
-  QString m;
-  if(!prefix.isEmpty()) m += ":" + prefix + " ";
-  m += cmd.toUpper();
-  for(int i = 0; i < params.size() - 1; i++) {
-    m += " " + params[i];
-  }
-  if(!params.isEmpty()) m += " :" + params.last();
-  qDebug() << "Sent: " << m;
-  m += "\r\n";
-  socket.write(m.toAscii());
-}
-
-/** Handle a raw message string sent by the server. We try to find a suitable handler, otherwise we call a default handler. */
-void Server::handleServerMsg(QString msg) {
-  try {
-    if(msg.isEmpty()) {
-      qWarning() << "Received empty string from server!";
-      return;
-    }
-    // OK, first we split the raw message into its various parts...
-    QString prefix;
-    QString cmd;
-    QStringList params;
-    if(msg[0] == ':') {
-      msg.remove(0,1);
-      prefix = msg.section(' ', 0, 0);
-      msg = msg.section(' ', 1);
-    }
-    cmd = msg.section(' ', 0, 0).toUpper();
-    msg = msg.section(' ', 1);
-    QString left, trailing;
-    // RPL_ISUPPORT (005) can contain colons, so don't treat it like the rest of the commands
-    if(cmd.toUInt() == 5) {
-      left = msg.remove(QString(":are supported by this server"));
-    } else {
-      left = msg.section(':', 0, 0);
-      trailing = msg.section(':', 1);
-    }
-    if(!left.isEmpty()) {
-      params << left.split(' ', QString::SkipEmptyParts);
-    }
-    if(!trailing.isEmpty()) {
-      params << trailing;
-    }
-    // numeric replies usually have our own nick as first param. Remove this!
-    // BTW, this behavior is not in the RFC.
-    uint num = cmd.toUInt();
-    if(num > 1 && params.count() > 0) {  // 001 sets our nick, so we shouldn't remove anything
-      if(params[0] == currentNick) params.removeFirst();
-      else qWarning((QString("First param NOT nick: %1:%2 %3").arg(prefix).arg(cmd).arg(params.join(" "))).toAscii());
-    }
-    // Now we try to find a handler for this message. BTW, I do love the Trolltech guys ;-)
-    QString hname = cmd.toLower();
-    hname[0] = hname[0].toUpper();
-    hname = "handleServer" + hname;
-    if(!QMetaObject::invokeMethod(this, hname.toAscii(), Q_ARG(QString, prefix), Q_ARG(QStringList, params))) {
-      // Ok. Default handler it is.
-      defaultServerHandler(cmd, prefix, params);
-    }
-  } catch(Exception e) {
-    emit displayMsg("", Message(Message::Error, e.msg()));
-  }
-}
-
-void Server::defaultServerHandler(QString cmd, QString prefix, QStringList params) {
-  uint num = cmd.toUInt();
-  if(num) {
-    // A lot of server messages don't really need their own handler because they don't do much.
-    // Catch and handle these here.
-    switch(num) {
-      // Welcome, status, info messages. Just display these.
-      case 2: case 3: case 4: case 5: case 251: case 252: case 253: case 254: case 255: case 372: case 375:
-        emit displayMsg("", Message(Message::Server, params.join(" "), prefix));
-        break;
-      // Server error messages without param, just display them
-      case 409: case 411: case 412: case 422: case 424: case 431: case 445: case 446: case 451: case 462:
-      case 463: case 464: case 465: case 466: case 472: case 481: case 483: case 485: case 491: case 501: case 502:
-        emit displayMsg("", Message(Message::Error, params.join(" "), prefix));
-        break;
-      // Server error messages, display them in red. First param will be appended.
-      case 401: case 402: case 403: case 404: case 406: case 408: case 415: case 421: case 432: case 442:
-      { QString p = params.takeFirst();
-        emit displayMsg("", Message(Message::Error, params.join(" ") + " " + p, prefix));
-        break;
-      }
-      // Server error messages which will be displayed with a colon between the first param and the rest
-      case 413: case 414: case 423: case 433: case 436: case 441: case 444: case 461:
-      case 467: case 471: case 473: case 474: case 475: case 476: case 477: case 478: case 482:
-      { QString p = params.takeFirst();
-        emit displayMsg("", Message(Message::Error, p + ": " + params.join(" ")));
-        break;
-      }
-      // Ignore these commands.
-      case 366: case 376:
-        break;
-
-      // Everything else will be marked in red, so we can add them somewhere.
-      default:
-        emit displayMsg("", Message(Message::Error, cmd + " " + params.join(" "), prefix));
-    }
-    //qDebug() << prefix <<":"<<cmd<<params;
-  } else {
-    emit displayMsg("", Message(Message::Error, QString("Unknown: ") + cmd + " " + params.join(" "), prefix));
-    //qDebug() << prefix <<":"<<cmd<<params;
-  }
-}
-
-void Server::handleUserInput(QString bufname, QString usrMsg) {
-  try {
-    /* Looks like we don't need core-side buffers...
-    Buffer *buffer = 0;
-    if(!bufname.isEmpty()) {
-      Q_ASSERT(buffers.contains(bufname));
-      buffer = buffers[bufname];
-    }
-    */
-    QString cmd = usrMsg.section(' ', 0, 0).remove(0, 1).toUpper();
-    QString msg = usrMsg.section(' ', 1);
-    QString hname = cmd.toLower();
-    hname[0] = hname[0].toUpper();
-    hname = "handleUser" + hname;
-    if(!QMetaObject::invokeMethod(this, hname.toAscii(), Q_ARG(QString, bufname), Q_ARG(QString, msg))) {
-        // Ok. Default handler it is.
-      defaultUserHandler(bufname, cmd, msg);
-    }
-  } catch(Exception e) {
-    emit displayMsg("", Message(Message::Error, e.msg()));
-  }
-}
-
-void Server::defaultUserHandler(QString bufname, QString cmd, QString msg) {
-  emit displayMsg("", Message(Message::Error, QString("Error: %1 %2").arg(cmd).arg(msg)));
-
-}
-
-/**********************************************************************************/
-
-/*
-void Server::handleUser(QString bufname, QString msg) {
-
-
-}
-*/
-
-void Server::handleUserAway(QString bufname, QString msg) {
-  putCmd("AWAY", QStringList(msg));
-}
-
-void Server::handleUserDeop(QString bufname, QString msg) {
-  QStringList nicks = msg.split(' ', QString::SkipEmptyParts);
-  QString m = "-"; for(int i = 0; i < nicks.count(); i++) m += 'o';
-  QStringList params;
-  params << bufname << m << nicks;
-  putCmd("MODE", params);
-}
-
-void Server::handleUserDevoice(QString bufname, QString msg) {
-  QStringList nicks = msg.split(' ', QString::SkipEmptyParts);
-  QString m = "-"; for(int i = 0; i < nicks.count(); i++) m += 'v';
-  QStringList params;
-  params << bufname << m << nicks;
-  putCmd("MODE", params);
-}
-
-void Server::handleUserInvite(QString bufname, QString msg) {
-  QStringList params;
-  params << msg << bufname;
-  putCmd("INVITE", params);
-}
-
-void Server::handleUserJoin(QString bufname, QString msg) {
-  putCmd("JOIN", QStringList(msg));
-}
-
-void Server::handleUserKick(QString bufname, QString msg) {
-  QStringList params;
-  params << bufname << msg.split(' ', QString::SkipEmptyParts);
-  putCmd("KICK", params);
-}
-
-void Server::handleUserList(QString bufname, QString msg) {
-  putCmd("LIST", msg.split(' ', QString::SkipEmptyParts));
-}
-
-void Server::handleUserMode(QString bufname, QString msg) {
-  putCmd("MODE", msg.split(' ', QString::SkipEmptyParts));
-}
-
-void Server::handleUserMsg(QString bufname, QString msg) {
-  QString nick = msg.section(" ", 0, 0);
-  msg = msg.section(" ", 1);
-  if(nick.isEmpty() || msg.isEmpty()) return;
-  QStringList params;
-  params << nick << msg;
-  putCmd("PRIVMSG", params);
-}
-
-void Server::handleUserNick(QString bufname, QString msg) {
-  QString nick = msg.section(' ', 0, 0);
-  putCmd("NICK", QStringList(nick));
-}
-
-void Server::handleUserOp(QString bufname, QString msg) {
-  QStringList nicks = msg.split(' ', QString::SkipEmptyParts);
-  QString m = "+"; for(int i = 0; i < nicks.count(); i++) m += 'o';
-  QStringList params;
-  params << bufname << m << nicks;
-  putCmd("MODE", params);
-}
-
-void Server::handleUserPart(QString bufname, QString msg) {
-  QStringList params;
-  params << bufname << msg;
-  putCmd("PART", params);
-}
-
-void Server::handleUserQuit(QString bufname, QString msg) {
-  putCmd("QUIT", QStringList(msg));
-}
-
-void Server::handleUserQuote(QString bufname, QString msg) {
-  putRawLine(msg);
-}
-
-void Server::handleUserSay(QString bufname, QString msg) {
-  if(bufname.isEmpty()) return;  // server buffer
-  QStringList params;
-  params << bufname << msg;
-  putCmd("PRIVMSG", params);
-  emit displayMsg(params[0], Message(Message::Msg, msg, currentNick, Message::Self));
-}
-
-void Server::handleUserVoice(QString bufname, QString msg) {
-  QStringList nicks = msg.split(' ', QString::SkipEmptyParts);
-  QString m = "+"; for(int i = 0; i < nicks.count(); i++) m += 'v';
-  QStringList params;
-  params << bufname << m << nicks;
-  putCmd("MODE", params);
-}
-
-/**********************************************************************************/
-
-void Server::handleServerJoin(QString prefix, QStringList params) {
-  Q_ASSERT(params.count() == 1);
-  QString nick = updateNickFromMask(prefix);
-  if(nick == currentNick) {
-  //  Q_ASSERT(!buffers.contains(params[0]));  // cannot join a buffer twice!
-  //  Buffer *buf = new Buffer(params[0]);
-  //  buffers[params[0]] = buf;
-  } else {
-    VarMap n;
-    if(nicks.contains(nick)) {
-      n = nicks[nick].toMap();
-      VarMap chans = n["Channels"].toMap();
-      // Q_ASSERT(!chans.keys().contains(params[0])); TODO uncomment
-      chans[params[0]] = VarMap();
-      n["Channels"] = chans;
-      nicks[nick] = n;
-      emit nickUpdated(network, nick, n);
-    } else {
-      VarMap chans;
-      chans[params[0]] = VarMap();
-      n["Channels"] = chans;
-      n["User"] = userFromMask(prefix);
-      n["Host"] = hostFromMask(prefix);
-      nicks[nick] = n;
-      emit nickAdded(network, nick, n);
-    }
-    emit displayMsg(params[0], Message(Message::Join, params[0], prefix));
-  }
-}
-
-void Server::handleServerKick(QString prefix, QStringList params) {
-  QString kicker = updateNickFromMask(prefix);
-  QString nick = params[1];
-  Q_ASSERT(nicks.contains(nick));
-  VarMap n = nicks[nick].toMap();
-  VarMap chans = n["Channels"].toMap();
-  Q_ASSERT(chans.contains(params[0]));
-  chans.remove(params[0]);
-  QString msg = nick;
-  if(params.count() > 2) msg = QString("%1 %2").arg(msg).arg(params[2]);
-  emit displayMsg(params[0], Message(Message::Kick, msg, prefix));
-  if(chans.count() > 0) {
-    n["Channels"] = chans;
-    nicks[nick] = n;
-    emit nickUpdated(network, nick, n);
-  } else {
-    nicks.remove(nick);
-    emit nickRemoved(network, nick);
-  }
-}
-
-void Server::handleServerMode(QString prefix, QStringList params) {
-  if(isChannelName(params[0])) {
-    // TODO only channel-user modes supported by now
-    QString prefixes = serverSupports["PrefixModes"].toString();
-    QString modes = params[1];
-    int p = 2;
-    int m = 0;
-    bool add = true;
-    while(m < modes.length()) {
-      if(modes[m] == '+') { add = true; m++; continue; }
-      if(modes[m] == '-') { add = false; m++; continue; }
-      if(prefixes.contains(modes[m])) {  // it's a user channel mode
-        Q_ASSERT(params.count() > m && nicks.contains(params[p]));
-        QString nick = params[p++];
-        VarMap n = nicks[nick].toMap(); VarMap clist = n["Channels"].toMap(); VarMap chan = clist[params[0]].toMap();
-        QString mstr = chan["Mode"].toString();
-        add ? mstr += modes[m] : mstr.remove(modes[m]);
-        chan["Mode"] = mstr; clist[params[0]] = chan; n["Channels"] = clist; nicks[nick] = n;
-        emit nickUpdated(network, nick, n);
-        m++;
-      } else {
-        // TODO add more modes
-        m++;
-      }
-    }
-    emit displayMsg(params[0], Message(Message::Mode, params.join(" "), prefix));
-  } else {
-    //Q_ASSERT(nicks.contains(params[0]));
-    //VarMap n = nicks[params[0]].toMap();
-    //QString mode = n["Mode"].toString();
-    emit displayMsg("", Message(Message::Mode, params.join(" ")));
-  }
-}
-
-void Server::handleServerNick(QString prefix, QStringList params) {
-  QString oldnick = updateNickFromMask(prefix);
-  QString newnick = params[0];
-  QVariant v = nicks.take(oldnick);
-  nicks[newnick] = v;
-  VarMap chans = v.toMap()["Channels"].toMap();
-  foreach(QString c, chans.keys()) {
-    if(oldnick != currentNick) { emit displayMsg(c, Message(Message::Nick, newnick, prefix)); }
-    else { emit displayMsg(c, Message(Message::Nick, newnick, newnick)); }
-  }
-  emit nickRenamed(network, oldnick, newnick);
-  if(oldnick == currentNick) {
-    currentNick = newnick;
-    emit ownNickSet(network, newnick);
-  }
-}
-
-void Server::handleServerNotice(QString prefix, QStringList params) {
-  //Message msg(Message::Notice, params[1], prefix);
-  if(prefix == currentServer) emit displayMsg("", Message(Message::Server, params[1], prefix));
-  else emit displayMsg("", Message(Message::Notice, params[1], prefix));
-}
-
-void Server::handleServerPart(QString prefix, QStringList params) {
-  QString nick = updateNickFromMask(prefix);
-  Q_ASSERT(nicks.contains(nick));
-  VarMap n = nicks[nick].toMap();
-  VarMap chans = n["Channels"].toMap();
-  Q_ASSERT(chans.contains(params[0]));
-  chans.remove(params[0]);
-  QString msg;
-  if(params.count() > 1) msg = params[1];
-  emit displayMsg(params[0], Message(Message::Part, msg, prefix));
-  if(chans.count() > 0) {
-    n["Channels"] = chans;
-    nicks[nick] = n;
-    emit nickUpdated(network, nick, n);
-  } else {
-    nicks.remove(nick);
-    emit nickRemoved(network, nick);
-  }
-}
-
-void Server::handleServerPing(QString prefix, QStringList params) {
-  putCmd("PONG", params);
-}
-
-void Server::handleServerPrivmsg(QString prefix, QStringList params) {
-  updateNickFromMask(prefix);
-  emit displayMsg(params[0], Message(Message::Msg, params[1], prefix));
-
-}
-
-void Server::handleServerQuit(QString prefix, QStringList params) {
-  QString nick = updateNickFromMask(prefix);
-  Q_ASSERT(nicks.contains(nick));
-  VarMap chans = nicks[nick].toMap()["Channels"].toMap();
-  foreach(QString c, chans.keys()) {
-    emit displayMsg(c, Message(Message::Quit, params[0], prefix));
-  }
-  nicks.remove(nick);
-  emit nickRemoved(network, nick);
-}
-
-/* RPL_WELCOME */
-void Server::handleServer001(QString prefix, QStringList params) {
-  currentServer = prefix;
-  currentNick = params[0];
-  VarMap n;
-  n["Channels"] = VarMap();
-  nicks[currentNick] = n;
-  emit ownNickSet(network, currentNick);
-  emit nickAdded(network, currentNick, VarMap());
-  emit displayMsg("", Message(Message::Server, params[1], prefix));
-}
-
-/* RPL_ISUPPORT */
-void Server::handleServer005(QString prefix, QStringList params) {
-  foreach(QString p, params) {
-    QString key = p.section("=", 0, 0);
-    QString val = p.section("=", 1);
-    serverSupports[key] = val;
-    // handle some special cases
-    if(key == "PREFIX") {
-      VarMap foo; QString modes, prefixes;
-      Q_ASSERT(val.contains(')') && val.startsWith('('));
-      int m = 1, p;
-      for(p = 2; p < val.length(); p++) if(val[p] == ')') break;
-      p++;
-      for(; val[m] != ')'; m++, p++) {
-        Q_ASSERT(p < val.length());
-        foo[QString(val[m])] = QString(val[p]);
-        modes += val[m]; prefixes += val[p];
-      }
-      serverSupports["PrefixModes"] = modes; serverSupports["Prefixes"] = prefixes;
-      serverSupports["ModePrefixMap"] = foo;
-    }
-  }
-}
-
-
-/* RPL_NOTOPIC */
-void Server::handleServer331(QString prefix, QStringList params) {
-  emit topicSet(network, params[0], "");
-  emit displayMsg(params[0], Message(Message::Server, tr("No topic is set for %1.").arg(params[0])));
-}
-
-/* RPL_TOPIC */
-void Server::handleServer332(QString prefix, QStringList params) {
-  emit topicSet(network, params[0], params[1]);
-  emit displayMsg(params[0], Message(Message::Server, tr("Topic for %1 is \"%2\"").arg(params[0]).arg(params[1])));
-}
-
-/* Topic set by... */
-void Server::handleServer333(QString prefix, QStringList params) {
-  emit displayMsg(params[0], Message(Message::Server,
-                  tr("Topic set by %1 on %2").arg(params[1]).arg(QDateTime::fromTime_t(params[2].toUInt()).toString())));
-}
-
-/* RPL_NAMREPLY */
-void Server::handleServer353(QString prefix, QStringList params) {
-  params.removeFirst(); // = or *
-  QString buf = params.takeFirst();
-  QString prefixes = serverSupports["Prefixes"].toString();
-  foreach(QString nick, params[0].split(' ')) {
-    QString mode = "", pfx = "";
-    if(prefixes.contains(nick[0])) {
-      pfx = nick[0];
-      for(int i = 0;; i++)
-        if(prefixes[i] == nick[0]) { mode = serverSupports["PrefixModes"].toString()[i]; break; }
-      nick.remove(0,1);
-    }
-    VarMap c; c["Mode"] = mode; c["Prefix"] = pfx;
-    if(nicks.contains(nick)) {
-      VarMap n = nicks[nick].toMap();
-      VarMap chans = n["Channels"].toMap();
-      chans[buf] = c;
-      n["Channels"] = chans;
-      nicks[nick] = n;
-      emit nickUpdated(network, nick, n);
-    } else {
-      VarMap n; VarMap c; VarMap chans;
-      c["Mode"] = mode;
-      chans[buf] = c;
-      n["Channels"] = chans;
-      nicks[nick] = n;
-      emit nickAdded(network, nick, n);
-    }
-  }
-}
-/***********************************************************************************/
-
-/* Exception classes for message handling */
-Server::ParseError::ParseError(QString cmd, QString prefix, QStringList params) {
-  _msg = QString("Command Parse Error: ") + cmd + params.join(" ");
-
-}
-
-Server::UnknownCmdError::UnknownCmdError(QString cmd, QString prefix, QStringList params) {
-  _msg = QString("Unknown Command: ") + cmd;
-
-}
diff --git a/network/server.h b/network/server.h
deleted file mode 100644 (file)
index f0f3a85..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005/06 by The Quassel Team                             *
- *   devel@quassel-irc.org                                                 *
- *                                                                         *
- *   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.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
- ***************************************************************************/
-
-#error "obsolete code"
-
-#ifndef _SERVER_H_
-#define _SERVER_H_
-
-#include <QtCore>
-#include <QTimer>
-#include <QtNetwork>
-
-#include "global.h"
-#include "buffer.h"
-#include "message.h"
-
-#define DEFAULT_PORT 6667
-
-
-/*!
- * This is a server object, managing a single connection to an IRC server, handling the associated channels and so on.
- * We have this running in its own thread mainly to not block other server objects or the core if something goes wrong,
- * e.g. if some scripts starts running wild...
- */
-
-class Server : public QThread {
-  Q_OBJECT
-
-  public:
-    Server(QString network);
-    ~Server();
-
-    // serverState state();
-    bool isConnected() { return socket.state() == QAbstractSocket::ConnectedState; }
-    QString getNetwork() { return network; }
-
-  public slots:
-    // void setServerOptions();
-    void connectToIrc(QString net);
-    void disconnectFromIrc(QString net);
-    void userInput(QString net, QString buffer, QString msg);
-
-    void putRawLine(QString input);
-    void putCmd(QString cmd, QStringList params, QString prefix = 0);
-
-    //void exitThread();
-
-  signals:
-    void recvRawServerMsg(QString);
-    void displayStatusMsg(QString);
-    void displayMsg(Message msg);
-    void disconnected();
-
-    void nickAdded(QString network, QString nick, VarMap props);
-    void nickRenamed(QString network, QString oldnick, QString newnick);
-    void nickRemoved(QString network, QString nick);
-    void nickUpdated(QString network, QString nick, VarMap props);
-    void modeSet(QString network, QString target, QString mode);
-    void topicSet(QString network, QString buffer, QString topic);
-    void setNicks(QString network, QString buffer, QStringList nicks);
-    void ownNickSet(QString network, QString newNick);
-
-
-  private slots:
-    void run();
-    void socketHasData();
-    void socketError(QAbstractSocket::SocketError);
-    void socketConnected();
-    void socketDisconnected();
-    void socketStateChanged(QAbstractSocket::SocketState);
-
-    /* Message Handlers */
-
-    /* void handleUser(QString, QString); */
-    void handleUserAway(QString, QString);
-    void handleUserDeop(QString, QString);
-    void handleUserDevoice(QString, QString);
-    void handleUserInvite(QString, QString);
-    void handleUserJoin(QString, QString);
-    void handleUserKick(QString, QString);
-    void handleUserList(QString, QString);
-    void handleUserMode(QString, QString);
-    void handleUserMsg(QString, QString);
-    void handleUserNick(QString, QString);
-    void handleUserOp(QString, QString);
-    void handleUserPart(QString, QString);
-    void handleUserQuit(QString, QString);
-    void handleUserQuote(QString, QString);
-    void handleUserSay(QString, QString);
-    void handleUserVoice(QString, QString);
-
-    /* void handleServer(QString, QStringList); */
-    void handleServerJoin(QString, QStringList);
-    void handleServerKick(QString, QStringList);
-    void handleServerMode(QString, QStringList);
-    void handleServerNick(QString, QStringList);
-    void handleServerNotice(QString, QStringList);
-    void handleServerPart(QString, QStringList);
-    void handleServerPing(QString, QStringList);
-    void handleServerPrivmsg(QString, QStringList);
-    void handleServerQuit(QString, QStringList);
-
-    void handleServer001(QString, QStringList);   // RPL_WELCOME
-    void handleServer005(QString, QStringList);   // RPL_ISUPPORT
-    void handleServer331(QString, QStringList);   // RPL_NOTOPIC
-    void handleServer332(QString, QStringList);   // RPL_TOPIC
-    void handleServer333(QString, QStringList);   // Topic set by...
-    void handleServer353(QString, QStringList);   // RPL_NAMREPLY
-
-    void defaultServerHandler(QString cmd, QString prefix, QStringList params);
-    void defaultUserHandler(QString buf, QString cmd, QString msg);
-
-  private:
-    QString network;
-    QTcpSocket socket;
-    //QHash<QString, Buffer*> buffers;
-
-    QString currentNick;
-    QString currentServer;
-    VarMap networkSettings;
-    VarMap identity;
-    VarMap nicks;  // stores all known nicks for the server
-    VarMap serverSupports;  // stores results from RPL_ISUPPORT
-
-    void handleServerMsg(QString rawMsg);
-    void handleUserInput(QString buffer, QString usrMsg);
-
-    QString updateNickFromMask(QString mask);
-
-    class ParseError : public Exception {
-      public:
-        ParseError(QString cmd, QString prefix, QStringList params);
-    };
-
-    class UnknownCmdError : public Exception {
-      public:
-        UnknownCmdError(QString cmd, QString prefix, QStringList params);
-    };
-};
-
-#endif
diff --git a/plugins/plugin.h b/plugins/plugin.h
new file mode 100644 (file)
index 0000000..5fa7052
--- /dev/null
@@ -0,0 +1,110 @@
+/***************************************************************************
+ *   Copyright (C) 2005/06 by The Quassel Team                             *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   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.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#ifndef _PLUGIN_H_
+#define _PLUGIN_H_
+
+// TODO disable GUI-related stuff for core-only compile
+
+#include <QtCore>
+#include <QtGui>
+
+/** \file plugin.h
+ * Header that needs to be included by all plugins and defines the interfaces a plugin
+ * can implement.
+ */
+
+/// The base class for the generic plugin interfaces.
+class PluginInterface {
+
+
+};
+
+
+/// All GUI plugins need to implement this interface.
+class GuiPluginInterface : public PluginInterface {
+
+
+};
+
+Q_DECLARE_INTERFACE(GuiPluginInterface,
+                    "eu.quassel.plugins.GuiPluginInterface/1.0");
+
+/// All core plugins need to implement this interface.
+class CorePluginInterface: public PluginInterface {
+
+
+
+};
+
+Q_DECLARE_INTERFACE(CorePluginInterface,
+                    "eu.quassel.plugins.CorePluginInterface/1.0");
+
+/** Plugins implementing this interface can provide a settings widget that will be shown in
+ * the application's settings dialog.
+ * This is also used by built-in settings dialogs.
+ */
+class SettingsInterface {
+  public:
+    virtual QWidget *settingsWidget(QWidget *parent = 0) = 0;
+
+};
+
+Q_DECLARE_INTERFACE(SettingsInterface,
+                    "eu.quassel.plugins.SettingsInterface/1.0");
+
+/** Plugins implementing this interface will be provided with the raw text the users enters.
+ * The output they generate is in turn treated like generic user input. Note that the order in
+ * which plugins are called is not defined.
+ */
+class UserInputFilterInterface {
+
+
+
+};
+
+Q_DECLARE_INTERFACE(UserInputFilterInterface,
+                    "eu.quassel.plugins.UserInputFilterInterface/1.0");
+
+/** Plugins implementing this interface receive and can process all messages coming from the core.
+ */
+class CoreMessageFilterInterface {
+
+
+
+};
+
+Q_DECLARE_INTERFACE(CoreMessageFilterInterface,
+                    "eu.quassel.plugins.CoreMessageFilterInterface/1.0");
+
+/** Plugins implementing this interface receive core messages for a single buffer only.
+ * Any ChatWidgetPlugin has to provide a widget it outputs these messages to, to be used
+ * in a ChannelWidget.
+ */
+class ChatWidgetInterface {
+
+
+
+};
+
+Q_DECLARE_INTERFACE(ChatWidgetInterface,
+                    "eu.quassel.plugins.ChatWidgetInterface/1.0");
+
+#endif
index e204ef8..53f7070 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005/06 by The Quassel Team                             *
+ *   Copyright (C) 2005-07 by The Quassel Team                             *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
index 5c25227..21a1438 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005/06 by The Quassel Team                             *
+ *   Copyright (C) 2005-07 by The Quassel Team                             *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *