IDManager : finished Import/Export. Added merging capability to import (asks if particular ID is replaced during import). Added ESC as closing shortcut to IDManager dialog, and adjusted its size.
authorEdouard Tisserant
Thu, 22 Nov 2018 23:39:54 +0100
changeset 2428 e0f16317668e
parent 2340 decf52efb7f7
child 2429 15f18dc8b56a
IDManager : finished Import/Export. Added merging capability to import (asks if particular ID is replaced during import). Added ESC as closing shortcut to IDManager dialog, and adjusted its size.
PSKManagement.py
controls/IDBrowser.py
dialogs/IDManager.py
dialogs/IDMergeDialog.py
--- a/PSKManagement.py	Wed Nov 21 14:10:51 2018 +0100
+++ b/PSKManagement.py	Thu Nov 22 23:39:54 2018 +0100
@@ -11,7 +11,8 @@
 
 # PSK Management Data model :
 # [[ID,Desc, LastKnownURI, LastConnect]]
-COL_ID,COL_URI,COL_DESC,COL_LAST = range(4)
+COL_ID, COL_URI, COL_DESC, COL_LAST = range(4)
+REPLACE, REPLACE_ALL, KEEP, KEEP_ALL, CANCEL = range(5)
 
 def _pskpath(project_path):
     return os.path.join(project_path, 'psk')
@@ -93,14 +94,18 @@
                 zf.write(os.path.join(path, nm), nm)
 
 def ImportIDs(project_path, import_zip, should_I_replace_callback):
+    zf = ZipFile(import_zip, 'r')
     data = GetData(project_path)
 
     zip_loaded_data = json.loads(zf.open('management.json').read())
     name_list = zf.namelist()
-    zip_filtered_data = _filterData(name_list, loaded_data)
+    zip_filtered_data = _filterData(name_list, zip_loaded_data)
 
     idata = _dataByID(data)
 
+    keys_to_import = []
+    result = None
+
     for imported_row in zip_filtered_data:
         ID = imported_row[COL_ID]
         existing_row = idata.get(ID, None)
@@ -108,16 +113,23 @@
             data.append(imported_row)
         else:
             # callback returns the selected list for merge or none if canceled
-            result = should_I_replace_callback(existing_row, imported_row)
-            if result is None:
-                break
+            if result not in [REPLACE_ALL, KEEP_ALL]:
+                result = should_I_replace_callback(existing_row, imported_row)
+
+            if result == CANCEL:
+                return
             
-            if result: 
+            if result in [REPLACE_ALL, REPLACE]:
                 # replace with imported
                 existing_row[:] = imported_row
                 # copy the key of selected
-                self.extract(ID+".secret", _pskpath(project_path))
+                keys_to_import.append(ID)
+    
+    for ID in keys_to_import:
+        zf.extract(ID+".secret", _pskpath(project_path))
 
     SaveData(project_path, data)
 
+    return data
 
+
--- a/controls/IDBrowser.py	Wed Nov 21 14:10:51 2018 +0100
+++ b/controls/IDBrowser.py	Thu Nov 22 23:39:54 2018 +0100
@@ -8,7 +8,8 @@
 import wx
 import wx.dataview as dv
 import PSKManagement as PSK
-from PSKManagement import COL_ID,COL_URI,COL_DESC,COL_LAST
+from PSKManagement import *
+from dialogs.IDMergeDialog import IDMergeDialog
 
 class IDBrowserModel(dv.PyDataViewIndexListModel):
     def __init__(self, project_path, columncount):
@@ -70,7 +71,10 @@
         self._saveData()
 
     def Import(self, filepath, sircb):
-        PSK.ImportIDs(self.project_path, filepath, sircb)
+        data = PSK.ImportIDs(self.project_path, filepath, sircb)
+        if data is not None:
+            self.data = data
+            self.Reset(len(self.data)) 
 
     def Export(self, filepath):
         PSK.ExportIDs(self.project_path, filepath)
@@ -184,10 +188,35 @@
         if dialog.ShowModal() == wx.ID_OK:
             self.model.Export(dialog.GetPath())
 
