<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;"># Copyright (C) 2007-13  Stephane Galland &lt;galland@arakhne.org&gt;
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program 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 this program; see the file COPYING.  If not, write to
# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.

=pod

=head1 NAME

AutoLaTeX::GUI::Gtk::TranslatorPanel - A GTK panel for translator management

=head1 DESCRIPTION

AutoLaTeX::GUI::Gtk::TranslatorPanel is a Perl module, which permits to
display a Gtk panel that manages AutoLaTeX translators.

=head1 METHOD DESCRIPTIONS

This section contains only the methods in GtkTranslatorPanel.pm itself.

=over

=cut

package AutoLaTeX::GUI::Gtk::TranslatorPanel;

@ISA = qw( Gtk2::Table AutoLaTeX::GUI::Gtk::WidgetUtil AutoLaTeX::GUI::AbstractTranslatorPanel );
@EXPORT = qw();
@EXPORT_OK = qw();

require 5.014;
use strict;
use utf8;
use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION);
use Exporter;

use Glib qw(TRUE FALSE);
use Gtk2;
use Gtk2::SimpleList;

use AutoLaTeX::Core::Util;
use AutoLaTeX::Core::IntUtils;
use AutoLaTeX::Core::Config;
use AutoLaTeX::Core::Translator;
use AutoLaTeX::GUI::AbstractTranslatorPanel;
use AutoLaTeX::GUI::Gtk::WidgetUtil;

#------------------------------------------------------
#
# Global vars
#
#------------------------------------------------------

# Version number
my $VERSION = "7.0" ;

#------------------------------------------------------
#
# Functions
#
#------------------------------------------------------

=pod

=item * new(\%\%\%\%;$)

Contructor.

Parameters are:

=over 4

=item the current configuration extracted from the configuration files.

=item the system configuration extracted from the configuration file.

=item the user configuration extracted from the configuration file.

=item the project configuration extracted from the configuration file.

=item an object on which the subroutine C&lt;onTranslatorPanelStateChanged()&gt; is available.

=back

=cut
sub new(\%\%\%\%;$) : method {
	my $proto = shift;
	my $class = ref($proto) || $proto;

	my $self = bless( $class-&gt;SUPER::new(
						2, #rows
						2, #columns
						FALSE), #non uniform
			$class ) ;

	die("The first parameter of AutoLaTeX::GUI::Gtk::TranslatorPanel::new() should be a hastable\nIf you pass a %v variable, please use the \%v syntax instead.\n")
		unless ((!defined($_[0]))||(isHash($_[0])));
	$self-&gt;attr('CONFIGURATIONS','FULL') = $_[0];

	die("The second parameter of AutoLaTeX::GUI::Gtk::TranslatorPanel::new() should be a hastable\nIf you pass a %v variable, please use the \%v syntax instead.\n")
		unless ((!defined($_[1]))||(isHash($_[1])));
	$self-&gt;attr('CONFIGURATIONS','SYSTEM') = $_[1];

	die("The third parameter of AutoLaTeX::GUI::Gtk::TranslatorPanel::new() should be a hastable\nIf you pass a %v variable, please use the \%v syntax instead.\n")
		unless ((!defined($_[2]))||(isHash($_[2])));
	$self-&gt;attr('CONFIGURATIONS','USER') = $_[2];

	die("The forth parameter of AutoLaTeX::GUI::Gtk::TranslatorPanel::new() should be a hastable\nIf you pass a %v variable, please use the \%v syntax instead.\n")
		unless ((!defined($_[3]))||(isHash($_[3])));
	$self-&gt;attr('CONFIGURATIONS','PROJECT') = $_[3];

	$self-&gt;attr('PANEL_LISTENERS') = [ $_[4] ] if ($_[4]);


	#Â&nbsp;Initialization
	$self-&gt;initializeTranslatorPanel();

	return $self;
}

=pod

=item * initControls()

Initializing the controls.

