changeset 13678:117ae3cb156e

Shifted IRCWidget.
author Jacob Dawid <jacob.dawid@googlemail.com>
date Sun, 25 Sep 2011 21:12:47 +0200
parents f27573828e92
children e272af3f252d
files gui/octave-gui.pro gui/src/HistoryDockWidget.cpp gui/src/HistoryDockWidget.h gui/src/IRCWidget.cpp gui/src/IRCWidget.h gui/src/VariablesDockWidget.cpp gui/src/VariablesDockWidget.h gui/src/qirc/IRCWidget.cpp gui/src/qirc/IRCWidget.h
diffstat 9 files changed, 575 insertions(+), 591 deletions(-) [+]
line wrap: on
line diff
--- a/gui/octave-gui.pro	Sun Sep 25 18:29:24 2011 +0200
+++ b/gui/octave-gui.pro	Sun Sep 25 21:12:47 2011 +0200
@@ -65,7 +65,7 @@
     	  src/FileEditorMdiSubWindow.cpp \
     	  src/BrowserWidget.cpp \
     	  src/ImageViewerMdiSubWindow.cpp \
-    src/IRCWidget.cpp \
+    src/qirc/IRCWidget.cpp \
     src/SettingsDialog.cpp \
     src/OctaveGUI.cpp \
     src/ResourceManager.cpp \
@@ -92,7 +92,7 @@
     	  src/FileEditorMdiSubWindow.h \
     	  src/BrowserWidget.h \
     	  src/ImageViewerMdiSubWindow.h \
-    src/IRCWidget.h \
+    src/qirc/IRCWidget.h \
     src/SettingsDialog.h \
     src/ResourceManager.h \
     src/CommandLineParser.h \
--- a/gui/src/HistoryDockWidget.cpp	Sun Sep 25 18:29:24 2011 +0200
+++ b/gui/src/HistoryDockWidget.cpp	Sun Sep 25 21:12:47 2011 +0200
@@ -63,12 +63,6 @@
 }
 
 void
