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