#!/usr/bin/python # -*- coding: utf-8 -*- # # Copyright (C) 2011 Sébastien Helleu # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # # WeeChat remote GUI using Qt toolkit. # (this script requires WeeChat 0.3.7 or newer, running on local or remote host) # # History: # # 2011-11-18, Sébastien Helleu : # version 0.1-dev: dev snapshot # 2011-05-27, Sébastien Helleu : # start dev # import sys from PyQt4 import QtGui, QtCore, QtNetwork SERVER_DEFAULT = (('server', 'weechat.org'), ('port', ''), ('password', '')) class Chat(QtGui.QSplitter): def __init__(self): QtGui.QSplitter.__init__(self) self.chatArea = QtGui.QTextEdit() self.chatArea.readOnly = True self.chatArea.setFocusPolicy(QtCore.Qt.NoFocus) self.nicklist = QtGui.QListWidget() self.nicklist.setMaximumWidth(100) self.nicklist.addItem('FlashCode') self.nicklist.addItem('abc1') self.nicklist.addItem('nick2') self.nicklist.setFocusPolicy(QtCore.Qt.NoFocus) self.addWidget(self.chatArea) self.addWidget(self.nicklist) self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) def display(self, text): self.chatArea.insertPlainText(text) if text[-1:] != '\n': self.chatArea.insertPlainText('\n') bar = self.chatArea.verticalScrollBar() bar.setValue(bar.maximum()) class Socket(QtNetwork.QTcpSocket): def __init__(self, window): QtNetwork.QTcpSocket.__init__(self) self.window = window self.server = None self.port = None self.password = None self.connect(self, QtCore.SIGNAL('connected()'), self.connected) self.connect(self, QtCore.SIGNAL('readyRead()'), self.readFromWeechat) self.connect(self, QtCore.SIGNAL('disconnected()'), self.disconnected) def connectWeechat(self, server, port, password): self.server = server try: self.port = int(port) except: self.port = 0 self.password = password if self.state() == QtNetwork.QAbstractSocket.UnconnectedState: self.connectToHost(self.server, self.port) #self.window.statusBar().showMessage('Connecting to %s:%d' % (self.server, self.port)) else: self.window.chat.display('Already connected!') def disconnectWeechat(self): if self.state() != QtNetwork.QAbstractSocket.UnconnectedState: self.disconnectFromHost() def connected(self): #self.window.statusBar().showMessage('Connected to %s:%d' % (self.server, self.port)) self.window.chat.display('Connected') if self.password: self.sendToWeechat('pass %s' % self.password, quiet=True) def sendToWeechat(self, message, quiet=False): if not quiet: self.window.chat.display('Sending: %s' % message) self.writeData(message) def readFromWeechat(self): avail = self.bytesAvailable() response = self.read(avail) self.window.chat.display('Response (%d bytes):\n%s' % (avail, response)) def disconnected(self): #self.window.statusBar().showMessage('Disconnected') self.window.chat.display('Disconnected') self.server = None self.port = None self.password = None class ConnectionWindow(QtGui.QDialog): def __init__(self, window): QtGui.QDialog.__init__(self, window) self.window = window self.setModal(True) grid = QtGui.QGridLayout() grid.setSpacing(10) self.fields = {} for y, field in enumerate(SERVER_DEFAULT): grid.addWidget(QtGui.QLabel(field[0].capitalize()), y, 0) lineEdit = QtGui.QLineEdit() if field[0] == 'password': lineEdit.setEchoMode(QtGui.QLineEdit.Password) lineEdit.insert(field[1]) grid.addWidget(lineEdit, y, 1) self.fields[field[0]] = lineEdit dialogButtonBox = QtGui.QDialogButtonBox() dialogButtonBox.setStandardButtons(QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel) self.connect(dialogButtonBox, QtCore.SIGNAL('accepted()'), self.connectWeechat) self.connect(dialogButtonBox, QtCore.SIGNAL('rejected()'), self.closeWindow) grid.addWidget(dialogButtonBox, 3, 0, 1, 2) self.setLayout(grid) self.show() def connectWeechat(self): self.window.socket.connectWeechat(self.fields['server'].text(), self.fields['port'].text(), self.fields['password'].text()) self.close() def closeWindow(self): self.close() class MainWindow(QtGui.QMainWindow): def __init__(self): QtGui.QMainWindow.__init__(self) self.resize(600, 400) self.setWindowTitle('qweechat') # network self.socket = Socket(self) # list of buffers self.buffers = QtGui.QListWidget() self.buffers.setMaximumWidth(100) self.buffers.setFocusPolicy(QtCore.Qt.NoFocus) self.buffers.addItem('*status*') self.buffers.addItem('core') self.buffers.addItem('#weechat') self.buffers.addItem('#test') # tab bar #self.tabBar = QtGui.QTabBar() #self.tabBar.setShape(QtGui.QTabBar.RoundedWest) #self.tabBar.addTab('core') #self.tabBar.addTab('#weechat') #self.tabBar.addTab('#test') # nick self.nick = QtGui.QLabel('FlashCode') self.nick.setContentsMargins(0, 0, 5, 0) # input self.input = QtGui.QLineEdit() self.connect(self.input, QtCore.SIGNAL('returnPressed()'), self.returnPressed) # chat area + nicklist self.chat = Chat() # nick + command line hboxEdit = QtGui.QHBoxLayout() hboxEdit.setMargin(0) hboxEdit.setSpacing(0) hboxEdit.addWidget(self.nick) hboxEdit.addWidget(self.input) lineEdit = QtGui.QWidget() lineEdit.setLayout(hboxEdit) lineEdit.setContentsMargins(0, 0, 0, 0) vbox = QtGui.QVBoxLayout() vbox.setMargin(0) vbox.setSpacing(0) vbox.addWidget(self.chat) vbox.addWidget(lineEdit) #vbox.addWidget(tabBar) # chat + input chatInput = QtGui.QWidget() chatInput.setLayout(vbox) # splitter with buffers + chat/input splitter = QtGui.QSplitter() splitter.addWidget(self.buffers) splitter.addWidget(chatInput) self.setCentralWidget(splitter) #self.statusBar().visible = True # menu: file / connect fileConnect = QtGui.QAction('Connect', self) fileConnect.setShortcut('Ctrl+O') fileConnect.setStatusTip('Connect to WeeChat') self.connect(fileConnect, QtCore.SIGNAL('triggered()'), self.connectWeechat) # menu: file / disconnect fileDisconnect = QtGui.QAction('Disconnect', self) fileDisconnect.setShortcut('Ctrl+D') fileDisconnect.setStatusTip('Disconnect from WeeChat') self.connect(fileDisconnect, QtCore.SIGNAL('triggered()'), self.socket.disconnectWeechat) # menu: file / exit fileExit = QtGui.QAction('Exit', self) fileExit.setShortcut('Ctrl+Q') fileExit.setStatusTip('Exit application') self.connect(fileExit, QtCore.SIGNAL('triggered()'), QtCore.SLOT('close()')) # menu self.menu = self.menuBar() menuFile = self.menu.addMenu('&File') menuFile.addAction(fileConnect) menuFile.addAction(fileDisconnect) menuFile.addAction(fileExit) self.menu.addMenu('&Server') self.menu.addMenu('&Window') self.menu.addMenu('&Help') def connectWeechat(self): self.connectionWindow = ConnectionWindow(self) def returnPressed(self): if self.socket.isOpen(): self.socket.sendToWeechat(self.input.text()) self.input.clear() app = QtGui.QApplication(sys.argv) app.setStyle(QtGui.QStyleFactory.create('Cleanlooks')) main = MainWindow() main.show() sys.exit(app.exec_())