Automatic story formatting

From Scribus Wiki
Revision as of 15:43, 23 April 2013 by Meira (talk | contribs) (This script show a dialog with options to be applied to a selected text frame: paragraphs styles, title frame, number of text columns, etc.)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
This article is part of the Scripts series.

This script show a dialog with options to be applied to a selected text frame: paragraphs styles, title frame, number of text columns, etc.

Need Tkinter.

#!/usr/bin/python
# -*- coding: utf-8 -*-

'''
BUILD NEWSPAPER STORY.
Author: prof. José Antonio Meira da Rocha
joseantoniorocha@gmail.com
http://meiradarocha.jor.br
Licence: GPL 2
2011-01-26

USAGE:
Draw a text frame marking the area where you need a story, 
optionaly putting text inside. Select the frame, run the script 
and choose styles to be applied, numbers of columns, gutter
and guide lines.
The script will:
1. Resize the frame to hold headers.
2. Draw a second linked frame to hold text in columns.
3. Clean up the text, ripping off blank paragraphs, double spaces,
   changing quotes etc.
4. Apply the choosen styles.
5. Find and apply style to short paragraphs as sub-headers.

NEED:
Tcl/Tk 8.5 (or 8.4 with Tile 8.2)
Python 2.7 (or 2.5.4 with pyttk)
'''
############################
# Locales to be translated
# and user variables

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

# Style names - change to match your style sheet
paragraph1style = 'Standing head 1'
paragraph2style = 'Headline 1'
paragraph3style = 'Deck 1'
paragraph4style = 'Byline'
paragraph5style = 'Sub byline'
paragraph6style = 'First paragraph 1'
paragraph7style = 'Default Paragraph Style'
paragraphLaststyle = 'Default Paragraph Style'
defaultParagraphStyle = 'Default Paragraph Style'
subHeaderStyle = 'Subhead'
'''
# Style names - change to match your style sheet
paragraph1style = 'Antetitulo'
paragraph2style = 'Titulo 2'
paragraph3style = 'Subtitulo 1'
paragraph4style = 'Assinatura'
paragraph5style = 'Sub byline'
paragraph6style = 'Primeiro paragrafo'
paragraph7style = 'Default Paragraph Style'
paragraphLaststyle = 'Default Paragraph Style'
defaultParagraphStyle = 'Default Paragraph Style'
subHeaderStyle = 'Entretitulo'
'''
# Put in this list the paragraphs to be hyphenated
hyphenated = [paragraph6style,paragraph7style]

# Put in this dictionary the styles with special formating and the functions that does it
specialParagraphs = {
  paragraph1style: 'putBullet',
  paragraph4style: 'putBullet'
}

# Strings to ask to open a doc
openDocLabel= "Open a document"
askOpenDoc = "<h2>"+openDocLabel+"</h2>" \
    + "<p>Please, open a document and select some text frame before run this script</p>"

# Strings to ask to select frame
storyFrameLabel = "Selecione um quadro"
askOpenFrame = "<h2>"+storyFrameLabel+"</h2>\n" \
    + "Draw or select <b>a text frame</b>\nwhere you want to put a story." 

# GUI strings
guiWindow = "Build story"
guiHeader = "Newspaper Story builder"
guiAction = "Action"
guiJustApplyStyles = "Just apply styles"
guiRebuildFrames = "Rebuild frame too"
guiParagr = "Apply"
guiStyle = "Style"
guiLines = "Lines"
guiBody = 'Body ¶'
guiLastPara = "Last ¶"
guiColumns = "Columns"
guiNumCols = "How many?"
guiGutter = "Gutters"
guiContent = "Content"
guiUseCurrent = "Use current"
guiGetFromClipboard = "Get from clipboard"
guiImportFromFile = "Import from file"
guiOptions = "Options"
guiDrawGuideLines = "Draw guide lines"
guiSnapToBaselineGrid = "Snap to baseline grid"
guiOK = "OK"
guiCancel = "Cancel"

# END locale strings

paraLines = (1, 2, 3, 4, 5, 6)
numColumnsList = (1, 2, 3, 4, 5, 6, 7, 8 , 9, 10, 11, 12)

# IMPORTS
import sys

try:
    import scribus
except ImportError,err:
    print "This Python script is written for the Scribus scripting interface."
    print "It can only be run from within Scribus."
    sys.exit(1)
#
py2 = py30 = py31 = False
version = sys.hexversion
if version >= 0x020504F0 and version < 0x03000000 :
    py2 = True    # Python 2.5.4 or 2.6 or 2.7
    from Tkinter import *
    import ttk
elif version >= 0x03000000 and version < 0x03010000 :
    py30 = True
    from tkinter import *
    import ttk
elif version >= 0x03010000:
    py31 = True
    from tkinter import *
    import tkinter.ttk as ttk
else:
    print ("""
    You do not have a version of python supporting ttk widgets..
    You need a version >= 2.6 to execute PAGE modules
    or a version 2.5 patched with pyttk and Tcl with Tile.
    """)
    sys.exit()
#
from scribus import UNIT_POINTS, UNIT_MILLIMETERS, UNIT_CM, UNIT_INCHES, UNIT_PICAS, UNIT_CICERO, LINE_SOLID, JOIN_MITTER, BUTTON_OK, BUTTON_CANCEL, BUTTON_ABORT, BUTTON_NO, BUTTON_YES, ICON_WARNING, ICON_INFORMATION, pt, mm, p, cm, c

