Difference between revisions of "Bullets and numbered lists"

From Scribus Wiki
Jump to: navigation, search
m (Usage)
(Code)
Line 30: Line 30:
 
# -*- coding: utf-8 -*-
 
# -*- coding: utf-8 -*-
  
 +
#!/usr/bin/env python
 +
# -*- coding: utf-8 -*-
 +
 
"""
 
"""
 
Insert marks, numbers or letters in front selected paragraphs.
 
Insert marks, numbers or letters in front selected paragraphs.
Line 36: Line 39:
 
http://meiradarocha.jor.br
 
http://meiradarocha.jor.br
 
License GPL 2.0
 
License GPL 2.0
2011-01-15a
+
2011-01-17a
 
+
 
Usage:
 
Usage:
 
======
 
======
 
Select paragraphs at any points. Dialog will ask mark type.
 
Select paragraphs at any points. Dialog will ask mark type.
Input:  
+
Input:
 
* "*" will create bulleted list.
 
* "*" will create bulleted list.
 
* A number (up 3 digit) will create a numbered list begining with such number. Ex.: "1)"
 
* A number (up 3 digit) will create a numbered list begining with such number. Ex.: "1)"
Line 47: Line 50:
 
* An optional character after numbers or letters will be used as separator. Default: dot.
 
* An optional character after numbers or letters will be used as separator. Default: dot.
 
* "/" will clear all marks.
 
* "/" will clear all marks.
 
+
 
+
 
Caveats:
 
Caveats:
========
 
 
* Cleans all text format of text selection (font, bold, subscript, etc).
 
* Cleans all text format of text selection (font, bold, subscript, etc).
* Creates paragraph style "Numbered List", "Lettered list" or "Bullet",  
+
* Creates paragraph style "Numbered List", "Lettered list" or "Bullet", if it doesn't exist, with proper indentation. Tabulation need to be defined by user to identical identation value.
if it doesn't exist, with proper indentation. Tabulation need to be defined by user to identical identation value.
+
 
* If there is no selection, script will apply marks to all text in current frame.
 
* If there is no selection, script will apply marks to all text in current frame.
 
"""
 
"""
 
+
 
import sys
 
import sys
 
import re
 
import re
 
+
import os
 +
 
try:
 
try:
 
     import scribus
 
     import scribus
Line 67: Line 68:
 
     sys.exit(1)
 
     sys.exit(1)
 
from scribus import BUTTON_OK, ICON_WARNING
 
from scribus import BUTTON_OK, ICON_WARNING
 
+
 
#######################
 
#######################
 
# Change this variables
 
# Change this variables
 
# to match your needs
 
# to match your needs
 
#######################
 
#######################
numberedListStyle = 'Numbered list'
+
numberedListParaStyle = 'Numbered list'
letteredListStyle = 'Lettered list'
+
# Font name in Scribus style. Empty string don't apply font.
bulletStyle = 'Bullet'
+
# Get font list with 'getFontNames()' <F9> in Scripter console
defaultStyle = 'Default Paragraph Style'
+
numberedListCharFont = '' 
 +
numberedListCharSize = 0  # In points. Zero don't apply font size
 +
 +
letteredListParaStyle = 'Lettered list'
 +
letteredListCharFont = '' # 
 +
letteredListCharSize = 0 # 
 +
 +
bulletedListParaStyle = 'Bullet'
 +
bulletedListCharFont = 'Dingbats Regular' # 'Wingdings Regular' # 
 +
bulletedListCharSize = 0
 +
# Put your favorite unicode char and tab: '\u2022\t' # u'•\t' # bullet U+2022
 +
# Get hex code from menu: "Insert > Special character > [magnifying button]".
 +
# Modern dingbat fonts, as Zapf Dinbats or Wingdings, need special hex codes.
 +
# URW "Dingbats Regular" Type 1 font have diferent code in Linux and in Windows,
 +
# none of them Unicode.
 +
# "ITC Zapf Digbats Regular" have same code in both OS, but not Unicode encoding.
 +
if os.name == 'posix':
 +
    bulletString = u'\u006F\t'  #  lower right drop-shadowed white square U+274F
 +
else:
 +
    bulletString = u'\uF06F\t'
 +
 +
defaultParaStyle = 'Default Paragraph Style'
 +
