Added a specialized line edit for entering IRC messages, which supports a non-persistent edit history.

Sun, 09 Dec 2012 16:18:17 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sun, 09 Dec 2012 16:18:17 +0100
changeset 2255
3e728bfc178c
parent 2254
14f923d13971
child 2256
d07e2e6f3c56

Added a specialized line edit for entering IRC messages, which supports a non-persistent edit history.
Improved the "private IRC chat" support.

Network/IRC/IrcChannelWidget.py file | annotate | diff | comparison | revisions
Network/IRC/IrcChannelWidget.ui file | annotate | diff | comparison | revisions
Network/IRC/IrcMessageEdit.py file | annotate | diff | comparison | revisions
Network/IRC/IrcWidget.py file | annotate | diff | comparison | revisions
eric5.e4p file | annotate | diff | comparison | revisions
--- a/Network/IRC/IrcChannelWidget.py	Sun Dec 09 13:01:15 2012 +0100
+++ b/Network/IRC/IrcChannelWidget.py	Sun Dec 09 16:18:17 2012 +0100
@@ -205,7 +205,8 @@
         
         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
             (re.compile(r":([^!]+)!([^ ]+)\sJOIN\s:?([^ ]+)"), self.__userJoin),
             # :foo_!n=foo@foohost.bar.net PART #eric-ide :part message
@@ -299,7 +300,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):
@@ -368,6 +370,15 @@
         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.
@@ -390,27 +401,40 @@
         @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.__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(), 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.lower() in msg.lower():
-                    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.
--- a/Network/IRC/IrcChannelWidget.ui	Sun Dec 09 13:01:15 2012 +0100
+++ b/Network/IRC/IrcChannelWidget.ui	Sun Dec 09 16:18:17 2012 +0100
@@ -69,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>
@@ -82,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>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Network/IRC/IrcMessageEdit.py	Sun Dec 09 16:18:17 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/IrcWidget.py	Sun Dec 09 13:01:15 2012 +0100
+++ b/Network/IRC/IrcWidget.py	Sun Dec 09 16:18:17 2012 +0100
@@ -77,6 +77,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
@@ -267,6 +269,25 @@
             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):
         """
--- a/eric5.e4p	Sun Dec 09 13:01:15 2012 +0100
+++ b/eric5.e4p	Sun Dec 09 16:18:17 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>

eric ide

mercurial