-HistoryDockWidget::noticeSettings ()
-{
-
-}
-
-void
 HistoryDockWidget::handleDoubleClick (QModelIndex modelIndex)
 {
   emit commandDoubleClicked (modelIndex.data().toString());
--- a/gui/src/HistoryDockWidget.h	Sun Sep 25 18:29:24 2011 +0200
+++ b/gui/src/HistoryDockWidget.h	Sun Sep 25 21:12:47 2011 +0200
@@ -32,8 +32,6 @@
   void updateHistory (QStringList history);
 
 public slots:
-  /** Tells the widget to notice settings that are probably new. */
-  void noticeSettings ();
   void handleVisibilityChanged (bool visible);
 
 signals:
--- a/gui/src/IRCWidget.cpp	Sun Sep 25 18:29:24 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,448 +0,0 @@
-/* OctaveGUI - A graphical user interface for Octave
- * Copyright (C) 2011 Jacob Dawid (jacob.dawid@googlemail.com)
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "ResourceManager.h"
-#include "IRCWidget.h"
-#include <QMessageBox>
-#include <QHBoxLayout>
-#include <QVBoxLayout>
-#include <QLabel>
-#include <QSettings>
-#include <QInputDialog>
-#include <QKeyEvent>
-#include <QScrollBar>
-#include <QApplication>
-#include "IRCClientImpl.h"
-
-ChatMessageTextEdit::ChatMessageTextEdit (QWidget *parent)
-  : QPlainTextEdit (parent), m_completer (0)
-{
-  setMaximumHeight (50);
-  setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
-}
-
-ChatMessageTextEdit::~ChatMessageTextEdit ()
-{
-}
-
-void
-ChatMessageTextEdit::setCompleter (QCompleter *completer)
-{
-  if (m_completer)
-    QObject::disconnect (m_completer, 0, this, 0);
-
-  m_completer = completer;
-
-  if (!m_completer)
-    return;
-
-  m_completer->setWidget (this);
-  m_completer->setCompletionMode (QCompleter::PopupCompletion);
-  m_completer->setCaseSensitivity (Qt::CaseInsensitive);
-  QObject::connect (m_completer, SIGNAL (activated (QString)),
-                    this, SLOT (insertCompletion (QString)));
-}
-
-QCompleter *
-ChatMessageTextEdit::completer () const
-{
-  return m_completer;
-}
-
-void
-ChatMessageTextEdit::insertCompletion(const QString& completion)
-{
-
-  if (m_completer->widget() != this)
-    return;
-  QTextCursor tc = textCursor();
-  int extra = completion.length() - m_completer->completionPrefix().length();
-  tc.movePosition(QTextCursor::Left);
-  tc.movePosition(QTextCursor::EndOfWord);
-  tc.insertText(completion.right(extra));
-  setTextCursor(tc);
-}
-
-QString
-ChatMessageTextEdit::textUnderCursor () const
-{
-  QTextCursor tc = textCursor ();
-  tc.select (QTextCursor::WordUnderCursor);
-  return tc.selectedText ();
-}
-
-void
-ChatMessageTextEdit::focusInEvent (QFocusEvent *e)
-{
-  if (m_completer)
-    m_completer->setWidget (this);
-  QPlainTextEdit::focusInEvent (e);
-}
-
-void
-ChatMessageTextEdit::keyPressEvent (QKeyEvent *keyPressEvent)
-{
-  if (m_completer) {
-    switch (keyPressEvent->key ()) {
-    case Qt::Key_Enter:
-    case Qt::Key_Return:
-      if (! (keyPressEvent->modifiers () & Qt::ShiftModifier))
-        {
-          emit sendMessage (document ()->toPlainText ());
-          document ()->setPlainText ("");
-        }
-      else
-        {
-          QPlainTextEdit::keyPressEvent (keyPressEvent);
-        }
-      break;
-    case Qt::Key_Escape:
-    case Qt::Key_Tab:
-    case Qt::Key_Backtab:
-      keyPressEvent->ignore ();
-      return;
-    default:
-      QPlainTextEdit::keyPressEvent(keyPressEvent);
-      break;
-      }
-
-    QString completionPrefix = textUnderCursor ();
-    if (completionPrefix != m_completer->completionPrefix ())
-      {
-        m_completer->setCompletionPrefix(completionPrefix);
-      }
-
-    if (completionPrefix.length() > 2)
-      {
-        m_completer->popup ()->setCurrentIndex (m_completer->completionModel ()->index (0, 0));
-        m_completer->complete ();
-      }
-    else
-      {
-        m_completer->popup ()->hide ();
-      }
-  }
-}
-
-IRCWidget::IRCWidget (QWidget * parent):
-QWidget (parent)
-{
-  QSettings *settings = ResourceManager::instance ()->settings ();
-  bool connectOnStartup = settings->value ("connectOnStartup").toBool ();
-  m_autoIdentification = settings->value ("autoIdentification").toBool ();
-  m_nickServPassword = settings->value ("nickServPassword").toString ();
-
-  m_initialNick = settings->value ("IRCNick").toString ();
-
-  if (m_initialNick.isEmpty ())
-    m_initialNick = "OctaveGUI-User";
-
-  QVBoxLayout *layout = new QVBoxLayout ();
-
-  m_chatWindow = new QTextEdit (this);
-  m_chatWindow->setReadOnly (true);
-  m_chatWindow->setEnabled (false);
-  QWidget *bottomWidget = new QWidget (this);
-
-  layout->addWidget (m_chatWindow);
-  layout->addWidget (bottomWidget);
-  layout->setMargin (0);
-  setLayout (layout);
-
-  QHBoxLayout *bottomLayout = new QHBoxLayout ();
-  m_nickButton = new QPushButton (bottomWidget);
-  m_nickButton->setStatusTip (tr ((char *) "Click here to change your nick."));
-  m_nickButton->setText (m_initialNick);
-  m_chatMessageTextEdit = new ChatMessageTextEdit (bottomWidget);
-  m_chatMessageTextEdit->setStatusTip (tr ((char *) "Enter your message here."));
-
-  bottomLayout->addWidget (m_nickButton);
-  bottomLayout->addWidget (new QLabel (":", this));
-  bottomLayout->addWidget (m_chatMessageTextEdit);
-  bottomLayout->setMargin (0);
-  bottomWidget->setLayout (bottomLayout);
-
-  m_nickButton->setEnabled (false);
-  m_chatMessageTextEdit->setEnabled (false);
-
-  //setFocusProxy (m_chatMessageTextEdit);
-  m_nickButton->setFocusProxy (m_chatMessageTextEdit);
-
-  QFont font;
-  font.setFamily ("Courier");
-  font.setPointSize (11);
-  m_chatWindow->setFont (font);
-  m_ircClientInterface = new IRCClientImpl (this);
-  m_octaveChannel = m_ircClientInterface->ircChannelProxy ("#octave");
-
-  connect (m_ircClientInterface, SIGNAL (connected (QString)),
-           this, SLOT (handleConnected (QString)));
-  connect (m_ircClientInterface, SIGNAL(loggedIn(QString)),
-           this, SLOT (joinOctaveChannel (QString)));
-  connect (m_ircClientInterface, SIGNAL (error (QString)),
-           this, SLOT (showErrorMessage (QString)));
-  connect (m_ircClientInterface, SIGNAL (debugMessage (QString)),
-           this, SLOT (showStatusMessage (QString)));
-  connect (m_ircClientInterface, SIGNAL (message (QString, QString, QString)),
-           this, SLOT (showMessage (QString, QString, QString )));
-  connect (m_ircClientInterface, SIGNAL (nicknameChanged (QString,QString)),
-           this, SLOT (handleNickChange (QString,QString)));
-  connect (m_ircClientInterface, SIGNAL (notification (QString,QString)),
-           this, SLOT (showNotification (QString,QString)));
-  connect (m_ircClientInterface, SIGNAL (loggedIn (QString)),
-           this, SLOT (handleLoggedIn(QString)));
-  connect (m_ircClientInterface, SIGNAL (userNicknameChanged (QString)),
-           this, SLOT (handleUserNicknameChanged (QString)));
-
-  connect (m_nickButton, SIGNAL (clicked ()), this, SLOT (showChangeUserNickPopup ()));
-  connect (m_chatMessageTextEdit, SIGNAL (sendMessage (QString)),
-           this, SLOT (sendMessage (QString)));
-
-  m_chatMessageTextEdit->setCompleter
-      (new QCompleter (m_ircClientInterface->ircChannelProxy ("#octave")->userListModel (), this));
-  m_chatWindow->setDocument (m_octaveChannel->conversationModel ());
-
-  if (connectOnStartup)
-    connectToServer ();
-}
-
-void
-IRCWidget::connectToServer ()
-{
-  showStatusMessage ("Looking up irc.freenode.net.");
-  QHostInfo hostInfo = QHostInfo::fromName ("irc.freenode.net");
-  QList<QHostAddress> hostAddresses = hostInfo.addresses();
-  if (hostAddresses.isEmpty ())
-    {
-      showStatusMessage ("Failed to lookup irc.freenode.net.");
-    }
-  else
-    {
-      showStatusMessage (QString ("Attempting to connect to %1.")
-                         .arg (hostAddresses.at (0).toString ()));
-      m_ircClientInterface->connectToHost(hostAddresses.at (0), 6667, m_initialNick);
-    }
-}
-
-void
-IRCWidget::showStatusMessage (const QString& message)
-{
-  m_chatWindow->append (QString ("<i>%1</i>").arg (message));
-}
-
-void
-IRCWidget::showErrorMessage (const QString& message)
-{
-  m_chatWindow->append (QString ("<i>Error: %1</i>").arg (message));
-}
-
-void
-IRCWidget::handleConnected (const QString &host)
-{
-  showStatusMessage (QString ("Connected to server %1.").arg (host));
-}
-
-void
-IRCWidget::joinOctaveChannel (const QString& nick)
-{
-  Q_UNUSED (nick);
-  showStatusMessage (QString ("Joining channel #octave."));
-  m_octaveChannel->sendJoinRequest ();
-}
-
-void
-IRCWidget::showMessage (const QString& channel, const QString& sender, const QString& message)
-{
-  Q_UNUSED (channel);
-
-  // TODO: This doesn't work properly!
-  // Every message makes it emit unreadMessage (true),
-  // though it should inly be emitted when this window
-  // does not have focus, ie. is not the active window.
-  if (!(hasFocus()
-      || m_chatMessageTextEdit->hasFocus ()
-      || m_nickButton->hasFocus ()
-      || m_chatWindow->hasFocus () ))
-    {
-      emit unreadMessages (true);
-    }
-
-  QString output;
-  QString htmlMessage = message;
-  htmlMessage.replace ("<", "&lt;");
-  htmlMessage.replace (">", "&gt;");
-  htmlMessage.replace ("\n", "<br>");
-  if (message.contains (m_ircClientInterface->nickname ()))
-    {
-      output =
-        QString ("<font color=\"#990000\"><b>%1:</b> %2</font>").arg (sender).
-        arg (htmlMessage);
-
-      QApplication::alert (this);
-    }
-  else
-    {
-      output =
-        QString ("<b>%1:</b> %2").arg (sender).
-        arg (htmlMessage);
-    }
-  m_chatWindow->append (output);
-  scrollToBottom ();
-}
-
-void
-IRCWidget::showNotification (const QString& sender, const QString& message)
-{
-  Q_UNUSED (sender);
-  m_chatWindow->append (QString ("<font color=\"#007700\">%1</font>").arg (message));
-  scrollToBottom ();
-}
-
-void
-IRCWidget::showChangeUserNickPopup ()
-{
-  bool ok;
-  QString newNick =
-    QInputDialog::getText (this, QString ("Nickname"),
-			   QString ("Type in your nickname:"),
-                           QLineEdit::Normal, m_ircClientInterface->nickname (), &ok);
-  if (ok)
-    {
-      m_ircClientInterface->sendNicknameChangeRequest (newNick);
-    }
-}
-
-void
-IRCWidget::sendMessage (QString message)
-{
-  // Do not send empty messages.
-  if (message.isEmpty ())
-    return;
-
-  // Remove trailing spaces.
-  while (message.at (0).isSpace ())
-    message.remove (0, 1);
-  if (message.startsWith ("/"))
-    {
-      QStringList line =
-	message.split (QRegExp ("\\s+"), QString::SkipEmptyParts);
-      if (line.at (0) == "/join")
-	{
-          IRCChannelProxyInterface *ircChannel = m_ircClientInterface->ircChannelProxy (line.at (1));
-          ircChannel->sendJoinRequest ();
-	}
-      else if (line.at (0) == "/nick")
-	{
-          m_ircClientInterface->sendNicknameChangeRequest (line.at (1));
-	}
-      else if (line.at (0) == "/msg")
-	{
-	  QString recipient = line.at (1);
-	  // Since we splitted the message before, we have to glue it together again.
-	  QString pmsg = "";
-	  for (int i = 2; i < line.length (); i++)
-	    {
-	      pmsg += line.at (i);
-	      pmsg += " ";
-	    }
-          m_ircClientInterface->sendPrivateMessage(recipient, pmsg);
-	}
-    }
-  else
-    {
-      m_octaveChannel->sendMessage (message);
-      message.replace ("<", "&lt;");
-      message.replace (">", "&gt;");
-      message.replace ("\n", "<br>");
-      m_chatWindow->append (QString ("<b>%1:</b> %2").
-                            arg (m_ircClientInterface->nickname ()).arg (message));
-    }
-
-  scrollToBottom ();
-}
-
-void
-IRCWidget::maybeIdentifyOnNickServ ()
-{
-  if (m_autoIdentification)
-    {
-      m_ircClientInterface->sendPrivateMessage("NickServ", QString ("identify %1").
-                                          arg (m_nickServPassword));
-    }
-}
-
-void
-IRCWidget::scrollToBottom ()
-{
-  if (m_chatWindow->verticalScrollBar ())
-    {
-      m_chatWindow->verticalScrollBar ()->setValue (m_chatWindow->verticalScrollBar ()->maximum ());
-    }
-}
-
-void
-IRCWidget::focusInEvent (QFocusEvent *focusEvent)
-{
-  Q_UNUSED (focusEvent);
-  emit unreadMessages (false);
-  QWidget::focusInEvent (focusEvent);
-
-  m_chatMessageTextEdit->setFocus ();
-}
-
-void
-IRCWidget::handleLoggedIn (const QString &nick)
-{
-  m_chatWindow->
-    append (QString
-            ("<i><font color=\"#00AA00\"><b>Successfully logged in as %1.</b></font></i>").
-            arg (nick));
-  m_nickButton->setEnabled (true);
-  m_chatMessageTextEdit->setEnabled (true);
-  m_chatWindow->setEnabled (true);
-  m_chatMessageTextEdit->setFocus ();
-}
-
-void
-IRCWidget::handleNickChange (const QString &oldNick, const QString &newNick)
-{
-  m_chatWindow->append (QString ("%1 is now known as %2.").arg (oldNick).arg (newNick));
-  scrollToBottom ();
-}
-
-void
-IRCWidget::handleUserJoined (const QString &nick, const QString &channel)
-{
-  m_chatWindow->append (QString ("<i>%1 has joined %2.</i>").arg (nick).arg (channel));
-  scrollToBottom ();
-}
-
-void
-IRCWidget::handleUserQuit (const QString &nick, const QString &reason)
-{
-  m_chatWindow->append (QString ("<i>%1 has quit.(%2).</i>").arg (nick).arg (reason));
-  scrollToBottom ();
-}
-
-void
-IRCWidget::handleUserNicknameChanged (const QString &nick)
-{
-  m_nickButton->setText (nick);
-  QSettings *settings = ResourceManager::instance ()->settings ();
-  settings->setValue ("IRCNick", nick);
-  maybeIdentifyOnNickServ ();
-}
--- a/gui/src/IRCWidget.h	Sun Sep 25 18:29:24 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,101 +0,0 @@
-/* OctaveGUI - A graphical user interface for Octave
- * Copyright (C) 2011 Jacob Dawid (jacob.dawid@googlemail.com)
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef IRCWIDGET_H
-#define IRCWIDGET_H
-
-#include <QWidget>
-#include <QPlainTextEdit>
-#include <QPushButton>
-#include <QLineEdit>
-#include <QCompleter>
-#include "IRCClientInterface.h"
-
-class ChatMessageTextEdit : public QPlainTextEdit
-{
-  Q_OBJECT
-public:
-  explicit ChatMessageTextEdit(QWidget *parent = 0);
-  ~ChatMessageTextEdit();
-
-  void setCompleter(QCompleter *m_completer);
-  QCompleter *completer() const;
-
-signals:
-  void sendMessage (const QString& message);
-
-protected:
-  void keyPressEvent(QKeyEvent *e);
-  void focusInEvent(QFocusEvent *e);
-
-private slots:
-  void insertCompletion(const QString &completion);
-
-private:
-  QString textUnderCursor() const;
-
-private:
-  QCompleter *m_completer;
-};
-
-class IRCWidget : public QWidget
-{
-Q_OBJECT public:
-  explicit IRCWidget (QWidget * parent);
-  void connectToServer ();
-
-public slots:
-  void showStatusMessage (const QString&);
-  void showErrorMessage (const QString&);
-  void showMessage (const QString& channel, const QString& sender, const QString& message);
-  void showNotification (const QString& sender, const QString& message);
-
-  void handleConnected (const QString& host);
-  void joinOctaveChannel (const QString& nick);
-
-  void handleLoggedIn (const QString& nick);
-  void handleNickChange (const QString& oldNick, const QString& newNick);
-  void handleUserJoined (const QString& nick, const QString& channel);
-  void handleUserQuit (const QString& nick, const QString& reason);
-  void handleUserNicknameChanged (const QString& nick);
-
-  void showChangeUserNickPopup ();
-  void sendMessage (QString);
-
-  void maybeIdentifyOnNickServ ();
-  void scrollToBottom ();
-
-signals:
-  void unreadMessages (bool yes);
-
-protected:
-  void focusInEvent (QFocusEvent *focusEvent);
-
-private:
-  IRCClientInterface *m_ircClientInterface;
-  IRCChannelProxyInterface *m_octaveChannel;
-  QTextEdit *m_chatWindow;
-  QPushButton *m_nickButton;
-  ChatMessageTextEdit *m_chatMessageTextEdit;
-
-  QString m_initialNick;
-  bool m_autoIdentification;
-  QString m_nickServPassword;
-  QString m_settingsFile;
-};
-
-#endif // IRCWIDGET_H
--- a/gui/src/VariablesDockWidget.cpp	Sun Sep 25 18:29:24 2011 +0200
+++ b/gui/src/VariablesDockWidget.cpp	Sun Sep 25 21:12:47 2011 +0200
@@ -157,26 +157,26 @@
     // will contain the appropriate QTreeWidgetItem* pointing at it.
     for (int i = 0; i < childCount; i++)
       {
-	child = topLevelItem->child (i);
-	if (child->data (0, 0).toString () ==
-	    QString (symbolRecord.name ().c_str ()))
-	  {
-	    alreadyExists = true;
-	    break;
-	  }
+        child = topLevelItem->child (i);
+        if (child->data (0, 0).toString () ==
+            QString (symbolRecord.name ().c_str ()))
+          {
+            alreadyExists = true;
+            break;
+          }
       }
 
     // If it already exists, just update it.
     if (alreadyExists)
       {
-	updateTreeEntry (child, symbolRecord);
+        updateTreeEntry (child, symbolRecord);
       }
     else
       {
-	// It does not exist, so create a new one and set the right values.
-	child = new QTreeWidgetItem ();
-	updateTreeEntry (child, symbolRecord);
-	topLevelItem->addChild (child);
+        // It does not exist, so create a new one and set the right values.
+        child = new QTreeWidgetItem ();
+        updateTreeEntry (child, symbolRecord);
+        topLevelItem->addChild (child);
       }
   }
 
@@ -186,30 +186,24 @@
       bool existsInVariableList = false;
       QTreeWidgetItem *child = topLevelItem->child (i);
       foreach (SymbolRecord symbolRecord, symbolTable)
-      {
-	if (QString (symbolRecord.name ().c_str ()) ==
-	    child->data (0, 0).toString ())
-	  {
-	    existsInVariableList = true;
-	  }
-      }
+        {
+          if (QString (symbolRecord.name ().c_str ()) ==
+              child->data (0, 0).toString ())
+            {
+              existsInVariableList = true;
+            }
+        }
 
       if (!existsInVariableList)
-	{
-	  topLevelItem->removeChild (child);
-	  delete child;
-	  i--;
-	}
+        {
+          topLevelItem->removeChild (child);
+          delete child;
+          i--;
+        }
     }
 }
 
 void
-VariablesDockWidget::noticeSettings ()
-{
-
-}
-
-void
 VariablesDockWidget::fetchSymbolTable ()
 {
   QList < SymbolRecord > symbolTable = OctaveLink::instance ()->copyCurrentSymbolTable ();
--- a/gui/src/VariablesDockWidget.h	Sun Sep 25 18:29:24 2011 +0200
+++ b/gui/src/VariablesDockWidget.h	Sun Sep 25 21:12:47 2011 +0200
@@ -31,8 +31,6 @@
   void setVariablesList (QList < SymbolRecord > symbolTable);
 
 public slots:
-  /** Tells the widget to notice settings that are probably new. */
-  void noticeSettings ();
   void fetchSymbolTable ();
   void handleVisibilityChanged (bool visible);
 signals:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui/src/qirc/IRCWidget.cpp	Sun Sep 25 21:12:47 2011 +0200
@@ -0,0 +1,448 @@
+/* OctaveGUI - A graphical user interface for Octave
+ * Copyright (C) 2011 Jacob Dawid (jacob.dawid@googlemail.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ResourceManager.h"
+#include "IRCWidget.h"
+#include <QMessageBox>
+#include <QHBoxLayout>
+#include <QVBoxLayout>
+#include <QLabel>
+#include <QSettings>
+#include <QInputDialog>
+#include <QKeyEvent>
+#include <QScrollBar>
+#include <QApplication>
+#include "IRCClientImpl.h"
+
+ChatMessageTextEdit::ChatMessageTextEdit (QWidget *parent)
+  : QPlainTextEdit (parent), m_completer (0)
+{
+  setMaximumHeight (50);
+  setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
+}
+
+ChatMessageTextEdit::~ChatMessageTextEdit ()
+{
+}
+
+void
+ChatMessageTextEdit::setCompleter (QCompleter *completer)
+{
+  if (m_completer)
+    QObject::disconnect (m_completer, 0, this, 0);
+
+  m_completer = completer;
+
+  if (!m_completer)
+    return;
+
+  m_completer->setWidget (this);
+  m_completer->setCompletionMode (QCompleter::PopupCompletion);
+  m_completer->setCaseSensitivity (Qt::CaseInsensitive);
+  QObject::connect (m_completer, SIGNAL (activated (QString)),
+                    this, SLOT (insertCompletion (QString)));
+}
+
+QCompleter *
+ChatMessageTextEdit::completer () const
+{
+  return m_completer;
+}
+
+void
+ChatMessageTextEdit::insertCompletion(const QString& completion)
+{
+
+  if (m_completer->widget() != this)
+    return;
+  QTextCursor tc = textCursor();
+  int extra = completion.length() - m_completer->completionPrefix().length();
+  tc.movePosition(QTextCursor::Left);
+  tc.movePosition(QTextCursor::EndOfWord);
+  tc.insertText(completion.right(extra));
+  setTextCursor(tc);
+}
+
+QString
+ChatMessageTextEdit::textUnderCursor () const
+{
+  QTextCursor tc = textCursor ();
+  tc.select (QTextCursor::WordUnderCursor);
+  return tc.selectedText ();
+}
+
+void
+ChatMessageTextEdit::focusInEvent (QFocusEvent *e)
+{
+  if (m_completer)
+    m_completer->setWidget (this);
+  QPlainTextEdit::focusInEvent (e);
+}
+
+void
+ChatMessageTextEdit::keyPressEvent (QKeyEvent *keyPressEvent)
+{
+  if (m_completer) {
+    switch (keyPressEvent->key ()) {
+    case Qt::Key_Enter:
+    case Qt::Key_Return:
+      if (! (keyPressEvent->modifiers () & Qt::ShiftModifier))
+        {
+          emit sendMessage (document ()->toPlainText ());
+          document ()->setPlainText ("");
+        }
+      else
+        {
+          QPlainTextEdit::keyPressEvent (keyPressEvent);
+        }
+      break;
+    case Qt::Key_Escape:
+    case Qt::Key_Tab:
+    case Qt::Key_Backtab:
+      keyPressEvent->ignore ();
+      return;
+    default:
+      QPlainTextEdit::keyPressEvent(keyPressEvent);
+      break;
+      }
+
+    QString completionPrefix = textUnderCursor ();
+    if (completionPrefix != m_completer->completionPrefix ())
+      {
+        m_completer->setCompletionPrefix(completionPrefix);
+      }
+
+    if (completionPrefix.length() > 2)
+      {
+        m_completer->popup ()->setCurrentIndex (m_completer->completionModel ()->index (0, 0));
+        m_completer->complete ();
+      }
+    else
+      {
+        m_completer->popup ()->hide ();
+      }
+  }
+}
+
+IRCWidget::IRCWidget (QWidget * parent):
+QWidget (parent)
+{
+  QSettings *settings = ResourceManager::instance ()->settings ();
+  bool connectOnStartup = settings->value ("connectOnStartup").toBool ();
+  m_autoIdentification = settings->value ("autoIdentification").toBool ();
+  m_nickServPassword = settings->value ("nickServPassword").toString ();
+
+  m_initialNick = settings->value ("IRCNick").toString ();
+
+  if (m_initialNick.isEmpty ())
+    m_initialNick = "OctaveGUI-User";
+
+  QVBoxLayout *layout = new QVBoxLayout ();
+
+  m_chatWindow = new QTextEdit (this);
+  m_chatWindow->setReadOnly (true);
+  m_chatWindow->setEnabled (false);
+  QWidget *bottomWidget = new QWidget (this);
+
+  layout->addWidget (m_chatWindow);
+  layout->addWidget (bottomWidget);
+  layout->setMargin (0);
+  setLayout (layout);
+
+  QHBoxLayout *bottomLayout = new QHBoxLayout ();
+  m_nickButton = new QPushButton (bottomWidget);
+  m_nickButton->setStatusTip (tr ((char *) "Click here to change your nick."));
+  m_nickButton->setText (m_initialNick);
+  m_chatMessageTextEdit = new ChatMessageTextEdit (bottomWidget);
+  m_chatMessageTextEdit->setStatusTip (tr ((char *) "Enter your message here."));
+
+  bottomLayout->addWidget (m_nickButton);
+  bottomLayout->addWidget (new QLabel (":", this));
+  bottomLayout->addWidget (m_chatMessageTextEdit);
+  bottomLayout->setMargin (0);
+  bottomWidget->setLayout (bottomLayout);
+
+  m_nickButton->setEnabled (false);
+  m_chatMessageTextEdit->setEnabled (false);
+
+  //setFocusProxy (m_chatMessageTextEdit);
+  m_nickButton->setFocusProxy (m_chatMessageTextEdit);
+
+  QFont font;
+  font.setFamily ("Courier");
+  font.setPointSize (11);
+  m_chatWindow->setFont (font);
+  m_ircClientInterface = new IRCClientImpl (this);
+  m_octaveChannel = m_ircClientInterface->ircChannelProxy ("#octave");
+
+  connect (m_ircClientInterface, SIGNAL (connected (QString)),
+           this, SLOT (handleConnected (QString)));
+  connect (m_ircClientInterface, SIGNAL(loggedIn(QString)),
+           this, SLOT (joinOctaveChannel (QString)));
+  connect (m_ircClientInterface, SIGNAL (error (QString)),
+           this, SLOT (showErrorMessage (QString)));
+  connect (m_ircClientInterface, SIGNAL (debugMessage (QString)),
+           this, SLOT (showStatusMessage (QString)));
+  connect (m_ircClientInterface, SIGNAL (message (QString, QString, QString)),
+           this, SLOT (showMessage (QString, QString, QString )));
+  connect (m_ircClientInterface, SIGNAL (nicknameChanged (QString,QString)),
+           this, SLOT (handleNickChange (QString,QString)));
+  connect (m_ircClientInterface, SIGNAL (notification (QString,QString)),
+           this, SLOT (showNotification (QString,QString)));
+  connect (m_ircClientInterface, SIGNAL (loggedIn (QString)),
+           this, SLOT (handleLoggedIn(QString)));
+  connect (m_ircClientInterface, SIGNAL (userNicknameChanged (QString)),
+           this, SLOT (handleUserNicknameChanged (QString)));
+
+  connect (m_nickButton, SIGNAL (clicked ()), this, SLOT (showChangeUserNickPopup ()));
+  connect (m_chatMessageTextEdit, SIGNAL (sendMessage (QString)),
+           this, SLOT (sendMessage (QString)));
+
+  m_chatMessageTextEdit->setCompleter
+      (new QCompleter (m_ircClientInterface->ircChannelProxy ("#octave")->userListModel (), this));
+  m_chatWindow->setDocument (m_octaveChannel->conversationModel ());
+
+  if (connectOnStartup)
+    connectToServer ();
+}
+
+void
+IRCWidget::connectToServer ()
+{
+  showStatusMessage ("Looking up irc.freenode.net.");
+  QHostInfo hostInfo = QHostInfo::fromName ("irc.freenode.net");
+  QList<QHostAddress> hostAddresses = hostInfo.addresses();
+  if (hostAddresses.isEmpty ())
+    {
+      showStatusMessage ("Failed to lookup irc.freenode.net.");
+    }
+  else
+    {
+      showStatusMessage (QString ("Attempting to connect to %1.")
+                         .arg (hostAddresses.at (0).toString ()));
+      m_ircClientInterface->connectToHost(hostAddresses.at (0), 6667, m_initialNick);
+    }
+}
+
+void
+IRCWidget::showStatusMessage (const QString& message)
+{
+  m_chatWindow->append (QString ("<i>%1</i>").arg (message));
+}
+
+void
+IRCWidget::showErrorMessage (const QString& message)
+{
+  m_chatWindow->append (QString ("<i>Error: %1</i>").arg (message));
+}
+
+void
+IRCWidget::handleConnected (const QString &host)
+{
+  showStatusMessage (QString ("Connected to server %1.").arg (host));
+}
+
+void
+IRCWidget::joinOctaveChannel (const QString& nick)
+{
+  Q_UNUSED (nick);
+  showStatusMessage (QString ("Joining channel #octave."));
+  m_octaveChannel->sendJoinRequest ();
+}
+
+void
+IRCWidget::showMessage (const QString& channel, const QString& sender, const QString& message)
+{
+  Q_UNUSED (channel);
+
+  // TODO: This doesn't work properly!
+  // Every message makes it emit unreadMessage (true),
+  // though it should inly be emitted when this window
+  // does not have focus, ie. is not the active window.
+  if (!(hasFocus()
+      || m_chatMessageTextEdit->hasFocus ()
+      || m_nickButton->hasFocus ()
+      || m_chatWindow->hasFocus () ))
+    {
+      emit unreadMessages (true);
+    }
+
+  QString output;
+  QString htmlMessage = message;
+  htmlMessage.replace ("<", "&lt;");
+  htmlMessage.replace (">", "&gt;");
+  htmlMessage.replace ("\n", "<br>");
+  if (message.contains (m_ircClientInterface->nickname ()))
+    {
+      output =
+        QString ("<font color=\"#990000\"><b>%1:</b> %2</font>").arg (sender).
+        arg (htmlMessage);
+
+      QApplication::alert (this);
+    }
+  else
+    {
+      output =
+        QString ("<b>%1:</b> %2").arg (sender).
+        arg (htmlMessage);
+    }
+  m_chatWindow->append (output);
+  scrollToBottom ();
+}
+
+void
+IRCWidget::showNotification (const QString& sender, const QString& message)
+{
+  Q_UNUSED (sender);
+  m_chatWindow->append (QString ("<font color=\"#007700\">%1</font>").arg (message));
+  scrollToBottom ();
+}
+
+void
+IRCWidget::showChangeUserNickPopup ()
+{
+  bool ok;
+  QString newNick =
+    QInputDialog::getText (this, QString ("Nickname"),
+			   QString ("Type in your nickname:"),
+                           QLineEdit::Normal, m_ircClientInterface->nickname (), &ok);
+  if (ok)
+    {
+      m_ircClientInterface->sendNicknameChangeRequest (newNick);
+    }
+}
+
+void
+IRCWidget::sendMessage (QString message)
+{
+  // Do not send empty messages.
+  if (message.isEmpty ())
+    return;
+
+  // Remove trailing spaces.
+  while (message.at (0).isSpace ())
+    message.remove (0, 1);
+  if (message.startsWith ("/"))
+    {
+      QStringList line =
+	message.split (QRegExp ("\\s+"), QString::SkipEmptyParts);
+      if (line.at (0) == "/join")
+	{
+          IRCChannelProxyInterface *ircChannel = m_ircClientInterface->ircChannelProxy (line.at (1));
+          ircChannel->sendJoinRequest ();
+	}
+      else if (line.at (0) == "/nick")
+	{
+          m_ircClientInterface->sendNicknameChangeRequest (line.at (1));
+	}
+      else if (line.at (0) == "/msg")
+	{
+	  QString recipient = line.at (1);
+	  // Since we splitted the message before, we have to glue it together again.
+	  QString pmsg = "";
+	  for (int i = 2; i < line.length (); i++)
+	    {
+	      pmsg += line.at (i);
+	      pmsg += " ";
+	    }
+          m_ircClientInterface->sendPrivateMessage(recipient, pmsg);
+	}
+    }
+  else
+    {
+      m_octaveChannel->sendMessage (message);
+      message.replace ("<", "&lt;");
+      message.replace (">", "&gt;");
+      message.replace ("\n", "<br>");
+      m_chatWindow->append (QString ("<b>%1:</b> %2").
+                            arg (m_ircClientInterface->nickname ()).arg (message));
+    }
+
+  scrollToBottom ();
+}
+
+void
+IRCWidget::maybeIdentifyOnNickServ ()
+{
+  if (m_autoIdentification)
+    {
+      m_ircClientInterface->sendPrivateMessage("NickServ", QString ("identify %1").
+                                          arg (m_nickServPassword));
+    }
+}
+
+void
+IRCWidget::scrollToBottom ()
+{
+  if (m_chatWindow->verticalScrollBar ())
+    {
+      m_chatWindow->verticalScrollBar ()->setValue (m_chatWindow->verticalScrollBar ()->maximum ());
+    }
+}
+
+void
+IRCWidget::focusInEvent (QFocusEvent *focusEvent)
+{
+  Q_UNUSED (focusEvent);
+  emit unreadMessages (false);
+  QWidget::focusInEvent (focusEvent);
+
+  m_chatMessageTextEdit->setFocus ();
+}
+
+void
+IRCWidget::handleLoggedIn (const QString &nick)
+{
+  m_chatWindow->
+    append (QString
+            ("<i><font color=\"#00AA00\"><b>Successfully logged in as %1.</b></font></i>").
+            arg (nick));
+  m_nickButton->setEnabled (true);
+  m_chatMessageTextEdit->setEnabled (true);
+  m_chatWindow->setEnabled (true);
+  m_chatMessageTextEdit->setFocus ();
+}
+
+void
+IRCWidget::handleNickChange (const QString &oldNick, const QString &newNick)
+{
+  m_chatWindow->append (QString ("%1 is now known as %2.").arg (oldNick).arg (newNick));
+  scrollToBottom ();
+}
+
+void
+IRCWidget::handleUserJoined (const QString &nick, const QString &channel)
+{
+  m_chatWindow->append (QString ("<i>%1 has joined %2.</i>").arg (nick).arg (channel));
+  scrollToBottom ();
+}
+
+void
+IRCWidget::handleUserQuit (const QString &nick, const QString &reason)
+{
+  m_chatWindow->append (QString ("<i>%1 has quit.(%2).</i>").arg (nick).arg (reason));
+  scrollToBottom ();
+}
+
+void
+IRCWidget::handleUserNicknameChanged (const QString &nick)
+{
+  m_nickButton->setText (nick);
+  QSettings *settings = ResourceManager::instance ()->settings ();
+  settings->setValue ("IRCNick", nick);
+  maybeIdentifyOnNickServ ();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui/src/qirc/IRCWidget.h	Sun Sep 25 21:12:47 2011 +0200
@@ -0,0 +1,101 @@
+/* OctaveGUI - A graphical user interface for Octave
+ * Copyright (C) 2011 Jacob Dawid (jacob.dawid@googlemail.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef IRCWIDGET_H
+#define IRCWIDGET_H
+
+#include <QWidget>
+#include <QPlainTextEdit>
+#include <QPushButton>
+#include <QLineEdit>
+#include <QCompleter>
+#include "IRCClientInterface.h"
+
+class ChatMessageTextEdit : public QPlainTextEdit
+{
+  Q_OBJECT
+public:
+  explicit ChatMessageTextEdit(QWidget *parent = 0);
+  ~ChatMessageTextEdit();
+
+  void setCompleter(QCompleter *m_completer);
+  QCompleter *completer() const;
+
+signals:
+  void sendMessage (const QString& message);
+
+protected:
+  void keyPressEvent(QKeyEvent *e);
+  void focusInEvent(QFocusEvent *e);
+
+private slots:
+  void insertCompletion(const QString &completion);
+
+private:
+  QString textUnderCursor() const;
+
+private:
+  QCompleter *m_completer;
+};
+
+class IRCWidget : public QWidget
+{
+Q_OBJECT public:
+  explicit IRCWidget (QWidget * parent);
+  void connectToServer ();
+
+public slots:
+  void showStatusMessage (const QString&);
+  void showErrorMessage (const QString&);
+  void showMessage (const QString& channel, const QString& sender, const QString& message);
+  void showNotification (const QString& sender, const QString& message);
+
+  void handleConnected (const QString& host);
+  void joinOctaveChannel (const QString& nick);
+
+  void handleLoggedIn (const QString& nick);
+  void handleNickChange (const QString& oldNick, const QString& newNick);
+  void handleUserJoined (const QString& nick, const QString& channel);
+  void handleUserQuit (const QString& nick, const QString& reason);
+  void handleUserNicknameChanged (const QString& nick);
+
+  void showChangeUserNickPopup ();
+  void sendMessage (QString);
+
+  void maybeIdentifyOnNickServ ();
+  void scrollToBottom ();
+
+signals:
+  void unreadMessages (bool yes);
+
+protected:
+  void focusInEvent (QFocusEvent *focusEvent);
+
+private:
+  IRCClientInterface *m_ircClientInterface;
+  IRCChannelProxyInterface *m_octaveChannel;
+  QTextEdit *m_chatWindow;
+  QPushButton *m_nickButton;
+  ChatMessageTextEdit *m_chatMessageTextEdit;
+
+  QString m_initialNick;
+  bool m_autoIdentification;
+  QString m_nickServPassword;
+  QString m_settingsFile;
+};
+
+#endif // IRCWIDGET_H