├── .gitignore ├── Biblelator ├── Apps │ ├── BOSManager.py │ ├── BiblelatorSettingsEditor.py │ ├── FRepEx.py │ ├── SwordManager.py │ └── __init__.py ├── Biblelator.py ├── BiblelatorGlobals.py ├── DataFiles │ ├── Biblelator.gif │ ├── Biblelator.jpg │ ├── BiblelatorLogo.gif │ ├── BiblelatorLogoSmall.gif │ └── __init__.py ├── Dialogs │ ├── About.py │ ├── BiblelatorDialogs.py │ ├── BiblelatorSimpleDialogs.py │ ├── Help.py │ ├── ModalDialog.py │ └── __init__.py ├── Helpers │ ├── AutocompleteFunctions.py │ ├── AutocorrectFunctions.py │ ├── BiblelatorHelpers.py │ ├── SpellChecking.py │ └── __init__.py ├── Settings │ ├── BiblelatorSettingsFunctions.py │ ├── Settings.py │ └── __init__.py ├── Windows │ ├── BibleNotesWindow.py │ ├── BibleReferenceCollection.py │ ├── BibleResourceCollection.py │ ├── BibleResourceWindows.py │ ├── ChildWindows.py │ ├── ESFMEditWindow.py │ ├── LexiconResourceWindows.py │ ├── TSVEditWindow.py │ ├── TextBoxes.py │ ├── TextEditWindow.py │ ├── USFMEditWindow.py │ └── __init__.py └── __init__.py ├── Documentation ├── Authors.md ├── DevelopmentPrinciples.md ├── FAQs.md ├── ForParatextUsers.md ├── ForProgrammers.md ├── GettingStarted.md ├── HelpfulHints.md ├── Installation.md ├── KeyboardShortcuts.md └── ToDo.md ├── LICENSE ├── README.md └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | _pycache__/ 2 | *.pyc 3 | *.o 4 | *.snap 5 | *.off 6 | 7 | *.bak 8 | *.bak1 9 | *.bak2 10 | *.bak3 11 | *.bak4 12 | *.bak5 13 | *.bak6 14 | *.bak7 15 | *.bak8 16 | *.bak9 17 | 18 | build/ 19 | dist/ 20 | myVEnv/ 21 | snap/ 22 | 23 | # Ignore various tools folders and files 24 | .mypy_cache/ 25 | .kdev4/ 26 | .scannerwork/ 27 | .vscode/ 28 | Biblelator.egg-info/ 29 | Biblelator.kdev4 30 | sonar-project.properties 31 | -------------------------------------------------------------------------------- /Biblelator/Apps/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Freely-Given-org/Biblelator/366ba255553dd18b8fb87f433f48ffafdd4108b9/Biblelator/Apps/__init__.py -------------------------------------------------------------------------------- /Biblelator/BiblelatorGlobals.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # BiblelatorGlobals.py 5 | # 6 | # Global variables for Biblelator Bible display/editing 7 | # 8 | # Copyright (C) 2013-2022 Robert Hunt 9 | # Author: Robert Hunt 10 | # License: See gpl-3.0.txt 11 | # 12 | # This program is free software: you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation, either version 3 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License 23 | # along with this program. If not, see . 24 | 25 | """ 26 | Global variables and functions for program 27 | to allow editing of USFM Bibles using Python3 with Tkinter. 28 | 29 | assembleWindowGeometry( width, height, xOffset, yOffset ) 30 | assembleWindowSize( width, height ) 31 | assembleWindowGeometryFromList( geometryValues ) 32 | assembleWindowSizeFromList( geometryValues ) 33 | parseWindowGeometry( geometry ) 34 | parseWindowSize( geometry ) 35 | centreWindow( self, width=400, height=250 ) 36 | centreWindowOnWindow( self, parentWindow, width=400, height=250 ) 37 | errorBeep() 38 | """ 39 | from gettext import gettext as _ 40 | import os 41 | from pathlib import Path 42 | import re 43 | 44 | # BibleOrgSys imports 45 | from BibleOrgSys import BibleOrgSysGlobals 46 | from BibleOrgSys.BibleOrgSysGlobals import fnPrint, vPrint, dPrint 47 | 48 | 49 | LAST_MODIFIED_DATE = '2022-07-18' # by RJH 50 | SHORT_PROGRAM_NAME = "BiblelatorGlobals" 51 | PROGRAM_NAME = "Biblelator Globals" 52 | PROGRAM_VERSION = '0.47' # This is the version number that will be displayed inside the app 53 | PROGRAM_NAME_VERSION = f'{PROGRAM_NAME} v{PROGRAM_VERSION}' 54 | 55 | DEBUGGING_THIS_MODULE = False 56 | 57 | 58 | # Programme settings 59 | APP_NAME = 'Biblelator' # Ugly coz doesn't necessarily match the PROGRAM_NAME in Biblelator.py 60 | APP_NAME_VERSION = f'{APP_NAME} v{PROGRAM_VERSION}' # Ugly coz doesn't necessarily match the PROGRAM_VERSION in Biblelator.py 61 | DATA_SUBFOLDER_NAME = f'{APP_NAME}Data/' 62 | LOGGING_SUBFOLDER_NAME = f'{APP_NAME}Logs/' 63 | SETTINGS_SUBFOLDER_NAME = f'{APP_NAME}Settings/' 64 | PROJECTS_SUBFOLDER_NAME = f'{APP_NAME}Projects/' 65 | 66 | 67 | ########################################################################################################## 68 | # 69 | # Most of this file is "constants" and useful functions. 70 | # 71 | # This section has actual global variables. 72 | # 73 | theApp = None # This will contain a pointer to the main Application class 74 | # so we don't have to keep passing it thru all the levels. 75 | 76 | def setApp( mainApp ): 77 | global theApp 78 | assert mainApp 79 | theApp = mainApp 80 | 81 | 82 | ########################################################################################################## 83 | # 84 | # Readable folder paths 85 | SOURCE_BASE_FOLDERPATH = Path( __file__ ).parent.resolve() # Folder containing this file 86 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, f"SOURCE_BASE_FOLDERPATH = {SOURCE_BASE_FOLDERPATH}" ) 87 | DATAFILES_FOLDERPATH = SOURCE_BASE_FOLDERPATH.joinpath( 'DataFiles/' ) 88 | # DERIVED_DATAFILES_FOLDERPATH = DATAFILES_FOLDERPATH.joinpath( 'DerivedFiles/' ) 89 | 90 | # LIBRARY_BASE_FOLDERPATH = SOURCE_BASE_FOLDERPATH.parent # Folder above the one containing this file 91 | # #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, f"LIBRARY_BASE_FOLDERPATH = {LIBRARY_BASE_FOLDERPATH}" ) 92 | # TESTS_FOLDERPATH = LIBRARY_BASE_FOLDERPATH.joinpath( 'Tests/' ) 93 | # TEST_DATA_FOLDERPATH = TESTS_FOLDERPATH.joinpath( 'DataFilesForTests/' ) 94 | 95 | # # Resources like original language lexicons should be based from this folder 96 | # BADBAD_PARALLEL_RESOURCES_BASE_FOLDERPATH = LIBRARY_BASE_FOLDERPATH.parent # Two folders above the one containing this file 97 | # dPrint( 'Quiet', DEBUGGING_THIS_MODULE, f"BADBAD_PARALLEL_RESOURCES_BASE_FOLDERPATH = {BADBAD_PARALLEL_RESOURCES_BASE_FOLDERPATH}" ) 98 | 99 | 100 | # Constants for tkinter 101 | tkSTART = '1.0' 102 | tkBREAK = 'break' 103 | 104 | 105 | # Our constants 106 | DEFAULT = 'Default' 107 | EDIT_MODE_NORMAL = 'Edit' 108 | EDIT_MODE_USFM = 'USFM Edit' 109 | 110 | 111 | MAX_WINDOWS = 20 112 | MAX_RECENT_FILES = 9 113 | MAX_PSEUDOVERSES = 999 # in a non-chapter book like a glossary or something (or before the chapter one marker ) 114 | # NOTE: SimpleVerseKey does not currently handle larger numbers than this. 115 | 116 | 117 | # Default window size settings (Note: X=width, Y=height) 118 | INITIAL_MAIN_SIZE, INITIAL_MAIN_SIZE_DEBUG, MINIMUM_MAIN_SIZE, MAXIMUM_MAIN_SIZE = '607x76', '607x360', '550x75', '800x500' 119 | INITIAL_RESOURCE_SIZE, MINIMUM_RESOURCE_SIZE, MAXIMUM_RESOURCE_SIZE, MAXIMUM_LARGE_RESOURCE_SIZE = '600x360', '350x150', '800x600', '1200x800' 120 | INITIAL_RESOURCE_COLLECTION_SIZE, MINIMUM_RESOURCE_COLLECTION_SIZE, MAXIMUM_RESOURCE_COLLECTION_SIZE = '600x360', '350x150', '800x1200' 121 | INITIAL_REFERENCE_COLLECTION_SIZE, MINIMUM_REFERENCE_COLLECTION_SIZE, MAXIMUM_REFERENCE_COLLECTION_SIZE = '600x400', '350x150', '800x1200' 122 | INITIAL_HTML_SIZE, MINIMUM_HTML_SIZE, MAXIMUM_HTML_SIZE = '800x600', '550x200', '1200x800' 123 | INITIAL_RESULT_WINDOW_SIZE, MINIMUM_RESULT_WINDOW_SIZE, MAXIMUM_RESULT_WINDOW_SIZE = '600x400', '550x200', '1200x800' 124 | MINIMUM_HELP_X_SIZE, MINIMUM_HELP_Y_SIZE, MINIMUM_HELP_SIZE, MAXIMUM_HELP_SIZE = '350', '150', '350x150', '500x400' 125 | MINIMUM_ABOUT_X_SIZE, MINIMUM_ABOUT_Y_SIZE, MINIMUM_ABOUT_SIZE, MAXIMUM_ABOUT_SIZE = '350', '150', '350x150', '500x400' 126 | 127 | BIBLE_GROUP_CODES = 'A', 'B', 'C', 'D', 'E' 128 | BIBLE_CONTEXT_VIEW_MODES = 'BeforeAndAfter', 'BySection', 'ByVerse', 'ByBook', 'ByChapter' 129 | BIBLE_FORMAT_VIEW_MODES = 'Formatted', 'Unformatted', 130 | 131 | 132 | # DEFAULT_KEY_BINDING_DICT is a dictionary where 133 | # the index is a menu word like 'Save' 134 | # and the entry is a tuple where 135 | # the first entry is the keyboard description of the shortcut 136 | # followed by all (i.e., one or more) TKinter values which should be bound to that shortcut. 137 | # 138 | # Not all of these are used for all windows 139 | # 140 | DEFAULT_KEY_BINDING_DICT = { 141 | _('Cut'):('Ctrl+x',''), #,''), 142 | _('Copy'):('Ctrl+c',''), #,''), 143 | _('Paste'):('Ctrl+v',''), #,''), 144 | _('SelectAll'):('Ctrl+a',''), #,''), 145 | _('Find'):('Ctrl+f',''), #,''), 146 | _('Refind'):('F3/Ctrl+g',''), #,'',''), 147 | _('Replace'):('Ctrl+r',''), #,''), 148 | _('Undo'):('Ctrl+z',''), #,''), 149 | _('Redo'):('Ctrl+y',''), #,'','',''), 150 | _('Line'):('Ctrl+l',''), #,''), 151 | _('Save'):('Ctrl+s',''), #,''), 152 | _('ShowMain'):('F2',''), 153 | _('Help'):('F1',''), 154 | _('Info'):('F11',''), 155 | _('About'):('F12',''), 156 | _('Close'):('Ctrl+F4',''), 157 | _('Quit'):('Alt+F4',''), } 158 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, DEFAULT_KEY_BINDING_DICT ); halt 159 | 160 | 161 | 162 | def assembleWindowGeometry( width, height, xOffset, yOffset ): 163 | return "{}x{}+{}+{}".format( width, height, xOffset, yOffset ) 164 | # end of BiblelatorGlobals.assembleWindowGeometry 165 | 166 | 167 | def assembleWindowSize( width, height ): 168 | return "{}x{}".format( width, height ) 169 | # end of BiblelatorGlobals.assembleWindowSize 170 | 171 | 172 | def assembleWindowGeometryFromList( geometryValues ): 173 | width, height, xOffset, yOffset = geometryValues 174 | return "{}x{}+{}+{}".format( width, height, xOffset, yOffset ) 175 | # end of BiblelatorGlobals.assembleWindowGeometryFromList 176 | 177 | 178 | def assembleWindowSizeFromList( geometryValues ): 179 | width, height = geometryValues 180 | return "{}x{}".format( width, height ) 181 | # end of BiblelatorGlobals.assembleWindowSizeFromList 182 | 183 | 184 | def parseWindowGeometry( geometry ): 185 | """ 186 | Given a TKinter geometry string, e,g., 493x152+820+491 or 493x123+-119+9 187 | being width, height, xOffset, yOffset 188 | return a list containing the four integer values. 189 | """ 190 | m = re.match("(\d+)x(\d+)\+(-?\d+)\+(-?\d+)", geometry) 191 | if not m: 192 | raise ValueError( "parseWindowGeometry: failed to parse geometry string {!r}".format( geometry ) ) 193 | return [int(digits) for digits in m.groups()] 194 | # end of BiblelatorGlobals.parseWindowGeometry 195 | 196 | 197 | def parseWindowSize( geometry ): 198 | """ 199 | Given a TKinter geometry string, e,g., 493x152 (being width, height) 200 | return a list containing the two integer values. 201 | """ 202 | m = re.match("(\d+)x(\d+)", geometry) 203 | if not m: 204 | raise ValueError( "parseWindowSize: failed to parse geometry string {!r}".format( geometry ) ) 205 | return [int(digits) for digits in m.groups()] 206 | # end of BiblelatorGlobals.parseWindowSize 207 | 208 | 209 | def centreWindow( self, width=400, height=250 ): 210 | """ 211 | "self" here is a TKinter window object. 212 | """ 213 | if isinstance( width, str ): width = int( width ) 214 | if isinstance( height, str ): height = int( height ) 215 | 216 | screenWidth = self.winfo_screenwidth() 217 | screenHeight = self.winfo_screenheight() 218 | 219 | x = (screenWidth - width) // 2 220 | y = (screenHeight - height) // 2 221 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, "centreWindow", width, height, screenWidth, screenHeight, x, y ) 222 | 223 | self.geometry('{}x{}+{}+{}'.format( width, height, x, y ) ) 224 | # end of BiblelatorGlobals.centreWindow 225 | 226 | 227 | def centreWindowOnWindow( self, parentWindow, width=400, height=250 ): 228 | """ 229 | """ 230 | parentWidth, parentHeight, parentXOffset, parentYOffset = parseWindowGeometry( parentWindow.winfo_geometry() ) 231 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, "centreWindowOnWindow parent is", "w =",parentWidth, "h =",parentHeight, "x =",parentXOffset, "y =",parentYOffset ) 232 | 233 | x = parentXOffset + (parentWidth - width) // 2 234 | y = parentYOffset + (parentHeight - height) // 2 235 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, "centreWindowOnWindow", "w =",width, "h =",height, "x =",x, "y =",y ) 236 | 237 | self.geometry('{}x{}+{}+{}'.format( width, height, x, y ) ) 238 | # end of BiblelatorGlobals.centreWindowOnWindow 239 | 240 | 241 | def makeSafeProgramName( progName:str ) -> str: 242 | """ 243 | If we want to use the program name as a filename. 244 | """ 245 | return progName.replace('/','-').replace(':','_').replace('\\','_') 246 | # end of BiblelatorGlobals.makeSafeProgramName 247 | 248 | 249 | def errorBeep(): 250 | """ 251 | """ 252 | if BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 253 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "errorBeep()" ) 254 | 255 | # Does nothing yet :-( 256 | 257 | #import sys 258 | #from subprocess import call 259 | #if sys.platform == 'linux': call(["xdg-open","dialog-error.ogg"]) 260 | #elif sys.platform == 'darwin': call(["afplay","dialog-error.ogg"]) 261 | #else: vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "errorBeep: sp", sys.platform ) 262 | # end of errorBeep 263 | 264 | 265 | def briefDemo() -> None: 266 | """ 267 | Demo program to handle command line parameters and then run what they want. 268 | """ 269 | from tkinter import Tk 270 | 271 | BibleOrgSysGlobals.introduceProgram( __name__, PROGRAM_NAME_VERSION, LAST_MODIFIED_DATE ) 272 | dPrint( 'Quiet', DEBUGGING_THIS_MODULE, "Running demo…" ) 273 | 274 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "assembleWindowGeometry( 123, 234, 345, 456 ) = {}".format( assembleWindowGeometry( 123, 234, 345, 456 ) ) ) 275 | g1, g2 = "493x152+820+491", "493x123+-119+9" 276 | p1, p2 = parseWindowGeometry( g1 ), parseWindowGeometry( g2 ) 277 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "parseWindowGeometry( {} ) = {}".format( g1, p1 ) ) 278 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "assembleWindowGeometryFromList( {} ) = {}".format( p1, assembleWindowGeometryFromList( p1 ) ) ) 279 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "parseWindowGeometry( {} ) = {}".format( g2, p2 ) ) 280 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "assembleWindowGeometryFromList( {} ) = {}".format( p2, assembleWindowGeometryFromList( p2 ) ) ) 281 | 282 | #tkRootWindow = Tk() 283 | #tkRootWindow.title( PROGRAM_NAME_VERSION ) 284 | #settings = ApplicationSettings( DATA_SUBFOLDER_NAME, SETTINGS_SUBFOLDER_NAME, PROGRAM_NAME ) 285 | #settings.load() 286 | 287 | #application = Application( parent=tkRootWindow, settings=settings ) 288 | # Calls to the window manager class (wm in Tk) 289 | #application.master.title( PROGRAM_NAME_VERSION ) 290 | #application.master.minsize( application.minimumXSize, application.minimumYSize ) 291 | 292 | # Start the program running 293 | #tkRootWindow.mainloop() 294 | # end of BiblelatorGlobals.briefDemo 295 | 296 | def fullDemo() -> None: 297 | """ 298 | Full demo to check class is working 299 | """ 300 | from tkinter import Tk 301 | 302 | BibleOrgSysGlobals.introduceProgram( __name__, PROGRAM_NAME_VERSION, LAST_MODIFIED_DATE ) 303 | dPrint( 'Quiet', DEBUGGING_THIS_MODULE, "Running demo…" ) 304 | 305 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "assembleWindowGeometry( 123, 234, 345, 456 ) = {}".format( assembleWindowGeometry( 123, 234, 345, 456 ) ) ) 306 | g1, g2 = "493x152+820+491", "493x123+-119+9" 307 | p1, p2 = parseWindowGeometry( g1 ), parseWindowGeometry( g2 ) 308 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "parseWindowGeometry( {} ) = {}".format( g1, p1 ) ) 309 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "assembleWindowGeometryFromList( {} ) = {}".format( p1, assembleWindowGeometryFromList( p1 ) ) ) 310 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "parseWindowGeometry( {} ) = {}".format( g2, p2 ) ) 311 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "assembleWindowGeometryFromList( {} ) = {}".format( p2, assembleWindowGeometryFromList( p2 ) ) ) 312 | 313 | #tkRootWindow = Tk() 314 | #tkRootWindow.title( PROGRAM_NAME_VERSION ) 315 | #settings = ApplicationSettings( DATA_SUBFOLDER_NAME, SETTINGS_SUBFOLDER_NAME, PROGRAM_NAME ) 316 | #settings.load() 317 | 318 | #application = Application( parent=tkRootWindow, settings=settings ) 319 | # Calls to the window manager class (wm in Tk) 320 | #application.master.title( PROGRAM_NAME_VERSION ) 321 | #application.master.minsize( application.minimumXSize, application.minimumYSize ) 322 | 323 | # Start the program running 324 | #tkRootWindow.mainloop() 325 | # end of BiblelatorGlobals.fullDemo 326 | 327 | if __name__ == '__main__': 328 | from multiprocessing import freeze_support 329 | freeze_support() # Multiprocessing support for frozen Windows executables 330 | 331 | # Configure basic set-up 332 | parser = BibleOrgSysGlobals.setup( SHORT_PROGRAM_NAME, PROGRAM_VERSION, LAST_MODIFIED_DATE ) 333 | BibleOrgSysGlobals.addStandardOptionsAndProcess( parser ) 334 | 335 | fullDemo() 336 | 337 | BibleOrgSysGlobals.closedown( PROGRAM_NAME, PROGRAM_VERSION ) 338 | # end of BiblelatorGlobals.py 339 | -------------------------------------------------------------------------------- /Biblelator/DataFiles/Biblelator.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Freely-Given-org/Biblelator/366ba255553dd18b8fb87f433f48ffafdd4108b9/Biblelator/DataFiles/Biblelator.gif -------------------------------------------------------------------------------- /Biblelator/DataFiles/Biblelator.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Freely-Given-org/Biblelator/366ba255553dd18b8fb87f433f48ffafdd4108b9/Biblelator/DataFiles/Biblelator.jpg -------------------------------------------------------------------------------- /Biblelator/DataFiles/BiblelatorLogo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Freely-Given-org/Biblelator/366ba255553dd18b8fb87f433f48ffafdd4108b9/Biblelator/DataFiles/BiblelatorLogo.gif -------------------------------------------------------------------------------- /Biblelator/DataFiles/BiblelatorLogoSmall.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Freely-Given-org/Biblelator/366ba255553dd18b8fb87f433f48ffafdd4108b9/Biblelator/DataFiles/BiblelatorLogoSmall.gif -------------------------------------------------------------------------------- /Biblelator/DataFiles/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Freely-Given-org/Biblelator/366ba255553dd18b8fb87f433f48ffafdd4108b9/Biblelator/DataFiles/__init__.py -------------------------------------------------------------------------------- /Biblelator/Dialogs/About.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # About.py 5 | # 6 | # About box for Biblelator Bible display/editing 7 | # 8 | # Copyright (C) 2014-2020 Robert Hunt 9 | # Author: Robert Hunt 10 | # License: See gpl-3.0.txt 11 | # 12 | # This program is free software: you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation, either version 3 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License 23 | # along with this program. If not, see . 24 | 25 | """ 26 | A simple About box window containing text and an optional logo. 27 | """ 28 | from gettext import gettext as _ 29 | 30 | import tkinter as tk 31 | from tkinter.scrolledtext import ScrolledText 32 | from tkinter.ttk import Frame, Button 33 | 34 | if __name__ == '__main__': 35 | import sys 36 | aboveAboveFolderpath = os.path.dirname( os.path.dirname( os.path.dirname( os.path.abspath( __file__ ) ) ) ) 37 | if aboveAboveFolderpath not in sys.path: 38 | sys.path.insert( 0, aboveAboveFolderpath ) 39 | from Biblelator.BiblelatorGlobals import MINIMUM_ABOUT_SIZE, MAXIMUM_ABOUT_SIZE, \ 40 | parseWindowSize, centreWindowOnWindow 41 | 42 | from BibleOrgSys import BibleOrgSysGlobals 43 | from BibleOrgSys.BibleOrgSysGlobals import fnPrint, vPrint, dPrint 44 | 45 | 46 | LAST_MODIFIED_DATE = '2020-04-25' # by RJH 47 | SHORT_PROGRAM_NAME = "BiblelatorAbout" 48 | PROGRAM_NAME = "BiblelatorAbout Box" 49 | PROGRAM_VERSION = '0.46' 50 | PROGRAM_NAME_VERSION = f'{PROGRAM_NAME} v{PROGRAM_VERSION}' 51 | 52 | DEBUGGING_THIS_MODULE = False 53 | 54 | 55 | 56 | 57 | class AboutBox( tk.Toplevel ): 58 | """ 59 | """ 60 | def __init__( self, parent=None, progName=None, text=None, logoPath=None ) -> None: 61 | """ 62 | """ 63 | #if BibleOrgSysGlobals.debugFlag: vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "AboutBox.__init__( {} )".format( parent ) ) 64 | tk.Toplevel.__init__( self, parent ) 65 | self.minimumSize = MINIMUM_ABOUT_SIZE 66 | self.minsize( *parseWindowSize( self.minimumSize ) ) 67 | self.maximumSize = MAXIMUM_ABOUT_SIZE 68 | self.maxsize( *parseWindowSize( self.maximumSize ) ) 69 | if parent: centreWindowOnWindow( self, parent ) 70 | 71 | self.title( _("About") + ' '+progName ) 72 | 73 | buttonFrame = Frame( self ) #, cursor='hand2', relief=tk.RAISED, style='MainButtons.TFrame' ) 74 | if logoPath: 75 | self.logo = tk.PhotoImage( file=logoPath ) 76 | self.label = tk.Label( buttonFrame, image=self.logo ) 77 | self.label.pack( side=tk.LEFT ) 78 | Button( buttonFrame, text=_("Ok"), command=self.destroy ).pack( side=tk.RIGHT ) 79 | buttonFrame.pack( side=tk.BOTTOM, fill=tk.X ) 80 | 81 | self.textBox = ScrolledText( self, height=12 ) #, state=tk.DISABLED ) 82 | self.textBox.configure( wrap='word' ) 83 | self.textBox.insert( tk.END, text ) 84 | self.textBox.configure( state=tk.DISABLED ) # Don't allow editing 85 | self.textBox.pack( side=tk.TOP, expand=tk.YES ) 86 | 87 | self.focus_set() # take over input focus, 88 | self.grab_set() # disable other windows while I'm open, 89 | self.wait_window() # and wait here until win destroyed 90 | # end of AboutBox.__init__ 91 | # end of class AboutBox 92 | 93 | 94 | 95 | #class AboutBox2(): 96 | #""" 97 | #""" 98 | #def __init__( self, parent=None, progName=None, text=None, logoPath=None ): 99 | #""" 100 | #""" 101 | ##if BibleOrgSysGlobals.debugFlag: vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "AboutBox2.__init__( {} )".format( parent ) ) 102 | #ab = tk.Toplevel( parent ) 103 | #self.minimumXSize, self.minimumYSize = MINIMUM_ABOUT_X_SIZE, MINIMUM_ABOUT_Y_SIZE 104 | #ab.minsize( self.minimumXSize, self.minimumYSize ) 105 | #if parent: centreWindowOnWindow( ab, parent ) 106 | 107 | #if logoPath: 108 | #self.logo = tk.PhotoImage( file=logoPath ) 109 | #self.label = tk.Label( ab, image=self.logo ) 110 | #self.label.pack( side=tk.TOP ) 111 | 112 | #self.okButton = Button( ab, text=_("Ok"), command=ab.destroy ) 113 | #self.okButton.pack( side=tk.BOTTOM ) 114 | 115 | #ab.title( 'About '+progName ) 116 | 117 | #textBox = ScrolledText( ab ) #, state=tk.DISABLED ) 118 | #textBox.configure( wrap='word' ) 119 | #textBox.pack( expand=tk.YES ) 120 | #textBox.insert( tk.END, text ) 121 | #textBox.configure( state=tk.DISABLED ) # Don't allow editing 122 | 123 | #okButton = Button( ab, text=_("Ok"), command=ab.destroy ) 124 | #okButton.pack() 125 | 126 | #ab.focus_set() # take over input focus, 127 | #ab.grab_set() # disable other windows while I'm open, 128 | #ab.wait_window() # and wait here until win destroyed 129 | ## end of AboutBox2.__init__ 130 | ## end of class AboutBox2 131 | 132 | 133 | 134 | def briefDemo() -> None: 135 | """ 136 | Main program to handle command line parameters and then run what they want. 137 | """ 138 | BibleOrgSysGlobals.introduceProgram( __name__, PROGRAM_NAME_VERSION, LAST_MODIFIED_DATE ) 139 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "Running demo…" ) 140 | 141 | tkRootWindow = tk.Tk() 142 | if BibleOrgSysGlobals.debugFlag: 143 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, 'Windowing system is', repr( tkRootWindow.tk.call('tk', 'windowingsystem') ) ) 144 | for name in ('appname', 'inactive', 'scaling', 'useinputmethods', 'windowingsystem' ): # 'busy', 'caret', 'fontchooser', 145 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, 'Tkinter {} is {}'.format( name, repr( tkRootWindow.tk.call('tk', name) ) ) ) 146 | tkRootWindow.title( PROGRAM_NAME_VERSION ) 147 | ab = AboutBox( tkRootWindow, PROGRAM_NAME, PROGRAM_NAME_VERSION ) 148 | #ab = AboutBox2( tkRootWindow, PROGRAM_NAME, PROGRAM_NAME_VERSION ) 149 | # Calls to the window manager class (wm in Tk) 150 | #tkRootWindow.minsize( application.minimumXSize, application.minimumYSize ) 151 | 152 | # Program a shutdown 153 | tkRootWindow.after( 30000, tkRootWindow.destroy ) # Destroy the widget after 30 seconds 154 | 155 | # Start the program running 156 | tkRootWindow.mainloop() 157 | # end of About.briefDemo 158 | 159 | def fullDemo() -> None: 160 | """ 161 | Full demo to check class is working 162 | """ 163 | BibleOrgSysGlobals.introduceProgram( __name__, PROGRAM_NAME_VERSION, LAST_MODIFIED_DATE ) 164 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "Running demo…" ) 165 | 166 | tkRootWindow = tk.Tk() 167 | if BibleOrgSysGlobals.debugFlag: 168 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, 'Windowing system is', repr( tkRootWindow.tk.call('tk', 'windowingsystem') ) ) 169 | for name in ('appname', 'inactive', 'scaling', 'useinputmethods', 'windowingsystem' ): # 'busy', 'caret', 'fontchooser', 170 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, 'Tkinter {} is {}'.format( name, repr( tkRootWindow.tk.call('tk', name) ) ) ) 171 | tkRootWindow.title( PROGRAM_NAME_VERSION ) 172 | ab = AboutBox( tkRootWindow, PROGRAM_NAME, PROGRAM_NAME_VERSION ) 173 | #ab = AboutBox2( tkRootWindow, PROGRAM_NAME, PROGRAM_NAME_VERSION ) 174 | # Calls to the window manager class (wm in Tk) 175 | #tkRootWindow.minsize( application.minimumXSize, application.minimumYSize ) 176 | 177 | # Program a shutdown 178 | tkRootWindow.after( 30000, tkRootWindow.destroy ) # Destroy the widget after 30 seconds 179 | 180 | # Start the program running 181 | tkRootWindow.mainloop() 182 | # end of About.fullDemo 183 | 184 | if __name__ == '__main__': 185 | from multiprocessing import freeze_support 186 | freeze_support() # Multiprocessing support for frozen Windows executables 187 | 188 | 189 | # Configure basic set-up 190 | parser = BibleOrgSysGlobals.setup( SHORT_PROGRAM_NAME, PROGRAM_VERSION, LAST_MODIFIED_DATE ) 191 | BibleOrgSysGlobals.addStandardOptionsAndProcess( parser ) 192 | 193 | fullDemo() 194 | 195 | BibleOrgSysGlobals.closedown( PROGRAM_NAME, PROGRAM_VERSION ) 196 | # end of About.py 197 | -------------------------------------------------------------------------------- /Biblelator/Dialogs/BiblelatorSimpleDialogs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # BiblelatorSimpleDialogs.py 5 | # 6 | # Various dialog windows for Biblelator Bible display/editing 7 | # 8 | # Copyright (C) 2013-2022 Robert Hunt 9 | # Author: Robert Hunt 10 | # License: See gpl-3.0.txt 11 | # 12 | # This program is free software: you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation, either version 3 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License 23 | # along with this program. If not, see . 24 | 25 | """ 26 | Various simple modal dialog windows for Biblelator Bible warnings and errors. 27 | 28 | def showError( parentWindow, title, errorText ) 29 | def showWarning( parentWindow, title, warningText ) 30 | def showInfo( parentWindow, title, infoText ) 31 | """ 32 | from gettext import gettext as _ 33 | import logging 34 | 35 | import tkinter as tk 36 | import tkinter.messagebox as tkMsgBox 37 | 38 | # BibleOrgSys imports 39 | from BibleOrgSys import BibleOrgSysGlobals 40 | from BibleOrgSys.BibleOrgSysGlobals import fnPrint, vPrint, dPrint 41 | 42 | # Biblelator imports 43 | from Biblelator import BiblelatorGlobals 44 | 45 | 46 | LAST_MODIFIED_DATE = '2022-07-18' 47 | SHORT_PROGRAM_NAME = "BiblelatorSimpleDialogs" 48 | PROGRAM_NAME = "Biblelator simple dialogs" 49 | PROGRAM_VERSION = '0.47' 50 | PROGRAM_NAME_VERSION = f'{PROGRAM_NAME} v{PROGRAM_VERSION}' 51 | 52 | DEBUGGING_THIS_MODULE = False 53 | 54 | 55 | 56 | 57 | def showError( parentWindow, title:str, errorText:str ) -> None: 58 | """ 59 | """ 60 | fnPrint( DEBUGGING_THIS_MODULE, f"showError( {parentWindow}, '{title}', '{errorText}' )…" ) 61 | 62 | logging.error( f'{title}: {errorText}' ) 63 | BiblelatorGlobals.theApp.setStatus( _("Waiting for user input after error…") ) 64 | tkMsgBox.showerror( title, errorText, parent=parentWindow ) 65 | BiblelatorGlobals.theApp.setReadyStatus() 66 | # end of BiblelatorSimpleDialogs.showError 67 | 68 | 69 | def showWarning( parentWindow, title, warningText ): 70 | """ 71 | """ 72 | fnPrint( DEBUGGING_THIS_MODULE, "showWarning( {}, {!r}, {!r} )".format( parentWindow, title, warningText ) ) 73 | 74 | logging.warning( '{}: {}'.format( title, warningText ) ) 75 | BiblelatorGlobals.theApp.setStatus( _("Waiting for user input after warning…") ) 76 | tkMsgBox.showwarning( title, warningText, parent=parentWindow ) 77 | BiblelatorGlobals.theApp.setReadyStatus() 78 | # end of BiblelatorSimpleDialogs.showWarning 79 | 80 | 81 | def showInfo( parentWindow, title, infoText ): 82 | """ 83 | """ 84 | fnPrint( DEBUGGING_THIS_MODULE, "showInfo( {}, {!r}, {!r} )".format( parentWindow, title, infoText ) ) 85 | if BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 86 | infoText += '\n\nWindow parameters:\n' 87 | for configKey, configTuple in sorted(parentWindow.configure().items()): # Append the parentWindow window config info 88 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "showInfo: {!r}={} ({})".format( configKey, configTuple, len(configTuple) ) ) 89 | if len(configTuple)>2: # don't append alternative names like, bg for background 90 | # Don't display the last field if it just duplicates the previous one 91 | infoText += ' {}: {!r}{}\n'.format( configTuple[2], configTuple[3], 92 | '' if configTuple[4]==configTuple[3] else ', {!r}'.format( configTuple[4] ) ) 93 | elif DEBUGGING_THIS_MODULE: # append alternative names like, bg for background 94 | # Don't display the last field if it just duplicates the previous one 95 | infoText += ' {}={!r}\n'.format( configTuple[0], configTuple[1] ) 96 | 97 | logging.info( '{}: {}'.format( title, infoText ) ) 98 | BiblelatorGlobals.theApp.setStatus( _("Waiting for user input after info…") ) 99 | tkMsgBox.showinfo( title, infoText, parent=parentWindow ) 100 | BiblelatorGlobals.theApp.setReadyStatus() 101 | # end of BiblelatorSimpleDialogs.showInfo 102 | 103 | 104 | 105 | def briefDemo() -> None: 106 | """ 107 | Main program to handle command line parameters and then run what they want. 108 | """ 109 | BibleOrgSysGlobals.introduceProgram( __name__, PROGRAM_NAME_VERSION, LAST_MODIFIED_DATE ) 110 | dPrint( 'Quiet', DEBUGGING_THIS_MODULE, "Running demo…" ) 111 | 112 | tkRootWindow = tk.Tk() 113 | tkRootWindow.title( PROGRAM_NAME_VERSION ) 114 | 115 | # Doesn't quite work yet :-( 116 | tkWindow = tk.Toplevel( tkRootWindow ) 117 | tkWindow.parentApp = tkRootWindow 118 | tkRootWindow.setStatus = lambda s: s 119 | tkRootWindow.setReadyStatus = lambda: 1 120 | showError( tkWindow, "Test Error", "This is just a test of an error box!" ) 121 | showWarning( tkWindow, "Test Warning", "This is just a test of an warning box!" ) 122 | showInfo( tkWindow, "Test Info", "This is just a test of an info box!" ) 123 | #tkRootWindow.quit() 124 | 125 | # Program a shutdown 126 | tkRootWindow.after( 2_000, tkRootWindow.destroy ) # Destroy the widget after 2 seconds 127 | 128 | # Start the program running 129 | #tkRootWindow.mainloop() 130 | # end of BiblelatorSimpleDialogs.briefDemo 131 | 132 | def fullDemo() -> None: 133 | """ 134 | Full demo to check class is working 135 | """ 136 | BibleOrgSysGlobals.introduceProgram( __name__, PROGRAM_NAME_VERSION, LAST_MODIFIED_DATE ) 137 | dPrint( 'Quiet', DEBUGGING_THIS_MODULE, "Running demo…" ) 138 | 139 | tkRootWindow = tk.Tk() 140 | tkRootWindow.title( PROGRAM_NAME_VERSION ) 141 | 142 | # Doesn't quite work yet :-( 143 | tkWindow = tk.Toplevel( tkRootWindow ) 144 | tkWindow.parentApp = tkRootWindow 145 | tkRootWindow.setStatus = lambda s: s 146 | tkRootWindow.setReadyStatus = lambda: 1 147 | showError( tkWindow, "Test Error", "This is just a test of an error box!" ) 148 | showWarning( tkWindow, "Test Warning", "This is just a test of an warning box!" ) 149 | showInfo( tkWindow, "Test Info", "This is just a test of an info box!" ) 150 | #tkRootWindow.quit() 151 | 152 | # Program a shutdown 153 | tkRootWindow.after( 30_000, tkRootWindow.destroy ) # Destroy the widget after 30 seconds 154 | 155 | # Start the program running 156 | #tkRootWindow.mainloop() 157 | # end of BiblelatorSimpleDialogs.fullDemo 158 | 159 | if __name__ == '__main__': 160 | from multiprocessing import freeze_support 161 | freeze_support() # Multiprocessing support for frozen Windows executables 162 | 163 | # Configure basic set-up 164 | parser = BibleOrgSysGlobals.setup( SHORT_PROGRAM_NAME, PROGRAM_VERSION, LAST_MODIFIED_DATE ) 165 | BibleOrgSysGlobals.addStandardOptionsAndProcess( parser ) 166 | 167 | fullDemo() 168 | 169 | BibleOrgSysGlobals.closedown( PROGRAM_NAME, PROGRAM_VERSION ) 170 | # end of BiblelatorSimpleDialogs.py 171 | -------------------------------------------------------------------------------- /Biblelator/Dialogs/Help.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Help.py 5 | # 6 | # Help box for Biblelator Bible display/editing 7 | # 8 | # Copyright (C) 2014-2020 Robert Hunt 9 | # Author: Robert Hunt 10 | # License: See gpl-3.0.txt 11 | # 12 | # This program is free software: you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation, either version 3 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License 23 | # along with this program. If not, see . 24 | 25 | """ 26 | A simple Help box window containing text and an optional logo. 27 | """ 28 | from gettext import gettext as _ 29 | 30 | import tkinter as tk 31 | from tkinter.scrolledtext import ScrolledText 32 | from tkinter.ttk import Frame, Button 33 | 34 | # BibleOrgSys imports 35 | from BibleOrgSys import BibleOrgSysGlobals 36 | from BibleOrgSys.BibleOrgSysGlobals import fnPrint, vPrint, dPrint 37 | 38 | # Biblelator imports 39 | if __name__ == '__main__': 40 | import sys 41 | aboveAboveFolderpath = os.path.dirname( os.path.dirname( os.path.dirname( os.path.abspath( __file__ ) ) ) ) 42 | if aboveAboveFolderpath not in sys.path: 43 | sys.path.insert( 0, aboveAboveFolderpath ) 44 | from Biblelator.BiblelatorGlobals import MINIMUM_HELP_SIZE, MAXIMUM_HELP_SIZE, MINIMUM_HELP_X_SIZE, MINIMUM_HELP_Y_SIZE, \ 45 | parseWindowSize, centreWindowOnWindow 46 | 47 | 48 | LAST_MODIFIED_DATE = '2020-04-25' # by RJH 49 | SHORT_PROGRAM_NAME = "BiblelatorHelp" 50 | PROGRAM_NAME = "Biblelator Help Box" 51 | PROGRAM_VERSION = '0.46' 52 | PROGRAM_NAME_VERSION = f'{PROGRAM_NAME} v{PROGRAM_VERSION}' 53 | 54 | DEBUGGING_THIS_MODULE = False 55 | 56 | 57 | 58 | 59 | class HelpBox( tk.Toplevel ): 60 | """ 61 | """ 62 | def __init__( self, parent=None, progName=None, text=None, logoPath=None ): 63 | """ 64 | """ 65 | #if BibleOrgSysGlobals.debugFlag: vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "HelpBox.__init__( {} )".format( parent ) ) 66 | tk.Toplevel.__init__( self, parent ) 67 | self.minimumSize = MINIMUM_HELP_SIZE 68 | self.minsize( *parseWindowSize( self.minimumSize ) ) 69 | self.maximumSize = MAXIMUM_HELP_SIZE 70 | self.maxsize( *parseWindowSize( self.maximumSize ) ) 71 | if parent: centreWindowOnWindow( self, parent ) 72 | 73 | self.title( 'Help for '+progName ) 74 | 75 | buttonFrame = Frame( self ) #, cursor='hand2', relief=tk.RAISED, style='MainButtons.TFrame' ) 76 | if logoPath: 77 | self.logo = tk.PhotoImage( file=logoPath ) 78 | self.label = tk.Label( buttonFrame, image=self.logo ) 79 | self.label.pack( side=tk.LEFT ) 80 | Button( buttonFrame, text=_("Ok"), command=self.destroy ).pack( side=tk.RIGHT ) 81 | buttonFrame.pack( side=tk.BOTTOM, fill=tk.X ) 82 | 83 | self.textBox = ScrolledText( self, height=12 ) #, state=tk.DISABLED ) 84 | self.textBox.configure( wrap='word' ) 85 | self.textBox.insert( tk.END, text ) 86 | self.textBox.configure( state=tk.DISABLED ) # Don't allow editing 87 | self.textBox.pack( expand=tk.YES ) 88 | 89 | self.focus_set() # take over input focus, 90 | self.grab_set() # disable other windows while I'm open, 91 | self.wait_window() # and wait here until win destroyed 92 | # end of HelpBox.__init__ 93 | # end of class HelpBox 94 | 95 | 96 | 97 | #class HelpBox2(): 98 | #""" 99 | #""" 100 | #def __init__( self, parent=None, progName=None, text=None, logoPath=None ): 101 | #""" 102 | #""" 103 | #if BibleOrgSysGlobals.debugFlag: vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "HelpBox2.__init__( {} )".format( parent ) ) 104 | #hb = tk.Toplevel( parent ) 105 | #self.minimumXSize, self.minimumYSize = MINIMUM_HELP_X_SIZE, MINIMUM_HELP_Y_SIZE 106 | #hb.minsize( self.minimumXSize, self.minimumYSize ) 107 | #if parent: centreWindowOnWindow( hb, parent ) 108 | 109 | #hb.title( 'Help for '+progName ) 110 | 111 | #textBox = ScrolledText( hb, height=12 ) #, state=tk.DISABLED ) 112 | #textBox.configure( wrap='word' ) 113 | #textBox.pack( expand=tk.YES ) 114 | #textBox.insert( tk.END, text ) 115 | #textBox.configure( state=tk.DISABLED ) # Don't allow editing 116 | 117 | #if logoPath: 118 | #self.logo = tk.PhotoImage( file=logoPath ) 119 | #self.label = tk.Label( hb, image=self.logo ) 120 | #self.label.pack( side=tk.LEFT ) 121 | 122 | #self.okButton = Button( hb, text=_("Ok"), command=hb.destroy ) 123 | #self.okButton.pack( side=tk.RIGHT ) 124 | 125 | #hb.focus_set() # take over input focus, 126 | #hb.grab_set() # disable other windows while I'm open, 127 | #hb.wait_window() # and wait here until win destroyed 128 | ## end of HelpBox.__init__ 129 | ## end of class HelpBox2 130 | 131 | 132 | 133 | def briefDemo() -> None: 134 | """ 135 | Main program to handle command line parameters and then run what they want. 136 | """ 137 | BibleOrgSysGlobals.introduceProgram( __name__, PROGRAM_NAME_VERSION, LAST_MODIFIED_DATE ) 138 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "Running demo…" ) 139 | 140 | tkRootWindow = tk.Tk() 141 | tkRootWindow.title( PROGRAM_NAME_VERSION ) 142 | 143 | # Program a shutdown 144 | tkRootWindow.after( 2_000, tkRootWindow.destroy ) # Destroy the widget after 2 seconds 145 | 146 | ab = HelpBox( tkRootWindow, PROGRAM_NAME, PROGRAM_NAME_VERSION, BibleOrgSysGlobals.DATAFILES_FOLDERPATH.joinpath( 'BiblelatorLogoSmall.gif' ) ) 147 | #ab = HelpBox2( tkRootWindow, PROGRAM_NAME, PROGRAM_NAME_VERSION, BibleOrgSysGlobals.DATAFILES_FOLDERPATH.joinpath( 'BiblelatorLogoSmall.gif' ) ) 148 | # Calls to the window manager class (wm in Tk) 149 | #tkRootWindow.minsize( application.minimumXSize, application.minimumYSize ) 150 | 151 | # Start the program running 152 | tkRootWindow.mainloop() 153 | # end of Help.briefDemo 154 | 155 | def fullDemo() -> None: 156 | """ 157 | Full demo to check class is working 158 | """ 159 | BibleOrgSysGlobals.introduceProgram( __name__, PROGRAM_NAME_VERSION, LAST_MODIFIED_DATE ) 160 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "Running demo…" ) 161 | 162 | tkRootWindow = tk.Tk() 163 | tkRootWindow.title( PROGRAM_NAME_VERSION ) 164 | 165 | # Program a shutdown 166 | tkRootWindow.after( 30_000, tkRootWindow.destroy ) # Destroy the widget after 30 seconds 167 | 168 | ab = HelpBox( tkRootWindow, PROGRAM_NAME, PROGRAM_NAME_VERSION, BibleOrgSysGlobals.DATAFILES_FOLDERPATH.joinpath( 'BiblelatorLogoSmall.gif' ) ) 169 | #ab = HelpBox2( tkRootWindow, PROGRAM_NAME, PROGRAM_NAME_VERSION, BibleOrgSysGlobals.DATAFILES_FOLDERPATH.joinpath( 'BiblelatorLogoSmall.gif' ) ) 170 | # Calls to the window manager class (wm in Tk) 171 | #tkRootWindow.minsize( application.minimumXSize, application.minimumYSize ) 172 | 173 | # Start the program running 174 | tkRootWindow.mainloop() 175 | # end of Help.fullDemo 176 | 177 | if __name__ == '__main__': 178 | from multiprocessing import freeze_support 179 | freeze_support() # Multiprocessing support for frozen Windows executables 180 | 181 | # Configure basic set-up 182 | parser = BibleOrgSysGlobals.setup( SHORT_PROGRAM_NAME, PROGRAM_VERSION, LAST_MODIFIED_DATE ) 183 | BibleOrgSysGlobals.addStandardOptionsAndProcess( parser ) 184 | 185 | fullDemo() 186 | 187 | BibleOrgSysGlobals.closedown( PROGRAM_NAME, PROGRAM_VERSION ) 188 | # end of Help.py 189 | -------------------------------------------------------------------------------- /Biblelator/Dialogs/ModalDialog.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # ModalDialog.py 5 | # 6 | # Framework for modal dialogs for the Biblelator program. 7 | # 8 | # Adapted from: http://effbot.org/tkinterbook/tkinter-dialog-windows.htm 9 | # 10 | # Copyright (C) 2014-2022 Robert Hunt 11 | # Author: Robert Hunt 12 | # License: See gpl-3.0.txt 13 | # 14 | # This program is free software: you can redistribute it and/or modify 15 | # it under the terms of the GNU General Public License as published by 16 | # the Free Software Foundation, either version 3 of the License, or 17 | # (at your option) any later version. 18 | # 19 | # This program is distributed in the hope that it will be useful, 20 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | # GNU General Public License for more details. 23 | # 24 | # You should have received a copy of the GNU General Public License 25 | # along with this program. If not, see . 26 | 27 | """ 28 | Framework for modal dialogs for the Biblelator program. 29 | """ 30 | from gettext import gettext as _ 31 | from typing import Optional 32 | 33 | import tkinter as tk 34 | from tkinter.ttk import Frame, Button 35 | 36 | # BibleOrgSys imports 37 | from BibleOrgSys import BibleOrgSysGlobals 38 | from BibleOrgSys.BibleOrgSysGlobals import fnPrint, vPrint, dPrint 39 | 40 | # Biblelator imports 41 | if __name__ == '__main__': 42 | import sys 43 | import os 44 | aboveAboveFolderpath = os.path.dirname( os.path.dirname( os.path.dirname( os.path.abspath( __file__ ) ) ) ) 45 | if aboveAboveFolderpath not in sys.path: 46 | sys.path.insert( 0, aboveAboveFolderpath ) 47 | from Biblelator import BiblelatorGlobals 48 | 49 | 50 | LAST_MODIFIED_DATE = '2022-07-13' # by RJH 51 | SHORT_PROGRAM_NAME = "BiblelatorModalDialog" 52 | PROGRAM_NAME = "Biblelator Modal Dialog" 53 | PROGRAM_VERSION = '0.47' 54 | PROGRAM_NAME_VERSION = f'{PROGRAM_NAME} v{PROGRAM_VERSION}' 55 | 56 | DEBUGGING_THIS_MODULE = False 57 | 58 | 59 | 60 | class ModalDialog( tk.Toplevel ): 61 | """ 62 | A Toplevel window that's a modal dialog 63 | and intended to be subclassed. 64 | """ 65 | def __init__(self, parentWindow, title:Optional[str]=None, okText:Optional[str]=None, cancelText:Optional[str]=None, geometry=None) -> None: 66 | fnPrint( DEBUGGING_THIS_MODULE, f"ModalDialog.__init__( {parentWindow}, {title}, {okText}, {cancelText}, {geometry} )" ) 67 | tk.Toplevel.__init__( self, parentWindow ) 68 | self.transient( parentWindow ) 69 | 70 | self.parentWindow = parentWindow 71 | if title: self.title( title ) 72 | 73 | self.result = None # Used to return an optional result 74 | 75 | if okText is None: okText = _("Ok") 76 | self.okText = okText 77 | if cancelText is None: cancelText = _("Cancel") 78 | self.cancelText = cancelText 79 | self.makeButtonBox() 80 | 81 | body = Frame( self ) 82 | self.initial_focus = self.makeBody( body ) # Create the widgets in the body 83 | body.pack( padx=5, pady=5, fill=tk.BOTH, expand=tk.YES ) 84 | 85 | self.grab_set() 86 | 87 | if not self.initial_focus: 88 | self.initial_focus = self 89 | 90 | self.protocol( 'WM_DELETE_WINDOW', self.cancel ) # Ensure that closing the dialog does a cancel 91 | 92 | self.geometry( geometry if geometry else "+{}+{}".format(parentWindow.winfo_rootx()+50, parentWindow.winfo_rooty()+50) ) 93 | 94 | BiblelatorGlobals.theApp.setStatus( _("Waiting for user input…") ) 95 | self.initial_focus.focus_set() 96 | self.wait_window( self ) 97 | # end of ModalDialog.__init__ 98 | 99 | 100 | # construction hooks 101 | def makeBody( self, master ) -> None: 102 | """ 103 | Create dialog body -- this method must be overridden. 104 | 105 | Returns the widget that should have initial focus. 106 | """ 107 | dPrint( 'Normal', DEBUGGING_THIS_MODULE, "This 'body' method must be overridden!" ); halt 108 | # end of ModalDialog.makeBody 109 | 110 | 111 | def makeButtonBox( self ) -> None: 112 | """ 113 | Add our standard button box 114 | 115 | Override if you don't want the standard buttons. 116 | """ 117 | box = Frame( self ) 118 | 119 | self.okButton = Button( box, text=self.okText, width=10, command=self.ok, default=tk.ACTIVE ) 120 | self.okButton.pack( side=tk.LEFT, padx=5, pady=5 ) 121 | self.cancelButton = Button( box, text=self.cancelText, width=10, command=self.cancel ) 122 | self.cancelButton.pack( side=tk.LEFT, padx=5, pady=5 ) 123 | 124 | self.bind( '', self.ok ) 125 | self.bind( '', self.cancel ) 126 | 127 | box.pack( side=tk.BOTTOM ) 128 | # end of ModalDialog.makeButtonBox 129 | 130 | 131 | # 132 | # standard button semantics 133 | def ok( self, event=None ) -> None: 134 | 135 | if not self.validate(): 136 | self.initial_focus.focus_set() # put focus back 137 | return 138 | 139 | self.withdraw() 140 | self.update_idletasks() 141 | 142 | self.apply() 143 | self.cancel() 144 | # end of ModalDialog.ok 145 | 146 | 147 | def cancel( self, event=None ) -> None: 148 | 149 | # put focus back to the parent window 150 | BiblelatorGlobals.theApp.setReadyStatus() 151 | self.parentWindow.focus_set() 152 | self.destroy() 153 | # end of ModalDialog.cancel 154 | 155 | 156 | # 157 | # command hooks 158 | def validate( self ) -> bool: 159 | """ 160 | This method is designed to be overridden 161 | and is called to check the entered data before the window is destroyed. 162 | """ 163 | dPrint( 'Info', DEBUGGING_THIS_MODULE, "This ModalDialog.validate() method can be overridden!" ) 164 | return True # override 165 | # end of ModalDialog.validate 166 | 167 | 168 | def apply( self ) -> None: 169 | """ 170 | This method is designed to be overridden 171 | and is called to obtain the entered data after the window is destroyed. 172 | 173 | It can optionally put the results into self.result (which otherwise defaults to None). 174 | """ 175 | dPrint( 'Quiet', DEBUGGING_THIS_MODULE, "This ModalDialog.apply() method should have been overridden!" ) 176 | self.result = True 177 | # end of ModalDialog.apply 178 | # end of class ModalDialog 179 | 180 | 181 | 182 | class MyTestDialog( ModalDialog ): 183 | 184 | def makeBody( self, master ): 185 | """ 186 | Override the empty ModalDialog.makeBody function 187 | to set up the dialog how we want it. 188 | """ 189 | from tkinter.ttk import Label, Entry 190 | from Biblelator.Windows.TextBoxes import BEntry 191 | 192 | Label( master, text="First:" ).grid( row=0 ) 193 | Label( master, text="Second:" ).grid( row=1 ) 194 | 195 | self.e1 = BEntry( master ) 196 | self.e2 = BEntry( master ) 197 | 198 | self.e1.grid( row=0, column=1 ) 199 | self.e2.grid( row=1, column=1 ) 200 | return self.e1 # initial focus 201 | # end of MyTestDialog.apply 202 | 203 | 204 | def validate( self ) -> bool: 205 | """ 206 | Override the empty ModalDialog.validate function 207 | to check that the results are how we need them. 208 | """ 209 | try: int( self.e1.get() ) and int( self.e2.get() ) 210 | except ValueError: 211 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "ERROR: We need two valid integers!" ) 212 | return False 213 | return True 214 | # end of MyTestDialog.validate 215 | 216 | 217 | def apply( self ) -> None: 218 | """ 219 | Override the empty ModalDialog.apply function 220 | to process the results how we need them. 221 | 222 | Results are left in self.result 223 | """ 224 | first = int( self.e1.get() ) 225 | second = int( self.e2.get() ) 226 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, first, second ) # or something 227 | self.result = (first, second,) 228 | # end of MyTestDialog.apply 229 | # end of class MyTestDialog 230 | 231 | 232 | 233 | def briefDemo() -> None: 234 | """ 235 | Main program to handle command line parameters and then run what they want. 236 | """ 237 | from tkinter import Tk 238 | 239 | BibleOrgSysGlobals.introduceProgram( __name__, PROGRAM_NAME_VERSION, LAST_MODIFIED_DATE ) 240 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "Running demo…" ) 241 | 242 | tkRootWindow = Tk() 243 | tkRootWindow.title( PROGRAM_NAME_VERSION ) 244 | tkRootWindow.parentApp = tkRootWindow 245 | 246 | # Program a shutdown 247 | tkRootWindow.after( 2_000, tkRootWindow.destroy ) # Destroy the widget after 2 seconds 248 | 249 | def ss( a ): pass 250 | tkRootWindow.setStatus = ss 251 | md = MyTestDialog( tkRootWindow, "Just playing" ) 252 | dPrint( 'Quiet', DEBUGGING_THIS_MODULE, "Result is:", repr(md.result) ) 253 | 254 | # Start the program running 255 | tkRootWindow.mainloop() 256 | # end of ModalDialog.briefDemo 257 | 258 | def fullDemo() -> None: 259 | """ 260 | Full demo to check class is working 261 | """ 262 | from tkinter import Tk 263 | 264 | BibleOrgSysGlobals.introduceProgram( __name__, PROGRAM_NAME_VERSION, LAST_MODIFIED_DATE ) 265 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "Running demo…" ) 266 | 267 | tkRootWindow = Tk() 268 | tkRootWindow.title( PROGRAM_NAME_VERSION ) 269 | tkRootWindow.parentApp = tkRootWindow 270 | 271 | # Program a shutdown 272 | tkRootWindow.after( 30_000, tkRootWindow.destroy ) # Destroy the widget after 30 seconds 273 | 274 | def ss( a ): pass 275 | tkRootWindow.setStatus = ss 276 | md = MyTestDialog( tkRootWindow, "Just playing" ) 277 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "Result is:", repr(md.result) ) 278 | 279 | # Start the program running 280 | tkRootWindow.mainloop() 281 | # end of ModalDialog.fullDemo 282 | 283 | if __name__ == '__main__': 284 | from multiprocessing import freeze_support 285 | freeze_support() # Multiprocessing support for frozen Windows executables 286 | 287 | # Configure basic set-up 288 | parser = BibleOrgSysGlobals.setup( SHORT_PROGRAM_NAME, PROGRAM_VERSION, LAST_MODIFIED_DATE ) 289 | BibleOrgSysGlobals.addStandardOptionsAndProcess( parser ) 290 | 291 | fullDemo() 292 | 293 | BibleOrgSysGlobals.closedown( PROGRAM_NAME, PROGRAM_VERSION ) 294 | # end of ModalDialog.py 295 | -------------------------------------------------------------------------------- /Biblelator/Dialogs/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Freely-Given-org/Biblelator/366ba255553dd18b8fb87f433f48ffafdd4108b9/Biblelator/Dialogs/__init__.py -------------------------------------------------------------------------------- /Biblelator/Helpers/AutocorrectFunctions.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # AutocorrectFunctions.py 5 | # 6 | # Functions to support the autocorrect function in text editors 7 | # 8 | # Copyright (C) 2016-2018 Robert Hunt 9 | # Author: Robert Hunt 10 | # License: See gpl-3.0.txt 11 | # 12 | # This program is free software: you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation, either version 3 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License 23 | # along with this program. If not, see . 24 | 25 | """ 26 | """ 27 | 28 | from gettext import gettext as _ 29 | 30 | # BibleOrgSys imports 31 | from BibleOrgSys import BibleOrgSysGlobals 32 | from BibleOrgSys.BibleOrgSysGlobals import fnPrint, vPrint, dPrint 33 | 34 | # Biblelator imports 35 | if __name__ == '__main__': 36 | import sys 37 | aboveAboveFolderpath = os.path.dirname( os.path.dirname( os.path.dirname( os.path.abspath( __file__ ) ) ) ) 38 | if aboveAboveFolderpath not in sys.path: 39 | sys.path.insert( 0, aboveAboveFolderpath ) 40 | from Biblelator import BiblelatorGlobals 41 | 42 | 43 | LAST_MODIFIED_DATE = '2018-03-15' # by RJH 44 | SHORT_PROGRAM_NAME = "AutocorrectFunctions" 45 | PROGRAM_NAME = "Biblelator Autocorrect Functions" 46 | PROGRAM_VERSION = '0.46' 47 | PROGRAM_NAME_VERSION = f'{PROGRAM_NAME} v{PROGRAM_VERSION}' 48 | 49 | DEBUGGING_THIS_MODULE = False 50 | 51 | 52 | 53 | def setAutocorrectEntries( self, autocorrectEntryList, append=False ): 54 | """ 55 | Given a word list, set the entries into the autocorrect words 56 | and then do necessary house-keeping. 57 | 58 | Note that the original word order is preserved (if the autocorrectEntryList has an order) 59 | so that more common/likely words can appear at the top of the list if desired. 60 | """ 61 | if BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 62 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, "AutocorrectFunctions.setAutocorrectEntries( {} )".format( autocorrectEntryList, append ) ) 63 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "AutocorrectFunctions.setAutocorrectEntries( {}.., {} )".format( len(autocorrectEntryList), append ) ) 64 | 65 | if append: self.autocorrectEntries.extend( autocorrectEntryList ) 66 | else: self.autocorrectEntries = autocorrectEntryList 67 | 68 | # This next bit needs to be done whenever the autocorrect entries are changed 69 | self.maxAutocorrectLength = 0 70 | for inChars,outChars in self.autocorrectEntries: 71 | self.maxAutocorrectLength = max( len(inChars), self.maxAutocorrectLength ) 72 | 73 | if BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 74 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, " autocorrect total entries loaded = {:,}".format( len(self.autocorrectEntries) ) ) 75 | # end of AutocorrectFunctions.setAutocorrectEntries 76 | 77 | 78 | def setDefaultAutocorrectEntries( self ): 79 | """ 80 | Given a word list, set the entries into the autocorrect words 81 | and then do necessary house-keeping. 82 | 83 | Note that the original word order is preserved (if the autocorrectEntryList has an order) 84 | so that more common/likely words can appear at the top of the list if desired. 85 | """ 86 | if BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 87 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "AutocorrectFunctions.setDefaultAutocorrectEntries()" ) 88 | 89 | ourAutocorrectEntries = [] 90 | 91 | ourAutocorrectEntries.append( ('<<','“') ) # Cycle through quotes with angle brackets 92 | ourAutocorrectEntries.append( ('“<','‘') ) 93 | ourAutocorrectEntries.append( ('‘<',"'") ) 94 | ourAutocorrectEntries.append( ("'<",'<') ) 95 | ourAutocorrectEntries.append( ('>>','”') ) 96 | ourAutocorrectEntries.append( ('”>','’') ) 97 | ourAutocorrectEntries.append( ('’>',"'") ) 98 | ourAutocorrectEntries.append( ("'>",'>') ) 99 | ourAutocorrectEntries.append( ('--','–') ) # Cycle through en-dash/em-dash with hyphens 100 | ourAutocorrectEntries.append( ('–-','—') ) 101 | ourAutocorrectEntries.append( ('—-','-') ) 102 | ourAutocorrectEntries.append( ('...','…') ) 103 | 104 | ourAutocorrectEntries.append( ('f1','\\f + \\fr ') ) 105 | ourAutocorrectEntries.append( ('f2',' \\ft ') ) 106 | ourAutocorrectEntries.append( ('fh',' \\ft In Hibruwanon: ') ) 107 | ourAutocorrectEntries.append( ('f3','\\f*') ) 108 | 109 | from datetime import datetime # Sorry -- this is a hack for our project 110 | ourAutocorrectEntries.append( ('QQQ',' [{} {}] XXX' \ 111 | .format( BiblelatorGlobals.theApp.currentUserInitials, datetime.now().strftime( '%d%b%y' ) ) ) ) 112 | 113 | # Add trailing spaces on these ones so that autocomplete doesn't kick in as well 114 | #ourAutocorrectEntries.append( ('(in','(incl) ') ) 115 | #ourAutocorrectEntries.append( ('(ex','(excl) ') ) 116 | #ourAutocorrectEntries.append( ('tlg','the Lord God ') ) 117 | 118 | setAutocorrectEntries( self, ourAutocorrectEntries ) 119 | # end of AutocorrectFunctions.setDefaultAutocorrectEntries 120 | 121 | 122 | 123 | def briefDemo() -> None: 124 | """ 125 | Demo program to handle command line parameters and then run what they want. 126 | """ 127 | import tkinter as tk 128 | 129 | BibleOrgSysGlobals.introduceProgram( __name__, PROGRAM_NAME_VERSION, LAST_MODIFIED_DATE ) 130 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "Running demo…" ) 131 | 132 | tkRootWindow = tk.Tk() 133 | tkRootWindow.title( PROGRAM_NAME_VERSION ) 134 | tkRootWindow.textBox = tk.Text( tkRootWindow ) 135 | 136 | #uEW = AutocorrectFunctions( tkRootWindow, None ) 137 | 138 | # Start the program running 139 | tkRootWindow.mainloop() 140 | # end of AutocorrectFunctions.demo 141 | 142 | 143 | def fullDemo() -> None: 144 | """ 145 | Full demo to check class is working 146 | """ 147 | briefDemo() 148 | # end of fullDemo 149 | 150 | if __name__ == '__main__': 151 | from multiprocessing import freeze_support 152 | freeze_support() # Multiprocessing support for frozen Windows executables 153 | 154 | # Configure basic set-up 155 | parser = BibleOrgSysGlobals.setup( SHORT_PROGRAM_NAME, PROGRAM_VERSION, LAST_MODIFIED_DATE ) 156 | BibleOrgSysGlobals.addStandardOptionsAndProcess( parser ) 157 | 158 | fullDemo() 159 | 160 | BibleOrgSysGlobals.closedown( PROGRAM_NAME, PROGRAM_VERSION ) 161 | # end of AutocorrectFunctions.py 162 | -------------------------------------------------------------------------------- /Biblelator/Helpers/BiblelatorHelpers.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # BiblelatorHelpers.py 5 | # 6 | # Various non-GUI helper functions for Biblelator Bible display/editing 7 | # 8 | # Copyright (C) 2014-2020 Robert Hunt 9 | # Author: Robert Hunt 10 | # License: See gpl-3.0.txt 11 | # 12 | # This program is free software: you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation, either version 3 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License 23 | # along with this program. If not, see . 24 | 25 | """ 26 | createEmptyUSFMBookText( BBB, getNumChapters, getNumVerses ) 27 | createEmptyUSFMBooks( folderpath, BBB, availableVersifications, availableVersions, requestDict ) 28 | calculateTotalVersesForBook( BBB, getNumChapters, getNumVerses ) 29 | mapReferenceVerseKey( mainVerseKey ) 30 | mapParallelVerseKey( forGroupCode, mainVerseKey ) 31 | findCurrentSection( currentVerseKey, getNumChapters, getNumVerses, getVerseData ) 32 | logChangedFile( userName, loggingFolder, projectName, savedBBB, bookText ) 33 | parseEnteredBooknameField( bookNameEntry, CEntry, VEntry, BBBfunction ) 34 | 35 | TODO: Can some of these non-GUI functions be (made more general and) moved to the BOS? 36 | """ 37 | from gettext import gettext as _ 38 | import os.path 39 | from datetime import datetime 40 | import re 41 | 42 | # BibleOrgSys imports 43 | from BibleOrgSys import BibleOrgSysGlobals 44 | from BibleOrgSys.BibleOrgSysGlobals import fnPrint, vPrint, dPrint 45 | from BibleOrgSys.Bible import Bible 46 | from BibleOrgSys.Reference.VerseReferences import SimpleVerseKey, BBB_RE #, FlexibleVersesKey 47 | from BibleOrgSys.Reference.BibleReferencesLinks import BibleReferencesLinks 48 | from BibleOrgSys.Internals.InternalBibleInternals import InternalBibleEntry 49 | 50 | # Biblelator imports 51 | if __name__ == '__main__': 52 | import sys 53 | aboveAboveFolderpath = os.path.dirname( os.path.dirname( os.path.dirname( os.path.abspath( __file__ ) ) ) ) 54 | if aboveAboveFolderpath not in sys.path: 55 | sys.path.insert( 0, aboveAboveFolderpath ) 56 | from Biblelator import BiblelatorGlobals 57 | 58 | 59 | LAST_MODIFIED_DATE = '2020-05-10' # by RJH 60 | SHORT_PROGRAM_NAME = "BiblelatorHelpers" 61 | PROGRAM_NAME = "Biblelator helpers" 62 | PROGRAM_VERSION = '0.46' 63 | PROGRAM_NAME_VERSION = f'{PROGRAM_NAME} v{PROGRAM_VERSION}' 64 | 65 | DEBUGGING_THIS_MODULE = False 66 | 67 | 68 | 69 | def createEmptyUSFMBookText( BBB, getNumChapters, getNumVerses ): 70 | """ 71 | Give it the functions for getting the number of chapters and the number of verses 72 | Returns a string that is the text of a blank USFM book. 73 | """ 74 | if BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 75 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "createEmptyUSFMBookText( {} )".format( BBB ) ) 76 | 77 | USFMAbbreviation = BibleOrgSysGlobals.loadedBibleBooksCodes.getUSFMAbbreviation( BBB ) 78 | USFMNumber = BibleOrgSysGlobals.loadedBibleBooksCodes.getUSFMNumStr( BBB ) 79 | bookText = '\\id {} Empty book created by {}\n'.format( USFMAbbreviation.upper(), BiblelatorGlobals.APP_NAME_VERSION ) 80 | bookText += '\\ide UTF-8\n' 81 | bookText += '\\h Bookname\n' 82 | bookText += '\\mt Book Title\n' 83 | try: 84 | for C in range( 1, getNumChapters(BBB)+1 ): 85 | bookText += '\\c {}\n'.format( C ) 86 | for V in range( 1, getNumVerses(BBB,C)+1 ): 87 | bookText += '\\v {} \n'.format( V ) 88 | except TypeError: # if something is None (i.e., a book without chapters or verses) 89 | pass 90 | return bookText 91 | # end of BiblelatorHelpers.createEmptyUSFMBookText 92 | 93 | 94 | 95 | def createEmptyUSFMBooks( folderpath, currentBBB, requestDict ): 96 | """ 97 | Create empty USFM books or CV shells in the given folderpath 98 | as requested by the dictionary parameters: 99 | Books: 'OT' 100 | Fill: 'Versification' 101 | Versification: 'KJV' 102 | Version: 'KJV1611' 103 | """ 104 | from BibleOrgSys.Reference.BibleVersificationSystems import BibleVersificationSystem 105 | from BibleOrgSys.Internals.InternalBible import OT39_BOOKLIST, NT27_BOOKLIST 106 | from BibleOrgSys.Internals.InternalBibleInternals import BOS_ALL_ADDED_MARKERS 107 | from BibleOrgSys.Formats.USFMBible import USFMBible 108 | 109 | if BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 110 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "createEmptyUSFMBooks( {}, {}, {} )".format( folderpath, currentBBB, requestDict ) ) 111 | 112 | 113 | versificationObject = BibleVersificationSystem( requestDict['Versification'] ) \ 114 | if requestDict['Fill']=='Versification' else None 115 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, 'versificationObject', versificationObject ) 116 | if versificationObject is not None: 117 | getNumChapters, getNumVerses = versificationObject.getNumChapters, versificationObject.getNumVerses 118 | 119 | if requestDict['Fill'] == 'Version': 120 | uB = USFMBible( requestDict['Version'] ) # Get the Bible object 121 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "Fill Bible1", uB ) 122 | uB.preload() 123 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "Fill Bible2", uB ) 124 | #uB.loadBooks() 125 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, "Fill Bible3", uB ) 126 | 127 | if requestDict['Books'] == 'None': booklist = [] 128 | elif requestDict['Books'] == 'Current': booklist = [ currentBBB ] 129 | elif requestDict['Books'] == 'All': booklist = OT39_BOOKLIST + NT27_BOOKLIST 130 | elif requestDict['Books'] == 'OT': booklist = OT39_BOOKLIST 131 | elif requestDict['Books'] == 'NT': booklist = NT27_BOOKLIST 132 | else: halt # programming error 133 | 134 | count = 0 135 | skippedBooklist = [] 136 | for BBB in booklist: 137 | if requestDict['Fill'] == 'Versification' \ 138 | and versificationObject is not None \ 139 | and BBB not in versificationObject: 140 | skippedBooklist.append( BBB ) 141 | continue 142 | #if requestDict['Fill'] == 'Version' \ 143 | #and uB is not None \ 144 | #and BBB not in uB: 145 | #skippedBooklist.append( BBB ) 146 | #continue 147 | 148 | USFMAbbreviation = BibleOrgSysGlobals.loadedBibleBooksCodes.getUSFMAbbreviation( BBB ) 149 | USFMNumber = BibleOrgSysGlobals.loadedBibleBooksCodes.getUSFMNumStr( BBB ) 150 | 151 | if requestDict['Fill'] == 'None': bookText = '' 152 | elif requestDict['Fill'] == 'Basic': 153 | bookText = '\\id {} Empty book created by {}\n'.format( USFMAbbreviation.upper(), BiblelatorGlobals.APP_NAME_VERSION ) 154 | bookText += '\\ide UTF-8\n' 155 | bookText += '\\h Bookname\n' 156 | bookText += '\\mt Book Title\n' 157 | bookText += '\\c 1\n' 158 | elif requestDict['Fill'] == 'Versification': 159 | bookText = createEmptyUSFMBookText( BBB, getNumChapters, getNumVerses ) 160 | elif requestDict['Fill'] == 'Version': 161 | try: uB.loadBook( BBB ) 162 | except FileNotFoundError: 163 | skippedBooklist.append( BBB ) 164 | continue 165 | uBB = uB[BBB] # Get the Bible book object 166 | bookText = '' 167 | for verseDataEntry in uBB._processedLines: 168 | pseudoMarker, cleanText = verseDataEntry.getMarker(), verseDataEntry.getCleanText() 169 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, BBB, pseudoMarker, repr(cleanText) ) 170 | if '¬' in pseudoMarker or pseudoMarker in BOS_ALL_ADDED_MARKERS or pseudoMarker in ('c#','vp#',): 171 | continue # Just ignore added markers -- not needed here 172 | #if pseudoMarker in ('v','f','fr','x','xo',): # These fields should always end with a space but the processing will have removed them 173 | #pseudoMarker += ' ' # Append a space since it didn't have one 174 | #if pseudoMarker in USFMAllExpandedCharacterMarkers: # Character markers to be closed 175 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, "CHAR MARKER" ) 176 | #pass 177 | ##if (USFM[-2]=='\\' or USFM[-3]=='\\') and USFM[-1]!=' ': 178 | #if bookText[-1] != ' ': 179 | #bookText += ' ' # Separate markers by a space e.g., \p\bk Revelation 180 | #if BibleOrgSysGlobals.debugFlag: vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "toUSFM: Added space to {!r} before {!r}".format( bookText[-2], pseudoMarker ) ) 181 | #adjValue += '\\{}*'.format( pseudoMarker ) # Do a close marker 182 | #elif pseudoMarker in ('f','x',): inField = pseudoMarker # Remember these so we can close them later 183 | #elif pseudoMarker in ('fr','fq','ft','xo',): USFM += ' ' # These go on the same line just separated by spaces and don't get closed 184 | if bookText: bookText += '\n' # paragraph markers go on a new line 185 | if not cleanText: bookText += '\\{}'.format( pseudoMarker ) 186 | elif pseudoMarker == 'c': bookText += '\\c {}'.format( cleanText ) 187 | elif pseudoMarker == 'v': bookText += '\\v {} '.format( cleanText ) 188 | else: bookText += '\\{} '.format( pseudoMarker ) 189 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, pseudoMarker, USFM[-200:] ) 190 | else: halt # programming error 191 | 192 | # Write the actual file 193 | filename = '{}-{}.USFM'.format( USFMNumber, USFMAbbreviation ) 194 | with open( os.path.join( folderpath, filename ), mode='wt', encoding='utf-8' ) as theFile: 195 | theFile.write( bookText ) 196 | count += 1 197 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, len(skippedBooklist), "books skipped:", skippedBooklist ) # Should warn the user here 198 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, count, "books created" ) 199 | # end of BiblelatorHelpers.createEmptyUSFMBooks 200 | 201 | 202 | 203 | def calculateTotalVersesForBook( BBB, getNumChapters, getNumVerses ): 204 | """ 205 | Give it the functions for getting the number of chapters and number of verses 206 | Returns the total number of verses in the book 207 | """ 208 | if BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 209 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "calculateTotalVersesForBook( {} )".format( BBB ) ) 210 | totalVerses = 0 211 | try: 212 | for C in range( 1, getNumChapters(BBB)+1 ): 213 | totalVerses += getNumVerses( BBB, C ) 214 | return totalVerses 215 | except TypeError: # if something is None (i.e., a book without chapters or verses) 216 | return 1 217 | # end of BiblelatorHelpers.calculateTotalVersesForBook 218 | 219 | 220 | 221 | def mapReferenceVerseKey( mainVerseKey ): 222 | """ 223 | Returns the verse key for OT references in the NT (and vv), etc. 224 | 225 | Returns None if we don't have a mapping. 226 | """ 227 | if BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 228 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "mapReferenceVerseKey( {} )".format( mainVerseKey.getShortText() ) ) 229 | 230 | # A (temporary) dictionary containing NT references to OT 231 | REFERENCE_VERSE_KEY_DICT = { 232 | SimpleVerseKey('MAT','2','18'): SimpleVerseKey('JER','31','15'), 233 | SimpleVerseKey('MAT','3','3'): SimpleVerseKey('ISA','40','3'), 234 | } 235 | 236 | if mainVerseKey in REFERENCE_VERSE_KEY_DICT: 237 | vPrint( 'Never', DEBUGGING_THIS_MODULE, ' returning {}'.format( REFERENCE_VERSE_KEY_DICT[mainVerseKey].getShortText() ) ) 238 | return REFERENCE_VERSE_KEY_DICT[mainVerseKey] 239 | # end of BiblelatorHelpers.mapReferenceVerseKey 240 | 241 | 242 | def mapParallelVerseKey( forGroupCode, mainVerseKey ): 243 | """ 244 | Returns the verse key for synoptic references in the NT, etc. 245 | 246 | Returns None if we don't have a mapping. 247 | """ 248 | if BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 249 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "mapParallelVerseKey( {}, {} )".format( forGroupCode, mainVerseKey.getShortText() ) ) 250 | groupIndex = BiblelatorGlobals.BIBLE_GROUP_CODES.index( forGroupCode ) - 1 251 | parallelVerseKeyDict = { 252 | SimpleVerseKey('MAT','3','13'): (SimpleVerseKey('MRK','1','9'), SimpleVerseKey('LUK','3','21'), SimpleVerseKey('JHN','1','31') ) 253 | } 254 | if mainVerseKey in parallelVerseKeyDict: 255 | vPrint( 'Never', DEBUGGING_THIS_MODULE, ' returning {}'.format( parallelVerseKeyDict[mainVerseKey][groupIndex].getShortText() ) ) 256 | return parallelVerseKeyDict[mainVerseKey][groupIndex] 257 | # end of BiblelatorHelpers.mapParallelVerseKey 258 | 259 | 260 | 261 | loadedReferences = None 262 | def mapReferencesVerseKey( mainVerseKey ): 263 | """ 264 | Returns the list of FlexibleVerseKeys for references related to the given verse key. 265 | 266 | Returns None if we don't have a mapping. 267 | """ 268 | global loadedReferences 269 | if BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 270 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "mapReferencesVerseKey( {} )".format( mainVerseKey.getShortText() ) ) 271 | if loadedReferences is None: 272 | loadedReferences = BibleReferencesLinks() 273 | loadedReferences.loadData() 274 | result = loadedReferences.getRelatedPassagesList( mainVerseKey ) 275 | # Returns a list containing 2-tuples: 276 | # 0: Link type ('QuotedOTReference','AlludedOTReference','PossibleOTReference') 277 | # 1: Link FlexibleVersesKey object 278 | if BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 279 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, " mapReferencesVerseKey got result:", result ) 280 | resultList = [] 281 | if result is not None: 282 | for linkType, link in result: 283 | resultList.append( link ) 284 | return resultList 285 | # old sample code 286 | #REFERENCE_VERSE_KEY_DICT = { 287 | #SimpleVerseKey('MAT','2','18'): SimpleVerseKey('JER','31','15'), 288 | #SimpleVerseKey('MAT','3','3'): FlexibleVersesKey( 'ISA_40:3,7,14-15' ), 289 | #} 290 | #if mainVerseKey in REFERENCE_VERSE_KEY_DICT: 291 | #if BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 292 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, ' returning {}'.format( REFERENCE_VERSE_KEY_DICT[mainVerseKey].getShortText() ) ) 293 | #return REFERENCE_VERSE_KEY_DICT[mainVerseKey] 294 | # end of BiblelatorHelpers.mapReferencesVerseKey 295 | 296 | 297 | 298 | def findCurrentSection( currentVerseKey, getNumChapters, getNumVerses, getVerseData ): 299 | """ 300 | Given the current verseKey 301 | and functions to find the number of chapters and verses in the book 302 | and a function to get verse data (probably cached), 303 | find the beginning and end of the current section. 304 | 305 | Returns the verseKey for the start of the section 306 | and for the end of the section -- well actually the start of the next section. 307 | 308 | If no sections are found, it goes a maximum of one chapter back or one chapter forward. 309 | """ 310 | if BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 311 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "findCurrentSection( {}, … )".format( currentVerseKey.getShortText() ) ) 312 | 313 | def sectionFoundIn( verseData ): 314 | """ 315 | Given some verse data (a string or an InternalBibleEntryList 316 | returns True or False whether a section heading is found in it 317 | """ 318 | fnPrint( DEBUGGING_THIS_MODULE, f"sectionFoundIn( {verseData} )" ) 319 | 320 | if verseData is None: return False 321 | 322 | elif isinstance( verseData, str ): 323 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, " It's a string!" ) 324 | if '\\s ' in thisVerseData or '\\s1' in thisVerseData \ 325 | or '\\s2' in thisVerseData or '\\s3' in thisVerseData: 326 | return True 327 | 328 | elif isinstance( verseData, tuple ): 329 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, " It's an InternalBibleEntryList!" ) 330 | assert len(verseData) == 2 331 | verseDataList, context = verseData 332 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, ' dataList', repr(verseDataList) ) 333 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, ' context', repr(context) ) 334 | for verseDataEntry in verseDataList: 335 | if isinstance( verseDataEntry, InternalBibleEntry ): 336 | marker, cleanText = verseDataEntry.getMarker(), verseDataEntry.getCleanText() 337 | elif isinstance( verseDataEntry, tuple ): 338 | marker, cleanText = verseDataEntry[0], verseDataEntry[3] 339 | elif isinstance( verseDataEntry, str ): 340 | if verseDataEntry=='': continue 341 | verseDataEntry += '\n' 342 | if verseDataEntry[0]=='\\': 343 | marker = '' 344 | for char in verseDataEntry[1:]: 345 | if char!='¬' and not char.isalnum(): break 346 | marker += char 347 | cleanText = verseDataEntry[len(marker)+1:].lstrip() 348 | else: 349 | marker, cleanText = None, verseDataEntry 350 | elif BibleOrgSysGlobals.debugFlag: halt 351 | if marker in ( 's','s1','s2','s3','s4' ): return True 352 | 353 | else: 354 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, 'Ooops', repr(verseData) ) 355 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, verseData.__type__ ) 356 | halt # Programming error 357 | 358 | return False 359 | # end of sectionFoundIn 360 | 361 | # Start of main section of findCurrentSection 362 | BBB, C, V = currentVerseKey.getBCV() 363 | intC, intV = currentVerseKey.getChapterNumberInt(), currentVerseKey.getVerseNumberInt() 364 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, 'fCS at', BBB, C, intC, V, intV ) 365 | 366 | # First let's find the beginning of the section 367 | # which could be in the current verse/chapter, 368 | # or in the previous chapter (at most we assume) 369 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, 'fCS finding start…' ) 370 | firstC = max( intC-1, 0 ) 371 | found = False 372 | for thisC in reversed( range( firstC, intC+1 ) ): # Look backwards 373 | numVerses = getNumVerses( BBB, thisC ) 374 | startV, endV = 0, numVerses 375 | if thisC == intC: endV = min( intV, numVerses ) 376 | for thisV in reversed( range( startV, endV+1 ) ): 377 | thisVerseKey = SimpleVerseKey( BBB, thisC, thisV ) 378 | thisVerseData = getVerseData( thisVerseKey ) 379 | if DEBUGGING_THIS_MODULE: ( ' ', thisC, thisV, repr(thisVerseData) ) 380 | if sectionFoundIn( thisVerseData ): 381 | found = thisC, thisV; break 382 | if found: break 383 | if not found: found = firstC, 0 384 | startKey = SimpleVerseKey( BBB, found[0], found[1] ) 385 | 386 | # Now let's find the end of the section 387 | # which could be in the current chapter, or in the next chapter (at most we assume) 388 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, 'fCS finding end…' ) 389 | lastC = min( intC+1, getNumChapters( BBB ) ) 390 | found = False 391 | for thisC in range( intC, lastC+1 ): 392 | numVerses = getNumVerses( BBB, thisC ) 393 | startV, endV = 0, numVerses 394 | if thisC == intC: startV = min( intV+1, numVerses ) 395 | for thisV in range( startV, endV+1 ): 396 | thisVerseKey = SimpleVerseKey( BBB, thisC, thisV ) 397 | thisVerseData = getVerseData( thisVerseKey ) 398 | if DEBUGGING_THIS_MODULE: ( ' ', thisC, thisV, repr(thisVerseData) ) 399 | if sectionFoundIn( thisVerseData ): 400 | found = thisC, thisV; break 401 | if found: break 402 | if not found: found = lastC, numVerses 403 | endKey = SimpleVerseKey( BBB, found[0], found[1] ) 404 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, "fCS returning", startKey.getShortText(), endKey.getShortText() ) 405 | return startKey, endKey 406 | # end of BiblelatorHelpers.findCurrentSection 407 | 408 | 409 | 410 | def handleInternalBibles( internalBible:Bible, controllingWindow ) -> Bible: 411 | """ 412 | Try to only have one copy of internal Bibles 413 | even if it's open in multiple windows. 414 | 415 | Note that Biblelator never directly changes InternalBible objects -- 416 | they are effectively 'read-only'. 417 | 418 | Returns an internal Bible object. 419 | """ 420 | debuggingThisFunction = False 421 | if debuggingThisFunction or (BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE): 422 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "handleInternalBibles( {}, {} )".format( internalBible, controllingWindow ) ) 423 | assert isinstance( internalBible, Bible ) 424 | #BiblelatorGlobals.theApp.setDebugText( "handleInternalBibles" ) 425 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, "hereHIB0", repr(internalBible), len(BiblelatorGlobals.theApp.internalBibles) ) 426 | 427 | result = internalBible # Default to returning what we were given 428 | if debuggingThisFunction and internalBible is None: 429 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, " hIB: Got None" ) 430 | if internalBible is not None: 431 | if debuggingThisFunction: vPrint( 'Quiet', DEBUGGING_THIS_MODULE, " hIB: Not None" ) 432 | foundControllingWindowList = None 433 | for iB,cWs in BiblelatorGlobals.theApp.internalBibles: 434 | # Some of these variables will be None but they'll still match 435 | #and internalBible.sourceFilepath == iB.sourceFilepath \ # PTX Bible sets sourceFilepath but others don't! 436 | if type(internalBible) is type(iB) \ 437 | and internalBible.abbreviation and internalBible.abbreviation == iB.abbreviation \ 438 | and internalBible.name and internalBible.name == iB.name \ 439 | and internalBible.sourceFilename and internalBible.sourceFilename == iB.sourceFilename \ 440 | and internalBible.encoding == iB.encoding: # Let's assume they're the same 441 | if internalBible.sourceFolder == iB.sourceFolder: 442 | if debuggingThisFunction: vPrint( 'Quiet', DEBUGGING_THIS_MODULE, " Got an IB match for {}!".format( iB.name ) ) 443 | result, foundControllingWindowList = iB, cWs 444 | break 445 | else: 446 | if debuggingThisFunction: 447 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "handleInternalBibles: Got an almost IB match for {}!".format( iB.name ) ) 448 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, " Source folders didn't match: {!r}\n and {!r}".format( internalBible.sourceFolder, iB.sourceFolder ) ) 449 | result, foundControllingWindowList = iB, cWs 450 | break 451 | 452 | if foundControllingWindowList is None: BiblelatorGlobals.theApp.internalBibles.append( (internalBible,[controllingWindow]) ) 453 | else: foundControllingWindowList.append( controllingWindow ) 454 | 455 | if debuggingThisFunction or DEBUGGING_THIS_MODULE or (BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE): 456 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "Internal Bibles ({}) now:".format( len(BiblelatorGlobals.theApp.internalBibles) ) ) 457 | for something in BiblelatorGlobals.theApp.internalBibles: 458 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, " ", something ) 459 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, BiblelatorGlobals.theApp.internalBibles ) 460 | for j,(iB,cWs) in enumerate( BiblelatorGlobals.theApp.internalBibles ): 461 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, " {}/ {} in {}".format( j+1, iB.getAName(), cWs ) ) 462 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, " {!r} {!r} {!r} {!r}".format( iB.name, iB.givenName, iB.shortName, iB.abbreviation ) ) 463 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, " {!r} {!r} {!r} {!r}".format( iB.sourceFolder, iB.sourceFilename, iB.sourceFilepath, iB.fileExtension ) ) 464 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, " {!r} {!r} {!r} {!r}".format( iB.status, iB.revision, iB.version, iB.encoding ) ) 465 | 466 | if DEBUGGING_THIS_MODULE or debuggingThisFunction: 467 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, f" handleInternalBibles is returning: {result}") 468 | return result 469 | # end of BiblelatorHelpers.handleInternalBibles 470 | 471 | 472 | def getChangeLogFilepath( loggingFolder, projectName ): 473 | """ 474 | """ 475 | return os.path.join( loggingFolder, \ 476 | BibleOrgSysGlobals.makeSafeFilename( projectName.replace(' ','_') + '_ChangeLog.txt' ) ) 477 | # end of BiblelatorHelpers.getChangeLogFilepath 478 | 479 | 480 | def logChangedFile( userName, loggingFolder, projectName, savedBBB, bookText ): 481 | """ 482 | Just logs some info about the recently changed book to a log file for the project. 483 | """ 484 | #if BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 485 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, "logChangedFile( {}, {!r}, {}, {} )".format( loggingFolder, projectName, savedBBB, len(bookText) ) ) 486 | 487 | filepath = getChangeLogFilepath( loggingFolder, projectName ) 488 | 489 | ## TODO: Why don't we just append it to the existing file??? 490 | #try: logText = open( filepath, 'rt', encoding='utf-8' ).read() 491 | #except FileNotFoundError: logText = '' 492 | 493 | logText = '{} {} {:,} characters ({} chapters, {:,} verses) saved by {}\n' \ 494 | .format( datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 495 | savedBBB, len(bookText), bookText.count( '\\c ' ), bookText.count( '\\v ' ), userName ) 496 | with open( filepath, 'at', encoding='utf-8' ) as logFile: # Append puts the file pointer at the end of the file 497 | logFile.write( logText ) 498 | # end of BiblelatorHelpers.logChangedFile 499 | 500 | 501 | 502 | def parseEnteredBooknameField( bookNameEntry, currentBBB, CEntry, VEntry, BBBfunction ): 503 | """ 504 | Checks if the bookName entry is just a book name, or an entire reference (e.g., "Gn 15:2") 505 | 506 | BBBfunction is a function to find BBB from a word/string. 507 | 508 | Returns the discovered BBB, C, V 509 | 510 | NOTE: We don't validate that they are valid C V combinations 511 | """ 512 | debuggingThisFunction = False 513 | 514 | if debuggingThisFunction or BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 515 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "parseEnteredBooknameField( {!r}, {}, {!r}, {!r}, … )" \ 516 | .format( bookNameEntry, currentBBB, CEntry, VEntry ) ) 517 | 518 | # Do a bit of preliminary cleaning-up 519 | bookNameEntry = bookNameEntry.strip().replace( ' ', ' ' ) 520 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, "parseEnteredBooknameField: pulling apart {!r}".format( bookNameEntry ) ) 521 | 522 | # Without the bookname (i.e., stay in current book) 523 | # Do these first because they are more strict (only digits and use re.fullmatch not re.search or re.match) 524 | match = re.fullmatch( '(\d{1,3})[:\. ](\d{1,3})', bookNameEntry ) # (Current book) C:V or C.V or C V 525 | if match: 526 | if debuggingThisFunction or BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 527 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, " matched CV! {!r} {!r}".format( match.group(1), match.group(2) ) ) 528 | return currentBBB, match.group(1), match.group(2) 529 | match = re.fullmatch( '(\d{1,3})', bookNameEntry ) # (Current book) C 530 | if match: 531 | if debuggingThisFunction or BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 532 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, " matched C or V! {!r} as {!r} from {!r}".format( match.group(0), match.group(1), bookNameEntry ) ) 533 | if BibleOrgSysGlobals.loadedBibleBooksCodes.isSingleChapterBook( currentBBB ): # take it as a V (not a C) 534 | return currentBBB, 1, match.group(1) 535 | return currentBBB, match.group(1), 1 536 | match = re.fullmatch( '[Vv:\.](\d{1,3})', bookNameEntry ) # (Current book) V 537 | if match: 538 | if debuggingThisFunction or BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 539 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, " matchedV! {!r}".format( match.group(1) ) ) 540 | return currentBBB, CEntry, match.group(1) 541 | 542 | # With a BBB first on the line 543 | uppercaseBookNameEntry = bookNameEntry.upper() 544 | match = re.fullmatch( BBB_RE + '[ ]{0,1}(\d{1,3})[:\. ](\d{1,3})', uppercaseBookNameEntry ) # bookname C:V or C.V or C V 545 | if match: 546 | if debuggingThisFunction or BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 547 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, " matchedBBBCV! {!r} {!r} {!r}".format( match.group(1), match.group(2), match.group(3) ) ) 548 | newBBB = match.group(1) 549 | if BibleOrgSysGlobals.loadedBibleBooksCodes.isValidBBB( newBBB ): # confirm that it's a BBB 550 | return newBBB, match.group(2), match.group(3) 551 | match = re.fullmatch( BBB_RE + '[ ]{0,1}[Vv:\.](\d{1,3})', uppercaseBookNameEntry ) # bookname (single chapter book) V 552 | if match: 553 | if debuggingThisFunction or BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 554 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, " matchedBBBV! {!r} {!r} (for chapter {!r})".format( match.group(1), match.group(2), CEntry ) ) 555 | newBBB = match.group(1) 556 | if BibleOrgSysGlobals.loadedBibleBooksCodes.isValidBBB( newBBB ): # confirm that it's a BBB 557 | return newBBB, CEntry, match.group(2) 558 | match = re.fullmatch( BBB_RE + '[ ]{0,1}(\d{1,3})', uppercaseBookNameEntry ) # bookname C (or single chapter book with V) 559 | if match: 560 | if debuggingThisFunction or BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 561 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, " matchedBBB C or V! {!r} {!r}".format( match.group(1), match.group(2) ) ) 562 | newBBB = match.group(1) 563 | if BibleOrgSysGlobals.loadedBibleBooksCodes.isValidBBB( newBBB ): # confirm that it's a BBB 564 | if BibleOrgSysGlobals.loadedBibleBooksCodes.isSingleChapterBook( newBBB ): # take it as a V (not a C) 565 | return newBBB, 1, match.group(2) 566 | return newBBB, match.group(2), 1 567 | 568 | # With a bookname first on the line 569 | match = re.fullmatch( '([123]{0,1}?\D+?)[ ]{0,1}(\d{1,3})[:\. ](\d{1,3})', bookNameEntry ) # bookname C:V or C.V or C V 570 | if match: 571 | if debuggingThisFunction or BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 572 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, " matchedBCV! {!r} {!r} {!r}".format( match.group(1), match.group(2), match.group(3) ) ) 573 | return BBBfunction( match.group(1) ), match.group(2), match.group(3) 574 | match = re.fullmatch( '([123]{0,1}?\D+?)[ ]{0,1}[Vv:\.](\d{1,3})', bookNameEntry ) # bookname (single chapter book) V 575 | if match: 576 | if debuggingThisFunction or BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 577 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, " matchedBV! {!r} {!r} (for chapter {!r})".format( match.group(1), match.group(2), CEntry ) ) 578 | newBBB = BBBfunction( match.group(1) ) 579 | return newBBB, CEntry, match.group(2) 580 | match = re.fullmatch( '([123]{0,1}?\D+?)[ ]{0,1}(\d{1,3})', bookNameEntry ) # bookname C (or single chapter book with V) 581 | if match: 582 | if debuggingThisFunction or BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 583 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, " matchedB C or V! {!r} {!r}".format( match.group(1), match.group(2) ) ) 584 | newBBB = BBBfunction( match.group(1) ) 585 | if BibleOrgSysGlobals.loadedBibleBooksCodes.isSingleChapterBook( newBBB ): # take it as a V (not a C) 586 | return newBBB, 1, match.group(2) 587 | return newBBB, match.group(2), 1 588 | 589 | #else: # assume it's just a book name (with no C or V specified) 590 | newBBB = BBBfunction( bookNameEntry ) 591 | if newBBB == currentBBB: 592 | return newBBB, CEntry, VEntry 593 | else: return newBBB, 1, 1 # Go to the first verse 594 | # end of BiblelatorHelpers.parseEnteredBooknameField 595 | 596 | 597 | 598 | def briefDemo() -> None: 599 | """ 600 | Main program to handle command line parameters and then run what they want. 601 | """ 602 | from tkinter import Tk 603 | 604 | BibleOrgSysGlobals.introduceProgram( __name__, PROGRAM_NAME_VERSION, LAST_MODIFIED_DATE ) 605 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "Running demo…" ) 606 | 607 | tkRootWindow = Tk() 608 | tkRootWindow.title( PROGRAM_NAME_VERSION ) 609 | 610 | #swnd = SaveWindowsLayoutNameDialog( tkRootWindow, ["aaa","BBB","CcC"], "Test SWND" ) 611 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, "swndResult", swnd.result ) 612 | #dwnd = DeleteWindowsLayoutNameDialog( tkRootWindow, ["aaa","BBB","CcC"], "Test DWND" ) 613 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, "dwndResult", dwnd.result ) 614 | #srb = SelectResourceBox( tkRootWindow, [(x,y) for x,y, in {"ESV":"ENGESV","WEB":"ENGWEB","MS":"MBTWBT"}.items()], "Test SRB" ) 615 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, "srbResult", srb.result ) 616 | 617 | # Program a shutdown 618 | tkRootWindow.after( 2_000, tkRootWindow.destroy ) # Destroy the widget after 2 seconds 619 | 620 | # Start the program running 621 | #tkRootWindow.mainloop() 622 | # end of BiblelatorHelpers.briefDemo 623 | 624 | def fullDemo() -> None: 625 | """ 626 | Full demo to check class is working 627 | """ 628 | from tkinter import Tk 629 | 630 | BibleOrgSysGlobals.introduceProgram( __name__, PROGRAM_NAME_VERSION, LAST_MODIFIED_DATE ) 631 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "Running demo…" ) 632 | 633 | tkRootWindow = Tk() 634 | tkRootWindow.title( PROGRAM_NAME_VERSION ) 635 | 636 | #swnd = SaveWindowsLayoutNameDialog( tkRootWindow, ["aaa","BBB","CcC"], "Test SWND" ) 637 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, "swndResult", swnd.result ) 638 | #dwnd = DeleteWindowsLayoutNameDialog( tkRootWindow, ["aaa","BBB","CcC"], "Test DWND" ) 639 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, "dwndResult", dwnd.result ) 640 | #srb = SelectResourceBox( tkRootWindow, [(x,y) for x,y, in {"ESV":"ENGESV","WEB":"ENGWEB","MS":"MBTWBT"}.items()], "Test SRB" ) 641 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, "srbResult", srb.result ) 642 | 643 | # Program a shutdown 644 | tkRootWindow.after( 30_000, tkRootWindow.destroy ) # Destroy the widget after 30 seconds 645 | 646 | # Start the program running 647 | #tkRootWindow.mainloop() 648 | # end of BiblelatorHelpers.fullDemo 649 | 650 | if __name__ == '__main__': 651 | from multiprocessing import freeze_support 652 | freeze_support() # Multiprocessing support for frozen Windows executables 653 | 654 | # Configure basic set-up 655 | parser = BibleOrgSysGlobals.setup( SHORT_PROGRAM_NAME, PROGRAM_VERSION, LAST_MODIFIED_DATE ) 656 | BibleOrgSysGlobals.addStandardOptionsAndProcess( parser ) 657 | 658 | fullDemo() 659 | 660 | BibleOrgSysGlobals.closedown( PROGRAM_NAME, PROGRAM_VERSION ) 661 | # end of BiblelatorHelpers.py 662 | -------------------------------------------------------------------------------- /Biblelator/Helpers/SpellChecking.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # SpellChecking.py 5 | # 6 | # Main program for Biblelator Bible spell-checking 7 | # 8 | # Copyright (C) 2016 Robert Hunt 9 | # Author: Robert Hunt 10 | # License: See gpl-3.0.txt 11 | # 12 | # This program is free software: you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation, either version 3 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License 23 | # along with this program. If not, see . 24 | 25 | """ 26 | Program to allow editing of USFM Bibles using Python3 and Tkinter. 27 | """ 28 | 29 | from gettext import gettext as _ 30 | #import sys 31 | 32 | import tkinter as tk 33 | from tkinter.scrolledtext import ScrolledText 34 | from tkinter.ttk import Button 35 | 36 | if __name__ == '__main__': 37 | import sys 38 | aboveAboveFolderpath = os.path.dirname( os.path.dirname( os.path.dirname( os.path.abspath( __file__ ) ) ) ) 39 | if aboveAboveFolderpath not in sys.path: 40 | sys.path.insert( 0, aboveAboveFolderpath ) 41 | from Biblelator.BiblelatorGlobals import parseWindowSize, centreWindowOnWindow 42 | 43 | from BibleOrgSys import BibleOrgSysGlobals 44 | from BibleOrgSys.BibleOrgSysGlobals import fnPrint, vPrint, dPrint 45 | 46 | 47 | LAST_MODIFIED_DATE = '2016-11-03' # by RJH 48 | SHORT_PROGRAM_NAME = "SpellChecking" 49 | PROGRAM_NAME = "Spell Checking routines" 50 | PROGRAM_VERSION = '0.39' # Still just a copy of "About.py" 51 | PROGRAM_NAME_VERSION = f'{PROGRAM_NAME} v{PROGRAM_VERSION}' 52 | 53 | DEBUGGING_THIS_MODULE = False 54 | 55 | 56 | 57 | class SpellCheckingBox( tk.Toplevel ): 58 | def __init__( self, parent=None, progName=None, text=None ): 59 | #if BibleOrgSysGlobals.debugFlag: vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "SpellCheckingBox.__init__( {} )".format( parent ) ) 60 | tk.Toplevel.__init__( self, parent ) 61 | self.minimumSize = MINIMUM_ABOUT_SIZE 62 | self.minsize( *parseWindowSize( self.minimumSize ) ) 63 | self.maximumSize = MAXIMUM_ABOUT_SIZE 64 | self.maxsize( *parseWindowSize( self.maximumSize ) ) 65 | if parent: centreWindowOnWindow( self, parent ) 66 | 67 | self.okButton = Button( self, text=_("Ok"), command=self.destroy ) 68 | self.okButton.pack( side=tk.BOTTOM ) 69 | 70 | self.title( 'SpellChecking '+progName ) 71 | self.textBox = ScrolledText( self ) #, state=tk.DISABLED ) 72 | self.textBox.configure( wrap='word' ) 73 | self.textBox.pack( expand=tk.YES ) 74 | self.textBox.insert( tk.END, text ) 75 | self.textBox.configure( state=tk.DISABLED ) # Don't allow editing 76 | 77 | self.focus_set() # take over input focus, 78 | self.grab_set() # disable other windows while I'm open, 79 | self.wait_window() # and wait here until win destroyed 80 | # end of SpellCheckingBox.__init__ 81 | # end of class SpellCheckingBox 82 | 83 | 84 | class SpellCheckingBox2(): 85 | def __init__( self, parent=None, progName=None, text=None ): 86 | #if BibleOrgSysGlobals.debugFlag: vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "SpellCheckingBox2.__init__( {} )".format( parent ) ) 87 | ab = tk.Toplevel( parent ) 88 | self.minimumXSize, self.minimumYSize = MINIMUM_ABOUT_X_SIZE, MINIMUM_ABOUT_Y_SIZE 89 | ab.minsize( self.minimumXSize, self.minimumYSize ) 90 | if parent: centreWindowOnWindow( ab, parent ) 91 | 92 | self.okButton = Button( ab, text=_("Ok"), command=ab.destroy ) 93 | self.okButton.pack( side=tk.BOTTOM ) 94 | 95 | ab.title( 'SpellChecking '+progName ) 96 | textBox = ScrolledText( ab ) #, state=tk.DISABLED ) 97 | textBox.configure( wrap='word' ) 98 | textBox.pack( expand=tk.YES ) 99 | textBox.insert( tk.END, text ) 100 | textBox.configure( state=tk.DISABLED ) # Don't allow editing 101 | 102 | okButton = Button( ab, text=_("Ok"), command=ab.destroy ) 103 | okButton.pack() 104 | 105 | ab.focus_set() # take over input focus, 106 | ab.grab_set() # disable other windows while I'm open, 107 | ab.wait_window() # and wait here until win destroyed 108 | # end of SpellCheckingBox.__init__ 109 | # end of class SpellCheckingBox 110 | 111 | 112 | def briefDemo() -> None: 113 | """ 114 | Main program to handle command line parameters and then run what they want. 115 | """ 116 | BibleOrgSysGlobals.introduceProgram( __name__, PROGRAM_NAME_VERSION, LAST_MODIFIED_DATE ) 117 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "Running demo…" ) 118 | 119 | tkRootWindow = tk.Tk() 120 | if BibleOrgSysGlobals.debugFlag: 121 | #dPrint( 'Quiet', DEBUGGING_THIS_MODULE, 'Windowing system is', repr( tkRootWindow.tk.call('tk', 'windowingsystem') ) ) 122 | for name in ('appname', 'inactive', 'scaling', 'useinputmethods', 'windowingsystem' ): # 'busy', 'caret', 'fontchooser', 123 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, 'Tkinter {} is {}'.format( name, repr( tkRootWindow.tk.call('tk', name) ) ) ) 124 | tkRootWindow.title( PROGRAM_NAME_VERSION ) 125 | ab = SpellCheckingBox( tkRootWindow, PROGRAM_NAME, PROGRAM_NAME_VERSION ) 126 | ab = SpellCheckingBox2( tkRootWindow, PROGRAM_NAME, PROGRAM_NAME_VERSION ) 127 | # Calls to the window manager class (wm in Tk) 128 | #tkRootWindow.minsize( application.minimumXSize, application.minimumYSize ) 129 | 130 | # Start the program running 131 | tkRootWindow.mainloop() 132 | # end of main 133 | 134 | 135 | def fullDemo() -> None: 136 | """ 137 | Full demo to check class is working 138 | """ 139 | briefDemo() 140 | # end of fullDemo 141 | 142 | if __name__ == '__main__': 143 | from multiprocessing import freeze_support 144 | freeze_support() # Multiprocessing support for frozen Windows executables 145 | 146 | 147 | # Configure basic set-up 148 | parser = BibleOrgSysGlobals.setup( SHORT_PROGRAM_NAME, PROGRAM_VERSION, LAST_MODIFIED_DATE ) 149 | BibleOrgSysGlobals.addStandardOptionsAndProcess( parser ) 150 | 151 | 152 | if BibleOrgSysGlobals.debugFlag: 153 | #from tkinter import TclVersion, TkVersion 154 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "TclVersion is", tk.TclVersion ) 155 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "TkVersion is", tk.TkVersion ) 156 | 157 | fullDemo() 158 | 159 | BibleOrgSysGlobals.closedown( PROGRAM_NAME, PROGRAM_VERSION ) 160 | # end of SpellChecking.py 161 | -------------------------------------------------------------------------------- /Biblelator/Helpers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Freely-Given-org/Biblelator/366ba255553dd18b8fb87f433f48ffafdd4108b9/Biblelator/Helpers/__init__.py -------------------------------------------------------------------------------- /Biblelator/Settings/Settings.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Settings.py 5 | # 6 | # Handle settings for Biblelator Bible display/editing 7 | # 8 | # Copyright (C) 2013-2020 Robert Hunt 9 | # Author: Robert Hunt 10 | # License: See gpl-3.0.txt 11 | # 12 | # This program is free software: you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation, either version 3 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License 23 | # along with this program. If not, see . 24 | 25 | """ 26 | Settings class 27 | __init__() 28 | __str__() 29 | __repr__() 30 | reset() 31 | load() 32 | save() 33 | 34 | ApplicationSettings class (Settings) 35 | __init__( homeFolderName, dataFolderName, settingsFolderName, settingsFilename ) 36 | 37 | 38 | BiblelatorProjectSettings class (Settings) 39 | __init__( projectFolderpath ) 40 | saveNameAndAbbreviation( projectName, projectAbbreviation ) 41 | saveNewBookSettings( detailsDict ) 42 | loadUSFMMetadataInto( theUSFMBible ) 43 | 44 | 45 | uWProjectSettings class (Settings) 46 | __init__( projectFolderpath ) 47 | saveNameAndAbbreviation( projectName, projectAbbreviation ) 48 | saveNewBookSettings( detailsDict ) 49 | loadUSFMMetadataInto( theUSFMBible ) 50 | """ 51 | from gettext import gettext as _ 52 | from typing import Dict, Any 53 | import os.path 54 | import logging 55 | import configparser 56 | from datetime import datetime 57 | 58 | # BibleOrgSys imports 59 | from BibleOrgSys import BibleOrgSysGlobals 60 | from BibleOrgSys.BibleOrgSysGlobals import fnPrint, vPrint, dPrint 61 | 62 | # Biblelator imports 63 | if __name__ == '__main__': 64 | import sys 65 | aboveAboveFolderpath = os.path.dirname( os.path.dirname( os.path.dirname( os.path.abspath( __file__ ) ) ) ) 66 | if aboveAboveFolderpath not in sys.path: 67 | sys.path.insert( 0, aboveAboveFolderpath ) 68 | from Biblelator.BiblelatorGlobals import APP_NAME 69 | from Biblelator.Settings.BiblelatorSettingsFunctions import SettingsVersion 70 | 71 | 72 | LAST_MODIFIED_DATE = '2020-05-08' # by RJH 73 | SHORT_PROGRAM_NAME = "BiblelatorSettings" 74 | PROGRAM_NAME = "Biblelator Settings" 75 | PROGRAM_VERSION = '0.46' 76 | PROGRAM_NAME_VERSION = f'{SHORT_PROGRAM_NAME} v{PROGRAM_VERSION}' 77 | 78 | DEBUGGING_THIS_MODULE = False 79 | 80 | 81 | 82 | class Settings: 83 | """ 84 | A class containing our basic common functions for loading and saving settings, etc. 85 | This class is designed to be a base class only. 86 | 87 | Biblelator settings are designed to be human readable (and therefore easily hackable). 88 | For this reason, the "Windows ini" type format was chosen 89 | over more complex and less readable formats like XML. 90 | 91 | Super class must set self.settingsFilepath 92 | """ 93 | def __init__( self ): 94 | """ 95 | """ 96 | self.objectNameString = 'Settings object' 97 | self.objectTypeString = 'Settings' 98 | self.data = None 99 | # end of Settings.__init__ 100 | 101 | 102 | def __str__( self ) -> str: 103 | result = self.objectNameString 104 | if self.data: 105 | for item in self.data.items(): 106 | result += str( item ) 107 | return result 108 | # end of Settings.__str__ 109 | 110 | def __repr__( self ): 111 | return repr( self.data.items() ) 112 | # end of Settings.__repr__ 113 | 114 | 115 | def reset( self ): 116 | """ 117 | Create a blank settings object. 118 | """ 119 | self.data = configparser.ConfigParser() 120 | self.data.optionxform = lambda option: option # Force true case matches for options (default is all lower case) 121 | # end of Settings.reset 122 | 123 | 124 | def loadINI( self ): 125 | """ 126 | Load the settings file (if we found it). 127 | """ 128 | fnPrint( DEBUGGING_THIS_MODULE, "Settings.loadINI() from {!r}".format( self.settingsFilepath ) ) 129 | 130 | self.reset() # Creates self.data 131 | assert self.data 132 | if self.settingsFilepath and os.path.isfile( self.settingsFilepath ) and os.access( self.settingsFilepath, os.R_OK ): 133 | self.data.read( self.settingsFilepath ) 134 | if BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 135 | for section in self.data: 136 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, f" Settings.loadINI: s.d main section = {section}" ) 137 | #end of Settings.loadINI 138 | 139 | 140 | def saveINI( self ) -> None: 141 | """ 142 | Save all of the program settings to disk. 143 | They must have already been saved into self.data. 144 | """ 145 | fnPrint( DEBUGGING_THIS_MODULE, "Settings.saveINI() in {!r}".format( self.settingsFilepath ) ) 146 | if DEBUGGING_THIS_MODULE or BibleOrgSysGlobals.debugFlag or BibleOrgSysGlobals.strictCheckingFlag: 147 | assert self.data 148 | assert self.settingsFilepath 149 | 150 | BibleOrgSysGlobals.backupAnyExistingFile( self.settingsFilepath, numBackups=8 ) 151 | with open( self.settingsFilepath, 'wt', encoding='utf-8' ) as settingsFile: # It may or may not have previously existed 152 | # Put a (comment) heading in the file first 153 | settingsFile.write( '# ' + _("{} {} settings file v{}").format( APP_NAME, PROGRAM_VERSION, SettingsVersion ) + '\n' ) 154 | settingsFile.write( '# ' + _("Originally saved {} as {}") \ 155 | .format( datetime.now().strftime('%Y-%m-%d %H:%M:%S'), self.settingsFilepath ) + '\n\n' ) 156 | 157 | self.data.write( settingsFile ) 158 | # end of Settings.saveINI 159 | 160 | 161 | def loadYAML( self, yamlFilepath=None ) -> None: 162 | """ 163 | Load the settings file (if we found it). 164 | 165 | Saves requiring a yaml library FWIW. 166 | 167 | Might still be fragile -- not fully debugged. 168 | """ 169 | from BibleOrgSys.Formats.uWNotesBible import loadYAML 170 | 171 | fnPrint( DEBUGGING_THIS_MODULE, f"Settings.loadYAML( {yamlFilepath} )" ) 172 | if yamlFilepath is None: yamlFilepath = self.settingsFilepath 173 | 174 | self.data = loadYAML( yamlFilepath ) 175 | # dPrint( 'Info', DEBUGGING_THIS_MODULE, "\nSettings", len(self.data), self.data.keys() ) 176 | if BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 177 | for j, (section,value) in enumerate( self.data.items(), start=1 ): 178 | vPrint( 'Normal', DEBUGGING_THIS_MODULE, f" Settings.loadYAML.load {j}: {section} = {value!r}" ) 179 | #end of Settings.loadYAML 180 | # end of class Settings 181 | 182 | 183 | 184 | class ApplicationSettings( Settings ): 185 | """ 186 | """ 187 | def __init__( self, homeFolderName, dataFolderName, settingsFolderName, settingsFilename ): 188 | """ 189 | This class is used before the main program starts. 190 | 191 | Try to find where the main settings file might be (if anywhere). 192 | """ 193 | fnPrint( DEBUGGING_THIS_MODULE, "ApplicationSettings.__init__( {!r}, {!r}, {!r}, {!r} )".format( homeFolderName, dataFolderName, settingsFolderName, settingsFilename ) ) 194 | self.dataFolderName, self.settingsFolderName, self.settingsFilename = dataFolderName, settingsFolderName, settingsFilename 195 | # NOTE: Settings.__init__ is NOT called -- not needed 196 | self.objectNameString = 'Application Settings object' 197 | self.objectTypeString = 'ApplicationSettings' 198 | self.data = None 199 | 200 | if not self.settingsFilename.lower().endswith( '.ini' ): 201 | self.settingsFilename = self.settingsFilename + '.ini' 202 | self.dataFolderpath = self.settingsFolder = self.settingsFilepath = None 203 | ourFolderpath1 = os.path.join( homeFolderName, dataFolderName ) 204 | if os.path.isdir( ourFolderpath1 ) and os.access( ourFolderpath1, os.W_OK ): 205 | self.dataFolderpath = ourFolderpath1 206 | dPrint( 'Info', DEBUGGING_THIS_MODULE, "ApplicationSettings.__init__: Found dataFolderpath = ", self.dataFolderpath ) 207 | ourFolderpath2 = os.path.join( self.dataFolderpath, settingsFolderName ) 208 | if os.path.isdir( ourFolderpath2 ) and os.access( ourFolderpath2, os.W_OK ): 209 | self.settingsFolder = ourFolderpath2 210 | dPrint( 'Info', DEBUGGING_THIS_MODULE, "ApplicationSettings.__init__: Found settingsFolder = ", self.settingsFolder ) 211 | ourFilepath = os.path.join( ourFolderpath2, self.settingsFilename ) 212 | if os.path.isfile( ourFilepath ) and os.access( ourFilepath, os.W_OK ): 213 | self.settingsFilepath = ourFilepath 214 | if BibleOrgSysGlobals.verbosityLevel > 2 or BibleOrgSysGlobals.debugFlag: 215 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "ApplicationSettings.__init__: Found settingsFilepath = ", self.settingsFilepath ) 216 | 217 | # Create new data and settings folders if necessary 218 | if not self.dataFolderpath: 219 | logging.info( "ApplicationSettings.__init__ " + _("No data folder found") ) 220 | if os.path.isdir( homeFolderName ) and os.access( homeFolderName, os.W_OK ): 221 | logging.info( "ApplicationSettings.__init__ " + _("Creating our data folder in {!r}").format( homeFolderName ) ) 222 | self.dataFolderpath = os.path.join( homeFolderName, dataFolderName ) 223 | os.mkdir( self.dataFolderpath ) 224 | if not self.settingsFolder: 225 | logging.info( "ApplicationSettings.__init__ " + _("No settings folder found") ) 226 | if os.path.isdir( self.dataFolderpath ) and os.access( self.dataFolderpath, os.W_OK ): 227 | logging.info( "ApplicationSettings.__init__ " + _("Creating our settings folder in {!r}").format( self.dataFolderpath ) ) 228 | self.settingsFolder = os.path.join( self.dataFolderpath, settingsFolderName ) 229 | os.mkdir( self.settingsFolder ) 230 | if not self.settingsFilepath: 231 | logging.info( "ApplicationSettings.__init__ " + _("No settings file found") ) 232 | self.settingsFilepath = os.path.join( self.settingsFolder, self.settingsFilename ) 233 | # end of ApplicationSettings.__init__ 234 | # end of class ApplicationSettings 235 | 236 | 237 | 238 | class BiblelatorProjectSettings( Settings ): 239 | """ 240 | Settings class for Biblelator USFM edit windows. 241 | """ 242 | def __init__( self, projectFolderpath ): 243 | """ 244 | Try to find where the settings file might be (if anywhere). 245 | """ 246 | fnPrint( DEBUGGING_THIS_MODULE, "BiblelatorProjectSettings.__init__( {!r} )".format( projectFolderpath ) ) 247 | self.projectFolderpath = projectFolderpath 248 | self.objectNameString = 'Biblelator Project Settings object' 249 | self.objectTypeString = 'BiblelatorProjectSettings' 250 | self.settingsFilename = 'ProjectSettings.ini' 251 | self.data = None 252 | 253 | self.settingsFilepath = os.path.join( projectFolderpath, self.settingsFilename ) 254 | if not os.path.isdir( self.projectFolderpath ): 255 | logging.critical( _("Project folder {} doesn't exist -- we'll try creating it!").format( self.projectFolderpath ) ) 256 | os.mkdir( self.projectFolderpath ) 257 | self.containingFolderpath, self.folderName = os.path.split( self.projectFolderpath ) 258 | # end of BiblelatorProjectSettings.__init__ 259 | 260 | 261 | def saveNameAndAbbreviation( self, projectName:str, projectAbbreviation:str ) -> None: 262 | """ 263 | Accept a project name and abbreviation. 264 | 265 | Used when starting a new project. 266 | """ 267 | fnPrint( DEBUGGING_THIS_MODULE, "BiblelatorProjectSettings.saveNameAndAbbreviation( {!r}, {!r} )".format( projectName, projectAbbreviation ) ) 268 | if DEBUGGING_THIS_MODULE or BibleOrgSysGlobals.debugFlag or BibleOrgSysGlobals.strictCheckingFlag: 269 | assert self.data is None 270 | 271 | self.reset() # Create new settings in self.data 272 | self.data['Project'] = {} 273 | main = self.data['Project'] 274 | main['Name'] = projectName 275 | main['Abbreviation'] = projectAbbreviation 276 | self.saveINI() # Write the basic data 277 | # end of BiblelatorProjectSettings.saveNameAndAbbreviation 278 | 279 | 280 | def saveNewBookSettings( self, detailsDict:Dict[str,Any] ) -> None: 281 | """ 282 | """ 283 | fnPrint( DEBUGGING_THIS_MODULE, "BiblelatorProjectSettings.saveNewBookSettings( {} )".format( detailsDict ) ) 284 | if DEBUGGING_THIS_MODULE or BibleOrgSysGlobals.debugFlag or BibleOrgSysGlobals.strictCheckingFlag: 285 | assert self.data is not None 286 | 287 | self.data['NewBooks'] = {} 288 | newBooks = self.data['NewBooks'] 289 | for someKey,someValue in detailsDict.items(): 290 | newBooks[someKey] = someValue 291 | self.saveINI() # Write the added data 292 | # end of BiblelatorProjectSettings.saveNewBookSettings 293 | 294 | 295 | def loadUSFMMetadataInto( self, theUSFMBible ) -> None: 296 | """ 297 | Using metadata from the project settings file, 298 | load the information into the given USFMBible object. 299 | """ 300 | fnPrint( DEBUGGING_THIS_MODULE, "BiblelatorProjectSettings.loadUSFMMetadataInto( {} )".format( theUSFMBible ) ) 301 | 302 | self.loadINI() # Load the project settings into self.data 303 | 304 | main = self.data['Project'] 305 | try: theUSFMBible.name = main['Name'] 306 | except KeyError: logging.critical( "Missing {} field in {!r} project settings".format( "'Name'", self.folderName ) ) 307 | try: theUSFMBible.abbreviation = main['Abbreviation'] 308 | except KeyError: logging.critical( "Missing {} field in {!r} project settings".format( "'Abbreviation'", self.folderName ) ) 309 | # end of BiblelatorProjectSettings.loadUSFMMetadataInto 310 | # end of class BiblelatorProjectSettings 311 | 312 | 313 | 314 | class uWProjectSettings( Settings ): 315 | """ 316 | Settings class for uW USFM edit windows. 317 | """ 318 | def __init__( self, projectFolderpath ): 319 | """ 320 | Try to find where the settings file might be (if anywhere). 321 | """ 322 | fnPrint( DEBUGGING_THIS_MODULE, "uWProjectSettings.__init__( {!r} )".format( projectFolderpath ) ) 323 | self.projectFolderpath = projectFolderpath 324 | self.objectNameString = 'uW Project Settings object' 325 | self.objectTypeString = 'uWProjectSettings' 326 | self.settingsFilename = 'manifest.yaml' 327 | self.data = None 328 | 329 | self.settingsFilepath = os.path.join( projectFolderpath, self.settingsFilename ) 330 | if not os.path.isdir( self.projectFolderpath ): 331 | logging.critical( _("Project folder {} doesn't exist -- we'll try creating it!").format( self.projectFolderpath ) ) 332 | # os.mkdir( self.projectFolderpath ) 333 | # self.containingFolderpath, self.folderName = os.path.split( self.projectFolderpath ) 334 | # end of uWProjectSettings.__init__ 335 | 336 | 337 | # def saveNameAndAbbreviation( self, projectName, projectAbbreviation ): 338 | # """ 339 | # """ 340 | # if BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 341 | # vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "uWProjectSettings.saveNameAndAbbreviation( {!r}, {!r} )".format( projectName, projectAbbreviation ) ) 342 | # assert self.data is None 343 | 344 | # self.reset() # Create new settings in self.data 345 | # self.data['Project'] = {} 346 | # main = self.data['Project'] 347 | # main['Name'] = projectName 348 | # main['Abbreviation'] = projectAbbreviation 349 | # self.saveINI() # Write the basic data 350 | # # end of uWProjectSettings.saveNameAndAbbreviation 351 | 352 | 353 | # def saveNewBookSettings( self, detailsDict ): 354 | # """ 355 | # """ 356 | # if BibleOrgSysGlobals.debugFlag and DEBUGGING_THIS_MODULE: 357 | # vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "uWProjectSettings.saveNewBookSettings( {} )".format( detailsDict ) ) 358 | # assert self.data is not None 359 | 360 | # self.data['NewBooks'] = {} 361 | # newBooks = self.data['NewBooks'] 362 | # for someKey,someValue in detailsDict.items(): 363 | # newBooks[someKey] = someValue 364 | # self.saveYAML() # Write the added data 365 | # # end of uWProjectSettings.saveNewBookSettings 366 | 367 | 368 | def loadUWMetadataInto( self, theUSFMBible ): 369 | """ 370 | Using metadata from the manifest.yaml project settings file, 371 | load the information into the given USFMBible object. 372 | """ 373 | fnPrint( DEBUGGING_THIS_MODULE, f"uWProjectSettings.loadUWMetadataInto( {theUSFMBible} )" ) 374 | 375 | self.loadYAML() # Load the project settings into self.data 376 | # dPrint( 'Info', DEBUGGING_THIS_MODULE, "Got", self.data.keys() ) 377 | 378 | if self.data: 379 | # main = self.data['dublin_core'] 380 | # try: theUSFMBible.name = main['title'] 381 | # except KeyError: logging.critical( "Missing {} field in {!r} project settings".format( "'title'", self.folderName ) ) 382 | # try: theUSFMBible.abbreviation = main['identifier'].upper() 383 | # except KeyError: logging.critical( "Missing {} field in {!r} project settings".format( "'identifier'", self.folderName ) ) 384 | if theUSFMBible.suppliedMetadata is None: theUSFMBible.suppliedMetadata = {} 385 | if 'uW' not in theUSFMBible.suppliedMetadata: theUSFMBible.suppliedMetadata['uW'] = {} 386 | assert 'Manifest' not in theUSFMBible.suppliedMetadata['uW'] 387 | theUSFMBible.suppliedMetadata['uW']['Manifest'] = self.data 388 | theUSFMBible.applySuppliedMetadata( 'uW' ) # Copy some files to theUSFMBible.settingsDict 389 | # end of uWProjectSettings.loadUWMetadataInto 390 | # end of class uWProjectSettings 391 | 392 | 393 | 394 | def briefDemo() -> None: 395 | """ 396 | Main program to handle command line parameters and then run what they want. 397 | """ 398 | BibleOrgSysGlobals.introduceProgram( __name__, PROGRAM_NAME_VERSION, LAST_MODIFIED_DATE ) 399 | 400 | s = Settings() 401 | print( "New s", s ) 402 | 403 | s.settingsFilepath = '/mnt/SSDs/Bibles/English translations/unfoldingWordVersions/en_ust/manifest.yaml' 404 | s.loadYAML() 405 | print( "Filled s", s ) 406 | # end of Settings.briefDemo 407 | 408 | def fullDemo() -> None: 409 | """ 410 | Full demo to check class is working 411 | """ 412 | BibleOrgSysGlobals.introduceProgram( __name__, PROGRAM_NAME_VERSION, LAST_MODIFIED_DATE ) 413 | 414 | s = Settings() 415 | print( "New s", s ) 416 | 417 | for filepath in ( '/mnt/SSDs/Bibles/English translations/unfoldingWordVersions/en_ust/manifest.yaml', 418 | '/mnt/SSDs/Bibles/unfoldingWordHelps/en_ta/intro/toc.yaml', 419 | ): 420 | s.settingsFilepath = filepath 421 | s.loadYAML() 422 | print( "Filled s", s, len(s.data), s.data ) 423 | # end of Settings.fullDemo 424 | 425 | if __name__ == '__main__': 426 | from multiprocessing import freeze_support 427 | freeze_support() # Multiprocessing support for frozen Windows executables 428 | 429 | # Configure basic set-up 430 | parser = BibleOrgSysGlobals.setup( SHORT_PROGRAM_NAME, PROGRAM_VERSION, LAST_MODIFIED_DATE ) 431 | BibleOrgSysGlobals.addStandardOptionsAndProcess( parser ) 432 | 433 | fullDemo() 434 | 435 | BibleOrgSysGlobals.closedown( PROGRAM_NAME, PROGRAM_VERSION ) 436 | # end of Settings.py 437 | -------------------------------------------------------------------------------- /Biblelator/Settings/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Freely-Given-org/Biblelator/366ba255553dd18b8fb87f433f48ffafdd4108b9/Biblelator/Settings/__init__.py -------------------------------------------------------------------------------- /Biblelator/Windows/ESFMEditWindow.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # ESFMEditWindow.py 5 | # 6 | # The actual edit windows for Biblelator text editing and USFM/ESFM Bible editing 7 | # 8 | # Copyright (C) 2013-2018 Robert Hunt 9 | # Author: Robert Hunt 10 | # License: See gpl-3.0.txt 11 | # 12 | # This program is free software: you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation, either version 3 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License 23 | # along with this program. If not, see . 24 | 25 | """ 26 | xxx to allow editing of USFM Bibles using Python3 and Tkinter. 27 | """ 28 | 29 | from gettext import gettext as _ 30 | #import sys #, os.path, logging #, re 31 | #from collections import OrderedDict 32 | #import multiprocessing 33 | 34 | import tkinter as tk 35 | #from tkinter.simpledialog import askstring, askinteger 36 | #from tkinter.filedialog import asksaveasfilename 37 | #from tkinter.colorchooser import askcolor 38 | #from tkinter.ttk import Style, Frame 39 | 40 | # Biblelator imports 41 | if __name__ == '__main__': 42 | import sys 43 | aboveAboveFolderpath = os.path.dirname( os.path.dirname( os.path.dirname( os.path.abspath( __file__ ) ) ) ) 44 | if aboveAboveFolderpath not in sys.path: 45 | sys.path.insert( 0, aboveAboveFolderpath ) 46 | #from BiblelatorGlobals import APP_NAME, DATA_SUBFOLDER_NAME, tkSTART, DEFAULT, EDIT_MODE_NORMAL, EDIT_MODE_USFM, BIBLE_GROUP_CODES 47 | #from BiblelatorDialogs import YesNoDialog, OkCancelDialog, GetBibleBookRangeDialog 48 | #from BiblelatorHelpers import createEmptyUSFMBookText, calculateTotalVersesForBook, mapReferenceVerseKey, mapParallelVerseKey 49 | #from TextBoxes import CustomText 50 | #from BibleResourceWindows import BibleBox, BibleResourceWindow 51 | #from BibleReferenceCollection import BibleReferenceCollectionWindow 52 | from Biblelator.Windows.USFMEditWindow import USFMEditWindow 53 | 54 | # BibleOrgSys imports 55 | from BibleOrgSys import BibleOrgSysGlobals 56 | from BibleOrgSys.BibleOrgSysGlobals import fnPrint, vPrint, dPrint 57 | 58 | #from BibleOrgSys.Reference.VerseReferences import SimpleVerseKey 59 | #from BibleOrgSys.BibleWriter import setDefaultControlFolderpath 60 | 61 | 62 | LAST_MODIFIED_DATE = '2018-03-15' # by RJH 63 | SHORT_PROGRAM_NAME = "ESFMEditWindow" 64 | PROGRAM_NAME = "Biblelator ESFM Edit Window" 65 | PROGRAM_VERSION = '0.46' 66 | PROGRAM_NAME_VERSION = f'{PROGRAM_NAME} v{PROGRAM_VERSION}' 67 | 68 | DEBUGGING_THIS_MODULE = False 69 | 70 | 71 | class ESFMEditWindow( USFMEditWindow ): 72 | pass 73 | # end of ESFMEditWindow class 74 | 75 | 76 | 77 | def briefDemo() -> None: 78 | """ 79 | Demo program to handle command line parameters and then run what they want. 80 | """ 81 | BibleOrgSysGlobals.introduceProgram( __name__, PROGRAM_NAME_VERSION, LAST_MODIFIED_DATE ) 82 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "Running demo…" ) 83 | 84 | tkRootWindow = tk.Tk() 85 | tkRootWindow.title( PROGRAM_NAME_VERSION ) 86 | tkRootWindow.textBox = tk.Text( tkRootWindow ) 87 | 88 | eEW = ESFMEditWindow( tkRootWindow, None ) 89 | 90 | # Start the program running 91 | tkRootWindow.mainloop() 92 | # end of ESFMEditWindow.demo 93 | 94 | 95 | def fullDemo() -> None: 96 | """ 97 | Full demo to check class is working 98 | """ 99 | briefDemo() 100 | # end of fullDemo 101 | 102 | if __name__ == '__main__': 103 | from multiprocessing import freeze_support 104 | freeze_support() # Multiprocessing support for frozen Windows executables 105 | 106 | # Configure basic set-up 107 | parser = BibleOrgSysGlobals.setup( SHORT_PROGRAM_NAME, PROGRAM_VERSION, LAST_MODIFIED_DATE ) 108 | BibleOrgSysGlobals.addStandardOptionsAndProcess( parser ) 109 | 110 | fullDemo() 111 | 112 | BibleOrgSysGlobals.closedown( PROGRAM_NAME, PROGRAM_VERSION ) 113 | # end of ESFMEditWindow.py 114 | -------------------------------------------------------------------------------- /Biblelator/Windows/LexiconResourceWindows.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # LexiconResourceWindows.py 5 | # 6 | # Bible and lexicon resource windows for Biblelator Bible display/editing 7 | # 8 | # Copyright (C) 2013-2022 Robert Hunt 9 | # Author: Robert Hunt 10 | # License: See gpl-3.0.txt 11 | # 12 | # This program is free software: you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation, either version 3 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License 23 | # along with this program. If not, see . 24 | 25 | """ 26 | Windows and frames to allow display and manipulation of 27 | Bible and lexicon resource windows. 28 | """ 29 | from gettext import gettext as _ 30 | import os.path 31 | import logging 32 | 33 | import tkinter as tk 34 | from tkinter.ttk import Style, Frame, Button 35 | 36 | # BibleOrgSys imports 37 | from BibleOrgSys import BibleOrgSysGlobals 38 | from BibleOrgSys.BibleOrgSysGlobals import fnPrint, vPrint, dPrint 39 | from BibleOrgSys.OriginalLanguages.BibleLexicon import BibleLexicon 40 | 41 | # Biblelator imports 42 | if __name__ == '__main__': 43 | import sys 44 | aboveAboveFolderpath = os.path.dirname( os.path.dirname( os.path.dirname( os.path.abspath( __file__ ) ) ) ) 45 | if aboveAboveFolderpath not in sys.path: 46 | sys.path.insert( 0, aboveAboveFolderpath ) 47 | from Biblelator import BiblelatorGlobals 48 | from Biblelator.Windows.TextBoxes import HTMLTextBox, ChildBoxAddon 49 | from Biblelator.Windows.ChildWindows import ChildWindow 50 | 51 | 52 | 53 | LAST_MODIFIED_DATE = '2022-07-12' # by RJH 54 | SHORT_PROGRAM_NAME = "LexiconResourceWindows" 55 | PROGRAM_NAME = "Biblelator Lexicon Resource Windows" 56 | PROGRAM_VERSION = '0.46' 57 | PROGRAM_NAME_VERSION = f'{PROGRAM_NAME} v{PROGRAM_VERSION}' 58 | 59 | DEBUGGING_THIS_MODULE = False 60 | 61 | 62 | 63 | class BibleLexiconResourceWindow( ChildWindow, ChildBoxAddon ): 64 | """ 65 | """ 66 | def __init__( self, parentWindow ) -> None: 67 | """ 68 | """ 69 | fnPrint( DEBUGGING_THIS_MODULE, f"BibleLexiconResourceWindow.__init__( {parentWindow} )" ) 70 | self.lexiconWord = None 71 | 72 | ChildWindow.__init__( self, parentWindow, 'LexiconResource' ) 73 | ChildBoxAddon.__init__( self, self ) 74 | self.moduleID = 'BibleLexicon' 75 | self.windowType = 'BibleLexiconResourceWindow' 76 | 77 | # Make our own textBox 78 | self.textBox.destroy() 79 | self.textBox = HTMLTextBox( self, yscrollcommand=self.vScrollbar.set, wrap='word' ) 80 | self.textBox.pack( expand=tk.YES, fill=tk.BOTH ) 81 | self.vScrollbar.configure( command=self.textBox.yview ) # link the scrollbar to the text box 82 | #self.createStandardWindowKeyboardBindings( reset=True ) 83 | 84 | self._createMenuBar() 85 | #self.createBibleLexiconResourceWindowWidgets() 86 | #for USFMKey, styleDict in self.myMaster.stylesheet.getTKStyles().items(): 87 | # self.textBox.tag_configure( USFMKey, **styleDict ) # Create the style 88 | 89 | 90 | try: self.BibleLexicon = BibleLexicon() 91 | # os.path.join( self.lexiconPath, 'HebrewLexicon/' ), # Hebrew 92 | # os.path.join( self.lexiconPath, 'strongs-dictionary-xml/' ) ) # Greek 93 | except FileNotFoundError: 94 | logging.critical( "BibleLexiconResourceWindow.__init__ " + _("Unable to find Bible lexicon path") ) 95 | self.BibleLexicon = None 96 | # end of BibleLexiconResourceWindow.__init__ 97 | 98 | 99 | def refreshTitle( self ) -> None: 100 | self.title( "[{}] {}".format( repr(self.lexiconWord), _("Bible Lexicon") ) ) 101 | # end if BibleLexiconResourceWindow.refreshTitle 102 | 103 | 104 | def _createMenuBar( self ) -> None: 105 | """ 106 | """ 107 | fnPrint( DEBUGGING_THIS_MODULE, "BibleLexiconResourceWindow._createMenuBar()" ) 108 | 109 | self.menubar = tk.Menu( self ) 110 | #self['menu'] = self.menubar 111 | self.configure( menu=self.menubar ) # alternative 112 | 113 | fileMenu = tk.Menu( self.menubar, tearoff=False ) 114 | self.menubar.add_cascade( menu=fileMenu, label=_('File'), underline=0 ) 115 | #fileMenu.add_command( label=_('New…'), underline=0, command=self.notWrittenYet ) 116 | #fileMenu.add_command( label=_('Open…'), underline=0, command=self.notWrittenYet ) 117 | #fileMenu.add_separator() 118 | #subfileMenuImport = tk.Menu( fileMenu ) 119 | #subfileMenuImport.add_command( label=_('USX'), underline=0, command=self.notWrittenYet ) 120 | #fileMenu.add_cascade( label=_('Import'), underline=0, menu=subfileMenuImport ) 121 | #subfileMenuExport = tk.Menu( fileMenu ) 122 | #subfileMenuExport.add_command( label=_('USX'), underline=0, command=self.notWrittenYet ) 123 | #subfileMenuExport.add_command( label=_('HTML'), underline=0, command=self.notWrittenYet ) 124 | #fileMenu.add_cascade( label=_('Export'), underline=0, menu=subfileMenuExport ) 125 | #fileMenu.add_separator() 126 | fileMenu.add_command( label=_('Info…'), underline=0, command=self.doShowInfo, accelerator=BiblelatorGlobals.theApp.keyBindingDict[_('Info')][0] ) 127 | fileMenu.add_separator() 128 | fileMenu.add_command( label=_('Close'), underline=0, command=self.doClose, accelerator=BiblelatorGlobals.theApp.keyBindingDict[_('Close')][0] ) # close this window 129 | 130 | editMenu = tk.Menu( self.menubar, tearoff=False ) 131 | self.menubar.add_cascade( menu=editMenu, label=_('Edit'), underline=0 ) 132 | editMenu.add_command( label=_('Copy'), underline=0, command=self.doCopy, accelerator=BiblelatorGlobals.theApp.keyBindingDict[_('Copy')][0] ) 133 | editMenu.add_separator() 134 | editMenu.add_command( label=_('Select all'), underline=0, command=self.doSelectAll, accelerator=BiblelatorGlobals.theApp.keyBindingDict[_('SelectAll')][0] ) 135 | 136 | searchMenu = tk.Menu( self.menubar ) 137 | self.menubar.add_cascade( menu=searchMenu, label=_('Search'), underline=0 ) 138 | searchMenu.add_command( label=_('Goto line…'), underline=0, command=self.doGotoWindowLine, accelerator=BiblelatorGlobals.theApp.keyBindingDict[_('Line')][0] ) 139 | searchMenu.add_separator() 140 | searchMenu.add_command( label=_('Find…'), underline=0, command=self.doBoxFind, accelerator=BiblelatorGlobals.theApp.keyBindingDict[_('Find')][0] ) 141 | searchMenu.add_command( label=_('Find again'), underline=5, command=self.doBoxRefind, accelerator=BiblelatorGlobals.theApp.keyBindingDict[_('Refind')][0] ) 142 | 143 | gotoMenu = tk.Menu( self.menubar ) 144 | self.menubar.add_cascade( menu=gotoMenu, label=_('Goto'), underline=0 ) 145 | gotoMenu.add_command( label=_('Previous entry'), underline=0, command=self.doGotoPreviousEntry ) 146 | gotoMenu.add_command( label=_('Next entry'), underline=0, command=self.doGotoNextEntry ) 147 | 148 | toolsMenu = tk.Menu( self.menubar, tearoff=False ) 149 | self.menubar.add_cascade( menu=toolsMenu, label=_('Tools'), underline=0 ) 150 | toolsMenu.add_command( label=_('Options…'), underline=0, command=self.notWrittenYet ) 151 | 152 | windowMenu = tk.Menu( self.menubar, tearoff=False ) 153 | self.menubar.add_cascade( menu=windowMenu, label=_('Window'), underline=0 ) 154 | windowMenu.add_command( label=_('Bring in'), underline=0, command=self.notWrittenYet ) 155 | windowMenu.add_separator() 156 | windowMenu.add_command( label=_('Show main window'), underline=0, command=self.doShowMainWindow, accelerator=BiblelatorGlobals.theApp.keyBindingDict[_('ShowMain')][0] ) 157 | 158 | helpMenu = tk.Menu( self.menubar, name='help', tearoff=False ) 159 | self.menubar.add_cascade( menu=helpMenu, underline=0, label=_('Help') ) 160 | helpMenu.add_command( label=_('Help…'), underline=0, command=self._doHelp, accelerator=BiblelatorGlobals.theApp.keyBindingDict[_('Help')][0] ) 161 | helpMenu.add_separator() 162 | helpMenu.add_command( label=_('About…'), underline=0, command=self._doAbout, accelerator=BiblelatorGlobals.theApp.keyBindingDict[_('About')][0] ) 163 | # end of BibleLexiconResourceWindow._createMenuBar 164 | 165 | 166 | def createToolBar( self ) -> None: 167 | """ 168 | Create a tool bar containing some helpful buttons at the top of the main window. 169 | """ 170 | fnPrint( DEBUGGING_THIS_MODULE, "createToolBar()" ) 171 | 172 | xPad, yPad = (6, 8) if BiblelatorGlobals.theApp.touchMode else (4, 4) 173 | 174 | Style().configure( 'LexToolBar.TFrame', background='wheat1' ) 175 | toolbar = Frame( self, cursor='hand2', relief=tk.RAISED, style='LexToolBar.TFrame' ) 176 | 177 | Style().configure( 'LexPrevious.TButton', background='lightgreen' ) 178 | Style().configure( 'LexNext.TButton', background='pink' ) 179 | 180 | Button( toolbar, text=_("Previous"), style='LexPrevious.TButton', command=self.doGotoPreviousEntry ) \ 181 | .pack( side=tk.LEFT, padx=xPad, pady=yPad ) 182 | Button( toolbar, text=_("Next"), style='LexNext.TButton', command=self.doGotoNextEntry ) \ 183 | .pack( side=tk.LEFT, padx=xPad, pady=yPad ) 184 | #Button( toolbar, text='Bring All', command=self.doBringAll ).pack( side=tk.LEFT, padx=2, pady=2 ) 185 | 186 | toolbar.pack( side=tk.TOP, fill=tk.X ) 187 | # end of BibleLexiconResourceWindow.createToolBar 188 | 189 | 190 | def doGotoPreviousEntry( self ) -> None: 191 | """ 192 | """ 193 | if BibleOrgSysGlobals.debugFlag: 194 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "doGotoPreviousEntry() from {}".format( repr(self.lexiconWord) ) ) 195 | #self.setDebugText( "doGotoPreviousEntry…" ) 196 | 197 | if self.lexiconWord is None: 198 | self.updateLexiconWord( 'G5624' ) 199 | elif (self.lexiconWord.startswith('H') or self.lexiconWord.startswith('G')) \ 200 | and self.lexiconWord[1:].isdigit() and int(self.lexiconWord[1:])>1: 201 | number = int( self.lexiconWord[1:] ) 202 | self.updateLexiconWord( self.lexiconWord[0] + str( number-1 ) ) 203 | else: logging.error( "can't doGotoPreviousEntry from {}".format( repr(self.lexiconWord) ) ) 204 | # end of BibleResourceWindow.doGotoPreviousEntry 205 | 206 | 207 | def doGotoNextEntry( self ) -> None: 208 | """ 209 | """ 210 | if BibleOrgSysGlobals.debugFlag: 211 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "doGotoNextEntry() from {}".format( repr(self.lexiconWord) ) ) 212 | #self.setDebugText( "doGotoNextEntry…" ) 213 | 214 | if self.lexiconWord is None: 215 | self.updateLexiconWord( 'H1' ) 216 | elif (self.lexiconWord.startswith('H') or self.lexiconWord.startswith('G')) \ 217 | and self.lexiconWord[1:].isdigit(): 218 | number = int( self.lexiconWord[1:] ) 219 | self.updateLexiconWord( self.lexiconWord[0] + str( number+1 ) ) 220 | else: logging.error( "can't doGotoNextEntry from {}".format( repr(self.lexiconWord) ) ) 221 | # end of BibleResourceWindow.doGotoNextEntry 222 | 223 | 224 | def updateLexiconWord( self, newLexiconWord:str ) -> None: 225 | """ 226 | Leaves text box in disabled state. (Not user editable.) 227 | """ 228 | fnPrint( DEBUGGING_THIS_MODULE, f"updateLexiconWord( {newLexiconWord} )" ) 229 | 230 | self.lexiconWord = newLexiconWord 231 | self.clearText() # Leaves the text box enabled 232 | if self.BibleLexicon is None: 233 | self.textBox.insert( tk.END, "

