1 """wxPython panel display cards/readers as a TreeCtrl.
2
3 __author__ = "gemalto http://www.gemalto.com"
4
5 Copyright 2001-2012 gemalto
6 Author: Jean-Daniel Aussel, mailto:jean-daniel.aussel@gemalto.com
7
8 This file is part of pyscard.
9
10 pyscard is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14
15 pyscard is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19
20 You should have received a copy of the GNU Lesser General Public License
21 along with pyscard; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 """
24
25
26 from threading import RLock
27 from smartcard.Exceptions import CardConnectionException, NoCardException
28 from smartcard.ReaderMonitoring import ReaderMonitor, ReaderObserver
29 from smartcard.CardMonitoring import CardMonitor, CardObserver
30 from smartcard.util import toHexString
31
32 import smartcard.wx.SimpleSCardApp
33 from smartcard.wx import ICO_SMARTCARD, ICO_READER
34
35
36 import wx
37
38
40 """Base class for the smart card and reader tree controls."""
41
42 - def __init__(self,
43 parent,
44 ID=wx.NewId(),
45 pos=wx.DefaultPosition,
46 size=wx.DefaultSize,
47 style=0,
48 clientpanel=None):
49 """Constructor. Initializes a smartcard or reader tree control."""
50 wx.TreeCtrl.__init__(
51 self, parent, ID, pos, size, wx.TR_SINGLE | wx.TR_NO_BUTTONS)
52
53 self.clientpanel = clientpanel
54 self.parent = parent
55
56 isz = (16, 16)
57 il = wx.ImageList(isz[0], isz[1])
58 self.capindex = il.Add(
59 wx.ArtProvider_GetBitmap(wx.ART_HELP_BOOK, wx.ART_OTHER, isz))
60 self.fldrindex = il.Add(
61 wx.ArtProvider_GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, isz))
62 self.fldropenindex = il.Add(
63 wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN, wx.ART_OTHER, isz))
64 if None != ICO_SMARTCARD:
65 self.cardimageindex = il.Add(
66 wx.Bitmap(ICO_SMARTCARD, wx.BITMAP_TYPE_ICO))
67 if None != ICO_READER:
68 self.readerimageindex = il.Add(
69 wx.Bitmap(ICO_READER, wx.BITMAP_TYPE_ICO))
70 self.il = il
71 self.SetImageList(self.il)
72
74 self.Refresh()
75 wx.PostEvent(self, wx.PaintEvent())
76
77
79 """The CardTreeCtrl monitors inserted cards and notifies the
80 application client dialog of any card activation."""
81
82 - def __init__(self,
83 parent,
84 ID=wx.NewId(),
85 pos=wx.DefaultPosition,
86 size=wx.DefaultSize,
87 style=0,
88 clientpanel=None):
89 """Constructor. Create a smartcard tree control."""
90 BaseCardTreeCtrl.__init__(self, parent, ID, pos, size,
91 wx.TR_SINGLE | wx.TR_NO_BUTTONS,
92 clientpanel)
93
94 self.root = self.AddRoot("Smartcards")
95 self.SetPyData(self.root, None)
96 self.SetItemImage(self.root, self.fldrindex, wx.TreeItemIcon_Normal)
97 self.SetItemImage(
98 self.root, self.fldropenindex, wx.TreeItemIcon_Expanded)
99 self.Expand(self.root)
100
102 """Called when a card is inserted.
103 Adds a smart card to the smartcards tree."""
104 parentnode = self.root
105 for cardtoadd in addedcards:
106 childCard = self.AppendItem(parentnode, toHexString(cardtoadd.atr))
107 self.SetItemText(childCard, toHexString(cardtoadd.atr))
108 self.SetPyData(childCard, cardtoadd)
109 self.SetItemImage(
110 childCard, self.cardimageindex, wx.TreeItemIcon_Normal)
111 self.SetItemImage(
112 childCard, self.cardimageindex, wx.TreeItemIcon_Expanded)
113 self.Expand(childCard)
114 self.Expand(self.root)
115 self.EnsureVisible(self.root)
116 self.Repaint()
117
119 """Called when a card is removed.
120 Removes a card from the tree."""
121 parentnode = self.root
122 for cardtoremove in removedcards:
123 (childCard, cookie) = self.GetFirstChild(parentnode)
124 while childCard.IsOk():
125 if self.GetItemText(childCard) == \
126 toHexString(cardtoremove.atr):
127 self.Delete(childCard)
128 (childCard, cookie) = self.GetNextChild(parentnode, cookie)
129 self.Expand(self.root)
130 self.EnsureVisible(self.root)
131 self.Repaint()
132
133
135 """The ReaderTreeCtrl monitors inserted cards and readers and notifies the
136 application client dialog of any card activation."""
137
138 - def __init__(self,
139 parent,
140 ID=wx.NewId(),
141 pos=wx.DefaultPosition,
142 size=wx.DefaultSize,
143 style=0,
144 clientpanel=None):
145 """Constructor. Create a reader tree control."""
146
147 BaseCardTreeCtrl.__init__(
148 self,
149 parent,
150 ID,
151 pos,
152 size,
153 wx.TR_SINGLE | wx.TR_NO_BUTTONS,
154 clientpanel)
155
156 self.mutex = RLock()
157
158 self.root = self.AddRoot("Smartcard Readers")
159 self.SetPyData(self.root, None)
160 self.SetItemImage(
161 self.root, self.fldrindex, wx.TreeItemIcon_Normal)
162 self.SetItemImage(
163 self.root, self.fldropenindex, wx.TreeItemIcon_Expanded)
164 self.Expand(self.root)
165
166 - def AddATR(self, readernode, atr):
167 """Add an ATR to a reader node."""
168 capchild = self.AppendItem(readernode, atr)
169 self.SetPyData(capchild, None)
170 self.SetItemImage(
171 capchild, self.cardimageindex, wx.TreeItemIcon_Normal)
172 self.SetItemImage(
173 capchild, self.cardimageindex, wx.TreeItemIcon_Expanded)
174 self.Expand(capchild)
175 return capchild
176
191
193 """Called when a card is inserted.
194 Adds the smart card child to the reader node."""
195 self.mutex.acquire()
196 try:
197 parentnode = self.root
198 for cardtoadd in addedcards:
199 (childReader, cookie) = self.GetFirstChild(parentnode)
200 found = False
201 while childReader.IsOk() and not found:
202 if self.GetItemText(childReader) == str(cardtoadd.reader):
203 (childCard, cookie2) = self.GetFirstChild(childReader)
204 self.SetItemText(childCard, toHexString(cardtoadd.atr))
205 self.SetPyData(childCard, cardtoadd)
206 found = True
207 else:
208 (childReader, cookie) = self.GetNextChild(
209 parentnode, cookie)
210
211
212
213
214
215 if not found:
216 childReader = self.AppendItem(
217 parentnode, str(cardtoadd.reader))
218 self.SetPyData(childReader, cardtoadd.reader)
219 self.SetItemImage(
220 childReader,
221 self.readerimageindex,
222 wx.TreeItemIcon_Normal)
223 self.SetItemImage(
224 childReader,
225 self.readerimageindex,
226 wx.TreeItemIcon_Expanded)
227 childCard = self.AddATR(
228 childReader, toHexString(cardtoadd.atr))
229 self.SetPyData(childCard, cardtoadd)
230 self.Expand(childReader)
231
232 self.Expand(self.root)
233 finally:
234 self.mutex.release()
235 self.EnsureVisible(self.root)
236 self.Repaint()
237
239 """Called when a reader is inserted.
240 Adds the smart card reader to the smartcard readers tree."""
241 self.mutex.acquire()
242
243 try:
244 parentnode = self.root
245 for readertoadd in addedreaders:
246
247 found = False
248 (childReader, cookie) = self.GetFirstChild(parentnode)
249 while childReader.IsOk() and not found:
250 if self.GetItemText(childReader) == str(readertoadd):
251 found = True
252 else:
253 (childReader, cookie) = self.GetNextChild(
254 parentnode, cookie)
255 if not found:
256 childReader = self.AppendItem(parentnode, str(readertoadd))
257 self.SetPyData(childReader, readertoadd)
258 self.SetItemImage(
259 childReader,
260 self.readerimageindex,
261 wx.TreeItemIcon_Normal)
262 self.SetItemImage(
263 childReader,
264 self.readerimageindex,
265 wx.TreeItemIcon_Expanded)
266 self.AddATR(
267 childReader,
268 self.GetATR(readertoadd))
269 self.Expand(childReader)
270 self.Expand(self.root)
271 finally:
272 self.mutex.release()
273 self.EnsureVisible(self.root)
274 self.Repaint()
275
277 """Called when a card is removed.
278 Removes the card from the tree."""
279 self.mutex.acquire()
280 try:
281 parentnode = self.root
282 for cardtoremove in removedcards:
283 (childReader, cookie) = self.GetFirstChild(parentnode)
284 found = False
285 while childReader.IsOk() and not found:
286 if self.GetItemText(childReader) == \
287 str(cardtoremove.reader):
288 (childCard, cookie2) = self.GetFirstChild(childReader)
289 self.SetItemText(childCard, 'no card inserted')
290 found = True
291 else:
292 (childReader, cookie) = \
293 self.GetNextChild(parentnode, cookie)
294 self.Expand(self.root)
295 finally:
296 self.mutex.release()
297 self.EnsureVisible(self.root)
298 self.Repaint()
299
301 """Called when a reader is removed.
302 Removes the reader from the smartcard readers tree."""
303 self.mutex.acquire()
304 try:
305 parentnode = self.root
306 for readertoremove in removedreaders:
307 (childReader, cookie) = self.GetFirstChild(parentnode)
308 while childReader.IsOk():
309 if self.GetItemText(childReader) == str(readertoremove):
310 self.Delete(childReader)
311 else:
312 (childReader, cookie) = \
313 self.GetNextChild(parentnode, cookie)
314 self.Expand(self.root)
315 finally:
316 self.mutex.release()
317 self.EnsureVisible(self.root)
318 self.Repaint()
319
320
322 """Panel containing the smart card and reader tree controls."""
323
325 """Inner CardObserver. Gets notified of card insertion
326 removal by the CardMonitor."""
327
329 self.cardtreectrl = cardtreectrl
330
331 - def update(self, observable, handlers):
332 """CardObserver callback that is notified
333 when cards are added or removed."""
334 addedcards, removedcards = handlers
335 self.cardtreectrl.OnRemoveCards(removedcards)
336 self.cardtreectrl.OnAddCards(addedcards)
337
339 """Inner ReaderObserver. Gets notified of reader insertion/removal
340 by the ReaderMonitor."""
341
343 self.readertreectrl = readertreectrl
344
345 - def update(self, observable, handlers):
346 """ReaderObserver callback that is notified when
347 readers are added or removed."""
348 addedcards, removedcards = handlers
349 self.readertreectrl.OnRemoveReaders(removedreaders)
350 self.readertreectrl.OnAddReaders(addedreaders)
351
352 - def __init__(self, parent, appstyle, clientpanel):
353 """Constructor. Create a smartcard and reader tree control on the
354 left-hand side of the application main frame.
355 @param parent: the tree panel parent
356 @param appstyle: a combination of the following styles (bitwise or |)
357 - TR_SMARTCARD: display a smartcard tree panel
358 - TR_READER: display a reader tree panel
359 - default is TR_DEFAULT = TR_SMARTCARD
360 @param clientpanel: the client panel to notify of smartcard and reader events
361 """
362 wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS)
363
364 sizer = wx.BoxSizer(wx.VERTICAL)
365
366
367 if appstyle & smartcard.wx.SimpleSCardApp.TR_SMARTCARD:
368 self.cardtreectrl = CardTreeCtrl(self, clientpanel=clientpanel)
369
370
371 self.cardtreecardobserver = self._CardObserver(self.cardtreectrl)
372
373
374
375 self.cardmonitor = CardMonitor()
376 self.cardmonitor.addObserver(self.cardtreecardobserver)
377
378 sizer.Add(
379 self.cardtreectrl, flag=wx.EXPAND | wx.ALL, proportion=1)
380
381
382 if appstyle & smartcard.wx.SimpleSCardApp.TR_READER:
383 self.readertreectrl = ReaderTreeCtrl(
384 self, clientpanel=clientpanel)
385
386
387 self.readertreereaderobserver = self._ReaderObserver(
388 self.readertreectrl)
389
390
391
392 self.readermonitor = ReaderMonitor()
393 self.readermonitor.addObserver(self.readertreereaderobserver)
394
395
396 self.readertreecardobserver = self._CardObserver(
397 self.readertreectrl)
398
399
400
401 self.cardmonitor = CardMonitor()
402 self.cardmonitor.addObserver(self.readertreecardobserver)
403
404 sizer.Add(
405 self.readertreectrl, flag=wx.EXPAND | wx.ALL, proportion=1)
406
407 self.SetSizer(sizer)
408 self.SetAutoLayout(True)
409
411 """Called on panel destruction."""
412
413 if hasattr(self, 'cardmonitor'):
414 self.cardmonitor.deleteObserver(self.cardtreecardobserver)
415 if hasattr(self, 'readermonitor'):
416 self.readermonitor.deleteObserver(self.readertreereaderobserver)
417 self.cardmonitor.deleteObserver(self.readertreecardobserver)
418 event.Skip()
419