defaultCharStyle = 'Default Character Style'
 
separator = '.'
 
separator = '.'
 
indent = 22 # points
 
indent = 22 # points
# Put your favorite unicode char and tab: '\u2022\t'
+
# Get hex code from "Insert > Special character..." palette
+
bulletString = u'•\t'
+
 
+
 
###########
 
###########
 
# Locales
 
# Locales
 
###########
 
###########
 +
  
 
# Message to ask frame selection
 
# Message to ask frame selection
 
scriptWindowTitle = "Format list"
 
scriptWindowTitle = "Format list"
 
askSelectText = "<h2>Select a text</h2>\n" \
 
askSelectText = "<h2>Select a text</h2>\n" \
        +"Select a <b>story text</b> where you want insert numbers."
+
+"Select a <b>story text</b> where you want insert numbers."
 +
 
 
# Message to open a document
 
# Message to open a document
 
askOpenDoc = "<h2>Open a document</h2>" \
 
askOpenDoc = "<h2>Open a document</h2>" \
        +"Open a document befora run this script."
+
+"Open a document befora run this script."
 +
 
 
# Message asking select more text
 
# Message asking select more text
 
askSelectMoreText = "<h2>Select more text</h2>" \
 
askSelectMoreText = "<h2>Select more text</h2>" \
        +"Not unique text selected. Select more text before run this script."
+
+"Not unique text selected. Select more text before run this script."
wrongFrameTypeErrorMsg = "<h2>Wrong object selected</h2>" \
+
        +"You must select a <b>text frame</b>."
+
  
 +
wrongFrameTypeErrorMsg = "<h2>Wrong object selected</h2>" \
 +
+"You must select a <b>text frame</b>."
 +
 
markOperation = ''
 
markOperation = ''
 
bulletOperation = '*'
 
bulletOperation = '*'
 
numberOperation = '1'
 
numberOperation = '1'
 
cleanOperation = '/'
 
cleanOperation = '/'
alphaOperation = 'Aa'
+
alphaOperation = 'a'
 
defaultOperation = bulletOperation
 
defaultOperation = bulletOperation
 
alphabet = 'abcdefghijklmnopqrstuvwxyz'
 
alphabet = 'abcdefghijklmnopqrstuvwxyz'
Line 109: Line 134:
  
 
askOperationMsg = '<h2>What mark operation?</h2>' \
 
askOperationMsg = '<h2>What mark operation?</h2>' \
        +'<ul><li>"<b>'+bulletOperation.lower()+'</b>" input will create <b>bullet</b> marks.' \
+
+'<ul><li>"<b>'+bulletOperation.lower()+'</b>" input will create <b>bullet</b> marks.' \
        +'and apply <i>'+bulletStyle+'</i>&nbsp;&nbsp;style.' \
+
+'and apply <i>'+bulletedListParaStyle+'</i> style.' \
        +'<li>A <b>number</b> input will create <b>numbered list</b> starting <br>' \
+
+'<li>A <b>number</b> input will create <b>numbered list</b> starting <br>' \
        +'with such number and apply <i>'+numberedListStyle+'</i>&nbsp;&nbsp;style.' \
+
+'with such number and apply <i>'+numberedListParaStyle+'</i> style.' \
        +'<li>One or two <b>letters</b> input, upper or lower case, <br>' \
+
+'<li>One or two <b>letters</b> input, upper or lower case, <br>' \
        +'will create <b>lettered list</b> starting with such letters,<br>' \
+
+'will create <b>lettered list</b> starting with such letters,<br>' \
        +'and apply <i>'+letteredListStyle+'</i>&nbsp;&nbsp;style.' \
+
+'and apply <i>'+letteredListParaStyle+'</i> style.' \
        +'<li><font color="#0000ff">Optional char after number or letter<br>' \
+
+'<li><font color="#0000ff">Optional char after number or letter<br>' \
        +'will be used as separator. Default: dot. Ex.: "<b>a)</b>"</font>' \
+
+'will be used as separator. Default: dot. Ex.: "<b>a)</b>"</font>' \
        +'<li>"<b>'+cleanOperation.lower()+'</b>" input will <b>delete</b> marks ' \
+
+'<li>"<b>'+cleanOperation.lower()+'</b>" input will <b>delete</b> marks ' \
        +'and apply <br><i>'+defaultStyle+'</i>&nbsp;&nbsp;style.</li>' \
