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