mirror of
https://github.com/EDCD/EDMarketConnector.git
synced 2025-04-14 08:17:13 +03:00
First pass utilising 'futurize' to do most of the work. There's an issue with ur'\"' in l10n.py which I'm not sure how to properly fix. This now has errors when hitting the 'Update' button.
172 lines
7.7 KiB
Python
172 lines
7.7 KiB
Python
from sys import platform
|
|
import webbrowser
|
|
|
|
import tkinter as tk
|
|
from tkinter import ttk
|
|
from tkinter import font as tkFont
|
|
|
|
if platform == 'win32':
|
|
import subprocess
|
|
import ctypes
|
|
from ctypes.wintypes import *
|
|
|
|
HKEY_CLASSES_ROOT = 0x80000000
|
|
HKEY_CURRENT_USER = 0x80000001
|
|
|
|
KEY_READ = 0x00020019
|
|
KEY_ALL_ACCESS = 0x000F003F
|
|
|
|
REG_SZ = 1
|
|
REG_DWORD = 4
|
|
REG_MULTI_SZ = 7
|
|
|
|
RegOpenKeyEx = ctypes.windll.advapi32.RegOpenKeyExW
|
|
RegOpenKeyEx.restype = LONG
|
|
RegOpenKeyEx.argtypes = [HKEY, LPCWSTR, DWORD, DWORD, ctypes.POINTER(HKEY)]
|
|
|
|
RegCloseKey = ctypes.windll.advapi32.RegCloseKey
|
|
RegCloseKey.restype = LONG
|
|
RegCloseKey.argtypes = [HKEY]
|
|
|
|
RegQueryValueEx = ctypes.windll.advapi32.RegQueryValueExW
|
|
RegQueryValueEx.restype = LONG
|
|
RegQueryValueEx.argtypes = [HKEY, LPCWSTR, LPCVOID, ctypes.POINTER(DWORD), LPCVOID, ctypes.POINTER(DWORD)]
|
|
|
|
|
|
# A clickable ttk Label
|
|
#
|
|
# In addition to standard ttk.Label arguments, takes the following arguments:
|
|
# url: The URL as a string that the user will be sent to on clicking on non-empty label text. If url is a function it will be called on click with the current label text and should return the URL as a string.
|
|
# underline: If True/False the text is always/never underlined. If None (the default) the text is underlined only on hover.
|
|
# popup_copy: Whether right-click on non-empty label text pops up a context menu with a 'Copy' option. Defaults to no context menu. If popup_copy is a function it will be called with the current label text and should return a boolean.
|
|
#
|
|
class HyperlinkLabel(platform == 'darwin' and tk.Label or ttk.Label, object):
|
|
|
|
def __init__(self, master=None, **kw):
|
|
self.url = 'url' in kw and kw.pop('url') or None
|
|
self.popup_copy = kw.pop('popup_copy', False)
|
|
self.underline = kw.pop('underline', None) # override ttk.Label's underline
|
|
self.foreground = kw.get('foreground') or 'blue'
|
|
self.disabledforeground = kw.pop('disabledforeground', ttk.Style().lookup('TLabel', 'foreground', ('disabled',))) # ttk.Label doesn't support disabledforeground option
|
|
|
|
if platform == 'darwin':
|
|
# Use tk.Label 'cos can't set ttk.Label background - http://www.tkdocs.com/tutorial/styles.html#whydifficult
|
|
kw['background'] = kw.pop('background', 'systemDialogBackgroundActive')
|
|
kw['anchor'] = kw.pop('anchor', tk.W) # like ttk.Label
|
|
tk.Label.__init__(self, master, **kw)
|
|
else:
|
|
ttk.Label.__init__(self, master, **kw)
|
|
|
|
self.bind('<Button-1>', self._click)
|
|
|
|
self.menu = tk.Menu(None, tearoff=tk.FALSE)
|
|
self.menu.add_command(label=_('Copy'), command = self.copy) # As in Copy and Paste
|
|
self.bind(platform == 'darwin' and '<Button-2>' or '<Button-3>', self._contextmenu)
|
|
|
|
self.bind('<Enter>', self._enter)
|
|
self.bind('<Leave>', self._leave)
|
|
|
|
# set up initial appearance
|
|
self.configure(state = kw.get('state', tk.NORMAL),
|
|
text = kw.get('text'),
|
|
font = kw.get('font', ttk.Style().lookup('TLabel', 'font')))
|
|
|
|
# Change cursor and appearance depending on state and text
|
|
def configure(self, cnf=None, **kw):
|
|
# This class' state
|
|
for thing in ['url', 'popup_copy', 'underline']:
|
|
if thing in kw:
|
|
setattr(self, thing, kw.pop(thing))
|
|
for thing in ['foreground', 'disabledforeground']:
|
|
if thing in kw:
|
|
setattr(self, thing, kw[thing])
|
|
|
|
# Emulate disabledforeground option for ttk.Label
|
|
if kw.get('state') == tk.DISABLED:
|
|
if 'foreground' not in kw:
|
|
kw['foreground'] = self.disabledforeground
|
|
elif 'state' in kw:
|
|
if 'foreground' not in kw:
|
|
kw['foreground'] = self.foreground
|
|
|
|
if 'font' in kw:
|
|
self.font_n = kw['font']
|
|
self.font_u = tkFont.Font(font = self.font_n)
|
|
self.font_u.configure(underline = True)
|
|
kw['font'] = self.underline is True and self.font_u or self.font_n
|
|
|
|
if 'cursor' not in kw:
|
|
if (kw['state'] if 'state' in kw else str(self['state'])) == tk.DISABLED:
|
|
kw['cursor'] = 'arrow' # System default
|
|
elif self.url and (kw['text'] if 'text' in kw else self['text']):
|
|
kw['cursor'] = platform=='darwin' and 'pointinghand' or 'hand2'
|
|
else:
|
|
kw['cursor'] = (platform=='darwin' and 'notallowed') or (platform=='win32' and 'no') or 'circle'
|
|
|
|
super(HyperlinkLabel, self).configure(cnf, **kw)
|
|
|
|
def __setitem__(self, key, value):
|
|
self.configure(None, **{key: value})
|
|
|
|
def _enter(self, event):
|
|
if self.url and self.underline is not False and str(self['state']) != tk.DISABLED:
|
|
super(HyperlinkLabel, self).configure(font = self.font_u)
|
|
|
|
def _leave(self, event):
|
|
if not self.underline:
|
|
super(HyperlinkLabel, self).configure(font = self.font_n)
|
|
|
|
def _click(self, event):
|
|
if self.url and self['text'] and str(self['state']) != tk.DISABLED:
|
|
url = self.url(self['text']) if callable(self.url) else self.url
|
|
if url:
|
|
self._leave(event) # Remove underline before we change window to browser
|
|
openurl(url)
|
|
|
|
def _contextmenu(self, event):
|
|
if self['text'] and (self.popup_copy(self['text']) if callable(self.popup_copy) else self.popup_copy):
|
|
self.menu.post(platform == 'darwin' and event.x_root + 1 or event.x_root, event.y_root)
|
|
|
|
def copy(self):
|
|
self.clipboard_clear()
|
|
self.clipboard_append(self['text'])
|
|
|
|
|
|
def openurl(url):
|
|
if platform == 'win32':
|
|
# On Windows webbrowser.open calls os.startfile which calls ShellExecute which can't handle long arguments,
|
|
# so discover and launch the browser directly.
|
|
# https://blogs.msdn.microsoft.com/oldnewthing/20031210-00/?p=41553
|
|
|
|
hkey = HKEY()
|
|
cls = 'http'
|
|
if not RegOpenKeyEx(HKEY_CURRENT_USER, r'Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice', 0, KEY_READ, ctypes.byref(hkey)):
|
|
typ = DWORD()
|
|
size = DWORD()
|
|
if not RegQueryValueEx(hkey, 'ProgId', 0, ctypes.byref(typ), None, ctypes.byref(size)) and typ.value in [REG_SZ, REG_MULTI_SZ]:
|
|
buf = ctypes.create_unicode_buffer(size.value / 2)
|
|
if not RegQueryValueEx(hkey, 'ProgId', 0, ctypes.byref(typ), buf, ctypes.byref(size)):
|
|
if buf.value in ['IE.HTTP', 'AppXq0fevzme2pys62n3e0fbqa7peapykr8v']:
|
|
# IE and Edge can't handle long arguments so just use webbrowser.open and hope
|
|
# https://blogs.msdn.microsoft.com/ieinternals/2014/08/13/url-length-limits/
|
|
cls = None
|
|
else:
|
|
cls = buf.value
|
|
RegCloseKey(hkey)
|
|
|
|
if cls and not RegOpenKeyEx(HKEY_CLASSES_ROOT, r'%s\shell\open\command' % cls, 0, KEY_READ, ctypes.byref(hkey)):
|
|
typ = DWORD()
|
|
size = DWORD()
|
|
if not RegQueryValueEx(hkey, None, 0, ctypes.byref(typ), None, ctypes.byref(size)) and typ.value in [REG_SZ, REG_MULTI_SZ]:
|
|
buf = ctypes.create_unicode_buffer(size.value / 2)
|
|
if not RegQueryValueEx(hkey, None, 0, ctypes.byref(typ), buf, ctypes.byref(size)) and 'iexplore' not in buf.value.lower():
|
|
RegCloseKey(hkey)
|
|
if '%1' in buf.value:
|
|
subprocess.Popen(buf.value.replace('%1', url))
|
|
else:
|
|
subprocess.Popen('%s "%s"' % (buf.value, url))
|
|
return
|
|
RegCloseKey(hkey)
|
|
|
|
webbrowser.open(url)
|