Automatic story formatting

This script shows 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
 * 1) -*- coding: utf-8 -*-

''' BUILD NEWSPAPER STORY. Author: prof. José Antonio Meira da Rocha joseantoniorocha@gmail.com http://meiradarocha.jor.br License: GPL 2 2013-05-02a

USAGE: Draw a text frame marking the area where you need a story, optionally 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 chosen 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)

'''


 * 1) Locales to be translated
 * 2) and user variables
 * 1) and user variables

subHeaderThreshold = 30 # max chars to a paragraph be styled as subHeader defaultNumCols = '2'

paragraph1style = 'Standing head 1' paragraph2style = 'Headline 1' paragraph3style = 'Deck 1' paragraph4style = 'Byline' paragraph5style = 'Sub byline' paragraph6style = 'First paragraph 1' bodyTextStyle  = 'Default Paragraph Style' paragraphLastStyle = 'Default Paragraph Style' defaultParagraphStyle = 'Default Paragraph Style' subHeaderStyle = 'Subhead'
 * 1) Default style names - change to match your style sheet
 * 2) Style names - change to match your style sheet

bulletedListStyle = 'Bullet' bulletSize = 0 # In points. Zero means same size as text. if os.name == 'posix': bullet = u'\u25cf' bulletFont = 'Dingbats Regular' else: bullet = u'\u25cf' bulletFont = 'Times New Roman Regular'
 * 1) Bullet special formats
 * 2) Put your favorite bullet to lists.
 * 3) Some OS have different character codes
 * 1) Some OS have different character codes
 * 1) Some common dingbat fonts:
 * 2) 'ITC Zapf Dingbats Regular' # 'Dingbats Regular' # 'Wingdings Regular'

standingHeadStyle = 'Standing head 1' headBulletSize = 0 if os.name == 'posix': headBullet = u'\u25ba' headBulletFont = 'Dingbats Regular' else: headBullet = u'\u25ba' headBulletFont = 'Times New Roman Regular' endBulletSize = 0 if os.name == 'posix': endBullet = u'\u25a0' endBulletFont = 'Dingbats Regular' else: endBullet = u'\u25a0' endBulletFont = 'Times New Roman Regular'
 * 1) Standing head special formats
 * 1) Standing head special formats
 * 1) Bullet to mark story end.
 * 1) Bullet to mark story end.

hyphenate = [ paragraph6style, bodyTextStyle, paragraphLastStyle, bulletedListStyle ]
 * 1) Put in this list the paragraphs styles to be hyphenated
 * 1) Put in this list the paragraphs styles to be hyphenated

specialParagraphs = { paragraph1style: 'formatBulletedList' #,paragraph4style: 'formatBulletedList' #,paragraphLastStyle: 'formatLastParagraph' }
 * 1) Put in this dictionary the styles with special formating
 * 2)   and the functions that does it (without "").
 * 3) Use it to put bullets in front or at end of a paragraph,
 * 4)   format first words as bold etc.
 * 1)   format first words as bold etc.

openDocLabel= "Open a document" askOpenDoc = " "+openDocLabel+" " \ + " Please, open a document and select some text frame before run this script "
 * 1) Strings to ask to open a doc

storyFrameLabel = "Select a frame" askOpenFrame = " "+storyFrameLabel+" \n" \ + "Draw or select a text frame\nwhere you want to put a story."
 * 1) Strings to ask to select frame

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"
 * 1) GUI strings


 * 1) END locale strings

paraLines = (1, 2, 3, 4, 5, 6) numColumnsList = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) 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
 * 1) Debugging functions
 * 1) Debugging functions



import sys import re
 * 1) IMPORTS

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

inch = 0.0138888888889 # mistakenly translated to 'pol', in Portuguese localization AROUND_FRAME = 1 APPEND = -1 # -1 append text to frame
 * 1) Constants

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' }
 * 1) Measure conversion dictionaries

import xml.parsers.expat

styles = {} charstyles = {} document = {} pages = {}
 * 1) Code to handle elements of XML Scribus doc
 * 2) Convert default points values to current units
 * 3) Dictionaries to hold style sheets
 * 1) Dictionaries to hold style sheets
 * 1) Dictionaries to hold style sheets

def start_element(name, attrs): Build dictionaries 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  # 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

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)
 * 1) GUI code
 * 1) GUI code

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("", self.__handleRebuild) self.tLa47_tRa49.bind("", self.__handleRebuild) self.tCh37.bind("", self.__handlePara1) self.tCh40.bind("", self.__handlePara2) self.tCh43.bind("", self.__handlePara3) self.tCh46.bind("", self.__handlePara4) self.tCh49.bind("", self.__handlePara5) #self.tCh52.bind("", self.__handlePara6) self.tCh54.bind("", self.__handlePara7) self.tCh33.bind("", 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

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(' '): t = t.replace(' ','\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
 * 1) Clean text
 * 1) Clean text

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)
 * 1) Format bulleted lists
 * 1) Format bulleted lists

specialParagraphs[bulletedListStyle] = 'formatBulletedList'
 * 1) Tie above function to style name

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)
 * 1) Format Standing Head
 * 1) Format Standing Head

specialParagraphs[standingHeadStyle] = 'formatStandingHead'
 * 1) Tie above function to style name

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
 * 1) formatLastParagraph.
 * 2) exec by formatText
 * 1) exec by formatText

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
 * 1) Insert text and
 * 2) format paragraph
 * 1) format paragraph

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)

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
 * 1) Do all the job
 * 1) Do all the job

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)