#!/usr/bin/perl
#
# Copyright (c) 2003 by Emmanuele Bassi (see the file AUTHORS)
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library 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
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public
# License along with this library; if not, see
# <https://www.gnu.org/licenses/>.

# This is an example of the power of GtkSourceView.  I've taken the code inside
# the test-widget test app that comes with libgtksourceview, and translated it
# in Perl. (ebassi)

use Gtk2 '-init';
use Gtk2::SourceView;

use Gnome2;
use Gnome2::VFS '-init';
use Gnome2::Print;

use Data::Dumper;

use warnings;
use strict;
use constant TRUE	=> 1;
use constant FALSE	=> 0;

our @items = (
	[
		'/_File',
		undef,
		undef, undef,
		'<Branch>',
	],
		[
			'/File/_Open',
			'<Control>O',
			\&on_file_open, 0,
			'<StockItem>', 'gtk-open',
		],
		[
			'/File/_Print Preview',
			'<Control>P',
			\&on_print_preview, 0,
			'<StockItem>', 'gtk-print',
		],
		[
			'/File/sep1',
			undef,
			undef, undef,
			'<Separator>',
		],
		[
			'/File/_Quit',
			undef,
			sub { Gtk2->main_quit; }, 0,
			'<StockItem>', 'gtk-quit',
		],
	[
		'/_Edit',
		undef,
		undef, undef,
		'<Branch>',
	],
		[
			'/Edit/Check _Brackets',
			undef,
			\&on_edit_toggled, 6,
			'<CheckItem>',
		],
		[
			'/Edit/_Syntax Highlight',
			undef,
			\&on_edit_toggled, 7,
			'<CheckItem>',
		],
	[
		'/_View',
		undef,
		undef, undef,
		'<Branch>',
	],
		[
			'/View/Show _Line Numbers',
			undef,
			\&on_view_toggled, 1,
			'<CheckItem>',
		],
		[
			'/View/Show _Markers',
			undef,
			\&on_view_toggled, 2,
			'<CheckItem>',
		],
		[
			'/View/Show M_argin',
			undef,
			\&on_view_toggled, 3,
			'<CheckItem>',
		],
		[
			'/View/sep1',
			undef,
			undef, undef,
			'<Separator>',
		],
		[
			'/View/Enable _Auto Indent',
			undef,
			\&on_view_toggled, 4,
			'<CheckItem>',
		],
		[
			'/View/Insert _Spaces Instead of Tabs',
			undef,
			\&on_view_toggled, 5,
			'<CheckItem>',
		],
		
);

sub on_file_open
{
	my ($window, $action, $menu_item) = @_;

	my $dialog = Gtk2::FileSelection->new("Open file...");
	$dialog->signal_connect(response => sub {
			my ($dialog, $response) = @_;
			my $file = $dialog->get_filename;
			
			if ('ok' eq $response)
			{
				open_file($window->{'sourcebuffer'}, $file);
				$dialog->destroy;
			}
		});
	$dialog->show;
}

sub on_print_preview
{
	my ($window, $action, $menu_item) = @_;

	my $job = Gtk2::SourceView::PrintJob->new(undef);
	$job->setup_from_view($window->{'sourceview'});
	$job->set_wrap_mode('char');
	$job->set_highlight(TRUE);
	$job->set_print_numbers(5);	# print the line number every five lines.
	
	# header and format strings uses a strftime-like format.
	$job->set_header_format("Printed on %A", undef, "%F", TRUE);
	
	my $filename = $window->{'sourcebuffer'}->{'filename'};
	$job->set_footer_format("%T", $filename, "Page %N/%Q", TRUE);

	$job->set_print_header(TRUE);
	$job->set_print_footer(TRUE);
	
	# do an async printing, in order to show the preview and the progress; a
	# nifty dialog with a progressbar should be better...
	my ($start, $end) = $window->{'sourcebuffer'}->get_bounds;
	if ($job->print_range_async($start, $end))
	{
		$job->signal_connect(begin_page => sub {
				printf "Printing %.2f    \r",
						(100.0 * $job->get_page() / $job->get_page_count());
			});
		$job->signal_connect(finished   => sub {
				print "\n";
				my $gjob = $job->get_print_job;
				my $preview = Gnome2::Print::JobPreview->new($gjob, "$0 preview");

				$preview->show;
			});
	}
	else
	{
		print STDERR "Async print failed.\n";
	}
}

sub on_edit_toggled
{
	my ($window, $action, $menu_item) = @_;

	my $active = $menu_item->get_active;
	my $sbuffer = $window->{'sourcebuffer'};

	if    ($action == 6)
	{
		$sbuffer->set_check_brackets($active);
	}
	elsif ($action == 7)
	{
		$sbuffer->set_highlight($active);
	}
}