=cut
sub initControls() : method {
	my $self = shift;

	#Â&nbsp;Label
	my $label = Gtk2::Label-&gt;new(_T("List of available translators:\n(click on the three left columns to change the loading state of the translators)"));
	$self-&gt;attach ($label, 
				0,1,0,1, # left, right, top and bottom columns
				'expand','shrink', # x and y options
				0,0); # horizontal and vertical paddings

	#Â&nbsp;Translator list and associated text
	my $translatorList = Gtk2::SimpleList-&gt;new (
					'system', 'pixbuf', 
					'user', 'pixbuf', 
					'project', 'pixbuf',
					'name', 'text',
					'description', 'text');
	$translatorList-&gt;set_headers_clickable (FALSE);
	$translatorList-&gt;set_headers_visible (FALSE);
	$self-&gt;attr('TRANSLATOR_LIST') = $translatorList;

	my $translatorListScroll = Gtk2::ScrolledWindow-&gt; new();
	$translatorListScroll-&gt;add ($translatorList);
	$translatorListScroll-&gt;set_size_request (500,400);
	$translatorListScroll-&gt;set_policy ('automatic','automatic');
	$translatorListScroll-&gt;set_shadow_type ('in');

	$self-&gt;attach ($translatorListScroll, 
				0,1,1,2, # left, right, top and bottom columns
				['fill','expand'],['fill','expand'], # x and y options
				5,5); # horizontal and vertical paddings

	#Â&nbsp;Management buttons
	my $buttonAlignment = Gtk2::VButtonBox-&gt;new ();
	$buttonAlignment-&gt;set_layout_default('start');
	$self-&gt;attach ($buttonAlignment, 
				1,2,0,2, # left, right, top and bottom columns
				'shrink',['fill','expand'], # x and y options
				5,5); # horizontal and vertical paddings

	my $addButton = Gtk2::Button-&gt;new_from_stock ('gtk-add');
	$self-&gt;connectSignal($addButton,'clicked','onTranslatorAdded');
	$addButton-&gt;set_sensitive( FALSE ) ;
	$self-&gt;attr('BUTTONS','addTranslator') = $addButton;
	$buttonAlignment-&gt;add ($addButton);

	my $editButton = Gtk2::Button-&gt;new_from_stock ('gtk-edit');
	$self-&gt;connectSignal($editButton,'clicked','onTranslatorEdited');
	$editButton-&gt;set_sensitive( FALSE ) ;
	$self-&gt;attr('BUTTONS','editTranslator') = $editButton;
	$buttonAlignment-&gt;add ($editButton);

	my $deleteButton = Gtk2::Button-&gt;new_from_stock ('gtk-delete');
	$self-&gt;connectSignal($deleteButton,'clicked','onTranslatorDeleted');
	$deleteButton-&gt;set_sensitive( FALSE ) ;
	$self-&gt;attr('BUTTONS','deleteTranslator') = $deleteButton;
	$buttonAlignment-&gt;add ($deleteButton);

	# Help
	$buttonAlignment-&gt;add (Gtk2::HSeparator-&gt;new ());
	$buttonAlignment-&gt;add ($self-&gt;makeLegend($self-&gt;getLevelIcon('system'), _T('All users')));
	$buttonAlignment-&gt;add ($self-&gt;makeLegend($self-&gt;getLevelIcon('user'), _T('Current usr')));
	$buttonAlignment-&gt;add ($self-&gt;makeLegend($self-&gt;getLevelIcon('project'), _T('Current project')));
	$buttonAlignment-&gt;add (Gtk2::HSeparator-&gt;new ());
	$buttonAlignment-&gt;add ($self-&gt;makeLegend($self-&gt;getLevelIcon('system'), _T('Loaded, no conflict')));
	$buttonAlignment-&gt;add ($self-&gt;makeLegend($self-&gt;getConflictLevelIcon('system'), _T('Loaded, conflict')));
	$buttonAlignment-&gt;add ($self-&gt;makeLegend($self-&gt;getRedLevelIcon('system'), _T('Not loaded')));
	$buttonAlignment-&gt;add ($self-&gt;makeLegend($self-&gt;getGrayedLevelIcon('system'), _T('Unspecified, no conflict')));
	$buttonAlignment-&gt;add ($self-&gt;makeLegend($self-&gt;getGrayedConflictLevelIcon('system'), _T('Unspecified, conflict')));
}