# Constants
inch = 0.0138888888889 # mistakenly translated to portuguese 'pol'
AROUND_FRAME = 1

# Measure convertion dictionaries
unitDict = {
    UNIT_POINTS:pt,
    UNIT_MILLIMETERS:mm,
    UNIT_INCHES:inch,
    UNIT_PICAS:(pt/12),  # Fix bug in Scribus
    UNIT_CM:cm,
    UNIT_CICERO:c 
}
unitStrDict = {
    UNIT_POINTS:'pt',
    UNIT_MILLIMETERS:'mm',
    UNIT_INCHES:'in',
    UNIT_PICAS:'p', 
    UNIT_CM:'cm',
    UNIT_CICERO:'c' 
}

import xml.parsers.expat

###################################
# Dictionaries to hold style sheets
styles = {}
charstyles = {}
document = {}
pages = {}

# Handle elements of XML Scribus doc 
# Convert default points values to current units
def start_element(name, attrs):
    '''Build dictonaries from SLA doc file.'''
    # print 'Start element:', name, attrs  #debug
    global styles, charstyles, document, pages
    if name == 'DOCUMENT':
        document = attrs
    if name == 'STYLE':
        styles[attrs[u'NAME']] = attrs
    if name == 'CHARSTYLE':
        charstyles[attrs[u'CNAME']] = attrs
    if name == 'PAGE':
        pages[attrs[u'NUM']] = attrs

def getParagraphStyle(styleName):
    '''Return a dictionary with paragraph style parameters.
    If style don't exist, create it with default paragraph parameters.'''
    try:
        res = styles[styleName]
    except:
        print styleName,'not in style sheet. Creating it.'
        scribus.createParagraphStyle(styleName)
        styles[styleName] = styles[defaultParagraphStyle]
        res = styles[defaultParagraphStyle]
    return res

def getParagraphAttribute(styleName,attrName):
    '''Return value of given attribute of given style
    ***in current mesurement units.***'''
    dic = getParagraphStyle(styleName)
    res = 0
    # Find parameter in parent style, if not in current style.
    if attrName in dic:
        res = dic[attrName]
        # Convert points to current units
        unit = scribus.getUnit()
        res = float(res)*unitDict[unit]
        return res
    else:    
        if 'PARENT' in dic:
            styleName = dic['PARENT']
            res = getParagraphAttribute(styleName,attrName)
            return res
        else:
            res = 0
            return res

def getStyleLineSpacing(styleName):
    '''Return line spacing of given style.'''
    res = float(getParagraphAttribute(styleName,'LINESP'))
    return res

def getStyleLineSpaceMode(styleName):
    '''0=fixed, 1=proportional.'''
    res = int(getParagraphAttribute(styleName,'LINESPMode'))
    return res

def getStyleSpaceAbove(styleName):
    '''Return space above of given paragraph style.'''
    res = float(getParagraphAttribute(styleName,'VOR'))
    return res

def getStyleSpaceBelow(styleName):
    '''Return space below of given paragraph style.'''
    res = float(getParagraphAttribute(styleName,'NACH'))
    return res

def getBaselineGrid():
    '''Get document baseline grid.'''
    global document
    if document == {}:
        res = 0
    else:
        res = float(document['BASEGRID'])
        unit = scribus.getUnit()
        res = res*unitDict[unit]
    return res

def getBaselineOffset():
    '''Get document baseline offset.'''
    global document
    if document == {}:
        res = 0
    else:
        res = float(document['BASEO'])
        unit = scribus.getUnit()
        res = res*unitDict[unit]
    return res

def getAutoLineSpace():
    '''Get automatic line space percentage of current document.'''
    global document
    if document == {}:
        res = 0
    else:
        res = float(document['AUTOL'])
        unit = scribus.getUnit()
        res = res*unitDict[unit]
    return res

def getPageAttributes(page):
    page = page - 1
    try: res = pages[str(unicode(page))]
    except:
        print 'Page',page,'not in document.'
        res = {}
    return res

def getVAutoGap():
    page = scribus.currentPage()
    pdic = getPageAttributes(page)
    if pdic == {}:
        res = 0
    else:
        try: 
            res = float(pdic['AGverticalAutoGap'])
            unit = scribus.getUnit()
            res = res*unitDict[unit]
        except: 
            print 'AGverticalAutoGap','not in page',page
    return res

def parseDoc():
    ''' Get attributes from current Scribus doc.'''
    global styleList
    parser = xml.parsers.expat.ParserCreate('UTF-8')
    parser.StartElementHandler = start_element
    try: 
        docName = scribus.saveDoc()
        docName = scribus.getDocName()  # Undocumented Scribus 1.3.9 function
        file = open(unicode(docName),'r')
        parser.ParseFile(file)
        file.close()
    except:
        earlyExit()
    styleList = scribus.getAllStyles()
    styleList.sort()

