class Writer(QObject): def __init__(self, filename): QObject.__init__(self, None) self._filename = filename self._file = None self._dstream = None def __enter__(self): self.open() return self def __exit__(self, exc_type, exc_value, traceback): self.close def open(self): self._file = QFile(self._filename) if not self._file.open(QIODevice.WriteOnly): raise ValueError("Cannot open " + self._filename) self._dstream = QDataStream(self._file) self._dstream.setVersion(QDataStream.Qt_4_5) for c in b"QGis.MemoryLayerData": self._dstream.writeUInt8(c) # Version of MLD format self._dstream.writeUInt32(2) def close(self): try: self._dstream.setDevice(None) self._file.close() except: # noqa: E722 pass self._dstream = None self._file = None def writeLayers(self, layers): for layer in layers: self.writeLayer(layer) def writeLayer(self, layer): if not self._dstream: raise ValueError("Layer stream not open for reading") ds = self._dstream dp = layer.dataProvider() ss = layer.subsetString() attr = dp.attributeIndexes() ds.writeQString(layer.id()) ds.writeQString(ss) ds.writeInt16(len(attr)) flds = dp.fields() # noqa: F841 fldnames = [] for i in attr: fld = dp.fields()[i] fldnames.append(fld.name()) ds.writeQString(fld.name()) ds.writeInt16(int(fld.type())) ds.writeQString(fld.typeName()) ds.writeInt16(fld.length()) ds.writeInt16(fld.precision()) ds.writeQString(fld.comment()) layer.setSubsetString("") feats = layer.getFeatures() for feat in feats: ds.writeBool(True) if attr: for field in fldnames: try: ds.writeQVariant(feat[field]) except KeyError: ds.writeQVariant(None) geom = feat.geometry() if not geom: ds.writeUInt32(0) else: wkb = geom.asWkb() ds.writeUInt32(len(wkb)) ds.writeRawData(wkb) ds.writeBool(False) layer.setSubsetString(ss)
class Reader(QObject): def __init__(self, filename): self._filename = filename self._file = None self._dstream = None self._version = None def __enter__(self): self.open() return self def __exit__(self, exc_type, exc_value, traceback): self.close def open(self): self._file = QFile(self._filename) if not self._file.open(QIODevice.ReadOnly): raise ValueError("Cannot open " + self._filename) self._dstream = QDataStream(self._file) self._dstream.setVersion(QDataStream.Qt_4_5) for c in b"QGis.MemoryLayerData": ct = self._dstream.readUInt8() if ct != c: raise ValueError(self._filename + " is not a valid memory layer data file") version = self._dstream.readInt32() if version not in (1, 2): raise ValueError( self._filename + " is not compatible with this version of the MemoryLayerSaver plugin" ) self._version = version def close(self): try: self._dstream.setDevice(None) self._file.close() except: # noqa: E722 pass self._dstream = None self._file = None def readLayers(self, layers): if not self._dstream: raise ValueError("Layer stream not open for reading") ds = self._dstream while True: if ds.atEnd(): return id = ds.readQString() layer = None for l in layers: # noqa: E741 if l.id() == id: layer = l break if layer is None: self.skipLayer() else: self.readLayer(layer) def readLayer(self, layer): ds = self._dstream dp = layer.dataProvider() if dp.featureCount() > 0: raise ValueError("Memory layer " + id + " is already loaded") attr = dp.attributeIndexes() dp.deleteAttributes(attr) ss = "" if self._version > 1: ss = ds.readQString() nattr = ds.readInt16() attr = list(range(nattr)) for i in attr: name = ds.readQString() qtype = ds.readInt16() typename = ds.readQString() length = ds.readInt16() precision = ds.readInt16() comment = ds.readQString() fld = QgsField(name, qtype, typename, length, precision, comment) dp.addAttributes([fld]) nullgeom = QgsGeometry() fields = dp.fields() while ds.readBool(): feat = QgsFeature(fields) for i in attr: value = ds.readQVariant() if value is not None: feat[i] = value wkbSize = ds.readUInt32() if wkbSize == 0: feat.setGeometry(nullgeom) else: geom = QgsGeometry() geom.fromWkb(ds.readRawData(wkbSize)) feat.setGeometry(geom) dp.addFeatures([feat]) layer.setSubsetString(ss) layer.updateFields() layer.updateExtents() def skipLayer(self): ds = self._dstream nattr = ds.readInt16() attr = list(range(nattr)) for i in attr: name = ds.readQString() # noqa: F841 qtype = ds.readInt16() # noqa: F841 typename = ds.readQString() # noqa: F841 length = ds.readInt16() # noqa: F841 precision = ds.readInt16() # noqa: F841 comment = ds.readQString() # noqa: F841 while ds.readBool(): for i in attr: ds.readQVariant() wkbSize = ds.readUInt32() if wkbSize > 0: ds.readRawData(wkbSize)
class Client(QDialog): def __init__(self, parent: QWidget = None): super().__init__(parent) self._in = QDataStream() self.blockSize = 0 self.currentFortune = "" self.hostLineEdit = QLineEdit("fortune") self.getFortuneButton = QPushButton(self.tr("Get Fortune")) self.statusLabel = QLabel( self. tr("This examples requires that you run the Local Fortune Server example as well." )) self.socket = QLocalSocket(self) self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) hostLabel = QLabel(self.tr("&Server name:")) hostLabel.setBuddy(self.hostLineEdit) self.statusLabel.setWordWrap(True) self.getFortuneButton.setDefault(True) quitButton = QPushButton(self.tr("Quit")) buttonBox = QDialogButtonBox() buttonBox.addButton(self.getFortuneButton, QDialogButtonBox.ActionRole) buttonBox.addButton(quitButton, QDialogButtonBox.RejectRole) self._in.setDevice(self.socket) self._in.setVersion(QDataStream.Qt_5_10) self.hostLineEdit.textChanged.connect(self.enableGetFortuneButton) self.getFortuneButton.clicked.connect(self.requestNewFortune) quitButton.clicked.connect(self.close) self.socket.readyRead.connect(self.readFortune) self.socket.errorOccurred.connect(self.displayError) mainLayout = QGridLayout(self) mainLayout.addWidget(hostLabel, 0, 0) mainLayout.addWidget(self.hostLineEdit, 0, 1) mainLayout.addWidget(self.statusLabel, 2, 0, 1, 2) mainLayout.addWidget(buttonBox, 3, 0, 1, 2) self.setWindowTitle(QGuiApplication.applicationDisplayName()) self.hostLineEdit.setFocus() @pyqtSlot() def requestNewFortune(self): self.getFortuneButton.setEnabled(False) self.blockSize = 0 self.socket.abort() self.socket.connectToServer(self.hostLineEdit.text()) @pyqtSlot() def readFortune(self): if self.blockSize == 0: # Relies on the fact that QDataStream serializes a quint32 into # sizeof(quint32) bytes if self.socket.bytesAvailable() < 4: # (int)sizeof(quint32)) return self.blockSize = self._in.readUInt32() if self.socket.bytesAvailable() < self.blockSize or self._in.atEnd(): return nextFortune = "" nextFortune = self._in.readQString() if nextFortune == self.currentFortune: QTimer.singleShot(0, self.requestNewFortune) return currentFortune = nextFortune self.statusLabel.setText(currentFortune) self.getFortuneButton.setEnabled(True) @pyqtSlot(QLocalSocket.LocalSocketError) def displayError(self, socketError): if socketError == QLocalSocket.ServerNotFoundError: QMessageBox.information( self, self.tr("Local Fortune Client"), self.tr("The host was not found. Please make sure " "that the server is running and that the " "server name is correct."), ) elif socketError == QLocalSocket.ConnectionRefusedError: QMessageBox.information( self, self.tr("Local Fortune Client"), self.tr("The connection was refused by the peer. " "Make sure the fortune server is running, " "and check that the server name is correct."), ) elif socketError == QLocalSocket.PeerClosedError: return else: QMessageBox.information( self, self.tr("Local Fortune Client"), self.tr("The following error occurred: %s." % (self.socket.errorString())), ) self.getFortuneButton.setEnabled(True) @pyqtSlot() def enableGetFortuneButton(self): self.getFortuneButton.setEnabled(bool(self.hostLineEdit.ext()))