RFC: refactoring window-register as widget-register + containing window

Josh Sled jsled@asynchronous.org
Thu, 22 Nov 2001 15:14:19 -0800


I'm attempting to fix something that came up earlier in the course
of Scheduled Transaction UI development... where I needed to
cut-and-paste a bunch of code from src/gnome/window-register.c into
dialog-scheduledxaction.c to get a register in the SX Editor.  I decided
at the time that that was a to-be-short-term-lived hack to see if/how
it all worked, and that something like this would be necessary, later.
Now, as the SX since-last-run dialog wants two more "embedded" registers,
it seems like time to do it.

As this is a fairly major change, I'd like input before proceeding
much further [i.e., actually making the changes], and definitely before
committing back.

...jsled


RFC:
Refactoring window-register into a composite widget and containing window.

Overview
--------

The Scheduled Transaction functionality desires to have multiple instances of
the register available for its UI [SX editing of template transactions and
review of created transactions in the since-last-run Druid].  For end-user
convenience, these instances should look-n-feel as close to the
window-register [src/gnome/window-register.c] as is possible.

More specifically, there are four generically-useful bits in
window-register.c:

. the ledger_display itself
. the toolbar
. the popup menu
. the status bar

These UI elts are configured in static functions in window-register.c, and
their callbacks are also static, leading to cut-and-paste for anyone else who
wants to use the register + toolbar + popup + statusbar... and even more
cut-n-paste to get the same behavior from the various toolbar buttons and
popup-menu-items.

Proposal
--------

I propose that these UI elts be brought out in a register composite widget
[widget-register].  This widget would be a vbox which would contain the four
widgets: toolbar, ledger_display, status bar and popup menu.