def set_Tk_var():
    # These are Tk variables used passed to Tkinter and must be
    # defined before the widgets using them are created.
    # Paragraph 1
    global action
    action = StringVar()
    action.set("0")
    
    # Paragraph 1
    global chk1
    chk1 = StringVar()
    chk1.set('0')
    global chk1label
    chk1label = StringVar()
    chk1label.set('')
    global para1style
    para1style = StringVar()
    para1style.set(paragraph1style)
    global para1lin
    para1lin = StringVar()
    para1lin.set('1')
    
    # Paragraph 2
    global chk2
    chk2 = StringVar()
    chk2.set('1')
    global chk2label
    chk2label = StringVar()
    chk2label.set('¶ 1')
    global para2style
    para2style = StringVar()
    para2style.set(paragraph2style)
    global para2lin
    para2lin = StringVar()
    para2lin.set('1')
    
    # Paragraph 3
    global chk3
    chk3 = StringVar()
    chk3.set('1')
    global chk3label
    chk3label = StringVar()
    chk3label.set('¶ 2')
    global para3style
    para3style = StringVar()
    para3style.set(paragraph3style)
    global para3lin
    para3lin = StringVar()
    para3lin.set('1')
    
    # Paragraph 4
    global chk4
    chk4 = StringVar()
    chk4.set('1')
    global chk4label
    chk4label = StringVar()
    chk4label.set('¶ 3')
    global para4style
    para4style = StringVar()
    para4style.set(paragraph4style)
    
    # Paragraph 5
    global chk5
    chk5 = StringVar()
    chk5.set('1')
    global chk5label
    chk5label = StringVar()
    chk5label.set('¶ 4')
    global para5style
    para5style = StringVar()
    para5style.set(paragraph5style)
    
    # Paragraph 6
    global chk6
    chk6 = StringVar()
    chk6.set('1')
    global chk6label
    chk6label = StringVar()
    chk6label.set('¶ 5')
    global para6style
    para6style = StringVar()
    para6style.set(paragraph6style)
    
    # Paragraph 7
    global chk7
    chk7 = StringVar()
    chk7.set('1')
    global chk7label
    chk7label = StringVar()
    chk7label.set(guiBody)
    global para7style
    para7style = StringVar()
    para7style.set(paragraph7style)
    
    # Paragraph Last
    global chkLast
    chkLast = StringVar()
    chkLast.set('1')
    global paraLastStyle
    paraLastStyle = StringVar()
    paraLastStyle.set(paragraphLaststyle)
    
    # Columns
    global numCols
    numCols = StringVar()
    numCols.set(defaultNumCols)
    
    # Columns & Gaps
    global gutter, unitString
    gutter = StringVar()
    gap = getVAutoGap()
    unit = scribus.getUnit()
    unitString = unitStrDict[unit]
    gutter.set(gap)
    
    # Content
    global contentSource
    contentSource = StringVar()
    contentSource.set('0')
    
    # Guides
    global isToDrawGuides
    isToDrawGuides = StringVar()
    isToDrawGuides.set('1')
    
    # Snap to baseline guides
    global snap
    snap = StringVar()
    snap.set('1')
    
