]>
Commit | Line | Data |
---|---|---|
1 | # -*- coding: utf-8 -*- | |
2 | # | |
3 | # qweechat.py - WeeChat remote GUI using Qt toolkit | |
4 | # | |
5 | # Copyright (C) 2011-2014 Sébastien Helleu <flashcode@flashtux.org> | |
6 | # | |
7 | # This file is part of QWeeChat, a Qt remote GUI for WeeChat. | |
8 | # | |
9 | # QWeeChat is free software; you can redistribute it and/or modify | |
10 | # it under the terms of the GNU General Public License as published by | |
11 | # the Free Software Foundation; either version 3 of the License, or | |
12 | # (at your option) any later version. | |
13 | # | |
14 | # QWeeChat is distributed in the hope that it will be useful, | |
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | # GNU General Public License for more details. | |
18 | # | |
19 | # You should have received a copy of the GNU General Public License | |
20 | # along with QWeeChat. If not, see <http://www.gnu.org/licenses/>. | |
21 | # | |
22 | ||
23 | """ | |
24 | QWeeChat is a WeeChat remote GUI using Qt toolkit. | |
25 | ||
26 | It requires requires WeeChat 0.3.7 or newer, running on local or remote host. | |
27 | """ | |
28 | ||
29 | # | |
30 | # History: | |
31 | # | |
32 | # 2011-05-27, Sébastien Helleu <flashcode@flashtux.org>: | |
33 | # start dev | |
34 | # | |
35 | ||
36 | import sys | |
37 | import traceback | |
38 | from pkg_resources import resource_filename | |
39 | import qt_compat | |
40 | QTCORE = qt_compat.import_module('QtCore') | |
41 | QTGUI = qt_compat.import_module('QtGui') | |
42 | import config | |
43 | import weechat.protocol as protocol | |
44 | from network import Network | |
45 | from connection import ConnectionDialog | |
46 | from buffer import BufferListWidget, Buffer | |
47 | from debug import DebugDialog | |
48 | from about import AboutDialog | |
49 | from version import qweechat_version | |
50 | ||
51 | NAME = 'QWeeChat' | |
52 | AUTHOR = 'Sébastien Helleu' | |
53 | AUTHOR_MAIL = 'flashcode@flashtux.org' | |
54 | WEECHAT_SITE = 'https://weechat.org/' | |
55 | ||
56 | # number of lines in buffer for debug window | |
57 | DEBUG_NUM_LINES = 50 | |
58 | ||
59 | ||
60 | class MainWindow(QTGUI.QMainWindow): | |
61 | """Main window.""" | |
62 | ||
63 | def __init__(self, *args): | |
64 | QTGUI.QMainWindow.__init__(*(self,) + args) | |
65 | ||
66 | self.config = config.read() | |
67 | ||
68 | self.resize(1000, 600) | |
69 | self.setWindowTitle(NAME) | |
70 | ||
71 | self.debug_dialog = None | |
72 | self.debug_lines = [] | |
73 | ||
74 | self.about_dialog = None | |
75 | self.connection_dialog = None | |
76 | self.preferences_dialog = None | |
77 | ||
78 | # network | |
79 | self.network = Network() | |
80 | self.network.statusChanged.connect(self._network_status_changed) | |
81 | self.network.messageFromWeechat.connect(self._network_weechat_msg) | |
82 | ||
83 | # list of buffers | |
84 | self.list_buffers = BufferListWidget() | |
85 | self.list_buffers.currentRowChanged.connect(self._buffer_switch) | |
86 | ||
87 | # default buffer | |
88 | self.buffers = [Buffer()] | |
89 | self.stacked_buffers = QTGUI.QStackedWidget() | |
90 | self.stacked_buffers.addWidget(self.buffers[0].widget) | |
91 | ||
92 | # splitter with buffers + chat/input | |
93 | splitter = QTGUI.QSplitter() | |
94 | splitter.addWidget(self.list_buffers) | |
95 | splitter.addWidget(self.stacked_buffers) | |
96 | ||
97 | self.setCentralWidget(splitter) | |
98 | ||
99 | if self.config.getboolean('look', 'statusbar'): | |
100 | self.statusBar().visible = True | |
101 | ||
102 | # actions for menu and toolbar | |
103 | actions_def = { | |
104 | 'connect': [ | |
105 | 'network-connect.png', 'Connect to WeeChat', | |
106 | 'Ctrl+O', self.open_connection_dialog], | |
107 | 'disconnect': [ | |
108 | 'network-disconnect.png', 'Disconnect from WeeChat', | |
109 | 'Ctrl+D', self.network.disconnect_weechat], | |
110 | 'debug': [ | |
111 | 'edit-find.png', 'Debug console window', | |
112 | 'Ctrl+B', self.open_debug_dialog], | |
113 | 'preferences': [ | |
114 | 'preferences-other.png', 'Preferences', | |
115 | 'Ctrl+P', self.open_preferences_dialog], | |
116 | 'about': [ | |
117 | 'help-about.png', 'About', | |
118 | 'Ctrl+H', self.open_about_dialog], | |
119 | 'save connection': [ | |
120 | 'document-save.png', 'Save connection configuration', | |
121 | 'Ctrl+S', self.save_connection], | |
122 | 'quit': [ | |
123 | 'application-exit.png', 'Quit application', | |
124 | 'Ctrl+Q', self.close], | |
125 | } | |
126 | self.actions = {} | |
127 | for name, action in list(actions_def.items()): | |
128 | self.actions[name] = QTGUI.QAction( | |
129 | QTGUI.QIcon( | |
130 | resource_filename(__name__, 'data/icons/%s' % action[0])), | |
131 | name.capitalize(), self) | |
132 | self.actions[name].setStatusTip(action[1]) | |
133 | self.actions[name].setShortcut(action[2]) | |
134 | self.actions[name].triggered.connect(action[3]) | |
135 | ||
136 | # menu | |
137 | self.menu = self.menuBar() | |
138 | menu_file = self.menu.addMenu('&File') | |
139 | menu_file.addActions([self.actions['connect'], | |
140 | self.actions['disconnect'], | |
141 | self.actions['preferences'], | |
142 | self.actions['save connection'], | |
143 | self.actions['quit']]) | |
144 | menu_window = self.menu.addMenu('&Window') | |
145 | menu_window.addAction(self.actions['debug']) | |
146 | menu_help = self.menu.addMenu('&Help') | |
147 | menu_help.addAction(self.actions['about']) | |
148 | self.network_status = QTGUI.QLabel() | |
149 | self.network_status.setFixedHeight(20) | |
150 | self.network_status.setFixedWidth(200) | |
151 | self.network_status.setContentsMargins(0, 0, 10, 0) | |
152 | self.network_status.setAlignment(QTCORE.Qt.AlignRight) | |
153 | if hasattr(self.menu, 'setCornerWidget'): | |
154 | self.menu.setCornerWidget(self.network_status, | |
155 | QTCORE.Qt.TopRightCorner) | |
156 | self.network_status_set(self.network.status_disconnected) | |
157 | ||
158 | # toolbar | |
159 | toolbar = self.addToolBar('toolBar') | |
160 | toolbar.setToolButtonStyle(QTCORE.Qt.ToolButtonTextUnderIcon) | |
161 | toolbar.addActions([self.actions['connect'], | |
162 | self.actions['disconnect'], | |
163 | self.actions['debug'], | |
164 | self.actions['preferences'], | |
165 | self.actions['about'], | |
166 | self.actions['quit']]) | |
167 | ||
168 | self.buffers[0].widget.input.setFocus() | |
169 | ||
170 | # open debug dialog | |
171 | if self.config.getboolean('look', 'debug'): | |
172 | self.open_debug_dialog() | |
173 | ||
174 | # auto-connect to relay | |
175 | if self.config.getboolean('relay', 'autoconnect'): | |
176 | self.network.connect_weechat(self.config.get('relay', 'server'), | |
177 | self.config.get('relay', 'port'), | |
178 | self.config.getboolean('relay', | |
179 | 'ssl'), | |
180 | self.config.get('relay', 'password'), | |
181 | self.config.get('relay', 'lines')) | |
182 | ||
183 | self.show() | |
184 | ||
185 | def _buffer_switch(self, index): | |
186 | """Switch to a buffer.""" | |
187 | if index >= 0: | |
188 | self.stacked_buffers.setCurrentIndex(index) | |
189 | self.stacked_buffers.widget(index).input.setFocus() | |
190 | ||
191 | def buffer_input(self, full_name, text): | |
192 | """Send buffer input to WeeChat.""" | |
193 | if self.network.is_connected(): | |
194 | message = 'input %s %s\n' % (full_name, text) | |
195 | self.network.send_to_weechat(message) | |
196 | self.debug_display(0, '<==', message, forcecolor='#AA0000') | |
197 | ||
198 | def open_preferences_dialog(self): | |
199 | """Open a dialog with preferences.""" | |
200 | # TODO: implement the preferences dialog box | |
201 | messages = ['Not yet implemented!', | |
202 | ''] | |
203 | self.preferences_dialog = AboutDialog('Preferences', messages, self) | |
204 | ||
205 | def save_connection(self): | |
206 | """Save connection configuration.""" | |
207 | if self.network: | |
208 | options = self.network.get_options() | |
209 | for option in options.keys(): | |
210 | self.config.set('relay', option, options[option]) | |
211 | ||
212 | def debug_display(self, *args, **kwargs): | |
213 | """Display a debug message.""" | |
214 | self.debug_lines.append((args, kwargs)) | |
215 | self.debug_lines = self.debug_lines[-DEBUG_NUM_LINES:] | |
216 | if self.debug_dialog: | |
217 | self.debug_dialog.chat.display(*args, **kwargs) | |
218 | ||
219 | def open_debug_dialog(self): | |
220 | """Open a dialog with debug messages.""" | |
221 | if not self.debug_dialog: | |
222 | self.debug_dialog = DebugDialog(self) | |
223 | self.debug_dialog.input.textSent.connect( | |
224 | self.debug_input_text_sent) | |
225 | self.debug_dialog.finished.connect(self._debug_dialog_closed) | |
226 | self.debug_dialog.display_lines(self.debug_lines) | |
227 | self.debug_dialog.chat.scroll_bottom() | |
228 | ||
229 | def debug_input_text_sent(self, text): | |
230 | """Send debug buffer input to WeeChat.""" | |
231 | if self.network.is_connected(): | |
232 | text = str(text) | |
233 | pos = text.find(')') | |
234 | if text.startswith('(') and pos >= 0: | |
235 | text = '(debug_%s)%s' % (text[1:pos], text[pos+1:]) | |
236 | else: | |
237 | text = '(debug) %s' % text | |
238 | self.debug_display(0, '<==', text, forcecolor='#AA0000') | |
239 | self.network.send_to_weechat(text + '\n') | |
240 | ||
241 | def _debug_dialog_closed(self, result): | |
242 | """Called when debug dialog is closed.""" | |
243 | self.debug_dialog = None | |
244 | ||
245 | def open_about_dialog(self): | |
246 | """Open a dialog with info about QWeeChat.""" | |
247 | messages = ['<b>%s</b> %s' % (NAME, qweechat_version()), | |
248 | '© 2011-2014 %s <<a href="mailto:%s">%s</a>>' | |
249 | % (AUTHOR, AUTHOR_MAIL, AUTHOR_MAIL), | |
250 | '', | |
251 | 'Running with %s' % ('PySide' if qt_compat.uses_pyside | |
252 | else 'PyQt4'), | |
253 | '', | |
254 | 'WeeChat site: <a href="%s">%s</a>' | |
255 | % (WEECHAT_SITE, WEECHAT_SITE), | |
256 | ''] | |
257 | self.about_dialog = AboutDialog(NAME, messages, self) | |
258 | ||
259 | def open_connection_dialog(self): | |
260 | """Open a dialog with connection settings.""" | |
261 | values = {} | |
262 | for option in ('server', 'port', 'ssl', 'password', 'lines'): | |
263 | values[option] = self.config.get('relay', option) | |
264 | self.connection_dialog = ConnectionDialog(values, self) | |
265 | self.connection_dialog.dialog_buttons.accepted.connect( | |
266 | self.connect_weechat) | |
267 | ||
268 | def connect_weechat(self): | |
269 | """Connect to WeeChat.""" | |
270 | self.network.connect_weechat( | |
271 | self.connection_dialog.fields['server'].text(), | |
272 | self.connection_dialog.fields['port'].text(), | |
273 | self.connection_dialog.fields['ssl'].isChecked(), | |
274 | self.connection_dialog.fields['password'].text(), | |
275 | int(self.connection_dialog.fields['lines'].text())) | |
276 | self.connection_dialog.close() | |
277 | ||
278 | def _network_status_changed(self, status, extra): | |
279 | """Called when the network status has changed.""" | |
280 | if self.config.getboolean('look', 'statusbar'): | |
281 | self.statusBar().showMessage(status) | |
282 | self.debug_display(0, '', status, forcecolor='#0000AA') | |
283 | self.network_status_set(status) | |
284 | ||
285 | def network_status_set(self, status): | |
286 | """Set the network status.""" | |
287 | pal = self.network_status.palette() | |
288 | if status == self.network.status_connected: | |
289 | pal.setColor(self.network_status.foregroundRole(), | |
290 | QTGUI.QColor('green')) | |
291 | else: | |
292 | pal.setColor(self.network_status.foregroundRole(), | |
293 | QTGUI.QColor('#aa0000')) | |
294 | ssl = ' (SSL)' if status != self.network.status_disconnected \ | |
295 | and self.network.is_ssl() else '' | |
296 | self.network_status.setPalette(pal) | |
297 | icon = self.network.status_icon(status) | |
298 | if icon: | |
299 | self.network_status.setText( | |
300 | '<img src="%s"> %s' % | |
301 | (resource_filename(__name__, 'data/icons/%s' % icon), | |
302 | status.capitalize() + ssl)) | |
303 | else: | |
304 | self.network_status.setText(status.capitalize()) | |
305 | if status == self.network.status_disconnected: | |
306 | self.actions['connect'].setEnabled(True) | |
307 | self.actions['disconnect'].setEnabled(False) | |
308 | else: | |
309 | self.actions['connect'].setEnabled(False) | |
310 | self.actions['disconnect'].setEnabled(True) | |
311 | ||
312 | def _network_weechat_msg(self, message): | |
313 | """Called when a message is received from WeeChat.""" | |
314 | self.debug_display(0, '==>', | |
315 | 'message (%d bytes):\n%s' | |
316 | % (len(message), | |
317 | protocol.hex_and_ascii(message, 20)), | |
318 | forcecolor='#008800') | |
319 | try: | |
320 | proto = protocol.Protocol() | |
321 | message = proto.decode(str(message)) | |
322 | if message.uncompressed: | |
323 | self.debug_display( | |
324 | 0, '==>', | |
325 | 'message uncompressed (%d bytes):\n%s' | |
326 | % (message.size_uncompressed, | |
327 | protocol.hex_and_ascii(message.uncompressed, 20)), | |
328 | forcecolor='#008800') | |
329 | self.debug_display(0, '', 'Message: %s' % message) | |
330 | self.parse_message(message) | |
331 | except: | |
332 | print('Error while decoding message from WeeChat:\n%s' | |
333 | % traceback.format_exc()) | |
334 | self.network.disconnect_weechat() | |
335 | ||
336 | def _parse_listbuffers(self, message): | |
337 | """Parse a WeeChat with list of buffers.""" | |
338 | for obj in message.objects: | |
339 | if obj.objtype != 'hda' or obj.value['path'][-1] != 'buffer': | |
340 | continue | |
341 | self.list_buffers.clear() | |
342 | while self.stacked_buffers.count() > 0: | |
343 | buf = self.stacked_buffers.widget(0) | |
344 | self.stacked_buffers.removeWidget(buf) | |
345 | self.buffers = [] | |
346 | for item in obj.value['items']: | |
347 | buf = self.create_buffer(item) | |
348 | self.insert_buffer(len(self.buffers), buf) | |
349 | self.list_buffers.setCurrentRow(0) | |
350 | self.buffers[0].widget.input.setFocus() | |
351 | ||
352 | def _parse_line(self, message): | |
353 | """Parse a WeeChat message with a buffer line.""" | |
354 | for obj in message.objects: | |
355 | lines = [] | |
356 | if obj.objtype != 'hda' or obj.value['path'][-1] != 'line_data': | |
357 | continue | |
358 | for item in obj.value['items']: | |
359 | if message.msgid == 'listlines': | |
360 | ptrbuf = item['__path'][0] | |
361 | else: | |
362 | ptrbuf = item['buffer'] | |
363 | index = [i for i, b in enumerate(self.buffers) | |
364 | if b.pointer() == ptrbuf] | |
365 | if index: | |
366 | lines.append( | |
367 | (index[0], | |
368 | (item['date'], item['prefix'], | |
369 | item['message'])) | |
370 | ) | |
371 | if message.msgid == 'listlines': | |
372 | lines.reverse() | |
373 | for line in lines: | |
374 | self.buffers[line[0]].widget.chat.display(*line[1]) | |
375 | ||
376 | def _parse_nicklist(self, message): | |
377 | """Parse a WeeChat message with a buffer nicklist.""" | |
378 | buffer_refresh = {} | |
379 | for obj in message.objects: | |
380 | if obj.objtype != 'hda' or \ | |
381 | obj.value['path'][-1] != 'nicklist_item': | |
382 | continue | |
383 | group = '__root' | |
384 | for item in obj.value['items']: | |
385 | index = [i for i, b in enumerate(self.buffers) | |
386 | if b.pointer() == item['__path'][0]] | |
387 | if index: | |
388 | if not index[0] in buffer_refresh: | |
389 | self.buffers[index[0]].nicklist = {} | |
390 | buffer_refresh[index[0]] = True | |
391 | if item['group']: | |
392 | group = item['name'] | |
393 | self.buffers[index[0]].nicklist_add_item( | |
394 | group, item['group'], item['prefix'], item['name'], | |
395 | item['visible']) | |
396 | for index in buffer_refresh: | |
397 | self.buffers[index].nicklist_refresh() | |
398 | ||
399 | def _parse_nicklist_diff(self, message): | |
400 | """Parse a WeeChat message with a buffer nicklist diff.""" | |
401 | buffer_refresh = {} | |
402 | for obj in message.objects: | |
403 | if obj.objtype != 'hda' or \ | |
404 | obj.value['path'][-1] != 'nicklist_item': | |
405 | continue | |
406 | group = '__root' | |
407 | for item in obj.value['items']: | |
408 | index = [i for i, b in enumerate(self.buffers) | |
409 | if b.pointer() == item['__path'][0]] | |
410 | if not index: | |
411 | continue | |
412 | buffer_refresh[index[0]] = True | |
413 | if item['_diff'] == ord('^'): | |
414 | group = item['name'] | |
415 | elif item['_diff'] == ord('+'): | |
416 | self.buffers[index[0]].nicklist_add_item( | |
417 | group, item['group'], item['prefix'], item['name'], | |
418 | item['visible']) | |
419 | elif item['_diff'] == ord('-'): | |
420 | self.buffers[index[0]].nicklist_remove_item( | |
421 | group, item['group'], item['name']) | |
422 | elif item['_diff'] == ord('*'): | |
423 | self.buffers[index[0]].nicklist_update_item( | |
424 | group, item['group'], item['prefix'], item['name'], | |
425 | item['visible']) | |
426 | for index in buffer_refresh: | |
427 | self.buffers[index].nicklist_refresh() | |
428 | ||
429 | def _parse_buffer_opened(self, message): | |
430 | """Parse a WeeChat message with a new buffer (opened).""" | |
431 | for obj in message.objects: | |
432 | if obj.objtype != 'hda' or obj.value['path'][-1] != 'buffer': | |
433 | continue | |
434 | for item in obj.value['items']: | |
435 | buf = self.create_buffer(item) | |
436 | index = self.find_buffer_index_for_insert(item['next_buffer']) | |
437 | self.insert_buffer(index, buf) | |
438 | ||
439 | def _parse_buffer(self, message): | |
440 | """Parse a WeeChat message with a buffer event | |
441 | (anything except a new buffer). | |
442 | """ | |
443 | for obj in message.objects: | |
444 | if obj.objtype != 'hda' or obj.value['path'][-1] != 'buffer': | |
445 | continue | |
446 | for item in obj.value['items']: | |
447 | index = [i for i, b in enumerate(self.buffers) | |
448 | if b.pointer() == item['__path'][0]] | |
449 | if not index: | |
450 | continue | |
451 | index = index[0] | |
452 | if message.msgid == '_buffer_type_changed': | |
453 | self.buffers[index].data['type'] = item['type'] | |
454 | elif message.msgid in ('_buffer_moved', '_buffer_merged', | |
455 | '_buffer_unmerged'): | |
456 | buf = self.buffers[index] | |
457 | buf.data['number'] = item['number'] | |
458 | self.remove_buffer(index) | |
459 | index2 = self.find_buffer_index_for_insert( | |
460 | item['next_buffer']) | |
461 | self.insert_buffer(index2, buf) | |
462 | elif message.msgid == '_buffer_renamed': | |
463 | self.buffers[index].data['full_name'] = item['full_name'] | |
464 | self.buffers[index].data['short_name'] = item['short_name'] | |
465 | elif message.msgid == '_buffer_title_changed': | |
466 | self.buffers[index].data['title'] = item['title'] | |
467 | self.buffers[index].update_title() | |
468 | elif message.msgid == '_buffer_cleared': | |
469 | self.buffers[index].widget.chat.clear() | |
470 | elif message.msgid.startswith('_buffer_localvar_'): | |
471 | self.buffers[index].data['local_variables'] = \ | |
472 | item['local_variables'] | |
473 | self.buffers[index].update_prompt() | |
474 | elif message.msgid == '_buffer_closing': | |
475 | self.remove_buffer(index) | |
476 | ||
477 | def parse_message(self, message): | |
478 | """Parse a WeeChat message.""" | |
479 | if message.msgid.startswith('debug'): | |
480 | self.debug_display(0, '', '(debug message, ignored)') | |
481 | elif message.msgid == 'listbuffers': | |
482 | self._parse_listbuffers(message) | |
483 | elif message.msgid in ('listlines', '_buffer_line_added'): | |
484 | self._parse_line(message) | |
485 | elif message.msgid in ('_nicklist', 'nicklist'): | |
486 | self._parse_nicklist(message) | |
487 | elif message.msgid == '_nicklist_diff': | |
488 | self._parse_nicklist_diff(message) | |
489 | elif message.msgid == '_buffer_opened': | |
490 | self._parse_buffer_opened(message) | |
491 | elif message.msgid.startswith('_buffer_'): | |
492 | self._parse_buffer(message) | |
493 | elif message.msgid == '_upgrade': | |
494 | self.network.desync_weechat() | |
495 | elif message.msgid == '_upgrade_ended': | |
496 | self.network.sync_weechat() | |
497 | ||
498 | def create_buffer(self, item): | |
499 | """Create a new buffer.""" | |
500 | buf = Buffer(item) | |
501 | buf.bufferInput.connect(self.buffer_input) | |
502 | buf.widget.input.bufferSwitchPrev.connect( | |
503 | self.list_buffers.switch_prev_buffer) | |
504 | buf.widget.input.bufferSwitchNext.connect( | |
505 | self.list_buffers.switch_next_buffer) | |
506 | return buf | |
507 | ||
508 | def insert_buffer(self, index, buf): | |
509 | """Insert a buffer in list.""" | |
510 | self.buffers.insert(index, buf) | |
511 | self.list_buffers.insertItem(index, '%d. %s' | |
512 | % (buf.data['number'], | |
513 | buf.data['full_name'].decode('utf-8'))) | |
514 | self.stacked_buffers.insertWidget(index, buf.widget) | |
515 | ||
516 | def remove_buffer(self, index): | |
517 | """Remove a buffer.""" | |
518 | if self.list_buffers.currentRow == index and index > 0: | |
519 | self.list_buffers.setCurrentRow(index - 1) | |
520 | self.list_buffers.takeItem(index) | |
521 | self.stacked_buffers.removeWidget(self.stacked_buffers.widget(index)) | |
522 | self.buffers.pop(index) | |
523 | ||
524 | def find_buffer_index_for_insert(self, next_buffer): | |
525 | """Find position to insert a buffer in list.""" | |
526 | index = -1 | |
527 | if next_buffer == '0x0': | |
528 | index = len(self.buffers) | |
529 | else: | |
530 | index = [i for i, b in enumerate(self.buffers) | |
531 | if b.pointer() == next_buffer] | |
532 | if index: | |
533 | index = index[0] | |
534 | if index < 0: | |
535 | print('Warning: unable to find position for buffer, using end of ' | |
536 | 'list by default') | |
537 | index = len(self.buffers) | |
538 | return index | |
539 | ||
540 | def closeEvent(self, event): | |
541 | """Called when QWeeChat window is closed.""" | |
542 | self.network.disconnect_weechat() | |
543 | if self.debug_dialog: | |
544 | self.debug_dialog.close() | |
545 | config.write(self.config) | |
546 | QTGUI.QMainWindow.closeEvent(self, event) | |
547 | ||
548 | ||
549 | app = QTGUI.QApplication(sys.argv) | |
550 | app.setStyle(QTGUI.QStyleFactory.create('Cleanlooks')) | |
551 | app.setWindowIcon(QTGUI.QIcon( | |
552 | resource_filename(__name__, 'data/icons/weechat_icon_32.png'))) | |
553 | main = MainWindow() | |
554 | sys.exit(app.exec_()) |