+
+'and apply <br><i>'+defaultParaStyle+'</i> style.</li>' \
        +'<li>Any <b>other</b> input will <b>cancel</b> all operations.</li></ul>' \
+
+'<li>Any <b>other</b> input will <b>cancel</b> all operations.</li></ul>' \
 
+
 
###### No need to change after this line #############
 
###### No need to change after this line #############
 
+
 
# Regular expression to match any mark:
 
# Regular expression to match any mark:
 
#  '\r' = carriage return in Python
 
#  '\r' = carriage return in Python
Line 129: Line 154:
 
#  [^\t|^\r] = non-tab or non-CR chars
 
#  [^\t|^\r] = non-tab or non-CR chars
 
#  {,4} = 0 to 4 ocurrencies from paragraph begin to tab
 
#  {,4} = 0 to 4 ocurrencies from paragraph begin to tab
reAnyMark  = r'\r[^\t|^\r]{,4}\t'  
+
reAnyMark  = r'(\r[^\t|^\r]{,4}\t)'
 
+
 
##############
 
##############
 
# Apply style
 
# Apply style
 
def applyStyle(style,frame):
 
def applyStyle(style,frame):
     '''Apply a style in selected text.  
+
     '''Apply a style in selected text.
 
     If style doesn't exist, create it.'''
 
     If style doesn't exist, create it.'''
 
     try:
 
     try:
Line 142: Line 167:
 
         scribus.setStyle(style,frame)
 
         scribus.setStyle(style,frame)
 
     return frame
 
     return frame
 
+
 
##########################
 
##########################
 
# Get text cursor position
 
# Get text cursor position
Line 157: Line 182:
 
     scribus.deselectAll()
 
     scribus.deselectAll()
 
     allText = scribus.getAllText(selectedFrame)
 
     allText = scribus.getAllText(selectedFrame)
   
+
   
 
     if allText.count(unicode(selectedText)) == 1:
 
     if allText.count(unicode(selectedText)) == 1:
 
         cur = allText.find(unicode(selectedText))
 
         cur = allText.find(unicode(selectedText))
Line 164: Line 189:
 
         scribus.selectObject(story)
 
         scribus.selectObject(story)
 
         sys.exit(1)
 
         sys.exit(1)
   
+
   
 
     return cur,allText,selectedText
 
     return cur,allText,selectedText
 
+
 
############
 
############
 
# Numbering
 
# Numbering
Line 179: Line 204:
 
     num += 1
 
     num += 1
 
     return s
 
     return s
 
+
 
####################
 
####################
 
# Lettering
 
# Lettering
 
def lettering(matchObj):
 
def lettering(matchObj):
 
     '''Function to re.sub use.'''
 
     '''Function to re.sub use.'''
    ######## bugged ################
 
 
     global num
 
     global num
 
     # Define limit to list (zz)
 
     # Define limit to list (zz)
Line 200: Line 224:
 
     num += 1
 
     num += 1
 
     return s
 
     return s
 
+
 
####################
 
####################
def insertMarks(t):
+
def processMarks(t):
 
     '''Delete old marks and insert new ones.'''
 
     '''Delete old marks and insert new ones.'''
 
     # Clear old numbers
 
     # Clear old numbers
 +
    splitedText = []
 
     s = re.sub(reAnyMark,u'\r',t)
 
     s = re.sub(reAnyMark,u'\r',t)
 
     if markOperation == numberOperation:
 
     if markOperation == numberOperation:
 
         # Insert numbers
 
         # Insert numbers
 
         s = re.sub(u'\r',numbering,s)
 
         s = re.sub(u'\r',numbering,s)
 +
        splitedText = re.split(reAnyMark,s)
 +
        print 'Split:\n',splitedText
 
     elif markOperation.isalpha():
 
     elif markOperation.isalpha():
 
         # Insert letters
 
         # Insert letters
 
         s = re.sub(u'\r',lettering,s)
 
         s = re.sub(u'\r',lettering,s)
 +
        splitedText = re.split(reAnyMark,s)
 +
        print 'Split:\n',splitedText
 
     elif markOperation == bulletOperation:
 
     elif markOperation == bulletOperation:
 
         # Insert bullets
 
         # Insert bullets
 
         b = u'\r'+bulletString
 
         b = u'\r'+bulletString
 
         s = re.sub(u'\r',b,s)
 
         s = re.sub(u'\r',b,s)
   
