From a2687277ff051ea8c3156ad0c0137f93c9900e1f Mon Sep 17 00:00:00 2001
From: Jonathan Harris <jonathan@marginal.org.uk>
Date: Sun, 19 Jun 2016 19:52:48 +0100
Subject: [PATCH] Rationalise verification process

---
 EDMarketConnector.py | 16 ++++++------
 companion.py         |  9 +++++--
 stats.py             | 58 +++++++++-----------------------------------
 3 files changed, 26 insertions(+), 57 deletions(-)

diff --git a/EDMarketConnector.py b/EDMarketConnector.py
index 18052819..5876c4cc 100755
--- a/EDMarketConnector.py
+++ b/EDMarketConnector.py
@@ -3,6 +3,7 @@
 
 import sys
 from sys import platform
+from functools import partial
 import json
 from os import mkdir
 from os.path import expanduser, isdir, join
@@ -143,7 +144,7 @@ class AppWindow:
             self.menubar.add_cascade(menu=self.edit_menu)
             self.w.bind('<Command-c>', self.copy)
             self.view_menu = tk.Menu(self.menubar, name='view')
-            self.view_menu.add_command(state=tk.DISABLED, command=lambda:stats.StatsDialog(self.w, self.session))
+            self.view_menu.add_command(command=lambda:stats.StatsDialog(self))
             self.menubar.add_cascade(menu=self.view_menu)
             window_menu = tk.Menu(self.menubar, name='window')
             self.menubar.add_cascade(menu=window_menu)
@@ -157,7 +158,7 @@ class AppWindow:
             self.w.protocol("WM_DELETE_WINDOW", self.w.withdraw)	# close button shouldn't quit app
         else:
             self.file_menu = self.view_menu = tk.Menu(self.menubar, tearoff=tk.FALSE)
-            self.file_menu.add_command(state=tk.DISABLED, command=lambda:stats.StatsDialog(self.w, self.session))
+            self.file_menu.add_command(command=lambda:stats.StatsDialog(self))
             self.file_menu.add_command(command=lambda:self.updater.checkForUpdates())
             self.file_menu.add_command(command=lambda:prefs.PreferencesDialog(self.w, self.postprefs))
             self.file_menu.add_separator()
@@ -287,9 +288,7 @@ class AppWindow:
         self.button['state'] = self.theme_button['state'] = tk.DISABLED
         self.w.update_idletasks()
         try:
-            self.view_menu.entryconfigure(0, state=tk.DISABLED)	# Status
             self.session.login(config.get('username'), config.get('password'))
-            self.view_menu.entryconfigure(0, state=tk.NORMAL)	# Status
             self.status['text'] = ''
         except companion.VerificationRequired:
             # don't worry about authentication now - prompt on query
@@ -315,7 +314,7 @@ class AppWindow:
         self.cooldown()
 
     # callback after verification code
-    def verify(self, code):
+    def verify(self, callback, code):
         try:
             self.session.verify(code)
             config.save()	# Save settings now for use by command-line app
@@ -324,7 +323,7 @@ class AppWindow:
             self.button['state'] = self.theme_button['state'] = tk.NORMAL
             self.status['text'] = unicode(e)
         else:
-            return self.getandsend()	# try again
+            return callback()	# try again
 
     def getandsend(self, event=None, retrying=False):
 
@@ -341,7 +340,7 @@ class AppWindow:
             self.cmdr['text'] = self.system['text'] = self.station['text'] = ''
             self.system['image'] = ''
             self.status['text'] = _('Fetching data...')
-            self.theme_button['state'] = tk.DISABLED
+            self.button['state'] = self.theme_button['state'] = tk.DISABLED
             self.edit_menu.entryconfigure(0, state=tk.DISABLED)	# Copy
             self.w.update_idletasks()
 
@@ -370,7 +369,6 @@ class AppWindow:
                 self.station['text'] = data.get('commander') and data.get('commander').get('docked') and data.get('lastStarport') and data.get('lastStarport').get('name') or (EDDB.system(self.system['text']) and self.STATION_UNDOCKED or '')
                 self.status['text'] = ''
                 self.edit_menu.entryconfigure(0, state=tk.NORMAL)	# Copy
