Automatic story formatting: Difference between revisions
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.) |
No edit summary |
||
Line 11: | Line 11: | ||
''' | ''' | ||
BUILD NEWSPAPER STORY. | BUILD NEWSPAPER STORY. | ||
Author: prof. | Author: prof. Jos\Uffffffffntonio Meira da Rocha | ||
joseantoniorocha@gmail.com | joseantoniorocha@gmail.com | ||
http://meiradarocha.jor.br | http://meiradarocha.jor.br | ||
Licence: GPL 2 | Licence: GPL 2 | ||
2012-03-10a | |||
USAGE: | USAGE: | ||
Line 25: | Line 25: | ||
1. Resize the frame to hold headers. | 1. Resize the frame to hold headers. | ||
2. Draw a second linked frame to hold text in columns. | 2. Draw a second linked frame to hold text in columns. | ||
3. Clean up the text, ripping off blank paragraphs, double spaces, | 3. Clean up the text, ripping off blank paragraphs, double spaces, changing quotes etc. | ||
4. Apply the choosen styles. | 4. Apply the choosen styles. | ||
5. Find and apply style to short paragraphs as sub-headers. | 5. Find and apply style to short paragraphs without dot as sub-headers. | ||
NEED: | NEED: | ||
Tcl/Tk 8.5 (or 8.4 with Tile 8.2) | Tcl/Tk 8.5 (or 8.4 with Tile 8.2) | ||
Python 2.7 (or 2.5.4 with pyttk) | Python 2.7 (or 2.5.4 with pyttk) | ||
''' | ''' | ||
############################ | ############################ | ||
# Locales to be translated | # Locales to be translated | ||
Line 41: | Line 42: | ||
defaultNumCols = '2' | defaultNumCols = '2' | ||
# Default style names - change to match your style sheet | |||
# Style names - change to match your style sheet | # Style names - change to match your style sheet | ||
paragraph1style = 'Standing head 1' | paragraph1style = 'Standing head 1' | ||
Line 52: | Line 54: | ||
defaultParagraphStyle = 'Default Paragraph Style' | defaultParagraphStyle = 'Default Paragraph Style' | ||
subHeaderStyle = 'Subhead' | subHeaderStyle = 'Subhead' | ||
# Put in this dictionary the styles with special formating and the functions that does it | ############################### | ||
# 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 = { | specialParagraphs = { | ||
paragraph1style: ' | paragraph1style: 'formatBulletedList' | ||
#,paragraph4style: 'formatBulletedList' | |||
#,paragraphLastStyle: 'formatLastParagraph' | |||
} | } | ||
Line 80: | Line 119: | ||
# Strings to ask to select frame | # Strings to ask to select frame | ||
storyFrameLabel = " | storyFrameLabel = "Select a frame" | ||
askOpenFrame = "<h2>"+storyFrameLabel+"</h2>\n" \ | askOpenFrame = "<h2>"+storyFrameLabel+"</h2>\n" \ | ||
+ "Draw or select <b>a text frame</b>\nwhere you want to put a story." | + "Draw or select <b>a text frame</b>\nwhere you want to put a story." | ||
Line 112: | Line 151: | ||
paraLines = (1, 2, 3, 4, 5, 6) | paraLines = (1, 2, 3, 4, 5, 6) | ||
numColumnsList = (1, 2, 3, 4, 5, 6, 7, 8 , 9, 10, 11, 12) | 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 | # IMPORTS | ||
import sys | import sys | ||
import re | |||
try: | try: | ||
Line 148: | Line 204: | ||
# Constants | # Constants | ||
inch = 0.0138888888889 # mistakenly translated to | inch = 0.0138888888889 # mistakenly translated to 'pol', in portuguese localization | ||
AROUND_FRAME = 1 | AROUND_FRAME = 1 | ||
APPEND = -1 # -1 append text to frame | |||
# Measure convertion dictionaries | # Measure convertion dictionaries | ||
Line 171: | Line 228: | ||
import xml.parsers.expat | import xml.parsers.expat | ||
################################### | ################################################ | ||
# Code to handle elements of XML Scribus doc | |||
# Convert default points values to current units | |||
################################################ | |||
# Dictionaries to hold style sheets | # Dictionaries to hold style sheets | ||
styles = {} | styles = {} | ||
Line 178: | Line 238: | ||
pages = {} | pages = {} | ||
def start_element(name, attrs): | def start_element(name, attrs): | ||
'''Build dictonaries from SLA doc file.''' | '''Build dictonaries from SLA doc file.''' | ||
Line 187: | Line 245: | ||
document = attrs | document = attrs | ||
if name == 'STYLE': | if name == 'STYLE': | ||
styles[attrs[u'NAME']] = attrs | #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': | if name == 'CHARSTYLE': | ||
charstyles[attrs[u'CNAME']] = attrs | try: charstyles[attrs[u'CNAME']] = attrs | ||
except: pass | |||
if name == 'PAGE': | if name == 'PAGE': | ||
pages[attrs[u'NUM']] = attrs | try: pages[attrs[u'NUM']] = attrs | ||
except: pass | |||
def getParagraphStyle(styleName): | def getParagraphStyle(styleName): | ||
Line 207: | Line 272: | ||
def getParagraphAttribute(styleName,attrName): | def getParagraphAttribute(styleName,attrName): | ||
'''Return value of given attribute of given style | '''Return value of given attribute of given style | ||
***in current mesurement units.***''' | ***in current mesurement units.*** ''' | ||
res = 0 | res = 0 | ||
# Find parameter in parent style, if not in current style. | # Find parameter in parent style, if not in current style, up to 10 levels. | ||
if attrName in dic: | 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: | else: | ||
res = 0 | 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): | def getStyleLineSpacing(styleName): | ||
'''Return line spacing of given style.''' | '''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')) | res = float(getParagraphAttribute(styleName,'LINESP')) | ||
return res | return res | ||
Line 303: | Line 376: | ||
def parseDoc(): | def parseDoc(): | ||
''' Get attributes from current Scribus doc.''' | ''' Get attributes from current Scribus doc.''' | ||
debug() | |||
global styleList | global styleList | ||
parser = xml.parsers.expat.ParserCreate('UTF-8') | parser = xml.parsers.expat.ParserCreate('UTF-8') | ||
Line 308: | Line 382: | ||
try: | try: | ||
docName = scribus.saveDoc() | docName = scribus.saveDoc() | ||
# Undocumented Scribus 1.3.9 function: | |||
file = open | docName = unicode(scribus.getDocName()) | ||
file = open(docName,'r') | |||
parser.ParseFile(file) | parser.ParseFile(file) | ||
file.close() | file.close() | ||
except: | except: | ||
print "Error analising doc." | |||
earlyExit() | earlyExit() | ||
styleList = scribus.getAllStyles() | styleList = scribus.getAllStyles() | ||
styleList.sort() | styleList.sort() | ||
################## | |||
# GUI code | |||
################## | |||
def set_Tk_var(): | def set_Tk_var(): | ||
# These are Tk variables used passed to Tkinter and must be | # These are Tk variables used passed to Tkinter and must be | ||
Line 345: | Line 424: | ||
global chk2label | global chk2label | ||
chk2label = StringVar() | chk2label = StringVar() | ||
chk2label.set(' | chk2label.set('\Uffffffff 1') | ||
global para2style | global para2style | ||
para2style = StringVar() | para2style = StringVar() | ||
Line 359: | Line 438: | ||
global chk3label | global chk3label | ||
chk3label = StringVar() | chk3label = StringVar() | ||
chk3label.set(' | chk3label.set('\Uffffffff 2') | ||
global para3style | global para3style | ||
para3style = StringVar() | para3style = StringVar() | ||
Line 373: | Line 452: | ||
global chk4label | global chk4label | ||
chk4label = StringVar() | chk4label = StringVar() | ||
chk4label.set(' | chk4label.set('\Uffffffff 3') | ||
global para4style | global para4style | ||
para4style = StringVar() | para4style = StringVar() | ||
Line 384: | Line 463: | ||
global chk5label | global chk5label | ||
chk5label = StringVar() | chk5label = StringVar() | ||
chk5label.set(' | chk5label.set('\Uffffffff 4') | ||
global para5style | global para5style | ||
para5style = StringVar() | para5style = StringVar() | ||
Line 395: | Line 474: | ||
global chk6label | global chk6label | ||
chk6label = StringVar() | chk6label = StringVar() | ||
chk6label.set(' | chk6label.set('\Uffffffff 5') | ||
global para6style | global para6style | ||
para6style = StringVar() | para6style = StringVar() | ||
Line 409: | Line 488: | ||
global para7style | global para7style | ||
para7style = StringVar() | para7style = StringVar() | ||
para7style.set( | para7style.set(bodyTextStyle) | ||
# Paragraph Last | # Paragraph Last | ||
Line 417: | Line 496: | ||
global paraLastStyle | global paraLastStyle | ||
paraLastStyle = StringVar() | paraLastStyle = StringVar() | ||
paraLastStyle.set( | paraLastStyle.set(paragraphLastStyle) | ||
global chkEndBull | |||
chkEndBull = StringVar() | |||
chkEndBull.set('1') | |||
# Columns | # Columns | ||
Line 440: | Line 522: | ||
global isToDrawGuides | global isToDrawGuides | ||
isToDrawGuides = StringVar() | isToDrawGuides = StringVar() | ||
isToDrawGuides.set(' | isToDrawGuides.set('0') | ||
# Snap to baseline guides | # Snap to baseline guides | ||
global snap | global snap | ||
snap = StringVar() | snap = StringVar() | ||
snap.set(' | snap.set('0') | ||
class Build_Story_dialog: | class Build_Story_dialog: | ||
Line 470: | Line 552: | ||
self.tLa47_tRa48.configure(text=guiJustApplyStyles,variable=action,value="0") | self.tLa47_tRa48.configure(text=guiJustApplyStyles,variable=action,value="0") | ||
self.tLa47_tRa49 = ttk.Radiobutton (self.tLa47) | self.tLa47_tRa49 = ttk.Radiobutton (self.tLa47) | ||
self.tLa47_tRa49.place(relx=0.49,rely=0.12,relheight=0.7,relwidth=0. | 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") | self.tLa47_tRa49.configure(text=guiRebuildFrames,variable=action,value="1") | ||
Line 478: | Line 560: | ||
self.tLa34.configure(text=guiParagr) | self.tLa34.configure(text=guiParagr) | ||
self.tLa35 = ttk.Label (master) | self.tLa35 = ttk.Label (master) | ||
self.tLa35.place(relx=0. | self.tLa35.place(relx=0.16,rely=0.28) | ||
self.tLa35.configure(text=guiStyle) | self.tLa35.configure(text=guiStyle) | ||
self.tLa36 = ttk.Label (master) | self.tLa36 = ttk.Label (master) | ||
Line 487: | Line 569: | ||
self.tCh37.place(relx=0.02,rely=0.34) | self.tCh37.place(relx=0.02,rely=0.34) | ||
self.tCh37.configure(textvariable=chk1label,variable=chk1) | self.tCh37.configure(textvariable=chk1label,variable=chk1) | ||
self.tCo38 = ttk.Combobox (master) | self.tCo38 = ttk.Combobox (master) | ||
self.tCo38.place(relx=0. | self.tCo38.place(relx=0.16,rely=0.34,relwidth=0.32) | ||
self.tCo38.configure(textvariable=para1style,values=styleList) | self.tCo38.configure(textvariable=para1style,values=styleList) | ||
self.tCo39 = ttk.Combobox (master) | self.tCo39 = ttk.Combobox (master) | ||
self.tCo39.place(relx=0.48,rely=0.34,relwidth=0.11) | self.tCo39.place(relx=0.48,rely=0.34,relwidth=0.11) | ||
self.tCo39.configure(textvariable=para1lin,values=paraLines,justify="center") | self.tCo39.configure(textvariable=para1lin,values=paraLines,justify="center") | ||
self.tCo38.configure(state="disabled") | self.tCo38.configure(state="disabled") | ||
self.tCo39.configure(state="disabled") | self.tCo39.configure(state="disabled") | ||
Line 500: | Line 585: | ||
self.tCh40.configure(textvariable=chk2label,variable=chk2) | self.tCh40.configure(textvariable=chk2label,variable=chk2) | ||
self.tCo41 = ttk.Combobox (master) | self.tCo41 = ttk.Combobox (master) | ||
self.tCo41.place(relx=0. | self.tCo41.place(relx=0.16,rely=0.42,relwidth=0.32) | ||
self.tCo41.configure(textvariable=para2style,values=styleList) | self.tCo41.configure(textvariable=para2style,values=styleList) | ||
self.tCo42 = ttk.Combobox (master) | self.tCo42 = ttk.Combobox (master) | ||
Line 511: | Line 596: | ||
self.tCh43.configure(textvariable=chk3label,variable=chk3) | self.tCh43.configure(textvariable=chk3label,variable=chk3) | ||
self.tCo44 = ttk.Combobox (master) | self.tCo44 = ttk.Combobox (master) | ||
self.tCo44.place(relx=0. | self.tCo44.place(relx=0.16,rely=0.5,relwidth=0.32) | ||
self.tCo44.configure(textvariable=para3style,values=styleList) | self.tCo44.configure(textvariable=para3style,values=styleList) | ||
self.tCo45 = ttk.Combobox (master) | self.tCo45 = ttk.Combobox (master) | ||
Line 522: | Line 607: | ||
self.tCh46.configure(textvariable=chk4label,variable=chk4) | self.tCh46.configure(textvariable=chk4label,variable=chk4) | ||
self.tCo47 = ttk.Combobox (master) | self.tCo47 = ttk.Combobox (master) | ||
self.tCo47.place(relx=0. | self.tCo47.place(relx=0.16,rely=0.58,relwidth=0.32) | ||
self.tCo47.configure(textvariable=para4style,values=styleList) | self.tCo47.configure(textvariable=para4style,values=styleList) | ||
# Para #5 | # Para #5 | ||
Line 529: | Line 614: | ||
self.tCh49.configure(textvariable=chk5label,variable=chk5) | self.tCh49.configure(textvariable=chk5label,variable=chk5) | ||
self.tCo50 = ttk.Combobox (master) | self.tCo50 = ttk.Combobox (master) | ||
self.tCo50.place(relx=0. | self.tCo50.place(relx=0.16,rely=0.66,relwidth=0.32) | ||
self.tCo50.configure(textvariable=para5style,values=styleList) | self.tCo50.configure(textvariable=para5style,values=styleList) | ||
# Para #6 | # Para #6 | ||
self.tCh52 = ttk.Checkbutton (master) | self.tCh52 = ttk.Checkbutton (master) | ||
self.tCh52.place(relx=0.02,rely=0.74) | self.tCh52.place(relx=0.02,rely=0.74) | ||
self.tCh52.configure(textvariable=chk6label,variable=chk6) | self.tCh52.configure(textvariable=chk6label,variable=chk6,state="disabled") | ||
self.tCo53 = ttk.Combobox (master) | self.tCo53 = ttk.Combobox (master) | ||
self.tCo53.place(relx=0. | self.tCo53.place(relx=0.16,rely=0.74,relwidth=0.32) | ||
self.tCo53.configure(textvariable=para6style,values=styleList) | self.tCo53.configure(textvariable=para6style,values=styleList) | ||
# Para #7 | # Para #7 | ||
Line 543: | Line 628: | ||
self.tCh54.configure(textvariable=chk7label,variable=chk7) | self.tCh54.configure(textvariable=chk7label,variable=chk7) | ||
self.tCo55 = ttk.Combobox (master) | self.tCo55 = ttk.Combobox (master) | ||
self.tCo55.place(relx=0. | self.tCo55.place(relx=0.16,rely=0.82,relwidth=0.32) | ||
self.tCo55.configure(textvariable=para7style,values=styleList) | self.tCo55.configure(textvariable=para7style,values=styleList) | ||
# Para #last | # Para #last | ||
Line 550: | Line 635: | ||
self.tCh33.configure(text=guiLastPara,variable=chkLast) | self.tCh33.configure(text=guiLastPara,variable=chkLast) | ||
self.tCo34 = ttk.Combobox (master) | self.tCo34 = ttk.Combobox (master) | ||
self.tCo34.place(relx=0. | self.tCo34.place(relx=0.16,rely=0.9,relwidth=0.32) | ||
self.tCo34.configure(textvariable=paraLastStyle,values=styleList) | 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 | # Content Frame | ||
Line 586: | Line 675: | ||
self.tLa32_cpd34.configure(justify="center",textvariable=numCols,values=numColumnsList) | self.tLa32_cpd34.configure(justify="center",textvariable=numCols,values=numColumnsList) | ||
self.tLa32_cpd34.configure(state="disabled") | self.tLa32_cpd34.configure(state="disabled") | ||
self.tLa32_cpd34.configure(validate="all",validatecommand="self.validateColumns") | |||
# Gutter label | # Gutter label | ||
self.tLa32_cpd35 = ttk.Label (self.tLa32) | self.tLa32_cpd35 = ttk.Label (self.tLa32) | ||
Line 634: | Line 724: | ||
self.tCh46.bind("<ButtonRelease-1>", self.__handlePara4) | self.tCh46.bind("<ButtonRelease-1>", self.__handlePara4) | ||
self.tCh49.bind("<ButtonRelease-1>", self.__handlePara5) | self.tCh49.bind("<ButtonRelease-1>", self.__handlePara5) | ||
self.tCh52.bind("<ButtonRelease-1>", self.__handlePara6) | #self.tCh52.bind("<ButtonRelease-1>", self.__handlePara6) | ||
self.tCh54.bind("<ButtonRelease-1>", self.__handlePara7) | self.tCh54.bind("<ButtonRelease-1>", self.__handlePara7) | ||
self.tCh33.bind("<ButtonRelease-1>", self.__handlePara8) | self.tCh33.bind("<ButtonRelease-1>", self.__handlePara8) | ||
def validateColumns(): | |||
pass | |||
def __handleRebuild(self,event): | def __handleRebuild(self,event): | ||
Line 675: | Line 768: | ||
if chk1.get() == '1': | if chk1.get() == '1': | ||
num += 1 | num += 1 | ||
chk1label.set(' | chk1label.set('\Uffffffff '+str(num)) | ||
else: chk1label.set('') | else: chk1label.set('') | ||
if chk2.get() == '1': | if chk2.get() == '1': | ||
num += 1 | num += 1 | ||
chk2label.set(' | chk2label.set('\Uffffffff '+str(num)) | ||
else: chk2label.set('') | else: chk2label.set('') | ||
if chk3.get() == '1': | if chk3.get() == '1': | ||
num += 1 | num += 1 | ||
chk3label.set(' | chk3label.set('\Uffffffff '+str(num)) | ||
else: chk3label.set('') | else: chk3label.set('') | ||
if chk4.get() == '1': | if chk4.get() == '1': | ||
num += 1 | num += 1 | ||
chk4label.set(' | chk4label.set('\Uffffffff '+str(num)) | ||
else: chk4label.set('') | else: chk4label.set('') | ||
if chk5.get() == '1': | if chk5.get() == '1': | ||
num += 1 | num += 1 | ||
chk5label.set(' | chk5label.set('\Uffffffff '+str(num)) | ||
else: chk5label.set('') | else: chk5label.set('') | ||
if chk6.get() | if chk6.get(): | ||
num += 1 | num += 1 | ||
chk6label.set(' | chk6label.set('\Uffffffff '+str(num)) | ||
else: chk6label.set('') | else: chk6label.set('') | ||
Line 801: | Line 894: | ||
# Clean text | # Clean text | ||
def normalizeText(t): | 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): | ||
def | |||
'''Insert bullet at first paragraph.''' | '''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." | |||
# Insert | 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): | def applyStyle(style,story): | ||
'''Try apply style to selected text. If style doesn't exist, create it.''' | '''Try apply style to selected text. If style doesn't exist, create it.''' | ||
debug() | |||
try: | try: | ||
scribus.setStyle(style, story) | scribus.setStyle(style, story) | ||
Line 860: | Line 1,068: | ||
def formatText(story): | def formatText(story): | ||
'''Format story with styles pre-header, header, sub-header etc.''' | '''Format story with styles pre-header, header, sub-header etc.''' | ||
# | # To do: translate italics, bolds, superscripts etc here | ||
debug() | |||
paraStyles = [] | |||
paraStyles = [] | |||
# Build a list of choosen styles | # Build a list of choosen styles | ||
if chk1.get() == '1': | if chk1.get() == '1': | ||
Line 881: | Line 1,082: | ||
if chk5.get() == '1': | if chk5.get() == '1': | ||
paraStyles.append(para5style.get()) | paraStyles.append(para5style.get()) | ||
if chk6.get() == '1': | if chk6.get() == '1': # let ever on | ||
paraStyles.append(para6style.get()) | paraStyles.append(para6style.get()) | ||
#################################### | |||
# Format headers and first paragraph | # Format headers and first paragraph | ||
scribus.deselectAll() | 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)): | for j in range(len(paraStyles)): | ||
paraLen = len | 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: | 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 | 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)): | for n in range((j+1),len(lines)): | ||
paraLen = len | 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: | else: | ||
if n == (len(lines) - 1): # | |||
####################### | |||
# If is last paragraph: | |||
else: | ####################### | ||
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 | textBegin += paraLen | ||
scribus.deselectAll() | scribus.deselectAll() | ||
################### | ################### | ||
Line 925: | Line 1,225: | ||
if body text is align to baseline. Put here the rules that fix this. | if body text is align to baseline. Put here the rules that fix this. | ||
Rules depends on your particular stylesheet.''' | Rules depends on your particular stylesheet.''' | ||
debug() | |||
hasHeader1 = int(chk1.get()) | hasHeader1 = int(chk1.get()) | ||
hasHeader2 = int(chk2.get()) | hasHeader2 = int(chk2.get()) | ||
Line 976: | Line 1,277: | ||
def getHeaderHeight(): | def getHeaderHeight(): | ||
'''Calculate header frame height using style sheet data.''' | '''Calculate header frame height using style sheet data.''' | ||
debug() | |||
global chk1, para1style, para1lin | global chk1, para1style, para1lin | ||
global chk2, para2style, para2lin | global chk2, para2style, para2lin | ||
Line 1,021: | Line 1,323: | ||
def roundToNearBaseline(num): | def roundToNearBaseline(num): | ||
'''Round vertical dimensions to near baseline grid.''' | '''Round vertical dimensions to near baseline grid.''' | ||
debug() | |||
offset = getBaselineOffset() | offset = getBaselineOffset() | ||
grid = getBaselineGrid() | grid = getBaselineGrid() | ||
Line 1,033: | Line 1,336: | ||
def roundToNextBaseline(num): | def roundToNextBaseline(num): | ||
'''Round vertical dimensions to next baseline grid.''' | '''Round vertical dimensions to next baseline grid.''' | ||
debug() | |||
offset = getBaselineOffset() | offset = getBaselineOffset() | ||
grid = getBaselineGrid() | grid = getBaselineGrid() | ||
Line 1,044: | Line 1,348: | ||
###################### | ###################### | ||
def buildStory(story): | def buildStory(story): | ||
'''Build headline | '''Build headline and body text frames.''' | ||
debug() | |||
# get selected object dimensions | # get selected object dimensions | ||
global storyLeft, storyTop, storyWidth, storyHeight, numCols, gutter | global storyLeft, storyTop, storyWidth, storyHeight, numCols, gutter | ||
Line 1,106: | Line 1,411: | ||
# Do all the job | # Do all the job | ||
def ok(): | def ok(): | ||
try: root.destroy() | #try: | ||
except: pass | root.destroy() | ||
story = scribus.getSelectedObject(0) | #except: pass | ||
story = scribus.getSelectedObject(0) | |||
# Build title and text frames, if asked | |||
if action.get() == '1': | if action.get() == '1': | ||
buildStory(story) | buildStory(story) | ||
# Load text, if asked | |||
if contentSource.get() == '2': | if contentSource.get() == '2': | ||
file = scribus.fileDialog("Open", "*.txt") | file = scribus.fileDialog("Open", "*.txt") | ||
if file != '': | if file != '': | ||
try: | try: | ||
text = open(file).read() | text = unicode(open(file).read()) | ||
except: print 'Error reading file' | except: print 'Error reading file' | ||
scribus.setText(text,story) | scribus.setText(text,story) | ||
# Apply styles and format text | |||
formatText(story) | formatText(story) | ||
# Finalize | |||
scribus.docChanged(True) | scribus.docChanged(True) | ||
quit() | quit() | ||
########### | ########### | ||
def quit(): | def quit(): | ||
Line 1,164: | Line 1,474: | ||
def main(argv): | def main(argv): | ||
if scribus.haveDoc(): | if scribus.haveDoc(): | ||
scribus.setRedraw(False) | #scribus.setRedraw(False) | ||
unit = scribus.getUnit() | unit = scribus.getUnit() | ||
parseDoc() | parseDoc() | ||
Line 1,186: | Line 1,496: | ||
if __name__ == '__main__': | if __name__ == '__main__': | ||
main_wrapper(sys.argv) | main_wrapper(sys.argv) | ||
</nowiki></pre> | </nowiki></pre> |
Revision as of 19:51, 2 May 2013
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\Uffffffffntonio 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)