def create(self, parent): nam = QNetworkAccessManager(parent) diskCache = QNetworkDiskCache(nam) cachePath = QStandardPaths.displayName(QStandardPaths.CacheLocation) print "cache path:", cachePath diskCache.setCacheDirectory(cachePath) diskCache.setMaximumCacheSize(100 * 1024 * 1024) # 设置100M缓存 nam.setCache(diskCache) return nam
def create(self, parent): nam = QNetworkAccessManager(parent) cache = QNetworkDiskCache(parent) cache_dir = QStandardPaths.writableLocation(QStandardPaths.CacheLocation) cache_subdir = os.path.join(cache_dir, "network") print("Cache dir:", cache_subdir) cache.setCacheDirectory(cache_subdir) nam.setCache(cache) return nam
def _fetch_inventory(self): cache_dir = config.cache_dir() cache_dir = os.path.join(cache_dir, "help", "intersphinx") try: os.makedirs(cache_dir) except OSError: pass url = QUrl(self.inventory) if not self.islocal: # fetch and cache the inventory file manager = QNetworkAccessManager(self) cache = QNetworkDiskCache() cache.setCacheDirectory(cache_dir) manager.setCache(cache) req = QNetworkRequest(url) self._reply = manager.get(req) manager.finished.connect(self._on_finished) else: self._load_inventory(open(six.text_type(url.toLocalFile()), "rb"))
class ScudCloud(QtWidgets.QMainWindow): forceClose = False messages = 0 speller = Speller() title = 'ScudCloud' def __init__(self, debug=False, minimized=None, urgent_hint=None, settings_path='', cache_path=''): super(ScudCloud, self).__init__(None) self.debug = debug self.minimized = minimized self.urgent_hint = urgent_hint self.setWindowTitle(self.title) self.settings_path = settings_path self.cache_path = cache_path self.notifier = Notifier(Resources.APP_NAME, Resources.get_path('scudcloud.png')) self.settings = QSettings(self.settings_path + '/scudcloud_qt5.cfg', QSettings.IniFormat) self.notifier.enabled = self.settings.value('Notifications', defaultValue=True, type=bool) self.identifier = self.settings.value("Domain") if Unity is not None: self.launcher = Unity.LauncherEntry.get_for_desktop_id( "scudcloud.desktop") else: self.launcher = DummyLauncher(self) self.webSettings() self.snippetsSettings() self.leftPane = LeftPane(self) self.stackedWidget = QtWidgets.QStackedWidget() centralWidget = QtWidgets.QWidget(self) layout = QtWidgets.QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(self.leftPane) layout.addWidget(self.stackedWidget) centralWidget.setLayout(layout) self.setCentralWidget(centralWidget) self.startURL = Resources.SIGNIN_URL if self.identifier is not None: if isinstance(self.identifier, str): self.domains = self.identifier.split(",") else: self.domains = self.identifier self.startURL = self.normalize(self.domains[0]) else: self.domains = [] self.addWrapper(self.startURL) self.addMenu() self.tray = Systray(self) self.systray(self.minimized) self.installEventFilter(self) self.statusBar().showMessage('Loading Slack...') self.tickler = QTimer(self) self.tickler.setInterval(1800000) # Watch for ScreenLock events if DBusQtMainLoop is not None: DBusQtMainLoop(set_as_default=True) sessionBus = dbus.SessionBus() # Ubuntu 12.04 and other distros sessionBus.add_match_string( "type='signal',interface='org.gnome.ScreenSaver'") # Ubuntu 14.04 sessionBus.add_match_string( "type='signal',interface='com.ubuntu.Upstart0_6'") # Ubuntu 16.04 and KDE sessionBus.add_match_string( "type='signal',interface='org.freedesktop.ScreenSaver'") # Cinnamon sessionBus.add_match_string( "type='signal',interface='org.cinnamon.ScreenSaver'") sessionBus.add_message_filter(self.screenListener) self.tickler.timeout.connect(self.sendTickle) # If dbus is not present, tickler timer will act like a blocker to not send tickle too often else: self.tickler.setSingleShot(True) self.tickler.start() def screenListener(self, bus, message): event = message.get_member() # "ActiveChanged" for Ubuntu 12.04 and other distros. "EventEmitted" for Ubuntu 14.04 and above if event == "ActiveChanged" or event == "EventEmitted": arg = message.get_args_list()[0] # True for Ubuntu 12.04 and other distros. "desktop-lock" for Ubuntu 14.04 and above if (arg == True or arg == "desktop-lock") and self.tickler.isActive(): self.tickler.stop() elif (arg == False or arg == "desktop-unlock") and not self.tickler.isActive(): self.sendTickle() self.tickler.start() def sendTickle(self): for i in range(0, self.stackedWidget.count()): self.stackedWidget.widget(i).sendTickle() def addWrapper(self, url): webView = Wrapper(self) webView.load(QtCore.QUrl(url)) webView.show() webView.setZoomFactor(self.zoom) self.stackedWidget.addWidget(webView) self.stackedWidget.setCurrentWidget(webView) self.clearMemory() def webSettings(self): self.cookiesjar = PersistentCookieJar(self) self.zoom = self.readZoom() # We don't want Flash (it causes a lot of trouble in some distros) QWebSettings.globalSettings().setAttribute(QWebSettings.PluginsEnabled, False) # We don't need Java QWebSettings.globalSettings().setAttribute(QWebSettings.JavaEnabled, False) # Enabling Local Storage (now required by Slack) QWebSettings.globalSettings().setAttribute( QWebSettings.LocalStorageEnabled, True) # We need browsing history (required to not limit LocalStorage) QWebSettings.globalSettings().setAttribute( QWebSettings.PrivateBrowsingEnabled, False) # Enabling Cache self.diskCache = QNetworkDiskCache(self) self.diskCache.setCacheDirectory(self.cache_path) # Required for copy and paste clipboard integration QWebSettings.globalSettings().setAttribute( QWebSettings.JavascriptCanAccessClipboard, True) # Enabling Inspeclet only when --debug=True (requires more CPU usage) QWebSettings.globalSettings().setAttribute( QWebSettings.DeveloperExtrasEnabled, self.debug) # Sharing the same networkAccessManager self.networkAccessManager = QNetworkAccessManager(self) self.networkAccessManager.setCookieJar(self.cookiesjar) self.networkAccessManager.setCache(self.diskCache) def snippetsSettings(self): self.disable_snippets = self.settings.value("Snippets") if self.disable_snippets is not None: self.disable_snippets = self.disable_snippets == "False" else: self.disable_snippets = False if self.disable_snippets: disable_snippets_css = '' with open(Resources.get_path('disable_snippets.css'), 'r') as f: disable_snippets_css = f.read() with open(os.path.join(self.cache_path, 'resources.css'), 'a') as f: f.write(disable_snippets_css) def toggleFullScreen(self): if self.isFullScreen(): self.showMaximized() else: self.showFullScreen() def toggleMenuBar(self): menu = self.menuBar() state = menu.isHidden() menu.setVisible(state) if state: self.settings.setValue("Menu", "True") else: self.settings.setValue("Menu", "False") def restore(self): geometry = self.settings.value("geometry") if geometry is not None: self.restoreGeometry(geometry) windowState = self.settings.value("windowState") if windowState is not None: self.restoreState(windowState) else: self.setWindowState(QtCore.Qt.WindowMaximized) def systray(self, show=None): if show is None: show = self.settings.value("Systray") == "True" if show: self.tray.show() self.menus["file"]["close"].setEnabled(True) self.settings.setValue("Systray", "True") else: self.tray.setVisible(False) self.menus["file"]["close"].setEnabled(False) self.settings.setValue("Systray", "False") def readZoom(self): default = 1 if self.settings.value("Zoom") is not None: default = float(self.settings.value("Zoom")) return default def setZoom(self, factor=1): if factor > 0: for i in range(0, self.stackedWidget.count()): widget = self.stackedWidget.widget(i) widget.setZoomFactor(factor) self.settings.setValue("Zoom", factor) def zoomIn(self): self.setZoom(self.current().zoomFactor() + 0.1) def zoomOut(self): self.setZoom(self.current().zoomFactor() - 0.1) def zoomReset(self): self.setZoom() def addTeam(self): self.switchTo(Resources.SIGNIN_URL) def addMenu(self): # We'll register the webpage shorcuts with the window too (Fixes #338) undo = self.current().pageAction(QWebPage.Undo) redo = self.current().pageAction(QWebPage.Redo) cut = self.current().pageAction(QWebPage.Cut) copy = self.current().pageAction(QWebPage.Copy) paste = self.current().pageAction(QWebPage.Paste) back = self.current().pageAction(QWebPage.Back) forward = self.current().pageAction(QWebPage.Forward) reload = self.current().pageAction(QWebPage.Reload) self.menus = { "file": { "preferences": self.createAction("Preferences", lambda: self.current().preferences()), "systray": self.createAction("Close to Tray", self.systray, None, True), "addTeam": self.createAction("Sign in to Another Team", lambda: self.addTeam()), "signout": self.createAction("Signout", lambda: self.current().logout()), "close": self.createAction("Close", self.close, QKeySequence.Close), "exit": self.createAction("Quit", self.exit, QKeySequence.Quit) }, "edit": { "undo": self.createAction( undo.text(), lambda: self.current().page().triggerAction(QWebPage.Undo), undo.shortcut()), "redo": self.createAction( redo.text(), lambda: self.current().page().triggerAction(QWebPage.Redo), redo.shortcut()), "cut": self.createAction( cut.text(), lambda: self.current().page().triggerAction(QWebPage.Cut), cut.shortcut()), "copy": self.createAction( copy.text(), lambda: self.current().page().triggerAction(QWebPage.Copy), copy.shortcut()), "paste": self.createAction( paste.text(), lambda: self.current().page().triggerAction( QWebPage.Paste), paste.shortcut()), "back": self.createAction( back.text(), lambda: self.current().page().triggerAction(QWebPage.Back), back.shortcut()), "forward": self.createAction( forward.text(), lambda: self.current().page(). triggerAction(QWebPage.Forward), forward.shortcut()), "reload": self.createAction( reload.text(), lambda: self.current().page().triggerAction( QWebPage.Reload), reload.shortcut()), }, "view": { "zoomin": self.createAction("Zoom In", self.zoomIn, QKeySequence.ZoomIn), "zoomout": self.createAction("Zoom Out", self.zoomOut, QKeySequence.ZoomOut), "reset": self.createAction("Reset", self.zoomReset, QtCore.Qt.CTRL + QtCore.Qt.Key_0), "fullscreen": self.createAction("Toggle Full Screen", self.toggleFullScreen, QtCore.Qt.Key_F11), "hidemenu": self.createAction("Toggle Menubar", self.toggleMenuBar, QtCore.Qt.Key_F12) }, "help": { "help": self.createAction("Help and Feedback", lambda: self.current().help(), QKeySequence.HelpContents), "center": self.createAction("Slack Help Center", lambda: self.current().helpCenter()), "about": self.createAction("About", lambda: self.current().about()) } } menu = self.menuBar() fileMenu = menu.addMenu("&File") fileMenu.addAction(self.menus["file"]["preferences"]) fileMenu.addAction(self.menus["file"]["systray"]) fileMenu.addSeparator() fileMenu.addAction(self.menus["file"]["addTeam"]) fileMenu.addAction(self.menus["file"]["signout"]) fileMenu.addSeparator() fileMenu.addAction(self.menus["file"]["close"]) fileMenu.addAction(self.menus["file"]["exit"]) editMenu = menu.addMenu("&Edit") editMenu.addAction(self.menus["edit"]["undo"]) editMenu.addAction(self.menus["edit"]["redo"]) editMenu.addSeparator() editMenu.addAction(self.menus["edit"]["cut"]) editMenu.addAction(self.menus["edit"]["copy"]) editMenu.addAction(self.menus["edit"]["paste"]) editMenu.addSeparator() editMenu.addAction(self.menus["edit"]["back"]) editMenu.addAction(self.menus["edit"]["forward"]) editMenu.addAction(self.menus["edit"]["reload"]) viewMenu = menu.addMenu("&View") viewMenu.addAction(self.menus["view"]["zoomin"]) viewMenu.addAction(self.menus["view"]["zoomout"]) viewMenu.addAction(self.menus["view"]["reset"]) viewMenu.addSeparator() viewMenu.addAction(self.menus["view"]["fullscreen"]) viewMenu.addAction(self.menus["view"]["hidemenu"]) helpMenu = menu.addMenu("&Help") helpMenu.addAction(self.menus["help"]["help"]) helpMenu.addAction(self.menus["help"]["center"]) helpMenu.addSeparator() helpMenu.addAction(self.menus["help"]["about"]) self.enableMenus(False) showSystray = self.settings.value("Systray") == "True" self.menus["file"]["systray"].setChecked(showSystray) self.menus["file"]["close"].setEnabled(showSystray) # Restore menu visibility visible = self.settings.value("Menu") if visible is not None and visible == "False": menu.setVisible(False) def enableMenus(self, enabled): self.menus["file"]["preferences"].setEnabled(enabled == True) self.menus["file"]["addTeam"].setEnabled(enabled == True) self.menus["file"]["signout"].setEnabled(enabled == True) self.menus["help"]["help"].setEnabled(enabled == True) def createAction(self, text, slot, shortcut=None, checkable=False): action = QtWidgets.QAction(text, self) action.triggered.connect(slot) if shortcut is not None: action.setShortcut(shortcut) self.addAction(action) if checkable: action.setCheckable(True) return action def normalize(self, url): if url.endswith(".slack.com"): url += "/" elif not url.endswith(".slack.com/"): url = "https://" + url + ".slack.com/" return url def current(self): return self.stackedWidget.currentWidget() def teams(self, teams): if len(self.domains) == 0: self.domains.append(teams[0]['team_url']) team_list = [t['team_url'] for t in teams] for t in teams: for i in range(0, len(self.domains)): self.domains[i] = self.normalize(self.domains[i]) # When team_icon is missing, the team already exists (Fixes #381, #391) if 'team_icon' in t: if self.domains[i] in team_list: add = next(item for item in teams if item['team_url'] == self.domains[i]) if 'team_icon' in add: self.leftPane.addTeam(add['id'], add['team_name'], add['team_url'], add['team_icon']['image_44'], add == teams[0]) # Adding new teams and saving loading positions if t['team_url'] not in self.domains: self.leftPane.addTeam( t['id'], t['team_name'], t['team_url'], t['team_icon']['image_44'], t == teams[0]) self.domains.append(t['team_url']) self.settings.setValue("Domain", self.domains) if len(teams) > 1: self.leftPane.show() def switchTo(self, url): exists = False for i in range(0, self.stackedWidget.count()): if self.stackedWidget.widget(i).url().toString().startswith(url): self.stackedWidget.setCurrentIndex(i) self.quicklist(self.current().listChannels()) self.current().setFocus() self.leftPane.click(i) self.clearMemory() exists = True break if not exists: self.addWrapper(url) def eventFilter(self, obj, event): if event.type( ) == QtCore.QEvent.ActivationChange and self.isActiveWindow(): self.focusInEvent(event) if event.type() == QtCore.QEvent.KeyPress: # Ctrl + <n> modifiers = QtWidgets.QApplication.keyboardModifiers() if modifiers == QtCore.Qt.ControlModifier: if event.key() == QtCore.Qt.Key_1: self.leftPane.click(0) elif event.key() == QtCore.Qt.Key_2: self.leftPane.click(1) elif event.key() == QtCore.Qt.Key_3: self.leftPane.click(2) elif event.key() == QtCore.Qt.Key_4: self.leftPane.click(3) elif event.key() == QtCore.Qt.Key_5: self.leftPane.click(4) elif event.key() == QtCore.Qt.Key_6: self.leftPane.click(5) elif event.key() == QtCore.Qt.Key_7: self.leftPane.click(6) elif event.key() == QtCore.Qt.Key_8: self.leftPane.click(7) elif event.key() == QtCore.Qt.Key_9: self.leftPane.click(8) # Ctrl + Tab elif event.key() == QtCore.Qt.Key_Tab: self.leftPane.clickNext(1) # Ctrl + BackTab if (modifiers & QtCore.Qt.ControlModifier) and ( modifiers & QtCore.Qt.ShiftModifier): if event.key() == QtCore.Qt.Key_Backtab: self.leftPane.clickNext(-1) # Ctrl + Shift + <key> if (modifiers & QtCore.Qt.ShiftModifier) and ( modifiers & QtCore.Qt.ShiftModifier): if event.key() == QtCore.Qt.Key_V: self.current().createSnippet() return QtWidgets.QMainWindow.eventFilter(self, obj, event) def focusInEvent(self, event): self.launcher.set_property("urgent", False) self.tray.stopAlert() # Let's tickle all teams on window focus, but only if tickle was not fired in last 30 minutes if DBusQtMainLoop is None and not self.tickler.isActive(): self.sendTickle() self.tickler.start() def titleChanged(self): self.setWindowTitle(self.current().title()) def setForceClose(self): self.forceClose = True def closeEvent(self, event): if not self.forceClose and self.settings.value("Systray") == "True": self.hide() event.ignore() else: self.cookiesjar.save() self.settings.setValue("Domain", self.domains) self.settings.setValue("geometry", self.saveGeometry()) self.settings.setValue("windowState", self.saveState()) self.settings.setValue("Domain", self.domains) self.forceClose = False def show(self): self.setWindowState(self.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive) self.activateWindow() self.setVisible(True) def exit(self): # Make sure tray is not visible (Fixes #513) self.tray.setVisible(False) self.setForceClose() self.close() def quicklist(self, channels): if Dbusmenu is not None: if channels is not None: ql = Dbusmenu.Menuitem.new() self.launcher.set_property("quicklist", ql) for c in channels: if type(c) is dict and hasattr( c, '__getitem__') and c['is_member']: item = Dbusmenu.Menuitem.new() item.property_set(Dbusmenu.MENUITEM_PROP_LABEL, "#" + c['name']) item.property_set("id", c['name']) item.property_set_bool(Dbusmenu.MENUITEM_PROP_VISIBLE, True) item.connect(Dbusmenu.MENUITEM_SIGNAL_ITEM_ACTIVATED, self.current().openChannel) ql.child_append(item) self.launcher.set_property("quicklist", ql) def notify(self, title, message, icon): if self.debug: print("Notification: title [{}] message [{}] icon [{}]".format( title, message, icon)) self.notifier.notify(title, message, icon) self.alert() def alert(self): if not self.isActiveWindow(): self.launcher.set_property("urgent", True) self.tray.alert() if self.urgent_hint is True: QApplication.alert(self) def count(self): total = 0 unreads = 0 for i in range(0, self.stackedWidget.count()): widget = self.stackedWidget.widget(i) highlights = widget.highlights unreads += widget.unreads total += highlights if total > self.messages: self.alert() if 0 == total: self.launcher.set_property("count_visible", False) self.tray.setCounter(0) if unreads > 0: self.setWindowTitle("*{}".format(self.title)) else: self.setWindowTitle(self.title) else: self.tray.setCounter(total) self.launcher.set_property("count", total) self.launcher.set_property("count_visible", True) self.setWindowTitle("[{}]{}".format(str(total), self.title)) self.messages = total def clearMemory(self): QWebSettings.globalSettings().clearMemoryCaches() QWebSettings.globalSettings().clearIconDatabase()
class SlippyMap(QObject): updated = pyqtSignal(QRect) def __init__(self, parent=None): super(SlippyMap, self).__init__(parent) self._offset = QPoint() self._tilesRect = QRect() self._tilePixmaps = {} # Point(x, y) to QPixmap mapping self._manager = QNetworkAccessManager() self._url = QUrl() # public vars self.width = 400 self.height = 300 self.zoom = 15 self.latitude = 59.9138204 self.longitude = 10.7387413 self._emptyTile = QPixmap(TDIM, TDIM) self._emptyTile.fill(Qt.lightGray) cache = QNetworkDiskCache() cache.setCacheDirectory( QStandardPaths.writableLocation(QStandardPaths.CacheLocation)) self._manager.setCache(cache) self._manager.finished.connect(self.handleNetworkData) def invalidate(self): if self.width <= 0 or self.height <= 0: return ct = tileForCoordinate(self.latitude, self.longitude, self.zoom) tx = ct.x() ty = ct.y() # top-left corner of the center tile xp = int(self.width / 2 - (tx - math.floor(tx)) * TDIM) yp = int(self.height / 2 - (ty - math.floor(ty)) * TDIM) # first tile vertical and horizontal xa = (xp + TDIM - 1) / TDIM ya = (yp + TDIM - 1) / TDIM xs = int(tx) - xa ys = int(ty) - ya # offset for top-left tile self._offset = QPoint(xp - xa * TDIM, yp - ya * TDIM) # last tile vertical and horizontal xe = int(tx) + (self.width - xp - 1) / TDIM ye = int(ty) + (self.height - yp - 1) / TDIM # build a rect self._tilesRect = QRect(xs, ys, xe - xs + 1, ye - ys + 1) if self._url.isEmpty(): self.download() self.updated.emit(QRect(0, 0, self.width, self.height)) def render(self, p, rect): for x in range(self._tilesRect.width()): for y in range(self._tilesRect.height()): tp = Point(x + self._tilesRect.left(), y + self._tilesRect.top()) box = self.tileRect(tp) if rect.intersects(box): p.drawPixmap(box, self._tilePixmaps.get(tp, self._emptyTile)) def pan(self, delta): dx = QPointF(delta) / float(TDIM) center = tileForCoordinate(self.latitude, self.longitude, self.zoom) - dx self.latitude = latitudeFromTile(center.y(), self.zoom) self.longitude = longitudeFromTile(center.x(), self.zoom) self.invalidate() # slots def handleNetworkData(self, reply): img = QImage() tp = Point(reply.request().attribute(QNetworkRequest.User)) url = reply.url() if not reply.error(): if img.load(reply, None): self._tilePixmaps[tp] = QPixmap.fromImage(img) reply.deleteLater() self.updated.emit(self.tileRect(tp)) # purge unused tiles bound = self._tilesRect.adjusted(-2, -2, 2, 2) for tp in list(self._tilePixmaps.keys()): if not bound.contains(tp): del self._tilePixmaps[tp] self.download() def download(self): grab = None for x in range(self._tilesRect.width()): for y in range(self._tilesRect.height()): tp = Point(self._tilesRect.topLeft() + QPoint(x, y)) if tp not in self._tilePixmaps: grab = QPoint(tp) break if grab is None: self._url = QUrl() return path = 'http://tile.openstreetmap.org/%d/%d/%d.png' % ( self.zoom, grab.x(), grab.y()) self._url = QUrl(path) request = QNetworkRequest() request.setUrl(self._url) request.setRawHeader(b'User-Agent', b'Nokia (PyQt) Graphics Dojo 1.0') request.setAttribute(QNetworkRequest.User, grab) self._manager.get(request) def tileRect(self, tp): t = tp - self._tilesRect.topLeft() x = t.x() * TDIM + self._offset.x() y = t.y() * TDIM + self._offset.y() return QRect(x, y, TDIM, TDIM)
class SlippyMap(QObject): updated = pyqtSignal(QRect) def __init__(self, parent=None): super(SlippyMap, self).__init__(parent) self._offset = QPoint() self._tilesRect = QRect() self._tilePixmaps = {} # Point(x, y) to QPixmap mapping self._manager = QNetworkAccessManager() self._url = QUrl() # public vars self.width = 400 self.height = 300 self.zoom = 15 self.latitude = 59.9138204 self.longitude = 10.7387413 self._emptyTile = QPixmap(TDIM, TDIM) self._emptyTile.fill(Qt.lightGray) cache = QNetworkDiskCache() cache.setCacheDirectory( QStandardPaths.writableLocation(QStandardPaths.CacheLocation)) self._manager.setCache(cache) self._manager.finished.connect(self.handleNetworkData) def invalidate(self): if self.width <= 0 or self.height <= 0: return ct = tileForCoordinate(self.latitude, self.longitude, self.zoom) tx = ct.x() ty = ct.y() # top-left corner of the center tile xp = int(self.width / 2 - (tx - math.floor(tx)) * TDIM) yp = int(self.height / 2 - (ty - math.floor(ty)) * TDIM) # first tile vertical and horizontal xa = (xp + TDIM - 1) / TDIM ya = (yp + TDIM - 1) / TDIM xs = int(tx) - xa ys = int(ty) - ya # offset for top-left tile self._offset = QPoint(xp - xa * TDIM, yp - ya * TDIM) # last tile vertical and horizontal xe = int(tx) + (self.width - xp - 1) / TDIM ye = int(ty) + (self.height - yp - 1) / TDIM # build a rect self._tilesRect = QRect(xs, ys, xe - xs + 1, ye - ys + 1) if self._url.isEmpty(): self.download() self.updated.emit(QRect(0, 0, self.width, self.height)) def render(self, p, rect): for x in range(self._tilesRect.width()): for y in range(self._tilesRect.height()): tp = Point(x + self._tilesRect.left(), y + self._tilesRect.top()) box = self.tileRect(tp) if rect.intersects(box): p.drawPixmap(box, self._tilePixmaps.get(tp, self._emptyTile)) def pan(self, delta): dx = QPointF(delta) / float(TDIM) center = tileForCoordinate(self.latitude, self.longitude, self.zoom) - dx self.latitude = latitudeFromTile(center.y(), self.zoom) self.longitude = longitudeFromTile(center.x(), self.zoom) self.invalidate() # slots def handleNetworkData(self, reply): img = QImage() tp = Point(reply.request().attribute(QNetworkRequest.User)) url = reply.url() if not reply.error(): if img.load(reply, None): self._tilePixmaps[tp] = QPixmap.fromImage(img) reply.deleteLater() self.updated.emit(self.tileRect(tp)) # purge unused tiles bound = self._tilesRect.adjusted(-2, -2, 2, 2) for tp in list(self._tilePixmaps.keys()): if not bound.contains(tp): del self._tilePixmaps[tp] self.download() def download(self): grab = None for x in range(self._tilesRect.width()): for y in range(self._tilesRect.height()): tp = Point(self._tilesRect.topLeft() + QPoint(x, y)) if tp not in self._tilePixmaps: grab = QPoint(tp) break if grab is None: self._url = QUrl() return path = 'http://tile.openstreetmap.org/%d/%d/%d.png' % (self.zoom, grab.x(), grab.y()) self._url = QUrl(path) request = QNetworkRequest() request.setUrl(self._url) request.setRawHeader(b'User-Agent', b'Nokia (PyQt) Graphics Dojo 1.0') request.setAttribute(QNetworkRequest.User, grab) self._manager.get(request) def tileRect(self, tp): t = tp - self._tilesRect.topLeft() x = t.x() * TDIM + self._offset.x() y = t.y() * TDIM + self._offset.y() return QRect(x, y, TDIM, TDIM)
class QOSM(QWebEngineView): mapMoved = pyqtSignal(float, float) mapClicked = pyqtSignal(float, float) mapRightClicked = pyqtSignal(float, float) mapDoubleClicked = pyqtSignal(float, float) markerMoved = pyqtSignal(str, float, float) markerClicked = pyqtSignal(str, float, float) markerDoubleClicked = pyqtSignal(str, float, float) markerRightClicked = pyqtSignal(str, float, float) def __init__(self, parent): super(QOSM, self).__init__(parent) self.manager = QNetworkAccessManager() self.cache = QNetworkDiskCache() self.cache.setCacheDirectory("cache") self.manager.setCache(self.cache) self.channel = QtWebChannel.QWebChannel(self) self.channel.registerObject("qOSMap", self) self.page().setWebChannel(self.channel) with open(path + 'index.html') as f: HTML = f.read() self.setHtml(HTML) self.loadFinished.connect(self.onLoadFinished) def onLoadFinished(self): with open(path + 'qwebchannel.js') as f: run_channel = f.read() with open(path + 'script.js') as f: JS = f.read() self.page().runJavaScript(run_channel) self.page().runJavaScript(JS) self.page().runJavaScript("initialize()") def waitUntilReady(self): while not self.initialized: QApplication.processEvents() def runScript(self, script): return self.page().runJavaScript(script) def centerAt(self, latitude, longitude): self.page().runJavaScript("osm_setCenter({}, {})".format( latitude, longitude)) def setZoom(self, zoom): self.page().runJavaScript("osm_setZoom({})".format(zoom)) def center(self): center = self.page().runJavaScript("osm_getCenter()") return center['lat'], center['lng'] def addMarker(self, key, latitude, longitude, **extra): return self.page().runJavaScript("osm_addMarker(key={!r}," "latitude= {}, " "longitude= {}, {});".format( key, latitude, longitude, json.dumps(extra))) def removeMarker(self, key): return self.page().runJavaScript( "osm_deleteMarker(key={!r});".format(key)) def addCircle(self, latitude, longitude, radius): return self.page().runJavaScript("osm_addCircle({},{},{})".format( latitude, longitude, radius)) def removeCircle(self, latitude, longitude, radius): return self.page.runJavaScript("osm_removeCircle()") def moveMarker(self, key, latitude, longitude): self.page().runJavaScript("osm_moveMarker(key={!r}," "latitude= {}, " "longitude= {});".format( key, latitude, longitude)) def positionMarker(self, key): return tuple(self.page().runJavaScript( "osm_posMarker(key={!r});".format(key))) #----------marker signals @pyqtSlot(str, float, float) def markerIsMoved(self, key, lat, lng): self.markerMoved.emit(key, lat, lng) @pyqtSlot(str, float, float) def markerIsClicked(self, key, lat, lng): self.markerClicked.emit(key, lat, lng) @pyqtSlot(str, float, float) def markerIsDBClicked(self, key, lat, lng): self.markerDoubleClicked.emit(key, lat, lng) @pyqtSlot(str, float, float) def markerIsRClicked(self, key, lat, lng): self.markerRightClicked.emit(key, lat, lng) #-----------map signals @pyqtSlot(float, float) def mapIsMoved(self, lat, lng): self.mapMoved.emit(lat, lng) @pyqtSlot(float, float) def mapIsClicked(self, lat, lng): self.mapClicked.emit(lat, lng) @pyqtSlot(float, float) def mapIsDoubleClicked(self, lat, lng): self.mapDoubleClicked.emit(lat, lng) @pyqtSlot(float, float) def mapIsRightClicked(self, lat, lng): self.mapRightClicked.emit(lat, lng)
class MostWatchedItems(QWidget): def __init__(self, parent=None): super(MostWatchedItems, self).__init__(parent) self.ui = Ui_MostWatchedItems() self.ui.setupUi(self) self.ui.tableWidget.setColumnCount(5) self.ui.tableWidget.setColumnWidth(0, 160) self.ui.tableWidget.setColumnWidth(1, 480) self.categoryID = '' self.manager = QNetworkAccessManager(self) diskCache = QNetworkDiskCache(self) diskCache.setCacheDirectory("cache") self.manager.setCache(diskCache) self.manager.finished.connect(self.on_finished) self.manager.sslErrors.connect(self.on_sslErrors) self.replyMap = dict() @pyqtSlot(bool) def on_selectPushButton_clicked(self, checked): dialog = CategoryInfoDialog.instance() res = dialog.exec() if res == QDialog.Accepted: self.ui.categoryLineEdit.setText('%s -> %s' % (dialog.categoryID(), dialog.categoryNamePath())) self.categoryID = dialog.categoryID() @pyqtSlot(bool) def on_clearPushButton_clicked(self, checked): self.ui.categoryLineEdit.setText('') self.categoryID = '' @pyqtSlot(bool) def on_wipePushButton_clicked(self, checked): while self.ui.tableWidget.rowCount() > 0: self.ui.tableWidget.removeRow(0) @pyqtSlot(bool) def on_searchPushButton_clicked(self, checked): if self.categoryID != '' and self.categoryID != '-1': merchandising = Merchandising(warnings = False) response = merchandising.execute( 'getMostWatchedItems', { 'categoryId': self.categoryID, 'maxResults': self.ui.spinBox.value() } ) reply = response.reply itemRecommendations = reply.itemRecommendations.item row = self.ui.tableWidget.rowCount() for item in itemRecommendations: self.ui.tableWidget.insertRow(row) imageUrl = 'http://thumbs3.ebaystatic.com/pict/%s4040.jpg' % item.itemId request = QNetworkRequest(QUrl(imageUrl)) request.setAttribute(QNetworkRequest.CacheLoadControlAttribute, QNetworkRequest.PreferCache) reply = self.manager.get(request) self.replyMap[reply] = row viewItemURL = QLabel() viewItemURL.setOpenExternalLinks(True) #viewItemURL.setTextInteractionFlags(Qt.TextBrowserInteraction) title = '<a href="%s">%s</a>' % (item.viewItemURL, item.title) viewItemURL.setText(title) self.ui.tableWidget.setCellWidget(row, 1, viewItemURL) self.ui.tableWidget.setItem(row, 2, QTableWidgetItem(item.primaryCategoryName)) self.ui.tableWidget.setItem(row, 3, QTableWidgetItem(item.buyItNowPrice.value)) self.ui.tableWidget.setItem(row, 4, QTableWidgetItem(item.watchCount)) row += 1 @pyqtSlot(QNetworkReply) def on_finished(self, reply): if reply in self.replyMap: row = self.replyMap.get(reply) del self.replyMap[reply] pixmap = QPixmap() pixmap.loadFromData(reply.readAll()) image = QLabel() image.setPixmap(pixmap) self.ui.tableWidget.setCellWidget(row, 0, image) self.ui.tableWidget.setRowHeight(row, 160) @pyqtSlot(QNetworkReply, list) def on_sslErrors(self, reply, errors): if reply in self.replyMap: del self.replyMap[reply]
class SlippyMap(QObject): def __init__(self, parent: QObject = None) -> None: super().__init__(parent) self.width: int = 400 self.height: int = 300 self.zoom: int = 15 self.latitude: float = 59.9138204 self.longitude: float = 10.7387413 self.m_offset = QPoint() self.m_tilesRect = QRect() self.m_emptyTile = QPixmap(tdim, tdim) self.m_emptyTile.fill(Qt.lightGray) self.m_tilePixmaps: typing.Dict[QPointH, QPixmap] = dict() self.m_manager = QNetworkAccessManager() self.m_url = QUrl() cache = QNetworkDiskCache() cache.setCacheDirectory( QStandardPaths.writableLocation(QStandardPaths.CacheLocation) ) self.m_manager.setCache(cache) self.m_manager.finished.connect(self.handleNetworkData) def invalidate(self) -> None: if self.width <= 0 or self.height <= 0: return ct = tileForCoordinate(self.latitude, self.longitude, self.zoom) tx = ct.x() ty = ct.y() # top-left corner of the center tile xp = self.width / 2 - (tx - math.floor(tx)) * tdim yp = self.height / 2 - (ty - math.floor(ty)) * tdim xa = (xp + tdim - 1) / tdim ya = (yp + tdim - 1) / tdim xs = int(tx) - xa ys = int(ty) - ya # offset for top-left tile self.m_offset = QPoint(xp - xa * tdim, yp - ya * tdim) # last tile vertical and horizontal xe = int(tx) + (self.width - xp - 1) / tdim ye = int(ty) + (self.height - yp - 1) / tdim # build a rect self.m_tilesRect = QRect(xs, ys, xe - xs + 1, ye - ys + 1) if self.m_url.isEmpty(): self.download() self.updated.emit(QRect(0, 0, self.width, self.height)) def render(self, painter: QPainter, rect: QRect) -> None: for x in range(self.m_tilesRect.width() + 1): for y in range(self.m_tilesRect.height() + 1): tp = QPoint(x + self.m_tilesRect.left(), y + self.m_tilesRect.top()) box = self.tileRect(tp) if rect.intersects(box): painter.drawPixmap( box, self.m_tilePixmaps.get(QPointH(tp), self.m_emptyTile) ) def pan(self, delta: QPoint) -> None: dx = QPointF(delta) / float(tdim) center = tileForCoordinate(self.latitude, self.longitude, self.zoom) - dx self.latitude = latitudeFromTile(center.y(), self.zoom) self.longitude = longitudeFromTile(center.x(), self.zoom) self.invalidate() updated = pyqtSignal(QRect) @pyqtSlot(QNetworkReply) def handleNetworkData(self, reply: QNetworkReply) -> None: img = QImage() tp = reply.request().attribute(QNetworkRequest.User) if not reply.error(): if not img.load(reply, ""): img = QImage() reply.deleteLater() self.m_tilePixmaps[QPointH(tp)] = ( self.m_emptyTile if img.isNull() else QPixmap.fromImage(img) ) self.updated.emit(self.tileRect(tp)) # purge unused spaces bound = self.m_tilesRect.adjusted(-2, -2, 2, 2) self.m_tilePixmaps = { tp: pixmap for tp, pixmap in self.m_tilePixmaps.items() if bound.contains(tp) } self.download() @pyqtSlot() def download(self): grab = QPoint(0, 0) for x in range(self.m_tilesRect.width() + 1): for y in range(self.m_tilesRect.height() + 1): tp = self.m_tilesRect.topLeft() + QPoint(x, y) if QPointH(tp) not in self.m_tilePixmaps: grab = tp break if grab == QPoint(0, 0): self.m_url = QUrl() return path = "http://tile.openstreetmap.org/%d/%d/%d.png" self.m_url = QUrl(path % (self.zoom, grab.x(), grab.y())) request = QNetworkRequest() request.setUrl(self.m_url) request.setRawHeader(b"User-Agent", b"The Qt Company (Qt) Graphics Dojo 1.0") request.setAttribute(QNetworkRequest.User, grab) self.m_manager.get(request) def tileRect(self, tp: QPoint): t = tp - self.m_tilesRect.topLeft() x = t.x() * tdim + self.m_offset.x() y = t.y() * tdim + self.m_offset.y() return QRect(x, y, tdim, tdim)