Module BaseDoc
[frames] | no frames]

Source Code for Module BaseDoc

   1  # 
   2  # Gramps - a GTK+/GNOME based genealogy program 
   3  # 
   4  # Copyright (C) 2000-2007  Donald N. Allingham 
   5  # Copyright (C) 2002       Gary Shao 
   6  # Copyright (C) 2007       Brian G. Matherly 
   7  # 
   8  # This program is free software; you can redistribute it and/or modify 
   9  # it under the terms of the GNU General Public License as published by 
  10  # the Free Software Foundation; either version 2 of the License, or 
  11  # (at your option) any later version. 
  12  # 
  13  # This program is distributed in the hope that it will be useful, 
  14  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
  15  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  16  # GNU General Public License for more details. 
  17  # 
  18  # You should have received a copy of the GNU General Public License 
  19  # along with this program; if not, write to the Free Software 
  20  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  21  # 
  22   
  23  # $Id: BaseDoc.py 10103 2008-02-24 13:55:55Z acraphae $ 
  24   
  25  """ 
  26  Provide base interface to text based documents. Specific document 
  27  interfaces should be derived from the core classes. 
  28  """ 
  29   
  30  #------------------------------------------------------------------------- 
  31  # 
  32  # standard python modules 
  33  # 
  34  #------------------------------------------------------------------------- 
  35  import os 
  36  from xml.sax.saxutils import escape 
  37   