-                self.view_menu.entryconfigure(0, state=tk.NORMAL)	# Status
 
                 if data['lastStarport'].get('commodities'):
                     # Fixup anomalies in the commodity data
@@ -447,7 +445,7 @@ class AppWindow:
                                 self.status['text'] = ''
 
         except companion.VerificationRequired:
-            return prefs.AuthenticationDialog(self.w, self.verify)
+            return prefs.AuthenticationDialog(self.w, partial(self.verify, self.getandsend))
 
         # Companion API problem
         except companion.ServerError as e:
diff --git a/companion.py b/companion.py
index a1029006..253e97e2 100644
--- a/companion.py
+++ b/companion.py
@@ -177,8 +177,13 @@ class Session:
 
     def login(self, username=None, password=None):
         if (not username or not password):
-            raise CredentialsError()
-        credentials = { 'email' : username, 'password' : password }
+            if not self.credentials:
+                raise CredentialsError()
+            else:
+                credentials = self.credentials
+        else:
+            credentials = { 'email' : username, 'password' : password }
+
         if self.credentials == credentials and self.state == Session.STATE_OK:
             return	# already logged in
         if self.credentials and self.credentials['email'] != credentials['email']:	# changed account
diff --git a/stats.py b/stats.py
index 8d1e58e4..6accf9c2 100644
--- a/stats.py
+++ b/stats.py
@@ -1,5 +1,6 @@
 from collections import OrderedDict
 from sys import platform
+from functools import partial
 import time
 if __debug__:
     from traceback import print_exc
@@ -159,58 +160,23 @@ def export_ships(data, filename):
     h.close()
 
 
-class StatsDialog(tk.Toplevel):
-
-    def __init__(self, parent, session):
-        tk.Toplevel.__init__(self, parent)
-
-        self.parent = parent
-        self.session = session
-        self.title(_('Status'))	# Menu item
-
-        if parent.winfo_viewable():
-            self.transient(parent)
-
-        # position over parent
-        if platform!='darwin' or parent.winfo_rooty()>0:	# http://core.tcl.tk/tk/tktview/c84f660833546b1b84e7
-            self.geometry("+%d+%d" % (parent.winfo_rootx(), parent.winfo_rooty()))
-
-        # remove decoration
-        self.resizable(tk.FALSE, tk.FALSE)
-        if platform=='win32':
-            self.attributes('-toolwindow', tk.TRUE)
-        elif platform=='darwin':
-            # http://wiki.tcl.tk/13428
-            parent.call('tk::unsupported::MacWindowStyle', 'style', self, 'utility')
-
-        frame = ttk.Frame(self)
-        frame.grid(sticky=tk.NSEW)
-
-        self.status = ttk.Label(frame, text=_('Fetching data...'))
-        self.status.grid(padx=10, pady=10)
-
-        # wait for window to appear on screen before calling grab_set
-        self.wait_visibility()
-        self.grab_set()
-        self.update()	# update_idletasks() isn't cutting it
+class StatsDialog():
 
+    def __init__(self, app):
+        self.parent = app.w
+        self.session = app.session
+        self.status = app.status
+        self.verify = app.verify
         self.showstats()
 
-    # callback after verification code
-    def verify(self, code):
-        try:
-            self.session.verify(code)
-        except Exception as e:
-            if __debug__: print_exc()
-            self.status['text'] = unicode(e)
-        else:
-            self.showstats()
-
     def showstats(self):
+        self.status['text'] = _('Fetching data...')
+        self.parent.update_idletasks()
+
         try:
             data = self.session.query()
         except companion.VerificationRequired:
-            return prefs.AuthenticationDialog(self.parent, self.verify)
+            return prefs.AuthenticationDialog(self.parent, partial(self.verify, self.showstats))
         except companion.ServerError as e:
             self.status['text'] = str(e)
             return
@@ -226,8 +192,8 @@ class StatsDialog(tk.Toplevel):
         elif not data.get('ship') or not data['ship'].get('modules') or not data['ship'].get('name','').strip():
             self.status['text'] = _("What are you flying?!")	# Shouldn't happen
         else:
+            self.status['text'] = ''
             StatsResults(self.parent, data)
-            self.destroy()
 
 
 class StatsResults(tk.Toplevel):