Edit an experience entry by double-clicking on the tree
[crapvine.git] / grapevine_xml.py
blob7f026bdadea6d4f73390115cd437f9f1071c8244
1 ## This file is part of Crapvine.
2 ##
3 ## Copyright (C) 2007 Andrew Sayman <lorien420@myrealbox.com>
4 ##
5 ## Crapvine is free software; you can redistribute it and/or modify
6 ## it under the terms of the GNU General Public License as published by
7 ## the Free Software Foundation; either version 3 of the License, or
8 ## (at your option) any later version.
9 ##
10 ## Crapvine is distributed in the hope that it will be useful,
11 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ## GNU General Public License for more details.
15 ## You should have received a copy of the GNU General Public License
16 ## along with this program. If not, see <http://www.gnu.org/licenses/>.
18 from __future__ import with_statement
19 import gtk
20 from xml.sax.saxutils import quoteattr, unescape
21 from xml.sax import sax2exts
22 from xml.sax.handler import feature_namespaces, property_lexical_handler
23 from dateutil.parser import parse
24 from datetime import datetime
26 from attribute import AttributeBuilder, classmaker
28 class AttributeReader:
29 def __init__(self, attrs):
30 self.attrs = attrs
32 def boolean(self, name, default=False):
33 if self.attrs.has_key(name):
34 bool_val = self.attrs.get(name)
35 if bool_val == 'yes':
36 return True
37 elif bool_val == 'no':
38 return False
39 else:
40 raise 'Boolean xml field set to invalid value |%s|' % (bool_val)
41 return False
42 def b(self, name, default=False):
43 return self.boolean(name, default)
45 def text(self, name, default=''):
46 if self.attrs.has_key(name):
47 return self.attrs.get(name)
48 return default
49 def t(self, name, default=''):
50 return self.text(name, default)
52 def number_as_text(self, name, default='0'):
53 # Should eventually verify that it's a number
54 return text(name, default)
55 def nat(self, name, default='0'):
56 return self.number_as_text(name, default)
58 def date(self, name, default='unknown'):
59 # Should eventually parse the date?
60 return text(name, default)
61 def d(self, name, default='unknown'):
62 return self.date(name, default)
64 class Attributed(object):
65 __metaclass__ = AttributeBuilder
66 def read_attributes(self, attrs):
67 r = AttributeReader(attrs)
68 required_matched = []
69 for attr in getattr(self, 'required_attrs', []):
70 if attrs.has_key(attr):
71 setattr(self, attr, unescape(attrs.get(attr)))
72 required_matched.append(attr)
73 if getattr(self, 'required_attrs', []) != required_matched:
74 raise AttributeError('Some required attributes were not found!')
75 for attr in getattr(self, 'text_attrs', []):
76 if attrs.has_key(attr):
77 setattr(self, attr, unescape(attrs.get(attr)))
78 for attr in getattr(self, 'number_as_text_attrs', []):
79 if attrs.has_key(attr):
80 setattr(self, attr, unescape(attrs.get(attr)))
81 for attr in getattr(self, 'date_attrs', []):
82 if attrs.has_key(attr):
83 setattr(self, attr, unescape(attrs.get(attr)))
84 for attr in getattr(self, 'bool_attrs', []):
85 setattr(self, attr, r.b(attr))
87 def __attr_default(self, name):
88 return getattr(self.__class__, name).default == getattr(self, name)
90 def get_attrs_xml(self):
91 attrs_strs = []
92 attrs_strs.extend(['%s=%s' % (name, quoteattr(self[name])) for name in getattr(self, 'required_attrs', []) if not self.__attr_default(name)])
93 attrs_strs.extend(['%s=%s' % (name, quoteattr(self[name])) for name in getattr(self, 'text_attrs', []) if not self.__attr_default(name)])
94 attrs_strs.extend(['%s=%s' % (name, quoteattr(getattr(self, name))) for name in getattr(self, 'number_as_text_attrs', []) if not self.__attr_default(name)])
95 attrs_strs.extend(['%s=%s' % (name, quoteattr(str(self[name]))) for name in getattr(self, 'date_attrs', []) if not self.__attr_default(name)])
96 for bool_attr in getattr(self, 'bool_attrs', []):
97 if not self.__attr_default(bool_attr):
98 my_bool = 'yes' if self[bool_attr] else 'no'
99 attrs_strs.append('%s="%s"' % (bool_attr, my_bool))
100 return ' '.join(attrs_strs)
102 def __setitem__(self, name, value):
103 return setattr(self, name, value)
104 def __getitem__(self, name):
105 return getattr(self, name)
107 class AttributedListModel(Attributed, gtk.GenericTreeModel):
108 __metaclass__ = classmaker()
110 def __init__(self):
111 Attributed.__init__(self)
112 gtk.GenericTreeModel.__init__(self)
113 def get_item(self, index):
114 return self.list[index]
115 def get_item_from_path(self, path):
116 return self.list[path[0]]
117 def on_get_flags(self):
118 return gtk.TREE_MODEL_LIST_ONLY
119 def on_get_n_columns(self):
120 return len(self.column_attrs)
121 def on_get_column_type(self, index):
122 return self.column_attr_types[index]
123 def on_get_path(self, iter):
124 if len(self.list) == 0:
125 return None
126 return (iter, )
127 def on_get_iter(self, path):
128 if len(self.list) == 0:
129 return None
130 return path[0]
131 def on_get_value(self, index, column):
132 if len(self.list) == 0:
133 return None
134 list = self.list[index]
135 return list[self.column_attrs[column]]
136 def on_iter_next(self, index):
137 if index >= (len(self.list) - 1):
138 return None
139 return index + 1
140 def on_iter_children(self, node):
141 return None
142 def on_iter_has_child(self, node):
143 return False
144 def on_iter_n_children(self, iter):
145 if iter:
146 return 0
147 return len(self.list)
148 def on_iter_nth_child(self, parent, n):
149 if parent:
150 return None
151 try:
152 self.list[n]
153 except IndexError:
154 return None
155 else:
156 return n
157 def on_iter_parent(self, node):
158 return None
160 class GEX(object):
161 def __init__(self):
162 self.filename = None
163 self.chronicle_loader = None
165 def load_from_file(self, filename):
166 from chronicle_loader import ChronicleLoader
167 self.filename = filename
168 self.chronicle_loader = ChronicleLoader()
170 parser = sax2exts.make_parser()
171 parser.setFeature(feature_namespaces, 0)
172 parser.setContentHandler(self.chronicle_loader)
173 parser.setProperty(property_lexical_handler, self.chronicle_loader)
174 print parser
175 parser.parse(self.filename)
177 def save_contents_to_file(self, filename):
178 all_character_xml = [c.get_xml(' ') for c in self.loader.chronicle_loader.vampires.values()]
179 out = ['<?xml version="1.0"?>',
180 '<grapevine version="3">']
181 out.extend(all_character_xml)
182 out.append('</grapevine>')
183 with file(filename, 'w') as f:
184 f.write("\n".join(out))