38 -def escxml(string):
39 """ 40 Escapes XML special characters. 41 """ 42 return escape(string, { '"' : '"' } )
43 44 #------------------------------------------------------------------------- 45 # 46 # GRAMPS modules 47 # 48 #------------------------------------------------------------------------- 49 import Utils 50 import FontScale 51 import const 52 53 #------------------------------------------------------------------------- 54 # 55 # set up logging 56 # 57 #------------------------------------------------------------------------- 58 import logging 59 log = logging.getLogger(".BaseDoc") 60 61 #------------------------------------------------------------------------- 62 # 63 # SAX interface 64 # 65 #------------------------------------------------------------------------- 66 try: 67 from xml.sax import make_parser, handler, SAXParseException 68 except ImportError: 69 from _xmlplus.sax import make_parser, handler, SAXParseException 70 71 #------------------------------------------------------------------------- 72 # 73 # constants 74 # 75 #------------------------------------------------------------------------- 76 FONT_SANS_SERIF = 0 77 FONT_SERIF = 1 78 FONT_MONOSPACE = 2 79 80 #------------------------------------------------------------------------- 81 # 82 # Page orientation 83 # 84 #------------------------------------------------------------------------- 85 PAPER_PORTRAIT = 0 86 PAPER_LANDSCAPE = 1 87 88 #------------------------------------------------------------------------- 89 # 90 # Paragraph alignment 91 # 92 #------------------------------------------------------------------------- 93 PARA_ALIGN_CENTER = 0 94 PARA_ALIGN_LEFT = 1 95 PARA_ALIGN_RIGHT = 2 96 PARA_ALIGN_JUSTIFY = 3 97 98 #------------------------------------------------------------------------- 99 # 100 # Text vs. Graphics mode 101 # 102 #------------------------------------------------------------------------- 103 TEXT_MODE = 0 104 GRAPHICS_MODE = 1 105 106 #------------------------------------------------------------------------- 107 # 108 # Line style 109 # 110 #------------------------------------------------------------------------- 111 SOLID = 0 112 DASHED = 1 113 114 #------------------------------------------------------------------------- 115 # 116 # IndexMark types 117 # 118 #------------------------------------------------------------------------- 119 INDEX_TYPE_ALP = 0 120 INDEX_TYPE_TOC = 1 121 122 #------------------------------------------------------------------------ 123 # 124 # cnv2color 125 # 126 #------------------------------------------------------------------------
127 -def cnv2color(text):
128 """ 129 converts a hex value in the form of #XXXXXX into a tuple of integers 130 representing the RGB values 131 """ 132 return (int(text[1:3], 16), int(text[3:5], 16), int(text[5:7], 16))
133 134 #------------------------------------------------------------------------ 135 # 136 # PaperSize 137 # 138 #------------------------------------------------------------------------
139 -class PaperSize:
140 """ 141 Defines the dimensions of a sheet of paper. All dimensions are in 142 centimeters. 143 """
144 - def __init__(self, name, height, width):
145 """ 146 Create a new paper style with. 147 148 @param name: name of the new style 149 @param height: page height in centimeters 150 @param width: page width in centimeters 151 """ 152 self.name = name 153 self.height = height 154 self.width = width
155
156 - def get_name(self):
157 "Return the name of the paper style" 158 return self.name
159
160 - def get_height(self):
161 "Return the page height in cm" 162 return self.height
163
164 - def set_height(self, height):
165 "Set the page height in cm" 166 self.height = height
167
168 - def get_width(self):
169 "Return the page width in cm" 170 return self.width
171
172 - def set_width(self, width):
173 "Set the page width in cm" 174 self.width = width
175
176 - def get_height_inches(self):
177 "Return the page height in inches" 178 return self.height / 2.54
179
180 - def get_width_inches(self):
181 "Return the page width in inches" 182 return self.width / 2.54
183 184 #------------------------------------------------------------------------ 185 # 186 # PaperStyle 187 # 188 #------------------------------------------------------------------------
189 -class PaperStyle:
190 """ 191 Define the various options for a sheet of paper. 192 """
193 - def __init__(self, size, orientation, 194 lmargin=2.54, rmargin=2.54, tmargin=2.54, bmargin=2.54):
195 """ 196 Create a new paper style. 197 198 @param size: size of the new style 199 @type size: PaperSize 200 @param orientation: page orientation 201 @type orientation: PAPER_PORTRAIT or PAPER_LANDSCAPE 202 203 """ 204 self.__orientation = orientation 205 206 if orientation == PAPER_PORTRAIT: 207 self.__size = PaperSize(size.get_name(), 208 size.get_height(), 209 size.get_width()) 210 else: 211 self.__size = PaperSize(size.get_name(), 212 size.get_width(), 213 size.get_height()) 214 self.__lmargin = lmargin 215 self.__rmargin = rmargin 216 self.__tmargin = tmargin 217 self.__bmargin = bmargin
218
219 - def get_size(self):
220 """ 221 Return the size of the paper. 222 223 @returns: object indicating the paper size 224 @rtype: PaperSize 225 226 """ 227 return self.__size
228
229 - def get_orientation(self):
230 """ 231 Return the orientation of the page. 232 233 @returns: PAPER_PORTRIAT or PAPER_LANDSCAPE 234 @rtype: int 235 236 """ 237 return self.__orientation
238
239 - def get_usable_width(self):
240 """ 241 Return the width of the page area in centimeters. 242 243 The value is the page width less the margins. 244 245 """ 246 return self.__size.get_width() - (self.__rmargin + self.__lmargin)
247
248 - def get_usable_height(self):
249 """ 250 Return the height of the page area in centimeters. 251 252 The value is the page height less the margins. 253 254 """ 255 return self.__size.get_height() - (self.__tmargin + self.__bmargin)
256
257 - def get_right_margin(self):
258 """ 259 Return the right margin. 260 261 @returns: Right margin in centimeters 262 @rtype: float 263 264 """ 265 return self.__rmargin
266
267 - def get_left_margin(self):
268 """ 269 Return the left margin. 270 271 @returns: Left margin in centimeters 272 @rtype: float 273 274 """ 275 return self.__lmargin
276
277 - def get_top_margin(self):
278 """ 279 Return the top margin. 280 281 @returns: Top margin in centimeters 282 @rtype: float 283 284 """ 285 return self.__tmargin
286
287 - def get_bottom_margin(self):
288 """ 289 Return the bottom margin. 290 291 @returns: Bottom margin in centimeters 292 @rtype: float 293 294 """ 295 return self.__bmargin
296 297 #------------------------------------------------------------------------ 298 # 299 # FontStyle 300 # 301 #------------------------------------------------------------------------
302 -class FontStyle:
303 """ 304 Defines a font style. Controls the font face, size, color, and 305 attributes. In order to remain generic, the only font faces available 306 are FONT_SERIF and FONT_SANS_SERIF. Document formatters should convert 307 these to the appropriate fonts for the target format. 308 309 The FontStyle represents the desired characteristics. There are no 310 guarentees that the document format generator will be able implement 311 all or any of the characteristics. 312 """ 313
314 - def __init__(self, style=None):
315 """ 316 Create a new FontStyle object, accepting the default values. 317 318 @param style: if specified, initializes the FontStyle from the passed 319 FontStyle instead of using the defaults. 320 """ 321 if style: 322 self.face = style.face 323 self.size = style.size 324 self.italic = style.italic 325 self.bold = style.bold 326 self.color = style.color 327 self.under = style.under 328 else: 329 self.face = FONT_SERIF 330 self.size = 12 331 self.italic = 0 332 self.bold = 0 333 self.color = (0, 0, 0) 334 self.under = 0
335
336 - def set(self, face=None, size=None, italic=None, bold=None, 337 underline=None, color=None):
338 """ 339 Set font characteristics. 340 341 @param face: font type face, either FONT_SERIF or FONT_SANS_SERIF 342 @param size: type face size in points 343 @param italic: True enables italics, False disables italics 344 @param bold: True enables bold face, False disables bold face 345 @param underline: True enables underline, False disables underline 346 @param color: an RGB color representation in the form of three integers 347 in the range of 0-255 represeting the red, green, and blue 348 components of a color. 349 """ 350 if face != None: 351 self.set_type_face(face) 352 if size != None: 353 self.set_size(size) 354 if italic != None: 355 self.set_italic(italic) 356 if bold != None: 357 self.set_bold(bold) 358 if underline != None: 359 self.set_underline(underline) 360 if color != None: 361 self.set_color(color)
362
363 - def set_italic(self, val):
364 "0 disables italics, 1 enables italics" 365 self.italic = val
366
367 - def get_italic(self):
368 "1 indicates use italics" 369 return self.italic
370
371 - def set_bold(self, val):
372 "0 disables bold face, 1 enables bold face" 373 self.bold = val
374
375 - def get_bold(self):
376 "1 indicates use bold face" 377 return self.bold
378
379 - def set_color(self, val):
380 "sets the color using an RGB color tuple" 381 self.color = val
382
383 - def get_color(self):
384 "Return an RGB color tuple" 385 return self.color
386
387 - def set_size(self, val):
388 "sets font size in points" 389 self.size = val
390
391 - def get_size(self):
392 "returns font size in points" 393 return self.size
394
395 - def set_type_face(self, val):
396 "sets the font face type" 397 self.face = val
398
399 - def get_type_face(self):
400 "returns the font face type" 401 return self.face
402
403 - def set_underline(self, val):
404 "1 enables underlining" 405 self.under = val
406
407 - def get_underline(self):
408 "1 indicates underlining" 409 return self.under
410 411 #------------------------------------------------------------------------ 412 # 413 # TableStyle 414 # 415 #------------------------------------------------------------------------
416 -class TableStyle:
417 """ 418 Specifies the style or format of a table. The TableStyle contains the 419 characteristics of table width (in percentage of the full width), the 420 number of columns, and the width of each column as a percentage of the 421 width of the table. 422 """
423 - def __init__(self, obj=None):
424 """ 425 Create a new TableStyle object, with the values initialized to 426 empty, with allocating space for up to 100 columns. 427 428 @param obj: if not None, then the object created gets is attributes 429 from the passed object instead of being initialized to empty. 430 """ 431 if obj: 432 self.width = obj.width 433 self.columns = obj.columns 434 self.colwid = obj.colwid[:] 435 else: 436 self.width = 0 437 self.columns = 0 438 self.colwid = [ 0 ] * 100
439
440 - def set_width(self, width):
441 """ 442 Set the width of the table in terms of percent of the available 443 width 444 """ 445 self.width = width
446
447 - def get_width(self):
448 """ 449 Return the specified width as a percentage of the available space 450 """ 451 return self.width
452
453 - def set_columns(self, columns):
454 """ 455 Set the number of columns. 456 457 @param columns: number of columns that should be used. 458 """ 459 self.columns = columns
460
461 - def get_columns(self):
462 """ 463 Return the number of columns 464 """ 465 return self.columns
466
467 - def set_column_widths(self, clist):
468 """ 469 Set the width of all the columns at once, taking the percentages 470 from the passed list. 471 """ 472 self.columns = len(clist) 473 for i in range(self.columns): 474 self.colwid[i] = clist[i]
475
476 - def set_column_width(self, index, width):
477 """ 478 Set the width of a specified column to the specified width. 479 480 @param index: column being set (index starts at 0) 481 @param width: percentage of the table width assigned to the column 482 """ 483 self.colwid[index] = width
484
485 - def get_column_width(self, index):
486 """ 487 Return the column width of the specified column as a percentage of 488 the entire table width. 489 490 @param index: column to return (index starts at 0) 491 """ 492 return self.colwid[index]
493 494 #------------------------------------------------------------------------ 495 # 496 # TableCellStyle 497 # 498 #------------------------------------------------------------------------
499 -class TableCellStyle:
500 """ 501 Defines the style of a particular table cell. Characteristics are: 502 right border, left border, top border, bottom border, and padding. 503 """
504 - def __init__(self, obj=None):
505 """ 506 Create a new TableCellStyle instance. 507 508 @param obj: if not None, specifies that the values should be 509 copied from the passed object instead of being initialized to empty. 510 """ 511 if obj: 512 self.rborder = obj.rborder 513 self.lborder = obj.lborder 514 self.tborder = obj.tborder 515 self.bborder = obj.bborder 516 self.padding = obj.padding 517 self.longlist = obj.longlist 518 else: 519 self.rborder = 0 520 self.lborder = 0 521 self.tborder = 0 522 self.bborder = 0 523 self.padding = 0 524 self.longlist = 0
525
526 - def set_padding(self, val):
527 "Return the cell padding in centimeters" 528 self.padding = val
529
530 - def set_right_border(self, val):
531 """ 532 Defines if a right border in used 533 534 @param val: if True, a right border is used, if False, it is not 535 """ 536 self.rborder = val
537
538 - def set_left_border(self, val):
539 """ 540 Defines if a left border in used 541 542 @param val: if True, a left border is used, if False, it is not 543 """ 544 self.lborder = val
545
546 - def set_top_border(self, val):
547 """ 548 Defines if a top border in used 549 550 @param val: if True, a top border is used, if False, it is not 551 """ 552 self.tborder = val
553
554 - def set_bottom_border(self, val):
555 """ 556 Defines if a bottom border in used 557 558 @param val: if 1, a bottom border is used, if 0, it is not 559 """ 560 self.bborder = val
561
562 - def set_longlist(self, val):
563 self.longlist = val
564
565 - def get_padding(self):
566 "Return the cell padding in centimeters" 567 return self.padding
568
569 - def get_right_border(self):
570 "Return 1 if a right border is requested" 571 return self.rborder
572
573 - def get_left_border(self):
574 "Return 1 if a left border is requested" 575 return self.lborder
576
577 - def get_top_border(self):
578 "Return 1 if a top border is requested" 579 return self.tborder
580
581 - def get_bottom_border(self):
582 "Return 1 if a bottom border is requested" 583 return self.bborder
584
585 - def get_longlist(self):
586 return self.longlist
587 588 #------------------------------------------------------------------------ 589 # 590 # ParagraphStyle 591 # 592 #------------------------------------------------------------------------
593 -class ParagraphStyle:
594 """ 595 Defines the characteristics of a paragraph. The characteristics are: 596 font (a FontStyle instance), right margin, left margin, first indent, 597 top margin, bottom margin, alignment, level, top border, bottom border, 598 right border, left border, padding, and background color. 599 600 """
601 - def __init__(self, source=None):
602 """ 603 @param source: if not None, then the ParagraphStyle is created 604 using the values of the source instead of the default values. 605 """ 606 if source: 607 self.font = FontStyle(source.font) 608 self.rmargin = source.rmargin 609 self.lmargin = source.lmargin 610 self.first_indent = source.first_indent 611 self.tmargin = source.tmargin 612 self.bmargin = source.bmargin 613 self.align = source.align 614 self.level = source.level 615 self.top_border = source.top_border 616 self.bottom_border = source.bottom_border 617 self.right_border = source.right_border 618 self.left_border = source.left_border 619 self.pad = source.pad 620 self.bgcolor = source.bgcolor 621 self.description = source.description 622 self.tabs = source.tabs 623 else: 624 self.font = FontStyle() 625 self.rmargin = 0 626 self.lmargin = 0 627 self.tmargin = 0 628 self.bmargin = 0 629 self.first_indent = 0 630 self.align = PARA_ALIGN_LEFT 631 self.level = 0 632 self.top_border = 0 633 self.bottom_border = 0 634 self.right_border = 0 635 self.left_border = 0 636 self.pad = 0 637 self.bgcolor = (255, 255, 255) 638 self.description = "" 639 self.tabs = []
640
641 - def set_description(self, text):
642 """ 643 Set the desciption of the paragraph 644 """ 645 self.description = text
646
647 - def get_description(self):
648 """ 649 Return the desciption of the paragraph 650 """ 651 return self.description
652
653 - def set(self, rmargin=None, lmargin=None, first_indent=None, 654 tmargin=None, bmargin=None, align=None, 655 tborder=None, bborder=None, rborder=None, lborder=None, 656 pad=None, bgcolor=None, font=None):
657 """ 658 Allows the values of the object to be set. 659 660 @param rmargin: right indent in centimeters 661 @param lmargin: left indent in centimeters 662 @param first_indent: first line indent in centimeters 663 @param tmargin: space above paragraph in centimeters 664 @param bmargin: space below paragraph in centimeters 665 @param align: alignment type (PARA_ALIGN_LEFT, PARA_ALIGN_RIGHT, PARA_ALIGN_CENTER, or PARA_ALIGN_JUSTIFY) 666 @param tborder: non zero indicates that a top border should be used 667 @param bborder: non zero indicates that a bottom border should be used 668 @param rborder: non zero indicates that a right border should be used 669 @param lborder: non zero indicates that a left border should be used 670 @param pad: padding in centimeters 671 @param bgcolor: background color of the paragraph as an RGB tuple. 672 @param font: FontStyle instance that defines the font 673 """ 674 if font != None: 675 self.font = FontStyle(font) 676 if pad != None: 677 self.set_padding(pad) 678 if tborder != None: 679 self.set_top_border(tborder) 680 if bborder != None: 681 self.set_bottom_border(bborder) 682 if rborder != None: 683 self.set_right_border(rborder) 684 if lborder != None: 685 self.set_left_border(lborder) 686 if bgcolor != None: 687 self.set_background_color(bgcolor) 688 if align != None: 689 self.set_alignment(align) 690 if rmargin != None: 691 self.set_right_margin(rmargin) 692 if lmargin != None: 693 self.set_left_margin(lmargin) 694 if first_indent != None: 695 self.set_first_indent(first_indent) 696 if tmargin != None: 697 self.set_top_margin(tmargin) 698 if bmargin != None: 699 self.set_bottom_margin(bmargin)
700
701 - def set_header_level(self, level):
702 """ 703 Set the header level for the paragraph. This is useful for 704 numbered paragraphs. A value of 1 indicates a header level 705 format of X, a value of two implies X.X, etc. A value of zero 706 means no header level. 707 """ 708 self.level = level
709
710 - def get_header_level(self):
711 "Return the header level of the paragraph" 712 return self.level
713
714 - def set_font(self, font):
715 """ 716 Set the font style of the paragraph. 717 718 @param font: FontStyle object containing the font definition to use. 719 """ 720 self.font = FontStyle(font)
721
722 - def get_font(self):
723 "Return the FontStyle of the paragraph" 724 return self.font
725
726 - def set_padding(self, val):
727 """ 728 Set the paragraph padding in centimeters 729 730 @param val: floating point value indicating the padding in centimeters 731 """ 732 self.pad = val
733
734 - def get_padding(self):
735 """Return a the padding of the paragraph""" 736 return self.pad
737
738 - def set_top_border(self, val):
739 """ 740 Set the presence or absence of top border. 741 742 @param val: True indicates a border should be used, False indicates 743 no border. 744 """ 745 self.top_border = val
746
747 - def get_top_border(self):
748 "Return 1 if a top border is specified" 749 return self.top_border
750
751 - def set_bottom_border(self, val):
752 """ 753 Set the presence or absence of bottom border. 754 755 @param val: True indicates a border should be used, False 756 indicates no border. 757 """ 758 self.bottom_border = val
759
760 - def get_bottom_border(self):
761 "Return 1 if a bottom border is specified" 762 return self.bottom_border
763
764 - def set_left_border(self, val):
765 """ 766 Set the presence or absence of left border. 767 768 @param val: True indicates a border should be used, False 769 indicates no border. 770 """ 771 self.left_border = val
772
773 - def get_left_border(self):
774 "Return 1 if a left border is specified" 775 return self.left_border
776
777 - def set_right_border(self, val):
778 """ 779 Set the presence or absence of rigth border. 780 781 @param val: True indicates a border should be used, False 782 indicates no border. 783 """ 784 self.right_border = val
785
786 - def get_right_border(self):
787 "Return 1 if a right border is specified" 788 return self.right_border
789
790 - def get_background_color(self):
791 """ 792 Return a tuple indicating the RGB components of the background 793 color 794 """ 795 return self.bgcolor
796
797 - def set_background_color(self, color):
798 """ 799 Set the background color of the paragraph. 800 801 @param color: tuple representing the RGB components of a color 802 (0,0,0) to (255,255,255) 803 """ 804 self.bgcolor = color
805
806 - def set_alignment(self, align):
807 """ 808 Set the paragraph alignment. 809 810 @param align: PARA_ALIGN_LEFT, PARA_ALIGN_RIGHT, PARA_ALIGN_CENTER, 811 or PARA_ALIGN_JUSTIFY 812 """ 813 self.align = align
814
815 - def get_alignment(self):
816 "Return the alignment of the paragraph" 817 return self.align
818
819 - def get_alignment_text(self):
820 """ 821 Return a text string representing the alginment, either 'left', 822 'right', 'center', or 'justify' 823 """ 824 if self.align == PARA_ALIGN_LEFT: 825 return "left" 826 elif self.align == PARA_ALIGN_CENTER: 827 return "center" 828 elif self.align == PARA_ALIGN_RIGHT: 829 return "right" 830 elif self.align == PARA_ALIGN_JUSTIFY: 831 return "justify" 832 return "unknown"
833
834 - def set_left_margin(self, value):
835 "sets the left indent in centimeters" 836 self.lmargin = value
837
838 - def set_right_margin(self, value):
839 "sets the right indent in centimeters" 840 self.rmargin = value
841
842 - def set_first_indent(self, value):
843 "sets the first line indent in centimeters" 844 self.first_indent = value
845
846 - def set_top_margin(self, value):
847 "sets the space above paragraph in centimeters" 848 self.tmargin = value
849
850 - def set_bottom_margin(self, value):
851 "sets the space below paragraph in centimeters" 852 self.bmargin = value
853
854 - def get_left_margin(self):
855 "returns the left indent in centimeters" 856 return self.lmargin
857
858 - def get_right_margin(self):
859 "returns the right indent in centimeters" 860 return self.rmargin
861
862 - def get_first_indent(self):
863 "returns the first line indent in centimeters" 864 return self.first_indent
865
866 - def get_top_margin(self):
867 "returns the space above paragraph in centimeters" 868 return self.tmargin
869
870 - def get_bottom_margin(self):
871 "returns the space below paragraph in centimeters" 872 return self.bmargin
873
874 - def set_tabs(self, tab_stops):
875 assert(type(tab_stops) == type([])) 876 self.tabs = tab_stops
877
878 - def get_tabs(self):
879 return self.tabs
880 881 #------------------------------------------------------------------------ 882 # 883 # StyleSheetList 884 # 885 #------------------------------------------------------------------------
886 -class StyleSheetList:
887 """ 888 Interface into the user's defined style sheets. Each StyleSheetList 889 has a predefined default style specified by the report. Additional 890 styles are loaded from a specified XML file if it exists. 891 """ 892
893 - def __init__(self, filename, defstyle):
894 """ 895 Create a new StyleSheetList from the specified default style and 896 any other styles that may be defined in the specified file. 897 898 file - XML file that contains style definitions 899 defstyle - default style 900 """ 901 defstyle.set_name('default') 902 self.map = { "default" : defstyle } 903 self.file = os.path.join(const.HOME_DIR, filename) 904 self.parse()
905
906 - def delete_style_sheet(self, name):
907 """ 908 Remove a style from the list. Since each style must have a 909 unique name, the name is used to delete the stylesheet. 910 911 name - Name of the style to delete 912 """ 913 del self.map[name]
914
915 - def get_style_sheet_map(self):
916 """ 917 Return the map of names to styles. 918 """ 919 return self.map
920
921 - def get_style_sheet(self, name):
922 """ 923 Return the StyleSheet associated with the name 924 925 name - name associated with the desired StyleSheet. 926 """ 927 return self.map[name]
928
929 - def get_style_names(self):
930 "Return a list of all the style names in the StyleSheetList" 931 return self.map.keys()
932
933 - def set_style_sheet(self, name, style):
934 """ 935 Add or replaces a StyleSheet in the StyleSheetList. The 936 default style may not be replaced. 937 938 name - name assocated with the StyleSheet to add or replace. 939 style - definition of the StyleSheet 940 """ 941 style.set_name(name) 942 if name != "default": 943 self.map[name] = style
944
945 - def save(self):
946 """ 947 Saves the current StyleSheet definitions to the associated file. 948 """ 949 xml_file = open(self.file,"w") 950 xml_file.write("<?xml version=\"1.0\"?>\n") 951 xml_file.write('<stylelist>\n') 952 for name in self.map.keys(): 953 if name == "default": 954 continue 955 sheet = self.map[name] 956 xml_file.write('<sheet name="%s">\n' % escxml(name)) 957 for p_name in sheet.get_paragraph_style_names(): 958 para = sheet.get_paragraph_style(p_name) 959 xml_file.write('<style name="%s">\n' % escxml(p_name)) 960 font = para.get_font() 961 xml_file.write('<font face="%d" ' % font.get_type_face()) 962 xml_file.write('size="%d" ' % font.get_size()) 963 xml_file.write('italic="%d" ' % font.get_italic()) 964 xml_file.write('bold="%d" ' % font.get_bold()) 965 xml_file.write('underline="%d" ' % font.get_underline()) 966 xml_file.write('color="#%02x%02x%02x"/>\n' % font.get_color()) 967 xml_file.write('<para ') 968 rmargin = float(para.get_right_margin()) 969 lmargin = float(para.get_left_margin()) 970 findent = float(para.get_first_indent()) 971 tmargin = float(para.get_top_margin()) 972 bmargin = float(para.get_bottom_margin()) 973 padding = float(para.get_padding()) 974 xml_file.write('description="%s" ' % 975 escxml(para.get_description())) 976 xml_file.write('rmargin="%s" ' % Utils.gformat(rmargin)) 977 xml_file.write('lmargin="%s" ' % Utils.gformat(lmargin)) 978 xml_file.write('first="%s" ' % Utils.gformat(findent)) 979 xml_file.write('tmargin="%s" ' % Utils.gformat(tmargin)) 980 xml_file.write('bmargin="%s" ' % Utils.gformat(bmargin)) 981 xml_file.write('pad="%s" ' % Utils.gformat(padding)) 982 bg_color = para.get_background_color() 983 xml_file.write('bgcolor="#%02x%02x%02x" ' % bg_color) 984 xml_file.write('level="%d" ' % para.get_header_level()) 985 xml_file.write('align="%d" ' % para.get_alignment()) 986 xml_file.write('tborder="%d" ' % para.get_top_border()) 987 xml_file.write('lborder="%d" ' % para.get_left_border()) 988 xml_file.write('rborder="%d" ' % para.get_right_border()) 989 xml_file.write('bborder="%d"/>\n' % para.get_bottom_border()) 990 xml_file.write('</style>\n') 991 xml_file.write('</sheet>\n') 992 xml_file.write('</stylelist>\n') 993 xml_file.close()
994
995 - def parse(self):
996 """ 997 Loads the StyleSheets from the associated file, if it exists. 998 """ 999 try: 1000 if os.path.isfile(self.file): 1001 parser = make_parser() 1002 parser.setContentHandler(SheetParser(self)) 1003 the_file = open(self.file) 1004 parser.parse(the_file) 1005 the_file.close() 1006 except (IOError,OSError,SAXParseException): 1007 pass
1008 1009 #------------------------------------------------------------------------ 1010 # 1011 # StyleSheet 1012 # 1013 #------------------------------------------------------------------------
1014 -class StyleSheet:
1015 """ 1016 A collection of named paragraph styles. 1017 """ 1018
1019 - def __init__(self, obj=None):
1020 """ 1021 Create a new empty StyleSheet. 1022 1023 @param obj: if not None, creates the StyleSheet from the values in 1024 obj, instead of creating an empty StyleSheet 1025 """ 1026 self.para_styles = {} 1027 self.draw_styles = {} 1028 self.table_styles = {} 1029 self.cell_styles = {} 1030 self.name = "" 1031 if obj != None: 1032 for style_name in obj.para_styles.keys(): 1033 style = obj.para_styles[style_name] 1034 self.para_styles[style_name] = ParagraphStyle(style) 1035 for style_name in obj.draw_styles.keys(): 1036 style = obj.draw_styles[style_name] 1037 self.draw_styles[style_name] = GraphicsStyle(style) 1038 for style_name in obj.table_styles.keys(): 1039 style = obj.table_styles[style_name] 1040 self.table_styles[style_name] = TableStyle(style) 1041 for style_name in obj.cell_styles.keys(): 1042 style = obj.cell_styles[style_name] 1043 self.cell_styles[style_name] = TableCellStyle(style)
1044
1045 - def set_name(self, name):
1046 """ 1047 Set the name of the StyleSheet 1048 1049 @param name: The name to be given to the StyleSheet 1050 """ 1051 self.name = name
1052
1053 - def get_name(self):
1054 """ 1055 Return the name of the StyleSheet 1056 """ 1057 return self.name
1058
1059 - def clear(self):
1060 "Remove all styles from the StyleSheet" 1061 self.para_styles = {} 1062 self.draw_styles = {} 1063 self.table_styles = {} 1064 self.cell_styles = {}
1065
1066 - def is_empty(self):
1067 "Checks if any styles are defined" 1068 style_count = len(self.para_styles) + \ 1069 len(self.draw_styles) + \ 1070 len(self.table_styles) + \ 1071 len(self.cell_styles) 1072 if style_count > 0: 1073 return False 1074 else: 1075 return True
1076
1077 - def add_paragraph_style(self, name, style):
1078 """ 1079 Add a paragraph style to the style sheet. 1080 1081 @param name: The name of the ParagraphStyle 1082 @param style: ParagraphStyle instance to be added. 1083 """ 1084 self.para_styles[name] = ParagraphStyle(style)
1085
1086 - def get_paragraph_style(self, name):
1087 """ 1088 Return the ParagraphStyle associated with the name 1089 1090 @param name: name of the ParagraphStyle that is wanted 1091 """ 1092 return ParagraphStyle(self.para_styles[name])
1093
1094 - def get_paragraph_style_names(self):
1095 "Return the the list of paragraph names in the StyleSheet" 1096 return self.para_styles.keys()
1097
1098 - def add_draw_style(self, name, style):
1099 """ 1100 Add a draw style to the style sheet. 1101 1102 @param name: The name of the GraphicsStyle 1103 @param style: GraphicsStyle instance to be added. 1104 """ 1105 self.draw_styles[name] = GraphicsStyle(style)
1106
1107 - def get_draw_style(self, name):
1108 """ 1109 Return the GraphicsStyle associated with the name 1110 1111 @param name: name of the GraphicsStyle that is wanted 1112 """ 1113 return GraphicsStyle(self.draw_styles[name])
1114
1115 - def get_draw_style_names(self):
1116 "Return the the list of draw style names in the StyleSheet" 1117 return self.draw_styles.keys()
1118
1119 - def add_table_style(self, name, style):
1120 """ 1121 Add a table style to the style sheet. 1122 1123 @param name: The name of the TableStyle 1124 @param style: TableStyle instance to be added. 1125 """ 1126 self.table_styles[name] = TableStyle(style)
1127
1128 - def get_table_style(self, name):
1129 """ 1130 Return the TableStyle associated with the name 1131 1132 @param name: name of the TableStyle that is wanted 1133 """ 1134 return TableStyle(self.table_styles[name])
1135
1136 - def get_table_style_names(self):
1137 "Return the the list of table style names in the StyleSheet" 1138 return self.table_styles.keys()
1139
1140 - def add_cell_style(self, name, style):
1141 """ 1142 Add a cell style to the style sheet. 1143 1144 @param name: The name of the TableCellStyle 1145 @param style: TableCellStyle instance to be added. 1146 """ 1147 self.cell_styles[name] = TableCellStyle(style)
1148
1149 - def get_cell_style(self, name):
1150 """ 1151 Return the TableCellStyle associated with the name 1152 1153 @param name: name of the TableCellStyle that is wanted 1154 """ 1155 return TableCellStyle(self.cell_styles[name])
1156
1157 - def get_cell_style_names(self):
1158 "Return the the list of cell style names in the StyleSheet" 1159 return self.cell_styles.keys()
1160 1161 #------------------------------------------------------------------------- 1162 # 1163 # SheetParser 1164 # 1165 #-------------------------------------------------------------------------
1166 -class SheetParser(handler.ContentHandler):
1167 """ 1168 SAX parsing class for the StyleSheetList XML file. 1169 """ 1170
1171 - def __init__(self, sheetlist):
1172 """ 1173 Create a SheetParser class that populates the passed StyleSheetList 1174 class. 1175 1176 sheetlist - StyleSheetList instance to be loaded from the file. 1177 """ 1178 handler.ContentHandler.__init__(self) 1179 self.sheetlist = sheetlist 1180 self.f = None 1181 self.p = None 1182 self.s = None 1183 self.sname = None 1184 self.pname = None
1185
1186 - def startElement(self, tag, attrs):
1187 """ 1188 Overridden class that handles the start of a XML element 1189 """ 1190 if tag == "sheet": 1191 self.s = StyleSheet(self.sheetlist.map["default"]) 1192 self.sname = attrs['name'] 1193 elif tag == "font": 1194 self.f = FontStyle() 1195 self.f.set_type_face(int(attrs['face'])) 1196 self.f.set_size(int(attrs['size'])) 1197 self.f.set_italic(int(attrs['italic'])) 1198 self.f.set_bold(int(attrs['bold'])) 1199 self.f.set_underline(int(attrs['underline'])) 1200 self.f.set_color(cnv2color(attrs['color'])) 1201 elif tag == "para": 1202 if attrs.has_key('description'): 1203 self.p.set_description(attrs['description']) 1204 self.p.set_right_margin(Utils.gfloat(attrs['rmargin'])) 1205 self.p.set_right_margin(Utils.gfloat(attrs['rmargin'])) 1206 self.p.set_left_margin(Utils.gfloat(attrs['lmargin'])) 1207 self.p.set_first_indent(Utils.gfloat(attrs['first'])) 1208 try: 1209 # This is needed to read older style files 1210 # lacking tmargin and bmargin 1211 self.p.set_top_margin(Utils.gfloat(attrs['tmargin'])) 1212 self.p.set_bottom_margin(Utils.gfloat(attrs['bmargin'])) 1213 except KeyError: 1214 pass 1215 self.p.set_padding(Utils.gfloat(attrs['pad'])) 1216 self.p.set_alignment(int(attrs['align'])) 1217 self.p.set_right_border(int(attrs['rborder'])) 1218 self.p.set_header_level(int(attrs['level'])) 1219 self.p.set_left_border(int(attrs['lborder'])) 1220 self.p.set_top_border(int(attrs['tborder'])) 1221 self.p.set_bottom_border(int(attrs['bborder'])) 1222 self.p.set_background_color(cnv2color(attrs['bgcolor'])) 1223 elif tag == "style": 1224 self.p = ParagraphStyle() 1225 self.pname = attrs['name']
1226
1227 - def endElement(self, tag):
1228 "Overridden class that handles the start of a XML element" 1229 if tag == "style": 1230 self.p.set_font(self.f) 1231 self.s.add_paragraph_style(self.pname, self.p) 1232 elif tag == "sheet": 1233 self.sheetlist.set_style_sheet(self.sname, self.s)
1234 1235 #------------------------------------------------------------------------ 1236 # 1237 # GraphicsStyle 1238 # 1239 #------------------------------------------------------------------------
1240 -class GraphicsStyle:
1241 """ 1242 Defines the properties of graphics objects, such as line width, 1243 color, fill, ect. 1244 """
1245 - def __init__(self, obj=None):
1246 """ 1247 Initialize the object with default values, unless a source 1248 object is specified. In that case, make a copy of the source 1249 object. 1250 """ 1251 if obj: 1252 self.para_name = obj.para_name 1253 self.shadow = obj.shadow 1254 self.shadow_space = obj.shadow_space 1255 self.color = obj.color 1256 self.fill_color = obj.fill_color 1257 self.lwidth = obj.lwidth 1258 self.lstyle = obj.lstyle 1259 else: 1260 self.para_name = "" 1261 self.shadow = 0 1262 self.shadow_space = 0.2 1263 self.lwidth = 0.5 1264 self.color = (0, 0, 0) 1265 self.fill_color = (255, 255, 255) 1266 self.lstyle = SOLID
1267
1268 - def set_line_width(self, val):
1269 """ 1270 sets the line width 1271 """ 1272 self.lwidth = val
1273
1274 - def get_line_width(self):
1275 """ 1276 Return the name of the StyleSheet 1277 """ 1278 return self.lwidth
1279
1280 - def get_line_style(self):
1281 return self.lstyle
1282
1283 - def set_line_style(self, val):
1284 self.lstyle = val
1285
1286 - def set_paragraph_style(self, val):
1287 self.para_name = val
1288
1289 - def set_shadow(self, val, space=0.2):
1290 self.shadow = val 1291 self.shadow_space = space
1292
1293 - def get_shadow_space(self):
1294 return self.shadow_space
1295
1296 - def set_color(self, val):
1297 self.color = val
1298
1299 - def set_fill_color(self, val):
1300 self.fill_color = val
1301
1302 - def get_paragraph_style(self):
1303 return self.para_name
1304
1305 - def get_shadow(self):
1306 return self.shadow
1307
1308 - def get_color(self):
1309 return self.color
1310
1311 - def get_fill_color(self):
1312 return self.fill_color
1313 1314 #------------------------------------------------------------------------ 1315 # 1316 # IndexMark 1317 # 1318 #------------------------------------------------------------------------
1319 -class IndexMark:
1320 """ 1321 Defines a mark to be associated with text for indexing. 1322 """
1323 - def __init__(self, key="", itype=INDEX_TYPE_ALP, level=1):
1324 """ 1325 Initialize the object with default values, unless values are specified. 1326 """ 1327 self.key = key 1328 self.type = itype 1329 self.level = level
1330 1331 #------------------------------------------------------------------------ 1332 # 1333 # BaseDoc 1334 # 1335 #------------------------------------------------------------------------
1336 -class BaseDoc:
1337 """ 1338 Base class for document generators. Different output formats, 1339 such as OpenOffice, AbiWord, and LaTeX are derived from this base 1340 class, providing a common interface to all document generators. 1341 """
1342 - def __init__(self, styles, paper_style, template):
1343 """ 1344 Create a BaseDoc instance, which provides a document generation 1345 interface. This class should never be instantiated directly, but 1346 only through a derived class. 1347 1348 @param styles: StyleSheet containing the styles used. 1349 @param paper_style: PaperStyle instance containing information about 1350 the paper. If set to None, then the document is not a page 1351 oriented document (e.g. HTML) 1352 @param template: Format template for document generators that are 1353 not page oriented. 1354 """ 1355 self.template = template 1356 self.paper = paper_style 1357 self._style_sheet = styles 1358 self._creator = "" 1359 self.print_req = 0 1360 self.init_called = False 1361 self.type = "standard"
1362
1363 - def init(self):
1364 self.init_called = True
1365
1366 - def print_requested(self):
1367 self.print_req = 1
1368
1369 - def set_creator(self, name):
1370 "Set the owner name" 1371 self._creator = name
1372
1373 - def get_creator(self):
1374 "Return the owner name" 1375 return self._creator
1376
1377 - def get_style_sheet(self):
1378 """ 1379 Return the StyleSheet of the document. 1380 """ 1381 return StyleSheet(self._style_sheet)
1382
1383 - def set_style_sheet(self, style_sheet):
1384 """ 1385 Set the StyleSheet of the document. 1386 1387 @param style_sheet: The new style sheet for the document 1388 @type style_sheet: StyleSheet 1389 """ 1390 self._style_sheet = StyleSheet(style_sheet)
1391
1392 - def open(self, filename):
1393 """ 1394 Opens the document. 1395 1396 @param filename: path name of the file to create 1397 """ 1398 raise NotImplementedError
1399
1400 - def close(self):
1401 "Closes the document" 1402 raise NotImplementedError
1403 1404 #------------------------------------------------------------------------ 1405 # 1406 # TextDoc 1407 # 1408 #------------------------------------------------------------------------
1409 -class TextDoc:
1410 """ 1411 Abstract Interface for text document generators. Output formats for 1412 text reports must implment this interface to be used by the report 1413 system. 1414 """
1415 - def page_break(self):
1416 "Forces a page break, creating a new page" 1417 raise NotImplementedError
1418
1419 - def start_bold(self):
1420 raise NotImplementedError
1421
1422 - def end_bold(self):
1423 raise NotImplementedError
1424
1425 - def start_superscript(self):
1426 raise NotImplementedError
1427
1428 - def end_superscript(self):
1429 raise NotImplementedError
1430
1431 - def start_paragraph(self, style_name, leader=None):
1432 """ 1433 Starts a new paragraph, using the specified style name. 1434 1435 @param style_name: name of the ParagraphStyle to use for the 1436 paragraph. 1437 @param leader: Leading text for a paragraph. Typically used 1438 for numbering. 1439 """ 1440 raise NotImplementedError
1441
1442 - def end_paragraph(self):
1443 "Ends the current parsgraph" 1444 raise NotImplementedError
1445
1446 - def start_table(self, name, style_name):
1447 """ 1448 Starts a new table. 1449 1450 @param name: Unique name of the table. 1451 @param style_name: TableStyle to use for the new table 1452 """ 1453 raise NotImplementedError
1454
1455 - def end_table(self):
1456 "Ends the current table" 1457 raise NotImplementedError
1458
1459 - def start_row(self):
1460 "Starts a new row on the current table" 1461 raise NotImplementedError
1462
1463 - def end_row(self):
1464 "Ends the current row on the current table" 1465 raise NotImplementedError
1466
1467 - def start_cell(self, style_name, span=1):
1468 """ 1469 Starts a new table cell, using the paragraph style specified. 1470 1471 @param style_name: TableCellStyle to use for the cell 1472 @param span: number of columns to span 1473 """ 1474 raise NotImplementedError
1475
1476 - def end_cell(self):
1477 "Ends the current table cell" 1478 raise NotImplementedError
1479
1480 - def write_note(self, text, format, style_name):
1481 """ 1482 Writes the note's text and take care of paragraphs, 1483 depending on the format. 1484 1485 @param text: text to write. 1486 @param format: format to use for writing. True for flowed text, 1487 1 for preformatted text. 1488 """ 1489 raise NotImplementedError
1490
1491 - def write_text(self, text, mark=None):
1492 """ 1493 Writes the text in the current paragraph. Should only be used after a 1494 start_paragraph and before an end_paragraph. 1495 1496 @param text: text to write. 1497 @param mark: IndexMark to use for indexing (if supported) 1498 """ 1499 raise NotImplementedError
1500
1501 - def add_media_object(self, name, align, w_cm, h_cm):
1502 """ 1503 Add a photo of the specified width (in centimeters) 1504 1505 @param name: filename of the image to add 1506 @param align: alignment of the image. Valid values are 'left', 1507 'right', 'center', and 'single' 1508 @param w_cm: width in centimeters 1509 @param h_cm: height in centimeters 1510 """ 1511 raise NotImplementedError
1512 1513 #------------------------------------------------------------------------ 1514 # 1515 # DrawDoc 1516 # 1517 #------------------------------------------------------------------------
1518 -class DrawDoc:
1519 """ 1520 Abstract Interface for graphical document generators. Output formats 1521 for graphical reports must implment this interface to be used by the 1522 report system. 1523 """ 1524
1525 - def start_page(self):
1526 raise NotImplementedError
1527
1528 - def end_page(self):
1529 raise NotImplementedError
1530
1531 - def get_usable_width(self):
1532 """ 1533 Return the width of the text area in centimeters. The value is 1534 the page width less the margins. 1535 """ 1536 width = self.paper.get_size().get_width() 1537 right = self.paper.get_right_margin() 1538 left = self.paper.get_left_margin() 1539 return width - (right + left)
1540
1541 - def get_usable_height(self):
1542 """ 1543 Return the height of the text area in centimeters. The value is 1544 the page height less the margins. 1545 """ 1546 height = self.paper.get_size().get_height() 1547 top = self.paper.get_top_margin() 1548 bottom = self.paper.get_bottom_margin() 1549 return height - (top + bottom)
1550
1551 - def string_width(self, fontstyle, text):
1552 "Determine the width need for text in given font" 1553 return FontScale.string_width(fontstyle, text)
1554
1555 - def draw_path(self, style, path):
1556 raise NotImplementedError
1557
1558 - def draw_box(self, style, text, x, y, w, h):
1559 raise NotImplementedError
1560
1561 - def draw_text(self, style, text, x1, y1):
1562 raise NotImplementedError
1563
1564 - def center_text(self, style, text, x1, y1):
1565 raise NotImplementedError
1566
1567 - def rotate_text(self, style, text, x, y, angle):
1568 raise NotImplementedError
1569
1570 - def draw_line(self, style, x1, y1, x2, y2):
1571 raise NotImplementedError
1572 1573 #------------------------------------------------------------------------------- 1574 # 1575 # GVDoc 1576 # 1577 #-------------------------------------------------------------------------------
1578 -class GVDoc:
1579 """ 1580 Abstract Interface for Graphviz document generators. Output formats 1581 for Graphviz reports must implment this interface to be used by the 1582 report system. 1583 """
1584 - def add_node(self, id, label, shape="box", fillcolor="white", url="", htmloutput=False):
1585 """ 1586 Add a node to this graph. Nodes can be different shapes like boxes and 1587 circles. 1588 1589 @param id: A unique identification value for this node. 1590 Example: "p55" 1591 @type id: string 1592 @param label: The text to be displayed in the node. 1593 Example: "John Smith" 1594 @type label: string 1595 @param shape: The shape for the node. 1596 Examples: "box", "ellipse", "circle" 1597 @type shape: string 1598 @param fillcolor: The fill color for the node. 1599 Examples: "blue", "lightyellow" 1600 @type fillcolor: string 1601 @param url: A URL for the node. 1602 @type url: string 1603 @param htmloutput: Whether the label contains HTML. 1604 @type htmloutput: boolean 1605 @return: nothing 1606 """ 1607 raise NotImplementedError
1608 1625
1626 - def add_comment(self, comment):
1627 """ 1628 Add a comment to the source file. 1629 1630 @param comment: A text string to add as a comment. 1631 Example: "Next comes the individuals." 1632 @type comment: string 1633 @return: nothing 1634 """ 1635 raise NotImplementedError
1636
1637 - def start_subgraph(self,id):
1638 """ 1639 Start a subgraph in this graph. 1640 1641 @param id: The unique identifier of the subgraph. 1642 Example: "p55" 1643 @type id1: string 1644 @return: nothing 1645 """ 1646 raise NotImplementedError
1647
1648 - def end_subgraph(self):
1649 """ 1650 End a subgraph that was previously started in this graph. 1651 1652 @return: nothing 1653 """ 1654 raise NotImplementedError
1655