def __init__(self, parent=None): super(Camera, self).__init__(parent) self.ui = Ui_Camera() self.pre_id = 0 self.cur_id = 0 self.count = 0 self.checked = 0 self.audio_settime = 0 self.allow_flag = 1 self.check_list = [] self.camera = None self.imageCapture = None self.isCapturingImage = False self.applicationExiting = False self.ui.setupUi(self) cameraDevice = QByteArray() videoDevicesGroup = QActionGroup(self) videoDevicesGroup.setExclusive(True) for deviceName in QCamera.availableDevices(): description = QCamera.deviceDescription(deviceName) videoDeviceAction = QAction(description, videoDevicesGroup) videoDeviceAction.setCheckable(True) videoDeviceAction.setData(deviceName) if cameraDevice.isEmpty(): cameraDevice = deviceName videoDeviceAction.setChecked(True) self.ui.menuDevices.addAction(videoDeviceAction) videoDevicesGroup.triggered.connect(self.updateCameraDevice) self.setCamera(cameraDevice) # Create and load model path_pretrained = "apis/models/facenet/20180402-114759.pb" path_SVM = "apis/models/SVM/SVM.pkl" self.recognizer = Recognizer() self.recognizer.create_graph(path_pretrained, path_SVM)
def __init__(self, parent=None, standalone=False): super(Camera, self).__init__(parent) # This prevents doing unneeded initialization # when QtDesginer loads the plugin. if parent is None and not standalone: return if not multimedia_available: return self.ui = uic.loadUi(os.path.join(WIDGET_PATH, "camera.ui"), self) self.camera = None self.imageCapture = None self.mediaRecorder = None self.isCapturingImage = False self.applicationExiting = False self.imageSettings = QImageEncoderSettings() self.audioSettings = QAudioEncoderSettings() self.videoSettings = QVideoEncoderSettings() self.videoContainerFormat = '' camera_device = QByteArray() videoDevicesGroup = QActionGroup(self) videoDevicesGroup.setExclusive(True) if not QCamera.availableDevices(): self.ui.devicesCombo.addItem("No Device") else: for deviceName in QCamera.availableDevices(): description = QCamera.deviceDescription(deviceName) self.ui.devicesCombo.addItem(description) videoDeviceAction = QAction(description, videoDevicesGroup) videoDeviceAction.setCheckable(True) videoDeviceAction.setData(deviceName) if camera_device.isEmpty(): cameraDevice = deviceName videoDeviceAction.setChecked(True) self.ui.devicesCombo.addAction(videoDeviceAction) videoDevicesGroup.triggered.connect(self.updateCameraDevice) self.ui.captureWidget.currentChanged.connect(self.updateCaptureMode) self.ui.devicesCombo.currentIndexChanged.connect( self.get_device_action) self.ui.lockButton.hide() # Start camera 2s after the UI has loaded QTimer.singleShot(2000, lambda: self.setCamera(camera_device))
def setup_camera(self): camera_device = QByteArray() for device in QCamera.availableDevices(): if camera_device.isEmpty(): camera_device = device if camera_device.isEmpty(): self.camera = QCamera() else: self.camera = QCamera(camera_device) self.image_capture = QCameraImageCapture(self.camera) self.image_capture.readyForCaptureChanged.connect(self.ready_for_capture) self.image_capture.imageCaptured.connect(self.process_captured_image) self.image_capture.imageSaved.connect(self.image_saved) self.camera.setViewfinder(self.ui.viewFinder) self.camera.start()
def setup_camera(self): camera_device = QByteArray() video_devices_group = QActionGroup(self) video_devices_group.setExclusive(True) for device in QCamera.availableDevices(): description = QCamera.deviceDescription(device) video_device_action = QAction(description, video_devices_group) video_device_action.setCheckable(True) video_device_action.setData(device) if camera_device.isEmpty(): camera_device = device video_device_action.setChecked(True) self.ui.menuDevices.addAction(video_device_action) if camera_device.isEmpty(): self.camera = QCamera() else: self.camera = QCamera(camera_device) self.camera.setViewfinder(self.ui.cameraViewFinder)
def __init__(self, parent=None): super(Camera, self).__init__(parent) global API API = AlgorithmAPIs(template_dir="templates", threshold=0.5, use_multiprocessing=False) self.ui = Ui_Camera() self.camera = None self.imageCapture = None # self.mediaRecorder = None self.isCapturingImage = False self.applicationExiting = False self.imageSettings = QImageEncoderSettings() self.audioSettings = QAudioEncoderSettings() self.ui.setupUi(self) cameraDevice = QByteArray() videoDevicesGroup = QActionGroup(self) videoDevicesGroup.setExclusive(True) for deviceName in QCamera.availableDevices(): description = QCamera.deviceDescription(deviceName) videoDeviceAction = QAction(description, videoDevicesGroup) videoDeviceAction.setCheckable(True) videoDeviceAction.setData(deviceName) if cameraDevice.isEmpty(): cameraDevice = deviceName videoDeviceAction.setChecked(True) self.ui.menuDevices.addAction(videoDeviceAction) videoDevicesGroup.triggered.connect(self.updateCameraDevice) self.ui.lcdNumber_2.display(0) self.ui.dial.valueChanged.connect(self.dial_display) global dial_value dial_value = 3 self.ui.lcdNumber_2.display(dial_value) self.setCamera(cameraDevice) # Create and load model path_pretrained = "apis/models/facenet/20180402-114759.pb" path_SVM = "apis/models/SVM/SVM.pkl" self.recognizer = Recognizer() self.recognizer.create_graph(path_pretrained, path_SVM)
def detectDevices(self): cameraDevice = QByteArray() for name in QCamera.availableDevices(): description = QCamera.deviceDescription(name) deviceAction = QAction(description, self.videoDevicesGroup) deviceAction.setCheckable(True) deviceAction.setData(name) if cameraDevice.isEmpty(): cameraDevice = name deviceAction.setChecked(True) self.menuDevices.addAction(deviceAction) self.videoDevicesGroup.triggered.connect(self.changeCameraDevice) self.setCamera(cameraDevice)
def initUI(self): # ========================= MENÚ =========================== menu = self.menuBar() archivoMenu = menu.addMenu("&Archivo") self.accionIniciarCamara = archivoMenu.addAction( self.style().standardIcon(QStyle.SP_MediaPlay), "Iniciar la camara", self.iniciarCamara) self.accionDetenerCamara = archivoMenu.addAction( self.style().standardIcon(QStyle.SP_MediaStop), "Detener la camara", self.detenerCamara) archivoMenu.addAction( self.style().standardIcon(QStyle.SP_MessageBoxCritical), " Salir", self.close) dispositivosMenu = menu.addMenu("&Dispositivos") videoDevicesGroup = QActionGroup(self) videoDevicesGroup.setExclusive(True) dispositivoCamara = QByteArray() for nombreDispositivo in QCamera.availableDevices(): descripcion = QCamera.deviceDescription(nombreDispositivo) videoDeviceAction = QAction(descripcion, videoDevicesGroup) videoDeviceAction.setCheckable(True) videoDeviceAction.setData(nombreDispositivo) if dispositivoCamara.isEmpty(): dispositivoCamara = nombreDispositivo videoDeviceAction.setChecked(True) dispositivosMenu.addAction(videoDeviceAction) # Instancia del Widget central self.widgets = Widgets(dispositivoCamara, self) # Llamar función cuando se activa una Acción del Menú videoDevicesGroup.triggered.connect( self.widgets.actualizarDispositivoCamara) # Establecer el Widget central de la ventana self.setCentralWidget(self.widgets)
def __init__(self, arg): super(Camera, self).__init__(parent) # self.arg = arg # Attributes variables self.ui = Ui_Camera() self.camera = None self.imageCapture = None self.mediaRecorder = None self.isCapturingImage = False self.applicationExiting = False self.imageSettings = QImageEncoderSettings() self.audioSettings = QAudioEncoderSettings() self.videoSettings = QVideoEncoderSettings() self.videoContainerFormat = '' self.ui.setupUi(self) #get device camera cameraDevice = QByteArray() videoDevicesGroup = QActionGroup(self) videoDevicesGroup.setExclusive(True) # Get informations about available cameras for deviceName in QCamera.availableDevices(): description = QCamera.deviceDescription(deviceName) videoDeviceAction = QAction(description, videoDevicesGroup) videoDeviceAction.setCheckable(True) videoDeviceAction.setData(deviceName) if cameraDevice.isEmpty(): cameraDevice = deviceName videoDeviceAction.setChecked(True) self.ui.menuDevices.addAction(videoDeviceAction) videoDevicesGroup.triggered.connect(self.updateCameraDevice) self.ui.captureWidget.currentChanged.connect(self.updateCaptureMode) self.ui.lockButton.hide() self.setCamera(cameraDevice)
def __init__(self, parent=None): super(Camera, self).__init__(parent) self.ui = Ui_Camera() self.camera = None self.imageCapture = None self.mediaRecorder = None self.isCapturingImage = False self.applicationExiting = False self.imageSettings = QImageEncoderSettings() self.audioSettings = QAudioEncoderSettings() self.videoSettings = QVideoEncoderSettings() self.videoContainerFormat = '' self.ui.setupUi(self) cameraDevice = QByteArray() videoDevicesGroup = QActionGroup(self) videoDevicesGroup.setExclusive(True) #for multiple cameras ata for deviceName in QCamera.availableDevices(): description = QCamera.deviceDescription(deviceName) videoDeviceAction = QAction(description, videoDevicesGroup) videoDeviceAction.setCheckable(True) videoDeviceAction.setData(deviceName) if cameraDevice.isEmpty(): cameraDevice = deviceName videoDeviceAction.setChecked(True) self.ui.menuDevices.addAction(videoDeviceAction) videoDevicesGroup.triggered.connect(self.updateCameraDevice) self.ui.captureWidget.currentChanged.connect(self.updateCaptureMode) self.ui.lockButton.hide() self.setCamera(cameraDevice)
class MainForm(QDialog): def __init__(self, parent=None): super(MainForm, self).__init__(parent) self.filename = "" self.copiedItem = QByteArray() self.pasteOffset = 5 self.prevPoint = QPoint() self.addOffset = 5 self.borders = [] self.printer = QPrinter(QPrinter.HighResolution) self.printer.setPageSize(QPrinter.Letter) self.view = GraphicsView() self.scene = QGraphicsScene(self) self.scene.setSceneRect(0, 0, PageSize[0], PageSize[1]) self.addBorders() self.view.setScene(self.scene) self.wrapped = [] # Needed to keep wrappers alive buttonLayout = QVBoxLayout() for text, slot in ( ("Add &Text", self.addText), ("Add &Box", self.addBox), ("Add Pi&xmap", self.addPixmap), ("&Align", None), ("&Copy", self.copy), ("C&ut", self.cut), ("&Paste", self.paste), ("&Delete...", self.delete), ("&Rotate", self.rotate), ("Pri&nt...", self.print_), ("&Open...", self.open), ("&Save", self.save), ("&Quit", self.accept)): button = QPushButton(text) if not MAC: button.setFocusPolicy(Qt.NoFocus) if slot is not None: button.clicked.connect(slot) if text == "&Align": menu = QMenu(self) for text, arg in ( ("Align &Left", Qt.AlignLeft), ("Align &Right", Qt.AlignRight), ("Align &Top", Qt.AlignTop), ("Align &Bottom", Qt.AlignBottom)): wrapper = functools.partial(self.setAlignment, arg) self.wrapped.append(wrapper) menu.addAction(text, wrapper) button.setMenu(menu) if text == "Pri&nt...": buttonLayout.addStretch(5) if text == "&Quit": buttonLayout.addStretch(1) buttonLayout.addWidget(button) buttonLayout.addStretch() layout = QHBoxLayout() layout.addWidget(self.view, 1) layout.addLayout(buttonLayout) self.setLayout(layout) fm = QFontMetrics(self.font()) self.resize(self.scene.width() + fm.width(" Delete... ") + 50, self.scene.height() + 50) self.setWindowTitle("Page Designer") def addBorders(self): self.borders = [] rect = QRectF(0, 0, PageSize[0], PageSize[1]) self.borders.append(self.scene.addRect(rect, Qt.yellow)) margin = 5.25 * PointSize self.borders.append(self.scene.addRect( rect.adjusted(margin, margin, -margin, -margin), Qt.yellow)) def removeBorders(self): while self.borders: item = self.borders.pop() self.scene.removeItem(item) del item def reject(self): self.accept() def accept(self): self.offerSave() QDialog.accept(self) def offerSave(self): if (Dirty and QMessageBox.question(self, "Page Designer - Unsaved Changes", "Save unsaved changes?", QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes): self.save() def position(self): point = self.mapFromGlobal(QCursor.pos()) if not self.view.geometry().contains(point): coord = random.randint(36, 144) point = QPoint(coord, coord) else: if point == self.prevPoint: point += QPoint(self.addOffset, self.addOffset) self.addOffset += 5 else: self.addOffset = 5 self.prevPoint = point return self.view.mapToScene(point) def addText(self): dialog = TextItemDlg(position=self.position(), scene=self.scene, parent=self) dialog.exec_() def addBox(self): BoxItem(self.position(), self.scene) def addPixmap(self): path = (QFileInfo(self.filename).path() if self.filename else ".") fname,filetype = QFileDialog.getOpenFileName(self, "Page Designer - Add Pixmap", path, "Pixmap Files (*.bmp *.jpg *.png *.xpm)") if not fname: return self.createPixmapItem(QPixmap(fname), self.position()) def createPixmapItem(self, pixmap, position, matrix=QTransform()): item = GraphicsPixmapItem(pixmap) item.setFlags(QGraphicsItem.ItemIsSelectable| QGraphicsItem.ItemIsMovable) item.setPos(position) item.setTransform(matrix) self.scene.clearSelection() self.scene.addItem(item) item.setSelected(True) global Dirty Dirty = True return item def selectedItem(self): items = self.scene.selectedItems() if len(items) == 1: return items[0] return None def copy(self): item = self.selectedItem() if item is None: return self.copiedItem.clear() self.pasteOffset = 5 stream = QDataStream(self.copiedItem, QIODevice.WriteOnly) self.writeItemToStream(stream, item) def cut(self): item = self.selectedItem() if item is None: return self.copy() self.scene.removeItem(item) del item def paste(self): if self.copiedItem.isEmpty(): return stream = QDataStream(self.copiedItem, QIODevice.ReadOnly) self.readItemFromStream(stream, self.pasteOffset) self.pasteOffset += 5 def setAlignment(self, alignment): # Items are returned in arbitrary order items = self.scene.selectedItems() if len(items) <= 1: return # Gather coordinate data leftXs, rightXs, topYs, bottomYs = [], [], [], [] for item in items: rect = item.sceneBoundingRect() leftXs.append(rect.x()) rightXs.append(rect.x() + rect.width()) topYs.append(rect.y()) bottomYs.append(rect.y() + rect.height()) # Perform alignment if alignment == Qt.AlignLeft: xAlignment = min(leftXs) for i, item in enumerate(items): item.moveBy(xAlignment - leftXs[i], 0) elif alignment == Qt.AlignRight: xAlignment = max(rightXs) for i, item in enumerate(items): item.moveBy(xAlignment - rightXs[i], 0) elif alignment == Qt.AlignTop: yAlignment = min(topYs) for i, item in enumerate(items): item.moveBy(0, yAlignment - topYs[i]) elif alignment == Qt.AlignBottom: yAlignment = max(bottomYs) for i, item in enumerate(items): item.moveBy(0, yAlignment - bottomYs[i]) global Dirty Dirty = True def rotate(self): for item in self.scene.selectedItems(): item.setRotation(item.rotation()+30) def delete(self): items = self.scene.selectedItems() if (len(items) and QMessageBox.question(self, "Page Designer - Delete", "Delete {0} item{1}?".format(len(items), "s" if len(items) != 1 else ""), QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes): while items: item = items.pop() self.scene.removeItem(item) del item global Dirty Dirty = True def print_(self): dialog = QPrintDialog(self.printer) if dialog.exec_(): painter = QPainter(self.printer) painter.setRenderHint(QPainter.Antialiasing) painter.setRenderHint(QPainter.TextAntialiasing) self.scene.clearSelection() self.removeBorders() self.scene.render(painter) self.addBorders() def open(self): self.offerSave() path = (QFileInfo(self.filename).path() if self.filename else ".") fname,filetype = QFileDialog.getOpenFileName(self, "Page Designer - Open", path, "Page Designer Files (*.pgd)") if not fname: return self.filename = fname fh = None try: fh = QFile(self.filename) if not fh.open(QIODevice.ReadOnly): raise IOError(str(fh.errorString())) items = self.scene.items() while items: item = items.pop() self.scene.removeItem(item) del item self.addBorders() stream = QDataStream(fh) stream.setVersion(QDataStream.Qt_5_7) magic = stream.readInt32() if magic != MagicNumber: raise IOError("not a valid .pgd file") fileVersion = stream.readInt16() if fileVersion != FileVersion: raise IOError("unrecognised .pgd file version") while not fh.atEnd(): self.readItemFromStream(stream) except IOError as e: QMessageBox.warning(self, "Page Designer -- Open Error", "Failed to open {0}: {1}".format(self.filename, e)) finally: if fh is not None: fh.close() global Dirty Dirty = False def save(self): if not self.filename: path = "." fname,filetype = QFileDialog.getSaveFileName(self, "Page Designer - Save As", path, "Page Designer Files (*.pgd)") if not fname: return self.filename = fname fh = None try: fh = QFile(self.filename) if not fh.open(QIODevice.WriteOnly): raise IOError(str(fh.errorString())) self.scene.clearSelection() stream = QDataStream(fh) stream.setVersion(QDataStream.Qt_5_7) stream.writeInt32(MagicNumber) stream.writeInt16(FileVersion) for item in self.scene.items(): self.writeItemToStream(stream, item) except IOError as e: QMessageBox.warning(self, "Page Designer -- Save Error", "Failed to save {0}: {1}".format(self.filename, e)) finally: if fh is not None: fh.close() global Dirty Dirty = False def readItemFromStream(self, stream, offset=0): type = "" position = QPointF() matrix = QTransform() rotateangle=0#add by yangrongdong type=stream.readQString() stream >> position >> matrix if offset: position += QPointF(offset, offset) if type == "Text": text = "" font = QFont() text=stream.readQString() stream >> font rotateangle=stream.readFloat() tx=TextItem(text, position, self.scene, font, matrix) tx.setRotation(rotateangle) elif type == "Box": rect = QRectF() stream >> rect style = Qt.PenStyle(stream.readInt16()) rotateangle=stream.readFloat() bx=BoxItem(position, self.scene, style, rect, matrix) bx.setRotation(rotateangle) elif type == "Pixmap": pixmap = QPixmap() stream >> pixmap rotateangle=stream.readFloat() px=self.createPixmapItem(pixmap, position, matrix) px.setRotation(rotateangle) def writeItemToStream(self, stream, item): if isinstance(item, TextItem): stream.writeQString("Text") stream<<item.pos()<< item.transform() stream.writeQString(item.toPlainText()) stream<< item.font() stream.writeFloat(item.rotation())#add by yangrongdong elif isinstance(item, GraphicsPixmapItem): stream.writeQString("Pixmap") stream << item.pos() << item.transform() << item.pixmap() stream.writeFloat(item.rotation())#add by yangrongdong elif isinstance(item, BoxItem): stream.writeQString("Box") stream<< item.pos() << item.transform() << item.rect stream.writeInt16(item.style) stream.writeFloat(item.rotation())#add by yangrongdong
class AdBlockSubscription(QObject): """ Class implementing the AdBlock subscription. @signal changed() emitted after the subscription has changed @signal rulesChanged() emitted after the subscription's rules have changed @signal enabledChanged(bool) emitted after the enabled state was changed """ changed = pyqtSignal() rulesChanged = pyqtSignal() enabledChanged = pyqtSignal(bool) def __init__(self, url, custom, parent=None, default=False): """ Constructor @param url AdBlock URL for the subscription (QUrl) @param custom flag indicating a custom subscription (boolean) @param parent reference to the parent object (QObject) @param default flag indicating a default subscription (boolean) """ super(AdBlockSubscription, self).__init__(parent) self.__custom = custom self.__url = url.toEncoded() self.__enabled = False self.__downloading = None self.__defaultSubscription = default self.__title = "" self.__location = QByteArray() self.__lastUpdate = QDateTime() self.__requiresLocation = "" self.__requiresTitle = "" self.__updatePeriod = 0 # update period in hours, 0 = use default self.__remoteModified = QDateTime() self.__rules = [] # list containing all AdBlock rules self.__networkExceptionRules = [] self.__networkBlockRules = [] self.__domainRestrictedCssRules = [] self.__elementHidingRules = "" self.__documentRules = [] self.__elemhideRules = [] self.__checksumRe = re.compile( r"""^\s*!\s*checksum[\s\-:]+([\w\+\/=]+).*\n""", re.IGNORECASE | re.MULTILINE) self.__expiresRe = re.compile( r"""(?:expires:|expires after)\s*(\d+)\s*(hour|h)?""", re.IGNORECASE) self.__remoteModifiedRe = re.compile( r"""!\s*(?:Last modified|Updated):\s*(\d{1,2})\s*""" r"""(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s*""" r"""(\d{2,4})\s*((\d{1,2}):(\d{2}))?""", re.IGNORECASE) self.__monthNameToNumber = { "Jan": 1, "Feb": 2, "Mar": 3, "Apr": 4, "May": 5, "Jun": 6, "Jul": 7, "Aug": 8, "Sep": 9, "Oct": 10, "Nov": 11, "Dec": 12 } self.__parseUrl(url) def __parseUrl(self, url): """ Private method to parse the AdBlock URL for the subscription. @param url AdBlock URL for the subscription (QUrl) """ if url.scheme() != "abp": return if url.path() != "subscribe": return if qVersion() >= "5.0.0": from PyQt5.QtCore import QUrlQuery urlQuery = QUrlQuery(url) self.__title = QUrl.fromPercentEncoding( QByteArray(urlQuery.queryItemValue("title").encode())) self.__enabled = urlQuery.queryItemValue("enabled") != "false" self.__location = QByteArray( QUrl.fromPercentEncoding( QByteArray(urlQuery.queryItemValue( "location").encode())).encode("utf-8")) # Check for required subscription self.__requiresLocation = QUrl.fromPercentEncoding( QByteArray( urlQuery.queryItemValue("requiresLocation").encode())) self.__requiresTitle = QUrl.fromPercentEncoding( QByteArray(urlQuery.queryItemValue("requiresTitle").encode())) if self.__requiresLocation and self.__requiresTitle: import Helpviewer.HelpWindow Helpviewer.HelpWindow.HelpWindow.adBlockManager()\ .loadRequiredSubscription(self.__requiresLocation, self.__requiresTitle) lastUpdateString = urlQuery.queryItemValue("lastUpdate") self.__lastUpdate = QDateTime.fromString(lastUpdateString, Qt.ISODate) else: self.__title = \ QUrl.fromPercentEncoding(url.encodedQueryItemValue(b"title")) self.__enabled = QUrl.fromPercentEncoding( url.encodedQueryItemValue(b"enabled")) != "false" self.__location = QByteArray( QUrl.fromPercentEncoding( url.encodedQueryItemValue(b"location")).encode("utf-8")) # Check for required subscription self.__requiresLocation = QUrl.fromPercentEncoding( url.encodedQueryItemValue(b"requiresLocation")) self.__requiresTitle = QUrl.fromPercentEncoding( url.encodedQueryItemValue(b"requiresTitle")) if self.__requiresLocation and self.__requiresTitle: import Helpviewer.HelpWindow Helpviewer.HelpWindow.HelpWindow.adBlockManager()\ .loadRequiredSubscription(self.__requiresLocation, self.__requiresTitle) lastUpdateByteArray = url.encodedQueryItemValue(b"lastUpdate") lastUpdateString = QUrl.fromPercentEncoding(lastUpdateByteArray) self.__lastUpdate = QDateTime.fromString(lastUpdateString, Qt.ISODate) self.__loadRules() def url(self): """ Public method to generate the URL for this subscription. @return AdBlock URL for the subscription (QUrl) """ url = QUrl() url.setScheme("abp") url.setPath("subscribe") queryItems = [] queryItems.append(("location", bytes(self.__location).decode())) queryItems.append(("title", self.__title)) if self.__requiresLocation and self.__requiresTitle: queryItems.append(("requiresLocation", self.__requiresLocation)) queryItems.append(("requiresTitle", self.__requiresTitle)) if not self.__enabled: queryItems.append(("enabled", "false")) if self.__lastUpdate.isValid(): queryItems.append( ("lastUpdate", self.__lastUpdate.toString(Qt.ISODate))) if qVersion() >= "5.0.0": from PyQt5.QtCore import QUrlQuery query = QUrlQuery() query.setQueryItems(queryItems) url.setQuery(query) else: url.setQueryItems(queryItems) return url def isEnabled(self): """ Public method to check, if the subscription is enabled. @return flag indicating the enabled status (boolean) """ return self.__enabled def setEnabled(self, enabled): """ Public method to set the enabled status. @param enabled flag indicating the enabled status (boolean) """ if self.__enabled == enabled: return self.__enabled = enabled self.enabledChanged.emit(enabled) def title(self): """ Public method to get the subscription title. @return subscription title (string) """ return self.__title def setTitle(self, title): """ Public method to set the subscription title. @param title subscription title (string) """ if self.__title == title: return self.__title = title self.changed.emit() def location(self): """ Public method to get the subscription location. @return URL of the subscription location (QUrl) """ return QUrl.fromEncoded(self.__location) def setLocation(self, url): """ Public method to set the subscription location. @param url URL of the subscription location (QUrl) """ if url == self.location(): return self.__location = url.toEncoded() self.__lastUpdate = QDateTime() self.changed.emit() def requiresLocation(self): """ Public method to get the location of a required subscription. @return location of a required subscription (string) """ return self.__requiresLocation def lastUpdate(self): """ Public method to get the date and time of the last update. @return date and time of the last update (QDateTime) """ return self.__lastUpdate def rulesFileName(self): """ Public method to get the name of the rules file. @return name of the rules file (string) """ if self.location().scheme() == "file": return self.location().toLocalFile() if self.__location.isEmpty(): return "" sha1 = bytes( QCryptographicHash.hash(self.__location, QCryptographicHash.Sha1).toHex()).decode() dataDir = os.path.join(Utilities.getConfigDir(), "browser", "subscriptions") if not os.path.exists(dataDir): os.makedirs(dataDir) fileName = os.path.join(dataDir, "adblock_subscription_{0}".format(sha1)) return fileName def __loadRules(self): """ Private method to load the rules of the subscription. """ fileName = self.rulesFileName() f = QFile(fileName) if f.exists(): if not f.open(QIODevice.ReadOnly): E5MessageBox.warning( None, self.tr("Load subscription rules"), self.tr( """Unable to open adblock file '{0}' for reading."""). format(fileName)) else: textStream = QTextStream(f) header = textStream.readLine(1024) if not header.startswith("[Adblock"): E5MessageBox.warning( None, self.tr("Load subscription rules"), self.tr("""AdBlock file '{0}' does not start""" """ with [Adblock.""").format(fileName)) f.close() f.remove() self.__lastUpdate = QDateTime() else: from .AdBlockRule import AdBlockRule self.__updatePeriod = 0 self.__remoteModified = QDateTime() self.__rules = [] self.__rules.append(AdBlockRule(header, self)) while not textStream.atEnd(): line = textStream.readLine() self.__rules.append(AdBlockRule(line, self)) expires = self.__expiresRe.search(line) if expires: period, kind = expires.groups() if kind: # hours self.__updatePeriod = int(period) else: # days self.__updatePeriod = int(period) * 24 remoteModified = self.__remoteModifiedRe.search(line) if remoteModified: day, month, year, time, hour, minute = \ remoteModified.groups() self.__remoteModified.setDate( QDate(int(year), self.__monthNameToNumber[month], int(day))) if time: self.__remoteModified.setTime( QTime(int(hour), int(minute))) self.__populateCache() self.changed.emit() elif not fileName.endswith("_custom"): self.__lastUpdate = QDateTime() self.checkForUpdate() def checkForUpdate(self): """ Public method to check for an update. """ if self.__updatePeriod: updatePeriod = self.__updatePeriod else: updatePeriod = Preferences.getHelp("AdBlockUpdatePeriod") * 24 if not self.__lastUpdate.isValid() or \ (self.__remoteModified.isValid() and self.__remoteModified.addSecs(updatePeriod * 3600) < QDateTime.currentDateTime()) or \ self.__lastUpdate.addSecs(updatePeriod * 3600) < \ QDateTime.currentDateTime(): self.updateNow() def updateNow(self): """ Public method to update the subscription immediately. """ if self.__downloading is not None: return if not self.location().isValid(): return if self.location().scheme() == "file": self.__lastUpdate = QDateTime.currentDateTime() self.__loadRules() return import Helpviewer.HelpWindow from Helpviewer.Network.FollowRedirectReply import FollowRedirectReply self.__downloading = FollowRedirectReply( self.location(), Helpviewer.HelpWindow.HelpWindow.networkAccessManager()) self.__downloading.finished.connect(self.__rulesDownloaded) def __rulesDownloaded(self): """ Private slot to deal with the downloaded rules. """ reply = self.sender() response = reply.readAll() reply.close() self.__downloading = None if reply.error() != QNetworkReply.NoError: if not self.__defaultSubscription: # don't show error if we try to load the default E5MessageBox.warning( None, self.tr("Downloading subscription rules"), self.tr("""<p>Subscription rules could not be""" """ downloaded.</p><p>Error: {0}</p>""").format( reply.errorString())) else: # reset after first download attempt self.__defaultSubscription = False return if response.isEmpty(): E5MessageBox.warning(None, self.tr("Downloading subscription rules"), self.tr("""Got empty subscription rules.""")) return fileName = self.rulesFileName() QFile.remove(fileName) f = QFile(fileName) if not f.open(QIODevice.ReadWrite): E5MessageBox.warning( None, self.tr("Downloading subscription rules"), self.tr("""Unable to open adblock file '{0}' for writing."""). file(fileName)) return f.write(response) f.close() self.__lastUpdate = QDateTime.currentDateTime() if self.__validateCheckSum(fileName): self.__loadRules() else: QFile.remove(fileName) self.__downloading = None reply.deleteLater() def __validateCheckSum(self, fileName): """ Private method to check the subscription file's checksum. @param fileName name of the file containing the subscription (string) @return flag indicating a valid file (boolean). A file is considered valid, if the checksum is OK or the file does not contain a checksum (i.e. cannot be checked). """ try: f = open(fileName, "r", encoding="utf-8") data = f.read() f.close() except (IOError, OSError): return False match = re.search(self.__checksumRe, data) if match: expectedChecksum = match.group(1) else: # consider it as valid return True # normalize the data data = re.sub(r"\r", "", data) # normalize eol data = re.sub(r"\n+", "\n", data) # remove empty lines data = re.sub(self.__checksumRe, "", data) # remove checksum line # calculate checksum md5 = hashlib.md5() md5.update(data.encode("utf-8")) calculatedChecksum = base64.b64encode(md5.digest()).decode()\ .rstrip("=") if calculatedChecksum == expectedChecksum: return True else: res = E5MessageBox.yesNo( None, self.tr("Downloading subscription rules"), self.tr("""<p>AdBlock subscription <b>{0}</b> has a wrong""" """ checksum.<br/>""" """Found: {1}<br/>""" """Calculated: {2}<br/>""" """Use it anyway?</p>""").format( self.__title, expectedChecksum, calculatedChecksum)) return res def saveRules(self): """ Public method to save the subscription rules. """ fileName = self.rulesFileName() if not fileName: return f = QFile(fileName) if not f.open(QIODevice.ReadWrite | QIODevice.Truncate): E5MessageBox.warning( None, self.tr("Saving subscription rules"), self.tr("""Unable to open adblock file '{0}' for writing."""). format(fileName)) return textStream = QTextStream(f) if not self.__rules or not self.__rules[0].isHeader(): textStream << "[Adblock Plus 1.1.1]\n" for rule in self.__rules: textStream << rule.filter() << "\n" def match(self, req, urlDomain, urlString): """ Public method to check the subscription for a matching rule. @param req reference to the network request (QNetworkRequest) @param urlDomain domain of the URL (string) @param urlString URL (string) @return reference to the rule object or None (AdBlockRule) """ for rule in self.__networkExceptionRules: if rule.networkMatch(req, urlDomain, urlString): return None for rule in self.__networkBlockRules: if rule.networkMatch(req, urlDomain, urlString): return rule return None def adBlockDisabledForUrl(self, url): """ Public method to check, if AdBlock is disabled for the given URL. @param url URL to check (QUrl) @return flag indicating disabled state (boolean) """ for rule in self.__documentRules: if rule.urlMatch(url): return True return False def elemHideDisabledForUrl(self, url): """ Public method to check, if element hiding is disabled for the given URL. @param url URL to check (QUrl) @return flag indicating disabled state (boolean) """ if self.adBlockDisabledForUrl(url): return True for rule in self.__elemhideRules: if rule.urlMatch(url): return True return False def elementHidingRules(self): """ Public method to get the element hiding rules. @return element hiding rules (string) """ return self.__elementHidingRules def elementHidingRulesForDomain(self, domain): """ Public method to get the element hiding rules for the given domain. @param domain domain name (string) @return element hiding rules (string) """ rules = "" for rule in self.__domainRestrictedCssRules: if rule.matchDomain(domain): rules += rule.cssSelector() + "," return rules def rule(self, offset): """ Public method to get a specific rule. @param offset offset of the rule (integer) @return requested rule (AdBlockRule) """ if offset >= len(self.__rules): return None return self.__rules[offset] def allRules(self): """ Public method to get the list of rules. @return list of rules (list of AdBlockRule) """ return self.__rules[:] def addRule(self, rule): """ Public method to add a rule. @param rule reference to the rule to add (AdBlockRule) @return offset of the rule (integer) """ self.__rules.append(rule) self.__populateCache() self.rulesChanged.emit() return len(self.__rules) - 1 def removeRule(self, offset): """ Public method to remove a rule given the offset. @param offset offset of the rule to remove (integer) """ if offset < 0 or offset > len(self.__rules): return del self.__rules[offset] self.__populateCache() self.rulesChanged.emit() def replaceRule(self, rule, offset): """ Public method to replace a rule given the offset. @param rule reference to the rule to set (AdBlockRule) @param offset offset of the rule to remove (integer) @return requested rule (AdBlockRule) """ if offset >= len(self.__rules): return None self.__rules[offset] = rule self.__populateCache() self.rulesChanged.emit() return self.__rules[offset] def __populateCache(self): """ Private method to populate the various rule caches. """ self.__networkExceptionRules = [] self.__networkBlockRules = [] self.__domainRestrictedCssRules = [] self.__elementHidingRules = "" self.__documentRules = [] self.__elemhideRules = [] for rule in self.__rules: if not rule.isEnabled(): continue if rule.isCSSRule(): if rule.isDomainRestricted(): self.__domainRestrictedCssRules.append(rule) else: self.__elementHidingRules += rule.cssSelector() + "," elif rule.isDocument(): self.__documentRules.append(rule) elif rule.isElementHiding(): self.__elemhideRules.append(rule) elif rule.isException(): self.__networkExceptionRules.append(rule) else: self.__networkBlockRules.append(rule) def canEditRules(self): """ Public method to check, if rules can be edited. @return flag indicating rules may be edited (boolean) """ return self.__custom def canBeRemoved(self): """ Public method to check, if the subscription can be removed. @return flag indicating removal is allowed (boolean) """ return not self.__custom and not self.__defaultSubscription def setRuleEnabled(self, offset, enabled): """ Public method to enable a specific rule. @param offset offset of the rule (integer) @param enabled new enabled state (boolean) @return reference to the changed rule (AdBlockRule) """ if offset >= len(self.__rules): return None rule = self.__rules[offset] rule.setEnabled(enabled) if rule.isCSSRule(): import Helpviewer.HelpWindow self.__populateCache() Helpviewer.HelpWindow.HelpWindow.mainWindow()\ .reloadUserStyleSheet() return rule
class AdBlockSubscription(QObject): """ Class implementing the AdBlock subscription. @signal changed() emitted after the subscription has changed @signal rulesChanged() emitted after the subscription's rules have changed @signal enabledChanged(bool) emitted after the enabled state was changed """ changed = pyqtSignal() rulesChanged = pyqtSignal() enabledChanged = pyqtSignal(bool) def __init__(self, url, custom, parent=None, default=False): """ Constructor @param url AdBlock URL for the subscription (QUrl) @param custom flag indicating a custom subscription (boolean) @param parent reference to the parent object (QObject) @param default flag indicating a default subscription (boolean) """ super(AdBlockSubscription, self).__init__(parent) self.__custom = custom self.__url = url.toEncoded() self.__enabled = False self.__downloading = None self.__defaultSubscription = default self.__title = "" self.__location = QByteArray() self.__lastUpdate = QDateTime() self.__requiresLocation = "" self.__requiresTitle = "" self.__updatePeriod = 0 # update period in hours, 0 = use default self.__remoteModified = QDateTime() self.__rules = [] # list containing all AdBlock rules self.__networkExceptionRules = [] self.__networkBlockRules = [] self.__domainRestrictedCssRules = [] self.__elementHidingRules = "" self.__documentRules = [] self.__elemhideRules = [] self.__checksumRe = re.compile( r"""^\s*!\s*checksum[\s\-:]+([\w\+\/=]+).*\n""", re.IGNORECASE | re.MULTILINE) self.__expiresRe = re.compile( r"""(?:expires:|expires after)\s*(\d+)\s*(hour|h)?""", re.IGNORECASE) self.__remoteModifiedRe = re.compile( r"""!\s*(?:Last modified|Updated):\s*(\d{1,2})\s*""" r"""(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s*""" r"""(\d{2,4})\s*((\d{1,2}):(\d{2}))?""", re.IGNORECASE) self.__monthNameToNumber = { "Jan": 1, "Feb": 2, "Mar": 3, "Apr": 4, "May": 5, "Jun": 6, "Jul": 7, "Aug": 8, "Sep": 9, "Oct": 10, "Nov": 11, "Dec": 12 } self.__parseUrl(url) def __parseUrl(self, url): """ Private method to parse the AdBlock URL for the subscription. @param url AdBlock URL for the subscription (QUrl) """ if url.scheme() != "abp": return if url.path() != "subscribe": return if qVersion() >= "5.0.0": from PyQt5.QtCore import QUrlQuery urlQuery = QUrlQuery(url) self.__title = QUrl.fromPercentEncoding( QByteArray(urlQuery.queryItemValue("title").encode())) self.__enabled = urlQuery.queryItemValue("enabled") != "false" self.__location = QByteArray(QUrl.fromPercentEncoding( QByteArray(urlQuery.queryItemValue("location").encode())) .encode("utf-8")) # Check for required subscription self.__requiresLocation = QUrl.fromPercentEncoding( QByteArray(urlQuery.queryItemValue( "requiresLocation").encode())) self.__requiresTitle = QUrl.fromPercentEncoding( QByteArray(urlQuery.queryItemValue("requiresTitle").encode())) if self.__requiresLocation and self.__requiresTitle: import Helpviewer.HelpWindow Helpviewer.HelpWindow.HelpWindow.adBlockManager()\ .loadRequiredSubscription(self.__requiresLocation, self.__requiresTitle) lastUpdateString = urlQuery.queryItemValue("lastUpdate") self.__lastUpdate = QDateTime.fromString(lastUpdateString, Qt.ISODate) else: self.__title = \ QUrl.fromPercentEncoding(url.encodedQueryItemValue(b"title")) self.__enabled = QUrl.fromPercentEncoding( url.encodedQueryItemValue(b"enabled")) != "false" self.__location = QByteArray(QUrl.fromPercentEncoding( url.encodedQueryItemValue(b"location")).encode("utf-8")) # Check for required subscription self.__requiresLocation = QUrl.fromPercentEncoding( url.encodedQueryItemValue(b"requiresLocation")) self.__requiresTitle = QUrl.fromPercentEncoding( url.encodedQueryItemValue(b"requiresTitle")) if self.__requiresLocation and self.__requiresTitle: import Helpviewer.HelpWindow Helpviewer.HelpWindow.HelpWindow.adBlockManager()\ .loadRequiredSubscription(self.__requiresLocation, self.__requiresTitle) lastUpdateByteArray = url.encodedQueryItemValue(b"lastUpdate") lastUpdateString = QUrl.fromPercentEncoding(lastUpdateByteArray) self.__lastUpdate = QDateTime.fromString(lastUpdateString, Qt.ISODate) self.__loadRules() def url(self): """ Public method to generate the URL for this subscription. @return AdBlock URL for the subscription (QUrl) """ url = QUrl() url.setScheme("abp") url.setPath("subscribe") queryItems = [] queryItems.append(("location", bytes(self.__location).decode())) queryItems.append(("title", self.__title)) if self.__requiresLocation and self.__requiresTitle: queryItems.append(("requiresLocation", self.__requiresLocation)) queryItems.append(("requiresTitle", self.__requiresTitle)) if not self.__enabled: queryItems.append(("enabled", "false")) if self.__lastUpdate.isValid(): queryItems.append(("lastUpdate", self.__lastUpdate.toString(Qt.ISODate))) if qVersion() >= "5.0.0": from PyQt5.QtCore import QUrlQuery query = QUrlQuery() query.setQueryItems(queryItems) url.setQuery(query) else: url.setQueryItems(queryItems) return url def isEnabled(self): """ Public method to check, if the subscription is enabled. @return flag indicating the enabled status (boolean) """ return self.__enabled def setEnabled(self, enabled): """ Public method to set the enabled status. @param enabled flag indicating the enabled status (boolean) """ if self.__enabled == enabled: return self.__enabled = enabled self.enabledChanged.emit(enabled) def title(self): """ Public method to get the subscription title. @return subscription title (string) """ return self.__title def setTitle(self, title): """ Public method to set the subscription title. @param title subscription title (string) """ if self.__title == title: return self.__title = title self.changed.emit() def location(self): """ Public method to get the subscription location. @return URL of the subscription location (QUrl) """ return QUrl.fromEncoded(self.__location) def setLocation(self, url): """ Public method to set the subscription location. @param url URL of the subscription location (QUrl) """ if url == self.location(): return self.__location = url.toEncoded() self.__lastUpdate = QDateTime() self.changed.emit() def requiresLocation(self): """ Public method to get the location of a required subscription. @return location of a required subscription (string) """ return self.__requiresLocation def lastUpdate(self): """ Public method to get the date and time of the last update. @return date and time of the last update (QDateTime) """ return self.__lastUpdate def rulesFileName(self): """ Public method to get the name of the rules file. @return name of the rules file (string) """ if self.location().scheme() == "file": return self.location().toLocalFile() if self.__location.isEmpty(): return "" sha1 = bytes(QCryptographicHash.hash( self.__location, QCryptographicHash.Sha1).toHex()).decode() dataDir = os.path.join( Utilities.getConfigDir(), "browser", "subscriptions") if not os.path.exists(dataDir): os.makedirs(dataDir) fileName = os.path.join( dataDir, "adblock_subscription_{0}".format(sha1)) return fileName def __loadRules(self): """ Private method to load the rules of the subscription. """ fileName = self.rulesFileName() f = QFile(fileName) if f.exists(): if not f.open(QIODevice.ReadOnly): E5MessageBox.warning( None, self.tr("Load subscription rules"), self.tr( """Unable to open adblock file '{0}' for reading.""") .format(fileName)) else: textStream = QTextStream(f) header = textStream.readLine(1024) if not header.startswith("[Adblock"): E5MessageBox.warning( None, self.tr("Load subscription rules"), self.tr("""AdBlock file '{0}' does not start""" """ with [Adblock.""") .format(fileName)) f.close() f.remove() self.__lastUpdate = QDateTime() else: from .AdBlockRule import AdBlockRule self.__updatePeriod = 0 self.__remoteModified = QDateTime() self.__rules = [] self.__rules.append(AdBlockRule(header, self)) while not textStream.atEnd(): line = textStream.readLine() self.__rules.append(AdBlockRule(line, self)) expires = self.__expiresRe.search(line) if expires: period, kind = expires.groups() if kind: # hours self.__updatePeriod = int(period) else: # days self.__updatePeriod = int(period) * 24 remoteModified = self.__remoteModifiedRe.search(line) if remoteModified: day, month, year, time, hour, minute = \ remoteModified.groups() self.__remoteModified.setDate( QDate(int(year), self.__monthNameToNumber[month], int(day)) ) if time: self.__remoteModified.setTime( QTime(int(hour), int(minute))) self.__populateCache() self.changed.emit() elif not fileName.endswith("_custom"): self.__lastUpdate = QDateTime() self.checkForUpdate() def checkForUpdate(self): """ Public method to check for an update. """ if self.__updatePeriod: updatePeriod = self.__updatePeriod else: updatePeriod = Preferences.getHelp("AdBlockUpdatePeriod") * 24 if not self.__lastUpdate.isValid() or \ (self.__remoteModified.isValid() and self.__remoteModified.addSecs(updatePeriod * 3600) < QDateTime.currentDateTime()) or \ self.__lastUpdate.addSecs(updatePeriod * 3600) < \ QDateTime.currentDateTime(): self.updateNow() def updateNow(self): """ Public method to update the subscription immediately. """ if self.__downloading is not None: return if not self.location().isValid(): return if self.location().scheme() == "file": self.__lastUpdate = QDateTime.currentDateTime() self.__loadRules() return import Helpviewer.HelpWindow from Helpviewer.Network.FollowRedirectReply import FollowRedirectReply self.__downloading = FollowRedirectReply( self.location(), Helpviewer.HelpWindow.HelpWindow.networkAccessManager()) self.__downloading.finished.connect(self.__rulesDownloaded) def __rulesDownloaded(self): """ Private slot to deal with the downloaded rules. """ reply = self.sender() response = reply.readAll() reply.close() self.__downloading = None if reply.error() != QNetworkReply.NoError: if not self.__defaultSubscription: # don't show error if we try to load the default E5MessageBox.warning( None, self.tr("Downloading subscription rules"), self.tr( """<p>Subscription rules could not be""" """ downloaded.</p><p>Error: {0}</p>""") .format(reply.errorString())) else: # reset after first download attempt self.__defaultSubscription = False return if response.isEmpty(): E5MessageBox.warning( None, self.tr("Downloading subscription rules"), self.tr("""Got empty subscription rules.""")) return fileName = self.rulesFileName() QFile.remove(fileName) f = QFile(fileName) if not f.open(QIODevice.ReadWrite): E5MessageBox.warning( None, self.tr("Downloading subscription rules"), self.tr( """Unable to open adblock file '{0}' for writing.""") .file(fileName)) return f.write(response) f.close() self.__lastUpdate = QDateTime.currentDateTime() if self.__validateCheckSum(fileName): self.__loadRules() else: QFile.remove(fileName) self.__downloading = None reply.deleteLater() def __validateCheckSum(self, fileName): """ Private method to check the subscription file's checksum. @param fileName name of the file containing the subscription (string) @return flag indicating a valid file (boolean). A file is considered valid, if the checksum is OK or the file does not contain a checksum (i.e. cannot be checked). """ try: f = open(fileName, "r", encoding="utf-8") data = f.read() f.close() except (IOError, OSError): return False match = re.search(self.__checksumRe, data) if match: expectedChecksum = match.group(1) else: # consider it as valid return True # normalize the data data = re.sub(r"\r", "", data) # normalize eol data = re.sub(r"\n+", "\n", data) # remove empty lines data = re.sub(self.__checksumRe, "", data) # remove checksum line # calculate checksum md5 = hashlib.md5() md5.update(data.encode("utf-8")) calculatedChecksum = base64.b64encode(md5.digest()).decode()\ .rstrip("=") if calculatedChecksum == expectedChecksum: return True else: res = E5MessageBox.yesNo( None, self.tr("Downloading subscription rules"), self.tr( """<p>AdBlock subscription <b>{0}</b> has a wrong""" """ checksum.<br/>""" """Found: {1}<br/>""" """Calculated: {2}<br/>""" """Use it anyway?</p>""") .format(self.__title, expectedChecksum, calculatedChecksum)) return res def saveRules(self): """ Public method to save the subscription rules. """ fileName = self.rulesFileName() if not fileName: return f = QFile(fileName) if not f.open(QIODevice.ReadWrite | QIODevice.Truncate): E5MessageBox.warning( None, self.tr("Saving subscription rules"), self.tr( """Unable to open adblock file '{0}' for writing.""") .format(fileName)) return textStream = QTextStream(f) if not self.__rules or not self.__rules[0].isHeader(): textStream << "[Adblock Plus 1.1.1]\n" for rule in self.__rules: textStream << rule.filter() << "\n" def match(self, req, urlDomain, urlString): """ Public method to check the subscription for a matching rule. @param req reference to the network request (QNetworkRequest) @param urlDomain domain of the URL (string) @param urlString URL (string) @return reference to the rule object or None (AdBlockRule) """ for rule in self.__networkExceptionRules: if rule.networkMatch(req, urlDomain, urlString): return None for rule in self.__networkBlockRules: if rule.networkMatch(req, urlDomain, urlString): return rule return None def adBlockDisabledForUrl(self, url): """ Public method to check, if AdBlock is disabled for the given URL. @param url URL to check (QUrl) @return flag indicating disabled state (boolean) """ for rule in self.__documentRules: if rule.urlMatch(url): return True return False def elemHideDisabledForUrl(self, url): """ Public method to check, if element hiding is disabled for the given URL. @param url URL to check (QUrl) @return flag indicating disabled state (boolean) """ if self.adBlockDisabledForUrl(url): return True for rule in self.__elemhideRules: if rule.urlMatch(url): return True return False def elementHidingRules(self): """ Public method to get the element hiding rules. @return element hiding rules (string) """ return self.__elementHidingRules def elementHidingRulesForDomain(self, domain): """ Public method to get the element hiding rules for the given domain. @param domain domain name (string) @return element hiding rules (string) """ rules = "" for rule in self.__domainRestrictedCssRules: if rule.matchDomain(domain): rules += rule.cssSelector() + "," return rules def rule(self, offset): """ Public method to get a specific rule. @param offset offset of the rule (integer) @return requested rule (AdBlockRule) """ if offset >= len(self.__rules): return None return self.__rules[offset] def allRules(self): """ Public method to get the list of rules. @return list of rules (list of AdBlockRule) """ return self.__rules[:] def addRule(self, rule): """ Public method to add a rule. @param rule reference to the rule to add (AdBlockRule) @return offset of the rule (integer) """ self.__rules.append(rule) self.__populateCache() self.rulesChanged.emit() return len(self.__rules) - 1 def removeRule(self, offset): """ Public method to remove a rule given the offset. @param offset offset of the rule to remove (integer) """ if offset < 0 or offset > len(self.__rules): return del self.__rules[offset] self.__populateCache() self.rulesChanged.emit() def replaceRule(self, rule, offset): """ Public method to replace a rule given the offset. @param rule reference to the rule to set (AdBlockRule) @param offset offset of the rule to remove (integer) @return requested rule (AdBlockRule) """ if offset >= len(self.__rules): return None self.__rules[offset] = rule self.__populateCache() self.rulesChanged.emit() return self.__rules[offset] def __populateCache(self): """ Private method to populate the various rule caches. """ self.__networkExceptionRules = [] self.__networkBlockRules = [] self.__domainRestrictedCssRules = [] self.__elementHidingRules = "" self.__documentRules = [] self.__elemhideRules = [] for rule in self.__rules: if not rule.isEnabled(): continue if rule.isCSSRule(): if rule.isDomainRestricted(): self.__domainRestrictedCssRules.append(rule) else: self.__elementHidingRules += rule.cssSelector() + "," elif rule.isDocument(): self.__documentRules.append(rule) elif rule.isElementHiding(): self.__elemhideRules.append(rule) elif rule.isException(): self.__networkExceptionRules.append(rule) else: self.__networkBlockRules.append(rule) def canEditRules(self): """ Public method to check, if rules can be edited. @return flag indicating rules may be edited (boolean) """ return self.__custom def canBeRemoved(self): """ Public method to check, if the subscription can be removed. @return flag indicating removal is allowed (boolean) """ return not self.__custom and not self.__defaultSubscription def setRuleEnabled(self, offset, enabled): """ Public method to enable a specific rule. @param offset offset of the rule (integer) @param enabled new enabled state (boolean) @return reference to the changed rule (AdBlockRule) """ if offset >= len(self.__rules): return None rule = self.__rules[offset] rule.setEnabled(enabled) if rule.isCSSRule(): import Helpviewer.HelpWindow self.__populateCache() Helpviewer.HelpWindow.HelpWindow.mainWindow()\ .reloadUserStyleSheet() return rule
class MainForm(QDialog): def __init__(self, parent=None): super(MainForm, self).__init__(parent) self.filename = "" self.copiedItem = QByteArray() self.pasteOffset = 5 self.prevPoint = QPoint() self.addOffset = 5 self.borders = [] self.printer = QPrinter(QPrinter.HighResolution) # enum QPrinter::PrinterMode # HighRes是一个高分辨率模式,是PrinterMode组成 self.printer.setPageSize(QPrinter.A4) self.view = GraphicsView() self.scene = QGraphicsScene(self) self.scene.setSceneRect(0, 0, PageSize[0], PageSize[1]) self.addBorders() self.view.setScene(self.scene) # 不用写 view.show? self.wrapped = [] # Needed to keep wrappers alive buttonLayout = QVBoxLayout() for text, slot in (("Add &Text", self.addText), ("Add &Box", self.addBox), ("Add Pi&xmap", self.addPixmap), ("&Align", None), ("&Copy", self.copy), ("C&ut", self.cut), ("&Paste", self.paste), ("&Delete...", self.delete), ("&Rotate", self.rotate), ("Pri&nt...", self.print_), ("&Open...", self.open), ("&Save", self.save), ("&Quit", self.accept)): button = QPushButton(text) if not MAC: button.setFocusPolicy(Qt.NoFocus) if slot is not None: button.clicked.connect(slot) if text == "&Align": menu = QMenu(self) for text, arg in (("Align &Left", Qt.AlignLeft), ("Align &Right", Qt.AlignRight), ("Align &Top", Qt.AlignTop), ("Align &Bottom", Qt.AlignBottom)): wrapper = functools.partial(self.setAlignment, arg) # ????? self.wrapped.append(wrapper) menu.addAction(text, wrapper) button.setMenu(menu) if text == "Pri&nt...": buttonLayout.addStretch(5) if text == "&Quit": buttonLayout.addStretch(1) buttonLayout.addWidget(button) buttonLayout.addStretch() layout = QHBoxLayout() layout.addWidget(self.view, 1) # QBoxLayout::addWidget(QWidget *widget, int stretch = 0, Qt::Alignment alignment = Qt::Alignment()) layout.addLayout(buttonLayout) self.setLayout(layout) fm = QFontMetrics(self.font()) self.resize(self.scene.width() + fm.width(" Delete... ") + 50, self.scene.height() + 50) self.setWindowTitle("Page Designer 页面设计器") def addBorders(self): '''添加出血框和打印边界框,对scene进行操作同时添加到self.borders这一列表中''' self.borders = [] rect = QRectF(0, 0, PageSize[0], PageSize[1]) self.borders.append(self.scene.addRect( rect, Qt.black)) # addRect px,py,x,y,QPen,QBrush or QRectF,QPen,QBrush # scene.addRect(): Return QGraphicsRectItem;Inherits: QGraphicsItem margin = 5.25 * PointSize self.borders.append( self.scene.addRect(rect.adjusted(margin, margin, -margin, -margin), Qt.red)) def removeBorders(self): '''从列表删除边框,从scene删除边框''' while self.borders: item = self.borders.pop() self.scene.removeItem( item ) #Removes the item item and all its children from the scene. 接受参数为QGraphicsItem del item def reject(self): self.accept() def accept(self): self.offerSave() QDialog.accept( self ) # 完成提示保存之后传递给QDialog的accept命令,之前几章好像讲过为什么要直接调用QDialog这个父类,这里的MWindow是QDialog def offerSave(self): '''根据Dirty判断是否更改,如果更改则弹出保存对话框,调用save()函数进行保存。''' if (Dirty and QMessageBox.question( self, "Page Designer - Unsaved Changes", "Save unsaved changes?", QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes): self.save() def position(self): point = self.mapFromGlobal(QCursor.pos( )) # mFG接受一个QPoint参数,包含两个元素的元组 此函数转换QPoint到map,返回依旧是QPoint # Translates the global screen coordinate pos to widget coordinates. if not self.view.geometry().contains( point): #?????????????????????????????????????????????? coord = random.randint(36, 144) point = QPoint(coord, coord) else: if point == self.prevPoint: point += QPoint(self.addOffset, self.addOffset) self.addOffset += 5 else: self.addOffset = 5 self.prevPoint = point return self.view.mapToScene( point) # 将Widght的点左边转换成为Scene坐标,调用对象是QGView def addText(self): dialog = TextItemDlg(position=self.position(), scene=self.scene, parent=self) dialog.exec_() def addBox(self): BoxItem(self.position(), self.scene) def addPixmap(self): path = (QFileInfo(self.filename).path() if self.filename else "." ) # 获取filename定义的正确地址,或者返回此程序根目录 fname, filetype = QFileDialog.getOpenFileName( self, "Page Designer - Add Pixmap", path, "Pixmap Files (*.bmp *.jpg *.png *.xpm)") if not fname: return self.createPixmapItem( QPixmap(fname), self.position()) # 插入时候要将地址传递给QPixmap生成对象,并且还需要位置参数 def createPixmapItem(self, pixmap, position, matrix=QTransform()): # 传递参数为:文件、位置和变换 item = GraphicsPixmapItem(pixmap) # 第一步,将QPixmap转换成为GPItem item.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable) # 设置一些属性 item.setPos(position) # 设置位置 item.setTransform(matrix) # 将变换参数应用到GPItem之中 self.scene.clearSelection() # 选择清空 self.scene.addItem(item) # 添加项目 item.setSelected(True) # 并且选中 global Dirty Dirty = True # 全局变量Dirty设置为True return item # 为什么需要返回这个??? def selectedItem( self): # 默认的scene选择的是一个列表,如果只有一个则返回index=0的item,如果多选则不返回任何一个 items = self.scene.selectedItems() if len(items) == 1: return items[0] return None def copy(self): item = self.selectedItem() if item is None: return self.copiedItem.clear() self.pasteOffset = 5 stream = QDataStream(self.copiedItem, QIODevice.WriteOnly) self.writeItemToStream(stream, item) # 写入到流 def cut(self): item = self.selectedItem() if item is None: return self.copy() self.scene.removeItem(item) del item def paste(self): if self.copiedItem.isEmpty(): return stream = QDataStream(self.copiedItem, QIODevice.ReadOnly) self.readItemFromStream( stream, self.pasteOffset) # 从数据流中读入信息,并且输出到self.pasteOffset中 self.pasteOffset += 5 def setAlignment(self, alignment): # Items are returned in arbitrary order items = self.scene.selectedItems() if len(items) <= 1: return # Gather coordinate data leftXs, rightXs, topYs, bottomYs = [], [], [], [] for item in items: rect = item.sceneBoundingRect() # Returns the bounding rect of this item in scene coordinates : Return QRectF leftXs.append(rect.x()) rightXs.append(rect.x() + rect.width()) topYs.append(rect.y()) bottomYs.append(rect.y() + rect.height()) # Perform alignment if alignment == Qt.AlignLeft: xAlignment = min(leftXs) for i, item in enumerate(items): item.moveBy(xAlignment - leftXs[i], 0) # void QGraphicsItem::moveBy(qreal dx, qreal dy) # Moves the item by dx points horizontally, and dy point vertically. elif alignment == Qt.AlignRight: xAlignment = max(rightXs) for i, item in enumerate(items): item.moveBy(xAlignment - rightXs[i], 0) elif alignment == Qt.AlignTop: yAlignment = min(topYs) for i, item in enumerate(items): item.moveBy(0, yAlignment - topYs[i]) elif alignment == Qt.AlignBottom: yAlignment = max(bottomYs) for i, item in enumerate(items): item.moveBy(0, yAlignment - bottomYs[i]) global Dirty Dirty = True def rotate(self): for item in self.scene.selectedItems(): item.setRotation(item.rotation() + 30) def delete(self): # 从基本scene属性中选取选择的多个,弹出对话框,如果允许,则迭代进行删除,并且设置Dirty为True items = self.scene.selectedItems() if (len(items) and QMessageBox.question( self, "Page Designer - Delete", "Delete {0} item{1}?".format( len(items), "s" if len(items) != 1 else ""), QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes): while items: item = items.pop() self.scene.removeItem(item) del item global Dirty Dirty = True def print_(self): # dialog = QPrintDialog(self.printer) # 在此已经设置好了self.printer 也就是QPrinter对象,QPDlg直接传递回了Printer对象,之后重新由 # # printer对象声称心的QPrinter就可以继续使用在这句话中设置好的参数了。 # if dialog.exec_(): painter = QPainter(self.printer) painter.setRenderHint(QPainter.Antialiasing) painter.setRenderHint(QPainter.TextAntialiasing) self.scene.clearSelection() self.removeBorders() self.scene.render(painter) # [void] Renders the source rect from scene into target, using painter. This function is useful for capturing the contents # of the scene onto a paint device, such as a QImage (e.g., to take a screenshot), or for printing with QPrinter. For example: self.addBorders() def open(self): self.offerSave() path = (QFileInfo(self.filename).path() if self.filename else ".") fname, filetype = QFileDialog.getOpenFileName( self, "Page Designer - Open", path, "cmPage Designer Files (*.cmpd *.pgd *.cmd)") if not fname: return self.filename = fname fh = None try: fh = QFile(self.filename) if not fh.open(QIODevice.ReadOnly): raise IOError(str(fh.errorString())) items = self.scene.items() # 返回所有的QGitem List形式 while items: item = items.pop() # 从列表中删除一个,从scene中删除一个,迭代到全部删除 self.scene.removeItem(item) del item self.addBorders() stream = QDataStream(fh) stream.setVersion(QDataStream.Qt_5_7) magic = stream.readInt32() if magic != MagicNumber: raise IOError("not a valid .cmpd file") fileVersion = stream.readInt16() if fileVersion != FileVersion: raise IOError("unrecognised .cmpd file version") while not fh.atEnd(): self.readItemFromStream(stream) except IOError as e: QMessageBox.warning( self, "Page Designer -- Open Error", "Failed to open {0}: {1}".format(self.filename, e)) finally: if fh is not None: fh.close() global Dirty Dirty = False def save(self): if not self.filename: path = "." fname, filetype = QFileDialog.getSaveFileName( self, "Page Designer - Save As", path, "cmPage Designer Files (*.cmpd *.pgd *.cmd)") if not fname: return self.filename = fname fh = None try: fh = QFile(self.filename) if not fh.open(QIODevice.WriteOnly): raise IOError(str(fh.errorString())) self.scene.clearSelection() stream = QDataStream(fh) stream.setVersion(QDataStream.Qt_5_7) stream.writeInt32(MagicNumber) stream.writeInt16(FileVersion) for item in self.scene.items(): self.writeItemToStream(stream, item) except IOError as e: QMessageBox.warning( self, "Page Designer -- Save Error", "Failed to save {0}: {1}".format(self.filename, e)) finally: if fh is not None: fh.close() global Dirty Dirty = False def readItemFromStream(self, stream, offset=0): type = "" position = QPointF() matrix = QTransform() rotateangle = 0 #add by yangrongdong type = stream.readQString() stream >> position >> matrix if offset: position += QPointF(offset, offset) if type == "Text": text = "" font = QFont() text = stream.readQString() stream >> font rotateangle = stream.readFloat() tx = TextItem(text, position, self.scene, font, matrix) tx.setRotation(rotateangle) elif type == "Box": rect = QRectF() stream >> rect style = Qt.PenStyle(stream.readInt16()) rotateangle = stream.readFloat() bx = BoxItem(position, self.scene, style, rect, matrix) bx.setRotation(rotateangle) elif type == "Pixmap": pixmap = QPixmap() stream >> pixmap rotateangle = stream.readFloat() px = self.createPixmapItem(pixmap, position, matrix) px.setRotation(rotateangle) def writeItemToStream(self, stream, item): if isinstance(item, TextItem): stream.writeQString("Text") stream << item.pos() << item.transform() stream.writeQString(item.toPlainText()) stream << item.font() stream.writeFloat(item.rotation()) #add by yangrongdong elif isinstance(item, GraphicsPixmapItem): stream.writeQString("Pixmap") stream << item.pos() << item.transform() << item.pixmap() stream.writeFloat(item.rotation()) #add by yangrongdong elif isinstance(item, BoxItem): stream.writeQString("Box") stream << item.pos() << item.transform() << item.rect stream.writeInt16(item.style) stream.writeFloat(item.rotation()) #add by yangrongdong