Merged with Spanish translations update done by Jaime.

Mon, 10 Dec 2012 18:40:10 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Mon, 10 Dec 2012 18:40:10 +0100
changeset 2260
e5146f38a03a
parent 2258
9ca42fd3ecc0 (diff)
parent 2259
227d9c687122 (current diff)
child 2261
f4bb5648fc29

Merged with Spanish translations update done by Jaime.

--- a/Cooperation/ChatWidget.py	Sun Dec 02 18:53:39 2012 +0100
+++ b/Cooperation/ChatWidget.py	Mon Dec 10 18:40:10 2012 +0100
@@ -504,6 +504,8 @@
             self.__chatMenu.addAction(
                 UI.PixmapCache.getIcon("fileSave.png"),
                 self.trUtf8("Save"), self.__saveChat)
+        
+        self.on_chatEdit_copyAvailable(False)
     
     @pyqtSlot(bool)
     def on_chatEdit_copyAvailable(self, yes):
--- a/IconEditor/cursors/cursors_rc.py	Sun Dec 02 18:53:39 2012 +0100
+++ b/IconEditor/cursors/cursors_rc.py	Mon Dec 10 18:40:10 2012 +0100
@@ -2,8 +2,8 @@
 
 # Resource object code
 #
-# Created: Do. Dez 31 16:47:09 2009
-#      by: The Resource Compiler for PyQt (Qt v4.5.3)
+# Created: Fr. Dez 7 18:40:19 2012
+#      by: The Resource Compiler for PyQt (Qt v4.8.3)
 #
 # WARNING! All changes made in this file will be lost!
 
@@ -62,50 +62,16 @@
 \x2e\x2e\x2e\x2e\x2e\x22\x2c\x0a\x22\x23\x69\x23\x2e\x2e\x2e\x2e\
 \x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x22\
 \x7d\x3b\x0a\
-\x00\x00\x02\x93\
-\x2f\
-\x2a\x20\x58\x50\x4d\x20\x2a\x2f\x0a\x73\x74\x61\x74\x69\x63\x20\
-\x63\x68\x61\x72\x20\x2a\x61\x69\x6d\x5b\x5d\x3d\x7b\x0a\x22\x32\
-\x32\x20\x32\x32\x20\x33\x20\x31\x22\x2c\x0a\x22\x2e\x20\x63\x20\
-\x4e\x6f\x6e\x65\x22\x2c\x0a\x22\x61\x20\x63\x20\x23\x30\x30\x30\
-\x30\x30\x30\x22\x2c\x0a\x22\x23\x20\x63\x20\x23\x66\x66\x66\x66\
-\x66\x66\x22\x2c\x0a\x22\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\
-\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x22\x2c\x0a\x22\
-\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x23\x2e\x2e\x2e\x2e\x2e\
-\x2e\x2e\x2e\x2e\x2e\x2e\x22\x2c\x0a\x22\x2e\x2e\x2e\x2e\x2e\x2e\
-\x2e\x2e\x2e\x23\x61\x23\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\
-\x22\x2c\x0a\x22\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x23\x61\x23\
-\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x22\x2c\x0a\x22\x2e\x2e\
-\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x23\x61\x23\x2e\x2e\x2e\x2e\x2e\x2e\
-\x2e\x2e\x2e\x2e\x22\x2c\x0a\x22\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\
-\x2e\x23\x61\x23\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x22\x2c\
-\x0a\x22\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x23\x61\x23\x2e\x2e\
-\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x22\x2c\x0a\x22\x2e\x2e\x2e\x2e\
-\x2e\x2e\x2e\x2e\x2e\x23\x61\x23\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\
-\x2e\x2e\x22\x2c\x0a\x22\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x23\
-\x61\x23\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x22\x2c\x0a\x22\
-\x2e\x2e\x23\x23\x23\x23\x23\x23\x23\x2e\x2e\x2e\x23\x23\x23\x23\
-\x23\x23\x23\x2e\x2e\x2e\x22\x2c\x0a\x22\x2e\x23\x61\x61\x61\x61\
-\x61\x61\x61\x2e\x2e\x2e\x61\x61\x61\x61\x61\x61\x61\x23\x2e\x2e\
-\x22\x2c\x0a\x22\x2e\x2e\x23\x23\x23\x23\x23\x23\x23\x2e\x2e\x2e\
-\x23\x23\x23\x23\x23\x23\x23\x2e\x2e\x2e\x22\x2c\x0a\x22\x2e\x2e\
-\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x61\x2e\x2e\x2e\x2e\x2e\x2e\x2e\
-\x2e\x2e\x2e\x2e\x22\x2c\x0a\x22\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\
-\x2e\x23\x61\x23\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x22\x2c\
-\x0a\x22\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x23\x61\x23\x2e\x2e\
-\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x22\x2c\x0a\x22\x2e\x2e\x2e\x2e\
-\x2e\x2e\x2e\x2e\x2e\x23\x61\x23\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\
-\x2e\x2e\x22\x2c\x0a\x22\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x23\
-\x61\x23\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x22\x2c\x0a\x22\
-\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x23\x61\x23\x2e\x2e\x2e\x2e\
-\x2e\x2e\x2e\x2e\x2e\x2e\x22\x2c\x0a\x22\x2e\x2e\x2e\x2e\x2e\x2e\
-\x2e\x2e\x2e\x23\x61\x23\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\
-\x22\x2c\x0a\x22\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x23\x2e\
-\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x22\x2c\x0a\x22\x2e\x2e\
-\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\
-\x2e\x2e\x2e\x2e\x22\x2c\x0a\x22\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\
-\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x22\x7d\
-\x3b\x0a\
+\x00\x00\x00\x7d\
+\x00\
+\x00\x02\x93\x78\x9c\xd3\xd7\x52\x88\x08\xf0\x55\xd0\xd2\xe7\x2a\
+\x2e\x49\x2c\xc9\x4c\x56\x48\xce\x48\x2c\x52\xd0\x4a\xcc\xcc\x8d\
+\x8e\xb5\xad\xe6\x52\x32\x32\x52\x00\x22\x63\x05\x43\x25\x1d\x2e\
+\x25\x3d\x85\x64\x05\xbf\xfc\xbc\x54\x10\x3b\x11\xc8\x56\x36\x00\
+\x03\x10\x57\x19\xc4\x4d\x03\x03\xb0\x4a\xac\x00\x55\x46\x19\x97\
+\x8c\x72\xa2\xf2\x50\x92\x51\x86\x00\x3d\x64\x16\x58\x46\x39\x11\
+\x02\x80\x7c\x28\x4b\x99\xa0\x1e\x38\x48\x1c\x8a\xa1\x83\x3b\x4e\
+\x51\x00\x1e\x99\x5a\x6b\x2e\x00\x12\x9a\x79\xb2\
 \x00\x00\x02\xe1\
 \x2f\
 \x2a\x20\x58\x50\x4d\x20\x2a\x2f\x0a\x73\x74\x61\x74\x69\x63\x20\
@@ -311,19 +277,17 @@
 
 qt_resource_struct = b"\
 \x00\x00\x00\x00\x00\x02\x00\x00\x00\x06\x00\x00\x00\x01\
-\x00\x00\x00\x54\x00\x00\x00\x00\x00\x01\x00\x00\x05\xaf\
-\x00\x00\x00\xa0\x00\x00\x00\x00\x00\x01\x00\x00\x0b\xa5\
-\x00\x00\x00\x32\x00\x00\x00\x00\x00\x01\x00\x00\x03\x18\
-\x00\x00\x00\xbc\x00\x00\x00\x00\x00\x01\x00\x00\x0c\xb0\
+\x00\x00\x00\x54\x00\x00\x00\x00\x00\x01\x00\x00\x03\x99\
+\x00\x00\x00\xa0\x00\x00\x00\x00\x00\x01\x00\x00\x09\x8f\
+\x00\x00\x00\x32\x00\x01\x00\x00\x00\x01\x00\x00\x03\x18\
+\x00\x00\x00\xbc\x00\x00\x00\x00\x00\x01\x00\x00\x0a\x9a\
 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
-\x00\x00\x00\x7c\x00\x00\x00\x00\x00\x01\x00\x00\x08\x94\
+\x00\x00\x00\x7c\x00\x00\x00\x00\x00\x01\x00\x00\x06\x7e\
 "
 
-
 def qInitResources():
     QtCore.qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data)
 
-
 def qCleanupResources():
     QtCore.qUnregisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data)
 
--- a/Network/IRC/IrcChannelWidget.py	Sun Dec 02 18:53:39 2012 +0100
+++ b/Network/IRC/IrcChannelWidget.py	Mon Dec 10 18:40:10 2012 +0100
@@ -9,10 +9,10 @@
 
 import re
 
-from PyQt4.QtCore import pyqtSlot, pyqtSignal, QDateTime
-from PyQt4.QtGui import QWidget, QListWidgetItem, QIcon, QPainter
+from PyQt4.QtCore import pyqtSlot, pyqtSignal, QDateTime, QPoint, QFileInfo, QTimer
+from PyQt4.QtGui import QWidget, QListWidgetItem, QIcon, QPainter, QMenu, QApplication
 
-from E5Gui import E5MessageBox
+from E5Gui import E5MessageBox, E5FileDialog
 from E5Gui.E5Application import e5App
 
 from .Ui_IrcChannelWidget import Ui_IrcChannelWidget
@@ -134,14 +134,43 @@
         painter.drawPixmap(0, 0, pix2)
         painter.end()
         return QIcon(pix1)
+    
+    def parseWhoFlags(self, flags):
+        """
+        Public method to parse the user flags reported by a WHO command.
+        
+        @param flags user flags as reported by WHO (string)
+        """
+        # H The user is not away.
+        # G The user is set away.
+        # * The user is an IRC operator.
+        # @ The user is a channel op in the channel listed in the first field.
+        # + The user is voiced in the channel listed.
+        if flags.endswith("@"):
+            privilege = IrcUserItem.Operator
+        elif flags.endswith("+"):
+            privilege = IrcUserItem.Voice
+        else:
+            privilege = IrcUserItem.Normal
+        if "*" in flags:
+            privilege = IrcUserItem.Admin
+        if flags.startswith("G"):
+            privilege |= IrcUserItem.Away
+        self.__privilege = privilege
+        self.__setIcon()
 
 
 class IrcChannelWidget(QWidget, Ui_IrcChannelWidget):
     """
     Class implementing the IRC channel widget.
+    
+    @signal sendData(str) emitted to send a message to the channel
+    @signal channelClosed(str) emitted after the user has left the channel
+    @signal openPrivateChat(str) emitted to open a "channel" for private messages
     """
     sendData = pyqtSignal(str)
     channelClosed = pyqtSignal(str)
+    openPrivateChat = pyqtSignal(str)
     
     UrlRe = re.compile(r"""((?:http|ftp|https):\/\/[\w\-_]+(?:\.[\w\-_]+)+"""
         r"""(?:[\w\-\.,@?^=%&amp;:/~\+#]*[\w\-\@?^=%&amp;/~\+#])?)""")
@@ -150,27 +179,6 @@
     LeaveIndicator = "&lt;--"
     MessageIndicator = "***"
     