sub makeLegend($$;$) {
	my $self = shift;
	my $icon = shift;
	my $textlabel = shift;
	my $topPadding = shift || 0;

	my $legendAlignment = Gtk2::Table-&gt;new (5,2);

	my $iconLabel = Gtk2::Image-&gt;new_from_pixbuf($icon);
	$legendAlignment-&gt;attach ($iconLabel, 0, 1, 0, 1, 'fill', 'fill', 0, $topPadding);

	my $text = Gtk2::Label-&gt;new ($textlabel);
	$legendAlignment-&gt;attach ($text, 1, 2, 0, 1, 'fill', 'fill', 5, $topPadding);

	return $legendAlignment;
}

=pod

=item * initializeTranslatorPanel()

Initializing the panel content before displaying.

This method read the list of the translators and
fill the attribute C&lt;{'DATA'}{'translators'}&gt;.

=cut
sub initializeTranslatorPanel() : method {
	my $self = shift;
	$self-&gt;SUPER::initializeTranslatorPanel();
	$self-&gt;initControls();
	$self-&gt;detectTranslatorConflicts();
	$self-&gt;fillTranslatorList();
	$self-&gt;notifyListeners();
	$self-&gt;connectGtkSignals();
}

=pod

=item * getInclusionStateIcon($$)

Replies the icon that corresponds to the inclusion state of a translator at the specified level.

=over 4

=item level

=item translator name

=cut
sub getInclusionStateIcon($$) : method {
	my $self = shift;
	my $level = shift;
	my $name = shift;

	# Does the translator has a conflict?
	my $conflict = $self-&gt;hasTranslatorConflict($level,$name);

	if ($self-&gt;hasattr('TRANSLATORS',"$name",'included',"$level")) {
		my $val = $self-&gt;attr('TRANSLATORS',"$name",'included',"$level");
		if (defined($val)) {
			if ($val) {
				return $self-&gt;getConflictLevelIcon($level) if ($conflict);
				return $self-&gt;getLevelIcon($level);
			}
			else {
				return $self-&gt;getIcon("warning.png") if ($conflict);
				return $self-&gt;getRedLevelIcon($level);
			}
		}
	}
	return $self-&gt;getGrayedConflictLevelIcon($level) if ($conflict);
	return $self-&gt;getGrayedLevelIcon($level);
}

=pod

=item * detectTranslatorConflicts()

Detect translator conflicts.

=cut
sub detectTranslatorConflicts() : method {
	my $self = shift;
	my %conflicts = detectConflicts(%{$self-&gt;attr('TRANSLATORS')});
	#Â&nbsp;Parse conflict data structure to extract the names of the
	# translators under conflict
	foreach my $k (keys %conflicts) {
		my %trs = ();
		foreach my $source (keys %{$conflicts{$k}}) {
			foreach my $t (keys %{$conflicts{$k}{$source}}) {
				$trs{$t} = 1;
			}
		}
		my @trs = keys %trs;
		$conflicts{$k} = \@trs;
	}
	if (!$self-&gt;hasProject()) {
		delete $conflicts{'project'};
	}
	$self-&gt;attr('TRANSLATOR_CONFLICTS') = \%conflicts;
}

=pod

=item * hasTranslatorConflict()

Replies if a conflict exists for the specified translator and level.

=over 4

=item level

=item translator name

=back

=cut
sub hasTranslatorConflict($$) : method {
	my $self = shift;
	my $level = shift;
	my $name = shift;
	if (($self-&gt;hasattr('TRANSLATOR_CONFLICTS',"$level"))&amp;&amp;
	    (isArray($self-&gt;attr('TRANSLATOR_CONFLICTS',"$level")))) {
		return arrayContains(@{$self-&gt;attr('TRANSLATOR_CONFLICTS',"$level")},$name);
	}
	return 0;
}

=pod

=item * isUnderConflict()

