Add VRS application and GUI (Public transport in Koeln and Bonn)
This commit is contained in:
parent
2f244a2083
commit
86c7778022
|
@ -0,0 +1,117 @@
|
||||||
|
from generic_application import Application
|
||||||
|
import struct, sha, binascii, os, datetime, sys, time
|
||||||
|
from iso_7816_4_card import ISO_7816_4_Card
|
||||||
|
import utils, TLV_utils, generic_card
|
||||||
|
|
||||||
|
|
||||||
|
class VRS_Application(Application):
|
||||||
|
DRIVER_NAME = ["VRS"]
|
||||||
|
|
||||||
|
AID_LIST = [
|
||||||
|
"d2760000254b414e4d303100",
|
||||||
|
"d2760001354b414e4d303100",
|
||||||
|
]
|
||||||
|
|
||||||
|
class VrsTicket(object):
|
||||||
|
def __init__(self):
|
||||||
|
self._birthdate = None
|
||||||
|
self._maindata = []
|
||||||
|
self._mainblob = None
|
||||||
|
self._rawdata = None
|
||||||
|
self._tlvdata = None
|
||||||
|
self._card = None
|
||||||
|
|
||||||
|
def from_card(cls, card, record_no = 1):
|
||||||
|
if not isinstance(card, VRS_Application):
|
||||||
|
if not isinstance(card, ISO_7816_4_Card):
|
||||||
|
raise ValueError, "card must be a VRS_Application object or a ISO_7816_4_Card object, not %s" % type(card)
|
||||||
|
else:
|
||||||
|
result = card.select_application(binascii.a2b_hex(VRS_Application.AID_LIST[0]))
|
||||||
|
if not card.check_sw(result.sw):
|
||||||
|
raise EnvironmentError, "card did not accept SELECT APPLICATION, sw was %02x %02x" % (result.sw1, result.sw2)
|
||||||
|
assert isinstance(card, VRS_Application)
|
||||||
|
|
||||||
|
c = cls()
|
||||||
|
c._card = card
|
||||||
|
|
||||||
|
result = card.open_file("\x0c\x05")
|
||||||
|
if card.check_sw(result.sw):
|
||||||
|
contents = card.read_record(record_no, 4)
|
||||||
|
if len(contents) > 0:
|
||||||
|
c._parse( contents )
|
||||||
|
else:
|
||||||
|
raise KeyError, "No ticket in record no. %i" % record_no
|
||||||
|
else:
|
||||||
|
raise EnvironmentError, "card did not accept SELECT FILE, sw was %02x %02x" % (result.sw1, result.sw2)
|
||||||
|
|
||||||
|
return c
|
||||||
|
|
||||||
|
def _parse(self, contents):
|
||||||
|
self._rawdata = contents
|
||||||
|
self._tlvdata = TLV_utils.unpack(contents)
|
||||||
|
|
||||||
|
tmp = TLV_utils.tlv_find_tag(self._tlvdata, 0xEA, num_results = 1)
|
||||||
|
if len(tmp) == 0:
|
||||||
|
raise ValueError, "Can't parse information file, tag 0xEA not found"
|
||||||
|
tmp = TLV_utils.tlv_find_tag(tmp, 0x85, num_results = 1)
|
||||||
|
if len(tmp) == 0:
|
||||||
|
raise ValueError, "Can't parse information file, tag 0x85 not found"
|
||||||
|
self._mainblob = tmp[0][2]
|
||||||
|
|
||||||
|
tmp = self._mainblob
|
||||||
|
some_id, tmp = tmp[:4], tmp[4:]
|
||||||
|
|
||||||
|
ascii_field_len = ord(tmp[0])
|
||||||
|
tmp = tmp[1:]
|
||||||
|
|
||||||
|
ascii_field, tmp = tmp[:ascii_field_len], tmp[ascii_field_len:]
|
||||||
|
self._maindata = ascii_field.split(" ")
|
||||||
|
|
||||||
|
if len(tmp) > 0:
|
||||||
|
if tmp[0] == "\x01":
|
||||||
|
tmp = tmp[1:]
|
||||||
|
birthdate_bin, tmp = tmp[:4], tmp[4:]
|
||||||
|
|
||||||
|
birthdate = binascii.b2a_hex(birthdate_bin)
|
||||||
|
self._birthdate = datetime.date( int(birthdate[0:4]), int(birthdate[4:6]), int(birthdate[6:8]) )
|
||||||
|
|
||||||
|
if len(tmp) > 0:
|
||||||
|
print "Warning: unparsed data trailing: %r" % tmp
|
||||||
|
|
||||||
|
from_card = classmethod(from_card)
|
||||||
|
|
||||||
|
def getter(index, encoding=None):
|
||||||
|
def g(self):
|
||||||
|
if self._maindata is None or len(self._maindata) <= index:
|
||||||
|
return None
|
||||||
|
if encoding is None:
|
||||||
|
return unicode( self._maindata[index] )
|
||||||
|
else:
|
||||||
|
return unicode( self._maindata[index], encoding = encoding )
|
||||||
|
|
||||||
|
return g
|
||||||
|
|
||||||
|
def _get_alter(self):
|
||||||
|
now = datetime.date.fromtimestamp( time.time() )
|
||||||
|
diff = now.year-self.geburtsdatum.year
|
||||||
|
thisyearsbirthday = datetime.date( now.year, self.geburtsdatum.month, self.geburtsdatum.day )
|
||||||
|
if now < thisyearsbirthday: diff = diff - 1
|
||||||
|
return diff
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "%s: %s %s" % (self.tickettyp, self.name_klar, self.abonr)
|
||||||
|
|
||||||
|
|
||||||
|
tickettyp = property(getter(0))
|
||||||
|
rnummer = property(getter(1))
|
||||||
|
gueltigkeit = property(getter(2))
|
||||||
|
feld4 = property(getter(3))
|
||||||
|
name_raw = property(getter(4))
|
||||||
|
vorname = property(lambda self: self.name_raw and "".join(self.name_raw.split(",_")[1:]).replace("_", " "))
|
||||||
|
nachname = property(lambda self: self.name_raw and "".join(self.name_raw.split(",_")[:1]).replace("_", " "))
|
||||||
|
name_klar = property(lambda self: self.vorname + " " + self.nachname)
|
||||||
|
schule = abonr = property(getter(5,'cp850'))
|
||||||
|
geburtsdatum = property(lambda self: self._birthdate)
|
||||||
|
alter = property(lambda self: self._birthdate and self._get_alter())
|
||||||
|
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
from PassportGUI import *
|
from PassportGUI import *
|
||||||
|
from ireadyou import *
|
||||||
|
|
|
@ -0,0 +1,380 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: iso-8859-1 -*-
|
||||||
|
|
||||||
|
import gtk,gtk.glade,gobject
|
||||||
|
import sys, os, time
|
||||||
|
try:
|
||||||
|
import utils, TLV_utils, cards
|
||||||
|
except ImportError, e:
|
||||||
|
try:
|
||||||
|
sys.path.append(".")
|
||||||
|
import utils, TLV_utils, cards
|
||||||
|
except ImportError:
|
||||||
|
raise e
|
||||||
|
|
||||||
|
from smartcard.CardMonitoring import CardMonitor, CardObserver
|
||||||
|
from smartcard.ReaderMonitoring import ReaderMonitor, ReaderObserver
|
||||||
|
import smartcard
|
||||||
|
|
||||||
|
class FileLikeTextBuffer(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.had_newline = True
|
||||||
|
self.buffer = gtk.TextBuffer()
|
||||||
|
self.endmark = self.buffer.create_mark("The End", self.buffer.get_end_iter(), False)
|
||||||
|
self.views = []
|
||||||
|
|
||||||
|
def add_view(self, v):
|
||||||
|
self.views.append(v)
|
||||||
|
v.scroll_mark_onscreen( self.endmark )
|
||||||
|
|
||||||
|
def writelines(self, sequence):
|
||||||
|
for s in sequence: self.write(s)
|
||||||
|
|
||||||
|
def write(self, s):
|
||||||
|
d = "%s: " % time.strftime("%F %T")
|
||||||
|
|
||||||
|
parts = s.split("\n")
|
||||||
|
if self.had_newline:
|
||||||
|
self.had_newline = False
|
||||||
|
s = d
|
||||||
|
else:
|
||||||
|
s = ""
|
||||||
|
|
||||||
|
if parts[-1] == '':
|
||||||
|
del parts[-1]
|
||||||
|
self.had_newline = True
|
||||||
|
|
||||||
|
s = s + ("\n"+d).join(parts)
|
||||||
|
if self.had_newline: s = s + "\n"
|
||||||
|
|
||||||
|
self.buffer.insert( self.buffer.get_end_iter(), s)
|
||||||
|
for v in self.views:
|
||||||
|
v.scroll_mark_onscreen( self.endmark )
|
||||||
|
|
||||||
|
def flush(self): pass
|
||||||
|
|
||||||
|
def for_stream(self, stream):
|
||||||
|
class stream_to_buf(object):
|
||||||
|
def __init__(self, parent, stream):
|
||||||
|
self.parent = parent
|
||||||
|
self.stream = stream
|
||||||
|
|
||||||
|
def flush(self):
|
||||||
|
self.parent.flush()
|
||||||
|
self.stream.flush()
|
||||||
|
|
||||||
|
def write(self, s):
|
||||||
|
self.parent.write(s)
|
||||||
|
self.stream.write(s)
|
||||||
|
|
||||||
|
def writelines(self, s):
|
||||||
|
self.parent.writelines(s)
|
||||||
|
self.stream.writelines(s)
|
||||||
|
|
||||||
|
return stream_to_buf(self, stream)
|
||||||
|
|
||||||
|
class ireadyou(object,CardObserver,ReaderObserver):
|
||||||
|
GLADE_FILE = "gui/ireadyou/ireadyou.glade"
|
||||||
|
|
||||||
|
def __init__(self, ticket = None):
|
||||||
|
"Create and show main window."
|
||||||
|
self.main_window_xml = gtk.glade.XML(self.GLADE_FILE, "main")
|
||||||
|
self.main_window = self.main_window_xml.get_widget("main")
|
||||||
|
|
||||||
|
self.card_tabs = self.main_window_xml.get_widget("card_tabs")
|
||||||
|
while self.card_tabs.get_n_pages() > 0:
|
||||||
|
self.card_tabs.remove_page(0)
|
||||||
|
for t in self.CARD_TYPES:
|
||||||
|
a, b, l = gtk.Alignment(yscale=1,xscale=1,xalign=0.5,yalign=0.5), gtk.VBox(), gtk.Label(t[1])
|
||||||
|
a.add(b)
|
||||||
|
a.show()
|
||||||
|
b.show()
|
||||||
|
l.show()
|
||||||
|
|
||||||
|
self.card_tabs.append_page(a, tab_label=l)
|
||||||
|
|
||||||
|
self.ticket_button_group = gtk.RadioButton()
|
||||||
|
self.ticket_button_group._ticket = None
|
||||||
|
|
||||||
|
self.status_area = self.main_window_xml.get_widget("status_area")
|
||||||
|
self.known_readers = []
|
||||||
|
self.known_cards = {} # Note stupid: the keys to this dict are not objects from the known_readers list but rather reader name strings
|
||||||
|
self.connected_cards = {} # Again: the keys are not cards but repr(card)
|
||||||
|
self.tickets = {} # ditto
|
||||||
|
self.ticket_displayed = None # This is either None or a tuple (card object, ticket object)
|
||||||
|
|
||||||
|
self._update_status()
|
||||||
|
|
||||||
|
self.logbuf = FileLikeTextBuffer()
|
||||||
|
sys.stdout = self.logbuf.for_stream(sys.stdout)
|
||||||
|
sys.stderr = self.logbuf.for_stream(sys.stderr)
|
||||||
|
self.logview = self.main_window_xml.get_widget("logview")
|
||||||
|
self.logview.set_buffer(self.logbuf.buffer)
|
||||||
|
self.logbuf.add_view(self.logview)
|
||||||
|
|
||||||
|
signals = {
|
||||||
|
"on_exit_clicked": self.exit_clicked,
|
||||||
|
"on_main_delete_event": self.exit_clicked,
|
||||||
|
"on_main_destroy": gtk.main_quit,
|
||||||
|
}
|
||||||
|
self.main_window_xml.signal_autoconnect(signals)
|
||||||
|
|
||||||
|
self._clear_display()
|
||||||
|
|
||||||
|
self.rmon = ReaderMonitor()
|
||||||
|
self.cmon = CardMonitor()
|
||||||
|
|
||||||
|
self.rmon.addObserver(self)
|
||||||
|
self.cmon.addObserver(self)
|
||||||
|
|
||||||
|
def _clear_display(self):
|
||||||
|
self.card_tabs.set_current_page(0)
|
||||||
|
|
||||||
|
for i in range(self.card_tabs.get_n_pages()):
|
||||||
|
a = self.card_tabs.get_nth_page(i)
|
||||||
|
vbox = a.get_child()
|
||||||
|
for c in vbox.get_children():
|
||||||
|
vbox.remove(c)
|
||||||
|
label = self.card_tabs.get_tab_label(a)
|
||||||
|
label.set_property("sensitive", False)
|
||||||
|
|
||||||
|
def _update_status(self):
|
||||||
|
for c in self.status_area.get_children():
|
||||||
|
self.status_area.remove(c)
|
||||||
|
|
||||||
|
if len(self.known_readers) == 0:
|
||||||
|
self.status_area.add( gtk.Label(u"Keine Lesegeräte angeschlossen.") )
|
||||||
|
else:
|
||||||
|
for reader in self.known_readers:
|
||||||
|
frame = gtk.Frame(label=str(reader))
|
||||||
|
|
||||||
|
if len(self.known_cards[ reader.name ]) == 0:
|
||||||
|
frame.add( gtk.Label(u"Keine Karten verbunden.") )
|
||||||
|
else:
|
||||||
|
vbox = gtk.VBox()
|
||||||
|
for card in self.known_cards[ reader.name ]:
|
||||||
|
if self.connected_cards.has_key(repr(card)):
|
||||||
|
card_ = self.connected_cards[ repr(card) ]
|
||||||
|
cardname = card_.get_driver_name()
|
||||||
|
else:
|
||||||
|
cardname = str(card)
|
||||||
|
|
||||||
|
hbox = gtk.HBox()
|
||||||
|
cardlabel = gtk.Label( "<b>%s</b>: " % cardname )
|
||||||
|
cardlabel.set_use_markup(True)
|
||||||
|
hbox.pack_start(cardlabel, expand=False)
|
||||||
|
|
||||||
|
vbox2 = gtk.VBox()
|
||||||
|
hbox.pack_start(vbox2, expand=True)
|
||||||
|
for ticket in self.tickets[ repr(card) ]:
|
||||||
|
button = gtk.RadioButton(group=self.ticket_button_group, label=str(ticket), use_underline=False)
|
||||||
|
vbox2.pack_start(button, expand=False)
|
||||||
|
|
||||||
|
button.connect("toggled", self._ticket_button_toggled)
|
||||||
|
button._ticket = (card, ticket)
|
||||||
|
|
||||||
|
if self.ticket_displayed is not None and ticket == self.ticket_displayed[1]:
|
||||||
|
button.set_active(True)
|
||||||
|
|
||||||
|
vbox.add(hbox)
|
||||||
|
frame.add(vbox)
|
||||||
|
|
||||||
|
self.status_area.add(frame)
|
||||||
|
|
||||||
|
self.status_area.show_all()
|
||||||
|
|
||||||
|
def _format_datum(d):
|
||||||
|
return d.strftime("%x")
|
||||||
|
|
||||||
|
CARD_TYPES = [
|
||||||
|
(("SCHUL_T",),
|
||||||
|
"Schulticket", (
|
||||||
|
("Name", "name_klar", None),
|
||||||
|
("Alter", "alter", None),
|
||||||
|
("Geburtsdatum", "geburtsdatum", _format_datum),
|
||||||
|
("Schule", "schule", None),
|
||||||
|
(u"Kartengültigkeit", "gueltigkeit", None),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(("JOBT_ERW",),
|
||||||
|
"Jobticket", (
|
||||||
|
("Name", "name_klar", None),
|
||||||
|
("Geburtsdatum", "geburtsdatum", _format_datum),
|
||||||
|
(u"Kartengültigkeit", "gueltigkeit", None),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(("MT_ABO",),
|
||||||
|
"Monatsabo", (
|
||||||
|
("Abo-Nummer", "abonr", None),
|
||||||
|
(u"Kartengültigkeit", "gueltigkeit", None),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(None,
|
||||||
|
"Anderes", (
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
def _ticket_button_toggled(self, togglebutton):
|
||||||
|
self.ticket_displayed = None
|
||||||
|
for b in togglebutton.get_group():
|
||||||
|
if b.get_active():
|
||||||
|
if hasattr(b, "_ticket"):
|
||||||
|
self.ticket_displayed = b._ticket
|
||||||
|
self._update_ticket_display()
|
||||||
|
|
||||||
|
def _update_ticket_display(self):
|
||||||
|
self._clear_display()
|
||||||
|
if self.ticket_displayed is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
todisplay = self.ticket_displayed[1]
|
||||||
|
|
||||||
|
for i,t in enumerate(self.CARD_TYPES):
|
||||||
|
if todisplay.tickettyp in t[0]:
|
||||||
|
break
|
||||||
|
# Note: implicit selection of the last card type when no match is found
|
||||||
|
|
||||||
|
self.card_tabs.set_current_page(i)
|
||||||
|
a = self.card_tabs.get_nth_page(i)
|
||||||
|
vbox = a.get_child()
|
||||||
|
label = self.card_tabs.get_tab_label(a)
|
||||||
|
label.set_property("sensitive", True)
|
||||||
|
|
||||||
|
for labeltext, propertyname, transformation in t[2]:
|
||||||
|
frame = gtk.Frame(label=labeltext)
|
||||||
|
content = getattr(todisplay, propertyname, None)
|
||||||
|
contenttext = str( transformation is not None and transformation(content) or content )
|
||||||
|
contentlabel = gtk.Label("<b><tt><big>%s</big></tt></b>" % contenttext)
|
||||||
|
contentlabel.set_use_markup(True)
|
||||||
|
contentlabel.show()
|
||||||
|
frame.add( contentlabel )
|
||||||
|
frame.show()
|
||||||
|
|
||||||
|
vbox.add(frame)
|
||||||
|
|
||||||
|
def exit_clicked(self, widget, event=None, data=None):
|
||||||
|
gtk.main_quit()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
gtk.main()
|
||||||
|
|
||||||
|
# From the CardObserver and ReaderObserver classes
|
||||||
|
def update( self, observable, (added, removed) ):
|
||||||
|
try:
|
||||||
|
gtk.gdk.threads_enter()
|
||||||
|
#print observable, added, removed
|
||||||
|
if observable is self.rmon.instance:
|
||||||
|
self.reader_update(observable, (added, removed) )
|
||||||
|
elif observable is self.cmon.instance:
|
||||||
|
self.card_update(observable, (added, removed) )
|
||||||
|
self._update_status()
|
||||||
|
self._update_ticket_display()
|
||||||
|
finally:
|
||||||
|
gtk.gdk.threads_leave()
|
||||||
|
|
||||||
|
def reader_update( self, observable, (added, removed) ):
|
||||||
|
for r in removed:
|
||||||
|
if r in self.known_readers:
|
||||||
|
for card in list(self.known_cards[ r.name ]):
|
||||||
|
self._remove_card(card)
|
||||||
|
assert len(self.known_cards[ r.name ]) == 0
|
||||||
|
del self.known_cards[ r.name ]
|
||||||
|
self.known_readers.remove(r)
|
||||||
|
for a in added:
|
||||||
|
if a not in self.known_readers:
|
||||||
|
self.known_readers.append(a)
|
||||||
|
self.known_cards[ a.name ] = []
|
||||||
|
|
||||||
|
def card_update( self, observable, (added, removed) ):
|
||||||
|
for r in removed:
|
||||||
|
if not self.known_cards.has_key(r.reader): continue
|
||||||
|
if r in self.known_cards[r.reader]:
|
||||||
|
self._remove_card(r)
|
||||||
|
for a in added:
|
||||||
|
if not self.known_cards.has_key(a.reader): continue
|
||||||
|
if a not in self.known_cards[a.reader]:
|
||||||
|
self._add_card(a)
|
||||||
|
|
||||||
|
def _add_card(self, card):
|
||||||
|
self.known_cards[ card.reader ].append(card)
|
||||||
|
if not self.tickets.has_key( repr(card) ):
|
||||||
|
self.tickets[ repr(card) ] = []
|
||||||
|
|
||||||
|
conn = card.createConnection()
|
||||||
|
connected = False
|
||||||
|
try:
|
||||||
|
conn.connect()
|
||||||
|
connected = True
|
||||||
|
except smartcard.Exceptions.NoCardException, e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if connected:
|
||||||
|
card_ = cards.new_card_object(conn)
|
||||||
|
cards.generic_card.DEBUG = False
|
||||||
|
self.connected_cards[ repr(card) ] = card_
|
||||||
|
|
||||||
|
for i in range(1,9):
|
||||||
|
try:
|
||||||
|
ticket = cards.vrs_application.VrsTicket.from_card(card_, record_no = i)
|
||||||
|
print "Loaded ticket '%s' from record %i" % (ticket, i)
|
||||||
|
self._add_ticket(card, ticket)
|
||||||
|
except (KeyboardInterrupt, SystemExit):
|
||||||
|
raise
|
||||||
|
except Exception,e:
|
||||||
|
if not str(e).startswith("'No ticket in record no."):
|
||||||
|
print e
|
||||||
|
|
||||||
|
if not isinstance(card_, cards.vrs_application.VRS_Application):
|
||||||
|
break
|
||||||
|
|
||||||
|
def _remove_card(self, card):
|
||||||
|
if self.tickets.has_key( repr(card) ):
|
||||||
|
for t in list(self.tickets[ repr(card) ]):
|
||||||
|
self._remove_ticket(card, t)
|
||||||
|
assert len(self.tickets[ repr(card) ]) == 0
|
||||||
|
del self.tickets[ repr(card) ]
|
||||||
|
|
||||||
|
if self.connected_cards.has_key( repr(card) ):
|
||||||
|
try:
|
||||||
|
self.connected_cards[ repr(card) ].close_card()
|
||||||
|
except smartcard.Exceptions.CardConnectionException, e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
del self.connected_cards[ repr(card) ]
|
||||||
|
self.known_cards[ card.reader ].remove(card)
|
||||||
|
|
||||||
|
def _add_ticket(self, card, ticket):
|
||||||
|
self.tickets[ repr(card) ].append( ticket )
|
||||||
|
if self.ticket_displayed is None:
|
||||||
|
self.ticket_displayed = ( card, ticket )
|
||||||
|
|
||||||
|
def _remove_ticket(self, card, ticket):
|
||||||
|
if self.ticket_displayed is not None and self.ticket_displayed[1] == ticket:
|
||||||
|
self.ticket_displayed = None
|
||||||
|
# TODO: Find a different ticket to display
|
||||||
|
self.tickets[ repr(card) ].remove(ticket)
|
||||||
|
|
||||||
|
OPTIONS = ""
|
||||||
|
LONG_OPTIONS = []
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
## c = utils.CommandLineArgumentHelper()
|
||||||
|
##
|
||||||
|
## (options, arguments) = c.getopt(sys.argv[1:], OPTIONS, LONG_OPTIONS)
|
||||||
|
##
|
||||||
|
## card_object = c.connect()
|
||||||
|
## card = cards.new_card_object(card_object)
|
||||||
|
## #cards.generic_card.DEBUG = False
|
||||||
|
##
|
||||||
|
## print >>sys.stderr, "Using %s" % card.DRIVER_NAME
|
||||||
|
##
|
||||||
|
## if len(arguments) > 0:
|
||||||
|
## ticket = cards.vrs_application.VrsTicket.from_card(card, record_no = int(arguments[0], 0))
|
||||||
|
## else:
|
||||||
|
## ticket = cards.vrs_application.VrsTicket.from_card(card)
|
||||||
|
|
||||||
|
gtk.gdk.threads_init()
|
||||||
|
g = ireadyou()
|
||||||
|
g.run()
|
|
@ -0,0 +1,337 @@
|
||||||
|
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||||
|
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
|
||||||
|
|
||||||
|
<glade-interface>
|
||||||
|
|
||||||
|
<widget class="GtkWindow" id="main">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="title" translatable="yes">iReadYou</property>
|
||||||
|
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||||
|
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||||
|
<property name="modal">False</property>
|
||||||
|
<property name="resizable">True</property>
|
||||||
|
<property name="destroy_with_parent">False</property>
|
||||||
|
<property name="decorated">True</property>
|
||||||
|
<property name="skip_taskbar_hint">False</property>
|
||||||
|
<property name="skip_pager_hint">False</property>
|
||||||
|
<property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
|
||||||
|
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||||
|
<property name="focus_on_map">True</property>
|
||||||
|
<property name="urgency_hint">False</property>
|
||||||
|
<signal name="destroy" handler="on_main_destroy" last_modification_time="Tue, 10 Jun 2008 03:23:32 GMT"/>
|
||||||
|
<signal name="delete_event" handler="on_main_delete_event" last_modification_time="Tue, 10 Jun 2008 03:23:40 GMT"/>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkAlignment" id="alignment4">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="yalign">0</property>
|
||||||
|
<property name="xscale">1</property>
|
||||||
|
<property name="yscale">1</property>
|
||||||
|
<property name="top_padding">0</property>
|
||||||
|
<property name="bottom_padding">0</property>
|
||||||
|
<property name="left_padding">0</property>
|
||||||
|
<property name="right_padding">0</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkVBox" id="vbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="homogeneous">False</property>
|
||||||
|
<property name="spacing">0</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkAlignment" id="alignment5">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="xalign">0.5</property>
|
||||||
|
<property name="yalign">0.5</property>
|
||||||
|
<property name="xscale">1</property>
|
||||||
|
<property name="yscale">1</property>
|
||||||
|
<property name="top_padding">0</property>
|
||||||
|
<property name="bottom_padding">0</property>
|
||||||
|
<property name="left_padding">0</property>
|
||||||
|
<property name="right_padding">0</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkFrame" id="frame1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label_xalign">0</property>
|
||||||
|
<property name="label_yalign">0.5</property>
|
||||||
|
<property name="shadow_type">GTK_SHADOW_NONE</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkAlignment" id="alignment1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="yalign">0</property>
|
||||||
|
<property name="xscale">0</property>
|
||||||
|
<property name="yscale">0</property>
|
||||||
|
<property name="top_padding">0</property>
|
||||||
|
<property name="bottom_padding">0</property>
|
||||||
|
<property name="left_padding">12</property>
|
||||||
|
<property name="right_padding">0</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkNotebook" id="card_tabs">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="show_tabs">True</property>
|
||||||
|
<property name="show_border">True</property>
|
||||||
|
<property name="tab_pos">GTK_POS_TOP</property>
|
||||||
|
<property name="scrollable">False</property>
|
||||||
|
<property name="enable_popup">False</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkVBox" id="bar">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="homogeneous">False</property>
|
||||||
|
<property name="spacing">0</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkLabel" id="label11">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">label11</property>
|
||||||
|
<property name="use_underline">False</property>
|
||||||
|
<property name="use_markup">False</property>
|
||||||
|
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||||
|
<property name="wrap">False</property>
|
||||||
|
<property name="selectable">False</property>
|
||||||
|
<property name="xalign">0.5</property>
|
||||||
|
<property name="yalign">0.5</property>
|
||||||
|
<property name="xpad">0</property>
|
||||||
|
<property name="ypad">0</property>
|
||||||
|
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||||
|
<property name="width_chars">-1</property>
|
||||||
|
<property name="single_line_mode">False</property>
|
||||||
|
<property name="angle">0</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">0</property>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="tab_expand">False</property>
|
||||||
|
<property name="tab_fill">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkLabel" id="label10">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">label10</property>
|
||||||
|
<property name="use_underline">False</property>
|
||||||
|
<property name="use_markup">False</property>
|
||||||
|
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||||
|
<property name="wrap">False</property>
|
||||||
|
<property name="selectable">False</property>
|
||||||
|
<property name="xalign">0.5</property>
|
||||||
|
<property name="yalign">0.5</property>
|
||||||
|
<property name="xpad">0</property>
|
||||||
|
<property name="ypad">0</property>
|
||||||
|
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||||
|
<property name="width_chars">-1</property>
|
||||||
|
<property name="single_line_mode">False</property>
|
||||||
|
<property name="angle">0</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="type">tab</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkLabel" id="label1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes"><b>Kartendaten</b></property>
|
||||||
|
<property name="use_underline">False</property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||||
|
<property name="wrap">False</property>
|
||||||
|
<property name="selectable">False</property>
|
||||||
|
<property name="xalign">0.5</property>
|
||||||
|
<property name="yalign">0.5</property>
|
||||||
|
<property name="xpad">0</property>
|
||||||
|
<property name="ypad">0</property>
|
||||||
|
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||||
|
<property name="width_chars">-1</property>
|
||||||
|
<property name="single_line_mode">False</property>
|
||||||
|
<property name="angle">0</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="type">label_item</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">0</property>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkFrame" id="frame2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label_xalign">0</property>
|
||||||
|
<property name="label_yalign">0.5</property>
|
||||||
|
<property name="shadow_type">GTK_SHADOW_NONE</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkAlignment" id="alignment2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="yalign">0</property>
|
||||||
|
<property name="xscale">0</property>
|
||||||
|
<property name="yscale">1</property>
|
||||||
|
<property name="top_padding">0</property>
|
||||||
|
<property name="bottom_padding">0</property>
|
||||||
|
<property name="left_padding">12</property>
|
||||||
|
<property name="right_padding">0</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkVBox" id="status_area">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="homogeneous">False</property>
|
||||||
|
<property name="spacing">0</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkLabel" id="label2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes"><b>Status</b></property>
|
||||||
|
<property name="use_underline">False</property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||||
|
<property name="wrap">False</property>
|
||||||
|
<property name="selectable">False</property>
|
||||||
|
<property name="xalign">0.5</property>
|
||||||
|
<property name="yalign">0.5</property>
|
||||||
|
<property name="xpad">0</property>
|
||||||
|
<property name="ypad">0</property>
|
||||||
|
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||||
|
<property name="width_chars">-1</property>
|
||||||
|
<property name="single_line_mode">False</property>
|
||||||
|
<property name="angle">0</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="type">label_item</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">0</property>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkExpander" id="expander1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="expanded">False</property>
|
||||||
|
<property name="spacing">0</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkAlignment" id="alignment3">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="xalign">0.5</property>
|
||||||
|
<property name="yalign">0.5</property>
|
||||||
|
<property name="xscale">1</property>
|
||||||
|
<property name="yscale">1</property>
|
||||||
|
<property name="top_padding">0</property>
|
||||||
|
<property name="bottom_padding">0</property>
|
||||||
|
<property name="left_padding">12</property>
|
||||||
|
<property name="right_padding">0</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkScrolledWindow" id="scrolledwindow1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||||
|
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||||
|
<property name="shadow_type">GTK_SHADOW_IN</property>
|
||||||
|
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkTextView" id="logview">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="editable">False</property>
|
||||||
|
<property name="overwrite">False</property>
|
||||||
|
<property name="accepts_tab">True</property>
|
||||||
|
<property name="justification">GTK_JUSTIFY_LEFT</property>
|
||||||
|
<property name="wrap_mode">GTK_WRAP_NONE</property>
|
||||||
|
<property name="cursor_visible">True</property>
|
||||||
|
<property name="pixels_above_lines">0</property>
|
||||||
|
<property name="pixels_below_lines">0</property>
|
||||||
|
<property name="pixels_inside_wrap">0</property>
|
||||||
|
<property name="left_margin">0</property>
|
||||||
|
<property name="right_margin">0</property>
|
||||||
|
<property name="indent">0</property>
|
||||||
|
<property name="text" translatable="yes"></property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkLabel" id="label12">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes"><b>Log</b></property>
|
||||||
|
<property name="use_underline">False</property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||||
|
<property name="wrap">False</property>
|
||||||
|
<property name="selectable">False</property>
|
||||||
|
<property name="xalign">0.5</property>
|
||||||
|
<property name="yalign">0.5</property>
|
||||||
|
<property name="xpad">0</property>
|
||||||
|
<property name="ypad">0</property>
|
||||||
|
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||||
|
<property name="width_chars">-1</property>
|
||||||
|
<property name="single_line_mode">False</property>
|
||||||
|
<property name="angle">0</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="type">label_item</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">0</property>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
|
||||||
|
</glade-interface>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||||
|
<!DOCTYPE glade-project SYSTEM "http://glade.gnome.org/glade-project-2.0.dtd">
|
||||||
|
|
||||||
|
<glade-project>
|
||||||
|
<name>iReadYou</name>
|
||||||
|
<program_name>ireadyou</program_name>
|
||||||
|
<gnome_support>FALSE</gnome_support>
|
||||||
|
</glade-project>
|
Loading…
Reference in New Issue