[ I now utilize a distinction between the "window-register" [the existing
  register in src/gnome/window-register.c] and "widget-register" [the
  to-be-created register composite widget. ]

Each of the widget-register's contained UI sub-elts is exposed to the caller
for modification; for instance, the window-register itself adds the following
toolbar actions:

. close

. transfer
. find
. report
. print

The popup menu, as well, will perhaps want to be modified by the caller; in
the SX Editor, there is no menubar on the dialog... thus there is no menu bar
for the actions which are currently in the window-register's Register, Edit
and Transaction menus.  A subset of the menu options provided by the
window-register [such as modifying the display style, exposing cut/paste
functionality] should be provided by the context/popup menu, or perhaps in
the toolbar... but in any case, the caller will want to modify the existing
menus where necessary to provide all appropriate functionality.


This code would live in src/gnome-util/gnc-regwidget.[ch], with functions
prefixed with "gnc_regwidget_".

Supported
---------

Looking at the window-register, there is a bunch of functionality present;
looking at my initial cut-n-paste of [a subset of] the window-register.c code
into the SX Editor, only some of this functionality was transfered over.
Specifically, the widget-register should support:

. Creation, by passing in the display_ledger to use, already configured
  for/with the appropriate type/Query.

[ These are the common actions between the toolbar and popup menu... more
  importantly, they seem "common" to both uses of the register. ]
. Enter
. Cancel
. Delete
. Duplicate
. Schedule
. Split
. Blank
. Jump
. Transfer

. Style options
  . Basic, Auto, Journal
  . Double-line

. Copy [split | txn]
. Cut [split | txn]
. Paste [split | txn]

Unsupported
-----------

The following functionality will be supported by the caller, if necessary
[read: the window-register will support these, as the SX-based callers won't
use it]

. Sorting
. Date-range selection
. Account editing/creation
. Check/repair
. Find
. Report
. Print
. Invoice
. Stock splitting
. Reconciliation

Functionality Vector
--------------------

A goal of this effort is consistency: the user has experience with the
window-register, and has created a mental map of actions and effects [and if
they haven't, it will retard that map creation by having multiple different
registers in different parts of the program].  Thus, the set of functionality
that the widget-register supports should be configurable in such a way that
not-available items ["Schedule..." while editing a Scheduled Transaction's
template-transaction] are not removed, but only grayed out.

This shall be done with a bitmask to be passed into the widget-register,
specifying which functionality to turn off.  Functionality which is turned
off is left visually in place, but set to be insensitive, and thus the
callbacks are not able to be invoked.  Probably the right thing, then, to do
is not attach the callbacks at all.

Handling Actions
----------------

Presently, the window-register directly attaches callbacks for the
clicked/activated signals of the widgets it creates.  However, this is
problematic in the widget-register case as the widget-register will create
the widgets, and the caller will want to attach the signals.

One option is to provide accessors for all of the sub-widgets to the caller,
but this assumes that all callers have a bit too much knowledge about how the
widget-register is working.

Thus, the widget-register will emit the following signals on sub-widget
activation, and the widget-register itself can be the object-of-attachment
for all the caller's event-handling purposes:

. "enter_txn"
. "cancel_txn"
. "delete_txn" [?]
. "duplicate_txn"
. "schedule_txn"
. "show_split_req"
. "jump_to_blank"
. "jump_to_acct"
. "transfer"

. "cut_split", "cut_txn"
. "copy_split", "copy_txn"
. "paste_split", "paste_txn"

. "style_change"

These signals will be attached-to by default handlers [provided by the
widget-register]... however, these default signal-handlers will be set to be
handled last, iff any later-attached signal handlers allow them to run [via
return status].

This will entail certain changes in how the caller[s] function.  Presently,
for instance, the window-register attaches the same callback [recordCB] to
both the "Enter" option in the popup menu and the 'Transaction | Enter'
window-menu item.  This, in turn, calls gnc_register_enter, which does some
register manip.

Now, with widget-register, the window-register could still create a
'Transaction | Enter' menu item, but the callback would instead force the
widget-register to emit the "enter_txn" signal, which would trigger the same
code, now provided by the widget-register.  If the window-register had added
another callback, it would be invoked first, perhaps blocking the invocation
of the "standard" "enter_txn" signal-handler.

Unknown/Questions
-----------------

. Gnome Dock stuff

  . The window-register makes use of the GnomeDock for the menu, toolbar and
  summarybar... I guess this can be the case for the widget-register as well,
  but it doesn't seem quite right; the caller probably wants to retain
  control about how all that is used.

. Functionality Vector

  . This seems to me like the right thing; we don't want the "Schedule"
  option to be available in the SX editor, but we don't want it to just
  disappear... is there a better way of spec'ing what features
  should/shouldn't be supported by the resulting widget-register?

  . Another option would be to ignore the functionality vector, create a
  widget-register, then go through and set_sensitive( FALSE ) the appropriate
  widgets.

. Signal/handler policy a good idea?

  . I'm not sure this _quite_ works.  The intent is to minimize the work that
  the callers have to [re-]do in order to get the "standard" register into
  their UI.  However, let's take the case of the "Duplicate" button.  In the
  SX Editor, clicking the duplicate button seems to work, except both the
  Date and Num that it asks for from the user are irrelevant to
  template-transaction editing.  After that, only the split memos are
  duplicated, as the accounts and credit/debit formulas are in
  kvp-frames... so this seems like something that would need to be re-written
  anyways...  OTOH, enter, cancel, blank [presumably cut, copy, paste], work
  fine with no re-writing.

. Menus/Toolbars

  . There's a pretty compelling argument which says that the different menus
  [both the containing-window menus and the popup menu] should be as common
  as possible, both in display and code/data-structures... do we want to have
  some way assisting in this?  Perhaps the caller can ask the widget-register
  for a menu, which is can then modify and place in it's own menubar?

. Vbox usage [Present/Future/Cleared/Reconciled bar] cleanliness

  . The window-register will want to add other UI elts [such as the
  Preset/Future/Cleared/Reconciled label bar] ... is there a cleaner way
  of doing this than gtk_box-inserting the new widgets at the right places?

. Status bar

  . The caller may want to re-place the summarybar at a different location,
  but the widget-register still needs to update it; this shouldn't be a
  problem.

  . If the caller wants a different interface than the status bar, that's
  more problematic...

Looks Like...
-------------

A quick example:

GNCLedgerDisplay *gnc_regwidget_get_ledger_display( GNCRegWidget* );
/* should these be gncUIWidget*s? */
GtkWidget *gnc_regwidget_get_toolbar( GNCRegWidget* );
GtkWidget *gnc_regwidget_get_statusbar( GNCRegWidget* );
GtkWidget *gnc_regwidget_get_popup_menu( GNCRegWidget* );

/* [maybe, as per "Menus/Toolbars" comment above.]
 * If m is non-null, appends elts ["enter", "cancel", "delete", <divider>,
 * "duplicate"...] otherwise, creates a new GtkMenu.
 *  Returns either m or the new GtkMenu.
 */
GtkWidget *gnc_regwidget_get_menu( GNCRegWidget*, GtkWidget *m );

/***** signal-handler prototypes *****/

gboolean (*enter_txn_cb_fn)( GNCRegWidget*, gpointer user_data );
gboolean (*cancel_txn_cb_fn)( GNCRegWidget*, gpointer user_data );
gboolean (*delete_tnx_cb_fn)( GNCRegWidget*, gpointer user_data );
gboolean (*dup_txn_cb_fn)( GNCRegWidget*, gpointer user_data );
gboolean (*sched_txn_cb_fn)( GNCRegWidget*, gpointer user_data );
/* "show_split_req" signal
 * Though thinking about it, this will either be on or off [depending on how
 * authoritarian the caller is being about display-control, and it should
 * never need to be over-ridden. */
gboolean (*show_split_cb_fn)( GNCRegWidget*, gpointer user_data );
gboolean (*jump_to_blank_cb_fn)( GNCRegWidget*, gpointer user_data );
gboolean (*jump_to_acct_cb_fn)( GNCRegWidget*, gpointer user_data );
gboolean (*transfer_cb_fn)( GNCRegWidget*, gpointer user_data );

gboolean (*cut_split_cb_fn)( GNCRegWidget*, gpointer user_data );
gboolean (*cut_txn_cb_fn)( GNCRegWidget*, gpointer user_data );
gboolean (*copy_split_cb_fn)( GNCRegWidget*, gpointer user_data );
gboolean (*copy_txn_cb_fn)( GNCRegWidget*, gpointer user_data );
gboolean (*paste_split_cb_fn)( GNCRegWidget*, gpointer user_data );
gboolean (*paste_txn_cb_fn)( GNCRegWidget*, gpointer user_data );

gboolean (*style_change_cb_fn)( GNCRegWidget*,
                                style_type_t t,
                                gpointer user_data );