261 formater.format(layout, stream) |
260 formater.format(layout, stream) |
262 res = stream.getvalue() |
261 res = stream.getvalue() |
263 if isinstance(res, str): |
262 if isinstance(res, str): |
264 res = unicode(res, 'UTF8') |
263 res = unicode(res, 'UTF8') |
265 return res |
264 return res |
266 |
|
267 def render_HTML_tree(tree, selected_node=None, render_node=None, caption=None): |
|
268 """ |
|
269 Generate a pure HTML representation of a tree given as an instance |
|
270 of a logilab.common.tree.Node |
|
271 |
|
272 selected_node is the currently selected node (if any) which will |
|
273 have its surrounding <div> have id="selected" (which default |
|
274 to a bold border libe with the default CSS). |
|
275 |
|
276 render_node is a function that should take a Node content (Node.id) |
|
277 as parameter and should return a string (what will be displayed |
|
278 in the cell). |
|
279 |
|
280 Warning: proper rendering of the generated html code depends on html_tree.css |
|
281 """ |
|
282 tree_depth = tree.depth_down() |
|
283 if render_node is None: |
|
284 render_node = str |
|
285 |
|
286 # helper function that build a matrix from the tree, like: |
|
287 # +------+-----------+-----------+ |
|
288 # | root | child_1_1 | child_2_1 | |
|
289 # | root | child_1_1 | child_2_2 | |
|
290 # | root | child_1_2 | | |
|
291 # | root | child_1_3 | child_2_3 | |
|
292 # | root | child_1_3 | child_2_4 | |
|
293 # +------+-----------+-----------+ |
|
294 # from: |
|
295 # root -+- child_1_1 -+- child_2_1 |
|
296 # | | |
|
297 # | +- child_2_2 |
|
298 # +- child_1_2 |
|
299 # | |
|
300 # +- child1_3 -+- child_2_3 |
|
301 # | |
|
302 # +- child_2_2 |
|
303 def build_matrix(path, matrix): |
|
304 if path[-1].is_leaf(): |
|
305 matrix.append(path[:]) |
|
306 else: |
|
307 for child in path[-1].children: |
|
308 build_matrix(path[:] + [child], matrix) |
|
309 |
|
310 matrix = [] |
|
311 build_matrix([tree], matrix) |
|
312 |
|
313 # make all lines in the matrix have the same number of columns |
|
314 for line in matrix: |
|
315 line.extend([None]*(tree_depth-len(line))) |
|
316 for i in range(len(matrix)-1, 0, -1): |
|
317 prev_line, line = matrix[i-1:i+1] |
|
318 for j in range(len(line)): |
|
319 if line[j] == prev_line[j]: |
|
320 line[j] = None |
|
321 |
|
322 # We build the matrix of link types (between 2 cells on a line of the matrix) |
|
323 # link types are : |
|
324 link_types = {(True, True, True ): 1, # T |
|
325 (False, False, True ): 2, # | |
|
326 (False, True, True ): 3, # + (actually, vert. bar with horiz. bar on the right) |
|
327 (False, True, False): 4, # L |
|
328 (True, True, False): 5, # - |
|
329 } |
|
330 links = [] |
|
331 for i, line in enumerate(matrix): |
|
332 links.append([]) |
|
333 for j in range(tree_depth-1): |
|
334 cell_11 = line[j] is not None |
|
335 cell_12 = line[j+1] is not None |
|
336 cell_21 = line[j+1] is not None and line[j+1].next_sibling() is not None |
|
337 link_type = link_types.get((cell_11, cell_12, cell_21), 0) |
|
338 if link_type == 0 and i > 0 and links[i-1][j] in (1, 2, 3): |
|
339 link_type = 2 |
|
340 links[-1].append(link_type) |
|
341 |
|
342 |
|
343 # We can now generate the HTML code for the <table> |
|
344 s = u'<table class="tree">\n' |
|
345 if caption: |
|
346 s += '<caption>%s</caption>\n' % caption |
|
347 |
|
348 for i, link_line in enumerate(links): |
|
349 line = matrix[i] |
|
350 |
|
351 s += '<tr>' |
|
352 for j, link_cell in enumerate(link_line): |
|
353 cell = line[j] |
|
354 if cell: |
|
355 if cell.id == selected_node: |
|
356 s += '<td class="tree_cell" rowspan="2"><div id="selected" class="tree_cell">%s</div></td>' % (render_node(cell.id)) |
|
357 else: |
|
358 s += '<td class="tree_cell" rowspan="2"><div class="tree_cell">%s</div></td>' % (render_node(cell.id)) |
|
359 else: |
|
360 s += '<td rowspan="2"> </td>' |
|
361 s += '<td class="tree_cell_%d_1"> </td>' % link_cell |
|
362 s += '<td class="tree_cell_%d_2"> </td>' % link_cell |
|
363 |
|
364 cell = line[-1] |
|
365 if cell: |
|
366 if cell.id == selected_node: |
|
367 s += '<td class="tree_cell" rowspan="2"><div id="selected" class="tree_cell">%s</div></td>' % (render_node(cell.id)) |
|
368 else: |
|
369 s += '<td class="tree_cell" rowspan="2"><div class="tree_cell">%s</div></td>' % (render_node(cell.id)) |
|
370 else: |
|
371 s += '<td rowspan="2"> </td>' |
|
372 |
|
373 s += '</tr>\n' |
|
374 if link_line: |
|
375 s += '<tr>' |
|
376 for j, link_cell in enumerate(link_line): |
|
377 s += '<td class="tree_cell_%d_3"> </td>' % link_cell |
|
378 s += '<td class="tree_cell_%d_4"> </td>' % link_cell |
|
379 s += '</tr>\n' |
|
380 |
|
381 s += '</table>' |
|
382 return s |
|
383 |
|
384 |
265 |
385 |
266 |
386 # traceback formatting ######################################################## |
267 # traceback formatting ######################################################## |
387 |
268 |
388 import traceback |
269 import traceback |