[jsword-devel] Design/Architecture of BibleDesktop
DM Smith
dmsmith555 at yahoo.com
Sat Jan 26 11:00:37 MST 2008
I've been asked to supplement the documentation of the Design and
Architecture of JSword (former thread at:
http://www.crosswire.org/pipermail/jsword-devel/2006-April/001954.html)
with that of BibleDesktop. Ideally, both of these should be put on the
website and not buried in a post.
BibleDesktop is best described top-down.
First, the relationship between Common, Common-Swing, JSword, and
BibleDesktop.
Common defines general purpose routines that can be used by any program.
They are directly used by the three other parts.
Common-swing defines general purpose "Java swing" code that can be used
by any program.
Neither Common or Common-swing are frameworks.
JSword is a framework that defines how to work with books. It is a
pluggable model and at this time, it supports Sword modules. It could
also support any other kind of module (e.g. STEP, eSword), if plugins
were written for these.
The program starts with org.crosswire.bibledesktop.desktop.Desktop (aka
o.c.b.desktop.Desktop or o.c.b.d.Desktop) which initializes the program.
The steps in initialization reflect the overall design and architecture
of the program, so they will be discussed in order.
BibleDesktop is governed by o.c.jsword.util.Project, which determines
the "home" directories of JSword. These directories are:
1) The default location of Sword resources, e.g. where modules should be
downloaded.
2) The location of JSword resources, i.e. various pieces of saved state.
3) All the possible locations of Sword modules. (This can get in your
way if you are developing modules and JSword sees
The location of these directories are platform dependent and vary across
Unix, Windows and Mac.
These directories are critical in the resource model that looks up
resources. For a description of the resource model, see the thread:
http://www.crosswire.org/pipermail/jsword-devel/2006-August/001997.html.
The next thing that BibleDesktop does is establish the Locale for the
program. Java by default will set the Locale to what it thinks is best
for the user. This may not be appropriate. BibleDesktop allows a user to
change this to any of the supported translations of BibleDesktop. The
setting of the locale has to be done before any other resources are
looked up.
At this point we know which splash screen to use and it is put up using
o.c.b.d.Splash. This is done at the earliest possible time so that the
user can know that the program is starting up and that it is making
progress toward it's goal of showing the main screen. The splash screen
is timed on the assumption that the application will show within that
time. The splash is dismissed on timeout, on user click and upon the
desktop being shown.
Once the proper locale is obtained, the user's preferences are read in.
This can be improved as at this time, we read in the catalog of
installed books to determine which should be put into the drop-downs in
the options dialog.
While it can be done earlier the rest of error management is set up.
Error management is done by reporting errors with o.c.c.u.Reporter. This
will report o.c.c.u.ReporterEvents to o.c.c.u.ReporterListerers. One
such listener is o.c.c.swing.ExceptionPane, used by BibleDesktop to show
exceptions.
On the topic of error management, BibleDesktop and JSword use a logging
mechanism, o.c.c.u.Logger to do all logging. We could use Java's logging
or another logging facility directly, but this lets us swap out
implementations fairly easily. Though it could be even easier with a
plug-in model.
We avoid writing to standard out and standard error as much as possible.
If these are found in the code, they are generally debug statements
which should be migrated to Logger.
With regard to this we try to have every message that goes through these
two mechanisms use strings defined in property files. We do this
through a class called o.c.c.u.MsgBase, from which we derive a Msg class
in nearly every package. We also use the Msg class for labels that are
shown in the GUI. This is a problem for translators, because it does not
separate what must be translated (i.e. the GUI) from what can probably
be skipped. It also does not distinguish between errors that the user
can cause (e.g. entering a badly formed Bible reference) and ones that
are programming errors (e.g. "Stupid programmer's error. Should never
get here!") This should be improved.
After that, a o.c.common.progress.Job is started to communicate to the
user what is going on. Jobs are background, threaded processes that
communicate with o.c.c.p.WorkListener of which Splash is one. There are
two types of Jobs, determinate and indeterminate. Determinate knows the
size of the job that need to be done and can measure progress toward the
goal. Indeterminate, which is most often used in BibleDesktop, guesses
at the progress the first time and then uses the length of time for the
last run to predict the next. One place that indeterminate is used that
is inappropriate is the downloading of modules. It should be based upon
the size of the module, which can vary widely.
Jobs are the mechanism in BibleDesktop to do things in the background so
that the user interface can keep refreshed and allow the user to do
other things. One place where it is not used but could be is in the
reading of a Dictionary's entries. Loading Webster's Dictionary makes
the program seem like it is hanging. Jobs don't need to be tied to a
o.c.c.swing.progress.JobsProgressBar, but it is preferable to let the
user know what is going on.
After setting up the job, o.c.b.d.DesktopActions is instantiated.
DesktopActions is the heart of user interaction in BibleDesktop. Nearly
every thing that can be done in the main screen goes through here.
DesktopActions used to be part of Desktop, but was broken out merely to
minimize file size and to have setup of BD in Desktop and the actual
work in DesktopActions. One of the strengths of Java is it's Action
model, where an action can be tied to one or more widgets. When a widget
is tickled, it activates ActionListeners tied to the Action. We define
o.c.c.u.CWActions within o.c.b.d.Desktop.properties, with each behavior
having multiple entries. This file has a complete definition of each of
the entries that define an action. We have extended this a bit further
with a bit of Java's reflection via o.c.c.u.ActionFactory, such that if
there is a File action defined in the properties file, then there must
be a corresponding doFile(...) and reflection ties the two together.
Generally, each screen in BibleDesktop follows this pattern.
This simplifies adding new behavior. One merely adds a behavior to an
*Action.properties and then adds a doNewBehavior(...) to the implementor
of ActionFactory.
One shortcoming of this is that a button cannot be used for two
different purposes. For example, if *Action.properties defines an OK
CWAction, then all instances of it are tied. It would be very nice to be
able to share some definitions, but not tie them together. (Peter and
other translators would love this! and perhaps it ought to be entered
into our issues db at www.crosswire.org/bugs under Common)
Desktop next sets up the GUI. This is split between generateComponents()
and init(), though there is little value in having these as two separate
methods, if any.
On the bottom of the screen is a o.c.b.d.StatusBar, which contains a
message area, a progress area which can show the progress of all the
jobs executing at the same time, and in the far right an area that shows
the version number of BD. BibleDesktop allows the user to hide the
status area. One needed improvement is that when it is hidden then any
jobs that are in progress should probably pop up a dialog box showing
the progress of all jobs.
On the top of the Desktop screen is a JMenuBar (except on Mac where it
shows on the top of the monitor). This always shows.
Below the menu bar (or at the top of the Desktop screen on the Mac), a
o.c.c.swing.ToolBar is shown. This extends JToolBar with a few
behaviors. This tool bar can be hidden by the user. The content of the
toolbar is hard coded in BD. It would be nice to allow the user to put
any button of their choice on it.
On the right side of the screen is o.c.b.book.MultiBookPane, which is a
vertical presentation of all non-Bible books. At the top is a selector
of books. In the middle is a picker appropriate for the type of the book
and at the bottom is a display of what has been picked.
On the left side of the screen, is the o.c.c.swing.desktop.ViewManager.
The ViewManager allows the flipping between a tabbed set of
o.c.b.b.BibleViewPanes and a multi-windowed view. I think the
multi-windowed view is needed a lot less now that BibleDesktop allows
parallel viewing of Bible passages.
The BibleViewPane consists of a o.c.b.passage.KeySidebar, which is
hidden by default. The KeySidebar show the list of passages currently
being shown in the BibleViewPane and allows one to add 1 or 5 verses to
both sides of each passage, or to delete a passage from view. This is
especially handy after a search to prune hits that do not match one's
goal for the search and to expand the context of particular passages to
see the full contextual meaning of a verse.
At the top of the BibleViewPane is o.c.b.book.DisplaySelectPane, which
allows a user
* to choose one or more Bibles with o.c.b.b.ParallelBookPicker
* to quickly pick a book and chapter using o.c.b.b.BibleComboBoxModelSet
* to enter a range of passages to lookup (JTextField)
* to search a Lucene index. This displays either a button to create an
index or enter a search.
To the right of the lookup is a button that will bring up a
o.c.b.b.PassageSelectPane, a tree view of Book, Chapter and Verse that
allows one to quickly create a passage selection without typing.
And right of search is a button that will bring up
o.c.b.b.AdvancedSearchPane, which is the only way to do a ranked search,
but is otherwise used to learn how to write searches using the advanced
search capabilities of JSword.
At the bottom of the BibleViewPane is a
o.c.b.display.basic.TabbedBookDataDisplay. The TabbedBookDataDisplay is
a bottom tabbed display of Bible verses. When ever there are more than a
user configurable number of verses to display, a "More..." tab is show
to the right of the current tab. Clicking on the More... tab will fetch
the next x verses and if there are more remaining, a new More... tab is
shown. The splitting up of verses needs to be improved. It sometimes
will break at the most unfortunate places. The purpose of the tabs is to
manage performance.
The actual display of Book content is handled by
o.c.b.display.basic.TextPaneBookDataDisplay. This is set up as a HTML
viewer. Java's ability to display HTML is very poor. We would like to
replace this with an OS dependent Web Browser (i.e. FireFox, IE, Safari,
...). This is the major reason that we are looking at rewriting
BibleDesktop with Eclipse's SWT/JFace/RCP. There is a prototype of the
start of this.
When JSword is requested for the contents of a set of passages it will
return an OSIS document regardless of the actual module's
representation. BibleDesktop then uses o.c.b.d.XSLTProperties to
remember the user's preferences on showing the passage and to pass it as
properties to the process that transforms the OSIS to HTML. The HTML is
then passed to the display. All this is contained in
TextPaneBookDataDisplay.refresh().
Well that's about it. Digging into the code should fill in the gaps. If
there is something missing that should be added please point it out.
In His Service,
DM Smith
More information about the jsword-devel
mailing list