-    def ShouldIReplaceCallback(self,some,stuff):
-        # TODO
-        wx.MessageBox("TODO : ShouldIReplaceCallback")
-        return True
+    def ShouldIReplaceCallback(self,existing,replacement):
+        ID,URI,DESC,LAST = existing
+        _ID,_URI,_DESC,_LAST = replacement
+        dlg = IDMergeDialog(self, 
+            _("Import IDs"), 
+            (_("Replace information for ID {ID} ?") + "\n\n" +
+             _("Existing:") + "\n    " +
+             _("Description:") + " {DESC}\n    " +
+             _("Last known URI:") + " {URI}\n    " +
+             _("Last connection:") + " {LAST}\n\n" +
+             _("Replacement:") + "\n    " +
+             _("Description:") + " {_DESC}\n    " +
+             _("Last known URI:") + " {_URI}\n    " +
+             _("Last connection:") + " {_LAST}\n").format(**locals()),
+            _("Do the same for following IDs"),
+            [_("Replace"), _("Keep"),_("Cancel")])
+
+        answer = dlg.ShowModal() # return value ignored as we have "Ok" only anyhow
+        if answer == wx.ID_CANCEL:
+            return CANCEL
+
+        if dlg.OptionChecked():
+            if answer == wx.ID_YES:
+                return REPLACE_ALL
+            return KEEP_ALL
+        else:
+            if answer == wx.ID_YES:
+                return REPLACE
+            return KEEP
 
     def OnImportButton(self, evt):
         dialog = wx.FileDialog(self, _("Choose a file"),
--- a/dialogs/IDManager.py	Wed Nov 21 14:10:51 2018 +0100
+++ b/dialogs/IDManager.py	Thu Nov 22 23:39:54 2018 +0100
@@ -11,8 +11,17 @@
         wx.Dialog.__init__(self,
                            name='IDManager', parent=parent,
                            title=_('URI Editor'),
-                           style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
+                           style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
+                           size=(800,600))
         # start IDBrowser in manager mode
         self.browser = IDBrowser(self, ctr)
+        self.Bind(wx.EVT_CHAR_HOOK, self.OnEscapeKey)
+
+    def OnEscapeKey(self, event):
+        keycode = event.GetKeyCode()
+        if keycode == wx.WXK_ESCAPE:
+            self.EndModal(wx.ID_CANCEL)
+        else:
+            event.Skip()
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dialogs/IDMergeDialog.py	Thu Nov 22 23:39:54 2018 +0100
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# See COPYING file for copyrights details.
+
+from __future__ import absolute_import
+import wx
+
+# class RichMessageDialog is still not available in wxPython 3.0.2 
+class IDMergeDialog(wx.Dialog):
+    def __init__(self, parent, title, question, optiontext, button_texts):
+        wx.Dialog.__init__(self, parent, title=title)
+
+        main_sizer = wx.BoxSizer(wx.VERTICAL)
+
+        message = wx.StaticText(self, label=question)
+        main_sizer.AddWindow(message, border=20,
+                             flag = wx.ALIGN_CENTER_HORIZONTAL | wx.TOP | wx.LEFT | wx.RIGHT)
+
+        self.check = wx.CheckBox(self, label=optiontext)
+        main_sizer.AddWindow(self.check, border=20,
+                             flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.ALIGN_CENTER_HORIZONTAL)
+
+        buttons_sizer = wx.BoxSizer(wx.HORIZONTAL)
+        for label,wxID in zip(button_texts, [wx.ID_YES, wx.ID_NO, wx.ID_CANCEL]):
+            Button = wx.Button(self, label=label)
+            def OnButtonFactory(_wxID):
+                return lambda event: self.EndModal(_wxID)
+            self.Bind(wx.EVT_BUTTON, OnButtonFactory(wxID), Button)
+            buttons_sizer.AddWindow(Button)
+
+        main_sizer.AddSizer(buttons_sizer, border=20,
+                            flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.ALIGN_RIGHT)
+
+        self.SetSizer(main_sizer)
+        self.Fit()
+
+        self.Bind(wx.EVT_CHAR_HOOK, self.OnEscapeKey)
+
+    def OnEscapeKey(self, event):
+        keycode = event.GetKeyCode()
+        if keycode == wx.WXK_ESCAPE:
+            self.EndModal(wx.ID_CANCEL)
+        else:
+            event.Skip()
+
+    def OptionChecked(self):
+        return self.check.GetValue()