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