Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(215)

Side by Side Diff: grit/format/policy_templates/writers/doc_writer.py

Issue 7994004: Initial source commit to grit-i18n project. (Closed) Base URL: http://grit-i18n.googlecode.com/svn/trunk/
Patch Set: Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5
6 import re
7
8 from xml.dom import minidom
9 from grit.format.policy_templates.writers import xml_formatted_writer
10
11
12 def GetWriter(config):
13 '''Factory method for creating DocWriter objects.
14 See the constructor of TemplateWriter for description of
15 arguments.
16 '''
17 return DocWriter(['*'], config)
18
19
20 class DocWriter(xml_formatted_writer.XMLFormattedWriter):
21 '''Class for generating policy templates in HTML format.
22 The intended use of the generated file is to upload it on
23 http://dev.chromium.org, therefore its format has some limitations:
24 - No HTML and body tags.
25 - Restricted set of element attributes: for example no 'class'.
26 Because of the latter the output is styled using the 'style'
27 attributes of HTML elements. This is supported by the dictionary
28 self._STYLES[] and the method self._AddStyledElement(), they try
29 to mimic the functionality of CSS classes. (But without inheritance.)
30
31 This class is invoked by PolicyTemplateGenerator to create the HTML
32 files.
33 '''
34
35 def _GetLocalizedMessage(self, msg_id):
36 '''Returns a localized message for this writer.
37
38 Args:
39 msg_id: The identifier of the message.
40
41 Returns:
42 The localized message.
43 '''
44 return self.messages['doc_' + msg_id]['text']
45
46 def _MapListToString(self, item_map, items):
47 '''Creates a comma-separated list.
48
49 Args:
50 item_map: A dictionary containing all the elements of 'items' as
51 keys.
52 items: A list of arbitrary items.
53
54 Returns:
55 Looks up each item of 'items' in 'item_maps' and concatenates the
56 resulting items into a comma-separated list.
57 '''
58 return ', '.join([item_map[x] for x in items])
59
60 def _AddTextWithLinks(self, parent, text):
61 '''Parse a string for URLs and add it to a DOM node with the URLs replaced
62 with <a> HTML links.
63
64 Args:
65 parent: The DOM node to which the text will be added.
66 text: The string to be added.
67 '''
68 # Iterate through all the URLs and replace them with links.
69 out = []
70 while True:
71 # Look for the first URL.
72 res = self._url_matcher.search(text)
73 if not res:
74 break
75 # Calculate positions of the substring of the URL.
76 url = res.group(0)
77 start = res.start(0)
78 end = res.end(0)
79 # Add the text prior to the URL.
80 self.AddText(parent, text[:start])
81 # Add a link for the URL.
82 self.AddElement(parent, 'a', {'href': url}, url)
83 # Drop the part of text that is added.
84 text = text[end:]
85 self.AddText(parent, text)
86
87
88 def _AddStyledElement(self, parent, name, style_ids, attrs=None, text=None):
89 '''Adds an XML element to a parent, with CSS style-sheets included.
90
91 Args:
92 parent: The parent DOM node.
93 name: Name of the element to add.
94 style_ids: A list of CSS style strings from self._STYLE[].
95 attrs: Dictionary of attributes for the element.
96 text: Text content for the element.
97 '''
98 if attrs == None:
99 attrs = {}
100
101 style = ''.join([self._STYLE[x] for x in style_ids])
102 if style != '':
103 # Apply the style specified by style_ids.
104 attrs['style'] = style + attrs.get('style', '')
105 return self.AddElement(parent, name, attrs, text)
106
107 def _AddDescription(self, parent, policy):
108 '''Adds a string containing the description of the policy. URLs are
109 replaced with links and the possible choices are enumerated in case
110 of 'string-enum' and 'int-enum' type policies.
111
112 Args:
113 parent: The DOM node for which the feature list will be added.
114 policy: The data structure of a policy.
115 '''
116 # Replace URLs with links in the description.
117 self._AddTextWithLinks(parent, policy['desc'])
118 # Add list of enum items.
119 if policy['type'] in ('string-enum', 'int-enum'):
120 ul = self.AddElement(parent, 'ul')
121 for item in policy['items']:
122 if policy['type'] == 'int-enum':
123 value_string = str(item['value'])
124 else:
125 value_string = '"%s"' % item['value']
126 self.AddElement(
127 ul, 'li', {}, '%s = %s' % (value_string, item['caption']))
128
129 def _AddFeatures(self, parent, policy):
130 '''Adds a string containing the list of supported features of a policy
131 to a DOM node. The text will look like as:
132 Feature_X: Yes, Feature_Y: No
133
134 Args:
135 parent: The DOM node for which the feature list will be added.
136 policy: The data structure of a policy.
137 '''
138 features = []
139 for key, value in policy['features'].iteritems():
140 key_name = self._FEATURE_MAP[key]
141 if value == 0:
142 value_name = self._GetLocalizedMessage('not_supported')
143 else:
144 value_name = self._GetLocalizedMessage('supported')
145 features.append('%s: %s' % (key_name, value_name))
146 self.AddText(parent, ', '.join(features))
147
148 def _AddListExampleMac(self, parent, policy):
149 '''Adds an example value for Mac of a 'list' policy to a DOM node.
150
151 Args:
152 parent: The DOM node for which the example will be added.
153 policy: A policy of type 'list', for which the Mac example value
154 is generated.
155 '''
156 example_value = policy['example_value']
157 self.AddElement(parent, 'dt', {}, 'Mac:')
158 mac = self._AddStyledElement(parent, 'dd', ['.monospace', '.pre'])
159
160 mac_text = ['<array>']
161 for item in example_value:
162 mac_text.append(' <string>%s</string>' % item)
163 mac_text.append('</array>')
164 self.AddText(mac, '\n'.join(mac_text))
165
166 def _AddListExampleWindows(self, parent, policy):
167 '''Adds an example value for Windows of a 'list' policy to a DOM node.
168
169 Args:
170 parent: The DOM node for which the example will be added.
171 policy: A policy of type 'list', for which the Windows example value
172 is generated.
173 '''
174 example_value = policy['example_value']
175 self.AddElement(parent, 'dt', {}, 'Windows:')
176 win = self._AddStyledElement(parent, 'dd', ['.monospace', '.pre'])
177 win_text = []
178 cnt = 1
179 for item in example_value:
180 win_text.append(
181 '%s\\%s\\%d = "%s"' %
182 (self.config['win_reg_key_name'], policy['name'], cnt, item))
183 cnt = cnt + 1
184 self.AddText(win, '\n'.join(win_text))
185
186 def _AddListExampleLinux(self, parent, policy):
187 '''Adds an example value for Linux of a 'list' policy to a DOM node.
188
189 Args:
190 parent: The DOM node for which the example will be added.
191 policy: A policy of type 'list', for which the Linux example value
192 is generated.
193 '''
194 example_value = policy['example_value']
195 self.AddElement(parent, 'dt', {}, 'Linux:')
196 linux = self._AddStyledElement(parent, 'dd', ['.monospace'])
197 linux_text = []
198 for item in example_value:
199 linux_text.append('"%s"' % item)
200 self.AddText(linux, '[%s]' % ', '.join(linux_text))
201
202
203 def _AddListExample(self, parent, policy):
204 '''Adds the example value of a 'list' policy to a DOM node. Example output:
205 <dl>
206 <dt>Windows:</dt>
207 <dd>
208 Software\Policies\Chromium\DisabledPlugins\0 = "Java"
209 Software\Policies\Chromium\DisabledPlugins\1 = "Shockwave Flash"
210 </dd>
211 <dt>Linux:</dt>
212 <dd>["Java", "Shockwave Flash"]</dd>
213 <dt>Mac:</dt>
214 <dd>
215 <array>
216 <string>Java</string>
217 <string>Shockwave Flash</string>
218 </array>
219 </dd>
220 </dl>
221
222 Args:
223 parent: The DOM node for which the example will be added.
224 policy: The data structure of a policy.
225 '''
226 example_value = policy['example_value']
227 examples = self._AddStyledElement(parent, 'dl', ['dd dl'])
228 self._AddListExampleWindows(examples, policy)
229 self._AddListExampleLinux(examples, policy)
230 self._AddListExampleMac(examples, policy)
231
232 def _AddExample(self, parent, policy):
233 '''Adds the HTML DOM representation of the example value of a policy to
234 a DOM node. It is simple text for boolean policies, like
235 '0x00000001 (Windows), true (Linux), <true /> (Mac)' in case of boolean
236 policies, but it may also contain other HTML elements. (See method
237 _AddListExample.)
238
239 Args:
240 parent: The DOM node for which the example will be added.
241 policy: The data structure of a policy.
242
243 Raises:
244 Exception: If the type of the policy is unknown or the example value
245 of the policy is out of its expected range.
246 '''
247 example_value = policy['example_value']
248 policy_type = policy['type']
249 if policy_type == 'main':
250 if example_value == True:
251 self.AddText(
252 parent, '0x00000001 (Windows), true (Linux), <true /> (Mac)')
253 elif example_value == False:
254 self.AddText(
255 parent, '0x00000000 (Windows), false (Linux), <false /> (Mac)')
256 else:
257 raise Exception('Expected boolean value.')
258 elif policy_type == 'string':
259 self.AddText(parent, '"%s"' % example_value)
260 elif policy_type in ('int', 'int-enum'):
261 self.AddText(
262 parent,
263 '0x%08x (Windows), %d (Linux/Mac)' % (example_value, example_value))
264 elif policy_type == 'string-enum':
265 self.AddText(parent, '"%s"' % (example_value))
266 elif policy_type == 'list':
267 self._AddListExample(parent, policy)
268 else:
269 raise Exception('Unknown policy type: ' + policy_type)
270
271 def _AddPolicyAttribute(self, dl, term_id,
272 definition=None, definition_style=None):
273 '''Adds a term-definition pair to a HTML DOM <dl> node. This method is
274 used by _AddPolicyDetails. Its result will have the form of:
275 <dt style="...">...</dt>
276 <dd style="...">...</dd>
277
278 Args:
279 dl: The DOM node of the <dl> list.
280 term_id: A key to self._STRINGS[] which specifies the term of the pair.
281 definition: The text of the definition. (Optional.)
282 definition_style: List of references to values self._STYLE[] that specify
283 the CSS stylesheet of the <dd> (definition) element.
284
285 Returns:
286 The DOM node representing the definition <dd> element.
287 '''
288 # Avoid modifying the default value of definition_style.
289 if definition_style == None:
290 definition_style = []
291 term = self._GetLocalizedMessage(term_id)
292 self._AddStyledElement(dl, 'dt', ['dt'], {}, term)
293 return self._AddStyledElement(dl, 'dd', definition_style, {}, definition)
294
295 def _AddSupportedOnList(self, parent, supported_on_list):
296 '''Creates a HTML list containing the platforms, products and versions
297 that are specified in the list of supported_on.
298
299 Args:
300 parent: The DOM node for which the list will be added.
301 supported_on_list: The list of supported products, as a list of
302 dictionaries.
303 '''
304 ul = self._AddStyledElement(parent, 'ul', ['ul'])
305 for supported_on in supported_on_list:
306 text = []
307 product = supported_on['product']
308 platforms = supported_on['platforms']
309 text.append(self._PRODUCT_MAP[product])
310 text.append('(%s)' %
311 self._MapListToString(self._PLATFORM_MAP, platforms))
312 if supported_on['since_version']:
313 since_version = self._GetLocalizedMessage('since_version')
314 text.append(since_version.replace('$6', supported_on['since_version']))
315 if supported_on['until_version']:
316 until_version = self._GetLocalizedMessage('until_version')
317 text.append(until_version.replace('$6', supported_on['until_version']))
318 # Add the list element:
319 self.AddElement(ul, 'li', {}, ' '.join(text))
320
321 def _AddPolicyDetails(self, parent, policy):
322 '''Adds the list of attributes of a policy to the HTML DOM node parent.
323 It will have the form:
324 <dl>
325 <dt>Attribute:</dt><dd>Description</dd>
326 ...
327 </dl>
328
329 Args:
330 parent: A DOM element for which the list will be added.
331 policy: The data structure of the policy.
332 '''
333
334 dl = self.AddElement(parent, 'dl')
335 self._AddPolicyAttribute(
336 dl,
337 'data_type',
338 self._TYPE_MAP[policy['type']])
339 self._AddPolicyAttribute(
340 dl,
341 'win_reg_loc',
342 self.config['win_reg_key_name'] + '\\' + policy['name'],
343 ['.monospace'])
344 self._AddPolicyAttribute(
345 dl,
346 'mac_linux_pref_name',
347 policy['name'],
348 ['.monospace'])
349 dd = self._AddPolicyAttribute(dl, 'supported_on')
350 self._AddSupportedOnList(dd, policy['supported_on'])
351 dd = self._AddPolicyAttribute(dl, 'supported_features')
352 self._AddFeatures(dd, policy)
353 dd = self._AddPolicyAttribute(dl, 'description')
354 self._AddDescription(dd, policy)
355 dd = self._AddPolicyAttribute(dl, 'example_value')
356 self._AddExample(dd, policy)
357
358 def _AddPolicyNote(self, parent, policy):
359 '''If a policy has an additional web page assigned with it, then add
360 a link for that page.
361
362 Args:
363 policy: The data structure of the policy.
364 '''
365 if 'problem_href' not in policy:
366 return
367 problem_href = policy['problem_href']
368 div = self._AddStyledElement(parent, 'div', ['div.note'])
369 note = self._GetLocalizedMessage('note').replace('$6', problem_href)
370 self._AddTextWithLinks(div, note)
371
372 def _AddPolicyRow(self, parent, policy):
373 '''Adds a row for the policy in the summary table.
374
375 Args:
376 parent: The DOM node of the summary table.
377 policy: The data structure of the policy.
378 '''
379 tr = self._AddStyledElement(parent, 'tr', ['tr'])
380 indent = 'padding-left: %dpx;' % (7 + self._indent_level * 14)
381 if policy['type'] != 'group':
382 # Normal policies get two columns with name and caption.
383 name_td = self._AddStyledElement(tr, 'td', ['td', 'td.left'],
384 {'style': indent})
385 self.AddElement(name_td, 'a',
386 {'href': '#' + policy['name']}, policy['name'])
387 self._AddStyledElement(tr, 'td', ['td', 'td.right'], {},
388 policy['caption'])
389 else:
390 # Groups get one column with caption.
391 name_td = self._AddStyledElement(tr, 'td', ['td', 'td.left'],
392 {'style': indent, 'colspan': '2'})
393 self.AddElement(name_td, 'a', {'href': '#' + policy['name']},
394 policy['caption'])
395
396 def _AddPolicySection(self, parent, policy):
397 '''Adds a section about the policy in the detailed policy listing.
398
399 Args:
400 parent: The DOM node of the <div> of the detailed policy list.
401 policy: The data structure of the policy.
402 '''
403 # Set style according to group nesting level.
404 indent = 'margin-left: %dpx' % (self._indent_level * 28)
405 if policy['type'] == 'group':
406 heading = 'h2'
407 else:
408 heading = 'h3'
409 parent2 = self.AddElement(parent, 'div', {'style': indent})
410
411 h2 = self.AddElement(parent2, heading)
412 self.AddElement(h2, 'a', {'name': policy['name']})
413 if policy['type'] != 'group':
414 # Normal policies get a full description.
415 policy_name_text = policy['name']
416 if 'deprecated' in policy and policy['deprecated'] == True:
417 policy_name_text += " ("
418 policy_name_text += self._GetLocalizedMessage('deprecated') + ")"
419 self.AddText(h2, policy_name_text)
420 self.AddElement(parent2, 'span', {}, policy['caption'])
421 self._AddPolicyNote(parent2, policy)
422 self._AddPolicyDetails(parent2, policy)
423 else:
424 # Groups get a more compact description.
425 self.AddText(h2, policy['caption'])
426 self._AddStyledElement(parent2, 'div', ['div.group_desc'],
427 {}, policy['desc'])
428 self.AddElement(
429 parent2, 'a', {'href': '#top'},
430 self._GetLocalizedMessage('back_to_top'))
431
432 #
433 # Implementation of abstract methods of TemplateWriter:
434 #
435
436 def IsDeprecatedPolicySupported(self, policy):
437 return True
438
439 def WritePolicy(self, policy):
440 self._AddPolicyRow(self._summary_tbody, policy)
441 self._AddPolicySection(self._details_div, policy)
442
443 def BeginPolicyGroup(self, group):
444 self.WritePolicy(group)
445 self._indent_level += 1
446
447 def EndPolicyGroup(self):
448 self._indent_level -= 1
449
450 def BeginTemplate(self):
451 # Add a <div> for the summary section.
452 summary_div = self.AddElement(self._main_div, 'div')
453 self.AddElement(summary_div, 'a', {'name': 'top'})
454 self.AddElement(summary_div, 'br')
455 self._AddTextWithLinks(
456 summary_div,
457 self._GetLocalizedMessage('intro'))
458 self.AddElement(summary_div, 'br')
459 self.AddElement(summary_div, 'br')
460 self.AddElement(summary_div, 'br')
461 # Add the summary table of policies.
462 summary_table = self._AddStyledElement(summary_div, 'table', ['table'])
463 # Add the first row.
464 thead = self.AddElement(summary_table, 'thead')
465 tr = self._AddStyledElement(thead, 'tr', ['tr'])
466 self._AddStyledElement(
467 tr, 'td', ['td', 'td.left', 'thead td'], {},
468 self._GetLocalizedMessage('name_column_title'))
469 self._AddStyledElement(
470 tr, 'td', ['td', 'td.right', 'thead td'], {},
471 self._GetLocalizedMessage('description_column_title'))
472 self._summary_tbody = self.AddElement(summary_table, 'tbody')
473
474 # Add a <div> for the detailed policy listing.
475 self._details_div = self.AddElement(self._main_div, 'div')
476
477 def Init(self):
478 dom_impl = minidom.getDOMImplementation('')
479 self._doc = dom_impl.createDocument(None, 'html', None)
480 body = self.AddElement(self._doc.documentElement, 'body')
481 self._main_div = self.AddElement(body, 'div')
482 self._indent_level = 0
483
484 # Human-readable names of supported platforms.
485 self._PLATFORM_MAP = {
486 'win': 'Windows',
487 'mac': 'Mac',
488 'linux': 'Linux',
489 'chrome_os': self.config['os_name'],
490 }
491 # Human-readable names of supported products.
492 self._PRODUCT_MAP = {
493 'chrome': self.config['app_name'],
494 'chrome_frame': self.config['frame_name'],
495 'chrome_os': self.config['os_name'],
496 }
497 # Human-readable names of supported features.
498 self._FEATURE_MAP = {
499 'dynamic_refresh': self._GetLocalizedMessage('feature_dynamic_refresh')
500 }
501 # Human-readable names of types.
502 self._TYPE_MAP = {
503 'string': 'String (REG_SZ)',
504 'int': 'Integer (REG_DWORD)',
505 'main': 'Boolean (REG_DWORD)',
506 'int-enum': 'Integer (REG_DWORD)',
507 'string-enum': 'String (REG_SZ)',
508 'list': 'List of strings',
509 }
510 # The CSS style-sheet used for the document. It will be used in Google
511 # Sites, which strips class attributes from HTML tags. To work around this,
512 # the style-sheet is a dictionary and the style attributes will be added
513 # "by hand" for each element.
514 self._STYLE = {
515 'table': 'border-style: none; border-collapse: collapse;',
516 'tr': 'height: 0px;',
517 'td': 'border: 1px dotted rgb(170, 170, 170); padding: 7px; '
518 'vertical-align: top; width: 236px; height: 15px;',
519 'thead td': 'font-weight: bold;',
520 'td.left': 'width: 200px;',
521 'td.right': 'width: 100%;',
522 'dt': 'font-weight: bold;',
523 'dd dl': 'margin-top: 0px; margin-bottom: 0px;',
524 '.monospace': 'font-family: monospace;',
525 '.pre': 'white-space: pre;',
526 'div.note': 'border: 2px solid black; padding: 5px; margin: 5px;',
527 'div.group_desc': 'margin-top: 20px; margin-bottom: 20px;',
528 'ul': 'padding-left: 0px; margin-left: 0px;'
529 }
530
531 # A simple regexp to search for URLs. It is enough for now.
532 self._url_matcher = re.compile('(http://[^\\s]*[^\\s\\.])')
533
534 def GetTemplateText(self):
535 # Return the text representation of the main <div> tag.
536 return self._main_div.toxml()
537 # To get a complete HTML file, use the following.
538 # return self._doc.toxml()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698