2
from reportlab.pdfbase import pdfmetrics
3
from reportlab.lib.units import inch,mm
4
from reportlab.pdfgen import canvas
5
import reportlab.platypus as platypus
6
from reportlab.platypus.flowables import ParagraphAndImage
7
import reportlab.lib.pagesizes as pagesizes
8
import reportlab.lib.fonts as fonts
9
import reportlab.lib.units as units
10
import reportlab.lib.styles as styles
11
from gettext import gettext as _
12
from gettext import ngettext
13
from gourmet import convert
14
from gourmet import gglobals
15
from gourmet.gtk_extras import dialog_extras as de
16
from gourmet import ImageExtras
17
import xml.sax.saxutils
20
import tempfile, os.path
22
from page_drawer import PageDrawer
24
PASS_REPORTLAB_UNICODE = (reportlab.Version.find('2')==0)
28
#'pagemode':'landscape',
29
#'left_margin':0.3*inch,
30
#'right_margin':0.3*inch,
31
#'top_margin':0.3*inch,
32
#'bottom_margin':0.3*inch,
34
#'mode':('index_cards',(5*inch,3.5*inch))
37
# Code for MCLine from:
38
# http://two.pairlist.net/pipermail/reportlab-users/2005-February/003695.html
39
class MCLine(platypus.Flowable):
40
"""Line flowable --- draws a line in a flowable"""
42
def __init__(self,width):
43
platypus.Flowable.__init__(self)
47
return "Line(w=%s)" % self.width
50
self.canv.line(0,0,self.width,0)
52
import reportlab.lib.colors as colors
53
class Star (platypus.Flowable):
54
'''A hand flowable.'''
55
def __init__(self, size=None, fillcolor=colors.tan, strokecolor=colors.green):
56
from reportlab.lib.units import inch
57
if size is None: size=12 # 12 point
58
self.fillcolor, self.strokecolor = fillcolor, strokecolor
60
# normal size is 4 inches
62
def getSpaceBefore (self):
65
def getSpaceAfter (self):
68
def wrap(self, availW, availH):
69
if self.size > availW or self.size > availH:
74
return (self.size,self.size)
77
size = self.size # * 0.8
78
self.draw_star(inner_length=size/4,
81
def draw_circle (self, x, y, r):
84
canvas.setLineWidth(0)
85
canvas.setStrokeColor(colors.grey)
86
canvas.setFillColor(colors.grey)
87
p = canvas.beginPath()
90
canvas.drawPath(p,fill=1)
92
def draw_half_star (self, inner_length=1*inch, outer_length=2*inch, points=5, origin=None):
94
canvas.setLineWidth(0)
95
if not origin: canvas.translate(self.size*0.5,self.size*0.5)
96
else: canvas.translate(*origin)
97
canvas.setFillColor(self.fillcolor)
98
canvas.setStrokeColor(self.strokecolor)
99
p = canvas.beginPath()
100
inner = False # Start on top
102
#print 'Drawing star with radius',outer_length,'(moving origin ',origin,')'
103
for theta in range(0,360,360/(points*2)):
104
if 0 < theta < 180: continue
105
if inner: r = inner_length
106
else: r = outer_length
107
x = (math.sin(math.radians(theta)) * r)
108
y = (math.cos(math.radians(theta)) * r)
117
canvas.drawPath(p,fill=1)
119
def draw_star (self, inner_length=1*inch, outer_length=2*inch, points=5, origin=None):
121
canvas.setLineWidth(0)
122
if not origin: canvas.translate(self.size*0.5,self.size*0.5)
123
else: canvas.translate(*origin)
124
canvas.setFillColor(self.fillcolor)
125
canvas.setStrokeColor(self.strokecolor)
126
p = canvas.beginPath()
127
inner = False # Start on top
129
#print 'Drawing star with radius',outer_length,'(moving origin ',origin,')'
130
for theta in range(0,360,360/(points*2)):
131
if inner: r = inner_length
132
else: r = outer_length
133
x = (math.sin(math.radians(theta)) * r)
134
y = (math.cos(math.radians(theta)) * r)
143
canvas.drawPath(p,fill=1)
146
class FiveStars (Star):
148
def __init__ (self, height, filled=5, out_of=5,
149
filled_color=colors.black,
150
unfilled_color=colors.lightgrey
152
self.height = self.size = height
155
self.filled_color = filled_color; self.unfilled_color = unfilled_color
156
self.width = self.height * self.out_of + (self.height * 0.2 * (self.out_of-1)) # 20% padding
157
self.ratio = self.height / 12 # 12 point is standard
160
def wrap (self, *args):
161
return self.width,self.height
164
#self.canv.scale(self.ratio,self.ratio)
167
def draw_stars (self):
169
for n in range(self.out_of):
170
if self.filled - n >= 1:
171
# Then we draw a gold star
172
self.fillcolor,self.strokecolor = self.filled_color,self.filled_color
173
r = self.height * 0.5
175
self.fillcolor,self.strokecolor = self.unfilled_color,self.unfilled_color
176
r = self.height * 0.75 * 0.5
179
((n >= 1 and (self.height * 1.2)) or self.height*0.5),
181
((n < 1 and self.height* 0.5) or 0)
183
#print 'origin = ',#origin,'or',
184
#print origin[0]/self.height,origin[1]/self.height
185
#self.draw_circle(origin[0],origin[1],r)
186
self.draw_star(points=5,origin=origin,inner_length=r/2,outer_length=r)
187
if self.filled - n == 0.5:
188
# If we're a half star...
189
self.fillcolor,self.strokecolor = self.filled_color,self.filled_color
190
self.draw_half_star(points=5,
191
inner_length=self.height*0.25,
192
outer_length=self.height*0.5,
196
# Copied from http://two.pairlist.net/pipermail/reportlab-users/2004-April/002917.html
197
# A convenience class for bookmarking
198
class Bookmark(platypus.Flowable):
199
""" Utility class to display PDF bookmark. """
201
def __init__(self, title, key):
204
platypus.Flowable.__init__(self)
206
def wrap(self, availWidth, availHeight):
207
""" Doesn't take up any space. """
211
# set the bookmark outline to show when the file's opened
212
self.canv.showOutline()
213
# step 1: put a bookmark on the
214
self.canv.bookmarkPage(str(self.key))
215
# step 2: put an entry in the bookmark outline
216
self.canv.addOutlineEntry(self.title,
225
def setup_document (self, file, mode=('column',1), size='default', pagesize='letter',
226
pagemode='portrait',left_margin=inch,right_margin=inch,
231
frames = self.setup_frames(mode,size,pagesize,pagemode,
232
left_margin,right_margin,top_margin,
233
bottom_margin,base_font_size)
234
pt = platypus.PageTemplate(frames=frames)
235
self.doc = platypus.BaseDocTemplate(file,pagesize=self.pagesize,
237
self.doc.frame_width = frames[0].width
238
self.doc.frame_height = frames[0].height
239
self.styleSheet = styles.getSampleStyleSheet()
240
perc_scale = float(base_font_size)/self.styleSheet['Normal'].fontSize
242
self.scale_stylesheet(perc_scale)
245
def setup_frames (self,mode=('column',1), size='default', pagesize='letter',
246
pagemode='portrait',left_margin=inch,right_margin=inch,
250
if type(mode)!=tuple: raise "What is this mode! %s"%str(mode)
251
if type(pagesize) in types.StringTypes:
252
self.pagesize = getattr(pagesizes,pagemode)(getattr(pagesizes,pagesize))
254
self.pagesize = getattr(pagesizes,pagemode)(pagesize)
255
self.margins = (left_margin,right_margin,top_margin,bottom_margin)
256
if mode[0] == 'column':
257
frames = self.setup_column_frames(mode[1])
258
elif mode[0] == 'index_cards':
259
frames = self.setup_multiple_index_cards(mode[1])
261
raise("WTF - mode = %s"%str(mode))
264
def scale_stylesheet (self, perc):
265
for name,sty in self.styleSheet.byName.items():
266
for attr in ['firstLineIndent',
271
setattr(sty,attr,int(perc*getattr(sty,attr)))
273
def setup_column_frames (self, n):
274
COLUMN_SEPARATOR = 0.5 * inch
277
leftM,rightM,topM,bottomM = self.margins
279
FRAME_HEIGHT = y - topM - bottomM
280
FRAME_WIDTH = (x - (COLUMN_SEPARATOR*(n-1)) - leftM - rightM)/n
283
left_start = leftM + (FRAME_WIDTH + COLUMN_SEPARATOR)*i
286
left_start,FRAME_Y,width=FRAME_WIDTH,height=FRAME_HEIGHT
291
def setup_multiple_index_cards (self,card_size):
292
leftM,rightM,topM,bottomM = self.margins
293
MINIMUM_SPACING = 0.1*inch
294
drawable_x = self.pagesize[0] - leftM - rightM
295
drawable_y = self.pagesize[1] - topM - bottomM
296
fittable_x = int(drawable_x / (card_size[0]+MINIMUM_SPACING))
297
fittable_y = int(drawable_y / (card_size[1]+MINIMUM_SPACING))
298
# Raise a ValueError if we can't actually fit multiple index cards on this page.
299
if (not fittable_x) or (not fittable_y):
300
raise ValueError("Card size %s does not fit on page %s with margins %s"%(
301
card_size,self.pagesize,self.margins
306
fittable_x * # Number of cards times
307
((drawable_x/fittable_x) # space per card
308
- card_size[0] ) # - space occupied by card
309
/ # Divide extra space by n+1, so we get [ CARD ], [ CARD CARD ], etc.
314
((drawable_y/fittable_y)
320
for x in range(fittable_x):
321
x_start = leftM + (x_spacer*(x+1)) + (card_size[0]*x)
322
for y in range(fittable_y-1,-1,-1):
323
# Count down for the y, since we start from the bottom
325
y_start = bottomM + (y_spacer*(y+1)) + (card_size[1]*y)
327
platypus.Frame(x_start,y_start,
334
def make_paragraph (self, txt, style=None, attributes="",keep_with_next=False):
336
txt = '<para %s>%s</para>'%(attributes,txt)
338
txt = '<para>%s</para>'%txt
339
if not style: style = self.styleSheet['Normal']
341
if PASS_REPORTLAB_UNICODE:
342
return platypus.Paragraph(unicode(txt),style)
344
return platypus.Paragraph(unicode(txt).encode('iso-8859-1','replace'),style)
345
except UnicodeDecodeError:
347
#print 'WORK AROUND UNICODE ERROR WITH ',txt[:20]
348
# This seems to be the standard on windows.
349
platypus.Paragraph(txt,style)
351
print 'Trouble with ',txt
354
def write_paragraph (self, txt, style=None, keep_with_next=False, attributes=""):
355
p = self.make_paragraph(txt,style,attributes,keep_with_next=keep_with_next)
357
# Keep with next isn't working, so we use a conditional
358
# page break, on the assumption that no header should have
359
# less than 3/4 inch of stuff after it on the page.
360
self.txt.append(platypus.CondPageBreak(0.75*inch))
364
def write_header (self, txt):
367
WARNING: If this is not followed by a call to our write_paragraph(...keep_with_next=False),
368
the header won't necessarily be written.
370
self.write_paragraph(
372
style=self.styleSheet['Heading1'],
373
keep_with_next = True
376
def write_subheader (self, txt):
377
"""Write a subheader.
379
WARNING: If this is not followed by a call to our write_paragraph(...keep_with_next=False),
380
the header won't necessarily be written.
382
self.write_paragraph(
384
style=self.styleSheet['Heading2'],
390
try: self.doc.build(self.txt)
392
print 'Trouble building',t[:20]
395
class PdfExporter (exporter.exporter_mult, PdfWriter):
397
def __init__ (self, rd, r, out,
401
pdf_args=DEFAULT_PDF_ARGS,
403
self.links = [] # Keep track of what recipes we link to to
404
# make sure we use them...
405
PdfWriter.__init__(self)
406
if type(out) in types.StringTypes:
409
self.setup_document(out,**pdf_args)
410
self.multidoc = False
412
self.doc = doc; self.styleSheet = styleSheet; self.txt = []
413
self.master_txt = txt
415
# Put nice lines to separate multiple recipes out...
416
#if pdf_args.get('mode',('columns',1))[0]=='columns':
417
# self.txt.append(MCLine(self.doc.frame_width*0.8))
418
exporter.exporter_mult.__init__(
421
None, # exporter_mult has no business touching a file
423
order=['image','attr','ings','text'],
425
fractions=convert.FRACTIONS_NORMAL,
428
if not self.multidoc:
429
self.close() # Finish the document if this is all-in-one
432
#self.txt.append(platypus.PageBreak()) # Otherwise, a new page
433
# Append to the txt list we were handed ourselves in a KeepTogether block
434
#self.txt.append(platypus.Spacer(0,inch*0.5))
435
#if pdf_args.get('mode',('column',1))[0]=='column':
436
# self.master_txt.append(platypus.KeepTogether(self.txt))
439
self.master_txt.append(platypus.FrameBreak())
440
self.master_txt.extend(self.txt)
441
#self.master_txt.extend(self.txt)
443
def handle_italic (self, chunk):
444
return '<i>' + chunk + '</i>'
446
def handle_bold (self, chunk):
447
return '<b>' + chunk + '</b>'
449
def handle_underline (self, chunk):
450
return '<u>' + chunk + '</u>'
452
def scale_image (self, image, proportion=None):
453
# Platypus assumes image size is in points -- this appears to
454
# be off by the amount below.
455
if not proportion: proportion = inch/100 # we want 100 dots per image
456
image.drawHeight = image.drawHeight*proportion
457
image.drawWidth = image.drawWidth*proportion
459
def write_image (self, data):
460
fn = ImageExtras.write_image_tempfile(data)
461
i = platypus.Image(fn)
464
MAX_WIDTH = self.doc.frame_width * 0.35
465
MAX_HEIGHT = self.doc.frame_height * 0.5
466
if i.drawWidth > MAX_WIDTH:
467
factor = MAX_WIDTH/i.drawWidth
468
if i.drawHeight > MAX_HEIGHT:
469
f = MAX_HEIGHT/i.drawHeight
470
if f < factor: factor = f
472
self.scale_image(i,factor)
475
def write_attr_head (self):
476
# just move .txt aside through the attrs -- this way we can
477
# use our regular methods to keep adding attribute elements
480
def write_attr_foot (self):
481
# If we have 3 or fewer attributes and no images, we don't
483
if len(self.attributes)<=3 and not hasattr(self,'image'):
484
self.txt.extend(self.attributes)
486
if not self.attributes and hasattr(self,'image'):
487
# If we only have an image...
488
self.txt.append(self.image)
490
elif hasattr(self,'image') and self.image.drawWidth > (self.doc.frame_width / 2.25):
491
self.txt.append(self.image)
492
self.txt.extend(self.attributes)
494
# Otherwise, we're going to make a table...
495
if hasattr(self,'image'):
496
# If we have an image, we put attributes on the
497
# left, image on the right
500
# column 1 = attributes
508
nattributes = len(self.attributes)
509
first_col_size = nattributes/2 + nattributes % 2
510
first = self.attributes[:first_col_size]
511
second = self.attributes[first_col_size:]
513
for n,left in enumerate(first):
514
right = len(second)>n and second[n] or ''
515
table_data.append([left,right])
516
t = platypus.Table(table_data)
518
platypus.TableStyle([
519
('VALIGN',(0,0),(0,-1),'TOP'),
520
('LEFTPADDING',(0,0),(0,-1),0),
522
#('INNERGRID',(0,0),(-1,-1),.25,colors.red),
523
#('BOX',(0,0),(-1,-1),.25,colors.red),
528
#self.txt = [platypus.KeepTogether(self.txt)]
530
def make_rating (self, label, val):
531
"""Make a pretty representation of our rating.
534
assert(type(val)==int)
536
raise TypeError("Rating %s is not an integer"%val)
537
i = FiveStars(10, filled=(val/2.0)) # 12 point
538
lwidth = len(label+': ')*4 # A very cheap approximation of width
541
colWidths=[lwidth,inch],
545
platypus.TableStyle([
546
('LEFTPADDING',(0,0),(-1,0),0),
547
('LEFTPADDING',(1,0),(1,0),6),
548
('TOPPADDING',(0,0),(-1,-1),0),
549
('ALIGNMENT',(1,0),(1,0),'LEFT'),
550
('VALIGN',(0,0),(0,0),'TOP'),
552
#('INNERGRID',(0,0),(-1,-1),.25,colors.black),
553
#('BOX',(0,0),(-1,-1),.25,colors.black),
559
def write_attr (self, label, text):
560
attr = gglobals.NAME_TO_ATTR[label]
562
self.txt.append(Bookmark(self.r.title,'r'+str(self.r.id)))
563
self.write_paragraph(text,style=self.styleSheet['Heading1'])
565
from gourmet.importers.importer import string_to_rating
566
val = string_to_rating(text)
568
self.attributes.append(self.make_rating(label,val))
571
trimmed = text.strip()
573
trimmed=trimmed[:29]+'…'
574
self.attributes.append(self.make_paragraph('%s: <link href="%s">%s</link>'%(label,text,trimmed)))
576
# If nothing else has returned...
577
self.attributes.append(self.make_paragraph("%s: %s"%(label,text)))
579
def write_text (self, label, text):
580
self.write_subheader(label)
582
for t in text.split('\n'):
583
# HARDCODING paragraph style to space
586
self.write_paragraph(t,attributes="spacebefore='6'")
588
def write_inghead (self):
589
self.save_txt = self.txt[:]
591
self.write_subheader(xml.sax.saxutils.escape(_('Ingredients')))
593
def write_grouphead (self, name):
594
self.write_paragraph(name,self.styleSheet['Heading3'])
596
def write_ingfoot (self):
597
# Ugly -- we know that heads comprise two elements -- a
598
# condbreak and a head...
601
half = (len(ings) / 2)
602
first_half = ings[:-half]
603
second_half = ings[-half:]
605
[[first_half,second_half]]
609
platypus.TableStyle([
610
('VALIGN',(0,0),(1,0),'TOP'),
614
self.txt = self.txt[:2] + [t]
615
self.txt = self.save_txt + [platypus.KeepTogether(self.txt)]
617
def write_ing (self, amount=1, unit=None, item=None, key=None, optional=False):
619
for blob in [amount,unit,item,(optional and _('optional') or '')]:
620
if not blob: continue
621
if txt: txt += " %s"%blob
624
self.write_paragraph(
626
attributes=' firstLineIndent="-%(hanging)s" leftIndent="%(hanging)s"'%locals()
629
def write_ingref (self, amount, unit, item, refid, optional):
630
reffed = self.rd.get_rec(refid)
632
reffed = self.rd.fetch_one(self.rd.recipe_table,title=item,deleted=False)
636
return self.write_ing(amount,unit,item,optional=optional)
638
for blob in [amount,unit,item,(optional and _('optional') or '')]:
640
blob = '<link href="r%s">'%refid + blob + '</link>'
641
if not blob: continue
642
if txt: txt += " %s"%blob
645
self.links.append(refid)
646
self.write_paragraph(
648
attributes=' firstLineIndent="-%(hanging)s" leftIndent="%(hanging)s"'%locals()
651
class PdfExporterMultiDoc (exporter.ExporterMultirec, PdfWriter):
652
def __init__ (self, rd, recipes, out, progress_func=None, conv=None,
653
pdf_args=DEFAULT_PDF_ARGS,
656
PdfWriter.__init__(self)
657
if type(out) in types.StringTypes:
659
self.setup_document(out,**pdf_args)
660
self.output_file = out
661
kwargs['doc'] = self.doc
662
kwargs['styleSheet'] = self.styleSheet
663
kwargs['txt'] = self.txt
664
kwargs['pdf_args'] = pdf_args
665
exporter.ExporterMultirec.__init__(
668
one_file=True, ext='pdf',
669
exporter=PdfExporter,
671
progress_func=progress_func,
672
exporter_kwargs=kwargs,
675
def write_footer (self):
677
self.output_file.close()
679
class Sizer (PdfWriter):
681
def get_size (self, *args, **kwargs):
682
frames = self.setup_frames(*args,**kwargs)
683
return self.pagesize,frames
685
def get_pagesize_and_frames_for_widget (self, *args, **kwargs):
686
ps,ff = self.get_size(*args,**kwargs)
688
(f.x1, # X (top corner)
689
ps[1]-f._y2, #Y (top corner)
690
f.width,f.height) for f in ff]
693
class PdfPageDrawer (PageDrawer):
695
def __init__ (self,*args,**kwargs):
696
PageDrawer.__init__(self,*args,**kwargs)
700
def set_page (self, *args, **kwargs):
701
self.last_kwargs = kwargs
702
size,areas = self.sizer.get_pagesize_and_frames_for_widget(*args,**kwargs)
703
self.set_page_area(size[0],size[1],areas)
706
'page_size':_('Letter'),
707
'orientation':_('Portrait'),
709
'page_layout':_('Plain'),
718
_('11x17"'):'elevenSeventeen',
719
_('Index Card (3.5x5")'):(3.5*inch,5*inch),
720
_('Index Card (4x6")'):(4*inch,6*inch),
721
_('Index Card (5x8")'):(5*inch,8*inch),
722
_('Index Card (A7)'):(74*mm,105*mm),
723
_('Letter'):'letter',
725
'A0':'A0','A1':'A1','A2':'A2','A3':'A3','A4':'A4','A5':'A5','A6':'A6',
726
'B0':'B0','B1':'B1','B2':'B2','B3':'B3','B4':'B4','B5':'B5','B6':'B6',
729
INDEX_CARDS = [(3.5*inch,5*inch),(4*inch,6*inch),(5*inch,8*inch),(74*mm,105*mm)]
730
INDEX_CARD_LAYOUTS = [_('Index Cards (3.5x5)'),
731
_('Index Cards (4x6)'),
732
_('Index Cards (A7)'),
735
_('Plain'):('column',1),
736
_('Index Cards (3.5x5)'):('index_cards',(5*inch,3.5*inch)),
737
_('Index Cards (4x6)'):('index_cards',(6*inch,4*inch)),
738
_('Index Cards (A7)'):('index_cards',(105*mm,74*mm)),
742
_('Portrait'):'portrait',
743
_('Landscape'):'landscape',
746
OPT_PS,OPT_PO,OPT_FS,OPT_PL,OPT_LM,OPT_RM,OPT_TM,OPT_BM = range(8)
748
def __init__ (self, defaults=PDF_PREF_DEFAULT):
749
self.size_strings = self.page_sizes.keys()
750
self.size_strings.sort()
752
self.layouts[ngettext('%s Column','%s Columns',n)%n]=('column',n)
753
self.layout_strings = self.layouts.keys()
754
self.layout_strings.sort()
756
[_('Paper _Size')+':',(defaults.get('page_size',PDF_PREF_DEFAULT['page_size']),
758
[_('_Orientation')+':',(defaults.get('orientation',PDF_PREF_DEFAULT['orientation']),
759
self.page_modes.keys())],
760
[_('_Font Size')+':',defaults.get('font_size',PDF_PREF_DEFAULT['font_size'])]
762
[_('Page _Layout'),(defaults.get('page_layout',PDF_PREF_DEFAULT['page_layout']),
764
self.layout_strings)],
765
[_('Left Margin')+':',defaults.get('left_margin',PDF_PREF_DEFAULT['left_margin'])]
767
[_('Right Margin')+':',defaults.get('right_margin',PDF_PREF_DEFAULT['right_margin'])]
769
[_('Top Margin')+':',defaults.get('top_margin',PDF_PREF_DEFAULT['top_margin'])]
771
[_('Bottom Margin')+':',defaults.get('bottom_margin',PDF_PREF_DEFAULT['bottom_margin'])]
775
self.page_drawer = PdfPageDrawer(yalign=0.0)
777
self.pd = de.PreferencesDialog(self.opts,option_label=None,value_label=None,
780
self.pd.table.connect('changed',self.change_cb)
781
self.pd.table.emit('changed')
782
self.pd.hbox.pack_start(self.page_drawer,fill=True,expand=True)
783
self.page_drawer.set_size_request(200,100)
784
self.page_drawer.show()
788
return self.get_args_from_opts(self.opts)
790
def get_args_from_opts (self, opts):
792
args['pagesize']=self.page_sizes[opts[self.OPT_PS][1]] # PAGE SIZE
793
args['pagemode']=self.page_modes[opts[self.OPT_PO][1]] # PAGE MODE
794
args['base_font_size']=opts[self.OPT_FS][1] # FONT SIZE
795
args['mode']=self.layouts[opts[self.OPT_PL][1]] # LAYOUT/MODE
796
args['left_margin']=opts[self.OPT_LM][1]*inch
797
args['right_margin']=opts[self.OPT_RM][1]*inch
798
args['top_margin']=opts[self.OPT_TM][1]*inch
799
args['bottom_margin']=opts[self.OPT_BM][1]*inch
802
def change_cb (self, option_table, *args,**kwargs):
803
if self.in_ccb: return
806
args = self.get_args_from_opts(self.opts)
808
if args['pagesize']!=self.page_drawer.last_kwargs.get('pagesize','letter'):
809
last_pagesize = self.page_drawer.last_kwargs.get('pagesize','letter')
810
pagesize = args['pagesize']
811
# If pagesize has changed from index to non-index card,
812
# toggle orientation and margins by default for our user's
814
if pagesize in self.INDEX_CARDS and last_pagesize not in self.INDEX_CARDS:
816
option_table.set_option(self.OPT_PO,_('Landscape'))
817
for o in [self.OPT_LM,self.OPT_RM,self.OPT_BM,self.OPT_TM]:
818
option_table.set_option(o,0.25)
819
option_table.set_option(self.OPT_FS,8)
820
# Also -- make sure we don't allow index card layout in this...
821
cb = option_table.widgets[self.OPT_PL][0]
822
if not hasattr(self,'index_card_layouts_to_put_back'):
823
self.index_card_layouts_to_put_back = []
824
for i in self.INDEX_CARD_LAYOUTS:
825
pos=self.layout_strings.index(i)
826
self.index_card_layouts_to_put_back.append((pos,i))
827
self.index_card_layouts_to_put_back.sort()
829
if n in [i[0] for i in self.index_card_layouts_to_put_back]:
830
default_pos = self.layout_strings.index(_('Plain'))
831
cb.set_active(default_pos)
832
self.index_card_layouts_to_put_back.reverse()
833
for pos,txt in self.index_card_layouts_to_put_back:
835
self.index_card_layouts_to_put_back.reverse()
836
elif pagesize not in self.INDEX_CARDS and last_pagesize in self.INDEX_CARDS:
838
option_table.set_option(self.OPT_PO,_('Portrait'))
839
for o in [self.OPT_LM,self.OPT_RM,self.OPT_BM,self.OPT_TM]:
840
option_table.set_option(o,1)
841
option_table.set_option(self.OPT_FS,10)
842
# Also -- we allow index card layout in this...
843
cb = option_table.widgets[self.OPT_PL][0]
844
if hasattr(self,'index_card_layouts_to_put_back'):
845
for pos,txt in self.index_card_layouts_to_put_back:
846
cb.insert_text(pos,txt)
848
if (args['mode'][0] != self.page_drawer.last_kwargs.get('mode',('column',1))[0]
850
(args['mode'][0]=='index_cards'
851
and (args['mode'] != self.page_drawer.last_kwargs['mode']
853
(args['pagesize'] != self.page_drawer.last_kwargs['pagesize']
855
'elevenSeventeen' in [args['pagesize'],self.page_drawer.last_kwargs['pagesize']]
860
# If our mode has changed...
862
if args['mode'][0]=='index_cards':
863
option_table.set_option(self.OPT_FS,8)
864
for o in [self.OPT_LM,self.OPT_RM,self.OPT_BM,self.OPT_TM]:
865
option_table.set_option(o,0.35)
866
if (args['mode'][1][0] <= 5.2*inch) ^ (args['pagesize']=='elevenSeventeen'):
867
option_table.set_option(self.OPT_PO,_('Landscape'))
869
option_table.set_option(self.OPT_PO,_('Portrait'))
871
# Otherwise it's columns...
872
option_table.set_option(self.OPT_FS,10)
873
for o in [self.OPT_LM,self.OPT_RM,self.OPT_BM,self.OPT_TM]:
874
option_table.set_option(o,1)
877
args = self.get_args_from_opts(self.opts)
878
#backup_args = page_drawer.last_kwargs
879
self.page_drawer.set_page(**args)
880
self.page_drawer.queue_draw()
883
def get_pdf_prefs (defaults=PDF_PREF_DEFAULT):
884
pdf_pref_getter = PdfPrefGetter(defaults=defaults)
885
return pdf_pref_getter.run()
887
if __name__ == '__main__':
888
from tempfile import tempdir
890
#opts = get_pdf_prefs(); print opts
892
f = file(os.path.join(tempdir,'foo.pdf'),'wb')
894
mode=('index_cards',(5*inch,3.5*inch)),
896
pagemode='landscape',
897
left_margin=0.25*inch,right_margin=0.25*inch,
898
top_margin=0.25*inch,bottom_margin=0.25*inch,
901
#sw.write_header('Heading')
902
#sw.write_subheader('This is a subheading')
908
# u"This is a subheader"
911
u"%s: These are some sentences. Hopefully some of these will be quite long sentences. Some of this text includes unicode -- 45\u00b0F, for example... \u00bfHow's that?"%n*10
913
#sw.write_paragraph('This is a <i>paragraph</i> with <b>some</b> <u>markup</u>.')
914
#sw.write_paragraph(u"This is some text with unicode - 45\u00b0, \u00bfHow's that?".encode('iso-8859-1'))
915
#sw.write_paragraph(u"This is some text with a unicode object - 45\u00b0, \u00bfHow's that?")
919
#star_file = file(os.path.join(tempdir,'star.pdf'),'wb')
921
#sw.setup_document(star_file,mode='two_column')
922
#for n in range(6,72,2):
923
# sw.write_paragraph("This is some text with a %s pt star"%n)
924
# sw.txt.append(FiveStars(n,filled=3.5))
929
#gnome.program_init('1.0','Gourmet PDF Exporter Test')
930
#gglobals.launch_url('file:/os.path.join(tempdir,/star.pdf')
931
#raise "I don')t want to go any further"
936
base = '/home/tom/Projects/grm'
938
#import gourmet.recipeManager as rm
939
#rd = rm.RecipeManager(file=os.path.join(base,'src','tests','reference_setup','recipes.db'))
940
#rd = rm.RecipeManager()
941
#ofi = file(os.path.join(tempdir,'test_rec.pdf'),'w')
943
#for n,rec in enumerate(rd.fetch_all(rd.recipe_table,deleted=False)):
946
#pe = PdfExporterMultiDoc(rd,rd.fetch_all(rd.recipe_table),os.path.join(tempdir,'fooby.pdf'))
947
#pe = PdfExporterMultiDoc(rd,rd.fetch_all(rd.recipe_table,deleted=False)[:10],os.path.join(tempdir,'fooby.pdf'))
948
#pe = PdfExporterMultiDoc(rd,rr,os.path.join(tempdir,'fooby.pdf'))
951
def test_formatting ():
952
print 'Test formatting'
954
f = file(os.path.join(tempdir,'format.pdf'),'wb')
956
sw.write_header('This is a header & isn\'t it nifty')
957
sw.write_paragraph('<i>This</i> is a <b>paragraph</b> with <u>formatting</u>!')
958
sw.write_header('<u>This is a formatted header & it is also nifty & cool</u>')
959
sw.write_paragraph('<i>This is another formatted paragraph</i>')
960
sw.write_paragraph('<span fg="\#f00">This is color</span>')
963
return os.path.join(tempdir,'format.pdf')
966
print 'Test 3x5 layout'
968
f = file(os.path.join(tempdir,'foo.pdf'),'wb')
970
mode=('index_cards',(5*inch,3.5*inch)),
971
#pagesize=(5*inch,3.5*inch),
973
pagemode='landscape',
974
left_margin=0.25*inch,right_margin=0.25*inch,
975
top_margin=0.25*inch,bottom_margin=0.25*inch,
983
u"%s: These are some sentences. Hopefully some of these will be quite long sentences. Some of this text includes unicode -- 45\u00b0F, for example... \u00bfHow's that?"%n*10
987
return os.path.join(tempdir,'foo.pdf')
989
def test_grm_export (pdf_args=DEFAULT_PDF_ARGS):
990
fname = tempfile.mktemp('.pdf')
992
# base = 'C:\\grm\grm'
994
# base = '/home/tom/Projects/grm'
995
import gourmet.recipeManager as rm
996
rd = rm.RecipeManager(file=os.path.join(base,'src','tests','reference_setup','recipes.db'))
997
#rd = rm.RecipeManager()
999
#for n,rec in enumerate(rd.fetch_all(rd.recipe_table,deleted=False)):
1002
pe = PdfExporterMultiDoc(rd,rd.fetch_all(rd.recipe_table,deleted=False),fname,pdf_args=pdf_args)
1006
import gourmet.gglobals as gglobals
1009
gnome.program_init('1.0','Gourmet PDF Exporter Test')
1011
print 'We must be on windows...'
1014
#gglobals.launch_url('file://'+test_3_x_5())
1015
#gglobals.launch_url('file://'+test_formatting())
1018
gglobals.launch_url('file://'+test_grm_export())
1019
#print 'TEST CUSTOM GRM'
1020
#gglobals.launch_url('file://'+test_grm_export(get_pdf_prefs({'page_size':_('A4'),'page_layout':'2 Columns'})))
1021
#ppg = PdfPrefGetter()