Automatic story formatting
Jump to navigation
Jump to search
This script show a dialog with options to be applied to a selected text frame: paragraphs styles, title frame, number of text columns, etc.
Need Tkinter.
#!/usr/bin/python # -*- coding: utf-8 -*- ''' BUILD NEWSPAPER STORY. Author: prof. José Antonio Meira da Rocha joseantoniorocha@gmail.com http://meiradarocha.jor.br Licence: GPL 2 2012-03-10a USAGE: Draw a text frame marking the area where you need a story, optionaly putting text inside. Select the frame, run the script and choose styles to be applied, numbers of columns, gutter and guide lines. The script will: 1. Resize the frame to hold headers. 2. Draw a second linked frame to hold text in columns. 3. Clean up the text, ripping off blank paragraphs, double spaces, changing quotes etc. 4. Apply the choosen styles. 5. Find and apply style to short paragraphs without dot as sub-headers. NEED: Tcl/Tk 8.5 (or 8.4 with Tile 8.2) Python 2.7 (or 2.5.4 with pyttk) ''' ############################ # Locales to be translated # and user variables subHeaderThreshold = 30 # max chars to a paragraph be styled as subHeader defaultNumCols = '2' # Default style names - change to match your style sheet # Style names - change to match your style sheet paragraph1style = 'Standing head 1' paragraph2style = 'Headline 1' paragraph3style = 'Deck 1' paragraph4style = 'Byline' paragraph5style = 'Sub byline' paragraph6style = 'First paragraph 1' paragraph7style = 'Default Paragraph Style' paragraphLaststyle = 'Default Paragraph Style' defaultParagraphStyle = 'Default Paragraph Style' subHeaderStyle = 'Subhead' ############################### # Bullet special formats # Put your favorite bullet to lists. # Some OS have different character codes bulletedListStyle = 'Bullet' bulletSize = 0 # In points. Zero means same size as text. # Some common dingbat fonts: # 'ITC Zapf Dingbats Regular' # 'Dingbats Regular' # 'Wingdings Regular' if os.name == 'posix': bullet = u'\u25cf' bulletFont = 'Dingbats Regular' else: bullet = u'\u25cf' bulletFont = 'Times New Roman Regular' ############################### # Standing head special formats standingHeadStyle = 'Standing head ' headBulletSize = 0 if os.name == 'posix': headBullet = u'\u25ba' headBulletFont = 'Dingbats Regular' else: headBullet = u'\u25ba' headBulletFont = 'Times New Roman Regular' ########################### # Bullet to mark story end. endBulletSize = 0 if os.name == 'posix': endBullet = u'\u25a0' endBulletFont = 'Dingbats Regular' else: endBullet = u'\u25a0' endBulletFont = 'Times New Roman Regular' ######################################################### # Put in this list the paragraphs styles to be hyphenated ######################################################### hyphenate = [ paragraph6style, bodyTextStyle, paragraphLastStyle, bulletedListStyle ] ########################################################## # Put in this dictionary the styles with special formating # and the functions that does it (without "()"). # Use it to put bullets in front or at end of a paragraph, # format first words as bold etc. ########################################################## specialParagraphs = { paragraph1style: 'formatBulletedList' #,paragraph4style: 'formatBulletedList' #,paragraphLastStyle: 'formatLastParagraph' } # Strings to ask to open a doc openDocLabel= "Open a document" askOpenDoc = "<h2>"+openDocLabel+"</h2>" \ + "<p>Please, open a document and select some text frame before run this script</p>" # Strings to ask to select frame storyFrameLabel = "Select a frame" askOpenFrame = "<h2>"+storyFrameLabel+"</h2>\n" \ + "Draw or select <b>a text frame</b>\nwhere you want to put a story." # GUI strings guiWindow = "Build story" guiHeader = "Newspaper Story builder" guiAction = "Action" guiJustApplyStyles = "Just apply styles" guiRebuildFrames = "Rebuild frame too" guiParagr = "Apply" guiStyle = "Style" guiLines = "Lines" guiBody = 'Body ¶' guiLastPara = "Last ¶" guiColumns = "Columns" guiNumCols = "How many?" guiGutter = "Gutters" guiContent = "Content" guiUseCurrent = "Use current" guiGetFromClipboard = "Get from clipboard" guiImportFromFile = "Import from file" guiOptions = "Options" guiDrawGuideLines = "Draw guide lines" guiSnapToBaselineGrid = "Snap to baseline grid" guiOK = "OK" guiCancel = "Cancel" # END locale strings paraLines = (1, 2, 3, 4, 5, 6) numColumnsList = (1, 2, 3, 4, 5, 6, 7, 8 , 9, 10, 11, 12) ################################ # Debugging functions ################################ import inspect debuggingOn = 0 def whoami(): return inspect.stack()[2][3] def whosdaddy(): return inspect.stack()[3][3] def debug(): if debuggingOn: here = "I'm %s, son of %s" % (whoami(), whosdaddy()) scribus.statusMessage(here) print here ################################ # IMPORTS import sys import re try: import scribus except ImportError,err: print "This Python script is written for the Scribus scripting interface." print "It can only be run from within Scribus." sys.exit(1) # py2 = py30 = py31 = False version = sys.hexversion if version >= 0x020504F0 and version < 0x03000000 : py2 = True # Python 2.5.4 or 2.6 or 2.7 from Tkinter import * import ttk elif version >= 0x03000000 and version < 0x03010000 : py30 = True from tkinter import * import ttk elif version >= 0x03010000: py31 = True from tkinter import * import tkinter.ttk as ttk else: print (""" You do not have a version of python supporting ttk widgets.. You need a version >= 2.6 to execute PAGE modules or a version 2.5 patched with pyttk and Tcl with Tile. """) sys.exit() # from scribus import UNIT_POINTS, UNIT_MILLIMETERS, UNIT_CM, UNIT_INCHES, UNIT_PICAS, UNIT_CICERO, LINE_SOLID, JOIN_MITTER, BUTTON_OK, BUTTON_CANCEL, BUTTON_ABORT, BUTTON_NO, BUTTON_YES, ICON_WARNING, ICON_INFORMATION, pt, mm, p, cm, c # Constants inch = 0.0138888888889 # mistakenly translated to 'pol', in portuguese localization AROUND_FRAME = 1 APPEND = -1 # -1 append text to frame # Measure convertion dictionaries unitDict = { UNIT_POINTS:pt, UNIT_MILLIMETERS:mm, UNIT_INCHES:inch, UNIT_PICAS:(pt/12), # Fix bug in Scribus UNIT_CM:cm, UNIT_CICERO:c } unitStrDict = { UNIT_POINTS:'pt', UNIT_MILLIMETERS:'mm', UNIT_INCHES:'in', UNIT_PICAS:'p', UNIT_CM:'cm', UNIT_CICERO:'c' } import xml.parsers.expat ################################################ # Code to handle elements of XML Scribus doc # Convert default points values to current units ################################################ # Dictionaries to hold style sheets styles = {} charstyles = {} document = {} pages = {} def start_element(name, attrs): '''Build dictonaries from SLA doc file.''' # print 'Start element:', name, attrs #debug global styles, charstyles, document, pages if name == 'DOCUMENT': document = attrs if name == 'STYLE': #print '=====\n',name,attrs,attrs[u'NAME'] # A bug in style editor: # sometimes create a anomale style definition <STYLE LANGUAGE="Portuguese"/> # So we need to catch errors and ignore it try: styles[attrs[u'NAME']] = attrs except: pass if name == 'CHARSTYLE': try: charstyles[attrs[u'CNAME']] = attrs except: pass if name == 'PAGE': try: pages[attrs[u'NUM']] = attrs except: pass def getParagraphStyle(styleName): '''Return a dictionary with paragraph style parameters. If style don't exist, create it with default paragraph parameters.''' try: res = styles[styleName] except: print styleName,'not in style sheet. Creating it.' scribus.createParagraphStyle(styleName) styles[styleName] = styles[defaultParagraphStyle] res = styles[defaultParagraphStyle] return res def getParagraphAttribute(styleName,attrName): '''Return value of given attribute of given style ***in current mesurement units.*** ''' res = 0 # Find parameter in parent style, if not in current style, up to 10 levels. for n in range(10): dic = getParagraphStyle(styleName) if attrName in dic: res = dic[attrName] # Convert points to current units unit = scribus.getUnit() res = float(res)*unitDict[unit] print "Find",attrName,"=",res,'in',styleName,"." break else: print "\nI don't find",attrName,"in",styleName,"." if 'PARENT' in dic: styleName = dic['PARENT'] print "I will search in his father,",styleName,"." else: print "I don't find any value. Setting to zero..." break else: res = 0 return res def getStyleLineSpacing(styleName): '''Return line spacing of given style.''' # Need test line spacing mode # If line space mode is automatic, # line space is equal font size times line space percent res = float(getParagraphAttribute(styleName,'LINESP')) return res def getStyleLineSpaceMode(styleName): '''0=fixed, 1=proportional.''' res = int(getParagraphAttribute(styleName,'LINESPMode')) return res def getStyleSpaceAbove(styleName): '''Return space above of given paragraph style.''' res = float(getParagraphAttribute(styleName,'VOR')) return res def getStyleSpaceBelow(styleName): '''Return space below of given paragraph style.''' res = float(getParagraphAttribute(styleName,'NACH')) return res def getBaselineGrid(): '''Get document baseline grid.''' global document if document == {}: res = 0 else: res = float(document['BASEGRID']) unit = scribus.getUnit() res = res*unitDict[unit] return res def getBaselineOffset(): '''Get document baseline offset.''' global document if document == {}: res = 0 else: res = float(document['BASEO']) unit = scribus.getUnit() res = res*unitDict[unit] return res def getAutoLineSpace(): '''Get automatic line space percentage of current document.''' global document if document == {}: res = 0 else: res = float(document['AUTOL']) unit = scribus.getUnit() res = res*unitDict[unit] return res def getPageAttributes(page): page = page - 1 try: res = pages[str(unicode(page))] except: print 'Page',page,'not in document.' res = {} return res def getVAutoGap(): page = scribus.currentPage() pdic = getPageAttributes(page) if pdic == {}: res = 0 else: try: res = float(pdic['AGverticalAutoGap']) unit = scribus.getUnit() res = res*unitDict[unit] except: print 'AGverticalAutoGap','not in page',page return res def parseDoc(): ''' Get attributes from current Scribus doc.''' debug() global styleList parser = xml.parsers.expat.ParserCreate('UTF-8') parser.StartElementHandler = start_element try: docName = scribus.saveDoc() # Undocumented Scribus 1.3.9 function: docName = unicode(scribus.getDocName()) file = open(docName,'r') parser.ParseFile(file) file.close() except: print "Error analising doc." earlyExit() styleList = scribus.getAllStyles() styleList.sort() ################## # GUI code ################## def set_Tk_var(): # These are Tk variables used passed to Tkinter and must be # defined before the widgets using them are created. # Paragraph 1 global action action = StringVar() action.set("0") # Paragraph 1 global chk1 chk1 = StringVar() chk1.set('0') global chk1label chk1label = StringVar() chk1label.set('') global para1style para1style = StringVar() para1style.set(paragraph1style) global para1lin para1lin = StringVar() para1lin.set('1') # Paragraph 2 global chk2 chk2 = StringVar() chk2.set('1') global chk2label chk2label = StringVar() chk2label.set('\Uffffffff 1') global para2style para2style = StringVar() para2style.set(paragraph2style) global para2lin para2lin = StringVar() para2lin.set('1') # Paragraph 3 global chk3 chk3 = StringVar() chk3.set('1') global chk3label chk3label = StringVar() chk3label.set('\Uffffffff 2') global para3style para3style = StringVar() para3style.set(paragraph3style) global para3lin para3lin = StringVar() para3lin.set('1') # Paragraph 4 global chk4 chk4 = StringVar() chk4.set('1') global chk4label chk4label = StringVar() chk4label.set('\Uffffffff 3') global para4style para4style = StringVar() para4style.set(paragraph4style) # Paragraph 5 global chk5 chk5 = StringVar() chk5.set('1') global chk5label chk5label = StringVar() chk5label.set('\Uffffffff 4') global para5style para5style = StringVar() para5style.set(paragraph5style) # Paragraph 6 global chk6 chk6 = StringVar() chk6.set('1') global chk6label chk6label = StringVar() chk6label.set('\Uffffffff 5') global para6style para6style = StringVar() para6style.set(paragraph6style) # Paragraph 7 global chk7 chk7 = StringVar() chk7.set('1') global chk7label chk7label = StringVar() chk7label.set(guiBody) global para7style para7style = StringVar() para7style.set(bodyTextStyle) # Paragraph Last global chkLast chkLast = StringVar() chkLast.set('1') global paraLastStyle paraLastStyle = StringVar() paraLastStyle.set(paragraphLastStyle) global chkEndBull chkEndBull = StringVar() chkEndBull.set('1') # Columns global numCols numCols = StringVar() numCols.set(defaultNumCols) # Columns & Gaps global gutter, unitString gutter = StringVar() gap = getVAutoGap() unit = scribus.getUnit() unitString = unitStrDict[unit] gutter.set(gap) # Content global contentSource contentSource = StringVar() contentSource.set('0') # Guides global isToDrawGuides isToDrawGuides = StringVar() isToDrawGuides.set('0') # Snap to baseline guides global snap snap = StringVar() snap.set('0') class Build_Story_dialog: def __init__(self, master=None): # Set background of toplevel window to match # current style style = ttk.Style() theme = style.theme_use() default = style.lookup(theme, 'background') master.configure(background=default) # Head label self.tLa33 = ttk.Label (master) self.tLa33.place(relx=0.02,rely=0.03) self.tLa33.configure(font="font12") self.tLa33.configure(text=guiHeader) # Actions frame self.tLa47 = ttk.Labelframe (master) self.tLa47.place(relx=0.02,rely=0.11,relheight=0.15,relwidth=0.57) self.tLa47.configure(text=guiAction,width="295",height="55") # Action radiobuttons self.tLa47_tRa48 = ttk.Radiobutton (self.tLa47) self.tLa47_tRa48.place(relx=0.03,rely=0.12,relheight=0.7,relwidth=0.45) self.tLa47_tRa48.configure(text=guiJustApplyStyles,variable=action,value="0") self.tLa47_tRa49 = ttk.Radiobutton (self.tLa47) self.tLa47_tRa49.place(relx=0.49,rely=0.12,relheight=0.7,relwidth=0.5) self.tLa47_tRa49.configure(text=guiRebuildFrames,variable=action,value="1") # Styles labels self.tLa34 = ttk.Label (master) self.tLa34.place(relx=0.02,rely=0.28) self.tLa34.configure(text=guiParagr) self.tLa35 = ttk.Label (master) self.tLa35.place(relx=0.16,rely=0.28) self.tLa35.configure(text=guiStyle) self.tLa36 = ttk.Label (master) self.tLa36.place(relx=0.48,rely=0.28) self.tLa36.configure(text=guiLines) # Para #1 self.tCh37 = ttk.Checkbutton (master) self.tCh37.place(relx=0.02,rely=0.34) self.tCh37.configure(textvariable=chk1label,variable=chk1) self.tCo38 = ttk.Combobox (master) self.tCo38.place(relx=0.16,rely=0.34,relwidth=0.32) self.tCo38.configure(textvariable=para1style,values=styleList) self.tCo39 = ttk.Combobox (master) self.tCo39.place(relx=0.48,rely=0.34,relwidth=0.11) self.tCo39.configure(textvariable=para1lin,values=paraLines,justify="center") self.tCo38.configure(state="disabled") self.tCo39.configure(state="disabled") # Para #2 self.tCh40 = ttk.Checkbutton (master) self.tCh40.place(relx=0.02,rely=0.42) self.tCh40.configure(textvariable=chk2label,variable=chk2) self.tCo41 = ttk.Combobox (master) self.tCo41.place(relx=0.16,rely=0.42,relwidth=0.32) self.tCo41.configure(textvariable=para2style,values=styleList) self.tCo42 = ttk.Combobox (master) self.tCo42.place(relx=0.48,rely=0.42,relwidth=0.11) self.tCo42.configure(textvariable=para2lin,values=paraLines,justify="center") self.tCo42.configure(state="disabled") # Para #3 self.tCh43 = ttk.Checkbutton (master) self.tCh43.place(relx=0.02,rely=0.5) self.tCh43.configure(textvariable=chk3label,variable=chk3) self.tCo44 = ttk.Combobox (master) self.tCo44.place(relx=0.16,rely=0.5,relwidth=0.32) self.tCo44.configure(textvariable=para3style,values=styleList) self.tCo45 = ttk.Combobox (master) self.tCo45.place(relx=0.48,rely=0.5,relwidth=0.11) self.tCo45.configure(textvariable=para3lin,values=paraLines,justify="center") self.tCo45.configure(state="disabled") # Para #4 self.tCh46 = ttk.Checkbutton (master) self.tCh46.place(relx=0.02,rely=0.58) self.tCh46.configure(textvariable=chk4label,variable=chk4) self.tCo47 = ttk.Combobox (master) self.tCo47.place(relx=0.16,rely=0.58,relwidth=0.32) self.tCo47.configure(textvariable=para4style,values=styleList) # Para #5 self.tCh49 = ttk.Checkbutton (master) self.tCh49.place(relx=0.02,rely=0.66) self.tCh49.configure(textvariable=chk5label,variable=chk5) self.tCo50 = ttk.Combobox (master) self.tCo50.place(relx=0.16,rely=0.66,relwidth=0.32) self.tCo50.configure(textvariable=para5style,values=styleList) # Para #6 self.tCh52 = ttk.Checkbutton (master) self.tCh52.place(relx=0.02,rely=0.74) self.tCh52.configure(textvariable=chk6label,variable=chk6,state="disabled") self.tCo53 = ttk.Combobox (master) self.tCo53.place(relx=0.16,rely=0.74,relwidth=0.32) self.tCo53.configure(textvariable=para6style,values=styleList) # Para #7 self.tCh54 = ttk.Checkbutton (master) self.tCh54.place(relx=0.02,rely=0.82) self.tCh54.configure(textvariable=chk7label,variable=chk7) self.tCo55 = ttk.Combobox (master) self.tCo55.place(relx=0.16,rely=0.82,relwidth=0.32) self.tCo55.configure(textvariable=para7style,values=styleList) # Para #last self.tCh33 = ttk.Checkbutton (master) self.tCh33.place(relx=0.02,rely=0.9) self.tCh33.configure(text=guiLastPara,variable=chkLast) self.tCo34 = ttk.Combobox (master) self.tCo34.place(relx=0.16,rely=0.9,relwidth=0.32) self.tCo34.configure(textvariable=paraLastStyle,values=styleList) self.tCh34b = ttk.Checkbutton (master) self.tCh34b.place(relx=0.49,rely=0.9) self.tCh34b.configure(text="Bullet",variable=chkEndBull) # Content Frame self.tLa38 = ttk.Labelframe (master) self.tLa38.place(relx=0.62,rely=0.11,relheight=0.26,relwidth=0.36) self.tLa38.configure(text=guiContent,width="185",height="95") # Use current label self.tLa38_cpd39 = ttk.Radiobutton (self.tLa38) self.tLa38_cpd39.place(relx=0.05,rely=0.08) self.tLa38_cpd39.configure(text=guiUseCurrent,variable=contentSource,value="0") # Import from file label self.tLa38_cpd41 = ttk.Radiobutton (self.tLa38) self.tLa38_cpd41.place(relx=0.05,rely=0.36) self.tLa38_cpd41.configure(text=guiImportFromFile,variable=contentSource,value="2") #self.tLa38_cpd41.configure(state="disabled") # Get from clipboard label self.tLa38_cpd40 = ttk.Radiobutton (self.tLa38) self.tLa38_cpd40.place(relx=0.05,rely=0.63) self.tLa38_cpd40.configure(text=guiGetFromClipboard,variable=contentSource,value="1") self.tLa38_cpd40.configure(state="disabled") # Columns frame self.tLa32 = ttk.Labelframe (master) self.tLa32.place(relx=0.62,rely=0.37,relheight=0.21,relwidth=0.36) self.tLa32.configure(text=guiColumns,width="185",height="70") # How many label self.tLa32_cpd33 = ttk.Label (self.tLa32) self.tLa32_cpd33.place(relx=0.05,rely=0.07) self.tLa32_cpd33.configure(text=guiNumCols) self.tLa32_cpd33.configure(state="disabled") # How many combo self.tLa32_cpd34 = ttk.Combobox (self.tLa32) self.tLa32_cpd34.place(relx=0.05,rely=0.4,relwidth=0.36) self.tLa32_cpd34.configure(justify="center",textvariable=numCols,values=numColumnsList) self.tLa32_cpd34.configure(state="disabled") self.tLa32_cpd34.configure(validate="all",validatecommand="self.validateColumns") # Gutter label self.tLa32_cpd35 = ttk.Label (self.tLa32) self.tLa32_cpd35.place(relx=0.5,rely=0.07) self.tLa32_cpd35.configure(justify="center",text=guiGutter) self.tLa32_cpd35.configure(state="disabled") # Gutter combo self.tLa32_cpd36 = ttk.Combobox (self.tLa32) self.tLa32_cpd36.place(relx=0.5,rely=0.4,relwidth=0.33) self.tLa32_cpd36.configure(justify="center",values=numColumnsList,textvariable=gutter) self.tLa32_cpd36.configure(state="disabled") # measure self.tLa32_cpd37 = ttk.Label (self.tLa32) self.tLa32_cpd37.place(relx=0.84,rely=0.5) self.tLa32_cpd37.configure(text=unitString) self.tLa32_cpd37.configure(state="disabled") # Options frame self.tLa42 = ttk.Labelframe (master) self.tLa42.place(relx=0.62,rely=0.58,relheight=0.23,relwidth=0.36) self.tLa42.configure(text=guiOptions,width="185",height="80") # Draw guides check self.tLa42_cpd44 = ttk.Checkbutton (self.tLa42) self.tLa42_cpd44.place(relx=0.05,rely=0.08) self.tLa42_cpd44.configure(text=guiDrawGuideLines,variable=isToDrawGuides) self.tLa42_cpd44.configure(state="disabled") # Snap guides check self.tLa42_cpd46 = ttk.Checkbutton (self.tLa42) self.tLa42_cpd46.place(relx=0.05,rely=0.5) self.tLa42_cpd46.configure(text=guiSnapToBaselineGrid,variable=snap) self.tLa42_cpd46.configure(state="disabled") # Button OK self.tBu67 = ttk.Button (master) self.tBu67.place(relx=0.81,rely=0.89) self.tBu67.configure(text=guiOK,command=ok) # Button Cancel self.tBu68 = ttk.Button (master) self.tBu68.place(relx=0.62,rely=0.89) self.tBu68.configure(text=guiCancel,command=quit) # Bind mouse button release to Rebuild check mark self.tLa47_tRa48.bind("<ButtonRelease-1>", self.__handleRebuild) self.tLa47_tRa49.bind("<ButtonRelease-1>", self.__handleRebuild) self.tCh37.bind("<ButtonRelease-1>", self.__handlePara1) self.tCh40.bind("<ButtonRelease-1>", self.__handlePara2) self.tCh43.bind("<ButtonRelease-1>", self.__handlePara3) self.tCh46.bind("<ButtonRelease-1>", self.__handlePara4) self.tCh49.bind("<ButtonRelease-1>", self.__handlePara5) #self.tCh52.bind("<ButtonRelease-1>", self.__handlePara6) self.tCh54.bind("<ButtonRelease-1>", self.__handlePara7) self.tCh33.bind("<ButtonRelease-1>", self.__handlePara8) def validateColumns(): pass def __handleRebuild(self,event): w = event.widget if w.cget('value') == '0': self.tLa32_cpd34.configure(state="disabled") # num cols combo self.tLa32_cpd36.configure(state="disabled") # gutter combo self.tLa42_cpd46.configure(state="disabled") # snap check self.tLa42_cpd44.configure(state="disabled") # guides check self.tLa32_cpd33.configure(state="disabled") # Labels self.tLa32_cpd35.configure(state="disabled") self.tLa32_cpd37.configure(state="disabled") self.tCo39.configure(state="disabled") self.tCo42.configure(state="disabled") self.tCo45.configure(state="disabled") else: self.tLa32_cpd34.configure(state="enabled") self.tLa32_cpd36.configure(state="enabled") self.tLa42_cpd46.configure(state="enabled") self.tLa42_cpd44.configure(state="enabled") self.tLa32_cpd33.configure(state="enabled") self.tLa32_cpd35.configure(state="enabled") self.tLa32_cpd37.configure(state="enabled") if int(chk1.get()): self.tCo39.configure(state="enabled") if int(chk2.get()): self.tCo42.configure(state="enabled") if int(chk3.get()): self.tCo45.configure(state="enabled") def __renumberPara(self,event): '''Come to here with variable no set yet''' #w = event.widget #print w.keys() # ['takefocus', 'variable', 'onvalue', 'offvalue', 'command', 'text', 'textvariable', 'underline', 'width', 'image', 'compound', 'padding', 'state', 'takefocus', 'cursor', 'style', 'class'] num = 0 if chk1.get() == '1': num += 1 chk1label.set('\Uffffffff '+str(num)) else: chk1label.set('') if chk2.get() == '1': num += 1 chk2label.set('\Uffffffff '+str(num)) else: chk2label.set('') if chk3.get() == '1': num += 1 chk3label.set('\Uffffffff '+str(num)) else: chk3label.set('') if chk4.get() == '1': num += 1 chk4label.set('\Uffffffff '+str(num)) else: chk4label.set('') if chk5.get() == '1': num += 1 chk5label.set('\Uffffffff '+str(num)) else: chk5label.set('') if chk6.get(): num += 1 chk6label.set('\Uffffffff '+str(num)) else: chk6label.set('') def __handlePara1(self,event): if chk1.get() == '0': self.tCo38.configure(state="enabled") if action.get() == '1': self.tCo39.configure(state="enabled") chk1.set('1') self.__renumberPara(event) chk1.set('0') else: self.tCo38.configure(state="disabled") self.tCo39.configure(state="disabled") chk1.set('0') self.__renumberPara(event) chk1.set('1') def __handlePara2(self,event): if chk2.get() == '0': self.tCo41.configure(state="enabled") if action.get() == '1': self.tCo42.configure(state="enabled") chk2.set('1') self.__renumberPara(event) chk2.set('0') else: self.tCo41.configure(state="disabled") self.tCo42.configure(state="disabled") chk2.set('0') self.__renumberPara(event) chk2.set('1') def __handlePara3(self,event): if chk3.get() == '0': self.tCo44.configure(state="enabled") if action.get() == '1': self.tCo45.configure(state="enabled") chk3.set('1') self.__renumberPara(event) chk3.set('0') else: self.tCo44.configure(state="disabled") self.tCo45.configure(state="disabled") chk3.set('0') self.__renumberPara(event) chk3.set('1') def __handlePara4(self,event): if chk4.get() == '0': self.tCo47.configure(state="enabled") chk4.set('1') self.__renumberPara(event) chk4.set('0') else: self.tCo47.configure(state="disabled") chk4.set('0') self.__renumberPara(event) chk4.set('1') def __handlePara5(self,event): if chk5.get() == '0': self.tCo50.configure(state="enabled") chk5.set('1') self.__renumberPara(event) chk5.set('0') else: self.tCo50.configure(state="disabled") chk5.set('0') self.__renumberPara(event) chk5.set('1') def __handlePara6(self,event): if chk6.get() == '0': self.tCo53.configure(state="enabled") chk6.set('1') self.__renumberPara(event) chk6.set('0') else: self.tCo53.configure(state="disabled") chk6.set('0') self.__renumberPara(event) chk6.set('1') def __handlePara7(self,event): if chk7.get() == '0': self.tCo55.configure(state="enabled") else: chk7.set('0') self.__renumberPara(event) chk7.set('1') self.tCo55.configure(state="disabled") def __handlePara8(self,event): if chkLast.get() == '0': self.tCo34.configure(state="enabled") else: self.tCo34.configure(state="disabled") def init(): pass ##################### # Clean text def normalizeText(t): '''Rip off blank paragraphs, double spaces, html tags, quotes etc.''' debug() t = t.strip() while t.count('\t'): t = t.replace('\t','') while t.count(' '): t = t.replace(' ',' ') while t.count('<br>'): t = t.replace('<br>','\n') while t.count('\r'): # DOS/Windows paragraph end. t = t.replace('\r','\n') # Change by new line while t.count(' \n'): t = t.replace(' \n','\n') while t.count('\n '): t = t.replace('\n ','\n') while t.count('\n\n'): t = t.replace('\n\n','\n') # Create m-dash while t.count('\n-'): t = t.replace('\n-','\n') # Change computer quotes by typographic quotes while t.count('\n"'): t = t.replace('\n"','\n') while t.count(' "'): t = t.replace(' "',' ') while t.count('" '): t = t.replace('" ',' ') while t.count('",'): t = t.replace('",',',') while t.count('".'): t = t.replace('".','.') while t.count('."'): t = t.replace('."','.') while t.count('.'): t = t.replace('.','.') return t ####################### # Format bulleted lists def formatBulletedList(textBegin,text,style,story): '''Insert bullet at first paragraph.''' debug() # Clear old marks reBullet = r'['+bullet+'|(^\*)]' s = re.sub(reBullet,'',text) s = s.strip(" ") paraLen = len(s) scribus.insertText(s, APPEND, story) try: scribus.selectText(textBegin, paraLen-1, story) applyStyle(style, story) except: print "Can't select and apply style",style # Hyphenate if style is in hyphenation list if hyphenate.count(style) != 0: scribus.hyphenateText() # Insert bullet b = bullet+u'\t' scribus.insertText(b, textBegin, story) scribus.selectText(textBegin,1,story) if bulletFont: try: scribus.setFont(bulletFont,story) except: print "Can't find font:",bulletFont if bulletSize: try: scribus.selectText(textBegin,1,story) scribus.setFontSize(bulletSize,story) except: print "Can't size bullet." return paraLen+len(b) # Tie above function to style name specialParagraphs[bulletedListStyle] = 'formatBulletedList' ####################### # Format Standing Head def formatStandingHead(textBegin,text,style,story): '''Insert bullet in standing head.''' # Clear old marks debug() reBullet = r''+headBullet s = re.sub(reBullet,'',text) s = s.strip(" ") paraLen = len(s) scribus.insertText(s, APPEND, story) try: scribus.selectText(textBegin, paraLen-1, story) applyStyle(style, story) except: print "Can't select and apply style",style # Hyphenate if style is in hyphenation list if hyphenate.count(style) != 0: scribus.hyphenateText() # Insert bullet b = headBullet+u'\t' scribus.insertText(b, textBegin, story) scribus.selectText(textBegin,1,story) if headBulletFont: try: scribus.setFont(headBulletFont,story) except: print "Can't find font:",headBulletFont if headBulletSize: try: scribus.selectText(textBegin,1,story) scribus.setFontSize(headBulletSize,story) except: print "Can't size bullet." return paraLen+len(b) # Tie above function to style name specialParagraphs[standingHeadStyle] = 'formatStandingHead' ###################### # formatLastParagraph. # exec by formatText ###################### def formatLastParagraph(textBegin,text,style,story): '''Do especial formating in last paragraph, as put a bullet at end of paragraph.''' # Clear old marks debug() reEndBullet = r''+endBullet s = re.sub(reEndBullet,'',text) s = s.strip(" ") paraLen = len(s) endPara = textBegin+paraLen scribus.insertText(s, APPEND, story) scribus.selectText(textBegin, paraLen-1, story) applyStyle(style, story) # Hyphenate if style is in hyphenation list if hyphenate.count(style) != 0: scribus.hyphenateText() # If terminate with bullet if (chkEndBull.get() == '1'): # Format end bullet eb = ' '+endBullet scribus.insertText(eb, APPEND, story) if endBulletFont: scribus.selectText(endPara+1,1,story) try: scribus.setFont(endBulletFont,story) except: print "Can't find font:",endBulletFont if endBulletSize: scribus.selectText(endPara+1,1,story) try: scribus.setFontSize(endBulletSize,story) except: print "Can't size end bullet." return paraLen ################### # Insert text and # format paragraph def formatParagraph(textBegin,text,style,story): '''Insert text and format paragraph.''' debug() paraLen = len(text) scribus.insertText(text, APPEND, story) scribus.selectText(textBegin, paraLen-1, story) applyStyle(style, story) # Hyphenate if style is in hyphenation list if hyphenate.count(style) != 0: scribus.hyphenateText() return paraLen ################### def applyStyle(style,story): '''Try apply style to selected text. If style doesn't exist, create it.''' debug() try: scribus.setStyle(style, story) except: scribus.createParagraphStyle(style) scribus.setStyle(style, story) return story #################### def formatText(story): '''Format story with styles pre-header, header, sub-header etc.''' # To do: translate italics, bolds, superscripts etc here debug() paraStyles = [] # Build a list of choosen styles if chk1.get() == '1': paraStyles.append(para1style.get()) if chk2.get() == '1': paraStyles.append(para2style.get()) if chk3.get() == '1': paraStyles.append(para3style.get()) if chk4.get() == '1': paraStyles.append(para4style.get()) if chk5.get() == '1': paraStyles.append(para5style.get()) if chk6.get() == '1': # let ever on paraStyles.append(para6style.get()) #################################### # Format headers and first paragraph scribus.deselectAll() scribus.selectObject(story) alltext = scribus.getAllText(story) # Do nothing if no text if len(alltext) == 0: return alltext = normalizeText(alltext) # Convert text to unicode alltext = unicode(alltext) scribus.deleteText(story) # lines = alltext.splitlines(1) # splitlines can't be used because catch line break '\x1C' as paragraph end lines = alltext.split('\n') # avoid separete paragraphs with line breaks (\x1C') # print repr(lines) # debug textBegin = 0 global paraLen # to permit exec string formatSpecial paraLen = 0 scribus.deselectAll() ################################### # For each choosen header paragraph ################################### for j in range(len(paraStyles)): try: paraLen = len(lines[j])+1 # add new-line to counter except IndexError,err: print "No more text in frame." return ###################################### # If paragraph needs special handling, # execute the function to do that. ###################################### if paraStyles[j] in specialParagraphs: # Ugly, I know. But I'm former Mumps programmer and I like xecute formatSpecial = 'global paraLen \nparaLen = '+specialParagraphs[paraStyles[j]]+ \ '(textBegin,lines[j]+"\\n",paraStyles[j],story)' # scribus.messageBox("Debug",formatSpecial,ICON_WARNING,BUTTON_OK) exec formatSpecial ############################################ # If paragraph don't needs special handling, # insert and format. ############################################ else: paraLen = formatParagraph(textBegin,lines[j]+'\n',paraStyles[j],story) textBegin += paraLen # if not desselect all, strange select errors happens scribus.deselectAll() ######################################## # Continue formating text after headers: # format body text and last paragraph. ######################################## bodySty = para7style.get() ########################## # For each body paragraph: ########################## for n in range((j+1),len(lines)): paraLen = len(lines[n])+1 # add 'new-line' to counter ########################### # Format bulleted lists # (lines begining with '* ' # or with bullet char) ########################### if (lines[n][0:2] == '* ') or (lines[n][0:1] == bullet): paraLen = formatBulletedList(textBegin,lines[n]+'\n',bulletedListStyle,story) ############################### # If is short paragraph without # dots, format as 'Subheader'. ############################### elif ((paraLen < subHeaderThreshold) and (lines[n].find('.')) == -1): paraLen = formatParagraph(textBegin,lines[n]+'\n',subHeaderStyle,story) ######################### # If is normal paragraph: ######################### else: ####################### # If is last paragraph: ####################### if (n == (len(lines) - 1)) and (chkLast.get() =='1'): ###################################### # If paragraph needs special handling, # execute the function to do that. ###################################### lastPara = paraLastStyle.get() if lastPara in specialParagraphs: formatSpecial = 'global paraLen\nparaLen = '+specialParagraphs[lastPara]+ \ '(textBegin,lines[n],lastPara,story)' exec formatSpecial # function need handle end bullets ################################################# # If last paragraph don't needs special handling, # just insert and format. ################################################# else: paraLen = formatLastParagraph(textBegin,lines[n],lastPara,story) ############################################# # If is not last paragraph, apply body style: ############################################# else: # If style needs special handling if bodySty in specialParagraphs: formatSpecial = 'global paraLen\nparaLen = '+specialParagraphs[bodySty]+ \ '(textBegin,lines[n]+"\\n",bodySty,story)' exec formatSpecial # If style don't needs special handling, insert and format. else: paraLen = formatParagraph(textBegin,lines[n]+'\n',bodySty,story) textBegin += paraLen scribus.deselectAll() ################### def adjustHeaderHeight(storyTop,headerBottom): '''Rules for header End adjustments. Some headers + lines combinations results in bad height if body text is align to baseline. Put here the rules that fix this. Rules depends on your particular stylesheet.''' debug() hasHeader1 = int(chk1.get()) hasHeader2 = int(chk2.get()) hasHeader3 = int(chk3.get()) lines1 = int(para1lin.get()) lines2 = int(para2lin.get()) lines3 = int(para3lin.get()) lineSpace1 = getStyleLineSpacing(para1style.get()) lineSpace2 = getStyleLineSpacing(para2style.get()) lineSpace3 = getStyleLineSpacing(para3style.get()) grid = getBaselineGrid() headerHeight = headerBottom - storyTop unit = scribus.getUnit() threshold = grid*3*unitDict[unit] headerHeight = max(headerHeight,threshold) headerBottom = storyTop + headerHeight columnsTop = headerBottom print 'threshold:',threshold,'headerHeight:',headerHeight if hasHeader1: pass if hasHeader2: if lines2 == 1: print 'lineSpace2:',lineSpace2 if hasHeader3: if (lineSpace2 < (52*unitDict[unit])) or (lineSpace2 > (41*unitDict[unit])): columnsTop -= grid return headerBottom,columnsTop if not hasHeader3: if (lineSpace2 < (41*unitDict[unit])) or (lineSpace2 > (32*unitDict[unit])): columnsTop -= grid return headerBottom,columnsTop if lines2 == 2: if not hasHeader3: if (lineSpace2 < (37*unitDict[unit])) or (lineSpace2 > (30*unitDict[unit])): columnsTop -= grid return headerBottom,columnsTop if lines2 == 3: if (lineSpace2 < (52*unitDict[unit])) or (lineSpace2 > (41*unitDict[unit])): columnsTop -= grid return headerBottom,columnsTop if hasHeader3: pass return headerBottom,columnsTop ###################### def getHeaderHeight(): '''Calculate header frame height using style sheet data.''' debug() global chk1, para1style, para1lin global chk2, para2style, para2lin global chk3, para3style, para3lin height = 0 # Pre-header hasHeader1 = int(chk1.get()) if hasHeader1: style = para1style.get() lineSpace = getStyleLineSpacing(style) lines = int(para1lin.get()) lineSpace *= lines spMode= getStyleLineSpaceMode(style) if spMode == 1: lineSpace *= ( 1 + ( getAutoLineSpace()/100 ) ) lineSpace += getStyleSpaceAbove(style) + getStyleSpaceBelow(style) height = lineSpace # Header hasHeader2 = int(chk2.get()) if hasHeader2: style = para2style.get() lineSpace = getStyleLineSpacing(style) lines = int(para2lin.get()) lineSpace *= lines spMode= getStyleLineSpaceMode(style) if spMode == 1: lineSpace *= ( 1 + ( getAutoLineSpace()/100 ) ) lineSpace += getStyleSpaceAbove(style) + getStyleSpaceBelow(style) height += lineSpace # Post-header hasHeader3 = int(chk3.get()) if hasHeader3: style = para3style.get() lineSpace = getStyleLineSpacing(style) lines = int(para3lin.get()) lineSpace *= lines spMode= getStyleLineSpaceMode(style) if spMode == 1: lineSpace *= ( 1 + ( getAutoLineSpace()/100 ) ) lineSpace += getStyleSpaceAbove(style) + getStyleSpaceBelow(style) height += lineSpace return height ############################# def roundToNearBaseline(num): '''Round vertical dimensions to near baseline grid.''' debug() offset = getBaselineOffset() grid = getBaselineGrid() n = num - offset times,mod = divmod(n,grid) if (mod < (grid / 2)): res = offset + (times * grid) else: res = offset + (times * grid) + grid return res def roundToNextBaseline(num): '''Round vertical dimensions to next baseline grid.''' debug() offset = getBaselineOffset() grid = getBaselineGrid() n = num - offset times,mod = divmod(n,grid) res = offset + (times * grid) if res != num: res += grid return res ###################### def buildStory(story): '''Build headline and body text frames.''' debug() # get selected object dimensions global storyLeft, storyTop, storyWidth, storyHeight, numCols, gutter global columnsFrame, headerHeight, columnsTop # Get frame dimensions storyLeft, storyTop = scribus.getPosition(story) storyWidth, storyHeight = scribus.getSize(story) # BUILD HEADLINES FRAME headerHeight = getHeaderHeight() headerBottom = storyTop + headerHeight # Round header height to baseline grid if snap.get() == '1': grid = getBaselineGrid() storyTop = roundToNearBaseline(storyTop) headerBottom = roundToNextBaseline(headerBottom) # Adjust some bad headerBottom headerBottom,columnsTop = adjustHeaderHeight(storyTop,headerBottom) #columnsTop = headerBottom else: columnsTop = headerBottom headerHeight = headerBottom - storyTop # Resize header frame scribus.moveObjectAbs(storyLeft, storyTop ,story) scribus.sizeObject(storyWidth, headerHeight, story) scribus.textFlowMode(story, 0) # # Set just one column for header scribus.setColumns(1, story) # BUILD BODY TEXT FRAME columnsBottom = storyHeight + storyTop if snap.get() == '1': columnsBottom = roundToNextBaseline(columnsBottom) gap = float(gutter.get()) columnsHeight = columnsBottom - columnsTop columnsFrame = scribus.createText(storyLeft, columnsTop, storyWidth, columnsHeight) scribus.textFlowMode(columnsFrame, 0) columnNumbers = int(numCols.get()) scribus.setColumnGap(gap, columnsFrame) scribus.setColumns(columnNumbers, columnsFrame) # Draw guides if isToDrawGuides.get() == '1': # Append guides to existing guides array scribus.setHGuides(scribus.getHGuides() + [storyTop] + [columnsTop] + [columnsBottom]) scribus.setVGuides(scribus.getVGuides() + [storyLeft-gap]) scribus.setVGuides(scribus.getVGuides() + [storyLeft,(storyLeft+storyWidth)]) scribus.setVGuides(scribus.getVGuides() + [(storyLeft+storyWidth+gap)]) columnWidth = (storyWidth - (gap * (columnNumbers - 1))) / columnNumbers nextCol = storyLeft+columnWidth columnGuides = [] for col in range(1,columnNumbers): columnGuides = columnGuides + [nextCol,(nextCol+gap)] nextCol = nextCol + columnWidth + gap scribus.setVGuides(scribus.getVGuides() + columnGuides) # Link header frame to body text frame scribus.linkTextFrames(story,columnsFrame) ################## # Do all the job def ok(): #try: root.destroy() #except: pass story = scribus.getSelectedObject(0) # Build title and text frames, if asked if action.get() == '1': buildStory(story) # Load text, if asked if contentSource.get() == '2': file = scribus.fileDialog("Open", "*.txt") if file != '': try: text = unicode(open(file).read()) except: print 'Error reading file' scribus.setText(text,story) # Apply styles and format text formatText(story) # Finalize scribus.docChanged(True) quit() ########### def quit(): earlyExit() def earlyExit(): if scribus.haveDoc(): scribus.setRedraw(True) scribus.statusMessage("") scribus.progressReset() try: root.destroy() except: pass sys.exit() ###################### def handleSelection(): '''Handle object selection.''' global storyFrame if (scribus.selectionCount() < 1): scribus.messageBox(storyFrameLabel,askOpenFrame,ICON_WARNING,BUTTON_OK) earlyExit() else: pass def vp_start_gui(): global val, w, root root = Tk() # Center the dialog wid, hei = root.winfo_screenwidth(), root.winfo_screenheight() x = (wid - 517) / 2 y = (hei - 363) / 2 geo = '517x363+'+str(x)+'+'+str(y) # root.title(guiWindow) root.geometry(geo) set_Tk_var() w = Build_Story_dialog (root) init() handleSelection() root.mainloop() def main(argv): if scribus.haveDoc(): #scribus.setRedraw(False) unit = scribus.getUnit() parseDoc() vp_start_gui() else: scribus.messageBox(openDocLabel,askOpenDoc,ICON_WARNING,BUTTON_OK) earlyExit() def main_wrapper(argv): """""" try: scribus.statusMessage("Running script...") scribus.progressReset() main(argv) finally: if scribus.haveDoc(): scribus.setRedraw(True) scribus.statusMessage("") scribus.progressReset() if __name__ == '__main__': main_wrapper(sys.argv)