sub on_view_toggled
{
	my ($window, $action, $menu_item) = @_;

	my $active = $menu_item->get_active;
	my $sview = $window->{'sourceview'};

	if    ($action == 1)
	{
		$sview->set_show_line_numbers($active);
	}
	elsif ($action == 2)
	{
		$sview->set_show_line_markers($active);
	}
	elsif ($action == 3)
	{
		$sview->set_show_margin($active);
	}
	elsif ($action == 4)
	{
		$sview->set_auto_indent($active);
	}
	elsif ($action == 5)
	{
		$sview->set_insert_spaces_instead_of_tabs($active);
	}	
}

sub open_file
{
	use File::Spec;
	
	my ($source_buffer, $filename) = @_;
	my ($uri, $mime_type, $lang);
	my $manager = $source_buffer->{'languages_manager'};

	# languages definitions are accessed by mime type, via the
	# LanguagesManager object.  We use Gnome2::VFS to gather the mime
	# type from the file.
	if (File::Spec->file_name_is_absolute($filename))
	{
		$mime_type = Gnome2::VFS->get_mime_type($filename);
	}
	else
	{
		my $path = File::Spec->rel2abs($filename);
		$mime_type = Gnome2::VFS->get_mime_type($path);
		$filename = $path;
	}

	if ($mime_type)
	{
		$lang = $manager->get_language_from_mime_type($mime_type);
		unless ($lang)
		{
			print STDERR "No language found for mime type '$mime_type'\n";
			$source_buffer->set('highlight', FALSE);
		}
		else
		{
			$source_buffer->set('highlight', TRUE);
			$source_buffer->set_language($lang);
		}
	}
	else
	{
		$source_buffer->set('highlight', FALSE);
		print STDERR "Couldn't get mime type for file '$filename'\n";
	}
	
	# reset buffer
	$source_buffer->set_text('');
	
	# loading a file is an atomic operation; thus, disabling undo while filling
	# the buffer is the Right Thing To Do(tm).
	$source_buffer->begin_not_undoable_action;
	open (INFILE, $filename) or die "Unable to open file '$filename'";
	while (<INFILE>)
	{
		my $iter = $source_buffer->get_end_iter;
		$source_buffer->insert($iter, $_);
	}
	$source_buffer->end_not_undoable_action;

	# a Buffer is a TextBuffer
	$source_buffer->set_modified(FALSE);
	$source_buffer->place_cursor($source_buffer->get_start_iter());

	$source_buffer->{'filename'} = $filename;
}

sub create_source_buffer
{
	my $manager = Gtk2::SourceView::LanguagesManager->new;
	my $buffer = Gtk2::SourceView::Buffer->new(undef);
	$buffer->{'languages_manager'} = $manager;

	return $buffer;
}

sub create_window
{
	my $file = shift;
	
	our $w = Gtk2::Window->new('toplevel');
	$w->signal_connect(delete_event	=> sub { Gtk2->main_quit; });
	$w->set_title('Gtk2::SourceView demo');
	$w->set_border_width(0);
	$w->set_size_request(400, 400);

	my $vbox = Gtk2::VBox->new(FALSE, 0);
	$w->add($vbox);

	my $factory = Gtk2::ItemFactory->new('Gtk2::MenuBar', '<main>', undef);
	$factory->create_items($w, @items);
	my $menu = $factory->get_widget('<main>');
	$w->{'menu'} = $menu;
	$vbox->pack_start($menu, FALSE, FALSE, 0);

	my $sw = Gtk2::ScrolledWindow->new;
	$sw->set_policy('automatic', 'automatic');
	$sw->set_shadow_type('in');
	$vbox->pack_start($sw, TRUE, TRUE, 0);

	my $sb = create_source_buffer();
	open_file($sb, $file);
	$w->{'sourcebuffer'} = $sb;

	my $sourceview = Gtk2::SourceView::View->new_with_buffer($sb);
	# an editor using a non-proportional font? *yuk*!
	my $font_desc = Gtk2::Pango::FontDescription->from_string("monospace 10");
	if ($font_desc)
	{
		$sourceview->modify_font($font_desc);
	}
	
	$w->{'sourceview'} = $sourceview;
	$sw->add($sourceview);

	$vbox->show_all;
	
	return $w;
}

my $file = $ARGV[0] || $0;
print "file := $file\n";

my $win = create_window($file);
$win->show;

Gtk2->main;

Gnome2::VFS->shutdown;

0;