+
        splitedText = re.split(reAnyMark,s)
     return s
+
        print 'Split:\n',splitedText
 
+
   
 +
     return s,splitedText
 +
 +
#################
 +
# Format marks
 +
def formatMarks(begin,splitedText,story):
 +
    '''Format marks inserted by processMarks().
 +
    Use splitedText array as map to point text in story frame.'''
 +
    for m in range (1,len(splitedText),2): # element 0 is ''
 +
        text = splitedText[m]
 +
        length = len(splitedText[m])-2  # don't count '\r' and '\t'
 +
        print repr(text[1:len(text)-1])
 +
        if markOperation == bulletOperation:
 +
            if bulletedListCharFont:
 +
                scribus.selectText(begin,length,story)
 +
                try: scribus.setFont(bulletedListCharFont,story)
 +
                except: print "Can't find font:",bulletedListCharFont
 +
            if bulletedListCharSize:
 +
                scribus.selectText(begin,length,story)
 +
                try: scribus.setFontSize(bulletedListCharSize,story)
 +
                except: print "Couldn't apply list char size"
 +
        if markOperation == numberOperation:
 +
            if numberedListCharFont:
 +
                scribus.selectText(begin,length,story)
 +
                try: scribus.setFont(numberedListCharFont,story)
 +
                except: print "Can't find font:",numberedListCharFont
 +
            if numberedListCharSize:
 +
                scribus.selectText(begin,length,story)
 +
                try: scribus.setFontSize(numberedListCharSize,story)
 +
                except: print "Couldn't apply list char size"
 +
        if markOperation.isalpha():
 +
            if letteredListCharFont:
 +
                scribus.selectText(begin,length,story)
 +
                try: scribus.setFont(letteredListCharFont,story)
 +
                except: print "Can't find font:",letteredListCharFont
 +
            if letteredListCharSize:
 +
                scribus.selectText(begin,length,story)
 +
                try: scribus.setFontSize(letteredListCharSize,story)
 +
                except: print "Couldn't apply list char size"
 +
        lineAfterBullet = splitedText[m+1]
 +
        print begin,lineAfterBullet
 +
        begin = begin + length + 2 + len(unicode(lineAfterBullet))
 +
 
#################
 
#################
 
# Do all the job
 
# Do all the job
Line 238: Line 309:
 
     # Put temporary carriage return to allow numbering at string begin
 
     # Put temporary carriage return to allow numbering at string begin
 
     selectedText = u'\r'+selectedText
 
     selectedText = u'\r'+selectedText
     # Clean old numbers and insert new ones
+
     # Clean old marks and insert new ones
     cleanedText = insertMarks(unicode(selectedText))
+
     processedText,splitedText = processMarks(unicode(selectedText))
     # Strip temp initial CR
+
     # Strip temporary initial CR
     cleanedText = unicode(cleanedText)[1:]
+
     processedText = unicode(processedText)[1:]
 
     scribus.deleteText(story)
 
     scribus.deleteText(story)
     scribus.insertText(cleanedText,begin,story)
+
     scribus.insertText(processedText,begin,story)
 
     # Apply style
 
     # Apply style
 
     scribus.deselectAll()
 
     scribus.deselectAll()
 
     # Get selection new end
 
     # Get selection new end
     end = len(unicode(cleanedText))
+
     length = len(unicode(processedText))
     scribus.selectText(begin,end,story)
+
     scribus.selectText(begin,length,story)
 
     if markOperation == bulletOperation:
 
     if markOperation == bulletOperation:
         applyStyle(bulletStyle,story)
+
         applyStyle(bulletedListParaStyle,story)
 
     elif markOperation == numberOperation:
 
     elif markOperation == numberOperation:
         applyStyle(numberedListStyle,story)
+
         applyStyle(numberedListParaStyle,story)
 
     elif markOperation == cleanOperation:
 
     elif markOperation == cleanOperation:
         applyStyle(defaultStyle,story)
+
         applyStyle(defaultParaStyle,story)
 
     elif markOperation.isalpha():
 
     elif markOperation.isalpha():
         applyStyle(letteredListStyle,story)
