Bullets and numbered lists
Jump to navigation
Jump to search
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:
- "*" 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.
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)