1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 import logging
17 import traceback
18
19 from collections import deque
20
21 try:
22 from cStringIO import StringIO
23 except ImportError, e:
24 from StringIO import StringIO
25
26 from muntjac.ui.ordered_layout import OrderedLayout
27 from muntjac.terminal.sizeable import ISizeable
28 from muntjac.ui.custom_component import CustomComponent
29 from muntjac.ui.panel import Panel
30 from muntjac.ui.component_container import IComponentContainer
31 from muntjac.ui.form import Form
32 from muntjac.ui.window import Window
33 from muntjac.ui.abstract_ordered_layout import AbstractOrderedLayout
34 from muntjac.ui.vertical_layout import VerticalLayout
35 from muntjac.ui.grid_layout import GridLayout
36 from muntjac.ui.split_panel import SplitPanel
37 from muntjac.ui.tab_sheet import TabSheet
38
39
40 logger = logging.getLogger(__name__)
44
45 _LAYERS_SHOWN = 4
46
47 _creationLocations = dict()
48 _widthLocations = dict()
49 _heightLocations = dict()
50
51 @classmethod
53 """Recursively checks given component and its subtree for invalid
54 layout setups. Prints errors to std err stream.
55
56 @param component:
57 component to check
58 @return: set of first level errors found
59 """
60
61 invalidHeight = not cls.checkHeights(component)
62 invalidWidth = not cls.checkWidths(component)
63
64 if invalidHeight or invalidWidth:
65 error = InvalidLayout(component, invalidHeight, invalidWidth)
66 if parent is not None:
67 parent.addError(error)
68 else:
69 if errors is None:
70 errors = list()
71 errors.append(error)
72 parent = error
73
74 if isinstance(component, Panel):
75 panel = component
76 errors = cls.validateComponentRelativeSizes(panel.getContent(),
77 errors, parent)
78
79 elif isinstance(component, IComponentContainer):
80 lo = component
81 for c in lo.getComponentIterator():
82 errors = cls.validateComponentRelativeSizes(c, errors, parent)
83
84 elif isinstance(component, Form):
85 form = component
86 if form.getLayout() is not None:
87 errors = cls.validateComponentRelativeSizes(form.getLayout(),
88 errors, parent)
89 if form.getFooter() is not None:
90 errors = cls.validateComponentRelativeSizes(form.getFooter(),
91 errors, parent)
92
93 return errors
94
95
96 @classmethod
98 err = StringIO()
99 err.write('Muntjac DEBUG\n')
100
101 indent = str()
102 if attributes is not None:
103 while len(attributes) > cls._LAYERS_SHOWN:
104 attributes.pop()
105 while len(attributes) > 0:
106 ci = attributes.pop()
107 cls.showComponent(ci.component, ci.info, err, indent,
108 widthError)
109
110 err.write('Layout problem detected: ')
111 err.write(msg)
112 err.write('\n')
113 err.write('Relative sizes were replaced by undefined sizes, '
114 'components may not render as expected.\n')
115 errorStream.write(err.getvalue())
116 err.close()
117
118
119 @classmethod
135
136
137 @classmethod
153
154
155 @classmethod
170
171
172 @classmethod
187
188
189 @classmethod
203
204
205 @classmethod
219
220
221 @classmethod
222 - def showComponent(cls, component, attribute, err, indent, widthError):
260
261
262 @classmethod
268
269
270 @classmethod
272 parent = component.getParent()
273 if parent is None:
274
275 return True
276
277 if parent.getHeight() < 0:
278
279 if isinstance(parent, Window):
280 w = parent
281 if w.getParent() is None:
282
283 return True
284
285 if isinstance(parent, AbstractOrderedLayout):
286 horizontal = True
287 if isinstance(parent, OrderedLayout):
288 horizontal = (parent.getOrientation() ==
289 OrderedLayout.ORIENTATION_HORIZONTAL)
290 elif isinstance(parent, VerticalLayout):
291 horizontal = False
292
293 if horizontal and cls.hasNonRelativeHeightComponent(parent):
294 return True
295 else:
296 return False
297
298 elif isinstance(parent, GridLayout):
299 gl = parent
300 componentArea = gl.getComponentArea(component)
301 rowHasHeight = False
302
303 row = componentArea.getRow1()
304 while not rowHasHeight and row <= componentArea.getRow2():
305 row += 1
306 column = 0
307 while not rowHasHeight and column < gl.getColumns():
308 column += 1
309 c = gl.getComponent(column, row)
310 if c is not None:
311 rowHasHeight = not cls.hasRelativeHeight(c)
312
313 if not rowHasHeight:
314 return False
315 else:
316
317 return True
318
319 if isinstance(parent, Panel) \
320 or isinstance(parent, SplitPanel) \
321 or isinstance(parent, TabSheet) \
322 or isinstance(parent, CustomComponent):
323
324
325
326 return False
327 else:
328
329
330
331 return True
332
333 elif cls.hasRelativeHeight(parent):
334
335 if parent.getParent() is not None:
336 return cls.parentCanDefineHeight(parent)
337 else:
338 return True
339 else:
340
341 return True
342
343
344 @classmethod
348
349
350 @classmethod
370
371
372 @classmethod
376
377
378 @classmethod
380 parent = component.getParent()
381 if parent is None:
382
383 return True
384
385 if isinstance(parent, Window):
386 w = parent
387 if w.getParent() is None:
388
389 return True
390
391 if parent.getWidth() < 0:
392
393
394 if isinstance(parent, AbstractOrderedLayout):
395 ol = parent
396 horizontal = True
397 if isinstance(ol, OrderedLayout):
398 if (ol.getOrientation()
399 == OrderedLayout.ORIENTATION_VERTICAL):
400 horizontal = False
401 elif isinstance(ol, VerticalLayout):
402 horizontal = False
403 if (not horizontal) and cls.hasNonRelativeWidthComponent(ol):
404
405 return True
406 else:
407 return False
408 elif isinstance(parent, GridLayout):
409 gl = parent
410 componentArea = gl.getComponentArea(component)
411 columnHasWidth = False
412 col = componentArea.getColumn1()
413 while ((not columnHasWidth)
414 and col <= componentArea.getColumn2()):
415 col += 1
416 row = 0
417 while (not columnHasWidth) and row < gl.getRows():
418 row += 1
419 c = gl.getComponent(col, row)
420 if c is not None:
421 columnHasWidth = not cls.hasRelativeWidth(c)
422
423 if not columnHasWidth:
424 return False
425 else:
426
427 return True
428 elif isinstance(parent, Form):
429
430
431 return cls.hasNonRelativeWidthComponent(parent)
432 elif (isinstance(parent, SplitPanel)
433 or isinstance(parent, TabSheet)
434 or isinstance(parent, CustomComponent)):
435
436
437
438
439
440
441 return False
442 elif isinstance(parent, Window):
443
444 if (parent.getCaption() is not None
445 and not (parent.getCaption() == '')):
446 return True
447 else:
448 return False
449 elif isinstance(parent, Panel):
450
451 return False
452 else:
453 return True
454
455 elif cls.hasRelativeWidth(parent):
456
457 if parent.getParent() is None:
458 return True
459 return cls.parentCanDefineWidth(parent)
460 else:
461 return True
462
463
464 @classmethod
467
468
469 @classmethod
472
473
474 @classmethod
477
478
479 @classmethod
481 traceLines = traceback.extract_stack()
482 for traceElement in traceLines:
483 try:
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498 cl = FileLocation(traceElement)
499 map[object] = cl
500 return
501 except Exception:
502
503 logger.info('An exception occurred while validating sizes.')
504
507
509
510 self.file = traceElement[0]
511 self.className = traceElement[2]
512 self.classNameSimple = traceElement[2]
513 self.lineNumber = traceElement[1]
514 self.method = traceElement[2]
515
518
519 - def __init__(self, component, height, width):
520 self._component = component
521 self._invalidHeight = height
522 self._invalidWidth = width
523 self._subErrors = list()
524
525
527 self._subErrors.append(error)
528
529
530 - def reportErrors(self, clientJSON, communicationManager,
531 serverErrorStream):
532 clientJSON.write('{')
533
534 parent = self._component.getParent()
535 paintableId = communicationManager.getPaintableId(self._component)
536
537 clientJSON.write('id:\"' + paintableId + '\"')
538
539 if self._invalidHeight:
540 attributes = None
541 msg = ''
542
543 if isinstance(parent, AbstractOrderedLayout):
544 ol = parent
545 vertical = False
546
547 if isinstance(ol, OrderedLayout):
548 if (ol.getOrientation()
549 == OrderedLayout.ORIENTATION_VERTICAL):
550 vertical = True
551 elif isinstance(ol, VerticalLayout):
552 vertical = True
553
554 if vertical:
555 msg = ('Component with relative height inside a '
556 'VerticalLayout with no height defined.')
557 attributes = ComponentSizeValidator.getHeightAttributes(
558 self._component)
559 else:
560 msg = ('At least one of a HorizontalLayout\'s components '
561 'must have non relative height if the height of '
562 'the layout is not defined')
563 attributes = ComponentSizeValidator.getHeightAttributes(
564 self._component)
565 elif isinstance(parent, GridLayout):
566 msg = ('At least one of the GridLayout\'s components in '
567 'each row should have non relative height if the '
568 'height of the layout is not defined.')
569 attributes = ComponentSizeValidator.getHeightAttributes(
570 self._component)
571 else:
572
573 msg = ('A component with relative height needs a parent '
574 'with defined height.')
575 attributes = ComponentSizeValidator.getHeightAttributes(
576 self._component)
577
578 self.printServerError(msg, attributes, False, serverErrorStream)
579 clientJSON.write(',\"heightMsg\":\"' + msg + '\"')
580
581 if self._invalidWidth:
582 attributes = None
583 msg = ''
584 if isinstance(parent, AbstractOrderedLayout):
585 ol = parent
586 horizontal = True
587
588 if isinstance(ol, OrderedLayout):
589 if (ol.getOrientation()
590 == OrderedLayout.ORIENTATION_VERTICAL):
591 horizontal = False
592 elif isinstance(ol, VerticalLayout):
593 horizontal = False
594
595 if horizontal:
596 msg = ('Component with relative width inside a '
597 'HorizontalLayout with no width defined')
598 attributes = ComponentSizeValidator.getWidthAttributes(
599 self._component)
600 else:
601 msg = ('At least one of a VerticalLayout\'s components '
602 'must have non relative width if the width of '
603 'the layout is not defined')
604 attributes = ComponentSizeValidator.getWidthAttributes(
605 self._component)
606
607 elif isinstance(parent, GridLayout):
608 msg = ('At least one of the GridLayout\'s components in each '
609 'column should have non relative width if the width '
610 'of the layout is not defined.')
611 attributes = ComponentSizeValidator.getWidthAttributes(
612 self._component)
613
614 else:
615
616 msg = ('A component with relative width needs a parent '
617 'with defined width.')
618 attributes = self.getWidthAttributes(self._component)
619
620 clientJSON.write(',\"widthMsg\":\"' + msg + '\"')
621 self.printServerError(msg, attributes, True, serverErrorStream)
622
623 if len(self._subErrors) > 0:
624 serverErrorStream.write('Sub errors >>')
625 clientJSON.write(', \"subErrors\" : [')
626 first = True
627 for subError in self._subErrors:
628 if not first:
629 clientJSON.write(',')
630 else:
631 first = False
632 subError.reportErrors(clientJSON, communicationManager,
633 serverErrorStream)
634 clientJSON.write(']')
635 serverErrorStream.write('<< Sub erros\n')
636
637 clientJSON.write('}')
638
641
643 self._component = component
644 self._info = info
645