Network/IRC/IrcChannelWidget.py

changeset 2252
1fc32bd13be3
parent 2246
fdf22a29fbf4
child 2253
7ba2af1ff785
equal deleted inserted replaced
2250:810e9c7b61e3 2252:1fc32bd13be3
7 Module implementing the IRC channel widget. 7 Module implementing the IRC channel widget.
8 """ 8 """
9 9
10 import re 10 import re
11 11
12 from PyQt4.QtCore import pyqtSlot, pyqtSignal, QDateTime, QPoint 12 from PyQt4.QtCore import pyqtSlot, pyqtSignal, QDateTime, QPoint, QFileInfo
13 from PyQt4.QtGui import QWidget, QListWidgetItem, QIcon, QPainter, QMenu 13 from PyQt4.QtGui import QWidget, QListWidgetItem, QIcon, QPainter, QMenu, QApplication
14 14
15 from E5Gui import E5MessageBox 15 from E5Gui import E5MessageBox, E5FileDialog
16 from E5Gui.E5Application import e5App 16 from E5Gui.E5Application import e5App
17 17
18 from .Ui_IrcChannelWidget import Ui_IrcChannelWidget 18 from .Ui_IrcChannelWidget import Ui_IrcChannelWidget
19 19
20 from .IrcUtilities import ircFilter, ircTimestamp, getChannelModesDict 20 from .IrcUtilities import ircFilter, ircTimestamp, getChannelModesDict
140 """ 140 """
141 Class implementing the IRC channel widget. 141 Class implementing the IRC channel widget.
142 142
143 @signal sendData(str) emitted to send a message to the channel 143 @signal sendData(str) emitted to send a message to the channel
144 @signal channelClosed(str) emitted after the user has left the channel 144 @signal channelClosed(str) emitted after the user has left the channel
145 @signal openPrivateChat(str) emitted to open a "channel" for private messages
145 """ 146 """
146 sendData = pyqtSignal(str) 147 sendData = pyqtSignal(str)
147 channelClosed = pyqtSignal(str) 148 channelClosed = pyqtSignal(str)
149 openPrivateChat = pyqtSignal(str)
148 150
149 UrlRe = re.compile(r"""((?:http|ftp|https):\/\/[\w\-_]+(?:\.[\w\-_]+)+""" 151 UrlRe = re.compile(r"""((?:http|ftp|https):\/\/[\w\-_]+(?:\.[\w\-_]+)+"""
150 r"""(?:[\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?)""") 152 r"""(?:[\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?)""")
151 153
152 JoinIndicator = "-->" 154 JoinIndicator = "-->"
161 # H The user is not away. 163 # H The user is not away.
162 # G The user is set away. 164 # G The user is set away.
163 # * The user is an IRC operator. 165 # * The user is an IRC operator.
164 # @ The user is a channel op in the channel listed in the first field. 166 # @ The user is a channel op in the channel listed in the first field.
165 # + The user is voiced in the channel listed. 167 # + The user is voiced in the channel listed.
166 # TODO: add context menu to messages pane with these entries:
167 # Copy
168 # Copy Link Location
169 # Copy All
170 # Clear
171 # Save
172 # Remember Position
173 # TODO: Remember current position with <hr/> when widget is invisible
174 # TODO: Check away indication in the user list 168 # TODO: Check away indication in the user list
175 def __init__(self, parent=None): 169 def __init__(self, parent=None):
176 """ 170 """
177 Constructor 171 Constructor
178 172
182 self.setupUi(self) 176 self.setupUi(self)
183 177
184 self.__ui = e5App().getObject("UserInterface") 178 self.__ui = e5App().getObject("UserInterface")
185 179
186 self.__initMessagesMenu() 180 self.__initMessagesMenu()
181 self.__initUsersMenu()
187 182
188 self.__name = "" 183 self.__name = ""
189 self.__userName = "" 184 self.__userName = ""
190 self.__partMessage = "" 185 self.__partMessage = ""
191 self.__prefixToPrivilege = {} 186 self.__prefixToPrivilege = {}
187 self.__private = False
188 self.__privatePartner = ""
192 189
193 self.__markerLine = "" 190 self.__markerLine = ""
191 self.__hidden = True
194 192
195 self.__patterns = [ 193 self.__patterns = [
196 # :foo_!n=foo@foohost.bar.net PRIVMSG #eric-ide :some long message 194 # :foo_!n=foo@foohost.bar.net PRIVMSG #eric-ide :some long message
197 (re.compile(r":([^!]+).*\sPRIVMSG\s([^ ]+)\s:(.*)"), self.__message), 195 (re.compile(r":([^!]+).*\sPRIVMSG\s([^ ]+)\s:(.*)"), self.__message),
198 # :foo_!n=foo@foohost.bar.net JOIN :#eric-ide 196 # :foo_!n=foo@foohost.bar.net JOIN :#eric-ide
209 # :foo_!n=foo@foohost.bar.net NICK :newnick 207 # :foo_!n=foo@foohost.bar.net NICK :newnick
210 (re.compile(r":([^!]+).*\sNICK\s:(.*)"), self.__userNickChange), 208 (re.compile(r":([^!]+).*\sNICK\s:(.*)"), self.__userNickChange),
211 # :barty!n=foo@foohost.bar.net MODE #eric-ide +o foo_ 209 # :barty!n=foo@foohost.bar.net MODE #eric-ide +o foo_
212 (re.compile(r":([^!]+).*\sMODE\s([^ ]+)\s([^ ]+)\s([^ ]+).*"), 210 (re.compile(r":([^!]+).*\sMODE\s([^ ]+)\s([^ ]+)\s([^ ]+).*"),
213 self.__setUserPrivilege), 211 self.__setUserPrivilege),
212 # :sturgeon.freenode.net 301 foo_ bar :Gone away for now
213 (re.compile(r":.*\s301\s([^ ]+)\s([^ ]+)\s:(.+)"), self.__userAway),
214 # :zelazny.freenode.net 324 foo_ #eric-ide +cnt 214 # :zelazny.freenode.net 324 foo_ #eric-ide +cnt
215 (re.compile(r":.*\s324\s.*\s([^ ]+)\s(.+)"), self.__channelModes), 215 (re.compile(r":.*\s324\s.*\s([^ ]+)\s(.+)"), self.__channelModes),
216 # :zelazny.freenode.net 328 foo_ #eric-ide :http://www.buggeroff.com/ 216 # :zelazny.freenode.net 328 foo_ #eric-ide :http://www.buggeroff.com/
217 (re.compile(r":.*\s328\s.*\s([^ ]+)\s:(.+)"), self.__channelUrl), 217 (re.compile(r":.*\s328\s.*\s([^ ]+)\s:(.+)"), self.__channelUrl),
218 # :zelazny.freenode.net 329 foo_ #eric-ide 1353001005 218 # :zelazny.freenode.net 329 foo_ #eric-ide 1353001005
223 (re.compile(r":.*\s333\s.*\s([^ ]+)\s([^ ]+)\s(\d+)"), self.__topicCreated), 223 (re.compile(r":.*\s333\s.*\s([^ ]+)\s([^ ]+)\s(\d+)"), self.__topicCreated),
224 # :zelazny.freenode.net 353 foo_ @ #eric-ide :@user1 +user2 user3 224 # :zelazny.freenode.net 353 foo_ @ #eric-ide :@user1 +user2 user3
225 (re.compile(r":.*\s353\s.*\s.\s([^ ]+)\s:(.*)"), self.__userList), 225 (re.compile(r":.*\s353\s.*\s.\s([^ ]+)\s:(.*)"), self.__userList),
226 # :zelazny.freenode.net 366 foo_ #eric-ide :End of /NAMES list. 226 # :zelazny.freenode.net 366 foo_ #eric-ide :End of /NAMES list.
227 (re.compile(r":.*\s366\s.*\s([^ ]+)\s:(.*)"), self.__ignore), 227 (re.compile(r":.*\s366\s.*\s([^ ]+)\s:(.*)"), self.__ignore),
228 # :sturgeon.freenode.net 704 foo_ index :Help topics available to users:
229 (re.compile(r":.*\s70[456]\s[^ ]+\s([^ ]+)\s:(.*)"), self.__help),
228 ] 230 ]
229 231
230 @pyqtSlot() 232 @pyqtSlot()
231 def on_messageEdit_returnPressed(self): 233 def on_messageEdit_returnPressed(self):
232 """ 234 """
238 '<font color="{0}">{2} <b>&lt;</b><font color="{1}">{3}</font>' 240 '<font color="{0}">{2} <b>&lt;</b><font color="{1}">{3}</font>'
239 '<b>&gt;</b> {4}</font>'.format( 241 '<b>&gt;</b> {4}</font>'.format(
240 Preferences.getIrc("ChannelMessageColour"), 242 Preferences.getIrc("ChannelMessageColour"),
241 Preferences.getIrc("OwnNickColour"), 243 Preferences.getIrc("OwnNickColour"),
242 ircTimestamp(), self.__userName, Utilities.html_encode(msg))) 244 ircTimestamp(), self.__userName, Utilities.html_encode(msg)))
243 self.sendData.emit("PRIVMSG " + self.__name + " :" + msg) 245 if msg.startswith("/"):
246 if self.__private:
247 E5MessageBox.information(self,
248 self.trUtf8("Send Message"),
249 self.trUtf8("""Messages starting with a '/' are not allowed"""
250 """ in private chats."""))
251 else:
252 msgList = msg.split(None, 1)
253 cmd = msgList[0][1:].upper()
254 if cmd == "MSG":
255 cmd = "PRIVMSG"
256 msgList[0] = cmd
257 self.sendData.emit(" ".join(msgList))
258 else:
259 if self.__private:
260 self.sendData.emit("PRIVMSG " + self.__privatePartner + " :" + msg)
261 else:
262 self.sendData.emit("PRIVMSG " + self.__name + " :" + msg)
244 self.messageEdit.clear() 263 self.messageEdit.clear()
245 264
246 def requestLeave(self): 265 def requestLeave(self):
247 """ 266 """
248 Public method to leave the channel. 267 Public method to leave the channel.
309 328
310 @param message message to be used for PART messages (string) 329 @param message message to be used for PART messages (string)
311 """ 330 """
312 self.__partMessage = message 331 self.__partMessage = message
313 332
333 def setPrivate(self, private, partner=""):
334 """
335 Public method to set the private chat mode.
336
337 @param private flag indicating private chat mode (boolean)
338 @param partner name of the partner user (string)
339 """
340 self.__private = private
341 self.__privatePartner = partner
342
314 def handleMessage(self, line): 343 def handleMessage(self, line):
315 """ 344 """
316 Public method to handle the message sent by the server. 345 Public method to handle the message sent by the server.
317 346
318 @param line server message (string) 347 @param line server message (string)
333 @param match match object that matched the pattern 362 @param match match object that matched the pattern
334 @return flag indicating whether the message was handled (boolean) 363 @return flag indicating whether the message was handled (boolean)
335 """ 364 """
336 if match.group(2).lower() == self.__name: 365 if match.group(2).lower() == self.__name:
337 msg = ircFilter(match.group(3)) 366 msg = ircFilter(match.group(3))
338 self.messages.append( 367 self.__appendMessage(
339 '<font color="{0}">{2} <b>&lt;</b><font color="{1}">{3}</font>' 368 '<font color="{0}">{2} <b>&lt;</b><font color="{1}">{3}</font>'
340 '<b>&gt;</b> {4}</font>'.format( 369 '<b>&gt;</b> {4}</font>'.format(
341 Preferences.getIrc("ChannelMessageColour"), 370 Preferences.getIrc("ChannelMessageColour"),
342 Preferences.getIrc("NickColour"), 371 Preferences.getIrc("NickColour"),
343 ircTimestamp(), match.group(1), 372 ircTimestamp(), match.group(1),
350 self.__ui.showNotification(UI.PixmapCache.getPixmap("irc48.png"), 379 self.__ui.showNotification(UI.PixmapCache.getPixmap("irc48.png"),
351 self.trUtf8("Nick mentioned"), msg) 380 self.trUtf8("Nick mentioned"), msg)
352 return True 381 return True
353 382
354 return False 383 return False
384
385 def addUsers(self, users):
386 """
387 Public method to add users to the channel.
388
389 @param users list of user names to add (list of string)
390 """
391 for user in users:
392 itm = self.__findUser(user)
393 if itm is None:
394 IrcUserItem(user, self.usersList)
355 395
356 def __userJoin(self, match): 396 def __userJoin(self, match):
357 """ 397 """
358 Private method to handle a user joining the channel. 398 Private method to handle a user joining the channel.
359 399
472 itm = self.__findUser(userName) 512 itm = self.__findUser(userName)
473 if itm is None: 513 if itm is None:
474 itm = IrcUserItem(userName, self.usersList) 514 itm = IrcUserItem(userName, self.usersList)
475 for privilege in userPrivileges: 515 for privilege in userPrivileges:
476 itm.changePrivilege(privilege) 516 itm.changePrivilege(privilege)
517 return True
518
519 return False
520
521 def __userAway(self, match):
522 """
523 Private method to handle a topic change of the channel.
524
525 @param match match object that matched the pattern
526 @return flag indicating whether the message was handled (boolean)
527 """
528 if match.group(1).lower() == self.__name:
529 self.__addManagementMessage(self.trUtf8("Away"),
530 self.trUtf8("{0} is away: {1}").format(match.group(2), match.group(3)))
477 return True 531 return True
478 532
479 return False 533 return False
480 534
481 def __setTopic(self, match): 535 def __setTopic(self, match):
603 if match.group(1).lower() == self.__name: 657 if match.group(1).lower() == self.__name:
604 return True 658 return True
605 659
606 return False 660 return False
607 661
662 def __help(self, match):
663 """
664 Private method to handle a help message.
665
666 @param match match object that matched the pattern
667 @return flag indicating whether the message was handled (boolean)
668 """
669 self.__addManagementMessage(self.trUtf8("Help"),
670 "{0} {1}".format(match.group(1), ircFilter(match.group(2))))
671 return True
672
608 def setUserPrivilegePrefix(self, prefixes): 673 def setUserPrivilegePrefix(self, prefixes):
609 """ 674 """
610 Public method to set the user privilege to prefix mapping. 675 Public method to set the user privilege to prefix mapping.
611 676
612 @param prefixes dictionary with privilege as key and prefix as value 677 @param prefixes dictionary with privilege as key and prefix as value
659 color = Preferences.getIrc("JoinChannelColour") 724 color = Preferences.getIrc("JoinChannelColour")
660 elif indicator == self.LeaveIndicator: 725 elif indicator == self.LeaveIndicator:
661 color = Preferences.getIrc("LeaveChannelColour") 726 color = Preferences.getIrc("LeaveChannelColour")
662 else: 727 else:
663 color = Preferences.getIrc("ChannelInfoColour") 728 color = Preferences.getIrc("ChannelInfoColour")
664 self.messages.append( 729 self.__appendMessage(
665 '<font color="{0}">{1} <b>[</b>{2}<b>]</b> {3}</font>'.format( 730 '<font color="{0}">{1} <b>[</b>{2}<b>]</b> {3}</font>'.format(
666 color, ircTimestamp(), indicator, message)) 731 color, ircTimestamp(), indicator, message))
732
733 def __appendMessage(self, message):
734 """
735 Private slot to append a message.
736 """
737 if self.__hidden and self.__markerLine == "":
738 self.setMarkerLine()
739 self.messages.append(message)
667 740
668 def setMarkerLine(self): 741 def setMarkerLine(self):
669 """ 742 """
670 Public method to draw a line to mark the current position. 743 Public method to draw a line to mark the current position.
671 """ 744 """
689 else: 762 else:
690 txt = txt.replace(self.__markerLine, "") 763 txt = txt.replace(self.__markerLine, "")
691 self.messages.setHtml(txt) 764 self.messages.setHtml(txt)
692 self.__markerLine = "" 765 self.__markerLine = ""
693 766
767 def __clearMessages(self):
768 """
769 Private slot to clear the contents of the messages display.
770 """
771 self.messages.clear()
772
773 def __copyMessages(self):
774 """
775 Private slot to copy the selection of the messages display to the clipboard.
776 """
777 self.messages.copy()
778
779 def __cutMessages(self):
780 """
781 Private slot to cut the selection of the messages display to the clipboard.
782 """
783 self.messages.cut()
784
785 def __copyAllMessages(self):
786 """
787 Private slot to copy the contents of the messages display to the clipboard.
788 """
789 txt = self.messages.toPlainText()
790 if txt:
791 cb = QApplication.clipboard()
792 cb.setText(txt)
793
794 def __cutAllMessages(self):
795 """
796 Private slot to cut the contents of the messages display to the clipboard.
797 """
798 txt = self.messages.toPlainText()
799 if txt:
800 cb = QApplication.clipboard()
801 cb.setText(txt)
802 self.messages.clear()
803
804 def __saveMessages(self):
805 """
806 Private slot to save the contents of the messages display.
807 """
808 hasText = not self.messages.document().isEmpty()
809 if hasText:
810 if Utilities.isWindowsPlatform():
811 htmlExtension = "htm"
812 else:
813 htmlExtension = "html"
814 fname, selectedFilter = E5FileDialog.getSaveFileNameAndFilter(
815 self,
816 self.trUtf8("Save Messages"),
817 "",
818 self.trUtf8(
819 "HTML Files (*.{0});;Text Files (*.txt);;All Files (*)").format(
820 htmlExtension),
821 None,
822 E5FileDialog.Options(E5FileDialog.DontConfirmOverwrite))
823 if fname:
824 ext = QFileInfo(fname).suffix()
825 if not ext:
826 ex = selectedFilter.split("(*")[1].split(")")[0]
827 if ex:
828 fname += ex
829 ext = QFileInfo(fname).suffix()
830 if QFileInfo(fname).exists():
831 res = E5MessageBox.yesNo(self,
832 self.trUtf8("Save Messages"),
833 self.trUtf8("<p>The file <b>{0}</b> already exists."
834 " Overwrite it?</p>").format(fname),
835 icon=E5MessageBox.Warning)
836 if not res:
837 return
838 fname = Utilities.toNativeSeparators(fname)
839
840 try:
841 if ext.lower() in ["htm", "html"]:
842 txt = self.messages.toHtml()
843 else:
844 txt = self.messages.toPlainText()
845 f = open(fname, "w", encoding="utf-8")
846 f.write(txt)
847 f.close()
848 except IOError as err:
849 E5MessageBox.critical(self,
850 self.trUtf8("Error saving Messages"),
851 self.trUtf8("""<p>The messages contents could not be written"""
852 """ to <b>{0}</b></p><p>Reason: {1}</p>""")\
853 .format(fname, str(err)))
854
694 def __initMessagesMenu(self): 855 def __initMessagesMenu(self):
695 """ 856 """
696 Private slot to initialize the context menu of the messages pane. 857 Private slot to initialize the context menu of the messages pane.
697 """ 858 """
698 self.__messagesMenu = QMenu(self) 859 self.__messagesMenu = QMenu(self)
699 ## self.__cutMessagesAct = \ 860 self.__cutMessagesAct = \
700 ## self.__messagesMenu.addAction( 861 self.__messagesMenu.addAction(
701 ## UI.PixmapCache.getIcon("editCut.png"), 862 UI.PixmapCache.getIcon("editCut.png"),
702 ## self.trUtf8("Cut"), self.__cutMessages) 863 self.trUtf8("Cut"), self.__cutMessages)
703 ## self.__copyMessagesAct = \ 864 self.__copyMessagesAct = \
704 ## self.__messagesMenu.addAction( 865 self.__messagesMenu.addAction(
705 ## UI.PixmapCache.getIcon("editCopy.png"), 866 UI.PixmapCache.getIcon("editCopy.png"),
706 ## self.trUtf8("Copy"), self.__copyMessages) 867 self.trUtf8("Copy"), self.__copyMessages)
707 ## self.__messagesMenu.addSeparator() 868 self.__messagesMenu.addSeparator()
708 ## self.__cutAllMessagesAct = \ 869 self.__cutAllMessagesAct = \
709 ## self.__messagesMenu.addAction( 870 self.__messagesMenu.addAction(
710 ## UI.PixmapCache.getIcon("editCut.png"), 871 UI.PixmapCache.getIcon("editCut.png"),
711 ## self.trUtf8("Cut all"), self.__cutAllMessages) 872 self.trUtf8("Cut all"), self.__cutAllMessages)
712 ## self.__copyAllMessagesAct = \ 873 self.__copyAllMessagesAct = \
713 ## self.__messagesMenu.addAction( 874 self.__messagesMenu.addAction(
714 ## UI.PixmapCache.getIcon("editCopy.png"), 875 UI.PixmapCache.getIcon("editCopy.png"),
715 ## self.trUtf8("Copy all"), self.__copyAllMessages) 876 self.trUtf8("Copy all"), self.__copyAllMessages)
716 ## self.__messagesMenu.addSeparator() 877 self.__messagesMenu.addSeparator()
717 ## self.__clearMessagesAct = \ 878 self.__clearMessagesAct = \
718 ## self.__messagesMenu.addAction( 879 self.__messagesMenu.addAction(
719 ## UI.PixmapCache.getIcon("editDelete.png"), 880 UI.PixmapCache.getIcon("editDelete.png"),
720 ## self.trUtf8("Clear"), self.__clearMessages) 881 self.trUtf8("Clear"), self.__clearMessages)
721 ## self.__messagesMenu.addSeparator() 882 self.__messagesMenu.addSeparator()
722 ## self.__saveMessagesAct = \ 883 self.__saveMessagesAct = \
723 ## self.__messagesMenu.addAction( 884 self.__messagesMenu.addAction(
724 ## UI.PixmapCache.getIcon("fileSave.png"), 885 UI.PixmapCache.getIcon("fileSave.png"),
725 ## self.trUtf8("Save"), self.__saveMessages) 886 self.trUtf8("Save"), self.__saveMessages)
887 self.__messagesMenu.addSeparator()
726 self.__setMarkerMessagesAct = \ 888 self.__setMarkerMessagesAct = \
727 self.__messagesMenu.addAction(self.trUtf8("Mark Current Position"), 889 self.__messagesMenu.addAction(self.trUtf8("Mark Current Position"),
728 self.setMarkerLine) 890 self.setMarkerLine)
729 self.__unsetMarkerMessagesAct = \ 891 self.__unsetMarkerMessagesAct = \
730 self.__messagesMenu.addAction(self.trUtf8("Remove Position Marker"), 892 self.__messagesMenu.addAction(self.trUtf8("Remove Position Marker"),
731 self.unsetMarkerLine) 893 self.unsetMarkerLine)
894
895 self.on_messages_copyAvailable(False)
896
897 @pyqtSlot(bool)
898 def on_messages_copyAvailable(self, yes):
899 """
900 Private slot to react to text selection/deselection of the messages edit.
901
902 @param yes flag signaling the availability of selected text (boolean)
903 """
904 self.__copyMessagesAct.setEnabled(yes)
905 self.__cutMessagesAct.setEnabled(yes)
732 906
733 @pyqtSlot(QPoint) 907 @pyqtSlot(QPoint)
734 def on_messages_customContextMenuRequested(self, pos): 908 def on_messages_customContextMenuRequested(self, pos):
735 """ 909 """
736 Private slot to show the context menu of the messages pane. 910 Private slot to show the context menu of the messages pane.
737 """ 911
912 @param pos the position of the mouse pointer (QPoint)
913 """
914 enable = not self.messages.document().isEmpty()
915 self.__cutAllMessagesAct.setEnabled(enable)
916 self.__copyAllMessagesAct.setEnabled(enable)
917 self.__saveMessagesAct.setEnabled(enable)
738 self.__setMarkerMessagesAct.setEnabled(self.__markerLine == "") 918 self.__setMarkerMessagesAct.setEnabled(self.__markerLine == "")
739 self.__unsetMarkerMessagesAct.setEnabled(self.__markerLine != "") 919 self.__unsetMarkerMessagesAct.setEnabled(self.__markerLine != "")
740 self.__messagesMenu.popup(self.messages.mapToGlobal(pos)) 920 self.__messagesMenu.popup(self.messages.mapToGlobal(pos))
741 921
922 def __whoIs(self):
923 """
924 Private slot to get information about the selected user.
925 """
926 # TODO: not implemented yet
927 return
928
929 def __openPrivateChat(self):
930 """
931 Private slot to open a chat with the selected user.
932 """
933 user = self.usersList.selectedItems()[0].text()
934 self.openPrivateChat.emit(user)
935
936 def __initUsersMenu(self):
937 """
938 Private slot to initialize the users list context menu.
939 """
940 self.__usersMenu = QMenu(self)
941 self.__usersMenu.addAction(self.trUtf8("Who Is"), self.__whoIs)
942 self.__usersMenu.addSeparator()
943 self.__privateChatAct = \
944 self.__usersMenu.addAction(self.trUtf8("Private Chat"),
945 self.__openPrivateChat)
946
742 @pyqtSlot(QPoint) 947 @pyqtSlot(QPoint)
743 def on_usersList_customContextMenuRequested(self, pos): 948 def on_usersList_customContextMenuRequested(self, pos):
744 """ 949 """
745 Private slot to show the context menu of the users list. 950 Private slot to show the context menu of the users list.
746 """ 951
747 # TODO: not implemented yet 952 @param pos the position of the mouse pointer (QPoint)
748 return 953 """
954 self.__privateChatAct.setEnabled(not self.__private)
955 if len(self.usersList.selectedItems()) > 0:
956 self.__usersMenu.popup(self.usersList.mapToGlobal(pos))
957
958 def hideEvent(self, evt):
959 """
960 Protected method handling hide events.
961
962 @param evt reference to the hide event (QHideEvent)
963 """
964 self.__hidden = True
965
966 def showEvent(self, evt):
967 """
968 Protected method handling show events.
969
970 @param evt reference to the show event (QShowEvent)
971 """
972 self.__hidden = False

eric ide

mercurial