class Build_Story_dialog:
    def __init__(self, master=None):
        # Set background of toplevel window to match
        # current style
        style = ttk.Style()
        theme = style.theme_use()
        default = style.lookup(theme, 'background')
        master.configure(background=default)
        # Head label
        self.tLa33 = ttk.Label (master)
        self.tLa33.place(relx=0.02,rely=0.03)
        self.tLa33.configure(font="font12")
        self.tLa33.configure(text=guiHeader)
        
        # Actions frame
        self.tLa47 = ttk.Labelframe (master)
        self.tLa47.place(relx=0.02,rely=0.11,relheight=0.15,relwidth=0.57)
        self.tLa47.configure(text=guiAction,width="295",height="55")
        # Action radiobuttons
        self.tLa47_tRa48 = ttk.Radiobutton (self.tLa47)
        self.tLa47_tRa48.place(relx=0.03,rely=0.12,relheight=0.7,relwidth=0.45)
        self.tLa47_tRa48.configure(text=guiJustApplyStyles,variable=action,value="0")
        self.tLa47_tRa49 = ttk.Radiobutton (self.tLa47)
        self.tLa47_tRa49.place(relx=0.49,rely=0.12,relheight=0.7,relwidth=0.45)
        self.tLa47_tRa49.configure(text=guiRebuildFrames,variable=action,value="1")
        
        # Styles labels
        self.tLa34 = ttk.Label (master)
        self.tLa34.place(relx=0.02,rely=0.28)
        self.tLa34.configure(text=guiParagr)
        self.tLa35 = ttk.Label (master)
        self.tLa35.place(relx=0.14,rely=0.28)
        self.tLa35.configure(text=guiStyle)
        self.tLa36 = ttk.Label (master)
        self.tLa36.place(relx=0.48,rely=0.28)
        self.tLa36.configure(text=guiLines)
        # Para #1
        self.tCh37 = ttk.Checkbutton (master)
        self.tCh37.place(relx=0.02,rely=0.34)
        self.tCh37.configure(textvariable=chk1label,variable=chk1)
        self.tCo38 = ttk.Combobox (master)
        self.tCo38.place(relx=0.14,rely=0.34,relwidth=0.34)
        self.tCo38.configure(textvariable=para1style,values=styleList)
        self.tCo39 = ttk.Combobox (master)
        self.tCo39.place(relx=0.48,rely=0.34,relwidth=0.11)
        self.tCo39.configure(textvariable=para1lin,values=paraLines,justify="center")
        self.tCo38.configure(state="disabled")
        self.tCo39.configure(state="disabled")
        # Para #2
        self.tCh40 = ttk.Checkbutton (master)
        self.tCh40.place(relx=0.02,rely=0.42)
        self.tCh40.configure(textvariable=chk2label,variable=chk2)
        self.tCo41 = ttk.Combobox (master)
        self.tCo41.place(relx=0.14,rely=0.42,relwidth=0.34)
        self.tCo41.configure(textvariable=para2style,values=styleList)
        self.tCo42 = ttk.Combobox (master)
        self.tCo42.place(relx=0.48,rely=0.42,relwidth=0.11)
        self.tCo42.configure(textvariable=para2lin,values=paraLines,justify="center")
        self.tCo42.configure(state="disabled")
        # Para #3
        self.tCh43 = ttk.Checkbutton (master)
        self.tCh43.place(relx=0.02,rely=0.5)
        self.tCh43.configure(textvariable=chk3label,variable=chk3)
        self.tCo44 = ttk.Combobox (master)
        self.tCo44.place(relx=0.14,rely=0.5,relwidth=0.34)
        self.tCo44.configure(textvariable=para3style,values=styleList)
        self.tCo45 = ttk.Combobox (master)
        self.tCo45.place(relx=0.48,rely=0.5,relwidth=0.11)
        self.tCo45.configure(textvariable=para3lin,values=paraLines,justify="center")
        self.tCo45.configure(state="disabled")
        # Para #4
        self.tCh46 = ttk.Checkbutton (master)
        self.tCh46.place(relx=0.02,rely=0.58)
        self.tCh46.configure(textvariable=chk4label,variable=chk4)
        self.tCo47 = ttk.Combobox (master)
        self.tCo47.place(relx=0.14,rely=0.58,relwidth=0.34)
        self.tCo47.configure(textvariable=para4style,values=styleList)
        # Para #5
        self.tCh49 = ttk.Checkbutton (master)
        self.tCh49.place(relx=0.02,rely=0.66)
        self.tCh49.configure(textvariable=chk5label,variable=chk5)
        self.tCo50 = ttk.Combobox (master)
        self.tCo50.place(relx=0.14,rely=0.66,relwidth=0.34)
        self.tCo50.configure(textvariable=para5style,values=styleList)
        # Para #6
        self.tCh52 = ttk.Checkbutton (master)
        self.tCh52.place(relx=0.02,rely=0.74)
        self.tCh52.configure(textvariable=chk6label,variable=chk6)
        self.tCo53 = ttk.Combobox (master)
        self.tCo53.place(relx=0.14,rely=0.74,relwidth=0.34)
        self.tCo53.configure(textvariable=para6style,values=styleList)
        # Para #7
        self.tCh54 = ttk.Checkbutton (master)
        self.tCh54.place(relx=0.02,rely=0.82)
        self.tCh54.configure(textvariable=chk7label,variable=chk7)
        self.tCo55 = ttk.Combobox (master)
        self.tCo55.place(relx=0.14,rely=0.82,relwidth=0.34)
        self.tCo55.configure(textvariable=para7style,values=styleList)
        # Para #last
        self.tCh33 = ttk.Checkbutton (master)
        self.tCh33.place(relx=0.02,rely=0.9)
        self.tCh33.configure(text=guiLastPara,variable=chkLast)
        self.tCo34 = ttk.Combobox (master)
        self.tCo34.place(relx=0.14,rely=0.9,relwidth=0.34)
        self.tCo34.configure(textvariable=paraLastStyle,values=styleList)
        
        # Content Frame
        self.tLa38 = ttk.Labelframe (master)
        self.tLa38.place(relx=0.62,rely=0.11,relheight=0.26,relwidth=0.36)
        self.tLa38.configure(text=guiContent,width="185",height="95")
        # Use current label
        self.tLa38_cpd39 = ttk.Radiobutton (self.tLa38)
        self.tLa38_cpd39.place(relx=0.05,rely=0.08)
        self.tLa38_cpd39.configure(text=guiUseCurrent,variable=contentSource,value="0")
        # Import from file label
        self.tLa38_cpd41 = ttk.Radiobutton (self.tLa38)
        self.tLa38_cpd41.place(relx=0.05,rely=0.36)
        self.tLa38_cpd41.configure(text=guiImportFromFile,variable=contentSource,value="2")
        #self.tLa38_cpd41.configure(state="disabled")
        # Get from clipboard label
        self.tLa38_cpd40 = ttk.Radiobutton (self.tLa38)
        self.tLa38_cpd40.place(relx=0.05,rely=0.63)
        self.tLa38_cpd40.configure(text=guiGetFromClipboard,variable=contentSource,value="1")
        self.tLa38_cpd40.configure(state="disabled")

        # Columns frame
        self.tLa32 = ttk.Labelframe (master)
        self.tLa32.place(relx=0.62,rely=0.37,relheight=0.21,relwidth=0.36)
        self.tLa32.configure(text=guiColumns,width="185",height="70")
        # How many label
        self.tLa32_cpd33 = ttk.Label (self.tLa32)
        self.tLa32_cpd33.place(relx=0.05,rely=0.07)
        self.tLa32_cpd33.configure(text=guiNumCols)
        self.tLa32_cpd33.configure(state="disabled")
        # How many combo
        self.tLa32_cpd34 = ttk.Combobox (self.tLa32)
        self.tLa32_cpd34.place(relx=0.05,rely=0.4,relwidth=0.36)
        self.tLa32_cpd34.configure(justify="center",textvariable=numCols,values=numColumnsList)
        self.tLa32_cpd34.configure(state="disabled")
        # Gutter label
        self.tLa32_cpd35 = ttk.Label (self.tLa32)
        self.tLa32_cpd35.place(relx=0.5,rely=0.07)
        self.tLa32_cpd35.configure(justify="center",text=guiGutter)
        self.tLa32_cpd35.configure(state="disabled")
        # Gutter combo
        self.tLa32_cpd36 = ttk.Combobox (self.tLa32)
        self.tLa32_cpd36.place(relx=0.5,rely=0.4,relwidth=0.33)
        self.tLa32_cpd36.configure(justify="center",values=numColumnsList,textvariable=gutter)
        self.tLa32_cpd36.configure(state="disabled")
        # measure
        self.tLa32_cpd37 = ttk.Label (self.tLa32)
        self.tLa32_cpd37.place(relx=0.84,rely=0.5)
        self.tLa32_cpd37.configure(text=unitString)
        self.tLa32_cpd37.configure(state="disabled")

        # Options frame
        self.tLa42 = ttk.Labelframe (master)
        self.tLa42.place(relx=0.62,rely=0.58,relheight=0.23,relwidth=0.36)
        self.tLa42.configure(text=guiOptions,width="185",height="80")
        # Draw guides check
        self.tLa42_cpd44 = ttk.Checkbutton (self.tLa42)
        self.tLa42_cpd44.place(relx=0.05,rely=0.08)
        self.tLa42_cpd44.configure(text=guiDrawGuideLines,variable=isToDrawGuides)
        self.tLa42_cpd44.configure(state="disabled")
        # Snap guides check
        self.tLa42_cpd46 = ttk.Checkbutton (self.tLa42)
        self.tLa42_cpd46.place(relx=0.05,rely=0.5)
        self.tLa42_cpd46.configure(text=guiSnapToBaselineGrid,variable=snap)
        self.tLa42_cpd46.configure(state="disabled")

        # Button OK
        self.tBu67 = ttk.Button (master)
        self.tBu67.place(relx=0.81,rely=0.89)
        self.tBu67.configure(text=guiOK,command=ok)
        # Button Cancel
        self.tBu68 = ttk.Button (master)
        self.tBu68.place(relx=0.62,rely=0.89)
        self.tBu68.configure(text=guiCancel,command=quit)
    
        # Bind mouse button release to Rebuild check mark
        self.tLa47_tRa48.bind("<ButtonRelease-1>", self.__handleRebuild)
        self.tLa47_tRa49.bind("<ButtonRelease-1>", self.__handleRebuild)
        self.tCh37.bind("<ButtonRelease-1>", self.__handlePara1)
        self.tCh40.bind("<ButtonRelease-1>", self.__handlePara2)
        self.tCh43.bind("<ButtonRelease-1>", self.__handlePara3)
        self.tCh46.bind("<ButtonRelease-1>", self.__handlePara4)
        self.tCh49.bind("<ButtonRelease-1>", self.__handlePara5)
        self.tCh52.bind("<ButtonRelease-1>", self.__handlePara6)
        self.tCh54.bind("<ButtonRelease-1>", self.__handlePara7)
        self.tCh33.bind("<ButtonRelease-1>", self.__handlePara8)
        
    def __handleRebuild(self,event):
        w = event.widget
        if w.cget('value') == '0':
            self.tLa32_cpd34.configure(state="disabled")  # num cols combo
            self.tLa32_cpd36.configure(state="disabled")  # gutter combo
            self.tLa42_cpd46.configure(state="disabled")  # snap check
            self.tLa42_cpd44.configure(state="disabled")  # guides check
            self.tLa32_cpd33.configure(state="disabled")  # Labels
            self.tLa32_cpd35.configure(state="disabled")
            self.tLa32_cpd37.configure(state="disabled")
            self.tCo39.configure(state="disabled")
            self.tCo42.configure(state="disabled")
            self.tCo45.configure(state="disabled")

        else:
            self.tLa32_cpd34.configure(state="enabled")
            self.tLa32_cpd36.configure(state="enabled")
            self.tLa42_cpd46.configure(state="enabled")
            self.tLa42_cpd44.configure(state="enabled")
            self.tLa32_cpd33.configure(state="enabled")
            self.tLa32_cpd35.configure(state="enabled")
            self.tLa32_cpd37.configure(state="enabled")
            if int(chk1.get()):
                self.tCo39.configure(state="enabled")
            if int(chk2.get()):
                self.tCo42.configure(state="enabled")
            if int(chk3.get()):
                self.tCo45.configure(state="enabled")
            
    def __renumberPara(self,event):
        '''Come to here with variable no set yet'''
        #w = event.widget
        #print w.keys()
        # ['takefocus', 'variable', 'onvalue', 'offvalue', 'command', 'text', 'textvariable', 'underline', 'width', 'image', 'compound', 'padding', 'state', 'takefocus', 'cursor', 'style', 'class']
        num = 0
        if chk1.get() == '1':
            num += 1
            chk1label.set('¶ '+str(num))
        else: chk1label.set('')
        if chk2.get() == '1':
            num += 1
            chk2label.set('¶ '+str(num))
        else: chk2label.set('')
        if chk3.get() == '1':
            num += 1
            chk3label.set('¶ '+str(num))
        else: chk3label.set('')
        if chk4.get() == '1':
            num += 1
            chk4label.set('¶ '+str(num))
        else: chk4label.set('')
        if chk5.get() == '1':
            num += 1
            chk5label.set('¶ '+str(num))
        else: chk5label.set('')
        if chk6.get() == '1':
            num += 1
            chk6label.set('¶ '+str(num))
        else: chk6label.set('')
       
    def __handlePara1(self,event):
        if chk1.get() == '0':
            self.tCo38.configure(state="enabled")
            if action.get() == '1':
                self.tCo39.configure(state="enabled")
            chk1.set('1')
            self.__renumberPara(event)
            chk1.set('0')
        else:
            self.tCo38.configure(state="disabled")
            self.tCo39.configure(state="disabled")
            chk1.set('0')
            self.__renumberPara(event)
            chk1.set('1')

    def __handlePara2(self,event):
        if chk2.get() == '0':
            self.tCo41.configure(state="enabled")
            if action.get() == '1':
                self.tCo42.configure(state="enabled")
            chk2.set('1')
            self.__renumberPara(event)
            chk2.set('0')
        else:
            self.tCo41.configure(state="disabled")
            self.tCo42.configure(state="disabled")
            chk2.set('0')
            self.__renumberPara(event)
            chk2.set('1')

    def __handlePara3(self,event):
        if chk3.get() == '0':
            self.tCo44.configure(state="enabled")
            if action.get() == '1':
                self.tCo45.configure(state="enabled")
            chk3.set('1')
            self.__renumberPara(event)
            chk3.set('0')
        else:
            self.tCo44.configure(state="disabled")
            self.tCo45.configure(state="disabled")
            chk3.set('0')
            self.__renumberPara(event)
            chk3.set('1')

    def __handlePara4(self,event):
        if chk4.get() == '0':
            self.tCo47.configure(state="enabled")
            chk4.set('1')
            self.__renumberPara(event)
            chk4.set('0')
        else:
            self.tCo47.configure(state="disabled")
            chk4.set('0')
            self.__renumberPara(event)
            chk4.set('1')

    def __handlePara5(self,event):
        if chk5.get() == '0':
            self.tCo50.configure(state="enabled")
            chk5.set('1')
            self.__renumberPara(event)
            chk5.set('0')
        else:
            self.tCo50.configure(state="disabled")
            chk5.set('0')
            self.__renumberPara(event)
            chk5.set('1')

    def __handlePara6(self,event):
        if chk6.get() == '0':
            self.tCo53.configure(state="enabled")
            chk6.set('1')
            self.__renumberPara(event)
            chk6.set('0')
        else:
            self.tCo53.configure(state="disabled")
            chk6.set('0')
            self.__renumberPara(event)
            chk6.set('1')

    def __handlePara7(self,event):
        if chk7.get() == '0':
            self.tCo55.configure(state="enabled")
        else:
            chk7.set('0')
            self.__renumberPara(event)
            chk7.set('1')
            self.tCo55.configure(state="disabled")

    def __handlePara8(self,event):
        if chkLast.get() == '0':
            self.tCo34.configure(state="enabled")
        else:
            
            self.tCo34.configure(state="disabled")

