1#!/usr/bin/env python
2
3
4#############################################################################
5##
6## Copyright (C) 2013 Riverbank Computing Limited.
7## Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
8## All rights reserved.
9##
10## This file is part of the examples of PyQt.
11##
12## $QT_BEGIN_LICENSE:BSD$
13## You may use this file under the terms of the BSD license as follows:
14##
15## "Redistribution and use in source and binary forms, with or without
16## modification, are permitted provided that the following conditions are
17## met:
18##   * Redistributions of source code must retain the above copyright
19##     notice, this list of conditions and the following disclaimer.
20##   * Redistributions in binary form must reproduce the above copyright
21##     notice, this list of conditions and the following disclaimer in
22##     the documentation and/or other materials provided with the
23##     distribution.
24##   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
25##     the names of its contributors may be used to endorse or promote
26##     products derived from this software without specific prior written
27##     permission.
28##
29## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
40## $QT_END_LICENSE$
41##
42#############################################################################
43
44
45from PyQt5.QtCore import QDataStream, QSettings, QTimer
46from PyQt5.QtGui import QIntValidator
47from PyQt5.QtWidgets import (QApplication, QComboBox, QDialog,
48        QDialogButtonBox, QGridLayout, QLabel, QLineEdit, QMessageBox,
49        QPushButton)
50from PyQt5.QtNetwork import (QAbstractSocket, QHostInfo, QNetworkConfiguration,
51        QNetworkConfigurationManager, QNetworkInterface, QNetworkSession,
52        QTcpSocket)
53
54
55class Client(QDialog):
56    def __init__(self, parent=None):
57        super(Client, self).__init__(parent)
58
59        self.networkSession = None
60        self.blockSize = 0
61        self.currentFortune = ''
62
63        hostLabel = QLabel("&Server name:")
64        portLabel = QLabel("S&erver port:")
65
66        self.hostCombo = QComboBox()
67        self.hostCombo.setEditable(True)
68
69        name = QHostInfo.localHostName()
70        if name != '':
71            self.hostCombo.addItem(name)
72
73            domain = QHostInfo.localDomainName()
74            if domain != '':
75                self.hostCombo.addItem(name + '.' + domain)
76
77        if name != 'localhost':
78            self.hostCombo.addItem('localhost')
79
80        ipAddressesList = QNetworkInterface.allAddresses()
81
82        for ipAddress in ipAddressesList:
83            if not ipAddress.isLoopback():
84                self.hostCombo.addItem(ipAddress.toString())
85
86        for ipAddress in ipAddressesList:
87            if ipAddress.isLoopback():
88                self.hostCombo.addItem(ipAddress.toString())
89
90        self.portLineEdit = QLineEdit()
91        self.portLineEdit.setValidator(QIntValidator(1, 65535, self))
92
93        hostLabel.setBuddy(self.hostCombo)
94        portLabel.setBuddy(self.portLineEdit)
95
96        self.statusLabel = QLabel("This examples requires that you run "
97                "the Fortune Server example as well.")
98
99        self.getFortuneButton = QPushButton("Get Fortune")
100        self.getFortuneButton.setDefault(True)
101        self.getFortuneButton.setEnabled(False)
102
103        quitButton = QPushButton("Quit")
104
105        buttonBox = QDialogButtonBox()
106        buttonBox.addButton(self.getFortuneButton, QDialogButtonBox.ActionRole)
107        buttonBox.addButton(quitButton, QDialogButtonBox.RejectRole)
108
109        self.tcpSocket = QTcpSocket(self)
110
111        self.hostCombo.editTextChanged.connect(self.enableGetFortuneButton)
112        self.portLineEdit.textChanged.connect(self.enableGetFortuneButton)
113        self.getFortuneButton.clicked.connect(self.requestNewFortune)
114        quitButton.clicked.connect(self.close)
115        self.tcpSocket.readyRead.connect(self.readFortune)
116        self.tcpSocket.error.connect(self.displayError)
117
118        mainLayout = QGridLayout()
119        mainLayout.addWidget(hostLabel, 0, 0)
120        mainLayout.addWidget(self.hostCombo, 0, 1)
121        mainLayout.addWidget(portLabel, 1, 0)
122        mainLayout.addWidget(self.portLineEdit, 1, 1)
123        mainLayout.addWidget(self.statusLabel, 2, 0, 1, 2)
124        mainLayout.addWidget(buttonBox, 3, 0, 1, 2)
125        self.setLayout(mainLayout)
126
127        self.setWindowTitle("Fortune Client")
128        self.portLineEdit.setFocus()
129
130        manager = QNetworkConfigurationManager()
131        if manager.capabilities() & QNetworkConfigurationManager.NetworkSessionRequired:
132            settings = QSettings(QSettings.UserScope, 'QtProject')
133            settings.beginGroup('QtNetwork')
134            id = settings.value('DefaultNetworkConfiguration')
135            settings.endGroup()
136
137            config = manager.configurationFromIdentifier(id)
138            if config.state() & QNetworkConfiguration.Discovered == 0:
139                config = manager.defaultConfiguration()
140
141            self.networkSession = QNetworkSession(config, self)
142            self.networkSession.opened.connect(self.sessionOpened)
143
144            self.getFortuneButton.setEnabled(False)
145            self.statusLabel.setText("Opening network session.")
146            self.networkSession.open()
147
148    def requestNewFortune(self):
149        self.getFortuneButton.setEnabled(False)
150        self.blockSize = 0
151        self.tcpSocket.abort()
152        self.tcpSocket.connectToHost(self.hostCombo.currentText(),
153                int(self.portLineEdit.text()))
154
155    def readFortune(self):
156        instr = QDataStream(self.tcpSocket)
157        instr.setVersion(QDataStream.Qt_4_0)
158
159        if self.blockSize == 0:
160            if self.tcpSocket.bytesAvailable() < 2:
161                return
162
163            self.blockSize = instr.readUInt16()
164
165        if self.tcpSocket.bytesAvailable() < self.blockSize:
166            return
167
168        nextFortune = instr.readQString()
169        if nextFortune == self.currentFortune:
170            QTimer.singleShot(0, self.requestNewFortune)
171            return
172
173        self.currentFortune = nextFortune
174        self.statusLabel.setText(self.currentFortune)
175        self.getFortuneButton.setEnabled(True)
176
177    def displayError(self, socketError):
178        if socketError == QAbstractSocket.RemoteHostClosedError:
179            pass
180        elif socketError == QAbstractSocket.HostNotFoundError:
181            QMessageBox.information(self, "Fortune Client",
182                    "The host was not found. Please check the host name and "
183                    "port settings.")
184        elif socketError == QAbstractSocket.ConnectionRefusedError:
185            QMessageBox.information(self, "Fortune Client",
186                    "The connection was refused by the peer. Make sure the "
187                    "fortune server is running, and check that the host name "
188                    "and port settings are correct.")
189        else:
190            QMessageBox.information(self, "Fortune Client",
191                    "The following error occurred: %s." % self.tcpSocket.errorString())
192
193        self.getFortuneButton.setEnabled(True)
194
195    def enableGetFortuneButton(self):
196        self.getFortuneButton.setEnabled(
197                (self.networkSession is None or self.networkSession.isOpen())
198                and self.hostCombo.currentText() != ''
199                and self.portLineEdit.text() != '')
200
201    def sessionOpened(self):
202        config = self.networkSession.configuration()
203
204        if config.type() == QNetworkConfiguration.UserChoice:
205            id = self.networkSession.sessionProperty('UserChoiceConfiguration')
206        else:
207            id = config.identifier()
208
209        settings = QSettings(QSettings.UserScope, 'QtProject')
210        settings.beginGroup('QtNetwork')
211        settings.setValue('DefaultNetworkConfiguration', id)
212        settings.endGroup()
213
214        self.statusLabel.setText("This examples requires that you run the "
215                            "Fortune Server example as well.")
216
217        self.enableGetFortuneButton()
218
219
220if __name__ == '__main__':
221
222    import sys
223
224    app = QApplication(sys.argv)
225    client = Client()
226    client.show()
227    sys.exit(client.exec_())
228