Gtk2-Ex-DBI
view release on metacpan or search on metacpan
lib/Gtk2/Ex/DBI.pm view on Meta::CPAN
}
$self->{read_only} = TRUE;
}
} else {
while ( my $column_info_row = $sth->fetchrow_hashref ) {
# Loop through the list of columns from the database, and
# add only columns that we're actually dealing with
for my $fieldname ( keys %{$self->{sql_to_widget_map}} ) {
if ( $column_info_row->{COLUMN_NAME} eq ( $fieldname ) ) {
# Note that we want to store this against the fieldname and NOT the sql_fieldname
$self->{column_info}->{ $self->{sql_to_widget_map}->{$fieldname} } = $column_info_row;
last;
}
}
}
}
# Make sure we've got the primary key in the widgets hash and the sql_to_widget_map hash
# It will NOT be here unless it's been specified in the SQL select string or the widgets hash already
# Note that we test the sql_to_widget_map, and NOT the widgets hash, as we don't know what
# the widget might be called, but we DO know what the name of the key in the sql_to_widget_map
# should be
foreach my $primary_key ( @{$self->{primary_keys}} ) {
if ( ! exists $self->{sql_to_widget_map}->{ $primary_key } ) {
$self->{widgets}->{ $primary_key } = {};
$self->{sql_to_widget_map}->{ $primary_key } = $primary_key;
}
if ( $self->{dont_update_keys} ) {
$self->{widgets}->{ $primary_key }->{dont_update} = 1;
}
}
# If things failed above, we mightn't have a $sth to finish, so
# check we do first ...
if ( $sth ) {
$sth->finish;
}
if ( ! $self->{skip_query} ) {
$self->query;
}
# We connect a few little goodies to various widgets ...
# - Connect our 'changed' method to whatever signal each widget emits when it's 'changed'
# - Gtk's ComboBoxEntry has a bug where it only registers a change and set's the currect iter if
# the combo box functionality is used. If the Entry functionality is used ( ie someone types a
# string that matches one in the list ), NOTHING is registered, and the active iter is not set.
# We *NEED* to work around this until the bug is fixed, otherwise ComboBoxEntrys are horribly broken.
# Therefore we connect the sub set_active_iter_for_broken_combo_box to the on_focus_out event.
# See http://bugzilla.gnome.org/show_bug.cgi?id=156017
# Note that while the above bug page shows this bug as being 'FIXED', I've yet to see this
# fix materialise in Gtk2 - when it does I will limit our work-around to those affected
# versions of Gtk2.
# - Use the populate-popup signal of Gtk2::Entry widgets to add the 'find' menu item
# - Connect to the 'key-press-event' signal of various widgets to move the focus along
# ( ie as if the TAB key was pressed )
# We also keep an array of widgets and signal ids so that we can disconnect all signal handlers
# and cleanly destroy ourselves when requested
# We also set up input / output formatters based on widget ( ie $self->{widgets} )
# Set up some defaults for different widget types
foreach my $fieldname ( keys %{$self->{widgets}} ) {
# Get hold of the widget def ...
my $widget_def = $self->{widgets}->{$fieldname};
if ( exists $widget_def->{number} ) {
# Properties of the number format:
# - decimals - number of decimal places
# - decimal_fill - whether to pad decimals out to the number of decimals
# - separate_thousands - whether to separate thousands groups with a comma
# - currency - whether to apply currency formatting
# Set some defaults for properties that haven't been specified ...
if ( ! exists $widget_def->{number}->{decimal_fill} ) {
$widget_def->{number}->{decimal_fill} = TRUE;
}
if ( ! exists $widget_def->{number}->{separate_thousands} ) {
$widget_def->{number}->{separate_thousands} = TRUE;
}
# If this is a currency widget, default to 2 decial places
if ( exists $widget_def->{currency} && $widget_def->{currency} && ! exists $widget_def->{number}->{decimals} ) {
$widget_def->{number}->{decimals} = 2;
}
}
my @widgets;
my $this_widget = $self->get_widget( $fieldname );
if ( $this_widget ) {
push @widgets, $this_widget;
} else {
# TODO Remove dodgy split-widget support and replace with custom widgets
# Check for split-widget widgets ... at present, TimeSpinners
foreach my $type qw / hh mm ss / {
$this_widget = $self->get_widget( $fieldname . "_" . $type );
if ( $this_widget ) {
push @widgets, $this_widget;
}
}
}
lib/Gtk2/Ex/DBI.pm view on Meta::CPAN
push @signals, $widget->signal_connect_after(
toggled => sub { $self->changed( $fieldname ) } );
} elsif ( $type eq "Gtk2::TextView" ) {
# In this case, we don't connect to the widget, but to the widget's buffer ...
# ... so we swap the buffer into $widget, so we can disconnect our signal later
$widget = $widget->get_buffer;
push @signals, $widget->signal_connect_after(
changed => sub { $self->changed( $fieldname ) } );
} elsif ( $type eq "Gtk2::ComboBoxEntry" ) {
push @signals, $widget->signal_connect_after(
changed => sub { $self->changed( $fieldname ) } );
# Append our work-around for broken combo directly to the objects_and_signals array ...
# ... We can't use the code below to append more than 1 widget at a time
my $child_widget = $widget->get_child;
my $signal = $child_widget->signal_connect_after(
changed => sub { $self->set_active_iter_for_broken_combo_box($widget) } );
if ( $self->{debug} ) {
warn "Remembering object / signal pair for later disconnection ...\n"
. " Field: $fieldname\n"
. " Widget: $child_widget\n"
. " Signal: $signal\n\n";
}
push @{$self->{objects_and_signals}},
[
$child_widget,
$signal
];
# Trigger 2 tab-forward events;
# 1 to get to the combo part ( ie the child's parent widget )
# and 1 to get to the next widget
$signal = $child_widget->signal_connect(
'activate' => sub {
$self->{window}->child_focus('tab-forward');
$self->{window}->child_focus('tab-forward');
} );
if ( $self->{debug} ) {
warn "Remembering object / signal pair for later disconnection ...\n"
. " Field: $fieldname\n"
. " Widget: $child_widget\n"
. " Signal: $signal\n\n";
}
push @{$self->{objects_and_signals}},
[
$child_widget,
$signal
];
# We also want a right-click menu for a Combo's child ( entry )
$signal = $child_widget->signal_connect_after(
'populate-popup' => sub { $self->build_right_click_menu(@_) } );
if ( $self->{debug} ) {
warn "Remembering object / signal pair for later disconnection ...\n"
. " Field: $fieldname\n"
. " Widget: $child_widget\n"
. " Signal: $signal\n\n";
}
push @{$self->{objects_and_signals}},
[
$child_widget,
$signal
];
} elsif ( $type eq "Gtk2::CheckButton" ) {
push @signals, $widget->signal_connect_after(
toggled => sub { $self->changed( $fieldname ) } );
} elsif ( $type eq "Gtk2::Entry" ) {
push @signals, $widget->signal_connect_after(
changed => sub { $self->changed( $fieldname ) } );
push @signals, $widget->signal_connect_after(
'populate-popup' => sub { $self->build_right_click_menu(@_) } );
push @signals, $widget->signal_connect(
'activate' => sub { $self->{window}->child_focus('tab-forward') } );
} elsif ( $type eq "Gtk2::SpinButton" ) {
push @signals, $widget->signal_connect_after(
changed => sub { $self->changed( $fieldname ) } );
push @signals, $widget->signal_connect_after(
'populate-popup' => sub { $self->build_right_click_menu(@_) } );
push @signals, $widget->signal_connect(
'key-press-event' => sub { $self->process_entry_keypress(@_) } );
} else {
push @signals, $widget->signal_connect_after(
changed => sub { $self->changed( $fieldname ) } );
}
# ... and then warn() some info about what we're doing, and also append
# the objects and signals to the *real* list
foreach my $signal ( @signals ) {
if ( $self->{debug} ) {
warn "Remembering object / signal pair for later disconnection ...\n"
. " Field: $fieldname\n"
. " Widget: $widget\n"
. " Signal: $signal\n\n";
}
push @{$self->{objects_and_signals}},
[
$widget,
$signal
];
}
}
}
$self->{spinner} = $self->get_widget( $self->{record_spinner} );
if ( $self->{spinner} ) {
$self->{record_spinner_value_changed_signal}
= $self->{spinner}->signal_connect_after( value_changed => sub {
$self->{spinner}->signal_handler_block( $self->{record_spinner_value_changed_signal} );
$self->move( undef, $self->{spinner}->get_text - 1 );
$self->{spinner}->signal_handler_unblock( $self->{record_spinner_value_changed_signal} );
return TRUE;
}
);
push @{$self->{objects_and_signals}},
[
$self->{spinner},
$self->{record_spinner_value_changed_signal}
];
}
# Check recordset status when window is destroyed
push @{$self->{objects_and_signals}},
[
$self->{window},
$self->{window}->signal_connect( delete_event => sub {
if ( $self->{changed} ) {
my $answer = TRUE;
if ( ! $self->{auto_apply} ) {
my $answer = Gtk2::Ex::Dialogs::Question->new_and_run(
title => "Apply changes to " . $self->{friendly_table_name} . " before closing?",
icon => "question",
text => $self->{custom_changed_text} ? $self->{custom_changed_text} :
( run in 0.695 second using v1.01-cache-2.11-cpan-364913b4093 )