math-image
view release on metacpan or search on metacpan
lib/App/MathImage/Gtk2/PodDialog.pm view on Meta::CPAN
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 3, or (at your option) any later
# version.
#
# Math-Image is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with Math-Image. If not, see <http://www.gnu.org/licenses/>.
package App::MathImage::Gtk2::PodDialog;
use 5.008;
use strict;
use warnings;
use FindBin;
use Glib 1.220; # for Glib::SOURCE_REMOVE and probably more
use Gtk2 1.200; # for Gtk2::GTK_PRIORITY_RESIZE and probably more
use Gtk2::Ex::PodViewer;
use Gtk2::Ex::WidgetCursor;
use Gtk2::Ex::Units;
use Module::Util;
use Locale::TextDomain ('Math-Image');
use App::MathImage::Generator;
# uncomment this to run the ### lines
#use Smart::Comments;
our $VERSION = 110;
use Glib::Object::Subclass 'Gtk2::Dialog',
properties => [
Glib::ParamSpec->string
('pod',
'POD',
'Blurb.',
$FindBin::Script,
Glib::G_PARAM_READWRITE),
];
sub INIT_INSTANCE {
my ($self) = @_;
{
my $title = __('POD Documentation');
if (defined (my $appname = Glib::get_application_name())) {
$title = "$appname: $title";
}
$self->set_title ($title);
}
# connect to self instead of a class handler since as of Gtk2-Perl 1.200 a
# Gtk2::Dialog class handler for 'response' is called with response IDs as
# numbers, not enum strings like 'accept'
$self->signal_connect (response => \&_do_response);
my $vbox = $self->vbox;
my $combobox = $self->{'combobox'} = Gtk2::ComboBox->new_text;
$combobox->append_text ($FindBin::Script);
foreach my $name (App::MathImage::Generator->path_choices) {
$combobox->append_text ($name);
}
foreach my $name (App::MathImage::Generator->values_choices) {
$combobox->append_text ($name);
}
if (defined (Module::Util::find_installed('Math::Aronson'))) {
$combobox->append_text ('Math::Aronson');
}
$combobox->append_text ('Math::Symbolic');
$combobox->append_text ('Math::Expression::Evaluator');
$combobox->set_active (0);
$combobox->signal_connect (changed => \&_do_combo_changed);
my $action_hbox = $self->get_action_area;
$action_hbox->pack_start ($combobox, 0,0,0);
$self->add_buttons ('gtk-close' => 'cancel');
my $scrolled = Gtk2::ScrolledWindow->new;
$scrolled->set_policy ('never', 'always');
$vbox->pack_start ($scrolled, 1,1,0);
my $viewer = $self->{'viewer'} = Gtk2::Ex::PodViewer->new;
$viewer->signal_connect (link_clicked => \&_do_viewer_link_clicked);
$scrolled->add ($viewer);
Gtk2::Ex::Units::set_default_size_with_subsizes
($self, [ $vbox, '60 ems', '35 lines' ]);
$self->show_all;
### default size: $self->get_default_size
# WidgetCursor doesn't work due to explicit set_cursor() in PodViewer
$self->{'cursor'} = Gtk2::Ex::WidgetCursor->new (widget => $self,
cursor => 'watch',
include_children => 1,
priority => 10,
active => 1);
Scalar::Util::weaken (my $weak_self = $self);
Glib::Idle->add (\&_do_idle, \$weak_self,
Gtk2::GTK_PRIORITY_RESIZE() + 10); # low priority
# Glib::Timeout->add (3000, \&_do_idle, \$weak_self,
# Gtk2::GTK_PRIORITY_RESIZE() + 10);
}
sub GET_PROPERTY {
my ($self, $pspec) = @_;
my $pname = $pspec->get_name;
if ($pname eq 'pod') {
return $self->{'combobox'}->get_active_text;
} else {
return $self->{$pname};
}
}
sub SET_PROPERTY {
my ($self, $pspec, $newval) = @_;
my $pname = $pspec->get_name;
if ($pname eq 'pod') {
if (! defined $newval) {
$newval = $pspec->get_default_value;
}
return Gtk2::Ex::ComboBoxBits::set_active_text
($self->{'combobox'}, $newval);
} else {
$self->{$pname} = $newval;
}
}
sub _do_idle {
my ($ref_weak_self) = @_;
if (my $self = $$ref_weak_self) {
_do_combo_changed ($self->{'combobox'});
delete $self->{'cursor'};
}
return Glib::SOURCE_REMOVE; # once only
}
sub _do_response {
my ($self, $response) = @_;
if ($response eq 'cancel') {
# "Close" button gives GTK_RESPONSE_CANCEL.
# Emit 'close' same as a keyboard Esc to close, and that signal defaults
# to raising 'delete-event', which in turn defaults to a destroy
$self->signal_emit ('close');
}
}
sub _do_combo_changed {
my ($combobox) = @_;
my $self = $combobox->get_ancestor(__PACKAGE__) || return;
my $filename;
my $name = $combobox->get_active_text;
if ($combobox->get_active == 0) {
$filename = "$FindBin::Bin/$name";
} elsif ($name) {
$name =~ s/-/::/g;
if ($name =~ /::/) {
$filename = Module::Util::find_installed ($name);
} else {
if (my $module = App::MathImage::Generator->path_choice_to_class($name)
|| App::MathImage::Generator->values_choice_to_class($name)) {
$filename = Module::Util::find_installed ($module);
}
}
}
### $filename
my $viewer = $self->{'viewer'};
if (! (defined $filename
&& defined ($viewer->load_file ($filename)) # successful load
&& $viewer->get_buffer->get_char_count)) { # and not empty
_empty ($viewer, $name);
}
$self->notify('pod');
}
sub _do_viewer_link_clicked {
my ($viewer, $target) = @_;
### _do_viewer_link_clicked(): $target
Gtk2::Ex::WidgetCursor->busy;
($target, my $section) = split(/\//, $target, 2);
if ($target) {
my $loaded;
if (eval { require Pod::Simple::Search }
&& (my $filename = Pod::Simple::Search->new->find($target))) {
$loaded = $viewer->load_file ($filename);
} else {
$loaded = $viewer->load ($target);
}
(defined $loaded
&& $viewer->get_buffer->get_char_count)
or _empty ($viewer, $target);
}
$section = lc($section);
foreach my $mark_name ($viewer->get_marks) {
### $mark_name
$mark_name =~ s/^[\"\']|[\"\']$//g; # no quotes
if (lc($mark_name) eq $section) {
$viewer->scroll_to_mark ($viewer->get_mark ($mark_name),
0, # within_margin
1, # use_align
0, # xalign, left of window
.05); # yalign, just below top of screen
last;
}
}
}
sub _empty {
my ($viewer, $target) = @_;
my $textbuf = $viewer->get_buffer;
$textbuf->delete ($textbuf->get_start_iter, $textbuf->get_end_iter);
( run in 0.552 second using v1.01-cache-2.11-cpan-59e3e3084b8 )