show errors on stderr
[dana/openbox.git] / tools / themeupdate / themeupdate.py
1 #! /usr/bin/python
2
3 import sys
4
5 data = []
6 valid = True
7
8 def out(str):
9     sys.stderr.write(str)
10     sys.stderr.flush()
11
12 def read_bool():
13     while True:
14         inp = sys.stdin.readline(1).strip()
15         if inp == 'y' or inp == '': return True
16         if inp == 'n': return False
17
18 def getkeyval(line):
19     key = line[:line.find(':')].strip()
20     value = line[line.find(':') + 1:].strip()
21     if not (key and value):
22         key = value = None
23     return key, value
24
25 def find_key(data, keysubstr, exact = False):
26     i = 0
27     n = len(data)
28     while i < n:
29         l = data[i]
30         key, value = getkeyval(l)
31         if key and value:
32             if (exact and key == keysubstr) or \
33                (not exact and key.find(keysubstr) != -1):
34                 return i, key, value
35         i += 1
36     return -1, None, None
37
38 def simple_replace(data):
39     pairs = {}
40     pairs['window.focus.font'] = 'window.label.focus.font'
41     pairs['window.unfocus.font'] = 'window.label.unfocus.font'
42     pairs['window.justify'] = 'window.label.justify'
43     pairs['menu.frame.disableColor'] = 'menu.disabled.textColor'
44     pairs['menu.frame'] = 'menu.items'
45     pairs['menu.hilite'] = 'menu.selected'
46     pairs['.picColor'] = '.imageColor'
47
48     for k in pairs.keys():
49         while 1:
50             i, key, nul = find_key(data, k);
51             if i >= 0:
52                 newl = data[i].replace(k, pairs[k])
53                 out('Updating "' + key +
54                     '" to "' + key.replace(k, pairs[k]) + '"\n')
55                 data[i] = newl
56             else:
57                 break
58
59 def remove(data):
60     invalid = []
61     invalid.append('toolbar')
62     invalid.append('rootCommand')
63     invalid.append('menu.frame.justify')
64     for inv in invalid:
65         while 1:
66             i, key, nul = find_key(data, inv)
67             if i >= 0:
68                 out(key + ' is no longer supported.\nRemove (Y/n)? ')
69                 if read_bool():
70                     out('Removing "' + key + '"\n')
71                     data.pop(i)
72             else:
73                 break
74
75 def pressed(data):
76     i, nul, nul = find_key(data, 'window.button.pressed', True)
77     if i >= 0:
78         out('The window.button.pressed option has been replaced by ' +
79             'window.button.pressed.focus and ' +
80             'window.button.pressed.unfocus.\nUpdate (Y/n)? ')
81         if read_bool():
82             l = data[i]
83             out('Removing "window.button.pressed"\n')
84             data.pop(i)
85             out('Adding "window.button.pressed.unfocus"\n')
86             data.insert(i, l.replace('window.button.pressed',
87                                              'window.button.pressed.unfocus'))
88             out('Adding "window.button.pressed.focus"\n')
89             data.insert(i, l.replace('window.button.pressed',
90                                      'window.button.pressed.focus'))
91
92 def x_fonts(data):
93     i, nul, nul = find_key(data, 'window.font')
94     if i >= 0:
95         out('You appear to specify fonts using the old X fonts ' +
96             'syntax.\nShall I remove all fonts from the theme (Y/n)? ')
97         if not read_bool():
98             return
99     else: return
100     while 1:
101         i, key = key_find(data, '.font')
102         if i < 0:
103             break
104         out('Removing "' + key + '"\n')
105         data.pop(i)
106
107 def xft_fonts(data):
108     i, nul, nul = find_key(data, '.xft.')
109     if i >= 0:
110         out('You appear to specify fonts using the old Xft fonts ' +
111             'syntax.\nShall I update these to the new syntax (Y/n)? ')
112         if not read_bool():
113             return
114     else: return
115     fonts = {}
116     fonts['window'] = 'window.label.focus.font'
117     fonts['menu.items'] = 'menu.items.font'
118     fonts['menu.title'] = 'menu.title.font'
119     for f in fonts.keys():
120         li, nul, flags = find_key(data, f + '.xft.flags')
121         if li < 0:
122             li, nul, flags = find_key(data, '*.xft.flags')
123         else:
124             out('Removing ' + f + '.xft.flags\n')
125             data.pop(li)
126         oi, nul, offset = find_key(data, f + '.xft.shadow.offset')
127         if oi < 0:
128             oi, nul, offset = find_key(data, '*.xft.shadow.offset')
129         else:
130             out('Removing ' + f + '.xft.shadow.offset\n')
131             data.pop(oi)
132         ti, nul, tint = find_key(data, f + '.xft.shadow.tint')
133         if ti < 0:
134             ti, nul, tint = find_key(data, '*.xft.shadow.tint')
135         else:
136             out('Removing ' + f + '.xft.shadow.tint\n')
137             data.pop(ti)
138         fi, nul, face = find_key(data, f + '.xft.font')
139         if fi < 0:
140             fi, nul, face = find_key(data, '*.xft.font')
141             if fi >= 0: fi = len(data) - 1
142         else:
143             out('Removing ' + f + '.xft.font\n')
144             data.pop(fi)
145
146         if fi >= 0:
147             s = face
148             if li >= 0:
149                 if flags.find('bold'):
150                     s = s + ':bold'
151                 if flags.find('shadow'):
152                     s = s + ':shadow=y'
153             if oi >= 0:
154                 s = s + ':shadowoffset=' + offset
155             if ti >= 0:
156                 s = s + ':shadowtint=' + tint
157         out('Adding ' + fonts[f] + '\n')
158         data.insert(fi, fonts[f] + ': ' + s)
159
160     for stars in ('*.xft.flags', '*.xft.shadow.offset' ,
161                   '*.xft.shadow.tint', '*.xft.font'):
162         i, key, nul = find_key(data, stars)
163         if i >= 0:
164             out('Removing ' + key + '\n')
165             data.pop(i)
166
167 def pixelsize(data):
168     fonts = ('window.label.focus.font',
169              'menu.items.font',
170              'menu.title.font')
171     for f in fonts:
172         i, key, value = find_key(data, f, True)
173         if value:
174             if value.find('pixelsize') == -1:
175                 out('*** ERROR *** The ' + key + ' font size is not being '
176                     'specified by pixelsize. It is recommended that you use '
177                     'pixelsize instead of pointsize for specifying theme '
178                     'fonts. e.g. "sans:pixelsize=12"\n')
179                 global valid
180                 valid = False
181
182 def warn_missing(data):
183     need = ('window.button.hover.focus',  'window.button.hover.unfocus',
184             'menuOverlap')
185     for n in need:
186         i, nul, nul = find_key(data, n)
187         if i < 0:
188             out('The ' + n + ' value was not found in the theme, but it '
189                 'can optionally be set.\n')
190
191 def err_missing(data):
192     need = ('window.button.disabled.focus',  'window.button.disabled.unfocus',
193             'window.frame.focusColor', 'window.frame.unfocusColor')
194     for n in need:
195         i, nul, nul = find_key(data, n)
196         if i < 0:
197             out('*** ERROR *** The ' + n + ' value was not found in the '
198                 'theme, but it is required to be set.\n')
199             global valid
200             valid = False
201
202
203 def usage():
204     out('Usage: themupdate.py /path/to/themerc > newthemerc\n\n')
205     sys.exit()
206
207 try:
208     file = open(sys.argv[1])
209 except IndexError:
210     usage()
211 except IOError:
212     out('Unable to open file "' + sys.argv[1] + '"\n\n')
213     usage()
214
215 data = file.readlines()
216 for i in range(len(data)):
217     data[i] = data[i].strip()
218
219 simple_replace(data)
220 remove(data)
221 pressed(data)
222 x_fonts(data)
223 xft_fonts(data)
224 pixelsize(data)
225 warn_missing(data)
226 err_missing(data)
227
228 for l in data:
229     print l
230
231 sys.exit(not valid)