Back to index

scribus-ng  1.3.4.dfsg+svn20071115
FontSample.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 # -*- coding: utf-8 -*-
00003 
00004 # ****************************************************************************
00005 #  This program is free software; you can redistribute it and/or modify
00006 #  it under the terms of the GNU General Public License as published by
00007 #  the Free Software Foundation; either version 2 of the License, or
00008 #  (at your option) any later version.
00009 #
00010 #  This program is distributed in the hope that it will be useful,
00011 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 #  GNU General Public License for more details.
00014 #
00015 #  You should have received a copy of the GNU General Public License
00016 #  along with this program; if not, write to the Free Software
00017 #  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00018 #
00019 # ****************************************************************************
00020 
00021 """
00022 ******************************************************************************
00023 
00024 DESCRIPTION & USAGE:
00025 This script needs Tkinter. It will create a GUI with an alphabetical list
00026 of fonts using the names as they will be shown in Scribus. User can select
00027 one or more fonts and create an example sheet(s) to print or create a PDF
00028 from. It is heavily commented to make it easier for the user to adjust it
00029 for his / her own needs.
00030 
00031 Note: this version needs read/write access to .scribus directory in users
00032 home. You will also need Python Imaging Library (PIL) installed.
00033 If your system does not meet these requirements then change showPreviewPanel
00034 to a value of 0. This will disable the new preview features.
00035 
00036 ******************************************************************************
00037 
00038 First release    : 30/12/2003
00039 This release     : v0.8.1tk (released 4th Dec 2005)
00040 Copyright        : (C) 2003 - 2005 Steve Callcott
00041 Latest releases
00042 and support      : www.firstwish.co.uk/sjc/scribus/index.php
00043 Maintainer       : Steve Callcott 2003 - 2005
00044 Email            : stotte@firstwish.co.uk
00045 
00046 For revision history see the ChangeLog file.
00047 Bugs and future plans are listed in the TODO file.
00048 See NEWS for new features since last version.
00049 
00050 WHATS NEW v0.8.2tk:
00051 A one liner change by Jean Ghali to line #734 to add the extra parameter missing.
00052 See: http://bugs.scribus.net/view.php?id=4377
00053 
00054 WHATS NEW v0.8.1tk:
00055 After reloading users saved preferences the status bar was not showing
00056 correct calculations.
00057 Changed text in settings menu.
00058 
00059 WHATS NEW v0.8tk Final:
00060 Cleaned up the checkbox labels and layout.
00061 
00062 WHATS NEW v0.8tk Preview 3:
00063 Calls the new Scribus zoomDocument() function to make the completed font
00064 sample document fit in Scribus window.
00065 
00066 Grey out "Start page number count from first page" when "Print TOC" is
00067 not checked as without a table of contents the first page would always 
00068 start on the same page number making this option irrelevant.
00069 
00070 WHATS NEW v0.8tk Preview 2:
00071 Replaced the newDoc() with newDocument(). Have not put any fallback code
00072 for use with earlier Scribus versions.
00073 
00074 When using double sided option we now make use of Scribus ability to display
00075 pages side by side as default. You may need to zoom out to view the
00076 complete document width.
00077 
00078 WHATS NEW v0.8tk Preview 1:
00079 Rearanged the initialisation. If no fonts are found for the Table of
00080 Contents, page numbers and font sample labels, the script shows a
00081 message box listing the problem and a possible solution as well as a message
00082 to the console.
00083 
00084 A Scribus messagebox alerts the user if Tkinter is not found. Previously
00085 this message was only printed to the console.
00086 
00087 Now able to do a dummy run to calculate and report the amount of samples
00088 that will fit on a page. This enables the script to correctly calculate
00089 how many sheets will be required. Previously it was always assumed that
00090 there would be 3 sample blocks on a sheet. This is now not always the case.
00091 
00092 Added menu. Also added "about" and "settings" dialogs.
00093 
00094 Sample rows can be selected or unselected to save on paper. The settings are
00095 automatically saved when changed and can be set as user defaults.
00096 
00097 User can choose to have page numbers count from first page of the toc instead
00098 of the first page of samples. This can be helpful if wanting to quickly look
00099 up a font in the toc and then using the Scribus page navigator dialog to go to
00100 the actual page on the screen to view it without printing it out.
00101 
00102 Added initial support for a sample paragraph. The sample paragraph defaults
00103 to "off" due to the amount of space it uses on the page.
00104 
00105 Some widgets read their defaults from a config dictionary.
00106 
00107 Many code cleanups. Classes used for settings storage have been replaced with
00108 dictionaries to make it easier for users to customise.
00109 
00110 ******************************************************************************
00111 """
00112 
00113 import sys
00114 import os
00115 import cPickle
00116 
00117 
00118 showPreviewPanel = 1 # change to 0 to permanently hide the preview
00119 TEMP_PATH = os.path.join(os.path.expanduser('~'), '.scribus')
00120 CONFIG_PATH = os.path.join(os.path.expanduser('~'), '.scribus/fontsampler')
00121 
00122 
00123 try:
00124     import scribus
00125 except ImportError,err:
00126     print 'This Python script is written for the Scribus scripting interface.'
00127     print 'It can only be run from within Scribus.'
00128     sys.exit(1)
00129 
00130 
00131 try:
00132     from Tkinter import *
00133 except ImportError,err:
00134     print 'This script will not work without Tkinter'
00135     scribus.messageBox('Error','This script will not work without Tkinter\nPlease install and try again',
00136                     scribus.ICON_WARNING)
00137     sys.exit(1)
00138 
00139 
00140 if not os.path.exists(CONFIG_PATH):
00141     try:
00142         print 'Attempting to creating configuration file directory...'
00143         os.mkdir(CONFIG_PATH)
00144         print 'Success, now testing for write access of new directory...'
00145         if os.access(CONFIG_PATH, os.W_OK):
00146             print 'Write access ok.'
00147         else:
00148             print 'Error, unable to write to .scribus/fontsampler directory.'
00149     except:
00150         CONFIG_PATH = ''
00151         print 'Failed to make configuration file directory,'
00152         print 'do you have a .scribus directory in your home directory?'
00153         print 'font sampler will not be able to save your preferences'
00154 
00155 
00156 try:
00157     import Image
00158 except ImportError,err:
00159     print 'You need to install Python Imaging Library (PIL).'
00160     print 'If using gentoo then you need to emerge /dev-python/imaging'
00161     print 'If using an RPM based linux distribution then you add python-imaging or similar.'
00162     print 'Script will continue without the font preview panel.'
00163     showPreviewPanel = 0
00164 
00165 
00166 try:
00167     import ImageTk
00168 except ImportError,err:
00169     print 'Module ImageTk not found, font preview disabled'
00170     showPreviewPanel = 0
00171 
00172 
00173 if showPreviewPanel:
00174     if not os.path.exists(TEMP_PATH):
00175         print '.scribus folder not found, disabling font preview panel'
00176         showPreviewPanel = 0
00177     if not os.access(TEMP_PATH, os.W_OK):
00178         print 'Unable to write to .scribus folder, disabling font preview panel'
00179         showPreviewPanel = 0
00180 
00181 
00182 # A few globals for use later...
00183 gSamplePic = None
00184 gPreviewId = None
00185 
00186 #*************************************************************************
00187 
00188 WINDOW_TITLE = 'Font Sampler v0.8.1tk - Steve Callcott'
00189 SUPPORT_PAGE = 'www.firstwish.co.uk/sjc/scribus/index.php'
00190 
00191 fontsListFixed = (
00192     'Luxi Mono Regular',
00193     'Nimbus Mono L Regular',
00194     'Courier 10 Pitch Regular',
00195     'Courier New Regular',
00196     'Courier Regular',
00197     'Andale Mono Regular',
00198     'Larabiefont Regular'
00199 )
00200 
00201 fontsListProportional = (
00202     'Nimbus Sans L Regular',
00203     'Luxi Sans Regular',
00204     'Bitstream Vera Sans',
00205     'Helvetica',
00206     'Arial Regular'
00207 )
00208 
00209 defaultPrefs = {
00210     'wantDoubleSided': 0,
00211     'paperSize':'A4',           # currently PAPER_LETTER or PAPER_A4
00212     'wantTOC': 1,
00213     'wantBindingOffset': 0,
00214     'wantPageNumbers': 1,
00215     'wantPageOneOnFirst': 0,
00216     'wantAlphabet' : 1,
00217     'want6Point' : 1,
00218     'want8Point' : 1,
00219     'want10Point' : 1,
00220     'want12Point' : 1,
00221     'want16Point' : 1,
00222     'want20Point' : 1,
00223     'want32Point' : 1,
00224     'wantParagraph' : 0         # Uses a lot of space so default is off
00225 }
00226 
00227 userPrefs = {}
00228 
00229 geometriesList = [
00230     {
00231         'paperName' : 'A4',
00232         'paperSize' : scribus.PAPER_A4,
00233         'paperWidth' : 595,
00234         'paperHeight' : 842,
00235         'paperTopMargin' : 60,
00236         'paperBottomMargin' : 50,
00237         'paperLeftMargin' : 50,
00238         'paperRightMargin' : 50,
00239         'paperBinding' : 16,
00240         'tocRowsPerPage' : 57,
00241         'paperPageNumVertOffset' : 16
00242     },
00243     {
00244         'paperName' : 'US Letter',
00245         'paperSize' : scribus.PAPER_LETTER,
00246         'paperWidth' : 612,
00247         'paperHeight' : 792,
00248         'paperTopMargin' : 27,
00249         'paperBottomMargin' : 45,
00250         'paperLeftMargin' : 50,
00251         'paperRightMargin' : 50,
00252         'paperBinding' : 18,
00253         'tocRowsPerPage' : 56,
00254         'paperPageNumVertOffset' : 16
00255     }
00256 ]
00257 
00258 # define our data dictionary and some of the data...
00259 dD = {
00260     'tocHeaderTitle' : 'Table of Contents',
00261     'tocCharsInRow' : 75,
00262     'previewpanelFontHeight' : 28,
00263     'previewpanelSampleText' : 'Woven silk pyjamas exchanged for blue quartz'
00264 }
00265 
00266 samplesHeader = {
00267     'fontSize' : 16,
00268     'lineSpace' : 15,
00269     'textHeight' : 23
00270 }
00271 
00272 # Use \xBC etc to insert Hex ascii chars into the sample strings below.
00273 sampleAlphabet = {
00274     'fontSize' : 10.5,
00275     'lineSpace' : 12,
00276     'textString' : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#?$*&',
00277     'textHeight' : 18
00278 }
00279 
00280 sample6Point = {
00281     'fontSize' : 6,
00282     'lineSpace' : 6,
00283     'textString' : 'This line is in 6 point',
00284     'textHeight' : 13
00285 }
00286 
00287 sample8Point = {
00288     'fontSize' : 8,
00289     'lineSpace' : 8,
00290     'textString' : 'This line is in 8 point',
00291     'textHeight' : 16
00292 }
00293 
00294 sample10Point = {
00295     'fontSize' : 10,
00296     'lineSpace' : 11,
00297     'textString' : 'This line is in 10 point',
00298     'textHeight' : 19
00299 }
00300 
00301 sample12Point = {
00302     'fontSize' : 12,
00303     'lineSpace' : 11,
00304     'textString' : 'This line is in 12 point',
00305     'textHeight' : 21
00306 }
00307 
00308 sample16Point = {
00309     'fontSize' : 16,
00310     'lineSpace' : 13,
00311     'textString' : 'This line is in 16 point',
00312     'textHeight' : 26
00313 }
00314 
00315 sample20Point = {
00316     'fontSize' : 20,
00317     'lineSpace' : 16,
00318     'textString' : 'This line is in 20 point',
00319     'textHeight' : 31
00320 }
00321 
00322 sample32Point = {
00323     'fontSize' : 32,
00324     'lineSpace' : 29,
00325     'textString' : 'This line is in 32 point',
00326     'textHeight' : 49
00327 }
00328 
00329 sampleParagraph = {
00330     'fontSize' : 9,
00331     'lineSpace' : 10.8,
00332     'textHeight' : 175
00333 }
00334 
00335 sampleParagraphText = 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut a sapien. \
00336 Aliquam aliquet purus molestie dolor. Integer quis eros ut erat posuere dictum. \
00337 Curabitur dignissim. Integer orci. Fusce vulputate lacus at ipsum. Quisque in libero \
00338 nec mi laoreet volutpat. Aliquam eros pede, scelerisque quis, tristique cursus, \
00339 placerat convallis, velit. Nam condimentum. Nulla ut mauris. Curabitur adipiscing, \
00340 mauris non dictum aliquam, arcu risus dapibus diam, nec sollicitudin quam erat quis \
00341 ligula. Aenean massa nulla, volutpat eu, accumsan et, fringilla eget, odio. \
00342 Nulla placerat porta justo. Nulla vitae turpis.\n\nPraesent lacus.Lorem ipsum dolor sit \
00343 amet, consectetuer adipiscing elit. Pellentesque habitant morbi tristique senectus \
00344 et netus et malesuada fames ac turpis egestas. Quisque vel erat eget diam \
00345 consectetuer iaculis. Cras ante velit, suscipit et, porta tempus, dignissim quis, \
00346 magna. Vivamus viverra, turpis nec rhoncus ultricies, diam turpis eleifend nisl, a \
00347 eleifend ante felis ac sapien. Integer bibendum. Suspendisse in mi non neque \
00348 bibendum convallis. Suspendisse potenti. Sed sit amet purus at felis adipiscing \
00349 aliquam. Vivamus et nisl sit amet mauris aliquet molestie. Integer tortor massa, \
00350 aliquam a, lacinia nonummy, sagittis nec, eros.'
00351 
00352 #*************************************************************************
00353 
00354 def set_font_fixed(fontList):
00355     """Find a matching font for the Table of Contents."""
00356     availableFonts = scribus.getFontNames()
00357     found = 0
00358     for f in fontList:
00359         if found:
00360             break
00361         for i in availableFonts:
00362             if not found:
00363                 if f == i:
00364                     return f
00365                     found = 1
00366                     break
00367     if not found:
00368         errorList = ''
00369         for j in fontList:
00370             errorList = errorList + j + '\n'
00371         errorMessage ='No suitable fixed width font found.\nPlease install at least one of these fixed width fonts:\n'+errorList
00372         print errorMessage
00373         raise Exception(errorMessage)
00374 
00375 
00376 def set_font_proportional(fontList):
00377     """Find a matching font for the page numbers and font names above samples."""
00378     availableFonts = scribus.getFontNames()
00379     found = 0
00380     for p in fontList:
00381         if found:
00382             break
00383         for i in availableFonts:
00384             if not found:
00385                 if p == i:
00386                     return p
00387                     found = 1
00388                     break
00389     if not found:
00390         errorList = ''
00391         for j in fontList:
00392             errorList = errorList + j + '\n'
00393         errorMessage = 'No suitable proportional font found.\nPlease install at least one of these proportional fonts:\n'+errorList
00394         print errorMessage
00395         raise Exception(errorMessage)
00396 
00397 
00398 def save_user_conf(path):
00399     """Save the data to the save file on the path specified by CONFIG_PATH.
00400 
00401     Note initialisation unsets the CONFIG_PATH if it failed to verify or create"""
00402     if not path == '':
00403         try:
00404             file = open(os.path.join(path,'fontsampler.conf'), 'w')
00405             data = {
00406                 'a' : defaultPrefs,
00407                 'b' : userPrefs
00408             }
00409             cPickle.dump(data, file)
00410             file.close()
00411         except:
00412             print 'failed to save data'
00413 
00414 
00415 def restore_user_conf(path):
00416     """Restore the data from the save file on the path specified by CONFIG_PATH."""
00417     try:
00418         file = open(os.path.join(path,'fontsampler.conf'), 'r')
00419         data = cPickle.load(file)
00420         file.close()
00421         defaultPrefs.update(data['a'])
00422         userPrefs.update(data['b'])
00423     except:
00424         userPrefs.update(defaultPrefs)
00425         print 'failed to load saved data so using default values defined in the script'
00426 
00427 
00428 def set_page_geometry(dD, geometriesList, paperSize, wantBindingOffset):
00429     """This is the experimental replacement paper size setting function.
00430 
00431     Each paper size and other associated data are stored in a dictionary.
00432     The dictionaries are stored in a list. We copy appropriate dictionary
00433     and custom calculations into a work dictionary for use.
00434     The advantage of this is its easier to add new paper definitions.
00435     Returns a new dictionary, use .update to merge in new values into dD.
00436     """
00437     try:
00438         result={}
00439         for i in geometriesList:
00440             if i['paperName'] == paperSize:
00441                 dD.update(i)
00442 
00443         result['paperLeftMarginOdd'] = dD['paperLeftMargin'] + \
00444                                        dD['paperBinding']
00445         result['paperRightMarginEven'] = dD['paperRightMargin'] + \
00446                                          dD['paperBinding']
00447         result['paperTextHeight'] = dD['paperHeight'] - \
00448                                     dD['paperTopMargin'] - \
00449                                     dD['paperBottomMargin']
00450         result['paperMargins'] =  dD['paperLeftMargin'],dD['paperRightMargin'],dD['paperTopMargin'],dD['paperBottomMargin']
00451 
00452         # if we are adding a binding offset to the margins then we will have less width for our text...
00453         if wantBindingOffset:
00454             result['paperTextWidth'] = dD['paperWidth'] - \
00455                                        dD['paperLeftMargin'] - \
00456                                        dD['paperRightMargin'] - \
00457                                        dD['paperBinding'] - \
00458                                        2
00459         else:
00460             result['paperTextWidth'] = dD['paperWidth'] - \
00461                                        dD['paperLeftMargin'] - \
00462                                        dD['paperRightMargin'] - \
00463                                        2
00464         return result
00465     except:
00466         errorMessage = 'set_page_geometry() failure: %s' % sys.exc_info()[1]
00467         print errorMessage
00468 
00469 
00470 def set_odd_even(pageNum):
00471     """ Sets the left margin position.
00472 
00473     Checks the number passed to it and sets left margin accordingly.
00474     Call once after each new page is created.
00475     Returns 1 if even and 0 if odd page.
00476     """
00477     if pageNum % 2 == 0:
00478         isEvenPage = 1                                          # Even side
00479     else:
00480         isEvenPage = 0                                          # Odd side
00481 
00482     if userPrefs['wantBindingOffset']:
00483         if isEvenPage and userPrefs['wantDoubleSided']:         # Even (when double sided)
00484             dD['paperLeftSide'] = dD['paperLeftMargin'] + 1
00485         else:                                                   # Odd side
00486             dD['paperLeftSide'] = dD['paperLeftMarginOdd'] + 1
00487     else:                                                       # No binding
00488         dD['paperLeftSide'] = dD['paperLeftMargin'] + 1
00489     return isEvenPage
00490 
00491 
00492 def draw_sample_row(font, fontSize, lineSpace, textString, x, y, w, h, getSizeOnly):
00493     """Creates one row of samples or a header for the top of the block.
00494 
00495     Called once by draw_sample_block() to create a block label then as many times
00496     as required to create each actual sample found in the list of dictionaries
00497     containing each samples definition.
00498     """
00499     if not getSizeOnly:
00500         f = scribus.createText(x, y, w, h)
00501         scribus.insertText(textString, 0, f)
00502         scribus.setFont(font, f)
00503         scribus.setFontSize(fontSize, f)
00504         scribus.setLineSpacing(lineSpace, f)
00505         scribus.setTextAlignment(0, f)
00506     return y + h + 1
00507 
00508 
00509 def draw_sample_block(fontName, x, y, w, getSizeOnly):
00510     """Drawing of a complete sample block starts from here.
00511 
00512     Iterates through each sample declared in the "samples" tuple. Places one
00513     complete block using the font specified in fontname.
00514     Note top line on page is drawn outside of this function. This ensures ease
00515     of returning same height of every sample block. Line could have been drawn
00516     at top inside this function and page finalised with line at bottom instead.
00517     If getSizeOnly is true then returns the overall height of the entire text
00518     block but without actually placing it.
00519     """
00520     startPos = y
00521     # Note there are 2 points of space before horizontal line at bottom of block.
00522     # This 2 points will not appear at top of page so need to add it.
00523 
00524     # set space below horizontal line to the top of the text block
00525     y = y + 4
00526 
00527     # (note there is one extra point inserted by addSampleRow() for each row generated)...
00528 
00529     # first need a header...
00530     y = draw_sample_row(dD['bookstylePropFont'], samplesHeader['fontSize'], samplesHeader['lineSpace'], fontName, x, y, w, samplesHeader['textHeight'], getSizeOnly)
00531 
00532     if userPrefs['wantAlphabet']:
00533         y = draw_sample_row(fontName, sampleAlphabet['fontSize'], sampleAlphabet['lineSpace'], sampleAlphabet['textString'], x, y, w, sampleAlphabet['textHeight'], getSizeOnly)
00534 
00535     if userPrefs['want6Point']:
00536         y = draw_sample_row(fontName, sample6Point['fontSize'], sample6Point['lineSpace'], sample6Point['textString'], x, y, w, sample6Point['textHeight'], getSizeOnly)
00537 
00538     if userPrefs['want8Point']:
00539         y = draw_sample_row(fontName, sample8Point['fontSize'], sample8Point['lineSpace'], sample8Point['textString'], x, y, w, sample8Point['textHeight'], getSizeOnly)
00540 
00541     if userPrefs['want10Point']:
00542         y = draw_sample_row(fontName, sample10Point['fontSize'], sample10Point['lineSpace'], sample10Point['textString'], x, y, w, sample10Point['textHeight'], getSizeOnly)
00543 
00544     if userPrefs['want12Point']:
00545         y = draw_sample_row(fontName, sample12Point['fontSize'], sample12Point['lineSpace'], sample12Point['textString'], x, y, w, sample12Point['textHeight'], getSizeOnly)
00546 
00547     if userPrefs['want16Point']:
00548         y = draw_sample_row(fontName, sample16Point['fontSize'], sample16Point['lineSpace'], sample16Point['textString'], x, y, w, sample16Point['textHeight'], getSizeOnly)
00549 
00550     if userPrefs['want20Point']:
00551         y = draw_sample_row(fontName, sample20Point['fontSize'], sample20Point['lineSpace'], sample20Point['textString'], x, y, w, sample20Point['textHeight'], getSizeOnly)
00552 
00553     if userPrefs['want32Point']:
00554         y = draw_sample_row(fontName, sample32Point['fontSize'], sample32Point['lineSpace'], sample32Point['textString'], x, y, w, sample32Point['textHeight'], getSizeOnly)
00555 
00556     if userPrefs['wantParagraph']:
00557         y = draw_sample_row(fontName, sampleParagraph['fontSize'], sampleParagraph['lineSpace'], sampleParagraphText, x, y, w, sampleParagraph['textHeight'], getSizeOnly)
00558 
00559     y = y + 1   # one extra point of space above bottom Horiz. line
00560 
00561     lineHeight = draw_horiz_line(y, x, w + x, getSizeOnly)
00562     y = y + lineHeight
00563 
00564     return y - startPos
00565 
00566 
00567 def insert_toc_row(fontName, pageNum, yPos, frame):
00568     """Called once for each content line to be drawn in the text frame."""
00569     dotLine = ""
00570     dotQuant = dD['tocCharsInRow'] - len(fontName) - len(str(pageNum)) + 1
00571     for i in range(dotQuant):
00572         dotLine = dotLine + '.'
00573     oneLine = fontName + dotLine + str(pageNum) + "\n"
00574     scribus.insertText(oneLine, yPos, frame)
00575     yPos = yPos + len(oneLine) + 0
00576     return yPos
00577 
00578 
00579 def build_toc_page_template():
00580     """Inserts empty toc template into the currently selected page."""
00581     # first put a header on the empty page...
00582     textstring = dD['tocHeaderTitle']
00583     yPos = dD['paperTopMargin'] + 1
00584     header = scribus.createText(dD['paperLeftSide'], yPos, dD['paperTextWidth'], 35)
00585     scribus.insertText(textstring, 0, header)
00586     scribus.setFont(dD['bookstylePropFont'], header)
00587     scribus.setFontSize(24, header)
00588     scribus.setTextAlignment(1, header)
00589     # now create a text frame for the table of contents...
00590     yPos = yPos + 36
00591     body = scribus.createText(dD['paperLeftSide'], yPos, dD['paperTextWidth'], dD['paperHeight'] - yPos - dD['paperBottomMargin'] - 1)
00592     scribus.setFont(dD['bookstyleFixedFont'], body)
00593     scribus.setFontSize(10, body)
00594     scribus.setLineSpacing(12, body)
00595     return body
00596 
00597 
00598 def build_toc(tocList):
00599     """Creates all the Table of Contents pages.
00600 
00601     Calls tocPageFramesBuild() to write the header and empty frame for the
00602     toc rows each time a new page is added.
00603     Then calls tocRowAdd() to add each line to the toc frame. Creates new page
00604     each time it completes last row on page.
00605     """
00606     rowCount = 0
00607     yPos = 0
00608     tocPageNum = 1
00609     tocPageCount = 1
00610 
00611     scribus.newPage(tocPageNum)
00612     isEvenPage = set_odd_even(tocPageNum)
00613     body = build_toc_page_template()             # create frames for new empty page
00614     if isEvenPage == 0:
00615         scribus.setTextAlignment(2, body)
00616     else:
00617         scribus.setTextAlignment(0, body)
00618     for i in tocList:
00619         if rowCount == dD['tocRowsPerPage']: # Need to build a new TOC page (count is from zero, not one)
00620             tocPageNum = tocPageNum + 1
00621             scribus.newPage(tocPageNum)
00622             isEvenPage = set_odd_even(tocPageNum)
00623             body = build_toc_page_template()
00624             if not isEvenPage:
00625                 scribus.setTextAlignment(2, body)
00626             else:
00627                 scribus.setTextAlignment(0, body)
00628             rowCount = 0
00629             yPos = 0
00630             tocPageCount = tocPageCount + 1
00631         yPos = insert_toc_row(i[0], i[1], yPos, body)
00632         rowCount = rowCount + 1
00633     if userPrefs['wantDoubleSided']:
00634         if tocPageCount % 2 != 0:           # Odd page
00635             tocPageNum = tocPageNum + 1
00636             scribus.newPage(tocPageNum)     # Add an extra page if odd number
00637 
00638 
00639 def add_page_num(pageNum):
00640     yPos = dD['paperHeight'] - \
00641            dD['paperBottomMargin'] - \
00642            dD['paperPageNumVertOffset']
00643     footer = scribus.createText(dD['paperLeftSide'], yPos, dD['paperTextWidth'], 15)
00644     scribus.insertText('%s' % pageNum, 0, footer)
00645     scribus.setFont(dD['bookstylePropFont'], footer)
00646     scribus.setFontSize(9, footer)
00647     scribus.setTextAlignment(1, footer)
00648     scribus.setLineSpacing(10, footer)
00649 
00650 
00651 def create_empty_samplepage(pageNum, getSizeOnly):
00652     """Creates a new page and increments page number by one.
00653 
00654     Note getSizeOnly is now evaluated. Will still generate page number increment
00655     but will not actually create the new page or place the number on the page."""
00656     if not getSizeOnly:
00657         scribus.newPage(-1)
00658     pageNum = pageNum + 1
00659     set_odd_even(pageNum)
00660     if not getSizeOnly:
00661         if userPrefs['wantPageNumbers']:
00662             add_page_num(pageNum)
00663     return pageNum
00664 
00665 
00666 def draw_horiz_line(yPos, xStart, xEnd, getSizeOnly):
00667     """Draws a line and returns the height.
00668 
00669     If getSizeOnly is set then returns the height it would have
00670     used but without actually creating a line.
00671     """
00672     lineWidth = 1
00673     if not getSizeOnly:
00674         newLine = scribus.createLine(xStart, yPos, xEnd, yPos)
00675         scribus.setLineWidth(lineWidth, newLine)
00676     return lineWidth
00677 
00678 
00679 def draw_selection(fontList, getSizeOnly):
00680     """Draws the sample blocks onto the Scribus canvas.
00681 
00682     Measure one font sample block including any horizontal lines and extra
00683     vertical spaces.
00684     Get the amount of vertical space available for the text area between the
00685     top line and top of page number area.
00686     Use these two values to calculate how many complete sample blocks will fit
00687     in the space available. This is the "pageBlocks"
00688     Note we always draw the top horizontal line before placing the blocks. This
00689     is taken into account when calculating the available text area.
00690     Next, if "getSizeOnly" is false we create a page then create the sample
00691     blocks while incrementing a counter until it matches the "pageBlocks".
00692     Reset the counter and create new page. We keep going until we have processed
00693     all the fonts in the selection list.
00694     We update the Scribus progress bar as we create each font sample block.
00695     The returned result is used to update some values in the status bar.
00696     """
00697     progress = 1
00698     scribus.progressReset()
00699     scribus.progressTotal(len(fontList))
00700     tocList = []
00701     pageNum = 1
00702     blockCounter = 0
00703     counter = 0
00704     facingPages = scribus.NOFACINGPAGES
00705     
00706     # Just get blocks per page value...
00707     set_odd_even(pageNum)
00708     lineHeight = 1 # include the one point of space below top margin
00709     lineHeight = lineHeight + draw_horiz_line(0, dD['paperLeftSide'], dD['paperLeftSide'] + dD['paperTextWidth'], 1)
00710     usuableArea = dD['paperHeight'] - \
00711                   dD['paperTopMargin'] - \
00712                   lineHeight - \
00713                   dD['paperBottomMargin'] - \
00714                   dD['paperPageNumVertOffset']
00715 
00716     blockHeight = draw_sample_block(fontList[0], dD['paperLeftSide'], 0, dD['paperTextWidth'], 1)
00717     pageBlocks = int(usuableArea / blockHeight)
00718     #print blockHeight
00719     #print "Usuable area %s points high" % usuableArea
00720     #print "Used space on page is %s points high" % (blockHeight * pageBlocks)
00721 
00722     if not getSizeOnly:
00723         # not a dummy run so start by setting up page numbering...
00724         if userPrefs['wantPageOneOnFirst'] and userPrefs['wantTOC']:
00725             tocPageCount = divmod(len(fontList), dD['tocRowsPerPage'])
00726             pageNum = pageNum + tocPageCount[0]
00727             if tocPageCount[1] != 0:
00728                 # (adding more to page number as not whole number)
00729                 pageNum = pageNum + 1
00730             if userPrefs['wantDoubleSided']:
00731                 oddEvenTest = divmod(pageNum, 2)
00732                 if oddEvenTest[1] == 0:
00733                     # (adding extra one to start number as odd amount)
00734                     pageNum = pageNum + 1
00735         if userPrefs['wantDoubleSided']:
00736             facingPages = scribus.FACINGPAGES
00737         # now create a new document with empty page and start building...
00738         scribus.newDocument(dD['paperSize'], dD['paperMargins'], scribus.PORTRAIT, 1, scribus.UNIT_POINTS, facingPages, scribus.FIRSTPAGERIGHT, 1)
00739         scribus.zoomDocument(-100)
00740         # A new doc gives us a new page by default so set it up first...
00741         set_odd_even(pageNum)
00742         yPos = dD['paperTopMargin'] + 1
00743         lineHeight = draw_horiz_line(yPos, dD['paperLeftSide'], dD['paperLeftSide'] + dD['paperTextWidth'], getSizeOnly)
00744         yPos = yPos + lineHeight
00745         if userPrefs['wantPageNumbers']:
00746             add_page_num(pageNum)
00747         for i in fontList:
00748             # Now place the actual sample block but create a new page if needed...
00749             if counter == pageBlocks:
00750                 pageNum = create_empty_samplepage(pageNum, getSizeOnly)
00751                 yPos = dD['paperTopMargin'] + 1
00752                 lineHeight = draw_horiz_line(yPos, dD['paperLeftSide'], dD['paperLeftSide'] + dD['paperTextWidth'], getSizeOnly)
00753                 yPos = yPos + lineHeight
00754                 counter = 0
00755             blockHeight = draw_sample_block(i, dD['paperLeftSide'], yPos, dD['paperTextWidth'], getSizeOnly)
00756             yPos = yPos + blockHeight
00757             # and also increment the Scribus progress bar...
00758             scribus.progressSet(progress)
00759             progress = progress + 1
00760             # Add current font to TOC...
00761             tocList.append([i, pageNum])
00762             counter = counter + 1
00763         if userPrefs['wantTOC']:
00764             # Insert table of contents - (before page numbering)...
00765             build_toc(tocList)
00766         scribus.gotoPage(1)
00767     return pageBlocks
00768 
00769 
00770 def preview_font(app, fontName):
00771     """Gets the named font and puts a sample in the preview panel.
00772 
00773     Pick up the temp sample qpixmap file and display it in a canvas object
00774     The temp file is put in the users ".scribus" folder and cleaned up on exit.
00775     We create samplePic as a global as a workaround because the reference count
00776     does not increase when we add the image to the canvas. Therefore python
00777     garbage collection removes our image before we have even displayed it.
00778     Note app.previewPanel is the actual canvas.
00779     """
00780     global gSamplePic
00781     global gPreviewId
00782     scribus.renderFont(fontName, os.path.join(TEMP_PATH,'temp079r.bmp'),dD['previewpanelSampleText'],dD['previewpanelFontHeight'])
00783     try:
00784         tempPic = Image.open(os.path.join(TEMP_PATH,'temp079r.bmp'))
00785         tempPic.save(os.path.join(TEMP_PATH,'temp079r.jpeg'),format='JPEG')
00786         tempImage = Image.open(os.path.join(TEMP_PATH,'temp079r.jpeg'))
00787         imgDimen = tempPic.getbbox()
00788         gSamplePic = ImageTk.PhotoImage(tempImage)
00789         # To center the image use "Half display height minus half the image height"
00790         # preview panel is allegedly 56 (60 less a 2 pixel border top and bottom)
00791         # need to be lower than that to look correct visually...
00792         topEdge = (32 - (imgDimen[3] / 2))
00793         gPreviewId = app.previewPanel.create_image(5, topEdge, anchor=NW, image=gSamplePic)
00794         os.remove(os.path.join(TEMP_PATH,'temp079r.bmp'))
00795         os.remove(os.path.join(TEMP_PATH,'temp079r.jpeg'))
00796     except IOError:
00797         gSamplePic = None
00798         gPreviewId = app.previewPanel.create_image(0, 0, anchor=NW, image=gSamplePic)
00799     return
00800 
00801 
00802 class AboutDialog(Toplevel):
00803 
00804     def __init__(self, parent):
00805         Toplevel.__init__(self, parent)
00806         self.transient(parent)
00807         self.title('About')
00808         self.parent = parent
00809         self.result = None
00810         self.resizable(0, 0)
00811 
00812         infoLabel = Label(self, text=WINDOW_TITLE+'\nSupport page at %s' % SUPPORT_PAGE)
00813         infoLabel.pack(padx=5, pady=5)
00814         # now the frame for contents...
00815         contentFrame = Frame(self)
00816         self.btnOk = Button(contentFrame, text='OK', command=self.ok, default=ACTIVE)
00817         self.btnOk.pack(side=LEFT, padx=5, pady=5)
00818         contentFrame.pack()
00819         self.bind('<Return>', self.ok)
00820         self.grab_set()
00821         self.protocol('WM_DELETE_WINDOW', self.ok)
00822         self.initial_focus = self.btnOk
00823         self.wait_window(self)
00824 
00825     def ok(self, event=None):
00826         self.withdraw()
00827         self.update_idletasks()
00828         self.parent.focus_set()
00829         self.destroy()
00830 
00831 
00832 class ConfigurationDialog(Toplevel):
00833 
00834     def __init__(self, parent):
00835         Toplevel.__init__(self, parent)
00836         self.transient(parent)
00837         self.title('Configuration')
00838         self.parent = parent
00839         self.result = None
00840         self.resizable(0, 0)
00841 
00842         # Create outer frame...
00843         self.topFrame = Frame(self, bd=1, relief=FLAT)
00844         self.topFrame.grid(row=0, column=0, padx=5, pady=5)
00845 
00846         self.paperSizeLabel = Label(self.topFrame, text='Sample Rows:')
00847         self.paperSizeLabel.grid(row=0, column=0, sticky=W)
00848 
00849         # This frame holds each sample selector...
00850         self.sampleSelectFrame = Frame(self.topFrame, bd=1, relief=RIDGE)
00851         self.sampleSelectFrame.grid(row=1, column=0, padx=0, pady=2)
00852 
00853         # now create the sample selector widgets for the frame...
00854         self.__wantAlphabet = IntVar()
00855         self.btnWantAlphabet = Checkbutton(self.sampleSelectFrame, text='want alphabet row', variable=self.__wantAlphabet, offvalue=0, onvalue=1, command=self.__sampleSelectionClick)
00856         self.btnWantAlphabet.grid(row=0, column=0, padx=10, pady=0, sticky=W)
00857         if userPrefs['wantAlphabet']:
00858             self.btnWantAlphabet.select()
00859 
00860         self.__want6Point = IntVar()
00861         self.btnWant6Point = Checkbutton(self.sampleSelectFrame, text='want 6 point row', variable=self.__want6Point, offvalue=0, onvalue=1, command=self.__sampleSelectionClick)
00862         self.btnWant6Point.grid(row=1, column=0, padx=10, pady=0, sticky=W)
00863         if userPrefs['want6Point']:
00864             self.btnWant6Point.select()
00865 
00866         self.__want8Point = IntVar()
00867         self.btnWant8Point = Checkbutton(self.sampleSelectFrame, text='want 8 point row', variable=self.__want8Point, offvalue=0, onvalue=1, command=self.__sampleSelectionClick)
00868         self.btnWant8Point.grid(row=2, column=0, padx=10, pady=0, sticky=W)
00869         if userPrefs['want8Point']:
00870             self.btnWant8Point.select()
00871 
00872         self.__want10Point = IntVar()
00873         self.btnWant10Point = Checkbutton(self.sampleSelectFrame, text='want 10 point row', variable=self.__want10Point, offvalue=0, onvalue=1, command=self.__sampleSelectionClick)
00874         self.btnWant10Point.grid(row=3, column=0, padx=10, pady=0, sticky=W)
00875         if userPrefs['want10Point']:
00876             self.btnWant10Point.select()
00877 
00878         self.__want12Point = IntVar()
00879         self.btnWant12Point = Checkbutton(self.sampleSelectFrame, text='want 12 point row', variable=self.__want12Point, offvalue=0, onvalue=1, command=self.__sampleSelectionClick)
00880         self.btnWant12Point.grid(row=4, column=0, padx=10, pady=0, sticky=W)
00881         if userPrefs['want12Point']:
00882             self.btnWant12Point.select()
00883 
00884         self.__want16Point = IntVar()
00885         self.btnWant16Point = Checkbutton(self.sampleSelectFrame, text='want 16 point row', variable=self.__want16Point, offvalue=0, onvalue=1, command=self.__sampleSelectionClick)
00886         self.btnWant16Point.grid(row=5, column=0, padx=10, pady=0, sticky=W)
00887         if userPrefs['want16Point']:
00888             self.btnWant16Point.select()
00889 
00890         self.__want20Point = IntVar()
00891         self.btnWant20Point = Checkbutton(self.sampleSelectFrame, text='want 20 point row', variable=self.__want20Point, offvalue=0, onvalue=1, command=self.__sampleSelectionClick)
00892         self.btnWant20Point.grid(row=6, column=0, padx=10, pady=0, sticky=W)
00893         if userPrefs['want20Point']:
00894             self.btnWant20Point.select()
00895 
00896         self.__want32Point = IntVar()
00897         self.btnWant32Point = Checkbutton(self.sampleSelectFrame, text='want 32 point row', variable=self.__want32Point, offvalue=0, onvalue=1, command=self.__sampleSelectionClick)
00898         self.btnWant32Point.grid(row=7, column=0, padx=10, pady=0, sticky=W)
00899         if userPrefs['want32Point']:
00900             self.btnWant32Point.select()
00901 
00902         self.__wantParagraph = IntVar()
00903         self.btnParagraphSelect = Checkbutton(self.sampleSelectFrame, text='want sample paragraph', variable=self.__wantParagraph, offvalue=0, onvalue=1, command=self.__sampleSelectionClick)
00904         self.btnParagraphSelect.grid(row=8, column=0, padx=10, pady=0, sticky=W)
00905         if userPrefs['wantParagraph']:
00906             self.btnParagraphSelect.select()
00907 
00908         self.paperSizeLabel = Label(self.topFrame, text='Paper Sizes:')
00909         self.paperSizeLabel.grid(row=2, column=0, sticky=W)
00910 
00911         self.paperSizeFrame = Frame(self.topFrame, bd=1, relief=RIDGE)
00912         self.paperSizeFrame.grid(row=3, column=0, padx=0, pady=2, sticky=W)
00913 
00914         self.__paper = StringVar()
00915         self.a4papersizeSelect = Radiobutton(self.paperSizeFrame, text='A4', variable=self.__paper, value='A4', command=self.__paperSelectionClick)
00916         self.a4papersizeSelect.grid(row=1, column=0, padx=10, sticky=W)
00917         self.uspapersizeSelect = Radiobutton(self.paperSizeFrame, text='US Letter', variable=self.__paper, value='US Letter', command=self.__paperSelectionClick)
00918         self.uspapersizeSelect.grid(row=2, column=0, padx=10, sticky=W)
00919 
00920         # set to match prefs...
00921         if userPrefs['paperSize'] == 'US Letter':
00922             self.uspapersizeSelect.select()
00923         if userPrefs['paperSize'] == 'A4':
00924             self.a4papersizeSelect.select()
00925 
00926         self.btnFrame = Frame(self.topFrame)
00927         self.btnFrame.grid(row=4, column=0, padx=10, pady=2)
00928         self.btnOk = Button(self.btnFrame, text='OK', command=self.ok)
00929         self.btnOk.grid(row=2, column=0, pady=5)
00930         self.bind('<Return>', self.ok)
00931         self.grab_set()
00932         self.initial_focus = self.btnOk
00933         self.wait_window(self)
00934 
00935 
00936     def __sampleSelectionClick(self):
00937         """Get and store all the selections.
00938         
00939         Just assigns the lot at once. Not worth being picky and only
00940         assigning values that have changed since last time.
00941         """
00942         userPrefs['wantAlphabet'] = self.__wantAlphabet.get()
00943         userPrefs['want6Point'] = self.__want6Point.get()
00944         userPrefs['want8Point'] = self.__want8Point.get()
00945         userPrefs['want10Point'] = self.__want10Point.get()
00946         userPrefs['want12Point'] = self.__want12Point.get()
00947         userPrefs['want16Point'] = self.__want16Point.get()
00948         userPrefs['want20Point'] = self.__want20Point.get()
00949         userPrefs['want32Point'] = self.__want32Point.get()
00950         userPrefs['wantParagraph'] = self.__wantParagraph.get()
00951         self.parent.statusbarUpdate()
00952 
00953     def __paperSelectionClick(self):
00954         userPrefs['paperSize'] = self.__paper.get()
00955         self.parent.statusbarUpdate()
00956 
00957     def ok(self, event=None):
00958         dD.update(set_page_geometry(dD, geometriesList, userPrefs['paperSize'], userPrefs['wantBindingOffset']))
00959         self.withdraw()
00960         self.update_idletasks()
00961         self.parent.focus_set()
00962         self.destroy()
00963 
00964 
00965 class Application(Frame):
00966 
00967     def __init__(self, master = None):
00968         Frame.__init__(self, master)
00969 
00970         self.grid()
00971 
00972         # Remove maximise button and resize. Not good to allow resizable window
00973         # because the listboxes are fixed width...
00974         self.master.resizable(0, 0)
00975 
00976         # build the menu...
00977         menubar = Menu(self)
00978         settingsmenu = Menu(menubar, tearoff=0)
00979         settingsmenu.add_command(label='Configuration', command=self.__configurationDlgShow)
00980         settingsmenu.add_separator()
00981         settingsmenu.add_command(label='Save current settings', command=self.__saveCurrentSettingsAsDefaults)
00982         settingsmenu.add_command(label='Load saved settings', command=self.__restoreCurrentSettingsFromDefault)
00983 
00984         menubar.add_cascade(label='Settings', menu=settingsmenu)
00985         helpmenu = Menu(menubar, tearoff=0)
00986         helpmenu.add_command(label='About', command=self.__aboutDlgShow)
00987         menubar.add_cascade(label='Help', menu=helpmenu)
00988         # display menu...
00989         self.master.config(menu=menubar)
00990 
00991         # now start adding our widgets starting with the top frame...
00992         self.listbox_frame = Frame(self)
00993         self.listbox_frame.grid(row=0, column=0, sticky=EW)
00994 
00995         # left hand listbox assembly
00996         self.leftListbox_frame = Frame(self.listbox_frame, borderwidth=1, relief=SUNKEN)
00997         self.leftListbox_frame.grid(row=1, column=0)
00998 
00999         self.leftLabel = Label(self.listbox_frame, text='Available Fonts')
01000         self.leftLabel.grid(row=0, column=0, sticky=NS)
01001 
01002         self.yScroll1 = Scrollbar(self.leftListbox_frame, orient=VERTICAL)
01003         self.yScroll1.grid(row=0, column=1, sticky=NS)
01004         self.xScroll1 = Scrollbar(self.leftListbox_frame, orient=HORIZONTAL)
01005         self.xScroll1.grid(row=1, column=0, sticky=EW)
01006 
01007         self.listbox1 = Listbox(self.leftListbox_frame,
01008             xscrollcommand=self.xScroll1.set,
01009             yscrollcommand=self.yScroll1.set,
01010             selectmode=EXTENDED,
01011             height=20, width=40)
01012         self.listbox1.grid(row=0, column=0, sticky=NSEW)
01013         self.xScroll1['command'] = self.listbox1.xview
01014         self.yScroll1['command'] = self.listbox1.yview
01015 
01016         def __listbox1KeyRelease(event):
01017             """Check if an Up or Down key has been pressed and released and
01018             if so the preview panel is refreshed. If the keys are held down
01019             the file system slows the scroll. Need a timer here to delay
01020             updates."""
01021             if (event.keysym == 'Down' or event.keysym == 'Up'):
01022                 __listbox1DoLogicCallback(self)
01023 
01024         def __listbox1SingleClick(event):
01025             """Call this first when listbox1 is clicked with mouse to put focus
01026             into the listbox. Note we call when mouse click is released, not pressed,
01027             due to the fact that the listbox does not change the selection until the button
01028             is released."""
01029             self.listbox1.focus_set()
01030             __listbox1DoLogicCallback(self)
01031         self.listbox1.bind('<ButtonRelease-1>', __listbox1SingleClick)
01032 
01033         def __listbox1DoLogicCallback(event):
01034             """Decides if current selection should be previewed.
01035 
01036             Start by counting items in selection list and if equal to one then
01037             show selected font, ignoring if more or less than one. Then also
01038             set up buttons logic depending on selection. We bind the FocusIn
01039             to this too so button logic and preview gets updated when focus
01040             enters the listbox.
01041             """
01042             # note we are not making use of "self.listbox1.get(ACTIVE)" due to
01043             # it not getting the real active name. Always one selection behind
01044             # even though we are doing all this in the ButtonRelease event.
01045             # Have made a change here. If more than one font name is selected
01046             # then we just empty the preview.
01047             names = self.listbox1.curselection()
01048             if len(names) == 1:
01049                 selectedFont = self.listbox1.get(names[0])
01050                 self.__curSelectedItem(selectedFont)
01051             else:
01052                 try:
01053                     app.previewPanel.delete(previewId)
01054                 except:
01055                     pass
01056             #else:
01057                 #selectedFont = self.listbox1.get(ACTIVE)
01058                 #print selectedFont  # for testing
01059                 #if selectedFont != "":
01060                     #self.__curSelectedItem(selectedFont)
01061 
01062             # Now do the button logic...
01063             self.listbox2.selection_clear(0,END)
01064             self.__setUpDownActive(0, 0)    # Force a disable if in other box
01065             if self.listbox1.size() > 0:
01066                 self.__setSelButtonsActive(0, 1)
01067             else:
01068                 self.__setSelButtonsActive(0, 0)
01069 
01070         self.listbox1.bind('<FocusIn>', __listbox1DoLogicCallback)
01071         self.listbox1.bind('<Any-KeyRelease>', __listbox1KeyRelease)
01072 
01073         def __listbox1DoubleClickCallback(event):
01074             """The single click event will fire also when left listbox
01075             is double clicked but we are detecting the single click button up event."""
01076             self.__listSelectionToRight()
01077 
01078         self.listbox1.bind('<Double-Button-1>', __listbox1DoubleClickCallback)
01079 
01080         # middle button frame assembly
01081         self.midbutton_frame = Frame(self.listbox_frame)
01082         self.midbutton_frame.grid(row=0, rowspan=2, column=1, sticky=NSEW)
01083 
01084         self.rsingleButton = Button(self.midbutton_frame, state='disabled', text='>', command=self.__rsingleButtonClick)
01085         self.rsingleButton.grid(row=0, column=0, padx=5, pady=5, sticky=EW)
01086         self.rdoubleButton = Button(self.midbutton_frame, text='>>', command=self.__rdoubleButtonClick)
01087         self.rdoubleButton.grid(row=1, column=0, padx=5, pady=5, sticky=EW)
01088 
01089         self.itemupButton = Button(self.midbutton_frame, state='disabled', text='Up', command=self.__itemupButtonClick)
01090         self.itemupButton.grid(row=2, column=0, padx=5, pady=5, sticky=EW)
01091         self.itemdownButton = Button(self.midbutton_frame, state='disabled', text='Down', command=self.__itemdownButtonClick)
01092         self.itemdownButton.grid(row=3, column=0, padx=5, pady=5, sticky=EW)
01093 
01094         self.lsingleButton = Button(self.midbutton_frame, state='disabled', text='<', command=self.__lsingleButtonClick)
01095         self.lsingleButton.grid(row=4, column=0, padx=5, pady=5, sticky=EW)
01096         self.ldoubleButton = Button(self.midbutton_frame, state='disabled', text='<<', command=self.__ldoubleButtonClick)
01097         self.ldoubleButton.grid(row=5, column=0, padx=5, pady=5, sticky=EW)
01098 
01099         # Right hand listbox assembly
01100         self.rightListbox_frame = Frame(self.listbox_frame, borderwidth=1, relief=SUNKEN)
01101         self.rightListbox_frame.grid(row=1, column=2)
01102 
01103         self.rightLabel = Label(self.listbox_frame, text='Selected Fonts')
01104         self.rightLabel.grid(row=0, column=2, sticky=NS)
01105 
01106         self.yScroll2 = Scrollbar(self.rightListbox_frame, orient=VERTICAL)
01107         self.yScroll2.grid(row=0, column=1, sticky=NS)
01108         self.xScroll2 = Scrollbar(self.rightListbox_frame, orient=HORIZONTAL)
01109         self.xScroll2.grid(row=1, column=0, sticky=EW)
01110 
01111         self.listbox2 = Listbox(self.rightListbox_frame,
01112             xscrollcommand=self.xScroll2.set,
01113             yscrollcommand=self.yScroll2.set,
01114             selectmode=EXTENDED,
01115             height=20, width=40)
01116         self.listbox2.grid(row=0, column=0, sticky=NSEW)
01117         self.xScroll2['command'] = self.listbox2.xview
01118         self.yScroll2['command'] = self.listbox2.yview
01119 
01120         def __listbox2SingleClick(event):
01121             """Similar to __listbox1SingleClick()."""
01122             self.listbox2.focus_set()
01123             __listbox2DoLogicCallback(self)
01124         self.listbox2.bind('<ButtonRelease-1>', __listbox2SingleClick)
01125 
01126         def __listbox2KeyRelease(event):
01127             if (event.keysym == 'Down' or event.keysym == 'Up'):
01128                 __listbox2DoLogicCallback(self)
01129 
01130         def __listbox2DoLogicCallback(event):
01131             """Similar to __listbox1DoLogicCallback()."""
01132             names = self.listbox2.curselection()
01133             if len(names) == 1:
01134                 selectedFont = self.listbox2.get(names[0])
01135                 self.__curSelectedItem(selectedFont)
01136             else:
01137                 try:
01138                     app.previewPanel.delete(previewId)
01139                 except:
01140                     pass
01141 
01142             # Now do the button logic...
01143             self.listbox1.selection_clear(0,END)
01144             self.__testUpDownState()
01145             if self.listbox2.size() > 0:
01146                 self.__setSelButtonsActive(1, 0)
01147             else:
01148                 self.__setSelButtonsActive(0, 0)
01149         self.listbox2.bind('<FocusIn>', __listbox2DoLogicCallback)
01150         self.listbox2.bind('<Any-KeyRelease>', __listbox2KeyRelease)
01151 
01152         def __listbox2DoubleClickCallback(event):
01153             """Similar to __listbox1DoubleClickCallback()."""
01154             self.__listSelectionToLeft()
01155         self.listbox2.bind('<Double-Button-1>', __listbox2DoubleClickCallback)
01156 
01157         # now draw the bottom font preview frame if required...
01158         if showPreviewPanel:
01159             self.preview_frame = Frame(self)
01160             self.preview_frame.grid(row=1, column=0, sticky=EW)
01161             self.previewPanel = Canvas(self.preview_frame, height=60, bg='white', bd=2, relief=SUNKEN)
01162             self.previewPanel.pack(fill=X)
01163 
01164         # now draw the bottom controls frame...
01165         self.controls_frame = Frame(self)
01166         self.controls_frame.grid(row=2, column=0, sticky=EW)
01167 
01168         # create a container...
01169         self.button_frame1 = Frame(self.controls_frame, bd=1, relief=RIDGE)
01170         self.button_frame1.grid(row=0, column=0, padx=10, pady=2)
01171         # create and add page number selection button...
01172         self.__wantPageNum = IntVar()
01173         self.pagenumSelect = Checkbutton(self.button_frame1, text='Print page numbers', variable=self.__wantPageNum, offvalue=0, onvalue=1, command=self.__pageNumberSelectButtonClick)
01174         self.pagenumSelect.grid(row=0, column=0, padx=0, sticky=W)
01175 
01176         # create a container...
01177         self.button_frame2 = Frame(self.controls_frame, bd=1, relief=RIDGE)
01178         self.button_frame2.grid(row=0, column=1, padx=10, pady=2)
01179         # create and add the TOC selector...
01180         self.__wantToc = IntVar()
01181         self.tocSelect = Checkbutton(self.button_frame2, text='Print table of contents', variable=self.__wantToc, offvalue=0, onvalue=1, command=self.__tocSelectButtonClick)
01182         self.tocSelect.grid(row=0, column=0, padx=0, sticky=W)
01183         # create and add page one on first selector...
01184         self.__wantPageOneOnFirst = IntVar()
01185         self.btnPageOneOnFirst = Checkbutton(self.button_frame2, text='Page count includes TOC', variable=self.__wantPageOneOnFirst, offvalue=0, onvalue=1, command=self.__wantPageOneOnFirstClick)
01186         self.btnPageOneOnFirst.grid(row=1, column=0, padx=0, sticky=W)
01187 
01188         # create a container...
01189         self.button_frame3 = Frame(self.controls_frame, bd=1, relief=RIDGE)
01190         self.button_frame3.grid(row=0, column=2, padx=10, pady=2)
01191         # create and add the binding offset...
01192         self.__wantBindingOffset = IntVar()
01193         self.bindingoffsetSelect = Checkbutton(self.button_frame3, text='Extra offset for binding', variable=self.__wantBindingOffset, offvalue=0, onvalue=1, command=self.__bindingoffsetSelectButtonClick)
01194         self.bindingoffsetSelect.grid(row=0, column=0, sticky=W)
01195         # create and add the double sided selection buttons...
01196         self.__wantDoubleSided = IntVar()
01197         self.doublesidedSelect = Checkbutton(self.button_frame3, text='Double sided pages', variable=self.__wantDoubleSided, offvalue=0, onvalue=1, command=self.__doubleSidedSelectButtonClick)
01198         self.doublesidedSelect.grid(row=1, column=0, rowspan=2, sticky=W)
01199 
01200         # now the ok and cancel buttons...
01201         self.cancelButton = Button(self.controls_frame, text='Cancel', command=self.__cancelButtonClick)
01202         self.cancelButton.grid(row=0, column=3, padx=5)
01203         self.okButton = Button(self.controls_frame, text='OK', state='disabled', command=self.__okButtonClick)
01204         self.okButton.grid(row=0, column=4, padx=5)
01205 
01206         # now create the bottom status bar frame and contents...
01207         self.status_frame = Frame(self)
01208         self.status_frame.grid(row=3, column=0, sticky=E+W)
01209         self.status0 = Label(self.status_frame, bd=1, relief=SUNKEN, anchor=W)
01210         self.status0.pack(side=LEFT)
01211         self.status1 = Label(self.status_frame, bd=1, relief=SUNKEN, anchor=W)
01212         self.status1.pack(side=LEFT)
01213         self.status2 = Label(self.status_frame, bd=1, relief=SUNKEN, anchor=W)
01214         self.status2.pack(side=LEFT)
01215         self.status3 = Label(self.status_frame, bd=1, relief=SUNKEN, anchor=W)
01216         self.status3.pack(side=LEFT)
01217         self.statusPaperSize = Label(self.status_frame, bd=1, relief=SUNKEN, anchor=W)
01218         self.statusPaperSize.pack(fill=X)
01219 
01220     def statusbarUpdate(self):
01221         """Draws the status bar contents.
01222 
01223         Note "draw_selection()" does a dummy run to count the amount of sample
01224         blocks on a sheet.
01225         TODO: Statusbar setting and recalculation should be separated. Just recalc
01226         and refresh panels as required instead of all of them each time.
01227         """
01228         available = self.listbox1.size()
01229         selected = self.listbox2.size()
01230         size = FloatType(selected)
01231         blocksPerSheet = draw_selection(scribus.getFontNames(), 1)
01232         value = size / blocksPerSheet
01233         pages = IntType(value)                  # Get whole part of number
01234         value = value - pages                   # Remove whole number part
01235         if value > 0:                           # Test remainder
01236             pages = pages + 1                   # Had remainder so add a page
01237         self.status0['text'] = 'Fonts available: %s   ' % (available + selected)
01238         self.status1['text'] = 'Fonts selected: %s   ' % selected
01239         self.status2['text'] = 'Sheets required: %s   ' % pages
01240         self.status3['text'] = 'Fonts per sheet: %s   ' % blocksPerSheet
01241         self.statusPaperSize['text'] = 'Paper size: %s   ' % userPrefs['paperSize']
01242 
01243     def __listSelectionToRight(self):
01244         toMoveRight = ListType(self.listbox1.curselection())
01245         self.listbox1.selection_clear(0,END)
01246         toMoveRight.reverse()   # reverse list so we delete from bottom of listbox first
01247         tempList = []
01248         for i in toMoveRight:
01249             tempList.insert(0,self.listbox1.get(i)) # gets the actual strings (reverse again)
01250             self.listbox1.delete(i)
01251         for j in tempList:
01252             self.listbox2.insert(END, j)
01253         self.__setButtonsState()
01254         self.__setSelButtonsActive(0, 0)
01255         self.statusbarUpdate()
01256 
01257     def __listSelectionToLeft(self):
01258         toMoveLeft = ListType(self.listbox2.curselection())
01259         toMoveLeft.reverse()
01260         self.listbox2.selection_clear(0,END)
01261         for i in toMoveLeft:
01262             self.listbox1.insert(END, self.listbox2.get(i)) # Insert it at the end
01263             self.listbox2.delete(i)
01264         fontList = ListType(self.listbox1.get(0, END))      # Copy contents to a list type
01265         self.listbox1.delete(0, END)                        # Remove all contents
01266         fontList.sort()                                     # Use sort method of list
01267         for j in fontList:
01268             self.listbox1.insert(END, j)                    # Replace with sorted version
01269         self.__setButtonsState()
01270         self.__setSelButtonsActive(0, 0)
01271         self.statusbarUpdate()
01272 
01273     def __listAllToRight(self):
01274         fontList = self.listbox1.get(0, END)    # Get each font name into a list
01275         for i in fontList:
01276             self.listbox2.insert(END, i)        # Copy each one
01277         self.listbox1.delete(0, END)            # All done so empty the left listbox
01278         self.__setButtonsState()
01279         self.__setSelButtonsActive(0, 0)
01280         self.statusbarUpdate()
01281 
01282     def __listAllToLeft(self):
01283         """Moves all selected fonts back to the left hand pane.
01284 
01285         Note we just clear both panes then reload the left listbox in correct
01286         order from scratch as this is probably quicker than moving each
01287         item individually.
01288         """
01289         self.listbox1.delete(0, END)
01290         fontList = scribus.getFontNames()
01291         fontList.sort()
01292         for i in fontList:
01293             self.listbox1.insert(END, i)
01294         self.listbox2.delete(0, END)
01295         self.__setButtonsState()
01296         self.__setSelButtonsActive(0, 0)
01297         self.statusbarUpdate()
01298 
01299     def __setSelButtonsActive(self, selToRight, selToLeft):
01300         # The "selection" buttons are the ones with ">"  and "<"  on them
01301         if selToRight == 1:
01302             self.lsingleButton['state'] = NORMAL
01303         else:
01304             self.lsingleButton['state'] = DISABLED
01305         if selToLeft == 1:
01306             self.rsingleButton['state'] = NORMAL
01307         else:
01308             self.rsingleButton['state'] = DISABLED
01309 
01310     def __setAllButtonsActive(self, allToRight, allToLeft):
01311         # The "all" buttons are the ones with ">>"  and "<<"  on them
01312         if allToRight == 1:
01313             self.rdoubleButton['state'] = NORMAL
01314         else:
01315             self.rdoubleButton['state'] = DISABLED
01316         if allToLeft == 1:
01317             self.ldoubleButton['state'] = NORMAL
01318         else:
01319             self.ldoubleButton['state'] = DISABLED
01320 
01321     def __setButtonsState(self):
01322         if self.listbox2.size() > 0 and self.listbox1.size() > 0:
01323             self.__setAllButtonsActive(1, 1)
01324             self.okButton['state'] = NORMAL
01325         elif self.listbox2.size() == 0:
01326             self.__setAllButtonsActive(1, 0)
01327             self.okButton['state'] = DISABLED
01328         elif self.listbox1.size() == 0:
01329             self.__setAllButtonsActive(0, 1)
01330             self.okButton['state'] = NORMAL
01331 
01332     def __itemUp(self):
01333         """Test if one item is selected then move it up one position."""
01334         selection = self.listbox2.curselection()
01335         if len(selection) == 1:
01336             indexId = IntType(selection[0]) # Get the first (only) item as integer type
01337             if indexId > 0:
01338                 fontString = self.listbox2.get(indexId)
01339                 self.listbox2.delete(indexId)
01340                 newPos = indexId - 1
01341                 self.listbox2.selection_clear(0, END)
01342                 self.listbox2.insert(newPos, fontString)
01343                 self.listbox2.see(newPos - 10)  # Scrolls listbox automatically into view if req.
01344                 self.listbox2.selection_set(newPos)
01345                 self.listbox2.activate(newPos)  # make focus follow selection
01346                 self.__testUpDownState()  # note tests only after an item has been moved
01347 
01348     def __itemDown(self):
01349         """Test if one item is selected then move it down one position."""
01350         limit = self.listbox2.size()
01351         selection = self.listbox2.curselection()
01352         if len(selection) == 1:
01353             indexId = IntType(selection[0])
01354             if indexId < limit - 1:
01355                 fontString = self.listbox2.get(indexId)
01356                 self.listbox2.delete(indexId)
01357                 newPos = indexId + 1
01358                 self.listbox2.selection_clear(0, END)
01359                 self.listbox2.insert(newPos, fontString)
01360                 self.listbox2.see(newPos + 10)
01361                 self.listbox2.selection_set(newPos)
01362                 self.listbox2.activate(newPos)  # make focus follow selection
01363                 self.__testUpDownState()
01364 
01365     def __setUpDownActive(self, up, down):
01366         """Just sets the buttons active or inactive.
01367 
01368         See testUpDown() for the actual evaluation
01369         """
01370         if up == 1:
01371             self.itemupButton['state'] = NORMAL
01372         else:
01373             self.itemupButton['state'] = DISABLED
01374         if down == 1:
01375             self.itemdownButton['state'] = NORMAL
01376         else:
01377             self.itemdownButton['state'] = DISABLED
01378 
01379     def __testUpDownState(self):
01380         """Only enable the up and down buttons when just a single item is selected.
01381 
01382         Enable should be applied to up, down or both depending on its
01383         position in the listbox. At all other times disable both.
01384         """
01385         # Get a count of how many items are currently selected...
01386         selection = list(self.listbox2.curselection())
01387         tcount = 0
01388         for sel in selection:
01389             tcount = tcount + 1
01390 
01391         position = 0
01392         if tcount == 1:
01393             position = IntType(selection[0])
01394 
01395         # If one selected and there is more than one item in the listbox then ok...
01396         if tcount == 1 and self.listbox2.size() > 1:
01397             # Now test the position of the selected line...
01398             if position > 0 and position < self.listbox2.size() - 1:    # Both
01399                 self.__setUpDownActive(1, 1)
01400             # If not one less or lesser from the bottom (listbox.count-1?) then gray the down button.
01401             elif position == self.listbox2.size() - 1:                  # Up only
01402                 self.__setUpDownActive(1, 0)
01403             # If not one or more from the top then gray up button.
01404             elif position == 0:                                         # Down only
01405                 self.__setUpDownActive(0, 1)
01406         else:
01407             self.__setUpDownActive(0, 0)
01408 
01409     def __curSelectedItem(self, selectedFont):
01410         """Send the selected font to the preview function if preview available."""
01411         if showPreviewPanel:
01412             preview_font(self, selectedFont)
01413 
01414     # create the button events...
01415     def __rsingleButtonClick(self):
01416         self.__listSelectionToRight()
01417 
01418     def __rdoubleButtonClick(self):
01419         self.__listAllToRight()
01420 
01421     def __lsingleButtonClick(self):
01422         self.__listSelectionToLeft()
01423         self.__testUpDownState()
01424 
01425     def __ldoubleButtonClick(self):
01426         self.__listAllToLeft()
01427         self.__testUpDownState()
01428 
01429     def __itemupButtonClick(self):
01430         self.__itemUp()
01431 
01432     def __itemdownButtonClick(self):
01433         self.__itemDown()
01434 
01435     def __tocSelectButtonClick(self):
01436         userPrefs['wantTOC'] = self.__wantToc.get()
01437         if userPrefs['wantTOC']:
01438             self.btnPageOneOnFirst['state'] = NORMAL
01439         else:
01440             self.btnPageOneOnFirst['state'] = DISABLED
01441 
01442     def __pageNumberSelectButtonClick(self):
01443         userPrefs['wantPageNumbers'] = self.__wantPageNum.get()
01444 
01445     def __bindingoffsetSelectButtonClick(self):
01446         userPrefs['wantBindingOffset'] = self.__wantBindingOffset.get()
01447         dD.update(set_page_geometry(dD, geometriesList, userPrefs['paperSize'], userPrefs['wantBindingOffset']))
01448 
01449     def __doubleSidedSelectButtonClick(self):
01450         userPrefs['wantDoubleSided'] = self.__wantDoubleSided.get()
01451 
01452     def __wantPageOneOnFirstClick(self):
01453         userPrefs['wantPageOneOnFirst'] = self.__wantPageOneOnFirst.get()
01454 
01455     def __cancelButtonClick(self):
01456         """We exit the app here if user presses cancel."""
01457         self.master.destroy()
01458 
01459     def __okButtonClick(self):
01460         """User presses ok, so lets create the pages."""
01461         save_user_conf(CONFIG_PATH)
01462         draw_selection(self.listbox2.get(0, END), 0)
01463         self.master.destroy()
01464 
01465     def __configurationDlgShow(self):
01466         """Opens the configuration dialog where user can set up the options"""
01467         configs = ConfigurationDialog(self)
01468         self.statusbarUpdate()
01469 
01470     def __saveCurrentSettingsAsDefaults(self):
01471         """Stores current settings as defaults."""
01472         defaultPrefs.update(userPrefs)
01473         save_user_conf(CONFIG_PATH)
01474 
01475     def __restoreCurrentSettingsFromDefault(self):
01476         """Restores current settings from defaults."""
01477         userPrefs.update(defaultPrefs)
01478         self.initialiseWidgets()
01479         self.statusbarUpdate()
01480 
01481     def initialiseWidgets(self):
01482         if userPrefs['wantPageNumbers']:
01483             self.pagenumSelect.select()
01484         else:
01485             self.pagenumSelect.deselect()
01486         if userPrefs['wantTOC']:
01487             self.tocSelect.select()
01488             self.btnPageOneOnFirst['state'] = NORMAL
01489         else:
01490             self.tocSelect.deselect()
01491             self.btnPageOneOnFirst['state'] = DISABLED
01492         if userPrefs['wantBindingOffset']:
01493             self.bindingoffsetSelect.select()
01494         else:
01495             self.bindingoffsetSelect.deselect()
01496         if userPrefs['wantDoubleSided']:
01497             self.doublesidedSelect.select()
01498         else:
01499             self.doublesidedSelect.deselect()
01500         if userPrefs['wantPageOneOnFirst']:
01501             self.btnPageOneOnFirst.select()
01502         else:
01503             self.btnPageOneOnFirst.deselect()
01504 
01505     def __aboutDlgShow(self):
01506         """Brings up a dialog with support url etc."""
01507         about = AboutDialog(self)
01508 
01509 
01510 def setup_tk():
01511     """Create and setup the Tkinter app."""
01512     root = Tk()
01513     app = Application(root)
01514     app.master.title(WINDOW_TITLE)
01515 
01516     # now get a list of all the fonts Scribus knows about...
01517     fontList = scribus.getFontNames()
01518     fontList.sort()
01519     # and load the list into the GUI listbox...
01520     for i in fontList:
01521         app.listbox1.insert(END, i)
01522     app.sampleBlocksPerPage = draw_selection(scribus.getFontNames(), 1)
01523     # now set the status bar message...
01524     app.statusbarUpdate()
01525     # set up widgets using data from userPrefs...
01526     app.initialiseWidgets()
01527     return app
01528 
01529 def initialisation():
01530     """Test for suitable fonts and on success creates tkinter app."""
01531     try:
01532         dD['bookstyleFixedFont'] = set_font_fixed(fontsListFixed)
01533         dD['bookstylePropFont'] = set_font_proportional(fontsListProportional)
01534     except:
01535         scribus.messageBox('Font problem',
01536                            '%s' % sys.exc_info()[1],
01537                            scribus.ICON_WARNING)
01538         sys.exit(1)
01539     # load users saved defaults...
01540     restore_user_conf(CONFIG_PATH)
01541     # get and set the initial paper size to match default radiobutton selection...
01542     dD.update(set_page_geometry(dD, geometriesList, userPrefs['paperSize'], userPrefs['wantBindingOffset']))
01543     # Made it this far so its time to create our Tkinter app...
01544     app = setup_tk()
01545     # now show the main window and wait for user to do something...
01546     app.mainloop()
01547 
01548 
01549 def main(argv):
01550     """Application initialization, font checks and initial setup."""
01551     initialisation()
01552 
01553 
01554 def main_wrapper(argv):
01555     """The main_wrapper() function disables redrawing, sets a sensible generic
01556     status bar message, and optionally sets up the progress bar. It then runs
01557     the main() function. Once everything finishes it cleans up after the main()
01558     function, making sure everything is sane before the script terminates."""
01559     try:
01560         scribus.statusMessage('Running script...')
01561         scribus.progressReset()
01562         main(argv)
01563     finally:
01564         # Exit neatly even if the script terminated with an exception,
01565         # so we leave the progress bar and status bar blank and make sure
01566         # drawing is enabled.
01567         if scribus.haveDoc():
01568             scribus.setRedraw(True)
01569         scribus.statusMessage('')
01570         scribus.progressReset()
01571 
01572 
01573 # This code detects if the script is being run as a script, or imported as a module.
01574 # It only runs main() if being run as a script. This permits you to import your script
01575 # and control it manually for debugging.
01576 if __name__ == '__main__':
01577     main_wrapper(sys.argv)
01578