def init():
    pass

#####################
# Clean text
def normalizeText(t):
        '''Rip off blank paragraphs, double spaces, html tags, quotes etc.'''
        t = t.strip()
        while t.count('\t'):
                t = t.replace('\t','')
        while t.count('  '):
                t = t.replace('  ',' ')
        while t.count('<br>'):
                t = t.replace('<br>','\n')
        while t.count('\r'):             # Fim de parágrafo tipo DOS e Windows. 
                t = t.replace('\r','\n') # Troca pelo fim-de-parágrafo padrão
        while t.count(' \n'):
                t = t.replace(' \n','\n')
        while t.count('\n '):
                t = t.replace('\n ','\n')
        while t.count('\n\n'):
                t = t.replace('\n\n','\n')
        # Cria travessões
        while t.count('\n-'):
                t = t.replace('\n-','\n—')
        # Change computer quotes by typographic quotes
        while t.count('\n"'):
                t = t.replace('\n"','\n“')
        while t.count(' "'):
                t = t.replace(' "',' “')
        while t.count('" '):
                t = t.replace('" ','” ')
        while t.count('",'):
                t = t.replace('",','”,')
        while t.count('".'):
                t = t.replace('".','”.')
        while t.count('."'):
                t = t.replace('."','”.')
        while t.count('.”'):
                t = t.replace('.”','”.')
        
        return t