No lexicon loaded so can't display entry for {}.

".format( repr(newLexiconWord) ) ) 234 | else: 235 | self.textBox.insert( tk.END, "

Entry for '{}'

".format( newLexiconWord ) ) 236 | txt = self.BibleLexicon.getEntryHTML( self.lexiconWord ) 237 | if txt: self.textBox.insert( tk.END, f'

{txt}

' ) 238 | self.textBox.configure( state=tk.DISABLED ) # Don't allow editing 239 | self.refreshTitle() 240 | # end of BibleLexiconResourceWindow.updateLexiconWord 241 | 242 | 243 | def _doHelp( self, event=None ) -> None: 244 | """ 245 | Display a help box. 246 | """ 247 | fnPrint( DEBUGGING_THIS_MODULE, "BibleLexiconResourceWindow._doHelp( {} )".format( event ) ) 248 | from Biblelator.Dialogs.Help import HelpBox 249 | 250 | helpInfo = PROGRAM_NAME_VERSION 251 | helpInfo += '\n' + _("Help for {}").format( self.windowType ) 252 | helpInfo += '\n ' + _("Keyboard shortcuts:") 253 | for name,shortcut in self.myKeyboardBindingsList: 254 | helpInfo += "\n {}\t{}".format( name, shortcut ) 255 | hb = HelpBox( self, self.genericWindowType, helpInfo ) 256 | return BiblelatorGlobals.tkBREAK # so we don't do the main window help also 257 | # end of BibleLexiconResourceWindow._doHelp 258 | 259 | 260 | def _doAbout( self, event=None ) -> None: 261 | """ 262 | Display an about box. 263 | """ 264 | fnPrint( DEBUGGING_THIS_MODULE, "BibleLexiconResourceWindow._doAbout( {} )".format( event ) ) 265 | from Biblelator.Dialogs.About import AboutBox 266 | 267 | aboutInfo = PROGRAM_NAME_VERSION 268 | aboutInfo += "\nInformation about {}".format( self.windowType ) 269 | ab = AboutBox( self, self.genericWindowType, aboutInfo ) 270 | return BiblelatorGlobals.tkBREAK # so we don't do the main window about also 271 | # end of BibleLexiconResourceWindow._doAbout 272 | # end of BibleLexiconResourceWindow class 273 | 274 | 275 | 276 | def briefDemo() -> None: 277 | """ 278 | Demo program to handle command line parameters and then run what they want. 279 | """ 280 | BibleOrgSysGlobals.introduceProgram( __name__, PROGRAM_NAME_VERSION, LAST_MODIFIED_DATE ) 281 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "Running demo…" ) 282 | 283 | tkRootWindow = tk.Tk() 284 | tkRootWindow.title( PROGRAM_NAME_VERSION ) 285 | #settings = ApplicationSettings( 'BiblelatorData/', 'BiblelatorSettings/', PROGRAM_NAME ) 286 | #settings.load() 287 | 288 | #application = Application( parent=tkRootWindow, settings=settings ) 289 | # Calls to the window manager class (wm in Tk) 290 | #application.master.title( PROGRAM_NAME_VERSION ) 291 | #application.master.minsize( application.minimumXSize, application.minimumYSize ) 292 | 293 | # Program a shutdown 294 | tkRootWindow.after( 2_000, tkRootWindow.destroy ) # Destroy the widget after 2 seconds 295 | 296 | # Start the program running 297 | # tkRootWindow.mainloop() 298 | # end of LexiconResourceWindows.briefDemo 299 | 300 | def fullDemo() -> None: 301 | """ 302 | Full demo to check class is working 303 | """ 304 | BibleOrgSysGlobals.introduceProgram( __name__, PROGRAM_NAME_VERSION, LAST_MODIFIED_DATE ) 305 | vPrint( 'Quiet', DEBUGGING_THIS_MODULE, "Running demo…" ) 306 | 307 | tkRootWindow = tk.Tk() 308 | tkRootWindow.title( PROGRAM_NAME_VERSION ) 309 | #settings = ApplicationSettings( 'BiblelatorData/', 'BiblelatorSettings/', PROGRAM_NAME ) 310 | #settings.load() 311 | 312 | #application = Application( parent=tkRootWindow, settings=settings ) 313 | # Calls to the window manager class (wm in Tk) 314 | #application.master.title( PROGRAM_NAME_VERSION ) 315 | #application.master.minsize( application.minimumXSize, application.minimumYSize ) 316 | 317 | # Program a shutdown 318 | tkRootWindow.after( 30_000, tkRootWindow.destroy ) # Destroy the widget after 30 seconds 319 | 320 | # Start the program running 321 | tkRootWindow.mainloop() 322 | # end of fullDemo 323 | 324 | if __name__ == '__main__': 325 | from multiprocessing import freeze_support 326 | freeze_support() # Multiprocessing support for frozen Windows executables 327 | 328 | # Configure basic set-up 329 | parser = BibleOrgSysGlobals.setup( SHORT_PROGRAM_NAME, PROGRAM_VERSION, LAST_MODIFIED_DATE ) 330 | BibleOrgSysGlobals.addStandardOptionsAndProcess( parser ) 331 | 332 | fullDemo() 333 | 334 | BibleOrgSysGlobals.closedown( PROGRAM_NAME, PROGRAM_VERSION ) 335 | # end of LexiconResourceWindows.py 336 | -------------------------------------------------------------------------------- /Biblelator/Windows/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Freely-Given-org/Biblelator/366ba255553dd18b8fb87f433f48ffafdd4108b9/Biblelator/Windows/__init__.py -------------------------------------------------------------------------------- /Biblelator/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Freely-Given-org/Biblelator/366ba255553dd18b8fb87f433f48ffafdd4108b9/Biblelator/__init__.py -------------------------------------------------------------------------------- /Documentation/Authors.md: -------------------------------------------------------------------------------- 1 | Authors.md for Biblelator 2 | ========================= 3 | 4 | Last updated: 2018-02-16 by RJH 5 | 6 | 7 | Principal Author 8 | ================ 9 | 10 | Robert Hunt (Freely-Given.Org) 11 | 12 | 13 | Other Contributors 14 | ================== 15 | 16 | Where all you all? 17 | 18 | -------------------------------------------------------------------------------- /Documentation/DevelopmentPrinciples.md: -------------------------------------------------------------------------------- 1 | Biblelator Development Principles 2 | ================================= 3 | 4 | Last updated: 2018-02-16 RJH 5 | 6 | 7 | The following are some of the reasons behind some of the major development decisions 8 | concerning the development of Biblelator. 9 | 10 | 11 | 1. Python as the language 12 | 13 | Python is not as fast and efficient as C or C++, but it is nevertheless an elegant, well-designed 14 | computer language that runs quite satisfactorily on most modern computer hardware. 15 | 16 | Another reason for choosing Python is that the source code to the software is usually provided 17 | and that it can be easier to read by novices/non-programmers than some other computer languages. 18 | This is important to us, because Biblelator is designed to be hackable, i.e., a creator or 19 | translator of the Bible might have a chance of making a small change to the program in order 20 | to handle a specific need that he/she might have (or if not, to hire someone else to make the 21 | change). 22 | 23 | According to Wikipedia: "Python is a widely used high-level, general-purpose, interpreted, 24 | dynamic programming language. Its design philosophy emphasizes code readability, and its syntax 25 | allows programmers to express concepts in fewer lines of code than would be possible in languages 26 | such as C++ or Java. The language provides constructs intended to enable clear programs on both 27 | a small and large scale." These are exactly some of the reasons that Python was chosen. 28 | (From https://en.wikipedia.org/wiki/Python_(programming_language) ) 29 | 30 | 31 | 2. Python3 versus Python2 32 | 33 | Python3 was already in development when the Bible Organisational System (BibleOrgSys -- 34 | started 2010) that Biblelator (started 2014) depends on was being prototyped. It was already 35 | obvious then that Python2 would eventually stop being developed, and so there didn't seem to 36 | be any point in creating a new piece of software based on a language version already 37 | destined to be obsoleted (even though many libraries hadn't yet been updated at the time). 38 | 39 | Also Python3 was Unicode compatible from the beginning and this is important for a Bible 40 | editor that's expected to be used to handle many non-Roman based character sets. 41 | 42 | 43 | 3. Tkinter as the widget set 44 | 45 | Tkinter is not the most beautiful or advanced widget set, but it is an intrinsic part 46 | of regular Python distributions. So it was chosen for its universality rather than 47 | trying to choose one of quite a number of competing toolkits (e.g., QT, wxWidgets, etc.) 48 | which require extra installation complexities and which may not work well (or at all) 49 | on some platforms. Time will tell whether or not this was a wise decision -- unfortunately 50 | some cross-platform behaviours have been found to be inconsistent. 51 | 52 | 53 | 4. Internationalisation 54 | 55 | Like the Bible Organisational System (BibleOrgSys) that Biblelator is based on top of, this 56 | Bible editor is designed to (eventually) be flexible enough to handle different versification 57 | systems, different combinations and orders for Bible books, etc. 58 | 59 | Some preparation work has already been done in the program to allow translations of menus, 60 | etc., to match your Operating System locale/language, but no translations have been 61 | started yet. 62 | 63 | Although all string handling in the BibleOrgSys and Biblelator is Unicode, no attempts 64 | have been made yet to test or handle complex fonts or right-to-left languages. 65 | 66 | 67 | 5. More control of child window placement 68 | 69 | Biblelator tries to allow the user to place the main window and child windows anywhere on 70 | a multi-screen system, but with tools to easily find child windows if they get covered. 71 | 72 | Possibly a future option will allow windows to be constrained within the main window. 73 | 74 | 75 | 6. Use of colour 76 | 77 | Biblelator tries to use colour effectively to help distinguish the various different types 78 | of controls and windows, as well as to distinguish various kinds of fields within documents. 79 | We have more concern about functionality (using colours to assist the user in finding things 80 | quickly), than in attractive appearance. Much more use of colour and stylesheets is expected 81 | in future versions. 82 | 83 | 84 | 7. Use of autocompletion and autocorrection 85 | 86 | Biblelator tries to use autocompletion of words and other modern helps to assist the 87 | translators to work more efficiently. 88 | 89 | 90 | 8. Use of keyboard shortcuts 91 | 92 | Biblelator aims to (eventually) make it very efficient for users to edit Bibles if they 93 | are prepared to invest a little time and energy into learning keyboard shortcuts for 94 | navigating around Bibles and around the most commonly used menu entries. (It's planned 95 | that keyboard shortcuts will eventually be customisable by the user.) 96 | 97 | 98 | 9. Downplaying chapters and verses 99 | 100 | I don't like the over-emphasis of chapters and verses in Bibles. I'm much more interested 101 | in semantic structure such as phrases, clauses, sentences, paragraphs, and sections. So 102 | Biblelator is designed to downplay chapter and verse boundaries as much as possible (yet 103 | keep them available for those who do value them). 104 | 105 | 106 | 10. Including book introductions 107 | 108 | Biblelator considers a book introduction as chapter "-1", and considers anything before 109 | verse one in a chapter (e.g., a chapter heading), as verse "zero". It should be as easy and 110 | convenient to edit introductions as actual Bible text, and we can also handle the (rare) 111 | Bibles that have an actual chapter 0 with "verses". 112 | 113 | 114 | 11. Including other front and back matter 115 | 116 | Biblelator is aware of front and back matter (e.g., Bible introduction, glossary, etc.) 117 | and knows to treat them differently than books containing chapters and verses. 118 | 119 | 120 | 12. Saving your work 121 | 122 | We currently use AutoSave to save regular copies of your Bible editing and plan to use 123 | (optional of course) remote storage in the cloud in the future to provide assurance 124 | that program bugs or power or computer failures won't lose lots of work. 125 | 126 | WARNING: Of course, being an early tester increases the risk that you'll be the one to 127 | discover a new bug, but the developer is currently using Biblelator for his own Bible 128 | translation work. 129 | 130 | 131 | 13. No hidden folders 132 | 133 | Settings files, log files, autosave files, etc. are all saved in non-hidden folders. 134 | While this might irritate some tidyness freaks, it's in line with our "hackable" 135 | goals to make everything about Biblelator obvious and accessible. 136 | 137 | 138 | 14. Protecting your work 139 | 140 | We do plan to implement a system where an administrator can set permissions for who in a 141 | team has easy edit access to particular projects and books (or even chapters) within 142 | projects. However, please note that since this requirement is in opposition to the 143 | "hackability" requirement, it will only be nominal protection that works with users who 144 | conform to the system, i.e., computer savy users will certainly be able to find ways to 145 | circumvent such "protections". 146 | 147 | 148 | 15. Translation resources 149 | 150 | We do hope to be able to automatically access more open-source Bible translation resources, 151 | create more of our own resources (especially key terms and other lists), and maybe get 152 | permission to redistribute other Bible and related modules in an easier-to-user format. 153 | 154 | 155 | 16. Prototype implementation 156 | 157 | All of the existing code is considered as "prototype/proof-of-concept", i.e., it has not 158 | been optimised for speed and software simplicity (refactoring), but rather to get the 159 | program working. (There is also an element of balancing expensive programmer time 160 | [expensive as "in short supply"] vs. cheap computer CPU time which we expect to continue 161 | to get "cheaper" as even mobile devices get faster/multicored CPUs and GPUs plus more 162 | onboard RAM and non-volatile [e.g., FLASH] memory.) 163 | 164 | Future optimisations will include optimising screen space, both for modern desktop 165 | environments and for small screen mobile devices. Bible translators usually like lots 166 | of resources open and they all compete for screen space. A first step might be getting 167 | rid of some of the menus and/or moving some commonly used buttons onto the blank space 168 | in the menu bars. 169 | 170 | After version one is released, only then will time and resources be spent on getting 171 | the program working more efficiently. Also, after version one, new versions will provide 172 | a path to automatically upgrade settings and other files if the formats change -- this 173 | is not guaranteed for preliminary versions (where you might have to set-up your 174 | preferences again). 175 | 176 | Note that not all settings can be adjusted from the menus in the prototypes -- some must 177 | be still be adjusted by editing settings files or changing program code. 178 | 179 | 180 | 17. User-requested priorities 181 | 182 | As far as fixing deficiencies and adding new features, we will try to prioritise what actual 183 | users find important for their workflow, including the developer of course. 184 | 185 | 186 | 18. ESFM (Enhanced Standard Format Markers) aware 187 | 188 | Biblelator is intended to become an ESFM Bible editor. This allows more links and other 189 | information to be included in source Bibles (especially those intended for online display.) 190 | 191 | NOTE: ESFM development is currently on hold, awaiting the release of the USFM v3 192 | specifications. See https://Freely-Given.org/Software/BibleDropBox/ESFMBibles.html 193 | for more info. 194 | -------------------------------------------------------------------------------- /Documentation/FAQs.md: -------------------------------------------------------------------------------- 1 | Frequently Asked Questions (FAQs) for Biblelator 2 | ================================================ 3 | 4 | Last updated: 2016-04-25 RJH 5 | 6 | 7 | This document is compiled from FAQs in order to help other users. You might also find 8 | HelpfulHints.md useful. 9 | 10 | 11 | 1. FAQ1 12 | 13 | I forgot the question. 14 | -------------------------------------------------------------------------------- /Documentation/ForParatextUsers.md: -------------------------------------------------------------------------------- 1 | Notes for Paratext users 2 | ======================== 3 | 4 | Last updated: 2018-02-16 RJH 5 | 6 | 7 | This document is to help the Biblelator user who has been accustomed to using UBS/SIL 8 | Paratext to get an understanding how the Biblelator differs from Paratext, 9 | including what Paratext features are missing, and what Biblelator features 10 | are different. You might also find HelpfulHints.md and FAQs.md helpful. 11 | 12 | Installation is not described here -- you should follow the instructions in 13 | Installation.md to get the program running. 14 | 15 | Getting started is not described here -- you should follow the instructions in 16 | GettingStarted.md before using this document. 17 | 18 | For an overview of the program design philosophy, see Development.md. 19 | 20 | 21 | Features in Biblelator that are different 22 | ========================================= 23 | 24 | 1. Window placement 25 | Biblelator doesn't have one large window like Paratext with "daughter" windows 26 | inside it. Rather the "main" window is relatively small, and "daughter" windows 27 | can be placed anywhere on your screen/screens, i.e., they don't all have to be 28 | together in one place. 29 | 30 | 2. Resources 31 | Paratext can display official downloaded resources (encypted zip files) that 32 | are kept in a special folder inside the Windows "Program Files" folder. 33 | Biblelator cannot access these passworded resources. 34 | 35 | Paratext can also display USFM resources that are inside the 36 | "My Paratext 8 Projects" or "My Paratext Projects" folders. Biblelator should 37 | be able to open and display these resources and/or to open them as projects 38 | for editing. 39 | 40 | Biblelator can display many kinds of Bible resources from any folder on your 41 | computer, as well as downloaded resources (from Faith Comes By Hearing). 42 | 43 | 3. Chapter/Verse Numbering 44 | Paratext lumps all USFM lines before chapter 1 verse 1 as chapter 1 verse 0 45 | (which means scrolling doesn't synchronise between different windows). 46 | 47 | Biblelator considers everything before the chapters/verses as "chapter -1", 48 | and each line is a verse number (starting with the id line as "verse 0"). 49 | This allows the rare case of Bibles which actually have a chapter 0. 50 | 51 | Also, Biblelator moves things like section headings into the next verse, 52 | rather than displaying them as an appendage to the previous verse. The 53 | chapter number itself, is considered to be in "verse 0". 54 | 55 | 56 | Features only in Biblelator 57 | =========================== 58 | 59 | 1. Autocomplete 60 | Biblelator can be asked to suggest words as you type. Suggested words can come 61 | from the current Bible, the current Bible book, or a dictionary. Just press 62 | ESC if you don't want any of the suggestions from the pop-up box. 63 | 64 | 65 | Features missing from Biblelator 66 | ================================ 67 | 68 | 1. Still too many to list. :( 69 | (See ToDo.md for a list of planned improvements and features to be added.) 70 | -------------------------------------------------------------------------------- /Documentation/ForProgrammers.md: -------------------------------------------------------------------------------- 1 | Biblelator Notes for Programmers 2 | ================================ 3 | 4 | Last updated: 2016-06-15 RJH 5 | 6 | 7 | I won't repeat what's in the other documentation files here. You should certainly study these 8 | others first: 9 | * Installation.md 10 | * GettingStarted.md 11 | * DevelopmentPrinciples.md 12 | * ToDo.md 13 | 14 | 15 | 1. GitHub 16 | 17 | Since Biblelator (and the Bible Organisational System: BibleOrgSys) are open-source (GPL-3) 18 | programs, GitHub was considered a good place to host them. 19 | 20 | Since the OpenScriptures group was already working towards making high-quality Bible source 21 | texts available, this software seemed compatible with their aims and so it's been placed 22 | under the OpenScriptures project. 23 | 24 | There is currently a master branch, with various alpha releases tagged, and a development 25 | branch where work-in-process is being uploaded for the keenest testers to try. 26 | 27 | 28 | 2. Coding style 29 | 30 | You might quickly notice that we don't use that "standard" Python coding style. Hackability 31 | is a major aim, and I feel that my style is more readable, despite the "costs" of being 32 | non-standard. You're welcome to disagree, but it's my project. I won't accept patches that 33 | simply alter the style of the code. 34 | 35 | Also, generally if there's a choice of using a short variable name, e.g., wi, we prefer 36 | going to the extra effort to call it wordIndex. It's a strong aim to try to make the code 37 | as readable as reasonably possible to a novice or even non-programmer. This also means 38 | that readable code is preferred over very clever code, unless there's a major efficiency 39 | advantage. 40 | 41 | 42 | 3. Comments 43 | 44 | In line with #2 above, I try hard to comment blocks of code, as well as any lines that 45 | might not be immediately intuitive. (Admittedly, sometimes I do do the commenting when 46 | I go back over my code and can't figure out myself exactly what it's doing.) But again, 47 | to make it hackable, I try to make the code as understandable as possible. 48 | 49 | 50 | 4. Quote marks 51 | 52 | I tend to try to use double quotes for strings which is text, e.g., "Too many words." 53 | Text which should be translated is also fed through the gettext function like this: 54 | _("Too many words.") 55 | I try to use single quotes for program strings which are not presented to the user, 56 | e.g., lastPressed = 'EnterKey' 57 | I use sets of three double quotes for function and class documentation strings, 58 | e.g., """This function does this and that.""" 59 | 60 | 61 | 5. Algorithmic efficiency 62 | 63 | Don't mock the inefficiency (either execution time or memory use) of any of my code. This 64 | is definitely prototype code -- everything so far has been written to get it working as 65 | quickly as possible. There's been absolutely no attempt to refactor or increase efficiency, 66 | and I don't plan to even consider this until AFTER the release of v1.0. That's not to say 67 | that patches from others to improve efficiency won't be accepted. But for me, NEW FEATURES 68 | are currently my priority, followed by removing bugs. Further automated testing will be 69 | next, following by packaging for distribution, and then restructuring and efficiency 70 | improvements are last. 71 | 72 | 73 | Robert Hunt. 74 | Biblelator developer. -------------------------------------------------------------------------------- /Documentation/GettingStarted.md: -------------------------------------------------------------------------------- 1 | Getting Started with Biblelator 2 | =============================== 3 | 4 | Last updated: 2018-02-16 RJH 5 | 6 | 7 | This document is to help the Biblelator user to get an understanding how the developer 8 | anticipated that the program might be used. 9 | 10 | Installation is not described here -- you should follow the instructions in 11 | Installation.md before using this document. 12 | 13 | For an overview of the program design philosophy, see Development.md. 14 | 15 | 16 | 1. Settings 17 | 18 | When Biblelator is run the first time, it tries to create a BiblelatorData folder in 19 | the user's home folder. Inside there, it creates a BiblelatorSettings folder and the 20 | file Biblelator.ini inside that. The idea of the settings file is that Biblelator tries 21 | to remember the size and position of open windows plus the current Scripture reference 22 | position, and to return to the last values when the program is restarted. 23 | 24 | The settings file can be viewed (or even changed if you are careful) with a simple text 25 | editor program. (If Notepad doesn't work, try Wordpad.) Just make sure that Biblelator 26 | is closed if you are editing settings, otherwise your changes may be overwritten when 27 | Biblelator exits. 28 | 29 | If you want to reset Biblelator to its default settings, the settings file can be 30 | renamed (e.g., to Biblelator.ini.bak) or deleted (if you're sure you don't want to 31 | reuse them) and Biblelator will now ignore those settings when starting up. (This might 32 | also be necessary if a bug causes Biblelator to freeze or malfunction.) 33 | 34 | ADVANCED: Biblelator can also be started with the --override flag to override the 35 | normal Biblelator.ini settings file with your own file, e.g., 36 | Biblelator.py --override Test.ini 37 | will use Test.ini rather than Biblelator.ini for loading/saving program settings. 38 | 39 | This feature can be used if you regularly switch between a number of different 40 | project environments, e.g., you are working on separate English and French translations 41 | and have different resources, etc. open in the two different projects. Run Biblelator, 42 | set-up your windows for the English project, then exit Biblelator. Go to the settings 43 | folder (see above) and rename Biblelator.ini to English.ini. Now do the same for 44 | the French translation windows so you get French.ini. Now you can start Biblelator 45 | with either of the following: 46 | Biblelator.py -o English 47 | Biblelator.py -o French 48 | 49 | It's recommended that you edit the .ini settings file to enable Internet access unless 50 | you have (security) reasons not to. You'll also see other settings that can be 51 | adjusted. (Eventually you'll be able to set these from inside the program, but 52 | the settings editor hasn't been written yet.) 53 | 54 | 55 | 2. Logging 56 | 57 | A folder called BiblelatorLogs is also created inside the BiblelatorData folder. The 58 | last two or more logs (e.g., Biblelator_log.txt and Biblelator_log.txt.bak) are kept 59 | in this folder. These logs may be useful to the programmers after a program crash to 60 | help determine what caused the fault. 61 | 62 | If Internet access is enabled in the settings file, and the sendUsageStatistics flag 63 | is enabled, then the logs will be automatically uploaded to the Freely-Given.org 64 | server. 65 | 66 | 67 | 3. Main window 68 | 69 | The Biblelator main window is a small window that is used to open other windows. 70 | It also contains the main bar for entering book/chapter/verse values 71 | and for entering lexicon words. 72 | Note that the introduction to a book is considered to be "chapter -1". 73 | The main window can usually be kept fairly small and be placed in the most convenient 74 | part of the screen. However, if Biblelator is started in debug mode (with the 75 | --debug flag on the command line), the main window may need to be made larger 76 | in order to properly display the additional debug logging information. 77 | In touch-screen mode, Biblelator will display the main window with larger buttons 78 | suitable for touching accurately with a fingertip. 79 | 80 | 81 | 4. Resource texts 82 | 83 | Resources are texts which are opened read-only for study or reference purposes as you 84 | translate in a project window. This includes most unencrypted Bibles, commentaries, 85 | and some lexicons. These might be other USFM Bibles that you have been given by 86 | colleagues in other nearby languages, or perhaps mainstream translations that have 87 | been installed on your computer by other Bible display programs or that you have 88 | downloaded. 89 | Depending on the type of resource you are opening, you might be required to select 90 | either a folder or a file to open the resource. 91 | 92 | 93 | 5. Resource Windows 94 | 95 | The Resource menu in the main window is used to launch new resource windows which can 96 | be moved anywhere on your screen(s). 97 | 98 | 99 | 6. Resource Collection Windows 100 | 101 | Resources are texts which are opened read-only for study or reference purposes as you 102 | translate in a project window. This includes Bibles, commentaries, and lexicons. 103 | Unllike Resource Windows above, Resource Collection Windows allow the display of several 104 | resource boxes within the same window. This makes better use of the screen space, 105 | however, these resource boxes can't display large segments of the text (like chapters) 106 | -- only a verse or two. 107 | The Resource menu in the main window is used to launch new resource collection windows, 108 | and then individual resource boxes are opened from the Resource menu inside that 109 | new window. 110 | 111 | 112 | 7. Reference Collection Windows 113 | 114 | Reference collection windows display read-only cross-references all in the same version. 115 | They display individual verses, groups of verses, or ranges of verses. 116 | The Window menu in an edit window is used to launch new reference collection windows, 117 | and the references will automatically show in that same version. 118 | 119 | 120 | 8. Lexicon Windows 121 | 122 | There is a Bible lexicon window, but it's not yet automatically linked to Bible resources. 123 | At this stage, you can use the text box to the right of the verse number in the main 124 | window in order to enter Hebrew or Greek Strong's codes such as H123 or G1026. 125 | 126 | 127 | 9. Project Windows 128 | 129 | Projects are Bibles in the process of being translated, so they have a full edit window. 130 | 131 | Note that the default settings for AutocompleteMode in the .ini settings file is None. 132 | Other options are Bible and BibleBook. Using Bible AutocompleteMode slows down the 133 | starting of Biblelator as existing Bible books are scanned to find all words used, but 134 | having the pop-up autocomplete box make suggestions can significantly speed up typing 135 | of commonly used terms, plus it can also highlight mispellings if you scan through the 136 | suggestions. (Use ESC or just keep typing to dismiss the pop-up window.) 137 | 138 | 139 | 9a. Biblelator Project Windows 140 | 141 | If Biblelator is your only Bible editor, you can use our native Bible projects. At this 142 | stage, you simply give a Bible name and abbreviation, e.g., "My special Bible", "MSB". 143 | The project files are saved as UTF-8 files in your BiblelatorSettings folder. (These 144 | projects are not fully developed yet.) 145 | 146 | 147 | 9b. Paratext Project Windows 148 | 149 | If you already have a Paratext project, Biblelator can also be used as an editor/checker 150 | (but of course you're likely to lose work if you edit using both programs on the same 151 | files at the same time so we suggest only having one of these programs open at a time). 152 | You point Biblelator at the .SSF file to open an existing Paratext project in Biblelator. 153 | (This feature is used extensively by the developer, so it's well tested, at least on 154 | Linux.) 155 | 156 | 157 | 10. Bible Groups 158 | 159 | Biblelator has five group codes (A,B,C,D,E) that Bible windows can be assigned to. All 160 | new windows are assigned to group A by default but this can be easily changed. Each 161 | group can be set to a different reference, e.g., if group A windows are in Matthew, 162 | group B windows might be displaying a reference in Isaiah that was quoted by Matthew. 163 | 164 | In the future, there will be automatic ways to display OT references (like the above 165 | example -- at the moment it must be set-up by hand) and also to display synoptic 166 | gospel references, e.g., by having separate Bible windows open in groups A,B,C,D 167 | automatically displaying parallels in Matthew, Mark, Luke, and John. 168 | 169 | 170 | 11. Optional Start-up Parameters 171 | 172 | If you start Biblelator with the --help command-line flag, the program will display 173 | the available parameters which can be used and then exit immediately. 174 | 175 | The --verbose flag can be used to get the program to display more information in 176 | the start-up/terminal window, although it can easily be overwhelming. However, 177 | it might be helpful to get more information in order to report a fault. 178 | 179 | The --debug flag is usually used by programmers to display debugging information 180 | and is more likely to cause the program to fail, so is not recommended for 181 | normal users. 182 | 183 | Note that the --strict flag is part of the Bible Organisational System 184 | usually used for strict checking of data files where you want to halt 185 | even if there's a small error. You usually don't want this behaviour 186 | in an editor so it's not recommended for Biblelator. 187 | 188 | The --single flag limits Biblelator and the Bible Organisational System to 189 | using a single thread. This only makes a difference on a multicore CPU or 190 | multiprocessor system. Setting this flag might make some debugging easier, 191 | but it may also slow down response times of the program in some cases, 192 | especially start-up. 193 | 194 | -------------------------------------------------------------------------------- /Documentation/HelpfulHints.md: -------------------------------------------------------------------------------- 1 | Helpful Hints for Biblelator 2 | ============================ 3 | 4 | Last updated: 2018-02-16 RJH 5 | 6 | 7 | This document is to help the Biblelator user to get an understanding how the program 8 | might be used more efficiently or productively. You might also find FAQs.md 9 | helpful. 10 | 11 | Installation is not described here -- you should follow the instructions in 12 | Installation.md to get the program running. 13 | 14 | Getting started is not described here -- you should follow the instructions in 15 | GettingStarted.md before using this document. 16 | 17 | For an overview of the program design philosophy, see Development.md. 18 | 19 | 20 | 1. Hint 1 21 | 22 | The introduction to a book (particularly in USFM files) is considered to be 23 | "chapter -1". 24 | -------------------------------------------------------------------------------- /Documentation/Installation.md: -------------------------------------------------------------------------------- 1 | Biblelator Installation 2 | ======================= 3 | 4 | Last updated: 2018-02-16 RJH 5 | 6 | 7 | Please see the document DevelopmentPrinciples.md for information about the design decisions 8 | behind how and why Biblelator was developed. 9 | 10 | This document provides basic instructions for installing and running a copy of a 11 | pre-release version of Biblelator onto your computer. 12 | 13 | After the numbered instructions, there's a description of my own experience of trying to 14 | follow my own instructions on a different computer. 15 | 16 | 17 | 1. Install Python3 18 | 19 | Biblelator uses Python3 (it's currently being developed on Python 3.6 20 | but will probably run on most relatively recent versions of Python3. 21 | 22 | To see if Python3 is installed on your computer, 23 | open a terminal or command prompt window on your system and enter: 24 | python3 25 | If Python3 is installed, it should show a version number and a >>> prompt. 26 | Type "quit()" (without the quotes) to exit Python. 27 | 28 | If it's not already installed, you should install Python3 on your system either 29 | through the software manager on your system, or else 30 | as per the instructions here at https://www.python.org/downloads. 31 | 32 | 33 | 2. Optionally install Git 34 | 35 | Git is a program that makes it easy to fetch the latest Biblelator files from the Internet. 36 | However, you don't have to install Git if you don't want to. 37 | 38 | You can run Git from a command prompt window, or else from a GUI program such as 39 | TortoiseGit on Windows. 40 | 41 | If it's not already installed, you should install Git on your system either 42 | through the software manager on your system, or else 43 | as per the instructions here at http://git-scm.com/downloads and/or 44 | TortoiseGit for Windows as per the instructions at 45 | https://code.google.com/p/tortoisegit/wiki/Download. 46 | 47 | If you use Git in steps #4 and #5 below, then to upgrade later to future versions 48 | of BibleOrgSys and Biblelator, you just have to do a "git pull" command 49 | on each of those folders. 50 | 51 | If Git is not on your path when you open a command prompt window in Windows, 52 | a command like "set PATH=%PATH%;C:\Program Files (x86)\git\bin" might help 53 | (or without the " (x86)" if it's not a 64-bit system). 54 | 55 | 56 | 3. Create a folder for Biblelator -- we recommend the name BiblelatorFiles. 57 | If you want other users on your computer to be able to use Biblelator, 58 | either create this folder somewhere public such as in Public Documents, or else 59 | change the permissions of the folder to allow other users 60 | to be able to read from it and write to it. 61 | You can call the folder anything you like, 62 | but these instructions will assume that you called it BiblelatorFiles. 63 | 64 | 65 | 4. A note about the Biblelator development version: 66 | When you are installing the Biblelator program files using git clone in #6 below, you have 67 | the option of using the master (stable) version, or the later development version. 68 | The development version is likely to have more features, and at any point in time, 69 | might have more or less bugs. If you want to do this, use: 70 | git checkout development 71 | after the git clone command in step #6a. 72 | Note that depending on the current stages of development, you might also need the 73 | development version of the BOS (in step #5a below). 74 | 75 | 76 | 5. Install the Bible Organisational System (BOS) inside the BiblelatorFiles folder. 77 | Open https://github.com/openscriptures/BibleOrgSys in a browser window. 78 | On the right-hand side of the page are links to either: 79 | a. Download (clone) BibleOrgSys with Git (using either HTTPS or SSH (if you have a GitHub account). 80 | This method allows easier updating to future development versions. 81 | The HTTPS link is https://github.com/openscriptures/BibleOrgSys.git 82 | b. Without Git, download the current version BibleOrgSys as a ZIP file and 83 | unzip the file in the BiblelatorFiles folder (then remove -master from the folder name). 84 | Either way, you should end up with a new folder called BibleOrgSys 85 | inside your BiblelatorFiles folder from step #3. 86 | 87 | 88 | 6. Install the Biblelator program inside the BiblelatorFiles folder. 89 | Open https://github.com/openscriptures/Biblelator in a browser window. 90 | On the right-hand side of the page are links to either: 91 | a. Download (clone) Biblelator with Git (using either HTTPS or SSH (if you have a GitHub account). 92 | This method allows easier updating to future development versions. 93 | The HTTPS link is https://github.com/openscriptures/Biblelator.git 94 | b. Without Git, download the current version Biblelator as a ZIP file and 95 | unzip the file in the BiblelatorFiles folder (then remove -master from the folder name). 96 | Either way, you should end up with a new folder called Biblelator 97 | inside your BiblelatorFiles folder from step #3. 98 | 99 | 100 | 7. Install OpenScriptures HebrewLexicon. 101 | Open https://github.com/openscriptures/HebrewLexicon 102 | On the right-hand side of the page are links to either: 103 | a. Download (clone) HebrewLexicon with Git (using either HTTPS or SSH (if you have a GitHub account). 104 | This method allows easier updating to future corrected versions. 105 | The HTTPS link is https://github.com/openscriptures/HebrewLexicon.git 106 | b. Without Git, download the current version HebrewLexicon as a ZIP file and 107 | unzip the file in the first/top BiblelatorFiles folder (then remove -master from the folder name). 108 | Either way, you should end up with a new folder called HebrewLexicon 109 | inside your BiblelatorFiles folder from step #3. 110 | 111 | 112 | 8. Install morphgnt Greek Strongs info. 113 | Open https://github.com/morphgnt/strongs-dictionary-xml 114 | On the right-hand side of the page are links to either: 115 | a. Download (clone) strongs-dictionary-xml with Git (using either HTTPS or SSH (if you have a GitHub account). 116 | This method allows easier updating to future corrected versions. 117 | The HTTPS link is https://github.com/morphgnt/strongs-dictionary-xml.git 118 | b. Without Git, download the current version strongs-dictionary-xml as a ZIP file and 119 | unzip the file in the first/top BiblelatorFiles folder (then remove -master from the folder name). 120 | Either way, you should end up with a new folder called strongs-dictionary-xml 121 | inside your BiblelatorFiles folder from step #3. 122 | 123 | 124 | 9. Make Biblelator.py executable -- only on Linux. 125 | Navigate to the 2nd Biblelator folder either in a command line window or a file manager. 126 | If on a command line, type "chmod +x Biblelator.py" (without the quotes), or 127 | if in a file manager, right-click on Biblelator.py, choose Properties, 128 | and Permissions (or similar) and set the Executable flag. 129 | 130 | 131 | 10. Try a test run of the Biblelator program. 132 | Open a command prompt window and navigate to your second Biblelator folder using the cd command, 133 | e.g., cd /home/fred/Biblelator/Biblelator (a Linux example), or 134 | cd \Users\Public\Documents\Biblelator\Biblelator (a Windows example). 135 | On Linux, type ".\Biblelator.py --version" (without the quotes), or 136 | on Windows, the command is something like: 137 | "Biblelator.py --version" (without the quotes) 138 | or if that doesn't work, you might need something like 139 | "C:\Python36\python.exe Biblelator.py --version" (without the quotes) 140 | depending on your Python3 version number and how it was installed. 141 | This test run of the program should just display the Biblelator version number 142 | and then exit immediately. 143 | If you see the error "ImportError: No module named tkinter", check in case you are 144 | accidentally using Python 2 rather than Python 3. 145 | If the program does not run, please copy the contents of the command prompt window, 146 | and paste them into the comment box at https://Freely-Given.org/Contact.html. 147 | 148 | 149 | 11. A note about the lock file: 150 | Biblelator creates a Biblelator.lock file in its home folder when it's running. 151 | This enables it to detect if you start Biblelator twice at the same time, and/or 152 | if the program crashed last time (because the file won't have been 153 | automatically deleted). 154 | When restarted after a crash, Biblelator tries to check if the autosave files 155 | contain valuable edit data. Then you can recover the files if they contain 156 | a lot of work. 157 | Then the Biblelator.lock file must be manually deleted before the program will 158 | run again. 159 | So if you were testing the program, or know that you hadn't done a lot of work 160 | since the last save, just go ahead and delete the Biblelator.lock file. 161 | 162 | 163 | 12. View optional parameters. 164 | On Linux, type ".\Biblelator.py --help" (without the quotes), or 165 | on Windows, the command is something like: 166 | "Biblelator.py --help" (without the quotes) 167 | or if that doesn't work, you might need something like 168 | "C:\Python36\python.exe Biblelator.py --help" (without the quotes) 169 | depending on your Python3 version number and how it was installed. 170 | This test run of the program should display the Biblelator command prompt 171 | help page and then exit immediately. 172 | Note that the --strict flag is part of the Bible Organisational System 173 | usually used for strict checking of data files where you want to halt 174 | even if there's a small error. You usually don't want this behaviour 175 | in an editor so it's not recommended for Biblelator. 176 | Note that multiprocessing is currently disabled, so the --single flag 177 | currently does nothing. 178 | 179 | 180 | 13. Run Biblelator in the normal mode for normal working. 181 | If everything seems to be working correctly, 182 | next time you run Biblelator you might not need to run it in debug mode, 183 | i.e., simply omit the "--version" or "--help" parameters in order to run in normal mode. 184 | If the program does not run, please copy the contents of the command prompt window, 185 | and paste them into the comment box at https://Freely-Given.org/Contact.html. 186 | It may also be helpful to include the contents of the Biblelator.ini file 187 | which should be in yourNormalHomeFolder/BiblelatorData/BiblelatorSettings/ folder. 188 | 189 | 190 | 14. IF #12 ABOVE CRASHED IMMEDIATELY, or if you need more info on what's going wrong, 191 | try starting the Biblelator program in debug mode. 192 | Using a command similar to what worked in the previous step, 193 | replace "--version" with "--debug" to actually run the program 194 | but with extra debugging information displayed in the command prompt window 195 | so we can more easily track issues if there's an installation program. 196 | This command should open the Biblelator main window 197 | (with an extra Debug menu and extra debug information inside the main window). 198 | Aside from displaying these extras, plus extra debug information displayed in the command 199 | prompt window, you should be able to access all (working) Biblelator functions as usual. 200 | 201 | WARNING: The debug mode has a HALT button, which unlike the QUIT button, 202 | exits immediately WITHOUT SAVING any files or settings, so use it with great caution. 203 | 204 | If the program does not run, please copy the contents of the command prompt window, 205 | and paste them into the comment box at https://Freely-Given.org/Contact.html. 206 | Note that a BiblelatorData folder should be created in your home folder when you exit the program, 207 | and inside that, a BiblelatorSettings folder should contain your settings information 208 | and a BiblelatorLogs folder should contain a log file. 209 | 210 | 211 | 15. In order to keep people safe who might be working on Bibles in sensitive locations, the 212 | default settings have all Internet access disabled. 213 | We recommend that most people enable Internet access. Unfortunately, this can't yet be 214 | done inside the program, so you need to find the settings file and edit it. The 215 | BiblelatorData folder should have been created in your home folder. Inside that is 216 | the BiblelatorSettings folder. Inside that, there's a default Biblelator.ini file 217 | (or you might have created a different ini file using the --override (or -o) argument). 218 | Open this file with a text editor, e.g., gedit or Notepad and change the setting 219 | "internetAccess" to Enabled (and then save the file of course). 220 | 221 | 222 | 16. Eventually (once the program is working fully and reliably) you might like to 223 | make a desktop or toolbar shortcut to run Biblelator on your system so it can be started easier 224 | (without having to open a command prompt window and manually navigate to files and folders). 225 | Meanwhile though, it's probably useful to have the command prompt window open. 226 | 227 | 228 | 17. If you wish to access online Scripture resources from the Digital Bible Platform 229 | (Faith Comes By Hearing FCBH), request further information from the Biblelator programmer(s) 230 | via https://Freely-Given.org/Contact.html. 231 | 232 | 233 | 18. If you wish to access offline Scripture resources from the Crosswire Sword project, 234 | you should download and install/unzip the resources from the Crosswire or other repositories. 235 | You might already have these installed if you use a Sword-based Bible program such as 236 | Xiphos, Bibletime, BPBible, etc. 237 | Then you should use https://Freely-Given.org/Contact.html to contact the Biblelator programmers 238 | and let us know how you installed the Sword modules, 239 | and which folder they were installed to. 240 | Then hopefully we can get you started with basic access to these modules. 241 | 242 | 243 | 19. PhotoBible 244 | If you wish to use the PhotoBible export option (converts each few verses into JPG files 245 | for use on "feature phones" with cameras) for your USFM projects, you need to install 246 | the free ImageMagick package. For Linux, this can usually be installed from your package 247 | manager, and for Windows (untested), the exe installation files can be downloaded from 248 | http://www.imagemagick.org/download/binaries. 249 | 250 | 251 | 20. Program updates 252 | If you used Git to install Biblelator and/or BibleOrgSys, you should regularly update each 253 | of them with "git pull" on each folder (or the equivalent command from the GUI if you 254 | use TortoiseGit or equivalent). 255 | If you installed Biblelator and/or BibleOrgSys by downloading a zip file from GitHub.com, 256 | you should regularly update each of them by downloading the latest zip file and 257 | extracting them into each folder to overwrite existing files. (This won't erase 258 | renamed or deleted files, but who cares.) 259 | 260 | 261 | Please see the document GettingStarted.md for help on how the Biblelator resource and project 262 | windows are designed to work. 263 | 264 | 265 | The following describes my attempt (March 2016) to install and run Biblelator v0.31 on a 266 | Windows-7 laptop: 267 | 268 | * Opened https://github.com/openscriptures/Biblelator/blob/master/Documentation/Installation.md in a browser 269 | * Python 3.4.3 was already installed for all users 270 | * Opened command prompt and typed "python". This worked. Closed Python 3.4.3. 271 | * Didn't want to install Git 272 | * Downloaded zip from https://github.com/openscriptures/BibleOrgSys (15MB) 273 | and https://github.com/openscriptures/Biblelator/tree/development 274 | * Moved two zip files from Downloads folder to C:\Users\Public\Documents 275 | * Right-clicked the files and choose Extract all… 276 | * Had to rename BibleOrgSys-master folder to BibleOrgSys and Biblelator-development to Biblelator 277 | * Discovered that these folders both had an extra folder inside them, so went into that folder, 278 | did Control+A to select all files, Control+X to cut, went back up a level then Control+V to 279 | paste and then deleted the now-empty extra folder 280 | * Now the file Biblelator.py, etc. is in C:\Users\Public\Documents\Biblelator\ 281 | and BCVBible.py, etc. is in C:\Users\Public\Documents\BibleOrgSys\ 282 | * (Yes I forgot to create a BiblelatorFiles folder like in the instructions above.) 283 | * Entered "cd C:\Users\Public\Documents\Biblelator" in command prompt window 284 | * Entered "Biblelator.py --version" in command prompt window. 285 | This gave a lot of WARNINGs and CRITICAL errors, but did display v0.32 at the bottom. 286 | (Since I downloaded the development branch from GitHub, this will likely be a still-unfinished v0.32.) 287 | * Entered "Biblelator.py --debug" in command prompt window. 288 | Same lot of errors and a multicoloured Biblelator window opened. I clicked the quit button. 289 | * Entered "Biblelator.py" in command prompt window. 290 | Same lot of errors and a less coloured Biblelator window which I made less deep by moving up the bottom border. 291 | * Tried to open some resource windows, but online Digitial Bible Platform was greyed out 292 | (needs a key code -- email the program developer to get one) 293 | * Tried to open a Sword module but it failed. (Not too surprised since I have none installed.) 294 | * I looked here https://www.crosswire.org/applications/?section=Windows and decided to install 295 | Xiphos from http://xiphos.org/download/. 296 | * Installed Xiphos (required the administrator password, 297 | plus again to allow Windows firewall access to the Internet) 298 | * Xiphos installed no modules, but after closing two introductory windows, showed the Module Manager. 299 | * Modules Sources / Choose indicated that resources would be installed into C:\Users\\AppData\Roaming/Sword. 300 | * I went into Modules / Install/Update, clicked Refresh, and installed some English Bibles, 301 | then restarted Xiphos to ensure that they were really there. 302 | * Now restarting Biblelator, I could open these Sword modules (although the display formatting 303 | was very messy -- but this is still only v0.32). 304 | * Closed Biblelator and restarted it, and it remembered which windows I had opened where. 305 | * Created a new project, and then created all (blank) books using RSV52 versification. 306 | * I could open a lexicon window, but it showed nothing but a heading when I typed H1234 307 | into the lexicon key box (to the right of the verse spinbox in the main window) 308 | * File / Info on the new project window showed me that the project was saved in C:\Users\\BiblelatorData\. 309 | 310 | 311 | -------------------------------------------------------------------------------- /Documentation/KeyboardShortcuts.md: -------------------------------------------------------------------------------- 1 | Biblelator Keyboard Shortcuts 2 | ============================= 3 | 4 | Last updated: 2016-06-14 RJH 5 | 6 | 7 | Biblelator still only has a few working keyboard shortcuts 8 | 9 | Navigation 10 | ========== 11 | Alt+Up Next verse From anywhere 12 | Alt+Dwn Previous verse From anywhere 13 | 14 | Files 15 | ===== 16 | Ctrl+S Save file From an edit window 17 | 18 | 19 | Standard editor shortcuts 20 | ========================= 21 | Ctrl+left Previous word 22 | Ctrl+right Next word 23 | 24 | 25 | Eventually we hope to make these keyboard shortcuts adjustable by the user. -------------------------------------------------------------------------------- /Documentation/ToDo.md: -------------------------------------------------------------------------------- 1 | Biblelator ToDo List 2 | ==================== 3 | 4 | Last updated: 2018-02-16 by RJH 5 | 6 | 7 | This is an informal list of things that need to be fixed or are planned to be done. 8 | 9 | Eventually we will use the issue tracker at Github 10 | -- actually, you're welcome to list your issues there already. 11 | 12 | Things nearer the top of the list are higher in priority 13 | (and due to my situation often only having smallish chunks of time available, 14 | smaller jobs often get done before larger ones unfortunately). 15 | 16 | VERY SERIOUS BUGS (e.g., can cause data loss) 17 | * Editing bridged verse caused it to be added twice!!! 18 | * Was it Biblelator that lost the last verse in a chapter??? 19 | * WHY DID GLOBAL SEARCH/REPLACE CAUSE DUPLICATE LINES IN BOOK ALREADY EDITED 20 | 21 | Biblelator bugs / unfinished 22 | * Why didn't it return to same folder when opening 2nd Biblelator project ??? 23 | * Find with regex doesn't seem to work great (maybe something to do with case???) 24 | * Typing Ctrl chars (e.g., Ctrl+F) in autocomplete box closes box, but adds icons to the text. 25 | * Prevent user from typing before start-up is finished 26 | * Make Bible find work on USFM files in USFM edit window (not on the internal Bible which already has some fixes when loaded) 27 | * USFM edit window still displays previous book when stepping to a non-existent book (and cancel create new file) 28 | * Enter a bookname, tab across enter a chapter number then enter, but it always goes to chapter 1 :( 29 | * Want Alt-up and down to go to previous/next find results 30 | * Bible find regex:XXX doesn't work unless match case or xxx is used 31 | * Bible find regex:XXX (with match case) shows regex in find result lines 32 | * Double-click in Bible windows doesn't select the word 33 | * Bible Search/Replace globally didn't show the update in the open USFMEditWindow 34 | * Bible find found heading (\s) in 1:19, but it's displayed in edit window above the NEXT verse (1:20) 35 | * Checking window: can't click on individual errors (for goto) 36 | * Checking window: enable/disable Back/Forward buttons (and display link when cursor over) 37 | * Clicked on an apocryphal book (result of search) and MBT got into sort of a loop "Need to create book" / cancel 38 | * CRITICAL: cacheBook: We have a duplicate Matigsalug Unicode Version GLS_0:419! -- already had '\n' and now appending '\\p \\k ubas\\k* [Ceb. paras, ubas; Eng. grape]\n' 39 | * Bible find can't find/replace space at end of line -- why not? because removed at load time! 40 | * Find in chapter -1 gives wrong verse (only sometimes -- why??? REMs removed at load time???) 41 | * Windows and Bible lists need to be displayed in a window 42 | * HTML source box isn't listed in child windows (included in show all / hide all) 43 | * Window find doesn't seem to work on resource windows 44 | * After moving replace box, it still keeps reappearing in the original position 45 | * Remember find/replace lists in settings (for each window/project -- maybe not) 46 | * Remember position of last find box 47 | * Add illegal character beep function? 48 | * Get extended find box working better -- need to show whole verse somehow (why can't right click or something?) 49 | * Sort out USFM styles for current verse / formatted / unformatted etc. 50 | * Work more on Tools/Options for edit window to set autocomplete mode, etc. 51 | * Make edit window status bar default (if screen is big enough) 52 | * Clicking in edit window while still starting can cause a spinbox error 53 | * Window settings don't work well for text collections, etc. (need to be nested???) 54 | * Bible find needs intro set if book in FRT, GLO, etc. 55 | * Make Bible find default to any currently selected text in edit window? 56 | * Bible find can't seem to jump to GLO lines 57 | * Bible replace needs more work on reloading open books/Bibles 58 | * Book number spinner needs to check if any window contains that book else skip it 59 | * Need wait status/cursor when opening a DBP resource, doing Bible checks, etc, etc. 60 | * Can't undo USFM Bible edit once moved cursor 61 | * Can't double-click in USFM editor to select a word (but can in text editor) 62 | * Ctrl+V seems to paste double in text edit windows (paste from menu or right-click only does it once) 63 | * Text file open and Biblelator project open dialogs flash for a while and then go smaller 64 | * Seems that Alt up and down do different things if a spinbox or the bookname box is selected 65 | * Make opening a 2nd DBP box inside a resource collection not download everything again 66 | * Having a DBP window open (and slow Internet) slows all verse navigation 67 | * Going up and down repeatedly over a chapter marker (in single verse USFM edit window) is not consistent 68 | * Do more usage logging 69 | * Settings editor is not finished enough 70 | * BOSManager is not finished enough 71 | * SwordManager is not finished enough 72 | * Make wording consistent between DIR and FOLDER 73 | * Make working consistent between FIND and SEARCH 74 | * When using custom sword module path, send it home so we can add it to the defaults??? 75 | * Maybe the --strict option should be removed for Biblelator??? 76 | 77 | Biblelator testing required 78 | * Biblelator project edit windows may fail on malformed markers (e.g., space before \v) 79 | * Need to set-up some special .ini files for testing (with every kind of window/box open) 80 | * Systematically work through all menus 81 | 82 | 83 | BOS bugs 84 | * Doesn't know about Sword NRSVA versification yet 85 | * OSIS (and other containerised) formats should insert end markers themselves when loading 86 | 87 | 88 | BOS improvements for Biblelator 89 | * Fix Unicode errors with Sword python bindings (SwordBible faults) 90 | * Cache Bible books as pickles 91 | * Make a class for a list of search results (being able to combine lists in various ways) 92 | * Start Names checking tool 93 | * Upgrade to USX 2.5 94 | * Are we able to read Sword dictionaries? 95 | * How to stop BibleOrganisation critical errors on Biblelator startup (need to manually cache data files???) 96 | * Fix speech mark / quotation checking 97 | * Fix intro/text section checking 98 | * Fully handle nested USFM markers (USFM 2.4) 99 | * Handle USFM 3.0 (when released) 100 | * Update ESFM spec (when USFM 3 is released) 101 | * Learn to read BCV files 102 | * Expand testing functions 103 | * Refactor code to be more modular 104 | * Increased multiprocessing 105 | * Investigate creating a plug-in structure 106 | * Add check for over-long paragraphs (and sentence length?) 107 | * Write a GUI for Bible search and search/replace ??? 108 | * Make a "remembered lists" folder (e.g., search parameters, etc.) 109 | 110 | 111 | BOS testing required 112 | * Can BOS import USFM with all books in one file? 113 | * Lots of errors/warnings reading various USX Bibles 114 | * Had 3 default mode failures: ['TestBDBSubmissions1', 'TestBDBSubmissions2', 'TestHaiola3'] 115 | 116 | 117 | BOSManager / SwordManager / Settings editor stuff 118 | * Make Bible fields in BOSManager into clickable links (to go to other tabs) 119 | * Work on final three tabs in BOSManager 120 | * Get SwordManager working to list/install/update modules 121 | * Allow settings manager to edit other settings files 122 | * Get apply/ok/cancel working 123 | 124 | 125 | Biblelator stuff 126 | * Handle Paratext 8 files 127 | * Release version 0.42 128 | * Allow footnote displays in Bible Resource boxes/windows 129 | * Add AND and OR for Bible find 130 | * Add a pop-up quick reference box (with all open translations???) 131 | * Make HTML window more robust (failed if meta line was missing self-closing slash) 132 | * Do we need separate visited lists for each group code? 133 | * Make a way for the program or installer to automatically download reference Bibles and other resources 134 | * USFM editor still only aware of basic/common USFM tags 135 | * Make Biblelator use Paratext autocorrect files for Paratext projects 136 | * Make a proper icon 137 | * Save iconification state of windows 138 | * Use checkboxes to allow individual exports 139 | * Get Sword resources displaying prettier 140 | * Check if a recreated (at startup or settings change) window is on the/a screen (and if not move it on) 141 | * Cache DBP to disk (if have expensive Internet)??? 142 | * Need keyboard shortcuts for list up/down 143 | * Biblelator project USFMEditWindow can't set project name correctly coz no settings loaded yet 144 | * Paste doesn't replace the selection 145 | * Remove double-spaces at either end of a paste 146 | * Need to remove autocorrect settings from code and put into files (with an editor???) 147 | * Prevent autocomplete if editing in the middle of a word -- maybe make this an option 148 | * Display toolbox dictionary??? 149 | * Allow windows to lock together (e.g., two or more project edit windows) 150 | * Send BCV updates from HTML window 151 | * Allow a very simple edit mode (for users who find USFM way too complex) 152 | * Send verse links to Paratext 153 | * Fix flashing SSF open window for Open / Paratext project 154 | * Don't allow two projects with the same name 155 | * Optional hints at start-up 156 | * Don't save settings if they haven't changed 157 | * Maybe should ask before just created a new settings file (could just be a user typo) 158 | * Pop up a select box if previous/next buttons are held down 159 | * Up/down verse over chapters isn't working -- also up/down chapter (to one with less verses) 160 | * Add debug menu to edit windows to display settings/log 161 | * Get some different views working on the edit window 162 | * Synchronise with other Bible programs (esp. on Windows) 163 | * Display footnotes and xrefs in resources 164 | * Work on a default stylesheet which can be copied to make a custom stylesheet 165 | * Make a full project properties dialog and do project setting properly 166 | * Add "Recent" entries to the main menus 167 | * Allow the user to set the containing folder for projects and exports 168 | * Release version 0.50 169 | * Allow undo of window/box close (from main window???) 170 | * Include some sample folders and sample ini files 171 | * Setting max window sizes prevents maximizing -- is this what we really want? 172 | * Consider when the same project/file is opened multiple times 173 | * Consider/optimize toolbars in child windows (and/or hiding the menu) 174 | * Handle multiple overlapping tags in the HTML window 175 | * Add "Display by Section" for Bibles that have section headings 176 | Does that mean we have previous/next section navigation also? 177 | * Design the default short-cut keys for verse/chapter navigation 178 | * Work with someone as a test user 179 | * Work out how the help system will work and start implementing some content 180 | * Improve Sword module display (Bibles and Commentaries) 181 | * Improve Strongs (lexicon) HTML display 182 | * Look at doing some windows updates in idle time 183 | * Make a splash screen (turned off/on in settings file) 184 | * Release version 0.60 185 | * Allow users to "log-on" with usernames (passwords?) 186 | * Allow setting of roles (administrator/project leader/superintendent/overseer, translator, consultant/reviewer/archivist/typesetter, contributor/friend/critic/observer) 187 | * Make logging more useful 188 | * Project sharing (Hg vs Git) -- requires server set-up 189 | * Allow user to show history of changes per verse (and per chapter???) 190 | * Write autocompletion settings load/edit routines 191 | * Allow autocomplete to use: Bible or Bible book, current text file, only spell-checked words, external dictionary for language, external file, etc. 192 | * Write spell-checking routines (use Hunspell?) 193 | * Write syntax colouring routines 194 | * Project backup to the cloud (secure Freely-Given.org server) 195 | * Handle automatic (background) USFM syntax checking 196 | * Allow handling of non-English DBP resources 197 | * Think more about use of colour for distinguishing windows 198 | * Think more about window arranging 199 | * Make multiple Bible lexicon windows use the same (loaded) lexicon 200 | * Handle interlinear display (for original language resources) 201 | * Investigate integrating more online resources 202 | * From a Bible edit window, have a menu item to view the current chapter/section typeset on a page (pop-up window) 203 | * Improve the about page(s) 204 | * Learn how to install Biblelator on OS X 205 | * Create back-translation windows with special features 206 | * Allow more settings to be edited within the program (full settings editor) 207 | * Allow the short-cut keys to be edited within the program 208 | * Get full multiprocessing working 209 | * Make autocompletion aware of previous work and so adjust for context 210 | * Add progress bars for slow tasks 211 | * Add tooltips 212 | * Make proper user-adjustable (by dragging) toolbar(s) 213 | * Create an intelligent installer (also investigate Snap packaging) 214 | * Allow for secure automatic program updates (choice of stable and development branches) 215 | * Work on automated GUI testing 216 | * Release version 1.0 (BibleOrgSys versification systems have to be working first) 217 | * Handle team / collaborative issues 218 | * Think more about fonts and writing systems, special Unicode characters, etc. 219 | * Make checklists including all original verses containing numbers/people's names/locations/flora/fauna, etc. 220 | * Handle hyphenation 221 | * Handle draft printing / typesetting 222 | * Get it usable as a ESFM Bible editor 223 | * Work on scripting/macro language 224 | * Do NT/OT reference mode (Groups A/B work together) 225 | * Do synoptic gospel mode (Groups A/B/C/D work together) 226 | * Make a child window mode (all windows stay within the main window) 227 | * Allow remote management (i.e., admin automatic sends source updates to group) 228 | 229 | 230 | Jobs for others 231 | * Work on lists (Bible people, animals, birds, vegetation, etc., etc.) 232 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Biblelator 2 | ========== 3 | 4 | A (hackable) multi-window Bible editor written in Python with Tkinter. 5 | 6 | See https://Freely-Given.org/Software/Biblelator 7 | 8 | Biblelator was used daily by the developer as a production Bible editor for a few years 9 | from February 2016 as an alternative to Paratext for editing Paratext USFM Bible files 10 | (on Ubuntu Linux). 11 | The first alpha release (v0.30) was advertised in mid-March 2016. 12 | Now in 2022, development has restarted again with many more features to come 13 | and many early features to be further extended and polished. 14 | 15 | By including the Bible Organisational System (BibleOrgSys), Biblelator is able 16 | to display most unencrypted Bibles that you have on your computer as translation 17 | resources, and is also able to export Bibles into a large number of formats. 18 | 19 | No memory or speed optimisations have been applied to make Biblelator run more efficiently yet -- 20 | the focus is still on experimentation and adding features. 21 | 22 | One very annoying limitation is hard-coded paths for resources such as Hebrew and Greek lexicons. 23 | This will hopefully be addressed by the end of 2022. 24 | 25 | Some documentation can be found in the Documentation folder 26 | including DevelopmentPrinciples.md, Installation.md, GettingStarted.md, KeyboardShortcuts.md, 27 | and ForProgrammers.md. 28 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | """ 2 | A setuptools based setup module. 3 | 4 | See: 5 | https://packaging.python.org/guides/distributing-packages-using-setuptools/ 6 | https://github.com/pypa/sampleproject 7 | """ 8 | from setuptools import setup # Always prefer setuptools over distutils 9 | # from os import path 10 | 11 | VERSION = '0.0.9' 12 | LAST_MODIFIED_DATE = '2020-04-30' # by RJH — when setup.py was modified below 13 | 14 | 15 | # INCLUDE_DERIVED_DATA_PICKLE_FILES = True 16 | # INCLUDE_DERIVED_DATA_JSON_FILES = False 17 | 18 | 19 | # this_folderpath = path.abspath(path.dirname(__file__)) 20 | 21 | # Get the long description from the README file 22 | #with open(path.join(this_folderpath, 'README.md'), encoding='utf-8') as f: 23 | # long_description = f.read() 24 | 25 | 26 | package_data_list = [ 27 | 'DataFiles/Biblelator.gif', 'DataFiles/Biblelator.jpg', 28 | 'DataFiles/BiblelatorLogo.gif', 'DataFiles/BiblelatorLogoSmall.gif', 29 | ] 30 | # if INCLUDE_DERIVED_DATA_PICKLE_FILES: 31 | # package_data_list += [ 32 | # 'DataFiles/DerivedFiles/iso_639_3_Languages_Tables.pickle', 33 | # 'DataFiles/DerivedFiles/USFM2Markers_Tables.pickle', 34 | # ] 35 | # if INCLUDE_DERIVED_DATA_JSON_FILES: 36 | # package_data_list += [ 37 | # 'DataFiles/DerivedFiles/iso_639_3_Languages_Tables.json', 38 | # 'DataFiles/DerivedFiles/USFM2Markers_Tables.json', 39 | # ] 40 | 41 | 42 | setup( 43 | name='Biblelator', 44 | version=VERSION, 45 | 46 | packages=['Biblelator', 47 | 'Biblelator.Apps', 48 | 'Biblelator.Dialogs', 49 | 'Biblelator.Helpers', 50 | 'Biblelator.Settings', 51 | 'Biblelator.Windows', 52 | ], 53 | package_dir ={ 'Biblelator': 'Biblelator' }, 54 | package_data={ 'Biblelator': package_data_list }, 55 | 56 | # Although 'package_data' is the preferred approach, in some case you may 57 | # need to place data files outside of your packages. See: 58 | # http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files 59 | # 60 | # In this case, 'data_file' will be installed into '/my_data' 61 | # data_files=[('my_data', ['data/data_file'])], # Optional 62 | 63 | # metadata to display on PyPI 64 | # This should be your name or the name of the organization which owns the project. 65 | author="Robert Hunt", 66 | author_email="Freely.Given.org+Biblelator@gmail.com", 67 | 68 | # This is a one-line description or tagline of what your project does. This 69 | # corresponds to the "Summary" metadata field: 70 | # https://packaging.python.org/specifications/core-metadata/#summary 71 | description="Biblelator — experimental USFM Bible Editor", 72 | license='GPLv3', 73 | 74 | # This is an optional longer description of your project that represents 75 | # the body of text which users will see when they visit PyPI. 76 | # 77 | # Often, this is the same as your README, so you can just read it in from 78 | # that file directly (as we have already done above) 79 | # 80 | # This field corresponds to the "Description" metadata field: 81 | # https://packaging.python.org/specifications/core-metadata/#description-optional 82 | long_description=""" 83 | A USFM Bible editor using the [BibleOrgSys](https://pypi.org/project/BibleOrgSys/) 84 | library and Python's tKinter windowing library for simple and easy installation. 85 | (It's all in the standard CPython install.) 86 | 87 | On most systems, Biblelator can be installed (as shown above) with: 88 | 89 | `pip install Biblelator` 90 | 91 | but if it complains, maybe: 92 | 93 | `python3 -m pip install Biblelator` 94 | 95 | The app can be run from the command line with: 96 | 97 | `Biblelator` 98 | 99 | which should start up and display a smallish window, 100 | or to view all the available options: 101 | 102 | `Biblelator --help` 103 | 104 | You can discover the program version (doesn't match the package version) with: 105 | 106 | `Biblelator --version` 107 | 108 | Biblelator reads or creates a `BiblelatorData` folder in your home folder. 109 | Log files are stored in a subfolder there and may be useful for reporting errors. 110 | (If you have start-up problems, you might want to edit the settings there, 111 | or even delete the entire settings file if you have no complex saved windows settings yet.) 112 | 113 | Because some Bible users need to remain anonymous, Biblelator defaults to no internet use. 114 | However this reduces functionality, and most users will want to run the program once, 115 | and then close it and edit the `Biblelator.ini` file created in the `BiblelatorData/BiblelatorSettings` folder 116 | and change `internetAccess` to `Enabled`. 117 | While there, you might as well update the `currentUserName` and other entries 118 | under `[Users]`. 119 | 120 | The other auxilliary apps included are `BiblelatorSettingsEditor`, 121 | `BOSManager` (for inspecting Bible Organisational Systems), and 122 | `SwordManager` for viewing 123 | and downloading [Sword](https://crosswire.org/sword/index.jsp) modules. 124 | (All three are at various stages of incompleteness.) 125 | 126 | NOTE: This packaging is still being tested following massive restructuring, 127 | and is not necessarily fully functional until it is marked as v0.1.0 or higher 128 | when some open-licensed resources will also be downloadable. 129 | We also have hopes to improve documentation before v0.2.0. 130 | After that point, we also hope to release some prepackaged versions— 131 | probably including Docker and Snap. 132 | 133 | This software has been developed in very small chunks of spare time since 2013 134 | (so it's not necessarily well structured, and definitely not polished). 135 | However, it was used as my main Bible editor instead of Paratext 136 | for a couple of years. 137 | 138 | This package will not reach v1.0.0 until after the BibleOrgSys reaches it. 139 | The API will not become fixed/stable until the v1.0.0 release. 140 | 141 | No attempt at all has been made at memory or speed optimisations 142 | and this is not planned until after the release of v1.0.0. 143 | So if it becomes very slow, you might need to close some Bible resource windows. 144 | 145 | Biblelator is developed and tested on Linux (Ubuntu) but should also run on Windows and OS X (although not so well tested). 146 | 147 | See https://ubsicap.github.io/usfm/ for more information about USFM. 148 | """, 149 | # long_description=long_description, 150 | 151 | # Denotes that our long_description is in Markdown; valid values are 152 | # text/plain, text/x-rst, and text/markdown 153 | # 154 | # Optional if long_description is written in reStructuredText (rst) but 155 | # required for plain-text or Markdown; if unspecified, "applications should 156 | # attempt to render [the long_description] as text/x-rst; charset=UTF-8 and 157 | # fall back to text/plain if it is not valid rst" (see link below) 158 | # 159 | # This field corresponds to the "Description-Content-Type" metadata field: 160 | # https://packaging.python.org/specifications/core-metadata/#description-content-type-optional 161 | long_description_content_type='text/markdown', 162 | 163 | # This field adds keywords for your project which will appear on the 164 | # project page. What does your project relate to? 165 | # 166 | # Note that this is a string of words separated by whitespace, not a list. 167 | keywords="Bible Scripture translation editor USFM", 168 | 169 | # This should be a valid link to your project's main homepage. 170 | # 171 | # This field corresponds to the "Home-Page" metadata field: 172 | # https://packaging.python.org/specifications/core-metadata/#home-page-optional 173 | url="https://Freely-Given.org/Software/Biblelator/", 174 | 175 | # List additional URLs that are relevant to your project as a dict. 176 | # 177 | # This field corresponds to the "Project-URL" metadata fields: 178 | # https://packaging.python.org/specifications/core-metadata/#project-url-multiple-use 179 | # 180 | # Examples listed include a pattern for specifying where the package tracks 181 | # issues, where the source is hosted, where to say thanks to the package 182 | # maintainers, and where to support the project financially. The key is 183 | # what's used to render the link text on PyPI. 184 | #project_urls={ # Optional 185 | # 'Bug Reports': 'https://github.com/pypa/sampleproject/issues', 186 | # 'Funding': 'https://donate.pypi.org', 187 | # 'Say Thanks!': 'http://saythanks.io/to/example', 188 | # 'Source': 'https://github.com/pypa/sampleproject/', 189 | #}, 190 | project_urls={ 191 | #"Bug Tracker": "https://bugs.example.com/HelloWorld/", 192 | #"Documentation": "https://docs.example.com/HelloWorld/", 193 | "Source Code": "https://github.com/openscriptures/Biblelator/", 194 | }, 195 | 196 | # Classifiers help users find your project by categorizing it. 197 | # 198 | # For a list of valid classifiers, see https://pypi.org/classifiers/ 199 | classifiers=[ 200 | # How mature is this project? Common values are 201 | # 1 - Planning 202 | # 2 - Pre-Alpha 203 | # 3 - Alpha 204 | # 4 - Beta 205 | # 5 - Production/Stable 206 | 'Development Status :: 2 - Pre-Alpha', 207 | 208 | # Indicate who your project is intended for 209 | 'Intended Audience :: Developers', 210 | 'Intended Audience :: Religion', 211 | 'Topic :: Religion', 212 | 213 | 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', 214 | 215 | # Specify the Python versions you support here. In particular, ensure 216 | # that you indicate whether you support Python 2, Python 3 or both. 217 | # These classifiers are *not* checked by 'pip install'. See instead 218 | # 'python_requires' below. 219 | 'Programming Language :: Python :: 3.7', 220 | 'Programming Language :: Python :: 3.8', 221 | 222 | 'Operating System :: OS Independent', 223 | ], 224 | 225 | # Specify which Python versions you support. In contrast to the 226 | # 'Programming Language' classifiers above, 'pip install' will check this 227 | # and refuse to install the project if the version does not match. If you 228 | # do not support Python 2, you can simplify this to '>=3.5' or similar, see 229 | # https://packaging.python.org/guides/distributing-packages-using-setuptools/#python-requires 230 | python_requires='>=3.7', 231 | 232 | # This field lists other packages that your project depends on to run. 233 | # Any package you put here will be installed by pip when your project is 234 | # installed, so they must be valid existing projects. 235 | # 236 | # For an analysis of "install_requires" vs pip's requirements files see: 237 | # https://packaging.python.org/en/latest/requirements.html 238 | install_requires=['BibleOrgSys>=0.0.21'], 239 | 240 | # To provide executable scripts, use entry points in preference to the 241 | # "scripts" keyword. Entry points provide cross-platform support and allow 242 | # `pip` to create the appropriate form of executable for the target 243 | # platform. 244 | # 245 | # For example, the following would provide a command called `sample` which 246 | # executes the function `main` from this package when invoked: 247 | # entry_points={ # Optional 248 | # 'console_scripts': [ 249 | # 'sample=sample:main', 250 | # ], 251 | # }, 252 | entry_points={ 253 | 'console_scripts': [ 254 | 'Biblelator=Biblelator.Biblelator:run', 255 | 'BiblelatorSettingsEditor=Biblelator.Apps.BiblelatorSettingsEditor:run', 256 | 'BOSManager=Biblelator.Apps.BOSManager:run', 257 | 'SwordManager=Biblelator.Apps.SwordManager:run', 258 | ], 259 | }, 260 | ) 261 | --------------------------------------------------------------------------------