-    # TODO: add context menu to users list with these entries:
-    #       Whois
-    #       Private Message
-    # TODO: add "Auto WHO" functionality (WHO <channel> %nf)
-    #       The possible combinations for this field are listed below:
-    #       H The user is not away.
-    #       G The user is set away.
-    #       * The user is an IRC operator.
-    #       @ The user is a channel op in the channel listed in the first field.
-    #       + The user is voiced in the channel listed.
-    # TODO: add context menu to messages pane with these entries:
-    #       Copy
-    #       Copy Link Location
-    #       Copy All
-    #       Clear
-    #       Save
-    #       Remember Position
-    # TODO: Remember current position with <hr/> when widget is invisible
-    # TODO: Remember current position with <hr/> upon user request (only one such line)
-    # TODO: Remember current position with <hr/> when away and configured accordingly
-    # TODO: Check away indication in the user list
     def __init__(self, parent=None):
         """
         Constructor
@@ -181,17 +189,27 @@
         self.setupUi(self)
         
         self.__ui = e5App().getObject("UserInterface")
+        self.__ircWidget = parent
+        
+        self.__initMessagesMenu()
+        self.__initUsersMenu()
         
         self.__name = ""
         self.__userName = ""
         self.__partMessage = ""
         self.__prefixToPrivilege = {}
+        self.__private = False
+        self.__privatePartner = ""
+        self.__whoIsNick = ""
+        
+        self.__markerLine = ""
+        self.__hidden = True
         
         self.__patterns = [
             # :foo_!n=foo@foohost.bar.net PRIVMSG #eric-ide :some long message
-            (re.compile(r":([^!]+).*\sPRIVMSG\s([^ ]+)\s:(.*)"), self.__message),
+            # :foo_!n=foo@foohost.bar.net PRIVMSG bar_ :some long message
+            (re.compile(r":([^!]+)!([^ ]+)\sPRIVMSG\s([^ ]+)\s:(.*)"), self.__message),
             # :foo_!n=foo@foohost.bar.net JOIN :#eric-ide
-            # :detlev_!~detlev@mnch-5d876cfa.pool.mediaWays.net JOIN #eric-ide
             (re.compile(r":([^!]+)!([^ ]+)\sJOIN\s:?([^ ]+)"), self.__userJoin),
             # :foo_!n=foo@foohost.bar.net PART #eric-ide :part message
             (re.compile(r":([^!]+).*\sPART\s([^ ]+)\s:(.*)"), self.__userPart),
@@ -203,9 +221,15 @@
             (re.compile(r":([^!]+).*\sQUIT\s*"), self.__userQuit),
             # :foo_!n=foo@foohost.bar.net NICK :newnick
             (re.compile(r":([^!]+).*\sNICK\s:(.*)"), self.__userNickChange),
-            # :barty!n=foo@foohost.bar.net MODE #eric-ide +o foo_
-            (re.compile(r":([^!]+).*\sMODE\s([^ ]+)\s([^ ]+)\s([^ ]+).*"),
+            # :foo_!n=foo@foohost.bar.net MODE #eric-ide +o foo_
+            (re.compile(r":([^!]+).*\sMODE\s([^ ]+)\s([+-][ovO]+)\s([^ ]+).*"),
                 self.__setUserPrivilege),
+            # :cameron.freenode.net MODE #testeric +ns
+            (re.compile(r":([^ ]+)\sMODE\s([^ ]+)\s(.+)"), self.__updateChannelModes),
+            # :sturgeon.freenode.net 301 foo_ bar :Gone away for now
+            (re.compile(r":.*\s301\s([^ ]+)\s([^ ]+)\s:(.+)"), self.__userAway),
+            # :sturgeon.freenode.net 315 foo_ #eric-ide :End of /WHO list.
+            (re.compile(r":.*\s315\s[^ ]+\s([^ ]+)\s:(.*)"), self.__whoEnd),
             # :zelazny.freenode.net 324 foo_ #eric-ide +cnt
             (re.compile(r":.*\s324\s.*\s([^ ]+)\s(.+)"), self.__channelModes),
             # :zelazny.freenode.net 328 foo_ #eric-ide :http://www.buggeroff.com/
@@ -216,11 +240,61 @@
             (re.compile(r":.*\s332\s.*\s([^ ]+)\s:(.*)"), self.__setTopic),
             # :zelazny.freenode.net foo_ 333 #eric-ide foo 1353089020
             (re.compile(r":.*\s333\s.*\s([^ ]+)\s([^ ]+)\s(\d+)"), self.__topicCreated), 
+            # :cameron.freenode.net 352 detlev_ #eric-ide ~foo foohost.bar.net cameron.freenode.net foo_ H :0 Foo Bar
+            (re.compile(r":.*\s352\s[^ ]+\s([^ ]+)\s([^ ]+)\s([^ ]+)\s[^ ]+\s([^ ]+)"
+                        r"\s([^ ]+)\s:\d+\s(.*)"), self.__whoEntry),
             # :zelazny.freenode.net 353 foo_ @ #eric-ide :@user1 +user2 user3
             (re.compile(r":.*\s353\s.*\s.\s([^ ]+)\s:(.*)"), self.__userList),
+            # :sturgeon.freenode.net 354 foo_ 42 ChanServ H@
+            (re.compile(r":.*\s354\s[^ ]+\s42\s([^ ]+)\s(.*)"), self.__autoWhoEntry),
             # :zelazny.freenode.net 366 foo_ #eric-ide :End of /NAMES list.
             (re.compile(r":.*\s366\s.*\s([^ ]+)\s:(.*)"), self.__ignore),
+            # :sturgeon.freenode.net 704 foo_ index :Help topics available to users:
+            (re.compile(r":.*\s70[456]\s[^ ]+\s([^ ]+)\s:(.*)"), self.__help),
+            
+            # WHOIS replies
+            # :sturgeon.freenode.net 311 foo_ bar ~bar barhost.foo.net * :Bar User
+            (re.compile(r":.*\s311\s[^ ]+\s([^ ]+)\s([^ ]+)\s([^ ]+)\s\*\s:(.*)"),
+                self.__whoIsUser),
+            # :sturgeon.freenode.net 319 foo_ bar :@#eric-ide
+            (re.compile(r":.*\s319\s[^ ]+\s([^ ]+)\s:(.*)"), self.__whoIsChannels),
+            # :sturgeon.freenode.net 312 foo_ bar sturgeon.freenode.net :London, UK
+            (re.compile(r":.*\s312\s[^ ]+\s([^ ]+)\s([^ ]+)\s:(.*)"), self.__whoIsServer),
+            # :sturgeon.freenode.net 671 foo_ bar :is using a secure connection
+            (re.compile(r":.*\s671\s[^ ]+\s([^ ]+)\s:.*"), self.__whoIsSecure),
+            # :sturgeon.freenode.net 317 foo_ bar 3758 1355046912 :seconds idle, signon time
+            (re.compile(r":.*\s317\s[^ ]+\s([^ ]+)\s(\d+)\s(\d+)\s:.*"),
+                self.__whoIsIdle),
+            # :sturgeon.freenode.net 330 foo_ bar bar :is logged in as
+            (re.compile(r":.*\s330\s[^ ]+\s([^ ]+)\s([^ ]+)\s:.*"), self.__whoIsAccount),
+            # :sturgeon.freenode.net 318 foo_ bar :End of /WHOIS list.
+            (re.compile(r":.*\s318\s[^ ]+\s([^ ]+)\s:(.*)"), self.__whoIsEnd),
+            # :sturgeon.freenode.net 307 foo_ bar :is an identified user
+            (re.compile(r":.*\s307\s[^ ]+\s([^ ]+)\s:(.*)"), self.__whoIsIdentify),
+            # :sturgeon.freenode.net 320 foo_ bar :is an identified user
+            (re.compile(r":.*\s320\s[^ ]+\s([^ ]+)\s:(.*)"), self.__whoIsIdentify),
+            # :sturgeon.freenode.net 310 foo_ bar :is available for help
+            (re.compile(r":.*\s310\s[^ ]+\s([^ ]+)\s:(.*)"), self.__whoIsHelper),
+            # :sturgeon.freenode.net 338 foo_ bar real.ident@real.host 12.34.56.78 :Actual user@host, Actual IP
+            (re.compile(r":.*\s338\s[^ ]+\s([^ ]+)\s([^ ]+)\s([^ ]+)\s:.*"),
+                self.__whoIsActually),
+            # :sturgeon.freenode.net 313 foo_ bar :is an IRC Operator
+            (re.compile(r":.*\s313\s[^ ]+\s([^ ]+)\s:(.*)"), self.__whoIsOperator),
+            # :sturgeon.freenode.net 378 foo_ bar :is connecting from *@mnch-4d044d5a.pool.mediaWays.net 77.4.77.90
+            (re.compile(r":.*\s311\s[^ ]+\s([^ ]+)\s:.*\s([^ ]+)\s([^ ]+)"),
+                self.__whoIsConnection),
         ]
+        # group(1)   nick
+        # group(2)   host name
+        # group(3)   IP
+        # group(4)   real name
+        # group(5)   
+        
+        self.__autoWhoTemplate = "WHO {0} %tnf,42"
+        self.__autoWhoTimer = QTimer()
+        self.__autoWhoTimer.setSingleShot(True)
+        self.__autoWhoTimer.timeout.connect(self.__sendAutoWhoCommand)
+        self.__autoWhoRequested = False
     
     @pyqtSlot()
     def on_messageEdit_returnPressed(self):
@@ -228,14 +302,33 @@
         Private slot to send a message to the channel.
         """
         msg = self.messageEdit.text()
-        self.messages.append(
-            '<font color="{0}">{2} <b>&lt;</b><font color="{1}">{3}</font>'
-            '<b>&gt;</b> {4}</font>'.format(
-            Preferences.getIrc("ChannelMessageColour"),
-            Preferences.getIrc("OwnNickColour"),
-            ircTimestamp(), self.__userName, Utilities.html_encode(msg)))
-        self.sendData.emit("PRIVMSG " + self.__name + " :" + msg)
-        self.messageEdit.clear()
+        if msg:
+            self.messages.append(
+                '<font color="{0}">{2} <b>&lt;</b><font color="{1}">{3}</font>'
+                '<b>&gt;</b> {4}</font>'.format(
+                Preferences.getIrc("ChannelMessageColour"),
+                Preferences.getIrc("OwnNickColour"),
+                ircTimestamp(), self.__userName, Utilities.html_encode(msg)))
+            if msg.startswith("/"):
+                if self.__private:
+                    E5MessageBox.information(self,
+                        self.trUtf8("Send Message"),
+                        self.trUtf8("""Messages starting with a '/' are not allowed"""
+                                    """ in private chats."""))
+                else:
+                    msgList = msg.split(None, 1)
+                    cmd = msgList[0][1:].upper()
+                    if cmd == "MSG":
+                        cmd = "PRIVMSG"
+                    msgList[0] = cmd
+                    self.sendData.emit(" ".join(msgList))
+            else:
+                if self.__private:
+                    self.sendData.emit("PRIVMSG " + self.__privatePartner + " :" + msg)
+                else:
+                    self.sendData.emit("PRIVMSG " + self.__name + " :" + msg)
+            self.messageEdit.clear()
+            self.unsetMarkerLine()
     
     def requestLeave(self):
         """
@@ -246,7 +339,8 @@
             self.trUtf8("""Do you really want to leave the IRC channel <b>{0}</b>?""")\
                 .format(self.__name))
         if ok:
-            self.sendData.emit("PART " + self.__name + " :" + self.__partMessage)
+            if not self.__private:
+                self.sendData.emit("PART " + self.__name + " :" + self.__partMessage)
             self.channelClosed.emit(self.__name)
     
     def name(self):
@@ -287,7 +381,7 @@
         
         @param name user name for the channel (string)
         """
-        self.__userName = name.lower()
+        self.__userName = name
     
     def partMessage(self):
         """
@@ -305,6 +399,25 @@
         """
         self.__partMessage = message
     
+    def setPrivate(self, private, partner=""):
+        """
+        Public method to set the private chat mode.
+        
+        @param private flag indicating private chat mode (boolean)
+        @param partner name of the partner user (string)
+        """
+        self.__private = private
+        self.__privatePartner = partner
+    
+    def setPrivateInfo(self, infoText):
+        """
+        Public method to set some info text for private chat mode.
+        
+        @param infoText info text to be shown (string)
+        """
+        if self.__private:
+            self.topicLabel.setText(infoText)
+    
     def handleMessage(self, line):
         """
         Public method to handle the message sent by the server.
@@ -327,26 +440,51 @@
         @param match match object that matched the pattern
         @return flag indicating whether the message was handled (boolean)
         """
-        if match.group(2).lower() == self.__name:
-            msg = ircFilter(match.group(3))
-            self.messages.append(
-                '<font color="{0}">{2} <b>&lt;</b><font color="{1}">{3}</font>'
-                '<b>&gt;</b> {4}</font>'.format(
-                Preferences.getIrc("ChannelMessageColour"),
-                Preferences.getIrc("NickColour"),
-                ircTimestamp(), match.group(1),
-                msg))
-            if Preferences.getIrc("ShowNotifications"):
-                if Preferences.getIrc("NotifyMessage"):
-                    self.__ui.showNotification(UI.PixmapCache.getPixmap("irc48.png"),
-                        self.trUtf8("Channel Message"), msg)
-                elif Preferences.getIrc("NotifyNick") and self.__userName in msg:
-                    self.__ui.showNotification(UI.PixmapCache.getPixmap("irc48.png"),
-                        self.trUtf8("Nick mentioned"), msg)
+        # group(1)   sender user name
+        # group(2)   sender user@host
+        # group(3)   target nick
+        # group(4)   message
+        if match.group(3).lower() == self.__name:
+            self.addMessage(match.group(1), match.group(4))
+            if self.__private and not self.topicLabel.text():
+                self.setPrivateInfo("{0} - {1}".format(match.group(1), match.group(2)))
             return True
         
         return False
     