####################
# Insert bullets 
# in some paragraphs
def putBullet(line):
    '''Insert bullet at first paragraph.'''
    # Remove old bullet
    
    # Insert new bullet
    
###################
def applyStyle(style,story):
    '''Try apply style to selected text. If style doesn't exist, create it.'''
    try:
        scribus.setStyle(style, story)
    except:
        scribus.createParagraphStyle(style)
        scribus.setStyle(style, story)
    return story

####################
def formatText(story):
    '''Format story with styles pre-header, header, sub-header etc.'''
    # Todo: translate italics, bolds, superscripts etc here
    scribus.deselectAll()
    scribus.selectObject(story)
    alltext = scribus.getAllText(story)
    scribus.deleteText(story)
    alltext = normalizeText(alltext)
    lines = alltext.splitlines(1)
    textBegin = 0
    paraStyles = []
    paraLen = 0
    # Build a list of choosen styles
    if chk1.get() == '1':
        paraStyles.append(para1style.get())
    if chk2.get() == '1':
        paraStyles.append(para2style.get())
    if chk3.get() == '1':
        paraStyles.append(para3style.get())
    if chk4.get() == '1':
        paraStyles.append(para4style.get())
    if chk5.get() == '1':
        paraStyles.append(para5style.get())
    if chk6.get() == '1':
        paraStyles.append(para6style.get())

    # Format headers and first paragraph
    scribus.deselectAll()
    for j in range(len(paraStyles)):
        paraLen = len(unicode(lines[j]))
        scribus.insertText(lines[j], -1, story) # -1 append text to frame
        scribus.selectText(textBegin, paraLen-1, story)
        applyStyle(paraStyles[j], story)
        if paraStyles[j] in specialParagraphs:
            execString = specialParagraphs[paraStyles[j]]+'("'+paraStyles[j]+'")'
            print execString # exec execString
        if hyphenated.count(paraStyles[j]) != 0:
            scribus.hyphenateText()
        textBegin += paraLen
        scribus.deselectAll()  # if not desselect all, strange select errors happens
    
    # Format body text 
    for n in range((j+1),len(lines)):
        paraLen = len(unicode(lines[n]))
        scribus.insertText(lines[n], -1, story) # append text to frame
        scribus.selectText(textBegin, paraLen-1, story)
        # Short paragraphs without dots are formated as 'Subheaders'.
        if ((paraLen < subHeaderThreshold) and (lines[n].find('.')) == -1):
            applyStyle(subHeaderStyle, story)
        else:
            if n == (len(lines) - 1):  # apply style to last paragraph
                applyStyle(paraLastStyle.get(), story)
                scribus.hyphenateText()
            else:  # Apply default style to all text
                applyStyle(para7style.get(), story)
                scribus.hyphenateText()
        textBegin += paraLen
        scribus.deselectAll()
        
    return

