|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2010 - 2019 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the chat dialog. |
|
8 """ |
|
9 |
|
10 from __future__ import unicode_literals |
|
11 |
|
12 from PyQt5.QtCore import Qt, pyqtSlot, pyqtSignal, QDateTime, QPoint, QFileInfo |
|
13 from PyQt5.QtGui import QColor |
|
14 from PyQt5.QtWidgets import QWidget, QListWidgetItem, QMenu, QApplication |
|
15 |
|
16 from E5Gui.E5Application import e5App |
|
17 from E5Gui import E5MessageBox, E5FileDialog |
|
18 |
|
19 from Globals import recentNameHosts |
|
20 |
|
21 from .CooperationClient import CooperationClient |
|
22 |
|
23 from .Ui_ChatWidget import Ui_ChatWidget |
|
24 |
|
25 import Preferences |
|
26 import Utilities |
|
27 import UI.PixmapCache |
|
28 |
|
29 |
|
30 class ChatWidget(QWidget, Ui_ChatWidget): |
|
31 """ |
|
32 Class implementing the chat dialog. |
|
33 |
|
34 @signal connected(connected) emitted to signal a change of the connected |
|
35 state (bool) |
|
36 @signal editorCommand(hashStr, filename, message) emitted when an editor |
|
37 command has been received (string, string, string) |
|
38 @signal shareEditor(share) emitted to signal a share is requested (bool) |
|
39 @signal startEdit() emitted to start a shared edit session |
|
40 @signal sendEdit() emitted to send a shared edit session |
|
41 @signal cancelEdit() emitted to cancel a shared edit session |
|
42 """ |
|
43 connected = pyqtSignal(bool) |
|
44 editorCommand = pyqtSignal(str, str, str) |
|
45 |
|
46 shareEditor = pyqtSignal(bool) |
|
47 startEdit = pyqtSignal() |
|
48 sendEdit = pyqtSignal() |
|
49 cancelEdit = pyqtSignal() |
|
50 |
|
51 def __init__(self, ui, port=-1, parent=None): |
|
52 """ |
|
53 Constructor |
|
54 |
|
55 @param ui reference to the user interface object (UserInterface) |
|
56 @param port port to be used for the cooperation server (integer) |
|
57 @param parent reference to the parent widget (QWidget) |
|
58 """ |
|
59 super(ChatWidget, self).__init__(parent) |
|
60 self.setupUi(self) |
|
61 |
|
62 self.shareButton.setIcon( |
|
63 UI.PixmapCache.getIcon("sharedEditDisconnected.png")) |
|
64 self.startEditButton.setIcon( |
|
65 UI.PixmapCache.getIcon("sharedEditStart.png")) |
|
66 self.sendEditButton.setIcon( |
|
67 UI.PixmapCache.getIcon("sharedEditSend.png")) |
|
68 self.cancelEditButton.setIcon( |
|
69 UI.PixmapCache.getIcon("sharedEditCancel.png")) |
|
70 |
|
71 self.__ui = ui |
|
72 self.__client = CooperationClient(self) |
|
73 self.__myNickName = self.__client.nickName() |
|
74 |
|
75 self.__initChatMenu() |
|
76 self.__initUsersMenu() |
|
77 |
|
78 self.messageEdit.returnPressed.connect(self.__handleMessage) |
|
79 self.sendButton.clicked.connect(self.__handleMessage) |
|
80 self.__client.newMessage.connect(self.appendMessage) |
|
81 self.__client.newParticipant.connect(self.__newParticipant) |
|
82 self.__client.participantLeft.connect(self.__participantLeft) |
|
83 self.__client.connectionError.connect(self.__showErrorMessage) |
|
84 self.__client.cannotConnect.connect(self.__initialConnectionRefused) |
|
85 self.__client.editorCommand.connect(self.__editorCommandMessage) |
|
86 |
|
87 self.serverButton.setText(self.tr("Start Server")) |
|
88 self.serverLed.setColor(QColor(Qt.red)) |
|
89 if port == -1: |
|
90 port = Preferences.getCooperation("ServerPort") |
|
91 |
|
92 self.serverPortSpin.setValue(port) |
|
93 |
|
94 self.__setConnected(False) |
|
95 |
|
96 if Preferences.getCooperation("AutoStartServer"): |
|
97 self.on_serverButton_clicked() |
|
98 |
|
99 self.recent = [] |
|
100 self.__loadHostsHistory() |
|
101 |
|
102 def __loadHostsHistory(self): |
|
103 """ |
|
104 Private method to load the recently connected hosts. |
|
105 """ |
|
106 self.__recent = [] |
|
107 Preferences.Prefs.rsettings.sync() |
|
108 rh = Preferences.Prefs.rsettings.value(recentNameHosts) |
|
109 if rh is not None: |
|
110 self.__recent = rh[:20] |
|
111 self.hostEdit.clear() |
|
112 self.hostEdit.addItems(self.__recent) |
|
113 self.hostEdit.clearEditText() |
|
114 |
|
115 def __saveHostsHistory(self): |
|
116 """ |
|
117 Private method to save the list of recently connected hosts. |
|
118 """ |
|
119 Preferences.Prefs.rsettings.setValue(recentNameHosts, self.__recent) |
|
120 Preferences.Prefs.rsettings.sync() |
|
121 |
|
122 def __setHostsHistory(self, host): |
|
123 """ |
|
124 Private method to remember the given host as the most recent entry. |
|
125 |
|
126 @param host host entry to remember (string) |
|
127 """ |
|
128 if host in self.__recent: |
|
129 self.__recent.remove(host) |
|
130 self.__recent.insert(0, host) |
|
131 self.__saveHostsHistory() |
|
132 self.hostEdit.clear() |
|
133 self.hostEdit.addItems(self.__recent) |
|
134 |
|
135 def __clearHostsHistory(self): |
|
136 """ |
|
137 Private slot to clear the hosts history. |
|
138 """ |
|
139 self.__recent = [] |
|
140 self.__saveHostsHistory() |
|
141 self.hostEdit.clear() |
|
142 self.hostEdit.addItems(self.__recent) |
|
143 |
|
144 def __handleMessage(self): |
|
145 """ |
|
146 Private slot handling the Return key pressed in the message edit. |
|
147 """ |
|
148 text = self.messageEdit.text() |
|
149 if text == "": |
|
150 return |
|
151 |
|
152 if text.startswith("/"): |
|
153 self.__showErrorMessage( |
|
154 self.tr("! Unknown command: {0}\n") |
|
155 .format(text.split()[0])) |
|
156 else: |
|
157 self.__client.sendMessage(text) |
|
158 self.appendMessage(self.__myNickName, text) |
|
159 |
|
160 self.messageEdit.clear() |
|
161 |
|
162 def __newParticipant(self, nick): |
|
163 """ |
|
164 Private slot handling a new participant joining. |
|
165 |
|
166 @param nick nick name of the new participant (string) |
|
167 """ |
|
168 if nick == "": |
|
169 return |
|
170 |
|
171 color = self.chatEdit.textColor() |
|
172 self.chatEdit.setTextColor(Qt.gray) |
|
173 self.chatEdit.append( |
|
174 QDateTime.currentDateTime().toString(Qt.SystemLocaleLongDate) + |
|
175 ":") |
|
176 self.chatEdit.append(self.tr("* {0} has joined.\n").format(nick)) |
|
177 self.chatEdit.setTextColor(color) |
|
178 |
|
179 QListWidgetItem( |
|
180 UI.PixmapCache.getIcon( |
|
181 "chatUser{0}.png".format(1 + self.usersList.count() % 6)), |
|
182 nick, self.usersList) |
|
183 |
|
184 if not self.__connected: |
|
185 self.__setConnected(True) |
|
186 |
|
187 if not self.isVisible(): |
|
188 self.__ui.showNotification( |
|
189 UI.PixmapCache.getPixmap("cooperation48.png"), |
|
190 self.tr("New User"), self.tr("{0} has joined.") |
|
191 .format(nick)) |
|
192 |
|
193 def __participantLeft(self, nick): |
|
194 """ |
|
195 Private slot handling a participant leaving the session. |
|
196 |
|
197 @param nick nick name of the participant (string) |
|
198 """ |
|
199 if nick == "": |
|
200 return |
|
201 |
|
202 items = self.usersList.findItems(nick, Qt.MatchExactly) |
|
203 for item in items: |
|
204 self.usersList.takeItem(self.usersList.row(item)) |
|
205 del item |
|
206 |
|
207 color = self.chatEdit.textColor() |
|
208 self.chatEdit.setTextColor(Qt.gray) |
|
209 self.chatEdit.append( |
|
210 QDateTime.currentDateTime().toString(Qt.SystemLocaleLongDate) + |
|
211 ":") |
|
212 self.chatEdit.append(self.tr("* {0} has left.\n").format(nick)) |
|
213 self.chatEdit.setTextColor(color) |
|
214 |
|
215 if not self.__client.hasConnections(): |
|
216 self.__setConnected(False) |
|
217 |
|
218 if not self.isVisible(): |
|
219 self.__ui.showNotification( |
|
220 UI.PixmapCache.getPixmap("cooperation48.png"), |
|
221 self.tr("User Left"), self.tr("{0} has left.") |
|
222 .format(nick)) |
|
223 |
|
224 def appendMessage(self, from_, message): |
|
225 """ |
|
226 Public slot to append a message to the display. |
|
227 |
|
228 @param from_ originator of the message (string) |
|
229 @param message message to be appended (string) |
|
230 """ |
|
231 if from_ == "" or message == "": |
|
232 return |
|
233 |
|
234 self.chatEdit.append( |
|
235 QDateTime.currentDateTime().toString(Qt.SystemLocaleLongDate) + |
|
236 " <" + from_ + ">:") |
|
237 self.chatEdit.append(message + "\n") |
|
238 bar = self.chatEdit.verticalScrollBar() |
|
239 bar.setValue(bar.maximum()) |
|
240 |
|
241 if not self.isVisible(): |
|
242 self.__ui.showNotification( |
|
243 UI.PixmapCache.getPixmap("cooperation48.png"), |
|
244 self.tr("Message from <{0}>").format(from_), message) |
|
245 |
|
246 @pyqtSlot(str) |
|
247 def on_hostEdit_editTextChanged(self, host): |
|
248 """ |
|
249 Private slot handling the entry of a host to connect to. |
|
250 |
|
251 @param host host to connect to (string) |
|
252 """ |
|
253 if not self.__connected: |
|
254 self.connectButton.setEnabled(host != "") |
|
255 |
|
256 def __getConnectionParameters(self): |
|
257 """ |
|
258 Private method to determine the connection parameters. |
|
259 |
|
260 @return tuple with hostname and port (string, integer) |
|
261 """ |
|
262 hostEntry = self.hostEdit.currentText() |
|
263 if "@" in hostEntry: |
|
264 host, port = hostEntry.split("@") |
|
265 try: |
|
266 port = int(port) |
|
267 except ValueError: |
|
268 port = Preferences.getCooperation("ServerPort") |
|
269 self.hostEdit.setEditText("{0}@{1}".format(host, port)) |
|
270 else: |
|
271 host = hostEntry |
|
272 port = Preferences.getCooperation("ServerPort") |
|
273 self.hostEdit.setEditText("{0}@{1}".format(host, port)) |
|
274 return host, port |
|
275 |
|
276 @pyqtSlot() |
|
277 def on_connectButton_clicked(self): |
|
278 """ |
|
279 Private slot initiating the connection. |
|
280 """ |
|
281 if not self.__connected: |
|
282 host, port = self.__getConnectionParameters() |
|
283 self.__setHostsHistory(self.hostEdit.currentText()) |
|
284 if not self.__client.isListening(): |
|
285 self.on_serverButton_clicked() |
|
286 if self.__client.isListening(): |
|
287 self.__client.connectToHost(host, port) |
|
288 self.__setConnected(True) |
|
289 else: |
|
290 self.__client.disconnectConnections() |
|
291 self.__setConnected(False) |
|
292 |
|
293 @pyqtSlot() |
|
294 def on_clearHostsButton_clicked(self): |
|
295 """ |
|
296 Private slot to clear the hosts list. |
|
297 """ |
|
298 self.__clearHostsHistory() |
|
299 |
|
300 @pyqtSlot() |
|
301 def on_serverButton_clicked(self): |
|
302 """ |
|
303 Private slot to start the server. |
|
304 """ |
|
305 if self.__client.isListening(): |
|
306 self.__client.close() |
|
307 self.serverButton.setText(self.tr("Start Server")) |
|
308 self.serverPortSpin.setEnabled(True) |
|
309 if (self.serverPortSpin.value() != |
|
310 Preferences.getCooperation("ServerPort")): |
|
311 self.serverPortSpin.setValue( |
|
312 Preferences.getCooperation("ServerPort")) |
|
313 self.serverLed.setColor(QColor(Qt.red)) |
|
314 else: |
|
315 res, port = self.__client.startListening( |
|
316 self.serverPortSpin.value()) |
|
317 if res: |
|
318 self.serverButton.setText(self.tr("Stop Server")) |
|
319 self.serverPortSpin.setValue(port) |
|
320 self.serverPortSpin.setEnabled(False) |
|
321 self.serverLed.setColor(QColor(Qt.green)) |
|
322 else: |
|
323 self.__showErrorMessage( |
|
324 self.tr("! Server Error: {0}\n").format( |
|
325 self.__client.errorString()) |
|
326 ) |
|
327 |
|
328 def __setConnected(self, connected): |
|
329 """ |
|
330 Private slot to set the connected state. |
|
331 |
|
332 @param connected new connected state (boolean) |
|
333 """ |
|
334 if connected: |
|
335 self.connectButton.setText(self.tr("Disconnect")) |
|
336 self.connectButton.setEnabled(True) |
|
337 self.connectionLed.setColor(QColor(Qt.green)) |
|
338 else: |
|
339 self.connectButton.setText(self.tr("Connect")) |
|
340 self.connectButton.setEnabled(self.hostEdit.currentText() != "") |
|
341 self.connectionLed.setColor(QColor(Qt.red)) |
|
342 self.on_cancelEditButton_clicked() |
|
343 self.shareButton.setChecked(False) |
|
344 self.on_shareButton_clicked(False) |
|
345 self.__connected = connected |
|
346 self.hostEdit.setEnabled(not connected) |
|
347 self.serverButton.setEnabled(not connected) |
|
348 self.sharingGroup.setEnabled(connected) |
|
349 |
|
350 if connected: |
|
351 vm = e5App().getObject("ViewManager") |
|
352 aw = vm.activeWindow() |
|
353 if aw: |
|
354 self.checkEditorActions(aw) |
|
355 |
|
356 def __showErrorMessage(self, message): |
|
357 """ |
|
358 Private slot to show an error message. |
|
359 |
|
360 @param message error message to show (string) |
|
361 """ |
|
362 color = self.chatEdit.textColor() |
|
363 self.chatEdit.setTextColor(Qt.red) |
|
364 self.chatEdit.append( |
|
365 QDateTime.currentDateTime().toString(Qt.SystemLocaleLongDate) + |
|
366 ":") |
|
367 self.chatEdit.append(message + "\n") |
|
368 self.chatEdit.setTextColor(color) |
|
369 |
|
370 def __initialConnectionRefused(self): |
|
371 """ |
|
372 Private slot to handle the refusal of the initial connection. |
|
373 """ |
|
374 self.__setConnected(False) |
|
375 |
|
376 def preferencesChanged(self): |
|
377 """ |
|
378 Public slot to handle a change of preferences. |
|
379 """ |
|
380 if not self.__client.isListening(): |
|
381 self.serverPortSpin.setValue( |
|
382 Preferences.getCooperation("ServerPort")) |
|
383 if Preferences.getCooperation("AutoStartServer"): |
|
384 self.on_serverButton_clicked() |
|
385 |
|
386 def getClient(self): |
|
387 """ |
|
388 Public method to get a reference to the cooperation client. |
|
389 |
|
390 @return reference to the cooperation client (CooperationClient) |
|
391 """ |
|
392 return self.__client |
|
393 |
|
394 def __editorCommandMessage(self, hashStr, fileName, message): |
|
395 """ |
|
396 Private slot to handle editor command messages from the client. |
|
397 |
|
398 @param hashStr hash of the project (string) |
|
399 @param fileName project relative file name of the editor (string) |
|
400 @param message command message (string) |
|
401 """ |
|
402 self.editorCommand.emit(hashStr, fileName, message) |
|
403 |
|
404 from QScintilla.Editor import Editor |
|
405 if message.startswith(Editor.StartEditToken + Editor.Separator) or \ |
|
406 message.startswith(Editor.EndEditToken + Editor.Separator): |
|
407 vm = e5App().getObject("ViewManager") |
|
408 aw = vm.activeWindow() |
|
409 if aw: |
|
410 self.checkEditorActions(aw) |
|
411 |
|
412 @pyqtSlot(bool) |
|
413 def on_shareButton_clicked(self, checked): |
|
414 """ |
|
415 Private slot to share the current editor. |
|
416 |
|
417 @param checked flag indicating the button state (boolean) |
|
418 """ |
|
419 if checked: |
|
420 self.shareButton.setIcon( |
|
421 UI.PixmapCache.getIcon("sharedEditConnected.png")) |
|
422 else: |
|
423 self.shareButton.setIcon( |
|
424 UI.PixmapCache.getIcon("sharedEditDisconnected.png")) |
|
425 self.startEditButton.setEnabled(checked) |
|
426 |
|
427 self.shareEditor.emit(checked) |
|
428 |
|
429 @pyqtSlot(bool) |
|
430 def on_startEditButton_clicked(self, checked): |
|
431 """ |
|
432 Private slot to start a shared edit session. |
|
433 |
|
434 @param checked flag indicating the button state (boolean) |
|
435 """ |
|
436 if checked: |
|
437 self.sendEditButton.setEnabled(True) |
|
438 self.cancelEditButton.setEnabled(True) |
|
439 self.shareButton.setEnabled(False) |
|
440 self.startEditButton.setEnabled(False) |
|
441 |
|
442 self.startEdit.emit() |
|
443 |
|
444 @pyqtSlot() |
|
445 def on_sendEditButton_clicked(self): |
|
446 """ |
|
447 Private slot to end a shared edit session and send the changes. |
|
448 """ |
|
449 self.sendEditButton.setEnabled(False) |
|
450 self.cancelEditButton.setEnabled(False) |
|
451 self.shareButton.setEnabled(True) |
|
452 self.startEditButton.setEnabled(True) |
|
453 self.startEditButton.setChecked(False) |
|
454 |
|
455 self.sendEdit.emit() |
|
456 |
|
457 @pyqtSlot() |
|
458 def on_cancelEditButton_clicked(self): |
|
459 """ |
|
460 Private slot to cancel a shared edit session. |
|
461 """ |
|
462 self.sendEditButton.setEnabled(False) |
|
463 self.cancelEditButton.setEnabled(False) |
|
464 self.shareButton.setEnabled(True) |
|
465 self.startEditButton.setEnabled(True) |
|
466 self.startEditButton.setChecked(False) |
|
467 |
|
468 self.cancelEdit.emit() |
|
469 |
|
470 def checkEditorActions(self, editor): |
|
471 """ |
|
472 Public slot to set action according to an editor's state. |
|
473 |
|
474 @param editor reference to the editor (Editor) |
|
475 """ |
|
476 shareable, sharing, editing, remoteEditing = editor.getSharingStatus() |
|
477 |
|
478 self.shareButton.setChecked(sharing) |
|
479 if sharing: |
|
480 self.shareButton.setIcon( |
|
481 UI.PixmapCache.getIcon("sharedEditConnected.png")) |
|
482 else: |
|
483 self.shareButton.setIcon( |
|
484 UI.PixmapCache.getIcon("sharedEditDisconnected.png")) |
|
485 self.startEditButton.setChecked(editing) |
|
486 |
|
487 self.shareButton.setEnabled(shareable and not editing) |
|
488 self.startEditButton.setEnabled( |
|
489 sharing and not editing and not remoteEditing) |
|
490 self.sendEditButton.setEnabled(editing) |
|
491 self.cancelEditButton.setEnabled(editing) |
|
492 |
|
493 def __initChatMenu(self): |
|
494 """ |
|
495 Private slot to initialize the chat edit context menu. |
|
496 """ |
|
497 self.__chatMenu = QMenu(self) |
|
498 self.__copyChatAct = \ |
|
499 self.__chatMenu.addAction( |
|
500 UI.PixmapCache.getIcon("editCopy.png"), |
|
501 self.tr("Copy"), self.__copyChat) |
|
502 self.__chatMenu.addSeparator() |
|
503 self.__cutAllChatAct = \ |
|
504 self.__chatMenu.addAction( |
|
505 UI.PixmapCache.getIcon("editCut.png"), |
|
506 self.tr("Cut all"), self.__cutAllChat) |
|
507 self.__copyAllChatAct = \ |
|
508 self.__chatMenu.addAction( |
|
509 UI.PixmapCache.getIcon("editCopy.png"), |
|
510 self.tr("Copy all"), self.__copyAllChat) |
|
511 self.__chatMenu.addSeparator() |
|
512 self.__clearChatAct = \ |
|
513 self.__chatMenu.addAction( |
|
514 UI.PixmapCache.getIcon("editDelete.png"), |
|
515 self.tr("Clear"), self.__clearChat) |
|
516 self.__chatMenu.addSeparator() |
|
517 self.__saveChatAct = \ |
|
518 self.__chatMenu.addAction( |
|
519 UI.PixmapCache.getIcon("fileSave.png"), |
|
520 self.tr("Save"), self.__saveChat) |
|
521 |
|
522 self.on_chatEdit_copyAvailable(False) |
|
523 |
|
524 @pyqtSlot(bool) |
|
525 def on_chatEdit_copyAvailable(self, yes): |
|
526 """ |
|
527 Private slot to react to text selection/deselection of the chat edit. |
|
528 |
|
529 @param yes flag signaling the availability of selected text (boolean) |
|
530 """ |
|
531 self.__copyChatAct.setEnabled(yes) |
|
532 |
|
533 @pyqtSlot(QPoint) |
|
534 def on_chatEdit_customContextMenuRequested(self, pos): |
|
535 """ |
|
536 Private slot to show the context menu for the chat. |
|
537 |
|
538 @param pos the position of the mouse pointer (QPoint) |
|
539 """ |
|
540 enable = self.chatEdit.toPlainText() != "" |
|
541 self.__saveChatAct.setEnabled(enable) |
|
542 self.__copyAllChatAct.setEnabled(enable) |
|
543 self.__cutAllChatAct.setEnabled(enable) |
|
544 self.__chatMenu.popup(self.chatEdit.mapToGlobal(pos)) |
|
545 |
|
546 def __clearChat(self): |
|
547 """ |
|
548 Private slot to clear the contents of the chat display. |
|
549 """ |
|
550 self.chatEdit.clear() |
|
551 |
|
552 def __saveChat(self): |
|
553 """ |
|
554 Private slot to save the contents of the chat display. |
|
555 """ |
|
556 txt = self.chatEdit.toPlainText() |
|
557 if txt: |
|
558 fname, selectedFilter = E5FileDialog.getSaveFileNameAndFilter( |
|
559 self, |
|
560 self.tr("Save Chat"), |
|
561 "", |
|
562 self.tr("Text Files (*.txt);;All Files (*)"), |
|
563 None, |
|
564 E5FileDialog.Options(E5FileDialog.DontConfirmOverwrite)) |
|
565 if fname: |
|
566 ext = QFileInfo(fname).suffix() |
|
567 if not ext: |
|
568 ex = selectedFilter.split("(*")[1].split(")")[0] |
|
569 if ex: |
|
570 fname += ex |
|
571 if QFileInfo(fname).exists(): |
|
572 res = E5MessageBox.yesNo( |
|
573 self, |
|
574 self.tr("Save Chat"), |
|
575 self.tr("<p>The file <b>{0}</b> already exists." |
|
576 " Overwrite it?</p>").format(fname), |
|
577 icon=E5MessageBox.Warning) |
|
578 if not res: |
|
579 return |
|
580 fname = Utilities.toNativeSeparators(fname) |
|
581 |
|
582 try: |
|
583 f = open(fname, "w", encoding="utf-8") |
|
584 f.write(txt) |
|
585 f.close() |
|
586 except IOError as err: |
|
587 E5MessageBox.critical( |
|
588 self, |
|
589 self.tr("Error saving Chat"), |
|
590 self.tr("""<p>The chat contents could not be""" |
|
591 """ written to <b>{0}</b></p>""" |
|
592 """<p>Reason: {1}</p>""") .format( |
|
593 fname, str(err))) |
|
594 |
|
595 def __copyChat(self): |
|
596 """ |
|
597 Private slot to copy the contents of the chat display to the clipboard. |
|
598 """ |
|
599 self.chatEdit.copy() |
|
600 |
|
601 def __copyAllChat(self): |
|
602 """ |
|
603 Private slot to copy the contents of the chat display to the clipboard. |
|
604 """ |
|
605 txt = self.chatEdit.toPlainText() |
|
606 if txt: |
|
607 cb = QApplication.clipboard() |
|
608 cb.setText(txt) |
|
609 |
|
610 def __cutAllChat(self): |
|
611 """ |
|
612 Private slot to cut the contents of the chat display to the clipboard. |
|
613 """ |
|
614 txt = self.chatEdit.toPlainText() |
|
615 if txt: |
|
616 cb = QApplication.clipboard() |
|
617 cb.setText(txt) |
|
618 self.chatEdit.clear() |
|
619 |
|
620 def __initUsersMenu(self): |
|
621 """ |
|
622 Private slot to initialize the users list context menu. |
|
623 """ |
|
624 self.__usersMenu = QMenu(self) |
|
625 self.__kickUserAct = \ |
|
626 self.__usersMenu.addAction( |
|
627 UI.PixmapCache.getIcon("chatKickUser.png"), |
|
628 self.tr("Kick User"), self.__kickUser) |
|
629 self.__banUserAct = \ |
|
630 self.__usersMenu.addAction( |
|
631 UI.PixmapCache.getIcon("chatBanUser.png"), |
|
632 self.tr("Ban User"), self.__banUser) |
|
633 self.__banKickUserAct = \ |
|
634 self.__usersMenu.addAction( |
|
635 UI.PixmapCache.getIcon("chatBanKickUser.png"), |
|
636 self.tr("Ban and Kick User"), self.__banKickUser) |
|
637 |
|
638 @pyqtSlot(QPoint) |
|
639 def on_usersList_customContextMenuRequested(self, pos): |
|
640 """ |
|
641 Private slot to show the context menu for the users list. |
|
642 |
|
643 @param pos the position of the mouse pointer (QPoint) |
|
644 """ |
|
645 itm = self.usersList.itemAt(pos) |
|
646 self.__kickUserAct.setEnabled(itm is not None) |
|
647 self.__banUserAct.setEnabled(itm is not None) |
|
648 self.__banKickUserAct.setEnabled(itm is not None) |
|
649 self.__usersMenu.popup(self.usersList.mapToGlobal(pos)) |
|
650 |
|
651 def __kickUser(self): |
|
652 """ |
|
653 Private slot to disconnect a user. |
|
654 """ |
|
655 itm = self.usersList.currentItem() |
|
656 self.__client.kickUser(itm.text()) |
|
657 |
|
658 color = self.chatEdit.textColor() |
|
659 self.chatEdit.setTextColor(Qt.darkYellow) |
|
660 self.chatEdit.append( |
|
661 QDateTime.currentDateTime().toString(Qt.SystemLocaleLongDate) + |
|
662 ":") |
|
663 self.chatEdit.append(self.tr("* {0} has been kicked.\n").format( |
|
664 itm.text().split("@")[0])) |
|
665 self.chatEdit.setTextColor(color) |
|
666 |
|
667 def __banUser(self): |
|
668 """ |
|
669 Private slot to ban a user. |
|
670 """ |
|
671 itm = self.usersList.currentItem() |
|
672 self.__client.banUser(itm.text()) |
|
673 |
|
674 color = self.chatEdit.textColor() |
|
675 self.chatEdit.setTextColor(Qt.darkYellow) |
|
676 self.chatEdit.append( |
|
677 QDateTime.currentDateTime().toString(Qt.SystemLocaleLongDate) + |
|
678 ":") |
|
679 self.chatEdit.append(self.tr("* {0} has been banned.\n").format( |
|
680 itm.text().split("@")[0])) |
|
681 self.chatEdit.setTextColor(color) |
|
682 |
|
683 def __banKickUser(self): |
|
684 """ |
|
685 Private slot to ban and kick a user. |
|
686 """ |
|
687 itm = self.usersList.currentItem() |
|
688 self.__client.banKickUser(itm.text()) |
|
689 |
|
690 color = self.chatEdit.textColor() |
|
691 self.chatEdit.setTextColor(Qt.darkYellow) |
|
692 self.chatEdit.append( |
|
693 QDateTime.currentDateTime().toString(Qt.SystemLocaleLongDate) + |
|
694 ":") |
|
695 self.chatEdit.append( |
|
696 self.tr("* {0} has been banned and kicked.\n") |
|
697 .format(itm.text().split("@")[0])) |
|
698 self.chatEdit.setTextColor(color) |
|
699 |
|
700 def shutdown(self): |
|
701 """ |
|
702 Public method to shut down the cooperation system. |
|
703 """ |
|
704 self.__client.disconnectConnections() |
|
705 self.__setConnected(False) |