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 2011-01-26 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 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' # 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' ''' # Style names - change to match your style sheet paragraph1style = 'Antetitulo' paragraph2style = 'Titulo 2' paragraph3style = 'Subtitulo 1' paragraph4style = 'Assinatura' paragraph5style = 'Sub byline' paragraph6style = 'Primeiro paragrafo' paragraph7style = 'Default Paragraph Style' paragraphLaststyle = 'Default Paragraph Style' defaultParagraphStyle = 'Default Paragraph Style' subHeaderStyle = 'Entretitulo' ''' # Put in this list the paragraphs to be hyphenated hyphenated = [paragraph6style,paragraph7style] # Put in this dictionary the styles with special formating and the functions that does it specialParagraphs = { paragraph1style: 'putBullet', paragraph4style: 'putBullet' } # 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 = "Selecione um quadro" 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) # IMPORTS import sys 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 portuguese 'pol' AROUND_FRAME = 1 # 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 ################################### # Dictionaries to hold style sheets styles = {} charstyles = {} document = {} pages = {} # Handle elements of XML Scribus doc # Convert default points values to current units 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': styles[attrs[u'NAME']] = attrs if name == 'CHARSTYLE': charstyles[attrs[u'CNAME']] = attrs if name == 'PAGE': pages[attrs[u'NUM']] = attrs 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.***''' dic = getParagraphStyle(styleName) res = 0 # Find parameter in parent style, if not in current style. if attrName in dic: res = dic[attrName] # Convert points to current units unit = scribus.getUnit() res = float(res)*unitDict[unit] return res else: if 'PARENT' in dic: styleName = dic['PARENT'] res = getParagraphAttribute(styleName,attrName) return res else: res = 0 return res def getStyleLineSpacing(styleName): '''Return line spacing of given style.''' 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.''' global styleList parser = xml.parsers.expat.ParserCreate('UTF-8') parser.StartElementHandler = start_element try: docName = scribus.saveDoc() docName = scribus.getDocName() # Undocumented Scribus 1.3.9 function file = open(unicode(docName),'r') parser.ParseFile(file) file.close() except: earlyExit() styleList = scribus.getAllStyles() styleList.sort() 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('¶ 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('¶ 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('¶ 3') global para4style para4style = StringVar() para4style.set(paragraph4style) # Paragraph 5 global chk5 chk5 = StringVar() chk5.set('1') global chk5label chk5label = StringVar() chk5label.set('¶ 4') global para5style para5style = StringVar() para5style.set(paragraph5style) # Paragraph 6 global chk6 chk6 = StringVar() chk6.set('1') global chk6label chk6label = StringVar() chk6label.set('¶ 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(paragraph7style) # Paragraph Last global chkLast chkLast = StringVar() chkLast.set('1') global paraLastStyle paraLastStyle = StringVar() paraLastStyle.set(paragraphLaststyle) # 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('1') # Snap to baseline guides global snap snap = StringVar() snap.set('1') 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.45) 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.14,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.14,rely=0.34,relwidth=0.34) 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.14,rely=0.42,relwidth=0.34) 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.14,rely=0.5,relwidth=0.34) 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.14,rely=0.58,relwidth=0.34) 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.14,rely=0.66,relwidth=0.34) 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) self.tCo53 = ttk.Combobox (master) self.tCo53.place(relx=0.14,rely=0.74,relwidth=0.34) 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.14,rely=0.82,relwidth=0.34) 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.14,rely=0.9,relwidth=0.34) self.tCo34.configure(textvariable=paraLastStyle,values=styleList) # 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") # 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 __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('¶ '+str(num)) else: chk1label.set('') if chk2.get() == '1': num += 1 chk2label.set('¶ '+str(num)) else: chk2label.set('') if chk3.get() == '1': num += 1 chk3label.set('¶ '+str(num)) else: chk3label.set('') if chk4.get() == '1': num += 1 chk4label.set('¶ '+str(num)) else: chk4label.set('') if chk5.get() == '1': num += 1 chk5label.set('¶ '+str(num)) else: chk5label.set('') if chk6.get() == '1': num += 1 chk6label.set('¶ '+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.''' 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'): # Fim de parágrafo tipo DOS e Windows. t = t.replace('\r','\n') # Troca pelo fim-de-parágrafo padrão 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') # Cria travessões 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 #################### # Insert bullets # in some paragraphs def putBullet(line): '''Insert bullet at first paragraph.''' # Remove old bullet # Insert new bullet ################### def applyStyle(style,story): '''Try apply style to selected text. If style doesn't exist, create it.''' 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.''' # Todo: translate italics, bolds, superscripts etc here scribus.deselectAll() scribus.selectObject(story) alltext = scribus.getAllText(story) scribus.deleteText(story) alltext = normalizeText(alltext) lines = alltext.splitlines(1) textBegin = 0 paraStyles = [] paraLen = 0 # 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': paraStyles.append(para6style.get()) # Format headers and first paragraph scribus.deselectAll() for j in range(len(paraStyles)): paraLen = len(unicode(lines[j])) scribus.insertText(lines[j], -1, story) # -1 append text to frame scribus.selectText(textBegin, paraLen-1, story) applyStyle(paraStyles[j], story) if paraStyles[j] in specialParagraphs: execString = specialParagraphs[paraStyles[j]]+'("'+paraStyles[j]+'")' print execString # exec execString if hyphenated.count(paraStyles[j]) != 0: scribus.hyphenateText() textBegin += paraLen scribus.deselectAll() # if not desselect all, strange select errors happens # Format body text for n in range((j+1),len(lines)): paraLen = len(unicode(lines[n])) scribus.insertText(lines[n], -1, story) # append text to frame scribus.selectText(textBegin, paraLen-1, story) # Short paragraphs without dots are formated as 'Subheaders'. if ((paraLen < subHeaderThreshold) and (lines[n].find('.')) == -1): applyStyle(subHeaderStyle, story) else: if n == (len(lines) - 1): # apply style to last paragraph applyStyle(paraLastStyle.get(), story) scribus.hyphenateText() else: # Apply default style to all text applyStyle(para7style.get(), story) scribus.hyphenateText() textBegin += paraLen scribus.deselectAll() return ################### 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.''' 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.''' 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.''' 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.''' 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 frame.''' # 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) if action.get() == '1': buildStory(story) if contentSource.get() == '2': file = scribus.fileDialog("Open", "*.txt") if file != '': try: text = open(file).read() text = unicode(text) except: print 'Error reading file' scribus.setText(text,story) formatText(story) 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)