Replies if a conflict exists.

=cut
sub isUnderConflict() : method {
	my $self = shift;
	if ($self-&gt;hasattr('TRANSLATOR_CONFLICTS')) {
		my $conflicts = $self-&gt;attr('TRANSLATOR_CONFLICTS');
		my $lastlevel = $self-&gt;hasProject() ? $ALL_LEVELS[$#ALL_LEVELS] : $ALL_LEVELS[$#ALL_LEVELS-1];
		return 1 if ((isArray($conflicts-&gt;{"$lastlevel"}))&amp;&amp;
			     (@{$conflicts-&gt;{"$lastlevel"}}));
		
	}
	return 0;
}

=pod

=item * fillTranslatorList()

Fill the list of translators.

=cut
sub fillTranslatorList() : method {
	my $self = shift;

	my @keys = sort keys %{$self-&gt;attr('TRANSLATORS')};

	@{$self-&gt;attr('TRANSLATOR_LIST')-&gt;{'data'}} = ();

	my ($systemIcon, $userIcon, $projectIcon);

	foreach my $trans (@keys) {
		$systemIcon = $self-&gt;getInclusionStateIcon('system',$trans);
		$userIcon = $self-&gt;getInclusionStateIcon('user',$trans);
		$projectIcon = $self-&gt;hasProject() ? $self-&gt;getInclusionStateIcon('project',$trans) : undef;

		push @{$self-&gt;attr('TRANSLATOR_LIST')-&gt;{'data'}}, 
			[ 
				$systemIcon,
				$userIcon,
				$projectIcon,
				$trans,
				$self-&gt;attr('TRANSLATORS',"$trans",'human-readable'),
			];
	}
}

=pod

=item * connectGtkSignals()

Differed connection of GTK signals to widgets.

=cut
sub connectGtkSignals() : method {
	my $self = shift;
	$self-&gt;connectSignal($self-&gt;attr('TRANSLATOR_LIST'),'row-activated','onTranslatorEdit');
	$self-&gt;connectSignal($self-&gt;attr('TRANSLATOR_LIST'),'button-press-event','onTranslatorClick');
	$self-&gt;connectSignal($self-&gt;attr('TRANSLATOR_LIST'),'cursor-changed','onTranslatorSelected');
}

=pod

=item * getTranslatorDataAt($)

Replies the data associated to the translator at the specified index

=cut
sub getTranslatorDataAt($) : method {
	my $self = shift;
	my $row = $self-&gt;attr('TRANSLATOR_LIST')-&gt;{'data'}[$_[0]];
	$self-&gt;attr('TRANSLATORS',$row-&gt;[3]);
}

=pod

=item * updateIcons($$)

Update the icons for the translator that support the given source
extension from the specified level.

=over 4

=item the level for which the update must be done.

=item the source extension that is the source of this update.

=back

=cut
sub updateIcons($$) : method {
	my $self = shift;
	my $level = shift;
	my $source = shift;

	my $levelIndex = arrayIndexOf(@ALL_LEVELS,$level);

	for(my $column=$levelIndex; $column&lt;@ALL_LEVELS; $column++) {
		my $clevel = $ALL_LEVELS[$column];
		if (($clevel ne 'project')||($self-&gt;hasProject())) {
			for(my $idxTrans=0; $idxTrans&lt;@{$self-&gt;attr('TRANSLATOR_LIST')-&gt;{'data'}}; $idxTrans++) {
				my $transData = $self-&gt;getTranslatorDataAt($idxTrans);
				if ($source eq $transData-&gt;{'full-source'}) {
					my $icon = $self-&gt;getInclusionStateIcon($clevel,$transData-&gt;{'name'});
					$self-&gt;attr('TRANSLATOR_LIST')-&gt;{'data'}[$idxTrans][$column] = $icon;
				}
			}
		}
	}
}	

=pod

=item * notifyListeners()

Notify listeners about a change of the stateof this panel.

=cut
sub notifyListeners() : method {
	my $self = shift;
	my $conflict = $self-&gt;isUnderConflict();
	if (($self-&gt;hasattr('PANEL_LISTENERS'))&amp;&amp;(isArray($self-&gt;attr('PANEL_LISTENERS')))) {
		foreach my $listener (@{$self-&gt;attr('PANEL_LISTENERS')}) {
			if ($listener-&gt;can('onTranslatorPanelStateChanged')) {
				$listener-&gt;onTranslatorPanelStateChanged($self,$conflict);
			}
		}
	}
}

#
#------------------------------------- SIGNALS
#

sub onTranslatorSelected(@) : method {
	my $self = shift;
	my $canWrite = 0;
	#my @sel = $self-&gt;attr('TRANSLATOR_LIST')-&gt;get_selected_indices ();
	#if (@sel) {
	#	my $sel = pop @sel;
	#	if ($sel&gt;=0) {
	#		my $data = $self-&gt;getTranslatorDataAt($sel);
	#		if ($data) {
	#			$canWrite = ((($data-&gt;{'level'} eq 'system')&amp;&amp;($self-&gt;isAdminUser()))||
	#					    ($data-&gt;{'level'} eq 'user')||
	#					    (($data-&gt;{'level'} eq 'project')&amp;&amp;($self-&gt;hasProject())));
	#		}
	#	}
	#}
	$self-&gt;attr('BUTTONS','editTranslator')-&gt;set_sensitive ($canWrite);
	$self-&gt;attr('BUTTONS','deleteTranslator')-&gt;set_sensitive ($canWrite);
}

sub onTranslatorClick(@) : method {
	my $self = shift;
	my $event = $_[1]; #Gtk2::Gdk::Event
	my ($x,$y) = $event-&gt;get_coords ();
	my ($path,$column,$cell_x,$cell_y) = $_[0]-&gt;get_path_at_pos ($x,$y);
	if ($path) {
		my @indices = $path-&gt;get_indices ();
		my $title = $column-&gt;get_title ();
		if ((($title eq 'system')&amp;&amp;($self-&gt;isAdminUser()))||
		    ($title eq 'user')||
		    (($title eq 'project')&amp;&amp;($self-&gt;hasProject()))) {
			my $index = pop @indices;
			my $data = $self-&gt;getTranslatorDataAt($index);
			if (!defined($data-&gt;{'included'}{"$title"})) {
				$data-&gt;{'included'}{"$title"} = 1;
			}
			elsif ($data-&gt;{'included'}{"$title"}) {
				$data-&gt;{'included'}{"$title"} = 0;
			}
			else {
				$data-&gt;{'included'}{"$title"} = undef;
			}

			$self-&gt;detectTranslatorConflicts();

			# Update the icons
			$self-&gt;updateIcons($title,$data-&gt;{'full-source'});

			# Notify listeners
			$self-&gt;notifyListeners();
		}
	}
}

sub onTranslatorAdded(@) : method {
	my $self = shift;
}

sub onTranslatorDeleted(@) : method {
	my $self = shift;
	#
	#my @sel = $self-&gt;attr('TRANSLATOR_LIST')-&gt;get_selected_indices ();
	#if (@sel) {
	#	foreach my $sel (@sel) {
	#		my $data = $self-&gt;getTranslatorDataAt($sel);
	#		if ($data) {
	#			my $canWrite = ((($data-&gt;{'level'} eq 'system')&amp;&amp;($self-&gt;isAdminUser()))||
	#					    ($data-&gt;{'level'} eq 'user')||
	#					    (($data-&gt;{'level'} eq 'project')&amp;&amp;($self-&gt;hasProject())));
	#		}
	#	}
	#}
}

1;
__END__

=back

=head1 COPYRIGHT

(c) Copyright 2007-13 Stephane Galland E&lt;lt&gt;galland@arakhne.orgE&lt;gt&gt;, under GPL.

=head1 AUTHORS

=over

=item *

Conceived and initially developed by StÃ©phane Galland E&lt;lt&gt;galland@arakhne.orgE&lt;gt&gt;.

=back

=head1 SEE ALSO

L&lt;autolatex&gt;
</pre></body></html>