# HG changeset patch # User Edouard Tisserant # Date 1542926394 -3600 # Node ID e0f16317668ec0533715cfb3d719c3cf9c60e0fb # Parent decf52efb7f7b0daa00b6d19bf37c40162baccb9 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. diff -r decf52efb7f7 -r e0f16317668e PSKManagement.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 + diff -r decf52efb7f7 -r e0f16317668e controls/IDBrowser.py --- 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"), diff -r decf52efb7f7 -r e0f16317668e dialogs/IDManager.py --- 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() diff -r decf52efb7f7 -r e0f16317668e dialogs/IDMergeDialog.py --- /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()