+    def addMessage(self, sender, msg):
+        """
+        Public method to add a message from external.
+        
+        @param sender nick name of the sender (string)
+        @param msg message received from sender (string)
+        """
+        self.__appendMessage(
+            '<font color="{0}">{2} <b>&lt;</b><font color="{1}">{3}</font>'
+            '<b>&gt;</b> {4}</font>'.format(
+            Preferences.getIrc("ChannelMessageColour"),
+            Preferences.getIrc("NickColour"),
+            ircTimestamp(), sender, ircFilter(msg)))
+        if Preferences.getIrc("ShowNotifications"):
+            if Preferences.getIrc("NotifyMessage"):
+                self.__ui.showNotification(UI.PixmapCache.getPixmap("irc48.png"),
+                    self.trUtf8("Channel Message"), msg)
+            elif Preferences.getIrc("NotifyNick") and \
+                 self.__userName.lower() in msg.lower():
+                self.__ui.showNotification(UI.PixmapCache.getPixmap("irc48.png"),
+                    self.trUtf8("Nick mentioned"), msg)
+    
+    def addUsers(self, users):
+        """
+        Public method to add users to the channel.
+        
+        @param users list of user names to add (list of string)
+        """
+        for user in users:
+            itm = self.__findUser(user)
+            if itm is None:
+                IrcUserItem(user, self.usersList)
+    
     def __userJoin(self, match):
         """
         Private method to handle a user joining the channel.
@@ -472,6 +610,20 @@
         
         return False
     
+    def __userAway(self, match):
+        """
+        Private method to handle a topic change of the channel.
+        
+        @param match match object that matched the pattern
+        @return flag indicating whether the message was handled (boolean)
+        """
+        if match.group(1).lower() == self.__name:
+            self.__addManagementMessage(self.trUtf8("Away"),
+                self.trUtf8("{0} is away: {1}").format(match.group(2), match.group(3)))
+            return True
+        
+        return False
+    
     def __setTopic(self, match):
         """
         Private method to handle a topic change of the channel.
@@ -569,6 +721,151 @@
         
         return False
     
+    def __updateChannelModes(self, match):
+        """
+        Private method to handle a message reporting the channel modes.
+        
+        @param match match object that matched the pattern
+        @return flag indicating whether the message was handled (boolean)
+        """
+        # group(1)  user or server
+        # group(2)  channel
+        # group(3)  modes and parameter list
+        if match.group(2).lower() == self.__name:
+            nick = match.group(1)
+            modesParameters = match.group(3).split()
+            modeString = modesParameters.pop(0)
+            isPlus = True
+            message = ""
+            for mode in modeString:
+                if mode == "+":
+                    isPlus = True
+                    continue
+                elif mode == "-":
+                    isPlus = False
+                    continue
+                elif mode == "a":
+                    if isPlus:
+                        message = self.trUtf8(
+                            "{0} sets the channel mode to 'anonymous'.").format(nick)
+                    else:
+                        message = self.trUtf8(
+                            "{0} removes the 'anonymous' mode from the channel.").format(
+                            nick)
+                elif mode == "b":
+                    if isPlus:
+                        message = self.trUtf8(
+                            "{0} sets a ban on {1}.").format(
+                            nick, modesParameters.pop(0))
+                    else:
+                        message = self.trUtf8(
+                            "{0} removes the ban on {1}.").format(
+                            nick, modesParameters.pop(0))
+                elif mode == "c":
+                    if isPlus:
+                        message = self.trUtf8(
+                            "{0} sets the channel mode to 'no colors allowed'.").format(
+                            nick)
+                    else:
+                        message = self.trUtf8(
+                            "{0} sets the channel mode to 'allow color codes'.").format(
+                            nick)
+                elif mode == "e":
+                    if isPlus:
+                        message = self.trUtf8(
+                            "{0} sets a ban exception on {1}.").format(
+                            nick, modesParameters.pop(0))
+                    else:
+                        message = self.trUtf8(
+                            "{0} removes the ban exception on {1}.").format(
+                            nick, modesParameters.pop(0))
+                elif mode == "i":
+                    if isPlus:
+                        message = self.trUtf8(
+                            "{0} sets the channel mode to 'invite only'.").format(nick)
+                    else:
+                        message = self.trUtf8(
+                            "{0} removes the 'invite only' mode from the channel."
+                            ).format(nick)
+                elif mode == "k":
+                    if isPlus:
+                        message = self.trUtf8(
+                            "{0} sets the channel key to '{1}'.").format(
+                            nick, modesParameters.pop(0))
+                    else:
+                        message = self.trUtf8(
+                            "{0} removes the channel key.").format(nick)
+                elif mode == "l":
+                    if isPlus:
+                        message = self.trUtf8(
+                            "{0} sets the channel limit to %n nick(s).", "",
+                            int(modesParameters.pop(0))).format(nick)
+                    else:
+                        message = self.trUtf8(
+                            "{0} removes the channel limit.").format(nick)
+                elif mode == "m":
+                    if isPlus:
+                        message = self.trUtf8(
+                            "{0} sets the channel mode to 'moderated'.").format(nick)
+                    else:
+                        message = self.trUtf8(
+                            "{0} sets the channel mode to 'unmoderated'.").format(nick)
+                elif mode == "n":
+                    if isPlus:
+                        message = self.trUtf8(
+                            "{0} sets the channel mode to 'no messages from outside'."
+                            ).format(nick)
+                    else:
+                        message = self.trUtf8(
+                            "{0} sets the channel mode to 'allow messages from outside'."
+                            ).format(nick)
+                elif mode == "p":
+                    if isPlus:
+                        message = self.trUtf8(
+                            "{0} sets the channel mode to 'private'.").format(nick)
+                    else:
+                        message = self.trUtf8(
+                            "{0} sets the channel mode to 'public'.").format(nick)
+                elif mode == "q":
+                    if isPlus:
+                        message = self.trUtf8(
+                            "{0} sets the channel mode to 'quiet'.").format(nick)
+                    else:
+                        message = self.trUtf8(
+                            "{0} removes the 'quiet' mode from the channel.").format(
+                            nick)
+                elif mode == "r":
+                    continue
+                elif mode == "s":
+                    if isPlus:
+                        message = self.trUtf8(
+                            "{0} sets the channel mode to 'secret'.").format(nick)
+                    else:
+                        message = self.trUtf8(
+                            "{0} sets the channel mode to 'visible'.").format(nick)
+                elif mode == "t":
+                    if isPlus:
+                        message = self.trUtf8(
+                            "{0} switches on 'topic protection'.").format(nick)
+                    else:
+                        message = self.trUtf8(
+                            "{0} switches off 'topic protection'.").format(nick)
+                elif mode == "I":
+                    if isPlus:
+                        message = self.trUtf8(
+                            "{0} sets invitation mask {1}.").format(
+                            nick, modesParameters.pop(0))
+                    else:
+                        message = self.trUtf8(
+                            "{0} removes the invitation mask {1}.").format(
+                            nick, modesParameters.pop(0))
+                
+                self.__addManagementMessage(self.trUtf8("Mode"), message)
+            
+            return True
+        
+        return False
+    
     def __setUserPrivilege(self, match):
         """
         Private method to handle a change of user privileges for the channel.
@@ -580,9 +877,9 @@
             itm = self.__findUser(match.group(4))
             if itm:
                 itm.changePrivilege(match.group(3))
-                self.__addManagementMessage(IrcChannelWidget.MessageIndicator,
-                    self.trUtf8("{0} sets mode for {1}: {2}.").format(
-                        match.group(1), match.group(4), match.group(3)))
+            self.__addManagementMessage(IrcChannelWidget.MessageIndicator,
+                self.trUtf8("{0} sets mode for {1}: {2}.").format(
+                    match.group(1), match.group(4), match.group(3)))
             return True
         
         return False
@@ -599,6 +896,17 @@
         
         return False
     
+    def __help(self, match):
+        """
+        Private method to handle a help message.
+        
+        @param match match object that matched the pattern
+        @return flag indicating whether the message was handled (boolean)
+        """
+        self.__addManagementMessage(self.trUtf8("Help"),
+            "{0} {1}".format(match.group(1), ircFilter(match.group(2))))
+        return True
+    
     def setUserPrivilegePrefix(self, prefixes):
         """
         Public method to set the user privilege to prefix mapping.
@@ -655,6 +963,628 @@
             color = Preferences.getIrc("LeaveChannelColour")
         else:
             color = Preferences.getIrc("ChannelInfoColour")
