Added early implementation of IDManager.py. For now only used to select ID in URIEditor
--- a/ProjectController.py Fri Nov 09 13:26:06 2018 +0100
+++ b/ProjectController.py Wed Nov 14 11:32:08 2018 +0100
@@ -1768,7 +1768,7 @@
if uri == "":
try:
# Launch Service Discovery dialog
- dialog = UriEditor(self.AppFrame)
+ dialog = UriEditor(self.AppFrame, self)
answer = dialog.ShowModal()
uri = dialog.GetURI()
dialog.Destroy()
--- a/connectors/PYRO/__init__.py Fri Nov 09 13:26:06 2018 +0100
+++ b/connectors/PYRO/__init__.py Wed Nov 14 11:32:08 2018 +0100
@@ -126,7 +126,10 @@
if servicetype != "PYROS":
ID,PSK = IDPSK
- secpath = os.path.join(str(confnodesroot.ProjectPath), 'psk', ID+'.secret')
+ secdir = os.path.join(str(confnodesroot.ProjectPath), 'psk')
+ if not os.path.exists(secdir):
+ os.mkdir(secdir)
+ secpath = os.path.join(secdir, ID+'.secret')
with open(secpath, 'w') as f:
f.write(ID+":"+PSK)
--- a/connectors/PYRO_dialog.py Fri Nov 09 13:26:06 2018 +0100
+++ b/connectors/PYRO_dialog.py Wed Nov 14 11:32:08 2018 +0100
@@ -14,17 +14,19 @@
model = [('host',_("Host:")),
('port',_("Port:"))]
-secure_model = model + [('ID',_("ID:"))]
-
-models = [("LOCAL", []), ("PYRO",model), ("PYROS",secure_model)]
+# (scheme, model, secure)
+models = [("LOCAL", [], False), ("PYRO", model, False), ("PYROS", model, True)]
Schemes = list(zip(*models)[0])
-ModelsDict = dict(models)
+_PerSchemeConf = {sch : (mod,sec) for sch,mod,sec in models}
class PYRO_dialog(SchemeEditor):
def __init__(self, scheme, *args, **kwargs):
- self.model = ModelsDict[scheme]
+
+ # ID selector is enabled only on PYROS (secure)
+ self.model, self.EnableIDSelector = _PerSchemeConf[scheme]
+
SchemeEditor.__init__(self, scheme, *args, **kwargs)
def SetLoc(self, loc):
@@ -38,6 +40,8 @@
template = "{host}"
if fields['port']:
template += ":{port}"
+ if fields['ID']:
+ template += "#{ID}"
return template.format(**fields)
return ''
--- a/connectors/SchemeEditor.py Fri Nov 09 13:26:06 2018 +0100
+++ b/connectors/SchemeEditor.py Wed Nov 14 11:32:08 2018 +0100
@@ -6,14 +6,20 @@
from __future__ import absolute_import
from itertools import repeat, izip_longest
+from functools import partial
import wx
+from controls.IDManager import IDManager
+
class SchemeEditor(wx.Panel):
def __init__(self, scheme, parent, *args, **kwargs):
self.txtctrls = {}
wx.Panel.__init__(self, parent, *args, **kwargs)
- self.mainSizer = wx.FlexGridSizer(cols=2, hgap=10, rows=5, vgap=10)
+ self.fieldsizer = wx.FlexGridSizer(cols=2, hgap=10, vgap=10)
+
+ if self.EnableIDSelector:
+ self.model = self.model + [("ID", _("ID:"))]
for tag, label in self.model:
txtctrl = wx.TextCtrl(parent=self, size=wx.Size(200, -1))
@@ -21,11 +27,20 @@
for win, flag in [
(wx.StaticText(self, label=label), wx.ALIGN_CENTER_VERTICAL),
(txtctrl, wx.GROW)]:
- self.mainSizer.AddWindow(win, flag=flag)
+ self.fieldsizer.AddWindow(win, flag=flag)
- self.mainSizer.AddSpacer(20)
+ self.fieldsizer.AddSpacer(20)
- self.SetSizer(self.mainSizer)
+ if self.EnableIDSelector:
+ self.mainsizer = wx.FlexGridSizer(cols=2, hgap=10, vgap=10)
+ self.mainsizer.AddSizer(self.fieldsizer)
+ self.idselector = IDManager(
+ self, parent.ctr,
+ partial(wx.CallAfter, parent.SetURI))
+ self.mainsizer.AddWindow(self.idselector)
+ self.SetSizer(self.mainsizer)
+ else:
+ self.SetSizer(self.fieldsizer)
def SetFields(self, fields):
for tag, label in self.model:
--- a/connectors/WAMP_dialog.py Fri Nov 09 13:26:06 2018 +0100
+++ b/connectors/WAMP_dialog.py Wed Nov 14 11:32:08 2018 +0100
@@ -14,12 +14,12 @@
model = [('host',_("Host:")),
('port',_("Port:")),
- ('realm',_("Realm:")),
- ('ID',_("ID:"))]
+ ('realm',_("Realm:"))]
class WAMP_dialog(SchemeEditor):
def __init__(self, *args, **kwargs):
self.model = model
+ self.EnableIDSelector = True
SchemeEditor.__init__(self, *args, **kwargs)
def SetLoc(self, loc):
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/controls/IDManager.py Wed Nov 14 11:32:08 2018 +0100
@@ -0,0 +1,210 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# See COPYING file for copyrights details.
+
+from __future__ import absolute_import
+import os
+import wx
+import wx.dataview as dv
+import json
+
+def _GetInitialData(psk_path):
+ # [(ID, Desc, LastKnownURI, LastConnect)
+ data = []
+
+ data_path = os.path.join(psk_path, 'management.json')
+
+ if os.path.isdir(psk_path):
+ # load known keys metadata
+ # {ID:(Desc, LastKnownURI, LastConnect)}
+ recovered_data = json.loads(open(data_path).read()) \
+ if os.path.exists(data_path) else {}
+
+ # go through all secret files available an build data
+ # out of data recoverd from json and list of secret.
+ # this implicitly filters IDs out of metadata who's
+ # secret is missing
+ psk_files = os.listdir(psk_path)
+ for filename in psk_files:
+ if filename.endswith('.secret'):
+ ID = filename[:-7] # strip filename extension
+ meta = recovered_data.get(ID,
+ ['', # default description
+ None, # last known URI
+ None]) # last connection date
+
+ data.append([ID]+meta)
+ return data
+
+def _DeleteID(psk_path, ID):
+ secret_path = os.path.join(psk_path, ID+'.secret')
+ os.remove(secret_path)
+
+def _SaveData(psk_path, data):
+ if not os.path.isdir(psk_path):
+ os.mkdir(psk_path)
+ data_path = os.path.join(psk_path, 'management.json')
+ to_store = {row[0]:row[1:] for row in data}
+ with open(data_path, 'w') as f:
+ f.write(json.dumps(to_store))
+
+class IDManagerModel(dv.PyDataViewIndexListModel):
+ def __init__(self, psk_path, columncount):
+ self.psk_path = psk_path
+ self.columncount = columncount
+ self.data = _GetInitialData(psk_path)
+ dv.PyDataViewIndexListModel.__init__(self, len(self.data))
+
+ def _saveData(self):
+ _SaveData(self.psk_path, self.data)
+
+ def GetColumnType(self, col):
+ return "string"
+
+ def GetValueByRow(self, row, col):
+ return self.data[row][col]
+
+ def SetValueByRow(self, value, row, col):
+ self.data[row][col] = value
+ self._saveData()
+
+ def GetColumnCount(self):
+ return len(self.data[0]) if self.data else self.columncount
+
+ def GetCount(self):
+ return len(self.data)
+
+ def GetAttrByRow(self, row, col, attr):
+ if col == 3:
+ attr.SetColour('blue')
+ attr.SetBold(True)
+ return True
+ return False
+
+
+ def Compare(self, item1, item2, col, ascending):
+ if not ascending: # swap sort order?
+ item2, item1 = item1, item2
+ row1 = self.GetRow(item1)
+ row2 = self.GetRow(item2)
+ if col == 0:
+ return cmp(int(self.data[row1][col]), int(self.data[row2][col]))
+ else:
+ return cmp(self.data[row1][col], self.data[row2][col])
+
+ def DeleteRows(self, rows):
+ rows = list(rows)
+ rows.sort(reverse=True)
+
+ for row in rows:
+ del self.data[row]
+ _DeleteID(self.psk_path, ID)
+ self.RowDeleted(row)
+ self._saveData()
+
+ def AddRow(self, value):
+ self.data.append(value)
+ self.RowAppended()
+ self._saveData()
+
+colflags = dv.DATAVIEW_COL_RESIZABLE|dv.DATAVIEW_COL_SORTABLE
+
+class IDManager(wx.Panel):
+ def __init__(self, parent, ctr, SelectURICallBack, *args, **kwargs):
+ wx.Panel.__init__(self, parent, -1, size=(400,200))
+
+ self.isManager = SelectURICallBack is None
+ self.SelectURICallBack = SelectURICallBack
+
+ dvStyle = wx.BORDER_THEME | dv.DV_ROW_LINES
+ if self.isManager :
+ # no multiple selection in selector mode
+ dvStyle |= dv.DV_MULTIPLE
+ self.dvc = dv.DataViewCtrl(self, style = dvStyle)
+
+ args = lambda *a,**k:(a,k)
+
+ ColumnsDesc = [
+ args(_("ID"), 0, width = 100),
+ args(_("Last URI"), 1, width = 80),
+ args(_("Description"), 2, width = 200,
+ mode = dv.DATAVIEW_CELL_EDITABLE
+ if self.isManager
+ else dv.DATAVIEW_CELL_INERT),
+ args(_("Last connection"), 3, width = 100),
+ ]
+
+ self.model = IDManagerModel(
+ os.path.join(str(ctr.ProjectPath), 'psk'),
+ len(ColumnsDesc))
+ self.dvc.AssociateModel(self.model)
+
+ for a,k in ColumnsDesc:
+ self.dvc.AppendTextColumn(*a,**dict(k, flags = colflags))
+
+ # TODO : when select,
+ # - update ID field of scheme editor
+ # - enable use URI button
+
+ self.Sizer = wx.BoxSizer(wx.VERTICAL)
+ self.Sizer.Add(self.dvc, 1, wx.EXPAND)
+
+ btnbox = wx.BoxSizer(wx.HORIZONTAL)
+ if self.isManager :
+
+ # deletion of secret and metadata
+ deleteButton = wx.Button(self, label=_("Delete ID"))
+ self.Bind(wx.EVT_BUTTON, self.OnDeleteButton, deleteButton)
+ btnbox.Add(deleteButton, 0, wx.LEFT|wx.RIGHT, 5)
+
+ # export all
+ exportButton = wx.Button(self, label=_("Export all"))
+ self.Bind(wx.EVT_BUTTON, self.OnExportButton, exportButton)
+ btnbox.Add(exportButton, 0, wx.LEFT|wx.RIGHT, 5)
+
+ # import with a merge -> duplicates are asked for
+ importButton = wx.Button(self, label=_("Import"))
+ self.Bind(wx.EVT_BUTTON, self.OnImportButton, importButton)
+ btnbox.Add(importButton, 0, wx.LEFT|wx.RIGHT, 5)
+
+ else :
+ # selector mode
+ # use last known URI button
+ # TODO : disable use URI button until something selected
+ selectButton = wx.Button(self, label=_("Use last URI"))
+ self.Bind(wx.EVT_BUTTON, self.OnSelectButton, selectButton)
+ btnbox.Add(selectButton, 0, wx.LEFT|wx.RIGHT, 5)
+
+ self.Sizer.Add(btnbox, 0, wx.TOP|wx.BOTTOM, 5)
+
+ def OnDeleteButton(self, evt):
+ items = self.dvc.GetSelections()
+ rows = [self.model.GetRow(item) for item in items]
+
+ # Ask if user really wants to delete
+ if wx.MessageBox(_('Are you sure to delete selected IDs?'),
+ _('Delete IDs'),
+ wx.YES_NO | wx.CENTRE | wx.NO_DEFAULT) != wx.YES:
+ return
+
+ self.model.DeleteRows(rows)
+
+ def OnSelectButton(self, evt):
+ # TODO : call SetURICallback with URI from curent selection.
+ wx.MessageBox(_('?'),
+ _('Mhe'),
+ wx.YES_NO | wx.CENTRE | wx.NO_DEFAULT)
+
+ def OnExportButton(self, evt):
+ # TODO
+ wx.MessageBox(_('?'),
+ _('Mhe'),
+ wx.YES_NO | wx.CENTRE | wx.NO_DEFAULT)
+
+ def OnImportButton(self, evt):
+ # TODO
+ wx.MessageBox(_('?'),
+ _('Mhe'),
+ wx.YES_NO | wx.CENTRE | wx.NO_DEFAULT)
+
--- a/dialogs/UriEditor.py Fri Nov 09 13:26:06 2018 +0100
+++ b/dialogs/UriEditor.py Wed Nov 14 11:32:08 2018 +0100
@@ -27,7 +27,8 @@
self.Layout()
self.Fit()
- def __init__(self, parent, uri=''):
+ def __init__(self, parent, ctr, uri=''):
+ self.ctr = ctr
wx.Dialog.__init__(self,
name='UriEditor', parent=parent,
title=_('URI Editor'))
--- a/editors/ConfTreeNodeEditor.py Fri Nov 09 13:26:06 2018 +0100
+++ b/editors/ConfTreeNodeEditor.py Wed Nov 14 11:32:08 2018 +0100
@@ -345,7 +345,7 @@
# Get connector uri
uri = CTR_BeremizRoot.getURI_location().strip()
- dialog = UriEditor(CTR_AppFrame, uri)
+ dialog = UriEditor(CTR_AppFrame, CTR, uri)
if dialog.ShowModal() == wx.ID_OK:
CTR_BeremizRoot.setURI_location(dialog.GetURI())