+
         applyStyle(letteredListParaStyle,story)
 +
    # Apply special formating
 +
    formatMarks(begin,splitedText,story)
 
     scribus.selectObject(story)
 
     scribus.selectObject(story)
 
+
 
#####################
 
#####################
 
def decodeInput(res):
 
def decodeInput(res):
Line 298: Line 371:
 
     else: f = ''
 
     else: f = ''
 
     return f
 
     return f
   
+
   
 
#####################
 
#####################
 
def handleSelected():
 
def handleSelected():
 
     """Handle frame selection."""
 
     """Handle frame selection."""
 
     global markOperation,separator
 
     global markOperation,separator
     story = scribus.getSelectedObject(0)  
+
     story = scribus.getSelectedObject(0)
 
     if story:
 
     if story:
 
         res = scribus.valueDialog(scriptWindowTitle,askOperationMsg,defaultOperation)
 
         res = scribus.valueDialog(scriptWindowTitle,askOperationMsg,defaultOperation)
Line 314: Line 387:
 
     else:
 
     else:
 
         scribus.messageBox(scriptWindowTitle,askSelectText,ICON_WARNING,BUTTON_OK)
 
         scribus.messageBox(scriptWindowTitle,askSelectText,ICON_WARNING,BUTTON_OK)
 
+
###############  
+
###############
 
def main(argv):
 
def main(argv):
 
     """Main entry point."""
 
     """Main entry point."""
Line 321: Line 394:
 
         scribus.setRedraw(False)
 
         scribus.setRedraw(False)
 
         handleSelected()
 
         handleSelected()
     else:
+
     else:  
 
         scribus.messageBox(scriptWindowTitle,askOpenDoc,ICON_WARNING,BUTTON_OK)
 
         scribus.messageBox(scriptWindowTitle,askOpenDoc,ICON_WARNING,BUTTON_OK)
 
+
 
#######################
 
#######################
 
def main_wrapper(argv):
 
def main_wrapper(argv):
Line 335: Line 408:
 
         scribus.statusMessage("")
 
         scribus.statusMessage("")
 
         scribus.progressReset()
 
         scribus.progressReset()
 
+
 
if __name__ == '__main__':
 
if __name__ == '__main__':
 
     main_wrapper(sys.argv)
 
     main_wrapper(sys.argv)
 
  
 
</pre>
 
</pre>

Revision as of 21:27, 17 January 2011

This article is part of the Scripts series.

Improved bullets simple script using regular expressions Python module. Build bulleted lists; numbered lists starting with any number plus separator; upper case or lower case lettered list; and delete list marks. Create styles -- if it doesn't exists -- with proper 2 digits indentation, but is necessary set tabulation "by hand", as this can't be done by script.

Install

  1. Copy the code and paste in a text file named "Bullets.py" or whatever "*.py".
  2. Run it by "Scripts > Execute script..."
  3. In order to scripts appear in "Scripts > Scribus scripts..." menu, put the file in:* Windows folder "x:\Program files\Scribus 1.3.9\share\scripts\" or in * Linux directory (copy as root) "/usr/share/scribus-nt/scripts/" (I gess). But this folders is for official scripts and could be overwritting when Scribus reinstalls.

Usage

Select a text frame or some paragraphs and run the script by choosing "Scripts" menu, options "Execute script..." or "SCribus scripts". Asked, input the operation type:

  • "*" will create bulleted list.
  • A number (up 3 digit) will create a numbered list begining with such number. Ex.: "1)"
  • One or two letters, uppper or lower case, will create a lettered list begining with such letters with same case. Ex.: "a)"
  • "/" will clear all marks.
  • An optional character after numbers or letters will be used as separator. Default: dot.

Tested in Windows XP and Ubuntu 10.10.

Caveats

  • Will clear any character formating in selected paragraphs (fonts, bold, superscripts etc), as scribus.getText() Python function get just plain text, not formating.