###################
def adjustHeaderHeight(storyTop,headerBottom):
    '''Rules for header End adjustments.
    Some headers + lines combinations results in bad height
    if body text is align to baseline. Put here the rules that fix this.
    Rules depends on your particular stylesheet.'''
    hasHeader1 = int(chk1.get())
    hasHeader2 = int(chk2.get())
    hasHeader3 = int(chk3.get())
    lines1 = int(para1lin.get())
    lines2 = int(para2lin.get())
    lines3 = int(para3lin.get())
    lineSpace1 = getStyleLineSpacing(para1style.get())
    lineSpace2 = getStyleLineSpacing(para2style.get())
    lineSpace3 = getStyleLineSpacing(para3style.get())
    grid = getBaselineGrid()
    headerHeight = headerBottom - storyTop
    unit = scribus.getUnit()
    threshold = grid*3*unitDict[unit]
    headerHeight = max(headerHeight,threshold)
    headerBottom = storyTop + headerHeight
    columnsTop = headerBottom
    print 'threshold:',threshold,'headerHeight:',headerHeight
    if hasHeader1:
        pass
            
    if hasHeader2:
        if lines2 == 1:
            print 'lineSpace2:',lineSpace2
            if hasHeader3:
                if (lineSpace2 < (52*unitDict[unit])) or (lineSpace2 > (41*unitDict[unit])):
                    columnsTop -= grid
                    return headerBottom,columnsTop
            if not hasHeader3:
                if (lineSpace2 < (41*unitDict[unit])) or (lineSpace2 > (32*unitDict[unit])):
                    columnsTop -= grid
                    return headerBottom,columnsTop
                
        if lines2 == 2:
            if not hasHeader3:
                if (lineSpace2 < (37*unitDict[unit])) or (lineSpace2 > (30*unitDict[unit])):
                    columnsTop -= grid
                    return headerBottom,columnsTop
                
        if lines2 == 3:
            if (lineSpace2 < (52*unitDict[unit])) or (lineSpace2 > (41*unitDict[unit])):
                columnsTop -= grid
                return headerBottom,columnsTop

    if hasHeader3:
        pass
    
    return headerBottom,columnsTop

######################
def getHeaderHeight():
    '''Calculate header frame height using style sheet data.'''
    global chk1, para1style, para1lin 
    global chk2, para2style, para2lin
    global chk3, para3style, para3lin
    height = 0
    # Pre-header
    hasHeader1 = int(chk1.get())
    if hasHeader1:
        style = para1style.get()
        lineSpace = getStyleLineSpacing(style)
        lines = int(para1lin.get())
        lineSpace *= lines
        spMode= getStyleLineSpaceMode(style)
        if spMode == 1:
            lineSpace *= ( 1 + ( getAutoLineSpace()/100 ) )
        lineSpace += getStyleSpaceAbove(style) + getStyleSpaceBelow(style)
        height = lineSpace 
    # Header
    hasHeader2 = int(chk2.get())
    if hasHeader2:
        style = para2style.get()
        lineSpace = getStyleLineSpacing(style)
        lines = int(para2lin.get())
        lineSpace *= lines
        spMode= getStyleLineSpaceMode(style)
        if spMode == 1:
            lineSpace *= ( 1 + ( getAutoLineSpace()/100 ) )
        lineSpace += getStyleSpaceAbove(style) + getStyleSpaceBelow(style)
        height += lineSpace
    # Post-header
    hasHeader3 = int(chk3.get())
    if hasHeader3:
        style = para3style.get()
        lineSpace = getStyleLineSpacing(style)
        lines = int(para3lin.get())
        lineSpace *= lines
        spMode= getStyleLineSpaceMode(style)
        if spMode == 1:
            lineSpace *= ( 1 + ( getAutoLineSpace()/100 ) )
        lineSpace += getStyleSpaceAbove(style) + getStyleSpaceBelow(style)
        height += lineSpace
    return height

#############################
def roundToNearBaseline(num):
    '''Round vertical dimensions to near baseline grid.'''
    offset = getBaselineOffset()
    grid = getBaselineGrid()
    n = num - offset
    times,mod = divmod(n,grid)
    if (mod < (grid / 2)):
        res = offset + (times * grid)
    else:
        res = offset + (times * grid) + grid
    return res

