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