aboutsummaryrefslogtreecommitdiffstats
path: root/examples/network
diff options
context:
space:
mode:
authorAhmed Youssef <xmonader@gmail.com>2009-08-19 20:26:00 +0300
committerAhmed Youssef <xmonader@gmail.com>2009-08-19 20:26:00 +0300
commit704bf0e5e6ed9b2b8a3dcbf8c5ad2648d33f4d3f (patch)
tree84e43bc770019161a349922b88ab2d9a2fcb75a7 /examples/network
Init
Diffstat (limited to 'examples/network')
-rw-r--r--examples/network/README26
-rwxr-xr-xexamples/network/blockingfortuneclient.py198
-rwxr-xr-xexamples/network/broadcastreceiver.py67
-rwxr-xr-xexamples/network/broadcastsender.py75
-rwxr-xr-xexamples/network/fortuneclient.py124
-rwxr-xr-xexamples/network/fortuneserver.py78
-rwxr-xr-xexamples/network/ftp/ftp.py251
-rw-r--r--examples/network/ftp/ftp.qrc7
-rw-r--r--examples/network/ftp/images/cdtoparent.pngbin0 -> 139 bytes
-rw-r--r--examples/network/ftp/images/dir.pngbin0 -> 155 bytes
-rw-r--r--examples/network/ftp/images/file.pngbin0 -> 129 bytes
-rw-r--r--examples/network/http/authenticationdialog.ui129
-rwxr-xr-xexamples/network/http/http.py196
-rwxr-xr-xexamples/network/loopback.py154
-rwxr-xr-xexamples/network/threadedfortuneserver.py121
15 files changed, 1426 insertions, 0 deletions
diff --git a/examples/network/README b/examples/network/README
new file mode 100644
index 0000000..7cfd561
--- /dev/null
+++ b/examples/network/README
@@ -0,0 +1,26 @@
+PyQt is provided with an extensive set of network classes to support both
+client-based and server side network programming.
+
+These examples demonstrate the fundamental aspects of network programming
+with PyQt.
+
+
+The example launcher provided with PyQt can be used to explore each of the
+examples in this directory.
+
+Documentation for these examples can be found via the Tutorial and Examples
+link in the main Qt documentation.
+
+
+Finding the PyQt Examples and Demos launcher
+============================================
+
+On Windows:
+
+The launcher can be accessed via the Windows Start menu. Select the menu
+entry entitled "Examples and Demos" entry in the submenu containing PyQt4.
+
+On all platforms:
+
+The source code for the launcher can be found in the examples/demos/qtdemo
+directory in the PyQt package.
diff --git a/examples/network/blockingfortuneclient.py b/examples/network/blockingfortuneclient.py
new file mode 100755
index 0000000..068980d
--- /dev/null
+++ b/examples/network/blockingfortuneclient.py
@@ -0,0 +1,198 @@
+#!/usr/bin/env python
+
+############################################################################
+#
+# Copyright (C) 2004-2005 Trolltech AS. All rights reserved.
+#
+# This file is part of the example classes of the Qt Toolkit.
+#
+# This file may be used under the terms of the GNU General Public
+# License version 2.0 as published by the Free Software Foundation
+# and appearing in the file LICENSE.GPL included in the packaging of
+# self file. Please review the following information to ensure GNU
+# General Public Licensing requirements will be met:
+# http://www.trolltech.com/products/qt/opensource.html
+#
+# If you are unsure which license is appropriate for your use, please
+# review the following information:
+# http://www.trolltech.com/products/qt/licensing.html or contact the
+# sales department at sales@trolltech.com.
+#
+# This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+# WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+#
+############################################################################
+
+from PyQt4 import QtCore, QtGui, QtNetwork
+
+
+class FortuneThread(QtCore.QThread):
+ newFortune = QtCore.pyqtSignal(str)
+
+ error = QtCore.pyqtSignal(int, str)
+
+ def __init__(self, parent=None):
+ super(FortuneThread, self).__init__(parent)
+
+ self.quit = False
+ self.hostName = QtCore.QString()
+ self.cond = QtCore.QWaitCondition()
+ self.mutex = QtCore.QMutex()
+ self.port = 0
+
+ def __del__(self):
+ self.mutex.lock()
+ self.quit = True
+ self.cond.wakeOne()
+ self.mutex.unlock()
+ self.wait()
+
+ def requestNewFortune(self, hostname, port):
+ locker = QtCore.QMutexLocker(self.mutex)
+ self.hostName = hostname
+ self.port = port
+ if not self.isRunning():
+ self.start()
+ else:
+ self.cond.wakeOne()
+
+ def run(self):
+ self.mutex.lock()
+ serverName = self.hostName
+ serverPort = self.port
+ self.mutex.unlock()
+
+ while not self.quit:
+ Timeout = 5 * 1000
+
+ socket = QtNetwork.QTcpSocket()
+ socket.connectToHost(serverName, serverPort)
+
+ if not socket.waitForConnected(Timeout):
+ self.error.emit(socket.error(), socket.errorString())
+ return
+
+ while socket.bytesAvailable() < 2:
+ if not socket.waitForReadyRead(Timeout):
+ self.error.emit(socket.error(), socket.errorString())
+ return
+
+ instr = QtCore.QDataStream(socket)
+ instr.setVersion(QtCore.QDataStream.Qt_4_0)
+ blockSize = instr.readUInt16()
+
+ while socket.bytesAvailable() < blockSize:
+ if not socket.waitForReadyRead(Timeout):
+ self.error.emit(socket.error(), socket.errorString())
+ return
+
+ self.mutex.lock()
+ fortune = QtCore.QString()
+ instr >> fortune
+ self.newFortune.emit(fortune)
+
+ self.cond.wait(self.mutex)
+ serverName = self.hostName
+ serverPort = self.port
+ self.mutex.unlock()
+
+
+class BlockingClient(QtGui.QDialog):
+ def __init__(self, parent=None):
+ super(BlockingClient, self).__init__(parent)
+
+ self.thread = FortuneThread()
+ self.currentFortune = QtCore.QString()
+
+ hostLabel = QtGui.QLabel(self.tr("&Server name:"))
+ portLabel = QtGui.QLabel(self.tr("S&erver port:"))
+
+ self.hostLineEdit = QtGui.QLineEdit("Localhost")
+ self.portLineEdit = QtGui.QLineEdit()
+ self.portLineEdit.setValidator(QtGui.QIntValidator(1, 65535, self))
+
+ hostLabel.setBuddy(self.hostLineEdit)
+ portLabel.setBuddy(self.portLineEdit)
+
+ self.statusLabel = QtGui.QLabel(self.tr("This example requires that "
+ "you run the Fortune Server "
+ "example as well."))
+
+ self.getFortuneButton = QtGui.QPushButton(self.tr("Get Fortune"))
+ self.getFortuneButton.setDefault(True)
+ self.getFortuneButton.setEnabled(False)
+
+ quitButton = QtGui.QPushButton(self.tr("Quit"))
+
+ buttonBox = QtGui.QDialogButtonBox()
+ buttonBox.addButton(self.getFortuneButton,
+ QtGui.QDialogButtonBox.ActionRole)
+ buttonBox.addButton(quitButton, QtGui.QDialogButtonBox.RejectRole)
+
+ self.hostLineEdit.textChanged.connect(self.enableGetFortuneButton)
+ self.portLineEdit.textChanged.connect(self.enableGetFortuneButton)
+ self.getFortuneButton.clicked.connect(self.requestNewFortune)
+ quitButton.clicked.connect(self.close)
+ self.thread.newFortune.connect(self.showFortune)
+ self.thread.error.connect(self.displayError)
+
+ mainLayout = QtGui.QGridLayout()
+ mainLayout.addWidget(hostLabel, 0, 0)
+ mainLayout.addWidget(self.hostLineEdit, 0, 1)
+ mainLayout.addWidget(portLabel, 1, 0)
+ mainLayout.addWidget(self.portLineEdit, 1, 1)
+ mainLayout.addWidget(self.statusLabel, 2, 0, 1, 2)
+ mainLayout.addWidget(buttonBox, 3, 0, 1, 2)
+ self.setLayout(mainLayout)
+
+ self.setWindowTitle(self.tr("Blocking Fortune Client"))
+ self.portLineEdit.setFocus()
+
+ def requestNewFortune(self):
+ self.getFortuneButton.setEnabled(False)
+ self.thread.requestNewFortune(self.hostLineEdit.text(),
+ self.portLineEdit.text().toInt()[0])
+
+ def showFortune(self, nextFortune):
+ if nextFortune == self.currentFortune:
+ self.requestNewFortune()
+ return
+
+ self.currentFortune = QtCore.QString(nextFortune)
+ self.statusLabel.setText(self.currentFortune)
+ self.getFortuneButton.setEnabled(True)
+
+ def displayError(self, socketError, message):
+ if socketError == QtNetwork.QAbstractSocket.HostNotFoundError:
+ QtGui.QMessageBox.information(self,
+ self.tr("Blocking Fortune Client"),
+ self.tr("The host was not found. Please check the host "
+ "and port settings."))
+ elif socketError == QtNetwork.QAbstractSocket.ConnectionRefusedError:
+ QtGui.QMessageBox.information(self,
+ self.tr("Blocking Fortune Client"),
+ self.tr("The connection was refused by the peer. Make "
+ "sure the fortune server is running, and check "
+ "that the host name and port settings are "
+ "correct."))
+ else:
+ QtGui.QMessageBox.information(self,
+ self.tr("Blocking Fortune Client"),
+ self.tr("The following error occurred: %1.").arg(message))
+
+ self.getFortuneButton.setEnabled(True)
+
+ def enableGetFortuneButton(self):
+ self.getFortuneButton.setEnabled(
+ not self.hostLineEdit.text().isEmpty() and
+ not self.portLineEdit.text().isEmpty())
+
+
+if __name__ == '__main__':
+
+ import sys
+
+ app = QtGui.QApplication(sys.argv)
+ client = BlockingClient()
+ client.show()
+ sys.exit(client.exec_())
diff --git a/examples/network/broadcastreceiver.py b/examples/network/broadcastreceiver.py
new file mode 100755
index 0000000..169ec6c
--- /dev/null
+++ b/examples/network/broadcastreceiver.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+
+############################################################################
+#
+# Copyright (C) 2004-2005 Trolltech AS. All rights reserved.
+#
+# This file is part of the example classes of the Qt Toolkit.
+#
+# This file may be used under the terms of the GNU General Public
+# License version 2.0 as published by the Free Software Foundation
+# and appearing in the file LICENSE.GPL included in the packaging of
+# self file. Please review the following information to ensure GNU
+# General Public Licensing requirements will be met:
+# http://www.trolltech.com/products/qt/opensource.html
+#
+# If you are unsure which license is appropriate for your use, please
+# review the following information:
+# http://www.trolltech.com/products/qt/licensing.html or contact the
+# sales department at sales@trolltech.com.
+#
+# This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+# WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+#
+############################################################################
+
+from PyQt4 import QtGui, QtNetwork
+
+
+class Receiver(QtGui.QDialog):
+ def __init__(self, parent=None):
+ super(Receiver, self).__init__(parent)
+
+ self.statusLabel = QtGui.QLabel(self.tr("Listening for broadcasted messages"))
+ quitButton = QtGui.QPushButton(self.tr("&Quit"))
+
+ self.udpSocket = QtNetwork.QUdpSocket(self)
+ self.udpSocket.bind(45454)
+
+ self.udpSocket.readyRead.connect(self.processPendingDatagrams)
+ quitButton.clicked.connect(self.close)
+
+ buttonLayout = QtGui.QHBoxLayout()
+ buttonLayout.addStretch(1)
+ buttonLayout.addWidget(quitButton)
+ buttonLayout.addStretch(1)
+
+ mainLayout = QtGui.QVBoxLayout()
+ mainLayout.addWidget(self.statusLabel)
+ mainLayout.addLayout(buttonLayout)
+ self.setLayout(mainLayout)
+
+ self.setWindowTitle(self.tr("Broadcast Receiver"))
+
+ def processPendingDatagrams(self):
+ while self.udpSocket.hasPendingDatagrams():
+ datagram, host, port = self.udpSocket.readDatagram(self.udpSocket.pendingDatagramSize())
+ self.statusLabel.setText(self.tr("Received datagram: \"%1\"").arg(datagram))
+
+
+if __name__ == '__main__':
+
+ import sys
+
+ app = QtGui.QApplication(sys.argv)
+ receiver = Receiver()
+ receiver.show()
+ sys.exit(receiver.exec_())
diff --git a/examples/network/broadcastsender.py b/examples/network/broadcastsender.py
new file mode 100755
index 0000000..48fb5d3
--- /dev/null
+++ b/examples/network/broadcastsender.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+
+############################################################################
+#
+# Copyright (C) 2004-2005 Trolltech AS. All rights reserved.
+#
+# This file is part of the example classes of the Qt Toolkit.
+#
+# This file may be used under the terms of the GNU General Public
+# License version 2.0 as published by the Free Software Foundation
+# and appearing in the file LICENSE.GPL included in the packaging of
+# self file. Please review the following information to ensure GNU
+# General Public Licensing requirements will be met:
+# http://www.trolltech.com/products/qt/opensource.html
+#
+# If you are unsure which license is appropriate for your use, please
+# review the following information:
+# http://www.trolltech.com/products/qt/licensing.html or contact the
+# sales department at sales@trolltech.com.
+#
+# This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+# WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+#
+############################################################################
+
+from PyQt4 import QtCore, QtGui, QtNetwork
+
+
+class Sender(QtGui.QDialog):
+ def __init__(self, parent=None):
+ super(Sender, self).__init__(parent)
+
+ self.statusLabel = QtGui.QLabel(self.tr("Ready to broadcast datagrams on port 45454"))
+
+ self.startButton = QtGui.QPushButton(self.tr("&Start"))
+ quitButton = QtGui.QPushButton(self.tr("&Quit"))
+
+ buttonBox = QtGui.QDialogButtonBox()
+ buttonBox.addButton(self.startButton, QtGui.QDialogButtonBox.ActionRole)
+ buttonBox.addButton(quitButton, QtGui.QDialogButtonBox.RejectRole)
+
+ self.timer = QtCore.QTimer(self)
+ self.udpSocket = QtNetwork.QUdpSocket(self)
+ self.messageNo = 1
+
+ self.startButton.clicked.connect(self.startBroadcasting)
+ quitButton.clicked.connect(self.close)
+ self.timer.timeout.connect(self.broadcastDatagramm)
+
+ mainLayout = QtGui.QVBoxLayout()
+ mainLayout.addWidget(self.statusLabel)
+ mainLayout.addWidget(buttonBox)
+ self.setLayout(mainLayout)
+
+ self.setWindowTitle(self.tr("Broadcast Sender"))
+
+ def startBroadcasting(self):
+ self.startButton.setEnabled(False)
+ self.timer.start(1000)
+
+ def broadcastDatagramm(self):
+ self.statusLabel.setText(self.tr("Now broadcasting datagram %1").arg(self.messageNo))
+ datagram = "Broadcast message %d" % self.messageNo
+ self.udpSocket.writeDatagram(datagram, QtNetwork.QHostAddress(QtNetwork.QHostAddress.Broadcast), 45454)
+ self.messageNo += 1
+
+
+if __name__ == '__main__':
+
+ import sys
+
+ app = QtGui.QApplication(sys.argv)
+ sender = Sender()
+ sender.show()
+ sys.exit(sender.exec_())
diff --git a/examples/network/fortuneclient.py b/examples/network/fortuneclient.py
new file mode 100755
index 0000000..8f293fa
--- /dev/null
+++ b/examples/network/fortuneclient.py
@@ -0,0 +1,124 @@
+#!/usr/bin/env python
+
+"""PyQt4 port of the network/fortuneclient example from Qt v4.x"""
+
+from PyQt4 import QtCore, QtGui, QtNetwork
+
+
+class Client(QtGui.QDialog):
+ def __init__(self, parent=None):
+ super(Client, self).__init__(parent)
+
+ self.blockSize = 0
+ self.currentFortune = QtCore.QString()
+
+ hostLabel = QtGui.QLabel(self.tr("&Server name:"))
+ portLabel = QtGui.QLabel(self.tr("S&erver port:"))
+
+ self.hostLineEdit = QtGui.QLineEdit("Localhost")
+ self.portLineEdit = QtGui.QLineEdit()
+ self.portLineEdit.setValidator(QtGui.QIntValidator(1, 65535, self))
+
+ hostLabel.setBuddy(self.hostLineEdit)
+ portLabel.setBuddy(self.portLineEdit)
+
+ self.statusLabel = QtGui.QLabel(self.tr("This examples requires that "
+ "you run the Fortune Server "
+ "example as well."))
+
+ self.getFortuneButton = QtGui.QPushButton(self.tr("Get Fortune"))
+ self.getFortuneButton.setDefault(True)
+ self.getFortuneButton.setEnabled(False)
+
+ quitButton = QtGui.QPushButton(self.tr("Quit"))
+
+ buttonBox = QtGui.QDialogButtonBox()
+ buttonBox.addButton(self.getFortuneButton,
+ QtGui.QDialogButtonBox.ActionRole)
+ buttonBox.addButton(quitButton, QtGui.QDialogButtonBox.RejectRole)
+
+ self.tcpSocket = QtNetwork.QTcpSocket(self)
+
+ self.hostLineEdit.textChanged.connect(self.enableGetFortuneButton)
+ self.portLineEdit.textChanged.connect(self.enableGetFortuneButton)
+ self.getFortuneButton.clicked.connect(self.requestNewFortune)
+ quitButton.clicked.connect(self.close)
+ self.tcpSocket.readyRead.connect(self.readFortune)
+ self.tcpSocket.error.connect(self.displayError)
+
+ mainLayout = QtGui.QGridLayout()
+ mainLayout.addWidget(hostLabel, 0, 0)
+ mainLayout.addWidget(self.hostLineEdit, 0, 1)
+ mainLayout.addWidget(portLabel, 1, 0)
+ mainLayout.addWidget(self.portLineEdit, 1, 1)
+ mainLayout.addWidget(self.statusLabel, 2, 0, 1, 2)
+ mainLayout.addWidget(buttonBox, 3, 0, 1, 2)
+ self.setLayout(mainLayout)
+
+ self.setWindowTitle(self.tr("Fortune Client"))
+ self.portLineEdit.setFocus()
+
+ def requestNewFortune(self):
+ self.getFortuneButton.setEnabled(False)
+ self.blockSize = 0
+ self.tcpSocket.abort()
+ self.tcpSocket.connectToHost(self.hostLineEdit.text(),
+ self.portLineEdit.text().toInt()[0])
+
+ def readFortune(self):
+ instr = QtCore.QDataStream(self.tcpSocket)
+ instr.setVersion(QtCore.QDataStream.Qt_4_0)
+
+ if self.blockSize == 0:
+ if self.tcpSocket.bytesAvailable() < 2:
+ return
+
+ self.blockSize = instr.readUInt16()
+
+ if self.tcpSocket.bytesAvailable() < self.blockSize:
+ return
+
+ nextFortune = QtCore.QString()
+ instr >> nextFortune
+
+ if nextFortune == self.currentFortune:
+ QtCore.QTimer.singleShot(0, self.requestNewFortune)
+ return
+
+ self.currentFortune = nextFortune
+ self.statusLabel.setText(self.currentFortune)
+ self.getFortuneButton.setEnabled(True)
+
+ def displayError(self, socketError):
+ if socketError == QtNetwork.QAbstractSocket.RemoteHostClosedError:
+ pass
+ elif socketError == QtNetwork.QAbstractSocket.HostNotFoundError:
+ QtGui.QMessageBox.information(self, self.tr("Fortune Client"),
+ self.tr("The host was not found. Please check the host "
+ "name and port settings."))
+ elif socketError == QtNetwork.QAbstractSocket.ConnectionRefusedError:
+ QtGui.QMessageBox.information(self, self.tr("Fortune Client"),
+ self.tr("The connection was refused by the peer. Make "
+ "sure the fortune server is running, and check "
+ "that the host name and port settings are "
+ "correct."))
+ else:
+ QtGui.QMessageBox.information(self, self.tr("Fortune Client"),
+ self.tr("The following error occurred: %1.").arg(self.tcpSocket.errorString()))
+
+ self.getFortuneButton.setEnabled(True)
+
+ def enableGetFortuneButton(self):
+ self.getFortuneButton.setEnabled(
+ not self.hostLineEdit.text().isEmpty() and
+ not self.portLineEdit.text().isEmpty())
+
+
+if __name__ == '__main__':
+
+ import sys
+
+ app = QtGui.QApplication(sys.argv)
+ client = Client()
+ client.show()
+ sys.exit(client.exec_())
diff --git a/examples/network/fortuneserver.py b/examples/network/fortuneserver.py
new file mode 100755
index 0000000..d663fa1
--- /dev/null
+++ b/examples/network/fortuneserver.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+
+"""PyQt4 port of the network/fortuneserver example from Qt v4.x"""
+
+import random
+import sys
+
+sys.path +=['/usr/local/lib/python2.6/site-packages']
+
+from PySide import QtCore, QtGui, QtNetwork
+
+
+class Server(QtGui.QDialog):
+ def __init__(self, parent=None):
+ super(Server, self).__init__(parent)
+
+ statusLabel = QtGui.QLabel()
+ quitButton = QtGui.QPushButton(self.tr("Quit"))
+ quitButton.setAutoDefault(False)
+
+ self.tcpServer = QtNetwork.QTcpServer(self)
+ if not self.tcpServer.listen():
+ QtGui.QMessageBox.critical(self, self.tr("Fortune Server"),
+ self.tr("Unable to start the server: %1.").arg(self.tcpServer.errorString()))
+ self.close()
+ return
+
+ statusLabel.setText(self.tr("The server is running on port %1.\n"
+ "Run the Fortune Client example now.").arg(self.tcpServer.serverPort()))
+
+ self.fortunes = [
+ self.tr("You've been leading a dog's life. Stay off the furniture."),
+ self.tr("You've got to think about tomorrow."),
+ self.tr("You will be surprised by a loud noise."),
+ self.tr("You will feel hungry again in another hour."),
+ self.tr("You might have mail."),
+ self.tr("You cannot kill time without injuring eternity."),
+ self.tr("Computers are not intelligent. They only think they are.")]
+
+ quitButton.clicked.connect(self.close)
+ self.tcpServer.newConnection.connect(self.sendFortune)
+
+ buttonLayout = QtGui.QHBoxLayout()
+ buttonLayout.addStretch(1)
+ buttonLayout.addWidget(quitButton)
+ buttonLayout.addStretch(1)
+
+ mainLayout = QtGui.QVBoxLayout()
+ mainLayout.addWidget(statusLabel)
+ mainLayout.addLayout(buttonLayout)
+ self.setLayout(mainLayout)
+
+ self.setWindowTitle(self.tr("Fortune Server"))
+
+ def sendFortune(self):
+ block = QtCore.QByteArray()
+ out = QtCore.QDataStream(block, QtCore.QIODevice.WriteOnly)
+ out.setVersion(QtCore.QDataStream.Qt_4_0)
+ out.writeUInt16(0)
+ out << self.fortunes[random.randint(0, len(self.fortunes) - 1)]
+ out.device().seek(0)
+ out.writeUInt16(block.size() - 2)
+
+ clientConnection = self.tcpServer.nextPendingConnection()
+ clientConnection.disconnected.connect(clientConnection.deleteLater)
+
+ clientConnection.write(block)
+ clientConnection.disconnectFromHost()
+
+
+if __name__ == '__main__':
+
+ import sys
+
+ app = QtGui.QApplication(sys.argv)
+ server = Server()
+ random.seed(None)
+ sys.exit(server.exec_())
diff --git a/examples/network/ftp/ftp.py b/examples/network/ftp/ftp.py
new file mode 100755
index 0000000..cf2d373
--- /dev/null
+++ b/examples/network/ftp/ftp.py
@@ -0,0 +1,251 @@
+#!/usr/bin/env python
+
+"""PyQt4 port of the network/ftp example from Qt v4.x"""
+
+from PyQt4 import QtCore, QtGui, QtNetwork
+
+import ftp_rc
+
+
+class FtpWindow(QtGui.QDialog):
+ def __init__(self, parent=None):
+ super(FtpWindow, self).__init__(parent)
+
+ self.isDirectory = {}
+ self.currentPath = QtCore.QString()
+ self.ftp = None
+ self.outFile = None
+
+ ftpServerLabel = QtGui.QLabel(self.tr("Ftp &server:"))
+ self.ftpServerLineEdit = QtGui.QLineEdit("ftp.trolltech.com")
+ ftpServerLabel.setBuddy(self.ftpServerLineEdit)
+
+ self.statusLabel = QtGui.QLabel(self.tr("Please enter the name of an FTP server."))
+
+ self.fileList = QtGui.QTreeWidget()
+ self.fileList.setEnabled(False)
+ self.fileList.setRootIsDecorated(False)
+ self.fileList.setHeaderLabels(QtCore.QStringList() << self.tr("Name") << self.tr("Size") << self.tr("Owner") << self.tr("Group") << self.tr("Time"))
+ self.fileList.header().setStretchLastSection(False)
+
+ self.connectButton = QtGui.QPushButton(self.tr("Connect"))
+ self.connectButton.setDefault(True)
+
+ self.cdToParentButton = QtGui.QPushButton()
+ self.cdToParentButton.setIcon(QtGui.QIcon(":/images/cdtoparent.png"))
+ self.cdToParentButton.setEnabled(False)
+
+ self.downloadButton = QtGui.QPushButton(self.tr("Download"))
+ self.downloadButton.setEnabled(False)
+
+ self.quitButton = QtGui.QPushButton(self.tr("Quit"))
+
+ buttonBox = QtGui.QDialogButtonBox()
+ buttonBox.addButton(self.downloadButton,
+ QtGui.QDialogButtonBox.ActionRole)
+ buttonBox.addButton(self.quitButton, QtGui.QDialogButtonBox.RejectRole)
+
+ self.progressDialog = QtGui.QProgressDialog(self)
+
+ self.fileList.itemActivated.connect(self.processItem)
+ self.fileList.currentItemChanged.connect(self.enableDownloadButton)
+ self.progressDialog.canceled.connect(self.cancelDownload)
+ self.connectButton.clicked.connect(self.connectOrDisconnect)
+ self.cdToParentButton.clicked.connect(self.cdToParent)
+ self.downloadButton.clicked.connect(self.downloadFile)
+ self.quitButton.clicked.connect(self.close)
+
+ topLayout = QtGui.QHBoxLayout()
+ topLayout.addWidget(ftpServerLabel)
+ topLayout.addWidget(self.ftpServerLineEdit)
+ topLayout.addWidget(self.cdToParentButton)
+ topLayout.addWidget(self.connectButton)
+
+ mainLayout = QtGui.QVBoxLayout()
+ mainLayout.addLayout(topLayout)
+ mainLayout.addWidget(self.fileList)
+ mainLayout.addWidget(self.statusLabel)
+ mainLayout.addWidget(buttonBox)
+ self.setLayout(mainLayout)
+
+ self.setWindowTitle(self.tr("FTP"))
+
+ def sizeHint(self):
+ return QtCore.QSize(500, 300)
+
+ def connectOrDisconnect(self):
+ if self.ftp:
+ self.ftp.abort()
+ self.ftp.deleteLater()
+ self.ftp = None
+
+ self.fileList.setEnabled(False)
+ self.cdToParentButton.setEnabled(False)
+ self.downloadButton.setEnabled(False)
+ self.connectButton.setEnabled(True)
+ self.connectButton.setText(self.tr("Connect"))
+ self.setCursor(QtCore.Qt.ArrowCursor)
+
+ return
+
+ self.setCursor(QtCore.Qt.WaitCursor)
+
+ self.ftp = QtNetwork.QFtp(self)
+ self.ftp.commandFinished.connect(self.ftpCommandFinished)
+ self.ftp.listInfo.connect(self.addToList)
+ self.ftp.dataTransferProgress.connect(self.updateDataTransferProgress)
+
+ self.fileList.clear()
+ self.currentPath.clear()
+ self.isDirectory.clear()
+
+ url = QtCore.QUrl(self.ftpServerLineEdit.text())
+ if not url.isValid() or url.scheme().toLower() != 'ftp':
+ self.ftp.connectToHost(self.ftpServerLineEdit.text(), 21)
+ self.ftp.login()
+ else:
+ self.ftp.connectToHost(url.host(), url.port(21))
+
+ if not url.userName().isEmpty():
+ self.ftp.login(QtCore.QUrl.fromPercentEncoding(url.userName().toLatin1()), url.password())
+ else:
+ self.ftp.login()
+
+ if not url.path().isEmpty():
+ self.ftp.cd(url.path())
+
+ self.fileList.setEnabled(True)
+ self.connectButton.setEnabled(False)
+ self.connectButton.setText(self.tr("Disconnect"))
+ self.statusLabel.setText(self.tr("Connecting to FTP server %1...")
+ .arg(self.ftpServerLineEdit.text()))
+
+ def downloadFile(self):
+ fileName = self.fileList.currentItem().text(0)
+
+ if QtCore.QFile.exists(fileName):
+ QtGui.QMessageBox.information(self, self.tr("FTP"),
+ self.tr("There already exists a file called %1 in the "
+ "current directory.").arg(fileName))
+ return
+
+ self.outFile = QtCore.QFile(fileName)
+ if not self.outFile.open(QtCore.QIODevice.WriteOnly):
+ QtGui.QMessageBox.information(self, self.tr("FTP"),
+ self.tr("Unable to save the file %1: %2.").arg(fileName).arg(self.outFile.errorString()))
+ self.outFile = None
+ return
+
+ self.ftp.get(self.fileList.currentItem().text(0), self.outFile)
+
+ self.progressDialog.setLabelText(self.tr("Downloading %1...").arg(fileName))
+ self.downloadButton.setEnabled(False)
+ self.progressDialog.exec_()
+
+ def cancelDownload(self):
+ self.ftp.abort()
+
+ def ftpCommandFinished(self, _, error):
+ self.setCursor(QtCore.Qt.ArrowCursor)
+
+ if self.ftp.currentCommand() == QtNetwork.QFtp.ConnectToHost:
+ if error:
+ QtGui.QMessageBox.information(self, self.tr("FTP"),
+ self.tr("Unable to connect to the FTP server at %1. "
+ "Please check that the host name is correct.").arg(self.ftpServerLineEdit.text()))
+ self.connectOrDisconnect()
+ return
+
+ self.statusLabel.setText(self.tr("Logged onto %1.").arg(self.ftpServerLineEdit.text()))
+ self.fileList.setFocus()
+ self.downloadButton.setDefault(True)
+ self.connectButton.setEnabled(True)
+ return
+
+ if self.ftp.currentCommand() == QtNetwork.QFtp.Login:
+ self.ftp.list()
+
+ if self.ftp.currentCommand() == QtNetwork.QFtp.Get:
+ if error:
+ self.statusLabel.setText(self.tr("Canceled download of %1.")
+ .arg(self.outFile.fileName()))
+ self.outFile.close()
+ self.outFile.remove()
+ else:
+ self.statusLabel.setText(self.tr("Downloaded %1 to current directory.")
+ .arg(self.outFile.fileName()))
+ self.outFile.close()
+
+ self.outFile = None
+ self.enableDownloadButton()
+ self.progressDialog.hide()
+ elif self.ftp.currentCommand() == QtNetwork.QFtp.List:
+ if not self.isDirectory:
+ self.fileList.addTopLevelItem(QtGui.QTreeWidgetItem([self.tr("<empty>")]))
+ self.fileList.setEnabled(False)
+
+ def addToList(self, urlInfo):
+ item = QtGui.QTreeWidgetItem()
+ item.setText(0, urlInfo.name())
+ item.setText(1, QtCore.QString.number(urlInfo.size()))
+ item.setText(2, urlInfo.owner())
+ item.setText(3, urlInfo.group())
+ item.setText(4, urlInfo.lastModified().toString("MMM dd yyyy"))
+
+ if urlInfo.isDir():
+ icon = QtGui.QIcon(":/images/dir.png")
+ else:
+ icon = QtGui.QIcon(":/images/file.png")
+ item.setIcon(0, icon)
+
+ self.isDirectory[urlInfo.name()] = urlInfo.isDir()
+ self.fileList.addTopLevelItem(item)
+ if not self.fileList.currentItem():
+ self.fileList.setCurrentItem(self.fileList.topLevelItem(0))
+ self.fileList.setEnabled(True)
+
+ def processItem(self, item):
+ name = item.text(0)
+ if self.isDirectory.get(name):
+ self.fileList.clear()
+ self.isDirectory.clear()
+ self.currentPath += "/" + name
+ self.ftp.cd(name)
+ self.ftp.list()
+ self.cdToParentButton.setEnabled(True)
+ self.setCursor(QtCore.Qt.WaitCursor)
+
+ def cdToParent(self):
+ self.setCursor(QtCore.Qt.WaitCursor)
+ self.fileList.clear()
+ self.isDirectory.clear()
+ self.currentPath = self.currentPath.left(self.currentPath.lastIndexOf('/'))
+ if self.currentPath.isEmpty():
+ self.cdToParentButton.setEnabled(False)
+ self.ftp.cd("/")
+ else:
+ self.ftp.cd(self.currentPath)
+
+ self.ftp.list()
+
+ def updateDataTransferProgress(self, readBytes, totalBytes):
+ self.progressDialog.setMaximum(totalBytes)
+ self.progressDialog.setValue(readBytes)
+
+ def enableDownloadButton(self):
+ current = self.fileList.currentItem()
+ if current:
+ currentFile = current.text(0)
+ self.downloadButton.setEnabled(not self.isDirectory.get(currentFile))
+ else:
+ self.downloadButton.setEnabled(False)
+
+
+if __name__ == '__main__':
+
+ import sys
+
+ app = QtGui.QApplication(sys.argv)
+ ftpWin = FtpWindow()
+ ftpWin.show()
+ sys.exit(ftpWin.exec_())
diff --git a/examples/network/ftp/ftp.qrc b/examples/network/ftp/ftp.qrc
new file mode 100644
index 0000000..b598ab8
--- /dev/null
+++ b/examples/network/ftp/ftp.qrc
@@ -0,0 +1,7 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>images/cdtoparent.png</file>
+ <file>images/dir.png</file>
+ <file>images/file.png</file>
+</qresource>
+</RCC>
diff --git a/examples/network/ftp/images/cdtoparent.png b/examples/network/ftp/images/cdtoparent.png
new file mode 100644
index 0000000..24b6180
--- /dev/null
+++ b/examples/network/ftp/images/cdtoparent.png
Binary files differ
diff --git a/examples/network/ftp/images/dir.png b/examples/network/ftp/images/dir.png
new file mode 100644
index 0000000..e81f5cd
--- /dev/null
+++ b/examples/network/ftp/images/dir.png
Binary files differ
diff --git a/examples/network/ftp/images/file.png b/examples/network/ftp/images/file.png
new file mode 100644
index 0000000..be6c530
--- /dev/null
+++ b/examples/network/ftp/images/file.png
Binary files differ
diff --git a/examples/network/http/authenticationdialog.ui b/examples/network/http/authenticationdialog.ui
new file mode 100644
index 0000000..82d908c
--- /dev/null
+++ b/examples/network/http/authenticationdialog.ui
@@ -0,0 +1,129 @@
+<ui version="4.0" >
+ <class>Dialog</class>
+ <widget class="QDialog" name="Dialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>389</width>
+ <height>243</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Http authentication required</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" colspan="2" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>You need to supply a Username and a Password to access this site</string>
+ </property>
+ <property name="wordWrap" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Username:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QLineEdit" name="userEdit" />
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_3" >
+ <property name="text" >
+ <string>Password:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" >
+ <widget class="QLineEdit" name="passwordEdit" />
+ </item>
+ <item row="5" column="0" colspan="2" >
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_4" >
+ <property name="text" >
+ <string>Site:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLabel" name="siteDescription" >
+ <property name="font" >
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text" >
+ <string>%1 at %2</string>
+ </property>
+ <property name="wordWrap" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>Dialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>Dialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/examples/network/http/http.py b/examples/network/http/http.py
new file mode 100755
index 0000000..d76b2d0
--- /dev/null
+++ b/examples/network/http/http.py
@@ -0,0 +1,196 @@
+#!/usr/bin/env python
+
+"""PyQt4 port of the network/http example from Qt v4.x"""
+
+from PyQt4 import QtCore, QtGui, QtNetwork
+
+
+class HttpWindow(QtGui.QDialog):
+ def __init__(self, parent=None):
+ super(HttpWindow, self).__init__(parent)
+
+ self.outFile = None
+ self.httpGetId = 0
+ self.httpRequestAborted = False
+
+ self.urlLineEdit = QtGui.QLineEdit("https://")
+
+ urlLabel = QtGui.QLabel(self.tr("&URL:"))
+ urlLabel.setBuddy(self.urlLineEdit)
+ self.statusLabel = QtGui.QLabel(self.tr("Please enter the URL of a "
+ "file you want to download."))
+
+ self.downloadButton = QtGui.QPushButton(self.tr("Download"))
+ self.downloadButton.setDefault(True)
+ self.quitButton = QtGui.QPushButton(self.tr("Quit"))
+ self.quitButton.setAutoDefault(False)
+
+ buttonBox = QtGui.QDialogButtonBox()
+ buttonBox.addButton(self.downloadButton,
+ QtGui.QDialogButtonBox.ActionRole)
+ buttonBox.addButton(self.quitButton, QtGui.QDialogButtonBox.RejectRole)
+
+ self.progressDialog = QtGui.QProgressDialog(self)
+
+ self.http = QtNetwork.QHttp(self)
+
+ self.urlLineEdit.textChanged.connect(self.enableDownloadButton)
+ self.http.requestFinished.connect(self.httpRequestFinished)
+ self.http.dataReadProgress.connect(self.updateDataReadProgress)
+ self.http.responseHeaderReceived.connect(self.readResponseHeader)
+ self.http.authenticationRequired.connect(self.slotAuthenticationRequired)
+ self.http.sslErrors.connect(self.sslErrors)
+ self.progressDialog.canceled.connect(self.cancelDownload)
+ self.downloadButton.clicked.connect(self.downloadFile)
+ self.quitButton.clicked.connect(self.close)
+
+ topLayout = QtGui.QHBoxLayout()
+ topLayout.addWidget(urlLabel)
+ topLayout.addWidget(self.urlLineEdit)
+
+ mainLayout = QtGui.QVBoxLayout()
+ mainLayout.addLayout(topLayout)
+ mainLayout.addWidget(self.statusLabel)
+ mainLayout.addWidget(buttonBox)
+ self.setLayout(mainLayout)
+
+ self.setWindowTitle(self.tr("HTTP"))
+ self.urlLineEdit.setFocus()
+
+ def downloadFile(self):
+ url = QtCore.QUrl(self.urlLineEdit.text())
+ fileInfo = QtCore.QFileInfo(url.path())
+ fileName = QtCore.QString(fileInfo.fileName())
+
+ if fileName.isEmpty():
+ fileName = "index.html"
+
+ if QtCore.QFile.exists(fileName):
+ ret = QtGui.QMessageBox.question(self, self.tr("HTTP"),
+ self.tr("There already exists a file called %1 in the "
+ "current directory.").arg(fileName),
+ QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel,
+ QtGui.QMessageBox.Cancel)
+
+ if ret == QtGui.QMessageBox.Cancel:
+ return
+
+ QtCore.QFile.remove(fileName)
+
+ self.outFile = QtCore.QFile(fileName)
+ if not self.outFile.open(QtCore.QIODevice.WriteOnly):
+ QtGui.QMessageBox.information(self, self.tr("HTTP"),
+ self.tr("Unable to save the file %1: %2.").arg(fileName).arg(self.outFile.errorString()))
+ self.outFile = None
+ return
+
+ if url.scheme().toLower() == 'https':
+ mode = QtNetwork.QHttp.ConnectionModeHttps
+ else:
+ mode = QtNetwork.QHttp.ConnectionModeHttp
+
+ port = url.port()
+
+ if port == -1:
+ port = 0
+
+ self.http.setHost(url.host(), mode, port)
+
+ if not url.userName().isEmpty():
+ self.http.setUser(url.userName(), url.password())
+
+ self.httpRequestAborted = False
+ path = QtCore.QUrl.toPercentEncoding(url.path(), "!$&'()*+,;=:@/")
+ if path.isEmpty():
+ path = "/"
+ self.httpGetId = self.http.get(path, self.outFile)
+
+ self.progressDialog.setWindowTitle(self.tr("HTTP"))
+ self.progressDialog.setLabelText(self.tr("Downloading %1.").arg(fileName))
+ self.downloadButton.setEnabled(False)
+
+ def cancelDownload(self):
+ self.statusLabel.setText(self.tr("Download canceled."))
+ self.httpRequestAborted = True
+ self.http.abort()
+ self.downloadButton.setEnabled(True)
+
+ def httpRequestFinished(self, requestId, error):
+ if requestId != self.httpGetId:
+ return
+
+ if self.httpRequestAborted:
+ if self.outFile is not None:
+ self.outFile.close()
+ self.outFile.remove()
+ self.outFile = None
+
+ self.progressDialog.hide()
+ return
+
+ self.progressDialog.hide()
+ self.outFile.close()
+
+ if error:
+ self.outFile.remove()
+ QtGui.QMessageBox.information(self, self.tr("HTTP"),
+ self.tr("Download failed: %1.").arg(self.http.errorString()))
+ else:
+ fileName = QtCore.QFileInfo(QtCore.QUrl(self.urlLineEdit.text()).path()).fileName()
+ self.statusLabel.setText(self.tr("Downloaded %1 to current directory.").arg(fileName))
+
+ self.downloadButton.setEnabled(True)
+ self.outFile = None
+
+ def readResponseHeader(self, responseHeader):
+ # Check for genuine error conditions.
+ if responseHeader.statusCode() not in (200, 300, 301, 302, 303, 307):
+ QtGui.QMessageBox.information(self, self.tr("HTTP"),
+ self.tr("Download failed: %1.")
+ .arg(responseHeader.reasonPhrase()))
+ self.httpRequestAborted = True
+ self.progressDialog.hide()
+ self.http.abort()
+
+ def updateDataReadProgress(self, bytesRead, totalBytes):
+ if self.httpRequestAborted:
+ return
+
+ self.progressDialog.setMaximum(totalBytes)
+ self.progressDialog.setValue(bytesRead)
+
+ def enableDownloadButton(self):
+ self.downloadButton.setEnabled(not self.urlLineEdit.text().isEmpty())
+
+ def slotAuthenticationRequired(self, hostName, _, authenticator):
+ import os
+ from PyQt4 import uic
+
+ ui = os.path.join(os.path.dirname(__file__), 'authenticationdialog.ui')
+ dlg = uic.loadUi(ui)
+ dlg.adjustSize()
+ dlg.siteDescription.setText(self.tr("%1 at %2").arg(authenticator.realm()).arg(hostName))
+
+ if dlg.exec_() == QtGui.QDialog.Accepted:
+ authenticator.setUser(dlg.userEdit.text())
+ authenticator.setPassword(dlg.passwordEdit.text())
+
+ def sslErrors(self, errors):
+ errorString = ", ".join([str(error.errorString()) for error in errors])
+
+ ret = QtGui.QMessageBox.warning(self, self.tr("HTTP Example"),
+ self.tr("One or more SSL errors has occurred: %1").arg(errorString),
+ QtGui.QMessageBox.Ignore | QtGui.QMessageBox.Abort)
+
+ if ret == QtGui.QMessageBox.Ignore:
+ self.http.ignoreSslErrors()
+
+
+if __name__ == '__main__':
+
+ import sys
+
+ app = QtGui.QApplication(sys.argv)
+ httpWin = HttpWindow()
+ httpWin.show()
+ sys.exit(httpWin.exec_())
diff --git a/examples/network/loopback.py b/examples/network/loopback.py
new file mode 100755
index 0000000..8b6f8e1
--- /dev/null
+++ b/examples/network/loopback.py
@@ -0,0 +1,154 @@
+#!/usr/bin/env python
+
+############################################################################
+#
+# Copyright (C) 2004-2005 Trolltech AS. All rights reserved.
+#
+# This file is part of the example classes of the Qt Toolkit.
+#
+# This file may be used under the terms of the GNU General Public
+# License version 2.0 as published by the Free Software Foundation
+# and appearing in the file LICENSE.GPL included in the packaging of
+# self file. Please review the following information to ensure GNU
+# General Public Licensing requirements will be met:
+# http://www.trolltech.com/products/qt/opensource.html
+#
+# If you are unsure which license is appropriate for your use, please
+# review the following information:
+# http://www.trolltech.com/products/qt/licensing.html or contact the
+# sales department at sales@trolltech.com.
+#
+# This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+# WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+#
+############################################################################
+
+from PyQt4 import QtCore, QtGui, QtNetwork
+
+
+class Dialog(QtGui.QDialog):
+ TotalBytes = 50 * 1024 * 1024
+ PayloadSize = 65536
+
+ def __init__(self, parent=None):
+ super(Dialog, self).__init__(parent)
+
+ self.tcpServer = QtNetwork.QTcpServer()
+ self.tcpClient = QtNetwork.QTcpSocket()
+ self.bytesToWrite = 0
+ self.bytesWritten = 0
+ self.bytesReceived = 0
+
+ self.clientProgressBar = QtGui.QProgressBar()
+ self.clientStatusLabel = QtGui.QLabel(self.tr("Client ready"))
+ self.serverProgressBar = QtGui.QProgressBar()
+ self.serverStatusLabel = QtGui.QLabel(self.tr("Server ready"))
+
+ self.startButton = QtGui.QPushButton(self.tr("&Start"))
+ self.quitButton = QtGui.QPushButton(self.tr("&Quit"))
+
+ buttonBox = QtGui.QDialogButtonBox()
+ buttonBox.addButton(self.startButton, QtGui.QDialogButtonBox.ActionRole)
+ buttonBox.addButton(self.quitButton, QtGui.QDialogButtonBox.RejectRole)
+
+ self.startButton.clicked.connect(self.start)
+ self.quitButton.clicked.connect(self.close)
+ self.tcpServer.newConnection.connect(self.acceptConnection)
+ self.tcpClient.connected.connect(self.startTransfer)
+ self.tcpClient.bytesWritten.connect(self.updateClientProgress)
+ self.tcpClient.error.connect(self.displayError)
+
+ mainLayout = QtGui.QVBoxLayout()
+ mainLayout.addWidget(self.clientProgressBar)
+ mainLayout.addWidget(self.clientStatusLabel)
+ mainLayout.addWidget(self.serverProgressBar)
+ mainLayout.addWidget(self.serverStatusLabel)
+ mainLayout.addStretch(1)
+ mainLayout.addSpacing(10)
+ mainLayout.addWidget(buttonBox)
+ self.setLayout(mainLayout)
+
+ self.setWindowTitle(self.tr("Loopback"))
+
+ def start(self):
+ self.startButton.setEnabled(False)
+
+ QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)
+
+ self.bytesWritten = 0
+ self.bytesReceived = 0
+
+ while not self.tcpServer.isListening() and not self.tcpServer.listen():
+ ret = QtGui.QMessageBox.critical(self, self.tr("Loopback"),
+ self.tr("Unable to start the test: %1.").arg(self.tcpServer.errorString()),
+ QtGui.QMessageBox.Retry | QtGui.QMessageBox.Cancel)
+ if ret == QtGui.QMessageBox.Cancel:
+ return
+
+ self.serverStatusLabel.setText(self.tr("Listening"))
+ self.clientStatusLabel.setText(self.tr("Connecting"))
+
+ self.tcpClient.connectToHost(QtNetwork.QHostAddress(QtNetwork.QHostAddress.LocalHost), self.tcpServer.serverPort())
+
+ def acceptConnection(self):
+ self.tcpServerConnection = self.tcpServer.nextPendingConnection()
+ self.tcpServerConnection.readyRead.connect(self.updateServerProgress)
+ self.tcpServerConnection.error.connect(self.displayError)
+
+ self.serverStatusLabel.setText(self.tr("Accepted connection"))
+ self.tcpServer.close()
+
+ def startTransfer(self):
+ self.bytesToWrite = Dialog.TotalBytes - self.tcpClient.write(QtCore.QByteArray(Dialog.PayloadSize, '@'))
+ self.clientStatusLabel.setText(self.tr("Connected"))
+
+ def updateServerProgress(self):
+ self.bytesReceived += self.tcpServerConnection.bytesAvailable()
+ self.tcpServerConnection.readAll()
+
+ self.serverProgressBar.setMaximum(Dialog.TotalBytes)
+ self.serverProgressBar.setValue(self.bytesReceived)
+ self.serverStatusLabel.setText(self.tr("Received %1MB")
+ .arg(self.bytesReceived / (1024 * 1024)))
+
+ if self.bytesReceived == Dialog.TotalBytes:
+ self.tcpServerConnection.close()
+ self.startButton.setEnabled(True)
+ QtGui.QApplication.restoreOverrideCursor()
+
+ def updateClientProgress(self, numBytes):
+ self.bytesWritten += numBytes
+ if self.bytesToWrite > 0:
+ self.bytesToWrite -= self.tcpClient.write(QtCore.QByteArray(
+ min(self.bytesToWrite, Dialog.PayloadSize), '@'))
+
+ self.clientProgressBar.setMaximum(Dialog.TotalBytes)
+ self.clientProgressBar.setValue(self.bytesWritten)
+ self.clientStatusLabel.setText(self.tr("Sent %1MB")
+ .arg(self.bytesWritten / (1024 * 1024)))
+
+ def displayError(self, socketError):
+ if socketError == QtNetwork.QTcpSocket.RemoteHostClosedError:
+ return
+
+ QtGui.QMessageBox.information(self, self.tr("Network error"),
+ self.tr("The following error occured: %1.").arg(self.tcpClient.errorString()))
+
+ self.tcpClient.close()
+ self.tcpServer.close()
+ self.clientProgressBar.reset()
+ self.serverProgressBar.reset()
+ self.clientStatusLabel.setText(self.tr("Client ready"))
+ self.serverStatusLabel.setText(self.tr("Server ready"))
+ self.startButton.setEnabled(True)
+ QtGui.QApplication.restoreOverrideCursor()
+
+
+if __name__ == '__main__':
+
+ import sys
+
+ app = QtGui.QApplication(sys.argv)
+ dialog = Dialog()
+ dialog.show()
+ sys.exit(dialog.exec_())
diff --git a/examples/network/threadedfortuneserver.py b/examples/network/threadedfortuneserver.py
new file mode 100755
index 0000000..b7dfe8c
--- /dev/null
+++ b/examples/network/threadedfortuneserver.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+
+############################################################################
+#
+# Copyright (C) 2004-2005 Trolltech AS. All rights reserved.
+#
+# This file is part of the example classes of the Qt Toolkit.
+#
+# This file may be used under the terms of the GNU General Public
+# License version 2.0 as published by the Free Software Foundation
+# and appearing in the file LICENSE.GPL included in the packaging of
+# self file. Please review the following information to ensure GNU
+# General Public Licensing requirements will be met:
+# http://www.trolltech.com/products/qt/opensource.html
+#
+# If you are unsure which license is appropriate for your use, please
+# review the following information:
+# http://www.trolltech.com/products/qt/licensing.html or contact the
+# sales department at sales@trolltech.com.
+#
+# This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+# WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+#
+############################################################################
+
+import random
+
+from PyQt4 import QtCore, QtGui, QtNetwork
+
+
+class FortuneThread(QtCore.QThread):
+ error = QtCore.pyqtSignal(QtNetwork.QTcpSocket.SocketError)
+
+ def __init__(self, socketDescriptor, fortune, parent):
+ super(FortuneThread, self).__init__(parent)
+
+ self.socketDescriptor = socketDescriptor
+ self.text = fortune
+
+ def run(self):
+ tcpSocket = QtNetwork.QTcpSocket()
+ if not tcpSocket.setSocketDescriptor(self.socketDescriptor):
+ self.error.emit(tcpSocket.error())
+ return
+
+ block = QtCore.QByteArray()
+ outstr = QtCore.QDataStream(block, QtCore.QIODevice.WriteOnly)
+ outstr.setVersion(QtCore.QDataStream.Qt_4_0)
+ outstr.writeUInt16(0)
+ outstr << self.text
+ outstr.device().seek(0)
+ outstr.writeUInt16(block.count() - 2)
+
+ tcpSocket.write(block)
+ tcpSocket.disconnectFromHost()
+ tcpSocket.waitForDisconnected()
+
+
+class FortuneServer(QtNetwork.QTcpServer):
+ def __init__(self, parent=None):
+ super(FortuneServer, self).__init__(parent)
+
+ self.fortunes = [
+ self.tr("You've been leading a dog's life. Stay off the furniture."),
+ self.tr("You've got to think about tomorrow."),
+ self.tr("You will be surprised by a loud noise."),
+ self.tr("You will feel hungry again in another hour."),
+ self.tr("You might have mail."),
+ self.tr("You cannot kill time without injuring eternity."),
+ self.tr("Computers are not intelligent. They only think they are.")]
+
+ def incomingConnection(self, socketDescriptor):
+ fortune = self.fortunes[random.randint(0, len(self.fortunes) - 1)]
+ thread = FortuneThread(socketDescriptor, fortune, self)
+ thread.finished.connect(thread.deleteLater)
+ thread.start()
+
+
+class Dialog(QtGui.QDialog):
+ def __init__(self, parent=None):
+ super(Dialog, self).__init__(parent)
+
+ self.server = FortuneServer()
+
+ statusLabel = QtGui.QLabel()
+ quitButton = QtGui.QPushButton(self.tr("Quit"))
+ quitButton.setAutoDefault(False)
+
+ if not self.server.listen():
+ QtGui.QMessageBox.critical(self,
+ self.tr("Threaded Fortune Server"),
+ self.tr("Unable to start the server: %1.".arg(self.server.errorString())))
+ self.close()
+ return
+
+ statusLabel.setText(self.tr("The server is running on port %1.\n"
+ "Run the Fortune Client example now.").arg(self.server.serverPort()))
+
+ quitButton.clicked.connect(self.close)
+
+ buttonLayout = QtGui.QHBoxLayout()
+ buttonLayout.addStretch(1)
+ buttonLayout.addWidget(quitButton)
+ buttonLayout.addStretch(1)
+
+ mainLayout = QtGui.QVBoxLayout()
+ mainLayout.addWidget(statusLabel)
+ mainLayout.addLayout(buttonLayout)
+ self.setLayout(mainLayout)
+
+ self.setWindowTitle(self.tr("Threaded Fortune Server"))
+
+
+if __name__ == '__main__':
+
+ import sys
+
+ app = QtGui.QApplication(sys.argv)
+ dialog = Dialog()
+ dialog.show()
+ sys.exit(dialog.exec_())