Code

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

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
"""
Insert marks, numbers or letters in front selected paragraphs.
Author: prof. MS. José Antonio Meira da Rocha
mailto:joseantoniomeira@gmail.com
http://meiradarocha.jor.br
License GPL 2.0
2011-01-17a
 
Usage:
======
Select paragraphs at any points. Dialog will ask mark type.
Input:  
* "*" will create bulleted list.
* A number (up 3 digit) will create a numbered list begining with such number. Ex.: "1)"
* One or two letters uppper or lower case will create a lettered list begining with such letters. Ex.: "a)"
* An optional character after numbers or letters will be used as separator. Default: dot.
* "/" will clear all marks.
 
Caveats:
* Cleans all text format of text selection (font, bold, subscript, etc).
* Creates paragraph style "Numbered List", "Lettered list" or "Bullet", if it doesn't exist, with proper indentation. Tabulation need to be defined by user to identical identation value.
* If there is no selection, script will apply marks to all text in current frame.
"""
 
import sys
import re
import os
 
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)
from scribus import BUTTON_OK, ICON_WARNING
 
#######################
# Change this variables
# to match your needs
#######################
numberedListParaStyle = 'Numbered list'
# Font name in Scribus style. Empty string don't apply font.
# Get font list with 'getFontNames()' <F9> in Scripter console
numberedListCharFont = ''  
numberedListCharSize = 0  # In points. Zero don't apply font size
 
letteredListParaStyle = 'Lettered list'
letteredListCharFont = '' #  
letteredListCharSize = 0 #  
 
bulletedListParaStyle = 'Bullet'
bulletedListCharFont = 'Dingbats Regular' # 'Wingdings Regular' #  
bulletedListCharSize = 0
# Put your favorite unicode char and tab: '\u2022\t' # u'•\t' # bullet U+2022
# Get hex code from menu: "Insert > Special character > [magnifying button]".
# Modern dingbat fonts, as Zapf Dinbats or Wingdings, need special hex codes.
# URW "Dingbats Regular" Type 1 font have diferent code in Linux and in Windows,
# none of them Unicode.
# "ITC Zapf Digbats Regular" have same code in both OS, but not Unicode encoding.
if os.name == 'posix':
    bulletString = u'\u006F\t'  #  lower right drop-shadowed white square U+274F
else:
    bulletString = u'\uF06F\t' 
 
defaultParaStyle = 'Default Paragraph Style'
defaultCharStyle = 'Default Character Style'
separator = '.'
indent = 22 # points
 
 
###########
# Locales
###########
 

# Message to ask frame selection
scriptWindowTitle = "Format list"
askSelectText = "<h2>Select a text</h2>\n" \
+"Select a <b>story text</b> where you want insert numbers."

# Message to open a document
askOpenDoc = "<h2>Open a document</h2>" \
+"Open a document befora run this script."

# Message asking select more text
askSelectMoreText = "<h2>Select more text</h2>" \
+"Not unique text selected. Select more text before run this script."

wrongFrameTypeErrorMsg = "<h2>Wrong object selected</h2>" \
+"You must select a <b>text frame</b>."
 
markOperation = ''
bulletOperation = '*'
numberOperation = '1'
cleanOperation = '/'
alphaOperation = 'a'
defaultOperation = bulletOperation
alphabet = 'abcdefghijklmnopqrstuvwxyz'
alphabetLen = len(alphabet)

askOperationMsg = '<h2>What mark operation?</h2>' \
+'<ul><li>"<b>'+bulletOperation.lower()+'</b>" input will create <b>bullet</b> marks.' \
+'and apply <i>'+bulletedListParaStyle+'</i>  style.' \
+'<li>A <b>number</b> input will create <b>numbered list</b> starting <br>' \
+'with such number and apply <i>'+numberedListParaStyle+'</i>  style.' \
+'<li>One or two <b>letters</b> input, upper or lower case, <br>' \
+'will create <b>lettered list</b> starting with such letters,<br>' \
+'and apply <i>'+letteredListParaStyle+'</i>  style.' \
+'<li><font color="#0000ff">Optional char after number or letter<br>' \
+'will be used as separator. Default: dot. Ex.: "<b>a)</b>"</font>' \
+'<li>"<b>'+cleanOperation.lower()+'</b>" input will <b>delete</b> marks ' \
+'and apply <br><i>'+defaultParaStyle+'</i>  style.</li>' \
+'<li>Any <b>other</b> input will <b>cancel</b> all operations.</li></ul>' \
 
###### No need to change after this line #############
 
