From 3a70d9eb53d7c0a003c8c3ee80a7577398b4d68d Mon Sep 17 00:00:00 2001 From: Jim Easterbrook Date: Wed, 8 May 2024 08:55:41 +0100 Subject: [PATCH 1/6] Remove redundant importlib imports --- src/photini/pyqt.py | 3 +-- src/photini/scripts.py | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/photini/pyqt.py b/src/photini/pyqt.py index 52fa94d2..4ded499d 100644 --- a/src/photini/pyqt.py +++ b/src/photini/pyqt.py @@ -1,6 +1,6 @@ ## Photini - a simple photo metadata editor. ## http://github.com/jim-easterbrook/Photini -## Copyright (C) 2015-23 Jim Easterbrook jim@jim-easterbrook.me.uk +## Copyright (C) 2015-24 Jim Easterbrook jim@jim-easterbrook.me.uk ## ## This program is free software: you can redistribute it and/or ## modify it under the terms of the GNU General Public License as @@ -19,7 +19,6 @@ from collections import namedtuple from contextlib import contextmanager from functools import wraps -import importlib import logging import os import sys diff --git a/src/photini/scripts.py b/src/photini/scripts.py index 2f2c1b34..ce47dddb 100644 --- a/src/photini/scripts.py +++ b/src/photini/scripts.py @@ -16,7 +16,6 @@ ## along with this program. If not, see ## . -import importlib import logging from optparse import OptionParser import os From ba5615678075f43d601ebdc72498c9bad103149a Mon Sep 17 00:00:00 2001 From: Jim Easterbrook Date: Wed, 8 May 2024 08:57:39 +0100 Subject: [PATCH 2/6] Add debugging info --- src/photini/photinimap.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/photini/photinimap.py b/src/photini/photinimap.py index e8081afe..a19602c4 100644 --- a/src/photini/photinimap.py +++ b/src/photini/photinimap.py @@ -127,6 +127,7 @@ def __init__(self, *args, call_handler=None, transient=False, **kwds): self.web_channel.registerObject('python', self.call_handler) self.profile().setCachePath( os.path.join(appdirs.user_cache_dir('photini'), 'WebEngine')) + logger.debug('user agent: %s', self.profile().httpUserAgent()) @catch_all def acceptNavigationRequest(self, url, type_, isMainFrame): From c61650a527d1fac87e302645825dcfdfc405b66b Mon Sep 17 00:00:00 2001 From: Jim Easterbrook Date: Wed, 8 May 2024 09:13:21 +0100 Subject: [PATCH 3/6] More efficient Google Map markers Only need to change the marker icon source, not generate a whole new icon, when its selected status changes. --- src/photini/data/map/googlemap.js | 32 +++++++++++-------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/src/photini/data/map/googlemap.js b/src/photini/data/map/googlemap.js index 07173227..fbd6c90c 100644 --- a/src/photini/data/map/googlemap.js +++ b/src/photini/data/map/googlemap.js @@ -96,30 +96,25 @@ function fitPoints(points) map.panTo(bounds.getCenter()); } -function newGPSCircle(active) -{ - var result = document.createElement("img"); - result.src = active ? 'circle_red.png' : 'circle_blue.png'; - result.style.transform = 'translate(0.5px,8.5px)'; - return result; -} - function plotGPS(points) { for (var i = 0; i < points.length; i++) { var latlng = new google.maps.LatLng(points[i][0], points[i][1]); var id = points[i][2]; + var circle = document.createElement("img"); + circle.src = 'circle_blue.png'; + circle.style.transform = 'translate(0.5px,8.5px)'; gpsMarkers[id] = new google.maps.marker.AdvancedMarkerElement({ - map: map, position: latlng, - content: newGPSCircle(false), zIndex: 2}); + map: map, position: latlng, content: circle, zIndex: 2}); } } function enableGPS(ids) { for (var id in gpsMarkers) - gpsMarkers[id].content = newGPSCircle(ids.includes(id)); + gpsMarkers[id].content.src = + ids.includes(id) ? 'circle_red.png' : 'circle_blue.png'; gpsMarkers[id].zIndex = ids.includes(id) ? 3 : 2; } @@ -130,25 +125,20 @@ function clearGPS() gpsMarkers = {}; } -function newIcon(active) -{ - var result = document.createElement("img"); - result.src = active ? 'pin_red.png' : 'pin_grey.png'; - result.style.transform = 'translate(1.5px,3px)'; - return result; -} - function enableMarker(id, active) { var marker = markers[id]; - marker.content = newIcon(active); + marker.content.src = active ? 'pin_red.png' : 'pin_grey.png'; marker.zIndex = active ? 1 : 0; } function addMarker(id, lat, lng, active) { + var icon = document.createElement("img"); + icon.src = 'pin_grey.png'; + icon.style.transform = 'translate(1.5px,3px)'; var marker = new google.maps.marker.AdvancedMarkerElement({ - content: newIcon(false), + content: icon, position: new google.maps.LatLng(lat, lng), map: map, gmpDraggable: true, From 96256474b839d6e24aaaf596c4c5b1bed3408d6e Mon Sep 17 00:00:00 2001 From: Jim Easterbrook Date: Wed, 8 May 2024 09:29:03 +0100 Subject: [PATCH 4/6] Let each map module define the javascript file name --- src/photini/bingmap.py | 3 ++- src/photini/googlemap.py | 3 ++- src/photini/mapboxmap.py | 5 +++-- src/photini/photinimap.py | 2 -- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/photini/bingmap.py b/src/photini/bingmap.py index 60ed848a..166b967f 100644 --- a/src/photini/bingmap.py +++ b/src/photini/bingmap.py @@ -122,7 +122,8 @@ def get_head(self): url += '&branch=experimental' return ''' '''.format(url) + + '''.format(url) @catch_all def new_status(self, status): diff --git a/src/photini/googlemap.py b/src/photini/googlemap.py index 7f0c9941..79b80a4f 100644 --- a/src/photini/googlemap.py +++ b/src/photini/googlemap.py @@ -116,4 +116,5 @@ def get_head(self): url += '®ion=' + region return ''' '''.format(url) + + '''.format(url) diff --git a/src/photini/mapboxmap.py b/src/photini/mapboxmap.py index 0fd1bbdf..5bd101c8 100644 --- a/src/photini/mapboxmap.py +++ b/src/photini/mapboxmap.py @@ -115,5 +115,6 @@ def get_head(self): '''.format(key=self.api_key, - url='https://api.mapbox.com/mapbox.js/v3.3.1') + + '''.format( + key=self.api_key, url='https://api.mapbox.com/mapbox.js/v3.3.1') diff --git a/src/photini/photinimap.py b/src/photini/photinimap.py index a19602c4..ab0eb0b1 100644 --- a/src/photini/photinimap.py +++ b/src/photini/photinimap.py @@ -301,7 +301,6 @@ def initialise(self): {initialize} {head} -
@@ -326,7 +325,6 @@ def initialise(self): ''' page = page.format( head = self.get_head(), - script = self.__module__.split('.')[-1], initialize = initialize.format(lat=lat, lng=lng, zoom=zoom)) QtWidgets.QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) self.widgets['map'].setHtml( From 7c7e8d10af1c64c81982a7011e78ac267d27e1bb Mon Sep 17 00:00:00 2001 From: Jim Easterbrook Date: Wed, 8 May 2024 10:41:36 +0100 Subject: [PATCH 5/6] Use old Google Map marker if Chrome < v86 The new markers use a 'replaceChildren' method that was added in Chrome v86. --- src/photini/data/map/googlemap_legacy.js | 214 +++++++++++++++++++++++ src/photini/googlemap.py | 18 +- 2 files changed, 229 insertions(+), 3 deletions(-) create mode 100644 src/photini/data/map/googlemap_legacy.js diff --git a/src/photini/data/map/googlemap_legacy.js b/src/photini/data/map/googlemap_legacy.js new file mode 100644 index 00000000..d6efc770 --- /dev/null +++ b/src/photini/data/map/googlemap_legacy.js @@ -0,0 +1,214 @@ +// Photini - a simple photo metadata editor. +// http://github.com/jim-easterbrook/Photini +// Copyright (C) 2012-24 Jim Easterbrook jim@jim-easterbrook.me.uk +// +// This program is free software: you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see +// . + +// See https://developers.google.com/maps/documentation/javascript/overview + +// This "legacy" version does not use AdvancedMarkerElement + +var map; +var markers = {}; +var gpsMarkers = {}; +var icon_on; +var icon_off; +var gpsBlueCircle; +var gpsRedCircle; + +function loadMap(lat, lng, zoom) +{ + var mapOptions = { + center: new google.maps.LatLng(lat, lng), + fullscreenControl: false, + scaleControl: true, + streetViewControl: false, + tilt: 0, + zoom: zoom, + maxZoom: 20, + mapId: "ce7cafb5b0de6e31", + mapTypeId: google.maps.MapTypeId.ROADMAP, + mapTypeControl: true, + mapTypeControlOptions: { + style: google.maps.MapTypeControlStyle.DROPDOWN_MENU, + }, + }; + map = new google.maps.Map(document.getElementById("mapDiv"), mapOptions); + google.maps.event.addListener(map, 'idle', newBounds); + var anchor = new google.maps.Point(11, 35); + icon_on = {anchor: anchor, url: 'pin_red.png'}; + icon_off = {anchor: anchor, url: 'pin_grey.png'}; + anchor = new google.maps.Point(5, 5); + gpsBlueCircle = {anchor: anchor, url: 'circle_blue.png'}; + gpsRedCircle = {anchor: anchor, url: 'circle_red.png'}; + python.initialize_finished(); +} + +function newBounds() +{ + var centre = map.getCenter(); + var bounds = map.getBounds(); + var sw = bounds.getSouthWest(); + var ne = bounds.getNorthEast(); + python.new_status({ + centre: [centre.lat(), centre.lng()], + bounds: [ne.lat(), ne.lng(), sw.lat(), sw.lng()], + zoom: map.getZoom(), + }); +} + +function setView(lat, lng, zoom) +{ + map.setZoom(zoom) + map.panTo(new google.maps.LatLng(lat, lng)); +} + +function adjustBounds(north, east, south, west) +{ + map.fitBounds({north: north, east: east, south: south, west: west}); +} + +function fitPoints(points) +{ + var bounds = new google.maps.LatLngBounds(); + for (var i = 0; i < points.length; i++) + { + bounds.extend({lat: points[i][0], lng: points[i][1]}); + } + var mapBounds = map.getBounds(); + var mapSpan = mapBounds.toSpan(); + var ne = bounds.getNorthEast(); + var sw = bounds.getSouthWest(); + bounds.extend({lat: ne.lat() + (mapSpan.lat() * 0.13), + lng: ne.lng() + (mapSpan.lng() * 0.04)}); + bounds.extend({lat: sw.lat() - (mapSpan.lat() * 0.04), + lng: sw.lng() - (mapSpan.lng() * 0.04)}); + ne = bounds.getNorthEast(); + sw = bounds.getSouthWest(); + if (mapBounds.contains(ne) && mapBounds.contains(sw)) + return; + var span = bounds.toSpan(); + if (span.lat() > mapSpan.lat() || span.lng() > mapSpan.lng()) + map.fitBounds(bounds); + else if (mapBounds.intersects(bounds)) + map.panToBounds(bounds); + else + map.panTo(bounds.getCenter()); +} + +function plotGPS(points) +{ + for (var i = 0; i < points.length; i++) + { + var latlng = new google.maps.LatLng(points[i][0], points[i][1]); + var id = points[i][2]; + var circle = document.createElement("img"); + circle.src = 'circle_blue.png'; + circle.style.transform = 'translate(0.5px,8.5px)'; + gpsMarkers[id] = new google.maps.Marker({ + map: map, position: latlng, + icon: gpsBlueCircle, zIndex: 2, clickable: false}); + } +} + +function enableGPS(ids) +{ + for (var id in gpsMarkers) + if (ids.includes(id)) + gpsMarkers[id].setOptions({icon: gpsRedCircle, zIndex: 3}); + else + gpsMarkers[id].setOptions({icon: gpsBlueCircle, zIndex: 2}); +} + +function clearGPS() +{ + for (var id in gpsMarkers) + gpsMarkers[id].setMap(null); + gpsMarkers = {}; +} + +function enableMarker(id, active) +{ + var marker = markers[id]; + if (active) + marker.setOptions({icon: icon_on, zIndex: 1}); + else + marker.setOptions({icon: icon_off, zIndex: 0}); +} + +function addMarker(id, lat, lng, active) +{ + var marker = new google.maps.Marker({ + icon: icon_off, + position: new google.maps.LatLng(lat, lng), + map: map, + draggable: true, + crossOnDrag: false, + }); + markers[id] = marker; + google.maps.event.addListener(marker, 'click', markerClick); + google.maps.event.addListener(marker, 'dragstart', markerClick); + google.maps.event.addListener(marker, 'drag', markerDrag); + google.maps.event.addListener(marker, 'dragend', markerDragEnd); + enableMarker(id, active) +} + +function markerToId(marker) +{ + for (var id in markers) + if (markers[id] == marker) + return id; +} + +function markerClick(event) +{ + python.marker_click(markerToId(this)); +} + +function markerDrag(event) +{ + var loc = event.latLng; + python.marker_drag(loc.lat(), loc.lng()); +} + +function markerDragEnd(event) +{ + var loc = event.latLng; + python.marker_drag_end(loc.lat(), loc.lng(), markerToId(this)); +} + +function markerDrop(x, y) +{ + // convert x, y to world coordinates + var scale = Math.pow(2, map.getZoom()); + var nw = new google.maps.LatLng( + map.getBounds().getNorthEast().lat(), + map.getBounds().getSouthWest().lng() + ); + var worldCoordinateNW = map.getProjection().fromLatLngToPoint(nw); + var worldX = worldCoordinateNW.x + (x / scale); + var worldY = worldCoordinateNW.y + (y / scale); + // convert world coordinates to lat & lng + var position = map.getProjection().fromPointToLatLng( + new google.maps.Point(worldX, worldY)); + python.marker_drop(position.lat(), position.lng()); +} + +function delMarker(id) +{ + google.maps.event.clearInstanceListeners(markers[id]); + markers[id].setMap(null); + delete markers[id]; +} diff --git a/src/photini/googlemap.py b/src/photini/googlemap.py index 79b80a4f..13beb6f5 100644 --- a/src/photini/googlemap.py +++ b/src/photini/googlemap.py @@ -18,6 +18,7 @@ import locale import logging +import re import requests @@ -101,10 +102,21 @@ def get_geocoder(self): return GoogleGeocoder(parent=self) def get_head(self): + user_agent = self.widgets['map'].page().profile().httpUserAgent() + match = re.search(r'\sChrome/(\d+)\.', user_agent) + if match: + chrome_version = int(match.group(1)) + else: + chrome_version = 0 url = ('http://maps.googleapis.com/maps/api/js' '?callback=initialize' - '&loading=async' - '&libraries=marker') + '&loading=async') + # AdvancedMarkerElement requires Chrome v86+ + if chrome_version >= 86: + url += '&libraries=marker' + script = 'googlemap.js' + else: + script = 'googlemap_legacy.js' if self.app.options.test: url += '&v=beta' url += '&key=' + self.api_key @@ -117,4 +129,4 @@ def get_head(self): return ''' - '''.format(url) + '''.format(url, script) From bd97aaf5476ab18aac2e0f3faf7b082ab2f874df Mon Sep 17 00:00:00 2001 From: Jim Easterbrook Date: Wed, 8 May 2024 10:57:31 +0100 Subject: [PATCH 6/6] Update chenge log --- CHANGELOG.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index a2fa73ac..095588a6 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -16,6 +16,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . +Changes in v2024.5.0: + 1/ Use deprecated Google Map marker with QtWebEngline v5.15.2 or lower. + 2/ Copy files from camera in chunks. + Changes in v2024.4.0: 1/ Google Map no longer used deprecated marker. 2/ Improved handling of multiple language configurations.