def roundToNextBaseline(num):
    '''Round vertical dimensions to next baseline grid.'''
    offset = getBaselineOffset()
    grid = getBaselineGrid()
    n = num - offset
    times,mod = divmod(n,grid)
    res = offset + (times * grid)
    if res != num:
        res += grid
    return res

######################
def buildStory(story):
    '''Build headline frame.'''
    # get selected object dimensions 
    global storyLeft, storyTop, storyWidth, storyHeight, numCols, gutter
    global columnsFrame, headerHeight, columnsTop
    # Get frame dimensions
    storyLeft, storyTop = scribus.getPosition(story)
    storyWidth, storyHeight = scribus.getSize(story)
    
    # BUILD HEADLINES FRAME
    headerHeight = getHeaderHeight()
    headerBottom = storyTop + headerHeight
    # Round header height to baseline grid
    if snap.get() == '1':
        grid = getBaselineGrid()
        storyTop = roundToNearBaseline(storyTop)
        headerBottom = roundToNextBaseline(headerBottom)
        # Adjust some bad headerBottom
        headerBottom,columnsTop = adjustHeaderHeight(storyTop,headerBottom)
        #columnsTop = headerBottom
    else:
        columnsTop = headerBottom
    headerHeight = headerBottom - storyTop
    # Resize header frame
    scribus.moveObjectAbs(storyLeft, storyTop ,story)
    scribus.sizeObject(storyWidth, headerHeight, story)
    scribus.textFlowMode(story, 0) # 
    # Set just one column for header
    scribus.setColumns(1, story)
    
    # BUILD BODY TEXT FRAME
    columnsBottom = storyHeight + storyTop
    if snap.get() == '1':
        columnsBottom = roundToNextBaseline(columnsBottom)
    gap = float(gutter.get())
    columnsHeight = columnsBottom - columnsTop
    columnsFrame = scribus.createText(storyLeft, columnsTop, storyWidth, columnsHeight)
    scribus.textFlowMode(columnsFrame, 0)
    columnNumbers = int(numCols.get())
    scribus.setColumnGap(gap, columnsFrame)
    scribus.setColumns(columnNumbers, columnsFrame)
    
    # Draw guides
    if isToDrawGuides.get() == '1':
        # Append guides to existing guides array
        scribus.setHGuides(scribus.getHGuides() + [storyTop] + [columnsTop] + [columnsBottom])
        scribus.setVGuides(scribus.getVGuides() + [storyLeft-gap])
        scribus.setVGuides(scribus.getVGuides() + [storyLeft,(storyLeft+storyWidth)])
        scribus.setVGuides(scribus.getVGuides() + [(storyLeft+storyWidth+gap)])
        columnWidth = (storyWidth - (gap * (columnNumbers - 1))) / columnNumbers
        nextCol = storyLeft+columnWidth
        columnGuides = []
        for col in range(1,columnNumbers):
            columnGuides = columnGuides + [nextCol,(nextCol+gap)]
            nextCol = nextCol + columnWidth + gap
        scribus.setVGuides(scribus.getVGuides() + columnGuides)
    
    # Link header frame to body text frame
    scribus.linkTextFrames(story,columnsFrame)

##################
# Do all the job
def ok():
    try: root.destroy()
    except: pass
    story = scribus.getSelectedObject(0) 
    if action.get() == '1':
        buildStory(story)
    if contentSource.get() == '2':
        file = scribus.fileDialog("Open", "*.txt")
        if file != '':
            try:
                text = open(file).read()
                text = unicode(text)
            except: print 'Error reading file'
            scribus.setText(text,story)
    formatText(story)
    scribus.docChanged(True)
    quit()
###########
def quit():
    earlyExit()

def earlyExit():
    if scribus.haveDoc():
        scribus.setRedraw(True)
    scribus.statusMessage("")
    scribus.progressReset()
    try: root.destroy()
    except: pass
    sys.exit()

######################
def handleSelection():
    '''Handle object selection.'''
    global storyFrame
    if (scribus.selectionCount() < 1):
        scribus.messageBox(storyFrameLabel,askOpenFrame,ICON_WARNING,BUTTON_OK)
        earlyExit()
    else:
        pass

def vp_start_gui():
    global val, w, root
    root = Tk()
    # Center the dialog
    wid, hei = root.winfo_screenwidth(), root.winfo_screenheight()
    x = (wid - 517) / 2
    y = (hei - 363) / 2
    geo = '517x363+'+str(x)+'+'+str(y)
    #
    root.title(guiWindow)
    root.geometry(geo)
    set_Tk_var()
    w = Build_Story_dialog (root)
    init()
    handleSelection()
    root.mainloop()

def main(argv):
    if scribus.haveDoc():
        scribus.setRedraw(False)
        unit = scribus.getUnit()
        parseDoc()
        vp_start_gui()
    else:
        scribus.messageBox(openDocLabel,askOpenDoc,ICON_WARNING,BUTTON_OK)
        earlyExit()

def main_wrapper(argv):
    """"""
    try:
        scribus.statusMessage("Running script...")
        scribus.progressReset()
        main(argv)
    finally:
        if scribus.haveDoc():
            scribus.setRedraw(True)
        scribus.statusMessage("")
        scribus.progressReset()

if __name__ == '__main__':
    main_wrapper(sys.argv)