Bullets and numbered lists
From Scribus Wiki
(Difference between revisions)
m (→Caveats) |
(→Caveats) |
||
| Line 21: | Line 21: | ||
""" | """ | ||
| − | Insert marks | + | Insert marks, numbers or letters in front selected paragraphs. |
Author: prof. MS. José Antonio Meira da Rocha | Author: prof. MS. José Antonio Meira da Rocha | ||
mailto:joseantoniomeira@gmail.com | mailto:joseantoniomeira@gmail.com | ||
http://meiradarocha.jor.br | http://meiradarocha.jor.br | ||
License GPL 2.0 | License GPL 2.0 | ||
| − | 2011-01- | + | 2011-01-15a |
| − | |||
Usage: | Usage: | ||
| − | Select paragraphs at any points. | + | ====== |
| − | + | Select paragraphs at any points. Dialog will ask mark type. | |
| − | will create numbered list. | + | 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)" | ||
| + | * "/" will clear all marks. | ||
| + | * An optional character after numbers or letters will be used as separator. Default: dot. | ||
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" or "Bullet", if it doesn't exist, with proper indentation. Tabulation need to be defined by user to identical identation value. | + | * 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, will apply | + | * If there is no selection, script will apply marks to all text in current frame. |
""" | """ | ||
| Line 55: | Line 59: | ||
# to match your needs | # to match your needs | ||
####################### | ####################### | ||
| − | + | numberedListStyle = 'Numbered list' | |
| + | letteredListStyle = 'Lettered list' | ||
bulletStyle = 'Bullet' | bulletStyle = 'Bullet' | ||
defaultStyle = 'Default Paragraph Style' | defaultStyle = 'Default Paragraph Style' | ||
separator = '.' | separator = '.' | ||
| − | indent = | + | indent = 22 # points |
# Put your favorite unicode char and tab: '\u2022\t' | # Put your favorite unicode char and tab: '\u2022\t' | ||
# Get hex code from "Insert > Special character..." palette | # Get hex code from "Insert > Special character..." palette | ||
| Line 82: | Line 87: | ||
markOperation = '' | markOperation = '' | ||
| − | bulletOperation = ' | + | bulletOperation = '*' |
numberOperation = '1' | numberOperation = '1' | ||
| − | cleanOperation = ' | + | cleanOperation = '/' |
| − | + | alphaOperation = 'Aa' | |
| − | askOperationMsg = | + | defaultOperation = bulletOperation |
| − | +'<ul><li>"<b>'+bulletOperation.lower()+'</b>" input will create <b>bullet</b> marks. | + | 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>'+bulletStyle+'</i> style.' \ | +'and apply <i>'+bulletStyle+'</i> style.' \ | ||
| − | +'<li><b> | + | +'<li>A <b>number</b> input will create <b>numbered list</b> starting <br>with such number and apply <i>'+numberedListStyle+'</i> style.' \ |
| − | +'and apply <i>'+ | + | +'<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>'+letteredListStyle+'</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 ' \ | +'<li>"<b>'+cleanOperation.lower()+'</b>" input will <b>delete</b> marks ' \ | ||
+'and apply <br><i>'+defaultStyle+'</i> style.</li>' \ | +'and apply <br><i>'+defaultStyle+'</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 | + | ###### 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 | ||
# '\t' = tabulation in Python | # '\t' = tabulation in Python | ||
| − | # [^\t] = non-tab 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]{,4}\t' | + | reAnyMark = r'\r[^\t|^\r]{,4}\t' |
############## | ############## | ||
| Line 147: | Line 157: | ||
'''Function to re.sub use.''' | '''Function to re.sub use.''' | ||
global num | global num | ||
| + | # Define limit to list | ||
| + | limit = 999 | ||
| + | if num > limit: num = limit | ||
s = u'\r'+str(num)+separator+'\t' | s = u'\r'+str(num)+separator+'\t' | ||
| + | num += 1 | ||
| + | return s | ||
| + | |||
| + | #################### | ||
| + | # Lettering | ||
| + | def lettering(matchObj): | ||
| + | '''Function to re.sub use.''' | ||
| + | ######## bugged ################ | ||
| + | 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 | num += 1 | ||
return s | return s | ||
| Line 159: | Line 193: | ||
# Insert numbers | # Insert numbers | ||
s = re.sub(u'\r',numbering,s) | s = re.sub(u'\r',numbering,s) | ||
| + | elif markOperation.isalpha(): | ||
| + | # Insert letters | ||
| + | s = re.sub(u'\r',lettering,s) | ||
elif markOperation == bulletOperation: | elif markOperation == bulletOperation: | ||
# Insert bullets | # Insert bullets | ||
| Line 197: | Line 234: | ||
scribus.selectText(begin,end,story) | scribus.selectText(begin,end,story) | ||
if markOperation == bulletOperation: | if markOperation == bulletOperation: | ||
| − | + | applyStyle(bulletStyle,story) | |
elif markOperation == numberOperation: | elif markOperation == numberOperation: | ||
| − | + | applyStyle(numberedListStyle,story) | |
| − | + | elif markOperation == cleanOperation: | |
| − | + | applyStyle(defaultStyle,story) | |
| − | applyStyle( | + | elif markOperation.isalpha(): |
| + | applyStyle(letteredListStyle,story) | ||
scribus.selectObject(story) | scribus.selectObject(story) | ||
| + | ##################### | ||
def decodeInput(res): | def decodeInput(res): | ||
'''Parse user input.''' | '''Parse user input.''' | ||
global num,separator | global num,separator | ||
| − | f = res | + | f = res[0] |
| + | # Test numbered list | ||
if f.isdigit(): | if f.isdigit(): | ||
n = re.search('\d{1,3}',res).group() | n = re.search('\d{1,3}',res).group() | ||
num = int(n) | num = int(n) | ||
| + | # Get separator | ||
s = re.search('[^\d]{1,1}',res) | s = re.search('[^\d]{1,1}',res) | ||
if s: | if s: | ||
separator = s.group() | separator = s.group() | ||
return '1' | return '1' | ||
| − | else: | + | # Test alphabetic list |
| − | return f | + | 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 | ||
##################### | ##################### | ||
| Line 225: | Line 289: | ||
story = scribus.getSelectedObject(0) | story = scribus.getSelectedObject(0) | ||
if story: | if story: | ||
| − | res = scribus.valueDialog(scriptWindowTitle,askOperationMsg, | + | res = scribus.valueDialog(scriptWindowTitle,askOperationMsg,defaultOperation) |
res = res.strip() | res = res.strip() | ||
if res: | if res: | ||
markOperation = decodeInput(res) | markOperation = decodeInput(res) | ||
| − | + | if markOperation: | |
| − | if | + | |
doAllOperation(story) | doAllOperation(story) | ||
scribus.docChanged(True) | scribus.docChanged(True) | ||
| Line 259: | Line 322: | ||
if __name__ == '__main__': | if __name__ == '__main__': | ||
main_wrapper(sys.argv) | main_wrapper(sys.argv) | ||
| + | |||
| + | |||
</pre> | </pre> | ||
Revision as of 06:31, 16 January 2011
Improved bullets simple script using regular expressions Python module. Build bulleted lists, numbered lists starting with any number plus separator 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.
Usage
Select a frame or some paragraphs and run the script. Asked, input the operation type:
- "b" input will create bullet marks and apply "Bullet" style.
- Any number input will create numbered list, starting with such number, and will apply "Numbered List" style. Optional last char will be used as separator. Default: dot. Example: "1)", "16#", "256-".
- "x" input will delete marks and apply "Default Paragraph Style" style.
- Any other response will cancel all operations.
Caveats
Maybe will FREEZE Scribus in Ubuntu 10.04 and 10.10, as script use Pyhton module (re, regular expressions). This is a Ubuntu + Scribus Scripter bug.
#!/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-15a
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)"
* "/" will clear all marks.
* An optional character after numbers or letters will be used as separator. Default: dot.
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
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
#######################
numberedListStyle = 'Numbered list'
letteredListStyle = 'Lettered list'
bulletStyle = 'Bullet'
defaultStyle = 'Default Paragraph Style'
separator = '.'
indent = 22 # points
# Put your favorite unicode char and tab: '\u2022\t'
# Get hex code from "Insert > Special character..." palette
bulletString = u'•\t'
###########
# 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 = 'Aa'
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>'+bulletStyle+'</i> style.' \
+'<li>A <b>number</b> input will create <b>numbered list</b> starting <br>with such number and apply <i>'+numberedListStyle+'</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>'+letteredListStyle+'</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>'+defaultStyle+'</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.'''
######## bugged ################
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 insertMarks(t):
'''Delete old marks and insert new ones.'''
# Clear old numbers
s = re.sub(reAnyMark,u'\r',t)
if markOperation == numberOperation:
# Insert numbers
s = re.sub(u'\r',numbering,s)
elif markOperation.isalpha():
# Insert letters
s = re.sub(u'\r',lettering,s)
elif markOperation == bulletOperation:
# Insert bullets
b = u'\r'+bulletString
s = re.sub(u'\r',b,s)
return s
#################
# 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 numbers and insert new ones
cleanedText = insertMarks(unicode(selectedText))
# Strip temp initial CR
cleanedText = unicode(cleanedText)[1:]
scribus.deleteText(story)
scribus.insertText(cleanedText,begin,story)
# Apply style
scribus.deselectAll()
# Get selection new end
end = len(unicode(cleanedText))
scribus.selectText(begin,end,story)
if markOperation == bulletOperation:
applyStyle(bulletStyle,story)
elif markOperation == numberOperation:
applyStyle(numberedListStyle,story)
elif markOperation == cleanOperation:
applyStyle(defaultStyle,story)
elif markOperation.isalpha():
applyStyle(letteredListStyle,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)