-        self.messages.append(
+        self.__appendMessage(
             '<font color="{0}">{1} <b>[</b>{2}<b>]</b> {3}</font>'.format(
             color, ircTimestamp(), indicator, message))
+    
+    def __appendMessage(self, message):
+        """
+        Private slot to append a message.
+        """
+        if self.__hidden and \
+           self.__markerLine == "" and \
+           Preferences.getIrc("MarkPositionWhenHidden"):
+            self.setMarkerLine()
+        self.messages.append(message)
+    
+    def setMarkerLine(self):
+        """
+        Public method to draw a line to mark the current position.
+        """
+        self.unsetMarkerLine()
+        self.__markerLine = \
+            '<span style=" color:{0}; background-color:{1};">{2}</span>'.format(
+            Preferences.getIrc("MarkerLineForegroundColour"),
+            Preferences.getIrc("MarkerLineBackgroundColour"),
+            self.trUtf8('--- New From Here ---'))
+        self.messages.append(self.__markerLine)
+    
+    def unsetMarkerLine(self):
+        """
+        Public method to remove the marker line.
+        """
+        if self.__markerLine:
+            txt = self.messages.toHtml()
+            if txt.endswith(self.__markerLine + "</p></body></html>"):
+                # remove empty last paragraph
+                pos = txt.rfind("<p")
+                txt = txt[:pos] + "</body></html>"
+            else:
+                txt = txt.replace(self.__markerLine, "")
+            self.messages.setHtml(txt)
+            self.__markerLine = ""
+    
+    def __clearMessages(self):
+        """
+        Private slot to clear the contents of the messages display.
+        """
+        self.messages.clear()
+    
+    def __copyMessages(self):
+        """
+        Private slot to copy the selection of the messages display to the clipboard.
+        """
+        self.messages.copy()
+    
+    def __cutMessages(self):
+        """
+        Private slot to cut the selection of the messages display to the clipboard.
+        """
+        self.messages.cut()
+    
+    def __copyAllMessages(self):
+        """
+        Private slot to copy the contents of the messages display to the clipboard.
+        """
+        txt = self.messages.toPlainText()
+        if txt:
+            cb = QApplication.clipboard()
+            cb.setText(txt)
+    
+    def __cutAllMessages(self):
+        """
+        Private slot to cut the contents of the messages display to the clipboard.
+        """
+        txt = self.messages.toPlainText()
+        if txt:
+            cb = QApplication.clipboard()
+            cb.setText(txt)
+        self.messages.clear()
+    
+    def __saveMessages(self):
+        """
+        Private slot to save the contents of the messages display.
+        """
+        hasText = not self.messages.document().isEmpty()
+        if hasText:
+            if Utilities.isWindowsPlatform():
+                htmlExtension = "htm"
+            else:
+                htmlExtension = "html"
+            fname, selectedFilter = E5FileDialog.getSaveFileNameAndFilter(
+                self,
+                self.trUtf8("Save Messages"),
+                "",
+                self.trUtf8(
+                    "HTML Files (*.{0});;Text Files (*.txt);;All Files (*)").format(
+                    htmlExtension),
+                None,
+                E5FileDialog.Options(E5FileDialog.DontConfirmOverwrite))
+            if fname:
+                ext = QFileInfo(fname).suffix()
+                if not ext:
+                    ex = selectedFilter.split("(*")[1].split(")")[0]
+                    if ex:
+                        fname += ex
+                    ext = QFileInfo(fname).suffix()
+                if QFileInfo(fname).exists():
+                    res = E5MessageBox.yesNo(self,
+                        self.trUtf8("Save Messages"),
+                        self.trUtf8("<p>The file <b>{0}</b> already exists."
+                                    " Overwrite it?</p>").format(fname),
+                        icon=E5MessageBox.Warning)
+                    if not res:
+                        return
+                    fname = Utilities.toNativeSeparators(fname)
+                
+                try:
+                    if ext.lower() in ["htm", "html"]:
+                        txt = self.messages.toHtml()
+                    else:
+                        txt = self.messages.toPlainText()
+                    f = open(fname, "w", encoding="utf-8")
+                    f.write(txt)
+                    f.close()
+                except IOError as err:
+                    E5MessageBox.critical(self,
+                        self.trUtf8("Error saving Messages"),
+                        self.trUtf8("""<p>The messages contents could not be written"""
+                                    """ to <b>{0}</b></p><p>Reason: {1}</p>""")\
+                            .format(fname, str(err)))
+    
+    def __initMessagesMenu(self):
+        """
+        Private slot to initialize the context menu of the messages pane.
+        """
+        self.__messagesMenu = QMenu(self)
+        self.__cutMessagesAct = \
+            self.__messagesMenu.addAction(
+                UI.PixmapCache.getIcon("editCut.png"),
+                self.trUtf8("Cut"), self.__cutMessages)
+        self.__copyMessagesAct = \
+            self.__messagesMenu.addAction(
+                UI.PixmapCache.getIcon("editCopy.png"),
+                self.trUtf8("Copy"), self.__copyMessages)
+        self.__messagesMenu.addSeparator()
+        self.__cutAllMessagesAct = \
+            self.__messagesMenu.addAction(
+                UI.PixmapCache.getIcon("editCut.png"),
+                self.trUtf8("Cut all"), self.__cutAllMessages)
+        self.__copyAllMessagesAct = \
+            self.__messagesMenu.addAction(
+                UI.PixmapCache.getIcon("editCopy.png"),
+                self.trUtf8("Copy all"), self.__copyAllMessages)
+        self.__messagesMenu.addSeparator()
+        self.__clearMessagesAct = \
+            self.__messagesMenu.addAction(
+                UI.PixmapCache.getIcon("editDelete.png"),
+                self.trUtf8("Clear"), self.__clearMessages)
+        self.__messagesMenu.addSeparator()
+        self.__saveMessagesAct = \
+            self.__messagesMenu.addAction(
+                UI.PixmapCache.getIcon("fileSave.png"),
+                self.trUtf8("Save"), self.__saveMessages)
+        self.__messagesMenu.addSeparator()
+        self.__setMarkerMessagesAct = \
+            self.__messagesMenu.addAction(self.trUtf8("Mark Current Position"),
+                self.setMarkerLine)
+        self.__unsetMarkerMessagesAct = \
+            self.__messagesMenu.addAction(self.trUtf8("Remove Position Marker"),
+                self.unsetMarkerLine)
+        
+        self.on_messages_copyAvailable(False)
+    
+    @pyqtSlot(bool)
+    def on_messages_copyAvailable(self, yes):
+        """
+        Private slot to react to text selection/deselection of the messages edit.
+        
+        @param yes flag signaling the availability of selected text (boolean)
+        """
+        self.__copyMessagesAct.setEnabled(yes)
+        self.__cutMessagesAct.setEnabled(yes)
+    
+    @pyqtSlot(QPoint)
+    def on_messages_customContextMenuRequested(self, pos):
+        """
+        Private slot to show the context menu of the messages pane.
+        
+        @param pos the position of the mouse pointer (QPoint)
+        """
+        enable = not self.messages.document().isEmpty()
+        self.__cutAllMessagesAct.setEnabled(enable)
+        self.__copyAllMessagesAct.setEnabled(enable)
+        self.__saveMessagesAct.setEnabled(enable)
+        self.__setMarkerMessagesAct.setEnabled(self.__markerLine == "")
+        self.__unsetMarkerMessagesAct.setEnabled(self.__markerLine != "")
+        self.__messagesMenu.popup(self.messages.mapToGlobal(pos))
+    
+    def __whoIs(self):
+        """
+        Private slot to get information about the selected user.
+        """
+        self.__whoIsNick = self.usersList.selectedItems()[0].text()
+        self.sendData.emit("WHOIS " + self.__whoIsNick)
+    
+    def __openPrivateChat(self):
+        """
+        Private slot to open a chat with the selected user.
+        """
+        user = self.usersList.selectedItems()[0].text()
+        self.openPrivateChat.emit(user)
+    
+    def __initUsersMenu(self):
+        """
+        Private slot to initialize the users list context menu.
+        """
+        self.__usersMenu = QMenu(self)
+        self.__usersMenu.addAction(self.trUtf8("Who Is"), self.__whoIs)
+        self.__usersMenu.addSeparator()
+        self.__privateChatAct = \
+            self.__usersMenu.addAction(self.trUtf8("Private Chat"),
+            self.__openPrivateChat)
+    
+    @pyqtSlot(QPoint)
+    def on_usersList_customContextMenuRequested(self, pos):
+        """
+        Private slot to show the context menu of the users list.
+        
+        @param pos the position of the mouse pointer (QPoint)
+        """
+        self.__privateChatAct.setEnabled(not self.__private)
+        if len(self.usersList.selectedItems()) > 0:
+            self.__usersMenu.popup(self.usersList.mapToGlobal(pos))
+    
+    def hideEvent(self, evt):
+        """
+        Protected method handling hide events.
+        
+        @param evt reference to the hide event (QHideEvent)
+        """
+        self.__hidden = True
+    
+    def showEvent(self, evt):
+        """
+        Protected method handling show events.
+        
+        @param evt reference to the show event (QShowEvent)
+        """
+        self.__hidden = False
+    
+    def initAutoWho(self):
+        """
+        Public method to initialize the Auto Who system.
+        """
+        if Preferences.getIrc("AutoUserInfoLookup"):
+            self.__autoWhoTimer.setInterval(
+                Preferences.getIrc("AutoUserInfoInterval") * 1000)
+            self.__autoWhoTimer.start()
+    
+    @pyqtSlot()
+    def __sendAutoWhoCommand(self):
+        """
+        Private slot to send the WHO command to update the users list.
+        """
+        if self.usersList.count() <= Preferences.getIrc("AutoUserInfoMax"):
+            self.__autoWhoRequested = True
+            self.sendData.emit(self.__autoWhoTemplate.format(self.__name))
+    
+    def __autoWhoEntry(self, match):
+        """
+        Private method to handle a WHO entry returned by the server as requested
+        automatically.
+        
+        @param match match object that matched the pattern
+        @return flag indicating whether the message was handled (boolean)
+        """
+        # group(1)  nick
+        # group(2)  user flags
+        if self.__autoWhoRequested:
+            itm = self.__findUser(match.group(1))
+            if itm:
+                itm.parseWhoFlags(match.group(2))
+            return True
+        
+        return False
+    
+    def __whoEnd(self, match):
+        """
+        Private method to handle the end of the WHO list.
+        
+        @param match match object that matched the pattern
+        @return flag indicating whether the message was handled (boolean)
+        """
+        if match.group(1).lower() == self.__name:
+            if self.__autoWhoRequested:
+                self.__autoWhoRequested = False
+                self.initAutoWho()
+            else:
+                self.__addManagementMessage(self.trUtf8("Who"),
+                    self.trUtf8("End of WHO list for {0}.").format(match.group(1)))
+            return True
+        
+        return False
+    
+    def __whoEntry(self, match):
+        """
+        Private method to handle a WHO entry returned by the server as requested
+        manually.
+        
+        @param match match object that matched the pattern
+        @return flag indicating whether the message was handled (boolean)
+        """
+        # group(1)  channel
+        # group(2)  user
+        # group(3)  host
+        # group(4)  nick
+        # group(5)  user flags
+        # group(6)  real name
+        if match.group(2).lower() == self.__name:
+            away = self.trUtf8(" (Away)") if match.group(5).startswith("G") else ""
+            self.__addManagementMessage(self.trUtf8("Who"),
+                self.trUtf8("{0} is {1}@{2} ({3}){4}").format(
+                    match.group(4), match.group(2), match.group(3), match.group(6), away))
+            return True
+        
+        return False
+    
+    def __whoIsUser(self, match):
+        """
+        Private method to handle the WHOIS user reply.
+        
+        @param match match object that matched the pattern
+        @return flag indicating whether the message was handled (boolean)
+        """
+        # group(1)   nick
+        # group(2)   user
+        # group(3)   host
+        # group(4)   real name
+        if match.group(1) == self.__whoIsNick:
+            realName = match.group(4).replace("<", "&lt;").replace(">", "&gt;")
+            self.__addManagementMessage(self.trUtf8("Whois"),
+                self.trUtf8("{0} is {1}@{2} ({3}).").format(match.group(1),
+                match.group(2), match.group(3), realName))
+            return True
+        
+        return False
+    
+    def __whoIsChannels(self, match):
+        """
+        Private method to handle the WHOIS channels reply.
+        
+        @param match match object that matched the pattern
+        @return flag indicating whether the message was handled (boolean)
+        """
+        # group(1)   nick
+        # group(2)   channels
+        if match.group(1) == self.__whoIsNick:
+            userChannels = []
+            voiceChannels = []
+            opChannels = []
+            halfopChannels = []
+            ownerChannels = []
+            adminChannels = []
+            
+            # generate the list of channels the user is in
+            channelList = match.group(2).split()
+            for channel in channelList:
+                if channel.startswith(("*", "&")):
+                    adminChannels.append(channel[1:])
+                elif channel.startswith(("!", "~")) and \
+                     self.__ircWidget.isChannelName(channel[1:]):
+                    ownerChannels.append(channel[1:])
+                elif channel.startswith("@+"):
+                    opChannels.append(channel[2:])
+                elif channel.startswith("@"):
+                    opChannels.append(channel[1:])
+                elif channel.startswith("%"):
+                    halfopChannels.append(channel[1:])
+                elif channel.startswith("+"):
+                    voiceChannels.append(channel[1:])
+                else:
+                    userChannels.append(channel)
+            
+            # show messages
+            if userChannels:
+                self.__addManagementMessage(self.trUtf8("Whois"),
+                    self.trUtf8("{0} is a user on channels: {1}").format(
+                    match.group(1), " ".join(userChannels)))
+            if voiceChannels:
+                self.__addManagementMessage(self.trUtf8("Whois"),
+                    self.trUtf8("{0} has voice on channels: {1}").format(
+                    match.group(1), " ".join(voiceChannels)))
+            if halfopChannels:
+                self.__addManagementMessage(self.trUtf8("Whois"),
+                    self.trUtf8("{0} is a halfop on channels: {1}").format(
+                    match.group(1), " ".join(halfopChannels)))
+            if opChannels:
+                self.__addManagementMessage(self.trUtf8("Whois"),
+                    self.trUtf8("{0} is an operator on channels: {1}").format(
+                    match.group(1), " ".join(opChannels)))
+            if ownerChannels:
+                self.__addManagementMessage(self.trUtf8("Whois"),
+                    self.trUtf8("{0} is owner of channels: {1}").format(
+                    match.group(1), " ".join(ownerChannels)))
+            if adminChannels:
+                self.__addManagementMessage(self.trUtf8("Whois"),
+                    self.trUtf8("{0} is admin on channels: {1}").format(
+                    match.group(1), " ".join(adminChannels)))
+            return True
+        
+        return False
+    
+    def __whoIsServer(self, match):
+        """
+        Private method to handle the WHOIS server reply.
+        
+        @param match match object that matched the pattern
+        @return flag indicating whether the message was handled (boolean)
+        """
+        # group(1)   nick
+        # group(2)   server
+        # group(3)   server info
+        if match.group(1) == self.__whoIsNick:
+            self.__addManagementMessage(self.trUtf8("Whois"),
+                self.trUtf8("{0} is online via {1} ({2}).").format(match.group(1),
+                match.group(2), match.group(3)))
+            return True
+        
+        return False
+    
+    def __whoIsOperator(self, match):
+        """
+        Private method to handle the WHOIS operator reply.
+        
+        @param match match object that matched the pattern
+        @return flag indicating whether the message was handled (boolean)
+        """
+        # group(1)   nick
+        # group(2)   message
+        if match.group(1) == self.__whoIsNick:
+            if match.group(2).lower().startswith("is an irc operator"):
+                self.__addManagementMessage(self.trUtf8("Whois"),
+                    self.trUtf8("{0} is an IRC Operator.").format(match.group(1)))
+            else:
+                self.__addManagementMessage(self.trUtf8("Whois"),
+                    "{0} {1}".format(match.group(1), match.group(2)))
+            return True
+        
+        return False
+    
+    def __whoIsIdle(self, match):
+        """
+        Private method to handle the WHOIS idle reply.
+        
+        @param match match object that matched the pattern
+        @return flag indicating whether the message was handled (boolean)
+        """
+        # group(1)   nick
+        # group(2)   idle seconds
+        # group(3)   signon time
+        if match.group(1) == self.__whoIsNick:
+            seconds = int(match.group(2))
+            minutes = seconds // 60
+            hours = minutes // 60
+            days = hours // 24
+            
+            signonTimestamp = int(match.group(3))
+            signonTime = QDateTime()
+            signonTime.setTime_t(signonTimestamp)
+            
+            if days:
+                daysString = self.trUtf8("%n day(s)", "", days)
+                hoursString = self.trUtf8("%n hour(s)", "", hours)
+                minutesString = self.trUtf8("%n minute(s)", "", minutes)
+                secondsString = self.trUtf8("%n second(s)", "", seconds)
+                self.__addManagementMessage(self.trUtf8("Whois"),
+                    self.trUtf8("{0} has been idle for {1}, {2}, {3}, and {4}.",
+                                "{0} = name of person, {1} = (x days), {2} = (x hours),"
+                                " {3} = (x minutes), {4} = (x seconds)").format(
+                    match.group(1), daysString, hoursString, minutesString,
+                    secondsString))
+            elif hours:
+                hoursString = self.trUtf8("%n hour(s)", "", hours)
+                minutesString = self.trUtf8("%n minute(s)", "", minutes)
+                secondsString = self.trUtf8("%n second(s)", "", seconds)
+                self.__addManagementMessage(self.trUtf8("Whois"),
+                    self.trUtf8("{0} has been idle for {1}, {2}, and {3}.",
+                                "{0} = name of person, {1} = (x hours), "
+                                "{2} = (x minutes), {3} = (x seconds)").format(
+                    match.group(1), hoursString, minutesString, secondsString))
+            elif minutes:
+                minutesString = self.trUtf8("%n minute(s)", "", minutes)
+                secondsString = self.trUtf8("%n second(s)", "", seconds)
+                self.__addManagementMessage(self.trUtf8("Whois"),
+                    self.trUtf8("{0} has been idle for {1} and {2}.",
+                                "{0} = name of person, {1} = (x minutes), "
+                                "{3} = (x seconds)").format(
+                    match.group(1), minutesString, secondsString))
+            else:
+                self.__addManagementMessage(self.trUtf8("Whois"),
+                    self.trUtf8("{0} has been idle for %n second(s).", "",
+                        seconds).format(match.group(1)))
+            
+            if not signonTime.isNull():
+                self.__addManagementMessage(self.trUtf8("Whois"),
+                    self.trUtf8("{0} has been online since {1}.").format(
+                    match.group(1), signonTime.toString("yyyy-MM-dd, hh:mm:ss")))
+            return True
+        
+        return False
+    
+    def __whoIsEnd(self, match):
+        """
+        Private method to handle the end of WHOIS reply.
+        
+        @param match match object that matched the pattern
+        @return flag indicating whether the message was handled (boolean)
+        """
+        # group(1)   nick
+        # group(2)   end message
+        if match.group(1) == self.__whoIsNick:
+            self.__whoIsNick = ""
+            self.__addManagementMessage(self.trUtf8("Whois"),
+                self.trUtf8("End of WHOIS list for {0}.").format(match.group(1)))
+            return True
+        
+        return False
+    
+    def __whoIsIdentify(self, match):
+        """
+        Private method to handle the WHOIS identify and identified replies.
+        
+        @param match match object that matched the pattern
+        @return flag indicating whether the message was handled (boolean)
+        """
+        # group(1)   nick
+        # group(2)   identified message
+        if match.group(1) == self.__whoIsNick:
+            self.__addManagementMessage(self.trUtf8("Whois"),
+                self.trUtf8("{0} is an identified user.").format(match.group(1)))
+            return True
+        
+        return False
+    
+    def __whoIsHelper(self, match):
+        """
+        Private method to handle the WHOIS helper reply.
+        
+        @param match match object that matched the pattern
+        @return flag indicating whether the message was handled (boolean)
+        """
+        # group(1)   nick
+        # group(2)   helper message
+        if match.group(1) == self.__whoIsNick:
+            self.__addManagementMessage(self.trUtf8("Whois"),
+                self.trUtf8("{0} is available for help.").format(match.group(1)))
+            return True
+        
+        return False
+    
+    def __whoIsAccount(self, match):
+        """
+        Private method to handle the WHOIS account reply.
+        
+        @param match match object that matched the pattern
+        @return flag indicating whether the message was handled (boolean)
+        """
+        # group(1)   nick
+        # group(2)   login name
+        if match.group(1) == self.__whoIsNick:
+            self.__addManagementMessage(self.trUtf8("Whois"),
+                self.trUtf8("{0} is logged in as {1}.").format(match.group(1),
+                match.group(2)))
+            return True
+        
+        return False
+    
+    def __whoIsActually(self, match):
+        """
+        Private method to handle the WHOIS actually reply.
+        
+        @param match match object that matched the pattern
+        @return flag indicating whether the message was handled (boolean)
+        """
+        # group(1)   nick
+        # group(2)   actual user@host
+        # group(3)   actual IP
+        if match.group(1) == self.__whoIsNick:
+            self.__addManagementMessage(self.trUtf8("Whois"),
+                self.trUtf8("{0} is actually using the host {1} (IP: {2}).").format(
+                match.group(1), match.group(2), match.group(3)))
+            return True
+        
+        return False
+    
+    def __whoIsSecure(self, match):
+        """
+        Private method to handle the WHOIS secure reply.
+        
+        @param match match object that matched the pattern
+        @return flag indicating whether the message was handled (boolean)
+        """
+        # group(1)   nick
+        if match.group(1) == self.__whoIsNick:
+            self.__addManagementMessage(self.trUtf8("Whois"),
+                self.trUtf8("{0} is using a secure connection.").format(match.group(1)))
+            return True
+        
+        return False
+    
+    def __whoIsConnection(self, match):
+        """
+        Private method to handle the WHOIS connection reply.
+        
+        @param match match object that matched the pattern
+        @return flag indicating whether the message was handled (boolean)
+        """
+        # group(1)   nick
+        # group(2)   host name
+        # group(3)   IP
+        if match.group(1) == self.__whoIsNick:
+            self.__addManagementMessage(self.trUtf8("Whois"),
+                self.trUtf8("{0} is connecting from {1} (IP: {2}).").format(
+                match.group(1), match.group(2), match.group(3)))
+            return True
+        
+        return False
--- a/Network/IRC/IrcChannelWidget.ui	Sun Dec 02 18:53:39 2012 +0100
+++ b/Network/IRC/IrcChannelWidget.ui	Mon Dec 10 18:40:10 2012 +0100
@@ -33,6 +33,9 @@
       <enum>Qt::Vertical</enum>
      </property>
      <widget class="QListWidget" name="usersList">
+      <property name="contextMenuPolicy">
+       <enum>Qt::CustomContextMenu</enum>
+      </property>
       <property name="toolTip">
        <string>Shows the list of users</string>
       </property>
@@ -50,6 +53,9 @@
         <verstretch>1</verstretch>
        </sizepolicy>
       </property>
+      <property name="contextMenuPolicy">
+       <enum>Qt::CustomContextMenu</enum>
+      </property>
       <property name="toolTip">
        <string>Shows the channel messages</string>
       </property>
@@ -63,7 +69,7 @@
     </widget>
    </item>
    <item>
-    <widget class="E5ClearableLineEdit" name="messageEdit">
+    <widget class="IrcMessageEdit" name="messageEdit">
      <property name="toolTip">
       <string>Enter a message, send by pressing Return or Enter</string>
      </property>
@@ -76,9 +82,9 @@
  </widget>
  <customwidgets>
   <customwidget>
-   <class>E5ClearableLineEdit</class>
+   <class>IrcMessageEdit</class>
    <extends>QLineEdit</extends>
-   <header>E5Gui/E5LineEdit.h</header>
+   <header>Network/IRC/IrcMessageEdit.h</header>
   </customwidget>
  </customwidgets>
  <tabstops>
--- a/Network/IRC/IrcIdentitiesEditDialog.py	Sun Dec 02 18:53:39 2012 +0100
+++ b/Network/IRC/IrcIdentitiesEditDialog.py	Mon Dec 10 18:40:10 2012 +0100
@@ -117,9 +117,6 @@
         self.rememberPosOnAwayCheckBox.setChecked(
             self.__currentIdentity.rememberAwayPosition())
         self.awayEdit.setText(self.__currentIdentity.getAwayMessage())
-        self.autoAwayGroup.setChecked(self.__currentIdentity.autoAway())
-        self.inactivitySpinBox.setValue(self.__currentIdentity.getAutoAwayTimeout())
-        self.autoReturnCheckBox.setChecked(self.__currentIdentity.autoReturn())
         
         # Advanced Tab
         self.identEdit.setText(self.__currentIdentity.getIdent())
@@ -150,9 +147,6 @@
         self.__currentIdentity.setRememberAwayPosition(
             self.rememberPosOnAwayCheckBox.isChecked())
         self.__currentIdentity.setAwayMessage(self.awayEdit.text())
-        self.__currentIdentity.setAutoAway(self.autoAwayGroup.isChecked())
-        self.__currentIdentity.setAutoAwayTimeout(self.inactivitySpinBox.value())
-        self.__currentIdentity.setAutoReturn(self.autoReturnCheckBox.isChecked())
         
         # Advanced Tab
         self.__currentIdentity.setIdent(self.identEdit.text())
--- a/Network/IRC/IrcIdentitiesEditDialog.ui	Sun Dec 02 18:53:39 2012 +0100
+++ b/Network/IRC/IrcIdentitiesEditDialog.ui	Mon Dec 10 18:40:10 2012 +0100
@@ -237,71 +237,7 @@
          </property>
         </widget>
        </item>
-       <item row="2" column="0" colspan="2">
-        <widget class="QGroupBox" name="autoAwayGroup">
-         <property name="toolTip">
-          <string>Select to send an AWAY message when inactive</string>
-         </property>
-         <property name="title">
-          <string>Auto Away</string>
-         </property>
-         <property name="checkable">
-          <bool>true</bool>
-         </property>
-         <layout class="QGridLayout" name="gridLayout_4">
-          <item row="0" column="0">
-           <widget class="QLabel" name="label_9">
-            <property name="text">
-             <string>Time of Inactivity:</string>
-            </property>
-           </widget>
-          </item>
-          <item row="0" column="1">
-           <widget class="QSpinBox" name="inactivitySpinBox">
-            <property name="toolTip">
-             <string>Enter the time of inactivity to send the automatic AWAY message</string>
-            </property>
-            <property name="alignment">
-             <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-            </property>
-            <property name="suffix">
-             <string> min</string>
-            </property>
-            <property name="minimum">
-             <number>1</number>
-            </property>
-            <property name="maximum">
-             <number>120</number>
-            </property>
-           </widget>
-          </item>
-          <item row="0" column="2">
-           <spacer name="horizontalSpacer">
-            <property name="orientation">
-             <enum>Qt::Horizontal</enum>
-            </property>
-            <property name="sizeHint" stdset="0">
-             <size>
-              <width>321</width>
-              <height>20</height>
-             </size>
-            </property>
-           </spacer>
-          </item>
-          <item row="1" column="0" colspan="3">
-           <widget class="QCheckBox" name="autoReturnCheckBox">
-            <property name="toolTip">
-             <string>Select to return automatically when activity is detected</string>
-            </property>
-            <property name="text">
-             <string>Automatically return on activity</string>
-            </property>
-           </widget>
-          </item>
-         </layout>
-        </widget>
-       </item>
-       <item row="3" column="1">
+       <item row="2" column="1">
         <spacer name="verticalSpacer_3">
          <property name="orientation">
           <enum>Qt::Vertical</enum>
@@ -410,9 +346,6 @@
   <tabstop>passwordEdit</tabstop>
   <tabstop>rememberPosOnAwayCheckBox</tabstop>
   <tabstop>awayEdit</tabstop>
-  <tabstop>autoAwayGroup</tabstop>
-  <tabstop>inactivitySpinBox</tabstop>
-  <tabstop>autoReturnCheckBox</tabstop>
   <tabstop>identEdit</tabstop>
   <tabstop>quitEdit</tabstop>
   <tabstop>partEdit</tabstop>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Network/IRC/IrcMessageEdit.py	Mon Dec 10 18:40:10 2012 +0100
@@ -0,0 +1,126 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2012 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a specialized line edit for entering IRC messages.
+"""
+
+from PyQt4.QtCore import Qt
+
+from E5Gui.E5LineEdit import E5LineEdit, E5ClearableLineEdit
+
+
+class IrcMessageEdit(E5ClearableLineEdit):
+    """
+    Class implementing a specialized line edit for entering IRC messages.
+    """
+    MaxHistory = 100
+    
+    def __init__(self, parent=None, inactiveText="", side=E5LineEdit.RightSide):
+        """
+        Constructor
+        
+        @param parent reference to the parent widget (QWidget)
+        @keyparam inactiveText text to be shown on inactivity (string)
+        @keyparam side side the clear button should be shown at (E5LineEdit.RightSide,
+            E5LineEdit.LeftSide)
+        """
+        super().__init__(parent, inactiveText, side)
+        
+        self.__historyList = [""]   # initialize with one empty line
+        self.__historyLine = 0
+    
+    def setText(self, text):
+        """
+        Public method to set the text.
+        
+        Note: This reimplementation ensures, that the cursor is at the end of the text.
+        
+        @param text text to be set (string)
+        """
+        super().setText(text)
+        self.setCursorPosition(len(text))
+    
+    def keyPressEvent(self, evt):
+        """
+        Protected method implementing special key handling.
+        
+        @param evt reference to the event (QKeyEvent)
+        """
+        key = evt.key()
+        if key == Qt.Key_Up:
+            self.__getHistory(True)
+            return
+        elif key == Qt.Key_Down:
+            self.__getHistory(False)
+            return
+        elif key in [Qt.Key_Return, Qt.Key_Enter]:
+            if self.text():
+                self.__addHistory(self.text())
+        elif evt.text() == chr(21):
+            # ^U: clear the text
+            self.setText("")
+        
+        super().keyPressEvent(evt)
+    
+    def wheelEvent(self, evt):
+        """
+        Protected slot to support wheel events.
+        
+        @param reference to the wheel event (QWheelEvent)
+        """
+        if evt.delta() > 0:
+            self.__getHistory(True)
+        elif evt.delta() < 0:
+            self.__getHistory(False)
+        
+        super().wheelEvent(evt)
+    
+    def __addHistory(self, txt):
+        """
+        Private method to add an entry to the history.
+        
+        @param txt text to be added to the history (string)
+        """
+        # Only add the entry, if it is not the same as last time
+        if len(self.__historyList) == 1 or \
+           (len(self.__historyList) > 1 and self.__historyList[1] != txt):
+            # Replace empty first entry and add new empty first entry
+            self.__historyList[0] = txt
+            self.__historyList.insert(0, "")
+            # Keep history below the defined limit
+            del self.__historyList[IrcMessageEdit.MaxHistory:]
+        
+        self.__historyLine = 0
+    
+    def __getHistory(self, up):
+        """
+        Private method to move in the history.
+        
+        @param up flag indicating the direction (boolean)
+        """
+        # preserve the current text, if it is not empty
+        if self.text():
+            self.__historyList[self.__historyLine] = self.text()
+        
+        if up:
+            self.__historyLine += 1
+            # If the position was moved past the end of the history, go to the last entry
+            if self.__historyLine == len(self.__historyList):
+                self.__historyLine -= 1
+                return
+        else:
+            # If the position is at the top of the history, arrow-down shall add the text
+            # to the history and clear the line edit for new input
+            if self.__historyLine == 0:
+                if self.text():
+                    self.__addHistory(self.text())
+                self.setText("")
+            else:
+                # If the position is not at the top of the history, decrement it
+                self.__historyLine -= 1
+        
+        # replace the text of the line edit with the selected history entry
+        self.setText(self.__historyList[self.__historyLine])
--- a/Network/IRC/IrcNetworkManager.py	Sun Dec 02 18:53:39 2012 +0100
+++ b/Network/IRC/IrcNetworkManager.py	Mon Dec 10 18:40:10 2012 +0100
@@ -45,9 +45,6 @@
         
         self.__rememberPosOnAway = True
         self.__awayMessage = IrcIdentity.DefaultAwayMessage
-        self.__autoAway = False
-        self.__autoAwayTimeout = 1
-        self.__autoReturn = False
         
         self.__quitMessage = IrcIdentity.DefaultQuitMessage
         self.__partMessage = IrcIdentity.DefaultPartMessage
@@ -68,9 +65,6 @@
         settings.setValue("PartMessage", self.__partMessage)
         settings.setValue("RememberAwayPosition", self.__rememberPosOnAway)
         settings.setValue("AwayMessage", self.__awayMessage)
-        settings.setValue("AutoAway", self.__autoAway)
-        settings.setValue("AwayTimeout", self.__autoAwayTimeout)
-        settings.setValue("AutoReturn", self.__autoReturn)
     
     def load(self, settings):
         """
@@ -88,9 +82,6 @@
         self.__rememberPosOnAway = Preferences.toBool(
             settings.value("RememberAwayPosition", True))
         self.__awayMessage = settings.value("AwayMessage", IrcIdentity.DefaultAwayMessage)
-        self.__autoAway = Preferences.toBool(settings.value("AutoAway", False))
-        self.__autoAwayTimeout = int(settings.value("AwayTimeout", 1))
-        self.__autoReturn = Preferences.toBool(settings.value("AutoReturn", False))
     
     def setName(self, name):
         """
@@ -261,54 +252,6 @@
         """
         return self.__awayMessage
     
-    def setAutoAway(self, on):
-        """
-        Public method to set the auto away function.
-        
-        @param on flag indicating to enable the auto away function (boolean)
-        """
-        self.__autoAway = on
-    
-    def autoAway(self):
-        """
-        Public method to get the auto away flag.
-        
-        @return auto away flag (boolean)
-        """
-        return self.__autoAway
-    
-    def setAutoAwayTimeout(self, minutes):
-        """
-        Public method to set the auto away timeout.
-        
-        @param minutes auto away timeout in minutes (integer)
-        """
-        self.__autoAwayTimeout = minutes
-    
-    def getAutoAwayTimeout(self):
-        """
-        Public method to get the auto away timeout.
-        
-        @return auto away timeout in minutes (integer)
-        """
-        return self.__autoAwayTimeout
-    
-    def setAutoReturn(self, on):
-        """
-        Public method to set the auto return function.
-        
-        @param on flag indicating to enable the auto return function (boolean)
-        """
-        self.__autoReturn = on
-    
-    def autoReturn(self):
-        """
-        Public method to get the auto return flag.
-        
-        @return auto return flag (boolean)
-        """
-        return self.__autoReturn
-    
     @classmethod
     def createDefaultIdentity(cls):
         """
--- a/Network/IRC/IrcNetworkWidget.py	Sun Dec 02 18:53:39 2012 +0100
+++ b/Network/IRC/IrcNetworkWidget.py	Mon Dec 10 18:40:10 2012 +0100
@@ -7,8 +7,10 @@
 Module implementing the network part of the IRC widget.
 """
 
-from PyQt4.QtCore import pyqtSlot, pyqtSignal
-from PyQt4.QtGui import QWidget
+from PyQt4.QtCore import pyqtSlot, pyqtSignal, QPoint, QFileInfo
+from PyQt4.QtGui import QWidget, QApplication, QMenu
+
+from E5Gui import E5MessageBox, E5FileDialog
 
 from .Ui_IrcNetworkWidget import Ui_IrcNetworkWidget
 
@@ -16,6 +18,7 @@
 
 import UI.PixmapCache
 import Preferences
+import Utilities
 
 
 class IrcNetworkWidget(QWidget, Ui_IrcNetworkWidget):
@@ -26,20 +29,18 @@
     @signal editNetwork(str) emitted to edit a network configuration
     @signal joinChannel(str) emitted to join a channel
     @signal nickChanged(str) emitted to change the nick name
+    @signal sendData(str) emitted to send a message to the channel
+    @signal away(bool) emitted to indicate the away status
+    @signal autoConnected() emitted after an automatic connection was initiated
     """
     connectNetwork = pyqtSignal(str, bool)
     editNetwork = pyqtSignal(str)
     joinChannel = pyqtSignal(str)
     nickChanged = pyqtSignal(str)
-    
+    sendData = pyqtSignal(str)
+    away = pyqtSignal(bool)
+    autoConnected = pyqtSignal()
     
-    # TODO: add context menu to messages pane with these entries:
-    #       Copy
-    #       Copy Link Location
-    #       Copy All
-    #       Clear
-    #       Save
-    # TODO: add AWAY support (toolbutton in widget)
     def __init__(self, parent=None):
         """
         Constructor
@@ -52,10 +53,22 @@
         self.connectButton.setIcon(UI.PixmapCache.getIcon("ircConnect.png"))
         self.editButton.setIcon(UI.PixmapCache.getIcon("ircConfigure.png"))
         self.joinButton.setIcon(UI.PixmapCache.getIcon("ircJoinChannel.png"))
+        self.awayButton.setIcon(UI.PixmapCache.getIcon("ircUserPresent.png"))
+        
         self.joinButton.setEnabled(False)
+        self.nickCombo.setEnabled(False)
+        self.awayButton.setEnabled(False)
+        
+        self.channelCombo.lineEdit().returnPressed.connect(self.on_joinButton_clicked)
+        self.nickCombo.lineEdit().returnPressed.connect(
+            self.on_nickCombo_currentIndexChanged)
+        
+        self.__initMessagesMenu()
         
         self.__manager = None
         self.__connected = False
+        self.__registered = False
+        self.__away = False
     
     def initialize(self, manager):
         """
@@ -78,6 +91,7 @@
                 row = self.networkCombo.findText(networkName)
                 self.networkCombo.setCurrentIndex(row)
                 self.on_connectButton_clicked()
+                self.autoConnected.emit()
                 break
     
     @pyqtSlot()
@@ -106,6 +120,24 @@
         self.connectNetwork.emit(network, not self.__connected)
     
     @pyqtSlot()
+    def on_awayButton_clicked(self):
+        """
+        Private slot to toggle the away status.
+        """
+        if self.__away:
+            self.sendData.emit("AWAY")
+            self.awayButton.setIcon(UI.PixmapCache.getIcon("ircUserPresent.png"))
+            self.__away = False
+        else:
+            networkName = self.networkCombo.currentText()
+            identityName = self.__manager.getNetwork(networkName).getIdentityName()
+            awayMessage = self.__manager.getIdentity(identityName).getAwayMessage()
+            self.sendData.emit("AWAY :" + awayMessage)
+            self.awayButton.setIcon(UI.PixmapCache.getIcon("ircUserAway.png"))
+            self.__away = True
+        self.away.emit(self.__away)
+    
+    @pyqtSlot()
     def on_editButton_clicked(self):
         """
         Private slot to edit a network.
@@ -120,7 +152,7 @@
         
         @param txt current text of the channel combo (string)
         """
-        on = bool(txt) and self.__connected
+        on = bool(txt) and self.__registered
         self.joinButton.setEnabled(on)
     
     @pyqtSlot()
@@ -150,10 +182,8 @@
                 network.getIdentityName())
             if identity:
                 self.nickCombo.addItems(identity.getNickNames())
-            self.nickCombo.setEnabled(True)
         else:
             self.channelCombo.setEnabled(False)
-            self.nickCombo.setEnabled(False)
     
     def getNetworkChannels(self):
         """
@@ -167,7 +197,7 @@
         return network.getChannels()
     
     @pyqtSlot(str)
-    def on_nickCombo_currentIndexChanged(self, nick):
+    def on_nickCombo_currentIndexChanged(self, nick=""):
         """
         Private slot to use another nick name.
         
@@ -252,5 +282,161 @@
         else:
             self.connectButton.setIcon(UI.PixmapCache.getIcon("ircConnect.png"))
         
-        on = bool(self.channelCombo.currentText()) and self.__connected
+    def setRegistered(self, registered):
+        """
+        Public slot to set the registered state.
+        
+        @param connected flag indicating the connection state (boolean)
+        """
+        self.__registered = registered
+        on = bool(self.channelCombo.currentText()) and self.__registered
         self.joinButton.setEnabled(on)
+        self.nickCombo.setEnabled(registered)
+        self.awayButton.setEnabled(registered)
+        if registered:
+            self.awayButton.setIcon(UI.PixmapCache.getIcon("ircUserPresent.png"))
+            self.__away = False
+    
+    def __clearMessages(self):
+        """
+        Private slot to clear the contents of the messages display.
+        """
+        self.messages.clear()
+    
+    def __copyMessages(self):
+        """
+        Private slot to copy the selection of the messages display to the clipboard.
+        """
+        self.messages.copy()
+    
+    def __cutMessages(self):
+        """
+        Private slot to cut the selection of the messages display to the clipboard.
+        """
+        self.messages.cut()
+    
+    def __copyAllMessages(self):
+        """
+        Private slot to copy the contents of the messages display to the clipboard.
+        """
+        txt = self.messages.toPlainText()
+        if txt:
+            cb = QApplication.clipboard()
+            cb.setText(txt)
+    
+    def __cutAllMessages(self):
+        """
+        Private slot to cut the contents of the messages display to the clipboard.
+        """
+        txt = self.messages.toPlainText()
+        if txt:
+            cb = QApplication.clipboard()
+            cb.setText(txt)
+        self.messages.clear()
+    
+    def __saveMessages(self):
+        """
+        Private slot to save the contents of the messages display.
+        """
+        hasText = not self.messages.document().isEmpty()
+        if hasText:
+            if Utilities.isWindowsPlatform():
+                htmlExtension = "htm"
+            else:
+                htmlExtension = "html"
+            fname, selectedFilter = E5FileDialog.getSaveFileNameAndFilter(
+                self,
+                self.trUtf8("Save Messages"),
+                "",
+                self.trUtf8(
+                    "HTML Files (*.{0});;Text Files (*.txt);;All Files (*)").format(
+                    htmlExtension),
+                None,
+                E5FileDialog.Options(E5FileDialog.DontConfirmOverwrite))
+            if fname:
+                ext = QFileInfo(fname).suffix()
+                if not ext:
+                    ex = selectedFilter.split("(*")[1].split(")")[0]
+                    if ex:
+                        fname += ex
+                    ext = QFileInfo(fname).suffix()
+                if QFileInfo(fname).exists():
+                    res = E5MessageBox.yesNo(self,
+                        self.trUtf8("Save Messages"),
+                        self.trUtf8("<p>The file <b>{0}</b> already exists."
+                                    " Overwrite it?</p>").format(fname),
+                        icon=E5MessageBox.Warning)
+                    if not res:
+                        return
+                    fname = Utilities.toNativeSeparators(fname)
+                
+                try:
+                    if ext.lower() in ["htm", "html"]:
+                        txt = self.messages.toHtml()
+                    else:
+                        txt = self.messages.toPlainText()
+                    f = open(fname, "w", encoding="utf-8")
+                    f.write(txt)
+                    f.close()
+                except IOError as err:
+                    E5MessageBox.critical(self,
+                        self.trUtf8("Error saving Messages"),
+                        self.trUtf8("""<p>The messages contents could not be written"""
+                                    """ to <b>{0}</b></p><p>Reason: {1}</p>""")\
+                            .format(fname, str(err)))
+    
+    def __initMessagesMenu(self):
+        """
+        Private slot to initialize the context menu of the messages pane.
+        """
+        self.__messagesMenu = QMenu(self)
+        self.__cutMessagesAct = \
+            self.__messagesMenu.addAction(
+                UI.PixmapCache.getIcon("editCut.png"),
+                self.trUtf8("Cut"), self.__cutMessages)
+        self.__copyMessagesAct = \
+            self.__messagesMenu.addAction(
+                UI.PixmapCache.getIcon("editCopy.png"),
+                self.trUtf8("Copy"), self.__copyMessages)
+        self.__messagesMenu.addSeparator()
+        self.__cutAllMessagesAct = \
+            self.__messagesMenu.addAction(
+                UI.PixmapCache.getIcon("editCut.png"),
+                self.trUtf8("Cut all"), self.__cutAllMessages)
+        self.__copyAllMessagesAct = \
+            self.__messagesMenu.addAction(
+                UI.PixmapCache.getIcon("editCopy.png"),
+                self.trUtf8("Copy all"), self.__copyAllMessages)
+        self.__messagesMenu.addSeparator()
+        self.__clearMessagesAct = \
+            self.__messagesMenu.addAction(
+                UI.PixmapCache.getIcon("editDelete.png"),
+                self.trUtf8("Clear"), self.__clearMessages)
+        self.__messagesMenu.addSeparator()
+        self.__saveMessagesAct = \
+            self.__messagesMenu.addAction(
+                UI.PixmapCache.getIcon("fileSave.png"),
+                self.trUtf8("Save"), self.__saveMessages)
+        
+        self.on_messages_copyAvailable(False)
+    
+    @pyqtSlot(bool)
+    def on_messages_copyAvailable(self, yes):
+        """
+        Private slot to react to text selection/deselection of the messages edit.
+        
+        @param yes flag signaling the availability of selected text (boolean)
+        """
+        self.__copyMessagesAct.setEnabled(yes)
+        self.__cutMessagesAct.setEnabled(yes)
+    
+    @pyqtSlot(QPoint)
+    def on_messages_customContextMenuRequested(self, pos):
+        """
+        Private slot to show the context menu of the messages pane.
+        """
+        enable = not self.messages.document().isEmpty()
+        self.__cutAllMessagesAct.setEnabled(enable)
+        self.__copyAllMessagesAct.setEnabled(enable)
+        self.__saveMessagesAct.setEnabled(enable)
+        self.__messagesMenu.popup(self.messages.mapToGlobal(pos))
--- a/Network/IRC/IrcNetworkWidget.ui	Sun Dec 02 18:53:39 2012 +0100
+++ b/Network/IRC/IrcNetworkWidget.ui	Mon Dec 10 18:40:10 2012 +0100
@@ -14,8 +14,14 @@
    <string/>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="margin">
+    <number>0</number>
+   </property>
    <item>
     <widget class="QTextBrowser" name="messages">
+     <property name="contextMenuPolicy">
+      <enum>Qt::CustomContextMenu</enum>
+     </property>
      <property name="toolTip">
       <string>Shows the network messages</string>
      </property>
@@ -47,6 +53,16 @@
       </widget>
      </item>
      <item>
+      <widget class="QToolButton" name="awayButton">
+       <property name="toolTip">
+        <string>Press to set the user status to AWAY</string>
+       </property>
+       <property name="text">
+        <string/>
+       </property>
+      </widget>
+     </item>
+     <item>
       <widget class="QToolButton" name="editButton">
        <property name="toolTip">
         <string>Press to edit the networks</string>
@@ -122,6 +138,7 @@
  <tabstops>
   <tabstop>networkCombo</tabstop>
   <tabstop>connectButton</tabstop>
+  <tabstop>awayButton</tabstop>
   <tabstop>editButton</tabstop>
   <tabstop>nickCombo</tabstop>
   <tabstop>channelCombo</tabstop>
--- a/Network/IRC/IrcUtilities.py	Sun Dec 02 18:53:39 2012 +0100
+++ b/Network/IRC/IrcUtilities.py	Mon Dec 10 18:40:10 2012 +0100
@@ -146,16 +146,21 @@
     global __channelModesDict
     
     modesDict = {
-        "t": QCoreApplication.translate("IrcUtilities", "topic protection"),
+        "a": QCoreApplication.translate("IrcUtilities", "anonymous"),
+        "b": QCoreApplication.translate("IrcUtilities", "ban mask"),
+        "c": QCoreApplication.translate("IrcUtilities", "no colors allowed"),
+        "e": QCoreApplication.translate("IrcUtilities", "ban exception mask"),
+        "i": QCoreApplication.translate("IrcUtilities", "invite only"),
+        "k": QCoreApplication.translate("IrcUtilities", "password protected"),
+        "l": QCoreApplication.translate("IrcUtilities", "user limit"),
+        "m": QCoreApplication.translate("IrcUtilities", "moderated"),
         "n": QCoreApplication.translate("IrcUtilities", "no messages from outside"),
-        "s": QCoreApplication.translate("IrcUtilities", "secret"),
-        "i": QCoreApplication.translate("IrcUtilities", "invite only"),
         "p": QCoreApplication.translate("IrcUtilities", "private"),
-        "m": QCoreApplication.translate("IrcUtilities", "moderated"),
-        "k": QCoreApplication.translate("IrcUtilities", "password protected"),
-        "a": QCoreApplication.translate("IrcUtilities", "anonymous"),
-        "c": QCoreApplication.translate("IrcUtilities", "no colors allowed"),
-        "l": QCoreApplication.translate("IrcUtilities", "user limit"),
+        "q": QCoreApplication.translate("IrcUtilities", "quit"),
+        "r": QCoreApplication.translate("IrcUtilities", "reop channel"),
+        "s": QCoreApplication.translate("IrcUtilities", "secret"),
+        "t": QCoreApplication.translate("IrcUtilities", "topic protection"),
+        "I": QCoreApplication.translate("IrcUtilities", "invitation mask"),
     }
     __channelModesDict = modesDict
 
--- a/Network/IRC/IrcWidget.py	Sun Dec 02 18:53:39 2012 +0100
+++ b/Network/IRC/IrcWidget.py	Mon Dec 10 18:40:10 2012 +0100
@@ -10,7 +10,7 @@
 import re
 import logging
 
-from PyQt4.QtCore import pyqtSlot, Qt, QByteArray, QTimer
+from PyQt4.QtCore import pyqtSlot, pyqtSignal, Qt, QByteArray, QTimer
 from PyQt4.QtGui import QWidget, QToolButton, QLabel
 from PyQt4.QtNetwork import QTcpSocket, QAbstractSocket
 try:
@@ -34,12 +34,15 @@
 class IrcWidget(QWidget, Ui_IrcWidget):
     """
     Class implementing the IRC window.
+    
+    @signal autoConnected() emitted after an automatic connection was initiated
     """
+    autoConnected = pyqtSignal()
+    
     ServerDisconnected = 1
     ServerConnected = 2
     ServerConnecting = 3
     
-    # TODO: Implement the Auto Away functionality
     def __init__(self, parent=None):
         """
         Constructor
@@ -50,7 +53,6 @@
         self.setupUi(self)
         
         self.__ircNetworkManager = IrcNetworkManager(self)
-        self.__ircNetworkManager.dataChanged.connect(self.__networkDataChanged)
         
         self.__leaveButton = QToolButton(self)
         self.__leaveButton.setIcon(UI.PixmapCache.getIcon("ircCloseChannel.png"))
@@ -60,12 +62,6 @@
         self.channelsWidget.setCornerWidget(self.__leaveButton, Qt.BottomRightCorner)
         self.channelsWidget.setTabsClosable(False)
         
-        self.networkWidget.initialize(self.__ircNetworkManager)
-        self.networkWidget.connectNetwork.connect(self.__connectNetwork)
-        self.networkWidget.editNetwork.connect(self.__editNetwork)
-        self.networkWidget.joinChannel.connect(self.__joinChannel)
-        self.networkWidget.nickChanged.connect(self.__changeNick)
-        
         self.__channelList = []
         self.__channelTypePrefixes = ""
         self.__userName = ""
@@ -85,6 +81,8 @@
         self.__socket = None
         
         self.__patterns = [
+            # :foo_!n=foo@foohost.bar.net PRIVMSG bar_ :some long message
+            (re.compile(r":([^!]+)!([^ ]+)\sPRIVMSG\s([^ ]+)\s:(.*)"), self.__query),
             # :foo.bar.net COMMAND some message
             (re.compile(r""":([^ ]+)\s+([A-Z]+)\s+(.+)"""), self.__handleNamedMessage),
             # :foo.bar.net 123 * :info
@@ -101,6 +99,16 @@
         self.__emptyLabel.setAlignment(Qt.AlignVCenter | Qt.AlignHCenter)
         self.channelsWidget.addTab(self.__emptyLabel, "")
         
+        # all initialized, do connections now
+        self.__ircNetworkManager.dataChanged.connect(self.__networkDataChanged)
+        self.networkWidget.initialize(self.__ircNetworkManager)
+        self.networkWidget.connectNetwork.connect(self.__connectNetwork)
+        self.networkWidget.editNetwork.connect(self.__editNetwork)
+        self.networkWidget.joinChannel.connect(self.__joinChannel)
+        self.networkWidget.nickChanged.connect(self.__changeNick)
+        self.networkWidget.sendData.connect(self.__send)
+        self.networkWidget.away.connect(self.__away)
+        self.networkWidget.autoConnected.connect(self.autoConnected)
     
     def shutdown(self):
         """
@@ -244,12 +252,15 @@
         identity = self.__ircNetworkManager.getIdentity(self.__identityName)
         channel.setPartMessage(identity.getPartMessage())
         channel.setUserPrivilegePrefix(self.__userPrefix)
+        channel.initAutoWho()
         
         channel.sendData.connect(self.__send)
         channel.channelClosed.connect(self.__closeChannel)
+        channel.openPrivateChat.connect(self.__openPrivate)
         
         self.channelsWidget.addTab(channel, name)
         self.__channelList.append(channel)
+        self.channelsWidget.setCurrentWidget(channel)
         
         joinCommand = ["JOIN", name]
         if key:
@@ -263,6 +274,48 @@
             self.__leaveButton.setEnabled(True)
         self.channelsWidget.setTabsClosable(True)
     
+    def __query(self, match):
+        """
+        Private method to handle a new private connection.
+        
+        @param reference to the match object
+        @return flag indicating, if the message was handled (boolean)
+        """
+        # group(1)   sender user name
+        # group(2)   sender user@host
+        # group(3)   target nick
+        # group(4)   message
+        self.__openPrivate(match.group(1))
+        # the above call sets the new channel as the current widget
+        channel = self.channelsWidget.currentWidget()
+        channel.addMessage(match.group(1), match.group(4))
+        channel.setPrivateInfo("{0} - {1}".format(match.group(1), match.group(2)))
+        
+        return True
+    
+    @pyqtSlot(str)
+    def __openPrivate(self, name):
+        """
+        Private slot to open a private chat with the given user.
+        
+        @param name name of the user (string)
+        """
+        channel = IrcChannelWidget(self)
+        channel.setName(self.__nickName)
+        channel.setUserName(self.__nickName)
+        identity = self.__ircNetworkManager.getIdentity(self.__identityName)
+        channel.setPartMessage(identity.getPartMessage())
+        channel.setUserPrivilegePrefix(self.__userPrefix)
+        channel.setPrivate(True, name)
+        channel.addUsers([name, self.__nickName])
+        
+        channel.sendData.connect(self.__send)
+        channel.channelClosed.connect(self.__closeChannel)
+        
+        self.channelsWidget.addTab(channel, name)
+        self.__channelList.append(channel)
+        self.channelsWidget.setCurrentWidget(channel)
+    
     @pyqtSlot()
     def __leaveChannel(self):
         """
@@ -351,6 +404,7 @@
         """
         self.networkWidget.addServerMessage(self.trUtf8("Info"),
             self.trUtf8("Server disconnected."))
+        self.networkWidget.setRegistered(False)
         self.networkWidget.setConnected(False)
         self.__server = None
         self.__nickName = ""
@@ -422,7 +476,7 @@
                 # :detlev_ MODE detlev_ :+i
                 name, modes = match.group(3).split(" :")
                 sourceNick = match.group(1)
-                if not self.__isChannelName(name):
+                if not self.isChannelName(name):
                     if name == self.__nickName:
                         if sourceNick == self.__nickName:
                             msg = self.trUtf8(
@@ -459,6 +513,10 @@
                     self.trUtf8("User {0} is now known as {1}.").format(
                     oldNick, newNick))
             return True
+        elif name == "ERROR":
+            self.networkWidget.addErrorMessage(
+                self.trUtf8("Server Error"), match.group(3).split(":", 1)[1])
+            return True
         
         return False
     
@@ -512,6 +570,8 @@
             msgType = self.trUtf8("User")
         elif code in [372, 375, 376]:
             msgType = self.trUtf8("MOTD")
+        elif code in [305, 306]:
+            msgType = self.trUtf8("Away")
         else:
             msgType = self.trUtf8("Info ({0})").format(code)
         
@@ -532,6 +592,10 @@
             parts = message.strip().split()
             message = self.trUtf8("Current users on the network: {0}, max. {1}").format(
                 parts[1], parts[2])
+        elif code == 305:
+            message = self.trUtf8("You are no longer marked as being away.")
+        elif code == 306:
+            message = self.trUtf8("You have been marked as being away.")
         else:
             first, message = message.split(None, 1)
             if message.startswith(":"):
@@ -545,6 +609,7 @@
             # register with services after the welcome message
             self.__connectionState = IrcWidget.ServerConnected
             self.__registerWithServices()
+            self.networkWidget.setRegistered(True)
             QTimer.singleShot(1000, self.__autoJoinChannels)
         elif code == 5:
             # extract the user privilege prefixes
@@ -725,9 +790,9 @@
         """
         self.__channelTypePrefixes = prefixes
     
-    def __isChannelName(self, name):
+    def isChannelName(self, name):
         """
-        Private method to check, if the given name is a channel name.
+        PublicisChannelName method to check, if the given name is a channel name.
         
         @return flag indicating a channel name (boolean)
         """
@@ -738,3 +803,15 @@
             return name[0] in self.__channelTypePrefixes
         else:
             return name[0] in "#&"
+    
+    def __away(self, isAway):
+        """
+        Private slot handling the change of the away state.
+        
+        @param isAway flag indicating the current away state (boolean)
+        """
+        if isAway and self.__identityName:
+            identity = self.__ircNetworkManager.getIdentity(self.__identityName)
+            if identity.rememberAwayPosition():
+                for channel in self.__channelList:
+                    channel.setMarkerLine()
--- a/Preferences/ConfigurationPages/IrcPage.py	Sun Dec 02 18:53:39 2012 +0100
+++ b/Preferences/ConfigurationPages/IrcPage.py	Mon Dec 10 18:40:10 2012 +0100
@@ -21,7 +21,6 @@
     DateFormats = ["yyyy-MM-dd", "dd.MM.yyyy", "MM/dd/yyyy",
                    "yyyy MMM. dd", "dd MMM. yyyy", "MMM. dd, yyyy"]
     
-    # TODO: add config entries for auto WHO
     def __init__(self):
         """
         Constructor
@@ -105,6 +104,19 @@
                          Preferences.getIrc, byName=True)
         self.initColour("IrcColor15", self.ircColor15Button,
                          Preferences.getIrc, byName=True)
+        
+        # Automatic User Information Lookup
+        self.whoGroup.setChecked(Preferences.getIrc("AutoUserInfoLookup"))
+        self.whoUsersSpinBox.setValue(Preferences.getIrc("AutoUserInfoMax"))
+        self.whoIntervalSpinBox.setValue(Preferences.getIrc("AutoUserInfoInterval"))
+        
+        # Markers
+        self.markWhenHiddenCheckBox.setChecked(
+            Preferences.getIrc("MarkPositionWhenHidden"))
+        self.initColour("MarkerLineForegroundColour", self.markerForegroundButton,
+                         Preferences.getIrc, byName=True)
+        self.initColour("MarkerLineBackgroundColour", self.markerBackgroundButton,
+                         Preferences.getIrc, byName=True)
     
     def save(self):
         """
@@ -122,6 +134,15 @@
         Preferences.setIrc("NotifyMessage", self.messageCheckBox.isChecked())
         Preferences.setIrc("NotifyNick", self.ownNickCheckBox.isChecked())
         
+        # Automatic User Information Lookup
+        Preferences.setIrc("AutoUserInfoLookup", self.whoGroup.isChecked())
+        Preferences.setIrc("AutoUserInfoMax", self.whoUsersSpinBox.value())
+        Preferences.setIrc("AutoUserInfoInterval", self.whoIntervalSpinBox.value())
+        
+        # Markers
+        Preferences.setIrc("MarkPositionWhenHidden",
+            self.markWhenHiddenCheckBox.isChecked())
+        
         # colours
         self.saveColours(Preferences.setIrc)
 
--- a/Preferences/ConfigurationPages/IrcPage.ui	Sun Dec 02 18:53:39 2012 +0100
+++ b/Preferences/ConfigurationPages/IrcPage.ui	Mon Dec 10 18:40:10 2012 +0100
@@ -10,7 +10,7 @@
     <height>853</height>
    </rect>
   </property>
-  <layout class="QVBoxLayout" name="verticalLayout">
+  <layout class="QVBoxLayout" name="verticalLayout_2">
    <item>
     <widget class="QLabel" name="headerLabel">
      <property name="text">
@@ -708,6 +708,155 @@
     </widget>
    </item>
    <item>
+    <widget class="QGroupBox" name="whoGroup">
+     <property name="toolTip">
+      <string>Select this to enable the automatic lookup of user information for joined channels</string>
+     </property>
+     <property name="title">
+      <string>Enable Automatic User Information Lookup (/WHO)</string>
+     </property>
+     <property name="checkable">
+      <bool>true</bool>
+     </property>
+     <property name="checked">
+      <bool>false</bool>
+     </property>
+     <layout class="QGridLayout" name="gridLayout_5">
+      <item row="0" column="0">
+       <widget class="QLabel" name="label_31">
+        <property name="text">
+         <string>Max. Number of Users in Channel:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="1">
+       <widget class="QSpinBox" name="whoUsersSpinBox">
+        <property name="toolTip">
+         <string>Enter the maximum numbers of users in a channel allowed for this function</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+        <property name="maximum">
+         <number>999</number>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="2">
+       <spacer name="horizontalSpacer">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>174</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item row="1" column="0">
+       <widget class="QLabel" name="label_32">
+        <property name="text">
+         <string>Update Interval:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="1">
+       <widget class="QSpinBox" name="whoIntervalSpinBox">
+        <property name="toolTip">
+         <string>Enter the user information update interval</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+        <property name="suffix">
+         <string> s</string>
+        </property>
+        <property name="minimum">
+         <number>30</number>
+        </property>
+        <property name="maximum">
+         <number>600</number>
+        </property>
+        <property name="singleStep">
+         <number>10</number>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="markerGroup">
+     <property name="title">
+      <string>Marker</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout">
+      <item>
+       <widget class="QCheckBox" name="markWhenHiddenCheckBox">
+        <property name="toolTip">
+         <string>Select to mark the current position, when the chat window is hidden</string>
+        </property>
+        <property name="text">
+         <string>Mark Current Position When Hidden</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout">
+        <item>
+         <widget class="QLabel" name="label_33">
+          <property name="text">
+           <string>Marker Foreground:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QPushButton" name="markerForegroundButton">
+          <property name="minimumSize">
+           <size>
+            <width>100</width>
+            <height>0</height>
+           </size>
+          </property>
+          <property name="toolTip">
+           <string>Select the foreground colour for the marker</string>
+          </property>
+          <property name="text">
+           <string/>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLabel" name="label_34">
+          <property name="text">
+           <string>Marker Background:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QPushButton" name="markerBackgroundButton">
+          <property name="minimumSize">
+           <size>
+            <width>100</width>
+            <height>0</height>
+           </size>
+          </property>
+          <property name="toolTip">
+           <string>Select the background colour for the marker</string>
+          </property>
+          <property name="text">
+           <string/>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
     <spacer name="verticalSpacer">
      <property name="orientation">
       <enum>Qt::Vertical</enum>
--- a/Preferences/__init__.py	Sun Dec 02 18:53:39 2012 +0100
+++ b/Preferences/__init__.py	Mon Dec 10 18:40:10 2012 +0100
@@ -953,6 +953,14 @@
         "NotifyJoinPart": True,
         "NotifyMessage": False,
         "NotifyNick": False,
+        
+        "AutoUserInfoLookup": True,
+        "AutoUserInfoMax": 200,
+        "AutoUserInfoInterval": 90,
+        
+        "MarkPositionWhenHidden": True,
+        "MarkerLineForegroundColour": "#000000",    # Black on
+        "MarkerLineBackgroundColour": "#ffff00",    # Yellow
     }
 
 
@@ -2587,9 +2595,13 @@
     @return the requested user setting
     """
     if key in ["TimestampIncludeDate", "ShowTimestamps", "ShowNotifications",
-               "NotifyJoinPart", "NotifyMessage", "NotifyNick", "EnableIrcColours"]:
+               "NotifyJoinPart", "NotifyMessage", "NotifyNick", "EnableIrcColours",
+               "AutoUserInfoLookup", "MarkPositionWhenHidden"]:
         return toBool(prefClass.settings.value("IRC/" + key,
                 prefClass.ircDefaults[key]))
+    elif key in ["AutoUserInfoMax", "AutoUserInfoInterval"]:
+        return int(prefClass.settings.value("IRC/" + key,
+                prefClass.ircDefaults[key]))
     else:
         return prefClass.settings.value("IRC/" + key, prefClass.ircDefaults[key])
 
--- a/UI/UserInterface.py	Sun Dec 02 18:53:39 2012 +0100
+++ b/UI/UserInterface.py	Mon Dec 10 18:40:10 2012 +0100
@@ -462,6 +462,8 @@
         
         self.numbersViewer.insertNumber.connect(self.viewmanager.insertNumber)
         
+        self.irc.autoConnected.connect(self.__ircAutoConnected)
+        
         # create the toolbar manager object
         self.toolbarManager = E5ToolBarManager(self, self)
         self.toolbarManager.setMainWindow(self)
@@ -5605,3 +5607,9 @@
         Public method to initiate the IRC auto connection.
         """
         self.irc.autoConnect()
+    
+    def __ircAutoConnected(self):
+        """
+        Private slot handling the automatic connection of the IRC client.
+        """
+        self.__activateIRC()
--- a/eric5.e4p	Sun Dec 02 18:53:39 2012 +0100
+++ b/eric5.e4p	Mon Dec 10 18:40:10 2012 +0100
@@ -1067,6 +1067,7 @@
     <Source>Network/IRC/IrcChannelEditDialog.py</Source>
     <Source>Network/IRC/IrcServerEditDialog.py</Source>
     <Source>Network/IRC/IrcIdentitiesEditDialog.py</Source>
+    <Source>Network/IRC/IrcMessageEdit.py</Source>
   </Sources>
   <Forms>
     <Form>PyUnit/UnittestDialog.ui</Form>
Binary file icons/default/ircUserAway.png has changed
Binary file icons/default/ircUserPresent.png has changed

eric ide

mercurial