# Regular expression to match any mark:
#  '\r' = carriage return in Python
#  '\t' = tabulation in Python
#  [^\t|^\r] = non-tab or non-CR chars
#  {,4} = 0 to 4 ocurrencies from paragraph begin to tab
reAnyMark  = r'(\r[^\t|^\r]{,4}\t)'  
 
##############
# Apply style
def applyStyle(style,frame):
    '''Apply a style in selected text.  
    If style doesn't exist, create it.'''
    try:
        scribus.setStyle(style,frame)
    except:
        scribus.createParagraphStyle(name=style,leftmargin=indent,firstindent=(indent*-1))
        scribus.setStyle(style,frame)
    return frame
 
##########################
# Get text cursor position
def getTextCursor(story):
    '''Find position of text cursor in text frame.
    Text need to be selected.'''
    selectedFrame = scribus.getSelectedObject()
    try:
        selectedText = scribus.getText()
    except:
        scribus.messageBox(scriptWindowTitle,wrongFrameTypeErrorMsg,ICON_WARNING,BUTTON_OK)
        scribus.selectObject(story)
        sys.exit()
    scribus.deselectAll()
    allText = scribus.getAllText(selectedFrame)
     
    if allText.count(unicode(selectedText)) == 1:
        cur = allText.find(unicode(selectedText))
    else:
        scribus.messageBox(scriptWindowTitle,askSelectMoreText,ICON_WARNING,BUTTON_OK)
        scribus.selectObject(story)
        sys.exit(1)
     
    return cur,allText,selectedText
 
############
# Numbering
num = 0
def numbering(matchObj):
    '''Function to re.sub use.'''
    global num
    # Define limit to list
    limit = 999
    if num > limit: num = limit
    s = u'\r'+str(num)+separator+'\t'
    num += 1
    return s
 
####################
# Lettering
def lettering(matchObj):
    '''Function to re.sub use.'''
    global num
    # Define limit to list (zz)
    limit = ((alphabetLen+1) * alphabetLen)
    if num > limit: num = limit
    d1 = ((num-1) % alphabetLen)
    s1 = alphabet[d1]
    d2 = ((num-1) / alphabetLen)-1
    if d2 > -1:
        s2 = alphabet[d2]
        s1 = s2+s1
    s = u'\r'+s1+separator+'\t'
    if markOperation.isupper():
        s = s.upper()
    num += 1
    return s
 
####################
def processMarks(t):
    '''Delete old marks and insert new ones.'''
    # Clear old numbers
    splitedText = []
    s = re.sub(reAnyMark,u'\r',t)
    if markOperation == numberOperation:
        # Insert numbers
        s = re.sub(u'\r',numbering,s)
        splitedText = re.split(reAnyMark,s)
        print 'Split:\n',splitedText
    elif markOperation.isalpha():
        # Insert letters
        s = re.sub(u'\r',lettering,s)
        splitedText = re.split(reAnyMark,s)
        print 'Split:\n',splitedText
    elif markOperation == bulletOperation:
        # Insert bullets
        b = u'\r'+bulletString
        s = re.sub(u'\r',b,s)
        splitedText = re.split(reAnyMark,s)
        print 'Split:\n',splitedText
     
    return s,splitedText
 
#################
# Format marks
def formatMarks(begin,splitedText,story):
    '''Format marks inserted by processMarks().
    Use splitedText array as map to point text in story frame.'''
    for m in range (1,len(splitedText),2): # element 0 is ''
        text = splitedText[m]
        length = len(splitedText[m])-2  # don't count '\r' and '\t'
        print repr(text[1:len(text)-1])
        if markOperation == bulletOperation:
            if bulletedListCharFont:
                scribus.selectText(begin,length,story)
                try: scribus.setFont(bulletedListCharFont,story)
                except: print "Can't find font:",bulletedListCharFont
            if bulletedListCharSize:
                scribus.selectText(begin,length,story)
                try: scribus.setFontSize(bulletedListCharSize,story)
                except: print "Couldn't apply list char size"
        if markOperation == numberOperation:
            if numberedListCharFont:
                scribus.selectText(begin,length,story)
                try: scribus.setFont(numberedListCharFont,story)
                except: print "Can't find font:",numberedListCharFont
            if numberedListCharSize:
                scribus.selectText(begin,length,story)
                try: scribus.setFontSize(numberedListCharSize,story)
                except: print "Couldn't apply list char size"
        if markOperation.isalpha():
            if letteredListCharFont:
                scribus.selectText(begin,length,story)
                try: scribus.setFont(letteredListCharFont,story)
                except: print "Can't find font:",letteredListCharFont
            if letteredListCharSize:
                scribus.selectText(begin,length,story)
                try: scribus.setFontSize(letteredListCharSize,story)
                except: print "Couldn't apply list char size"
        lineAfterBullet = splitedText[m+1]
        print begin,lineAfterBullet
        begin = begin + length + 2 + len(unicode(lineAfterBullet))
 
#################
# Do all the job
def doAllOperation(story):
    '''Insert marks in front selected paragraphs or clean marks.'''
    # Get selection begin
    cur,allText,selectedText = getTextCursor(story)
    # Get first selected paragraph begin
    # (last line break position after selection)
    begin = allText.rfind(u'\r',0,cur)+1 # Scribus not use '\n'?
    # Get selection end
    end = cur+len(unicode(selectedText))
    # Get last selected paragraph end
    end = allText.find(u'\r',end)
    totalLen = end - begin
    scribus.selectText(begin,totalLen,story)
    selectedText = scribus.getText(story)
    #print '\nSelected:\n',repr(selectedText.encode('utf-8')) # debug
    # Put temporary carriage return to allow numbering at string begin
    selectedText = u'\r'+selectedText
    # Clean old marks and insert new ones
    processedText,splitedText = processMarks(unicode(selectedText))
    # Strip temporary initial CR
    processedText = unicode(processedText)[1:]
    scribus.deleteText(story)
    scribus.insertText(processedText,begin,story)
    # Apply style
    scribus.deselectAll()
    # Get selection new end
    length = len(unicode(processedText))
    scribus.selectText(begin,length,story)
    if markOperation == bulletOperation:
        applyStyle(bulletedListParaStyle,story)
    elif markOperation == numberOperation:
        applyStyle(numberedListParaStyle,story)
    elif markOperation == cleanOperation:
        applyStyle(defaultParaStyle,story)
    elif markOperation.isalpha():
        applyStyle(letteredListParaStyle,story)
    # Apply special formating
    formatMarks(begin,splitedText,story)
    scribus.selectObject(story)
 
#####################
def decodeInput(res):
    '''Parse user input.'''
    global num,separator
    f = res[0]
    # Test numbered list
    if f.isdigit():
        n = re.search('\d{1,3}',res).group()
        num = int(n)
        # Get separator
        s = re.search('[^\d]{1,1}',res)
        if s:
            separator = s.group()
        return '1'
    # Test alphabetic list
    elif f.isalpha():
        if len(res) > 1: # if there is second letter or separator
            f2 = re.search('[a-zA-Z]{1,2}',res).group()
            if len(f2) > 1:
                digit1 = f2[1].lower()
                num = alphabet.find(digit1)+1
                digit2 = f2[0].lower()
                num2 = alphabet.find(digit2)+1
                num2 = num2 * len(alphabet)
                num = num + num2
            else:
                digit1 = f2[0].lower()
                num = alphabet.find(digit1)+1
        else:
            digit1 = f.lower()
            num = alphabet.find(digit1)+1
        # Get separator
        s = re.search('[^a-zA-Z]{1,1}',res)
        if s:
            separator = s.group()
    elif f == bulletOperation: pass
    elif f == cleanOperation: pass
    else: f = ''
    return f
     
#####################
def handleSelected():
    """Handle frame selection."""
    global markOperation,separator
    story = scribus.getSelectedObject(0)  
    if story:
        res = scribus.valueDialog(scriptWindowTitle,askOperationMsg,defaultOperation)
        res = res.strip()
        if res:
            markOperation = decodeInput(res)
            if markOperation:
                doAllOperation(story)
                scribus.docChanged(True)
    else:
        scribus.messageBox(scriptWindowTitle,askSelectText,ICON_WARNING,BUTTON_OK)
 
###############  
def main(argv):
    """Main entry point."""
    if scribus.haveDoc():
        scribus.setRedraw(False)
        handleSelected()
    else:   
        scribus.messageBox(scriptWindowTitle,askOpenDoc,ICON_WARNING,BUTTON_OK)
 
#######################
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)