{ package GCPlugins; ################################################### # # Copyright 2005-2010 Christian Jodar # # This file is part of GCstar. # # GCstar 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. # # GCstar 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 GCstar; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA # ################################################### use strict; use File::Basename; use GCUtils 'glob'; use GCDialogs; use base 'Exporter'; our @EXPORT = qw(%pluginsMap %pluginsNameArrays); our %pluginsMap; our %pluginsNameArrays; sub loadPlugins { my $model = shift; return if $pluginsNameArrays{$model}; my $dir = $ENV{GCS_LIB_DIR}.'/GCPlugins/'.$model; foreach (glob "$dir/*.pm") { my $plugin = basename($_, '.pm')."\n"; next if $plugin =~ /Common/; (my $class = $plugin) =~ s/^GC/GCPlugin/; my $obj; eval "use GCPlugins::".$model."::$plugin; \$obj = new GCPlugins::".$model."::$class;"; die "Fatal error with plugin $plugin : $@" if $@; $pluginsMap{$model}->{$obj->getName} = $obj; } my @names = sort keys %{$pluginsMap{$model}}; $pluginsNameArrays{$model} = \@names; } sub loadAllPlugins { foreach my $dir(glob $ENV{GCS_LIB_DIR}.'/GCPlugins/*') { next if $dir =~ /PluginsBase/; my $model = basename($dir); next if ($model !~ /^GC/) || ($model eq 'GCstar'); loadPlugins($model); } } { package GCPluginJob; use Storable qw(store_fd fd_retrieve); use IO::Handle; use GCPlugins::GCPluginsBase; sub new { my ($proto, $command, $data) = @_; my $class = ref($proto) || $proto; my $self = {command => $command, data => $data}; $command->autoflush(1); $data->autoflush(1); #GCPlugins::loadPlugins if ! $ENV{GCS_PROFILING}; bless ($self, $class); return $self; } sub run { my $self = shift; my $command = $self->{command}; my $info; while (1) { local $Storable::forgive_me = 1; $info = fd_retrieve($command); eval {$self->beginSearch($info)}; } } sub quit { my $self = shift; close $self->{command}; close $self->{data}; wait; exit; } sub beginSearch { my ($self, $info) = @_; my $pid; GCPlugins::loadPlugins($info->{model}) if $info->{model}; if ($pid = fork) { my $command = $self->{command}; $command->autoflush(1); my $cmd = readline($command); chomp $cmd; kill 9,$pid if ($cmd eq 'STOP'); $self->quit if $cmd eq 'EXIT'; wait; } else { #$info could be a simple hash or the plugin itself depending on the phase if ($info->{type} eq 'load') { # Here we create the plugin my $plugin = $pluginsMap{$info->{model}}->{$info->{name}}; $plugin->setProxy($info->{proxy}); $plugin->setCookieJar($info->{cookieJar}); $plugin->{type} = $info->{type}; $plugin->{urlField} = $info->{urlField}; $plugin->{bigPics} = $info->{bigPics}; $self->{currentPlugin} = $plugin; $plugin->{title} = $info->{query}; $plugin->{searchField} = $info->{field}; $plugin->{pass} = $info->{pass}; $plugin->{nextUrl} = $info->{nextUrl}; $plugin->load; # Remove the user agent part of the data, otherwise the Storable lib complains # about not being able to store the sub's stored in it. undef($plugin->{ua}); local $Storable::forgive_me = 1; store_fd $plugin, $self->{data}; } elsif ($info->{type} ne 'exit') { # Here we re-use it my $plugin = $info; store_fd $plugin->getItemInfo, $self->{data}; } exit; } } } use Gtk2; { package GCPluginsDialog; use base 'GCModalDialog'; sub show { my $self = shift; $self->{useThisSite}->set_active(0); $self->SUPER::show(); $self->show_all; $self->{fieldsList}->hide if $self->{hideFieldsList}; my $path = $self->{pluginsList}->get_selection->get_selected_rows; $self->{pluginsList}->scroll_to_cell($path) if $path; my $response = $self->run; $self->{plugin} = undef; if ($response eq 'ok') { my $pluginName = ''; my $idx = ($self->{pluginsList}->get_selected_indices)[0]; $pluginName = $self->{pluginsList}->{data}->[$idx]->[0]; $self->{plugin} = $self->{model}->getPlugin($pluginName); if ($self->{useThisSite}->get_active) { $self->{parent}->{model}->{preferences}->plugin($pluginName); $self->{parent}->checkPlugin; } } $self->hide; } sub new { my ($proto, $parent) = @_; my $class = ref($proto) || $proto; my $self = $class->SUPER::new($parent, $parent->{lang}->{PluginsTitle}, 'gtk-jump-to' ); bless ($self, $class); $self->{parent} = $parent; $self->{titleGroup} = new GCGroup($parent->{lang}->{PluginsQuery}); my $queryHbox = new Gtk2::HBox(0,0); $self->{query} = new GCShortText; $self->{query}->signal_connect(activate => sub { $self->response('ok'); }); $self->{fieldsList} = new GCMenuList; $queryHbox->pack_start($self->{query}, 1, 1, 0); $queryHbox->pack_start($self->{fieldsList}, 0, 0, $GCUtils::halfMargin); $self->{titleGroup}->addWidget($queryHbox); $self->vbox->pack_start($self->{titleGroup}, 0, 0, 0); my $pluginGroup = undef; my $pluginsFrame = new GCGroup($parent->{lang}->{PluginsFrame}); $self->{pluginsList} = new Gtk2::SimpleList($parent->{lang}->{PluginsName} => "text", $parent->{lang}->{PluginsLang} => "text", $parent->{lang}->{PluginsSearchFields} => "text", $parent->{lang}->{PluginsAuthor} => "text", $parent->{lang}->{PluginsPreferred} => "pixbuf",); $self->{pluginsList}->set_border_width(5); $self->{pluginsList}->set_rules_hint(1); $self->{pluginsList}->get_column(0)->set_min_width(150); for my $i (0..2) { $self->{pluginsList}->get_column($i)->set_resizable(1); } $self->{pluginsList}->signal_connect(row_activated => sub { $self->response('ok'); }); # Setup tooltips for list control $self->{pluginsList}->set_has_tooltip(1); $self->{pluginsList}->signal_connect (query_tooltip => sub { my ($widget, $x, $y, $keyboard_mode, $tooltip) = @_; # Place the tooltip in the right position my $path = $self->{pluginsList}->get_path_at_pos ($x, $y); return 0 unless $path; $self->{pluginsList}->set_tooltip_row($tooltip, $path); # If row is for a preferred plugin, set the tooltip my $index = ($path->get_indices)[0]; if (${ $self->{pluginsList}->{data} }[$index][4] == $self->{starPixbuf}) { $tooltip->set_text($parent->{lang}->{PluginsPreferredTooltip}); return 1; } else { return 0; } }); # Pixbufs for preferred and standard plugins $self->{starPixbuf} = Gtk2::Gdk::Pixbuf->new_from_file($ENV{GCS_SHARE_DIR}.'/icons/star.png'); $self->{blankPixbuf} = Gtk2::Gdk::Pixbuf->new ('rgb', 1, 8, 1, 1); $self->{blankPixbuf}->fill(0x00000000); $self->{currentPluginList} = undef; #$self->setModel; my $scrollPanelList = new Gtk2::ScrolledWindow; $scrollPanelList->set_border_width(5); $scrollPanelList->set_policy ('never', 'automatic'); $scrollPanelList->set_shadow_type('etched-in'); $scrollPanelList->add($self->{pluginsList}); $self->{useThisSite} = Gtk2::CheckButton->new($parent->{lang}->{PluginsUseSite}); my $pluginBox = new Gtk2::VBox(0,0); $pluginBox->pack_start($scrollPanelList, 1, 1, 0); $pluginBox->pack_start(Gtk2::VBox->new, 0, 0, $GCUtils::halfMargin); $pluginBox->pack_start($self->{useThisSite}, 0, 0, 0); $pluginsFrame->addWidget($pluginBox); $self->vbox->pack_start($pluginsFrame, 1, 1, 0); $self->set_default_size(1,550); return $self; } sub query { my $self = shift; if (@_) { my ($query, $field, $queries) = @_; $self->{fieldsList}->setValue($field); $self->{query}->setValue($query); $self->{queries} = $queries; $self->{fieldsList}->signal_connect('changed' => sub { # Only change the search query if it's not empty, otherwise keep existing value if ($self->{queries}->{$self->{fieldsList}->getValue}) { $self->{query}->setValue( $self->{queries}->{$self->{fieldsList}->getValue} ); } }); #$self->{fieldsList}->setDefaultValues(shift); #$self->{searchField} = shift; } return ($self->{query}->getValue, $self->{fieldsList}->getValue); } sub plugin { my $self = shift; return $self->{plugin}; } sub setModel { my ($self, $model, $list) = @_; $model ||= $self->{parent}->{model}; my @plugins_array = sort split (",", $list) if $list; my @fields = @{$model->getSearchFields}; if ($#fields < 1) { $self->{hideFieldsList} = 1; } else { $self->{hideFieldsList} = 0; my @values; foreach (@fields) { push @values, {value => $_, displayed => $model->getDisplayedText($model->{fieldsInfo}->{$_}->{label})}; } $self->{fieldsList}->setValues(\@values); } # if ($model) # { # my $titleField = $model->{commonFields}->{title}; # my $titleInfo = $self->{parent}->{model}->{fieldsInfo}->{$titleField}; # my $titleText = $model->getDisplayedText($titleInfo->{label}); # $self->{titleGroup}->setLabel($titleText); # } return if $list && ($self->{currentPluginList} eq $list); $self->{currentPluginList} = $list; my $pluginGroup = undef; my $i = 0; my @newData; $self->{model} = $model; if ($model) { foreach (sort keys %{$model->getAllPlugins}) { my $plugin = $model->getPlugin($_); if ((!$list) || ($plugin->getName eq $plugins_array[$i])) { # Add plugin to list # Plugin should be marked as a default if it's both preferred, and for the user's language, # or if isPreferred is 2 (not language dependant) push @newData, [$plugin->getName, "\n".$plugin->getLang."\n", $plugin->getSearchFields($model), $plugin->getAuthor, ((($plugin->isPreferred == 1) && ($self->{parent}->{options}->lang eq $plugin->getLang)) || ($plugin->isPreferred == 2)) ? $self->{starPixbuf} : $self->{blankPixbuf}]; $i++; } } } # Sort list with preferred plugins first @{$self->{pluginsList}->{data}} = sort { if (($a->[4] == $self->{starPixbuf}) && ($b->[4] == $self->{starPixbuf})) { return lc($a->[0]) cmp lc($b->[0]); } elsif ($a->[4] == $self->{starPixbuf}) { return -1; } elsif ($b->[4] == $self->{starPixbuf}) { return 1; } else { return lc($a->[0]) cmp lc($b->[0]); } } @newData; $self->{pluginsList}->select(0); } } { package GCAllPluginsDialog; use base 'GCModalDialog'; sub show { my $self = shift; $self->SUPER::show(); $self->show_all; ($self->action_area->get_children)[1]->hide_all; my $response = $self->run; $self->hide; } sub new { my ($proto, $parent) = @_; my $class = ref($proto) || $proto; my $self = $class->SUPER::new($parent, $parent->{lang}->{PluginsFrame}, 'gtk-close' ); bless ($self, $class); $self->{parent} = $parent; $self->{factory} = $parent->{modelsFactory}; my @columnsNames = ('Name', 'Lang', 'SearchFields', 'Author', 'Preferred'); $self->{pluginsModel} = new Gtk2::TreeStore(map {'Glib::String'} @columnsNames); $self->{pluginsList} = Gtk2::TreeView->new_with_model($self->{pluginsModel}); my @columns; my $i = 0; for my $col(@columnsNames) { my $column = Gtk2::TreeViewColumn->new_with_attributes($parent->{lang}->{'Plugins'.$col}, Gtk2::CellRendererText->new, 'text' => $i); $column->set_resizable(1); $self->{pluginsList}->append_column($column); $i++; } $self->{pluginsList}->set_border_width(5); $self->{pluginsList}->set_rules_hint(1); my $scrollPanelList = new Gtk2::ScrolledWindow; $scrollPanelList->set_border_width(5); $scrollPanelList->set_policy ('never', 'automatic'); $scrollPanelList->set_shadow_type('etched-in'); $scrollPanelList->add($self->{pluginsList}); $self->{useThisSite} = Gtk2::CheckButton->new($parent->{lang}->{PluginsUseSite}); my $pluginBox = new Gtk2::VBox(0,0); $pluginBox->pack_start($scrollPanelList, 1, 1, 0); for my $modelInfo (@{$self->{factory}->getDefaultModels}) { my $modelIter = $self->{pluginsModel}->append(undef); $self->{pluginsModel}->set($modelIter, (0 => $modelInfo->{description}) ); my $model = $self->{factory}->getModel($modelInfo->{name}); for my $pluginName (sort keys %{$model->getAllPlugins}) { my $plugin = $model->getPlugin($pluginName); my $pluginIter = $self->{pluginsModel}->append($modelIter); my %data; $i = 0; my $method; ($method = 'get'.$_, $data{$i++} = $plugin->$method($model)) foreach (@columnsNames); $self->{pluginsModel}->set($pluginIter, %data); # ( # 0 => $plugin->getName, # 1 => $plugin->getLang, # 2 => $plugin->getSearchFieldsAsString($model), # 4 => $plugin->getAuthor # ) # ); } } $self->vbox->pack_start($pluginBox, 1, 1, 0); $self->set_default_size(1,550); return $self; } sub setModel { my ($self, $model, $list) = @_; $model ||= $self->{parent}->{model}; my @plugins_array = sort split (",", $list) if $list; my @fields = @{$model->getSearchFields}; if ($#fields < 1) { $self->{hideFieldsList} = 1; } else { $self->{hideFieldsList} = 0; my @values; foreach (@fields) { push @values, {value => $_, displayed => $model->getDisplayedText($model->{fieldsInfo}->{$_}->{label})}; } $self->{fieldsList}->setValues(\@values); } return if $list && ($self->{currentPluginList} eq $list); $self->{currentPluginList} = $list; my $pluginGroup = undef; my $i = 0; my @newData; $self->{model} = $model; if ($model) { foreach (sort keys %{$model->getAllPlugins}) { my $plugin = $model->getPlugin($_); if ((!$list) || ($plugin->getName eq $plugins_array[$i])) { push @newData, [$plugin->getName, "\n".$plugin->getLang."\n", $plugin->getAuthor, $plugin->isPreferred ? $self->{starPixbuf} : $self->{blankPixbuf}]; $i++; } } } # Sort list with preferred plugins first @{$self->{pluginsList}->{data}} = sort { if (($a->[4] == $self->{starPixbuf}) && ($b->[4] == $self->{starPixbuf})) { return lc($a->[0]) cmp lc($b->[0]); } elsif ($a->[4] == $self->{starPixbuf}) { return -1; } elsif ($b->[4] == $self->{starPixbuf}) { return 1; } else { return lc($a->[0]) cmp lc($b->[0]); } } @newData; $self->{pluginsList}->select(0); } } { #Class that is used to let user select #plugins he wants to use in a multi-site search. package GCMultiSiteDialog; use base 'GCDoubleListDialog'; sub getInitData { my $self = shift; return $self->{model}->getPluginsNames; } sub getData { my $self = shift; my @array = split m/,/, $self->{model}->{preferences}->multisite; return \@array; } sub saveList { my ($self, $list) = @_; my $value = join ',', @$list; $self->{model}->{preferences}->multisite($value); } sub getPlugin { my ($self, $idx) = @_; $self->init; return $self->{usedArray}->[$idx]; } sub getPluginsNumber { my $self = shift; $self->init; return scalar @{$self->{usedArray}}; } sub preFill { my $self = shift; my @data; my $langName = $self->{options}->lang; foreach (@{$self->{model}->getPluginsNames}) { push @data, $_ if $self->{model}->getPlugin($_)->getLang eq $langName; } $self->getDoubleList->setListData(\@data); } sub setModel { my ($self, $model) = @_; $self->{model} = $model; } sub new { my ($proto, $parent, $model) = @_; my $class = ref($proto) || $proto; my $self = $class->SUPER::new( $parent, $parent->{lang}->{MultiSiteTitle}, 0, $parent->{lang}->{MultiSiteUnused}, $parent->{lang}->{MultiSiteUsed} ); bless ($self, $class); $self->setModel($model); if (! $self->{model}->{preferences}->exists('multisite')) { $self->preFill; $self->saveList(\@{$self->{usedArray}}); $self->{initialized} = 1; } my $langButton = new Gtk2::Button($parent->{lang}->{MultiSiteLang}); $langButton->set_border_width($GCUtils::margin); $langButton->signal_connect('clicked' => sub { $self->preFill; }); my $clearButton = new Gtk2::Button($parent->{lang}->{MultiSiteClear}); $clearButton->set_border_width($GCUtils::margin); $clearButton->signal_connect('clicked' => sub { $self->clearList; }); $self->getDoubleList->setDataHandler($self); $self->getDoubleList->addBottomButtons($langButton,$clearButton); return $self; } } { #Class that is used to let user select #plugin order he wants to use for each imported fields package GCMultiSitePerFieldDialog; use base 'GCModalDialog'; our $removeValue = 'GCListRemove'; my $startColMenus=1; my $pluginListOrderPerField; my $fieldsToFetch; my $remainingSourcesOrderPerField; sub show { my $self = shift; $self->SUPER::show(); $self->show_all; my $response = $self->run; $self->hide; $self->cleanListOrder; $self->savePrefOrderListFromForm if ($response eq 'ok'); $self->loadPrefOrderListInForm if ($response ne 'ok'); return ($response eq 'ok'); } sub getSourcesListMenu { my ($self,$withRemoveItem) = @_; return new GCMenuList($self->{sourcesList}) if !$withRemoveItem; return new GCMenuList($self->{sourcesListWithRemoveItem}) if $withRemoveItem; } sub createRowForField { my ($self, $field, $row, $mandatory) = @_; my $fieldsInfo = $self->{parent}->{model}->{fieldsInfo}; $self->{fields}->{$field}->{row}=$row; $self->{fields}->{$field}->{'Cb'} = new GCCheckBox($self->{parent}->{model}->getDisplayedText($fieldsInfo->{$field}->{label})); if ($mandatory) { $self->{fields}->{$field}->{'Cb'}->lock(1); $self->{fields}->{$field}->{'Cb'}->setValue(1); $self->{fields}->{$field}->{'Cb'}->{mandatory} = 1; } $self->{table}->attach($self->{fields}->{$field}->{'Cb'}, 0, 1, $row, $row + 1, 'fill', ['fill', 'expand'], 0, 0); my $curNbSite=0; $self->{fields}->{$field}->{'SiteListMenus'}=[]; $self->{fields}->{$field}->{'SiteListAddLast'}=new Gtk2::Button("+"); $self->{fields}->{$field}->{'SiteListAddLast'}->signal_connect('clicked' => sub { $self->addSiteListToField($field,-1); }); $self->{fields}->{$field}->{'SiteListAddLast'}->set_no_show_all(1); $self->{fields}->{$field}->{'SiteListAddFirst'}=new Gtk2::Button("+"); $self->{fields}->{$field}->{'SiteListAddFirst'}->signal_connect('clicked' => sub { $self->addSiteListToField($field,0); }); $self->{table}->attach($self->{fields}->{$field}->{'SiteListAddFirst'}, $startColMenus, 1+$startColMenus, $row, $row + 1, 'fill', 'fill', 0, 0); my $Align = new Gtk2::Alignment(0.0, 0.5, 0.0, 0.0); my $Hbox = new Gtk2::HBox(); $self->{fields}->{$field}->{'Hbox'}=$Hbox; $Hbox->pack_start($self->{fields}->{$field}->{'SiteListAddLast'},1,0,0); $Align->add($Hbox); $self->{table}->attach($Align, 1+$startColMenus, 2+$startColMenus, $row, $row + 1, ['expand','fill'], 'fill', 0, 0); } sub addSiteListToField { my ($self, $field, $position,$value) = @_; my $curListMenus=$self->{fields}->{$field}->{'SiteListMenus'}; my $curNbSite=scalar @{$curListMenus}; $curNbSite++; $position=$curNbSite-1 if $position==-1; my $Hbox = $self->{fields}->{$field}-> {'Hbox'}; my $newSiteList = $self->getSourcesListMenu(1); $value=$self->{bottomline}->{siteAddToAll}->getValue(1) if !$value; $newSiteList->setValue($value); $newSiteList->{orderInList}=$position; $newSiteList->signal_connect('changed' => sub { if ($newSiteList->getValue eq $removeValue) { $self->removeSiteListFromField($field, $newSiteList->{orderInList}) } }); #insert the new siteList splice @{$curListMenus}, $position, 0, $newSiteList; $Hbox->pack_start($newSiteList,0,0,0); $Hbox->reorder_child($newSiteList,$position); $newSiteList->show; #move other siteList on this row to the right for (my $idx=$position;$idx<$curNbSite;$idx++) { $curListMenus->[$idx]->{orderInList}=$idx; } if($curNbSite==1) { $self->{fields}->{$field}->{'SiteListAddLast'}->set_no_show_all(0); $self->{fields}->{$field}->{'SiteListAddLast'}->show; } } sub removeSiteListFromField { my ($self, $field, $position) = @_; my $curListMenus=$self->{fields}->{$field}->{'SiteListMenus'}; my $curNbSite=scalar @{$curListMenus}; $position=$curNbSite-1 if $position==-1; my $oldSiteList=splice @{$curListMenus}, $position, 1; my $Hbox = $self->{fields}->{$field}-> {'Hbox'}; $Hbox->remove($oldSiteList); $curNbSite--; #move other siteList on this row to the left for (my $idx=$position;$idx<$curNbSite;$idx++) { $curListMenus->[$idx]->{orderInList}=$idx; } if($curNbSite==0) { $self->{fields}->{$field}->{'SiteListAddLast'}->set_no_show_all(1); $self->{fields}->{$field}->{'SiteListAddLast'}->hide; } } sub removeAllSourceListFromField { my ($self, $field) = @_; my $curNbSite=scalar @{$self->{fields}->{$field}->{'SiteListMenus'}}; for (my $i=0;$i<$curNbSite;$i++) { $self->removeSiteListFromField($field,-1); } } sub new { my ($proto, $parent, $model,$usePlugins,$otherSources) = @_; my $class = ref($proto) || $proto; my $self = $class->SUPER::new($parent, $parent->{lang}->{OptionsPluginsMultiPerFieldWindowTitle} ); bless ($self, $class); $model=$parent->{model} if !$model; $self->{parent} = $parent; $self->set_modal(1); $self->set_position('center'); $self->set_default_size(1,500); my $layoutHbox = new Gtk2::HBox(0,0); $self->{layoutVBox} = new Gtk2::VBox(0,0); $self->vbox->pack_start($layoutHbox, 1,1,0); $layoutHbox->pack_start($self->{layoutVBox},0,0,$GCUtils::margin); $self->{table} = new Gtk2::Table(1, 3, 0); $self->{table}->set_row_spacings($GCUtils::halfMargin); $self->{table}->set_col_spacings($GCUtils::margin); $self->{table}->set_border_width($GCUtils::margin); $self->{scrollPanelList} = new Gtk2::ScrolledWindow; $self->{scrollPanelList}->set_policy ('never', 'automatic'); $self->{scrollPanelList}->set_shadow_type('none'); $self->{scrollPanelList}->add_with_viewport($self->{table}); $self->{descriptionLabel}=new GCLabel($parent->{lang}->{OptionsPluginsMultiPerFieldDesc}); $self->{layoutVBox}->pack_start($self->{descriptionLabel},0,0,$GCUtils::margin); $self->{layoutVBox}->pack_start($self->{scrollPanelList},1,1,$GCUtils::margin); $self->setModel($model); $self->setSourceList($usePlugins,$otherSources); $self->initForm; if (! $self->{model}->{preferences}->exists('multisiteperfield')) { $self->savePrefOrderListFromForm; } else { $self->loadPrefOrderListInForm; } return $self; } sub setSourceList { my ($self,$usePlugins,$otherSourcesList) = @_; $#{$self->{sourcesList}}=-1; $#{$self->{sourcesListWithRemoveItem}}=-1; if ($usePlugins) { foreach (@{$self->{model}->getPluginsNames}) { push @{$self->{sourcesList}},{value=>$_, displayed=>$_}; } } if ($otherSourcesList && scalar (@$otherSourcesList)) { foreach (@{$otherSourcesList}) { push @{$self->{sourcesList}},Storable::dclone($_); } } $self->{sourcesListWithRemoveItem}=Storable::dclone($self->{sourcesList}); unshift @{$self->{sourcesListWithRemoveItem}}, {value=>$removeValue,displayed=>$self->{parent}->{lang}->{OptionsPluginsMultiPerFieldRemove}}; } sub setModel { my ($self, $model) = @_; my $parent = $self->{parent}; return if $self->{model} == $model; $self->{model} = $model; } sub initForm { my ($self) = @_; my $parent = $self->{parent}; my $fieldsInfo = $self->{model}->{fieldsInfo}; $self->{urlField} = $self->{parent}->{model}->{commonFields}->{url}; foreach ($self->{table}->get_children) { $self->{table}->remove($_); $_->destroy; } my $row = 0; my $field; foreach $field(@{$self->{model}->{fieldsNames}}) { next if $fieldsInfo->{$field}->{imported} ne 'true'; next if ($field eq $self->{urlField}); $self->createRowForField($field, $row); $row++; } $row++; if($self->{bottomline}) { foreach($self->{bottomline}->get_children) { $self->{bottomline}->remove($_); $_->destroy; } $self->{bottomline}->destroy; undef $self->{bottomline}; } $self->{bottomline}=new Gtk2::HBox; $self->{bottomline}->{selectAll}=new Gtk2::Button($parent->{lang}->{ImportSelectAll}); $self->{bottomline}->{selectAll}->signal_connect('clicked' => sub { while ( my ($field, $row) = each(%{$self->{fields}}) ) { $row->{'Cb'}->setValue(1); } }); $self->{bottomline}->pack_start($self->{bottomline}->{selectAll},0,0,0); $self->{bottomline}->{selectNone}=new Gtk2::Button($parent->{lang}->{ImportSelectNone}); $self->{bottomline}->{selectNone}->signal_connect('clicked' => sub { while ( my ($field, $row) = each(%{$self->{fields}}) ) { $row->{'Cb'}->setValue(0); } }); $self->{bottomline}->pack_start($self->{bottomline}->{selectNone},0,0,0); $self->{bottomline}->{clear}=new Gtk2::Button($parent->{lang}->{OptionsPluginsMultiPerFieldClearSelected}); $self->{bottomline}->{clear}->signal_connect('clicked' => sub { while ( my ($field, $row) = each(%{$self->{fields}}) ) { $self->removeAllSourceListFromField($field) if $row->{'Cb'}->getValue; } }); $self->{bottomline}->pack_start($self->{bottomline}->{clear},0,0,0); $self->{bottomline}->{positionAddToAll} = new GCMenuList([{value=>'First',displayed=>$parent->{lang}->{OptionsPluginsMultiPerFieldFirst}}, {value=>'Last',displayed=>$parent->{lang}->{OptionsPluginsMultiPerFieldLast}}]); $self->{bottomline}->pack_end($self->{bottomline}->{positionAddToAll},0,0,0); $self->{bottomline}->{siteAddToAll} = $self->getSourcesListMenu; $self->{bottomline}->pack_end($self->{bottomline}->{siteAddToAll},0,0,0); $self->{bottomline}->{addToAll} = GCButton->newFromStock('gtk-add', 0); $self->{bottomline}->{addToAll}->signal_connect('clicked' => sub { my $positionAdd=$self->{bottomline}->{positionAddToAll}->getValue(0) eq 'First' ? 0:-1; foreach $field(keys %{$self->{fields}}) { $self->addSiteListToField($field,$positionAdd,$self->{bottomline}->{siteAddToAll}->getValue(0)); } }); $self->{bottomline}->pack_end($self->{bottomline}->{addToAll},0,0,0); $self->{layoutVBox}->pack_start($self->{bottomline},0,0,$GCUtils::margin); } sub loadPrefOrderListInForm { my $self = shift; # load from preference string undef $pluginListOrderPerField; undef $fieldsToFetch; my $valueStr = $self->{model}->{preferences}->multisiteperfield; my @arrValues= split ';', $valueStr; foreach (@arrValues) { my @line=split ',',$_; my $field=shift @line; $fieldsToFetch->{$field}=shift @line; $pluginListOrderPerField->{$field}=\@line if scalar(@line); } # add values in form while ( my ($field, $row) = each(%{$self->{fields}}) ) { $self->removeAllSourceListFromField($field); $self->addSiteListToField($field,-1,$_) foreach (@{$pluginListOrderPerField->{$field}}); $self->{fields}->{$field}->{Cb}->setValue($fieldsToFetch->{$field}); } $self->cleanListOrder; } sub savePrefOrderListFromForm { my $self = shift; undef $pluginListOrderPerField; undef $fieldsToFetch; # load from form $self->cleanListOrder; while ( my ($field, $row) = each(%{$self->{fields}}) ) { $fieldsToFetch->{$field}= $row->{'Cb'}->getValue; push @{$pluginListOrderPerField->{$field}},$_->getValue foreach (@{$row->{'SiteListMenus'}}); } # save to preference string my $valueStrArr = []; while ( my ($field, $row) = each(%{$self->{fields}}) ) { my $value=$field.','.$fieldsToFetch->{$field}; $value=$value.','.join ',',@{$pluginListOrderPerField->{$field}} if $pluginListOrderPerField->{$field}; push @$valueStrArr,$value; } $self->{model}->{preferences}->multisiteperfield(join ';',@$valueStrArr); } sub cleanListOrder { my $self = shift; # remove double sitename for each fields, keep the first one for my $field (keys %{$self->{fields}} ) { my $sites={}; my $row=$self->{fields}->{$field}->{SiteListMenus}; for (my $i = 0; $i <= $#$row; ++$i) { if ($sites->{$row->[$i]->getValue}) { $self->removeSiteListFromField($field,$i); $i--; } else { $sites->{$row->[$i]->getValue}=1; } } undef $sites; } } sub resetCurrentFetchingStatus { undef $remainingSourcesOrderPerField; foreach (keys %$fieldsToFetch) { $remainingSourcesOrderPerField->{$_}=Storable::dclone($pluginListOrderPerField->{$_}) if $fieldsToFetch->{$_} ; } } sub getNextSourceNeeded { my $self = shift; foreach my $field(keys %$remainingSourcesOrderPerField) { if (scalar(@{$remainingSourcesOrderPerField->{$field}})>0) { return $remainingSourcesOrderPerField->{$field}->[0]; } } return undef; } sub getPlugin { my ($self,$pluginName) = @_; return $self->{model}->getPlugin($pluginName); } sub getNonEmptyFields { my ($self,$info)=@_; my $nonEmptyFields=[]; foreach my $field(keys %$info) { push @$nonEmptyFields,$field if $self->isFieldNonEmpty($info->{$field}); } return $nonEmptyFields; } sub isFieldNonEmpty { my ($self,$var)=@_; return 0 if !defined $var; my $reftype=ref $var; if (!$reftype) { return $var ne ''; } elsif ($reftype eq 'SCALAR') { return $$var ne '' && $var!=undef; } elsif ($reftype eq 'ARRAY') { return scalar($var)>0; } elsif ($reftype eq 'HASH') { return scalar(keys(%{$var}))>0; } } sub doneWithSourceName { my ($self,$pluginName,$info) = @_; foreach my $field(keys %$remainingSourcesOrderPerField) { foreach my $pluginIdx (0..$#{$remainingSourcesOrderPerField->{$field}}) { if ($remainingSourcesOrderPerField->{$field}->[$pluginIdx] eq $pluginName) { if ($self->isFieldNonEmpty($info->{$field})) { # if we have the field, so we wont need other info $#{$remainingSourcesOrderPerField->{$field}}=$pluginIdx-1; last; } else { # else we will still need the next one splice @{$remainingSourcesOrderPerField->{$field}},$pluginIdx,1; last; } } } } } sub joinInfo { my ($self,$infoPerPlugin) = @_; my $info={}; my $fetchedSources=Storable::dclone($pluginListOrderPerField); my %urls; my $urlField=$self->{parent}->{model}->{commonFields}->{url}; foreach my $field(keys %$pluginListOrderPerField) { shift @{$fetchedSources->{$field}} while (scalar(@{$fetchedSources->{$field}}) && !$self->isFieldNonEmpty($infoPerPlugin->{$fetchedSources->{$field}->[0]}->{$field})); if (scalar(@{$fetchedSources->{$field}})>0) { $info->{$field}=$infoPerPlugin->{$fetchedSources->{$field}->[0]}->{$field} ; $urls{$fetchedSources->{$field}->[0]}=$infoPerPlugin->{$fetchedSources->{$field}->[0]}->{$urlField}; } } $info->{$urlField}=join ';',values %urls; return $info; } } } { package GCResultsDialog; use base 'GCModalDialog'; sub show { my $self = shift; for my $i (0..$self->{nbCols} - 1) { $self->{results}->get_column($i)->set_sort_indicator(0); } $self->{order} = 1; $self->{sort} = ''; $self->{validated} = 0; $self->SUPER::show(); $self->show_all; $self->{nextButton}->hide if !$self->{withNext}; $self->{multipleSelectionLabel}->hide if ! $self->{multipleSelection}; my $ended = 0; my $code; while (!$ended) { $code = $self->run; if ($code eq 'ok') { $self->{validated} = 1; $self->{itemsIndexes} = []; my @idxs = $self->{results}->get_selected_indices; foreach my $idx(@idxs) { push @{$self->{itemsIndexes}}, $self->{items}->[$idx]->{'#'}; } } elsif ($code eq 'yes') { my @idx = $self->{results}->get_selected_indices; my $itemIndex = $self->{items}->[$idx[0]]->{'#'}; $self->{parent}->downloadItemInfoFromPlugin($self->{plugin}, $itemIndex, 1); } $ended = 1 if ($code eq 'ok') || ($code eq 'cancel') || ($code eq 'delete-event') || ($code eq 'no'); } $self->hideTooltip; $self->hide; return ($code eq 'no'); } sub getItemsIndexes { my $self = shift; return $self->{itemsIndexes}; } sub setMultipleSelection { my ($self, $activate) = @_; return if !$self->{results}; $self->{results}->get_selection->set_mode ($activate ? 'multiple' : 'single'); $self->{multipleSelection} = $activate; } sub setWithNext { my ($self, $value) = @_; $self->{withNext} = $value; } sub setSearchPlugin { my ($self, $plugin) = @_; $self->{plugin} = $plugin; $self->set_title($self->{parent}->{lang}->{ResultsTitle}.' ('.$plugin->getName.')'); for my $i (0..$self->{nbCols} - 2) { # If plugin is a multi-pass plugin, then update the column headers for this pass $plugin->getReturnedFields() if $plugin->getNumberPasses > 1; $self->{results}->get_column($i)->set_visible($plugin->hasField($self->{fields}->[$i])); } if ($plugin->getExtra) { $self->{results}->get_column($self->{nbCols} - 1)->set_visible(1); $self->{results}->get_column($self->{nbCols} - 1)->set_title($plugin->getExtra); $self->{withExtra} = 1; } else { $self->{results}->get_column($self->{nbCols} - 1)->set_visible(0); $self->{withExtra} = 0; } } sub new { my ($proto, $parent) = @_; my $class = ref($proto) || $proto; my $self = $class->SUPER::new($parent, $parent->{lang}->{ResultsTitle}, undef, 0, 'gtk-zoom-in' => 'yes' ); bless ($self, $class); $self->{results} = 0; $self->{withExtra} = 0; $self->{withNext} = 0; $self->{multipleSelection} = 0; $self->{nextButton} = Gtk2::Button->new_from_stock('gtk-go-forward'); $parent->{tooltips}->set_tip($self->{nextButton}, $parent->{lang}->{ResultsNextTip}); $self->add_action_widget($self->{nextButton}, 'no'); $self->{parent} = $parent; $self->set_modal(1); $self->set_position('center'); $self->{scrollPanelList} = new Gtk2::ScrolledWindow; $self->{scrollPanelList}->set_policy ('never', 'automatic'); $self->{scrollPanelList}->set_shadow_type('etched-in'); $self->vbox->pack_start($self->{scrollPanelList}, 1, 1, 0); $self->vbox->pack_start(Gtk2::HSeparator->new, 0, 0, 0); my $fillBox = new Gtk2::HBox(0,0); $self->{multipleSelectionLabel} = GCLabel->new(''.$parent->{lang}->{ResultsInfo}.''); $self->{multipleSelectionLabel}->set_line_wrap(1); $self->{multipleSelectionLabel}->set_justify('center'); $self->{multipleSelectionLabel}->set_padding($GCUtils::margin, 0); $fillBox->pack_start(Gtk2::HBox->new(0,0),1,1,0); $fillBox->pack_start($self->{multipleSelectionLabel}, 0, 0, $GCUtils::margin); $fillBox->pack_start(Gtk2::HBox->new(0,0),1,1,0); $self->vbox->pack_start($fillBox, 0 , 0, $GCUtils::margin); # To create a tooltip as it is not implemented directly in Gtk2 $self->{tooltipLabel} = Gtk2::Label->new; $self->{tooltipLabel}->set_line_wrap(1); $self->{tooltipLabel}->set_padding($GCUtils::margin, $GCUtils::margin); $self->{tooltip} = Gtk2::Window->new('popup'); $self->{tooltip}->set_decorated(0); $self->{tooltip}->set_sensitive(1); $self->{tooltip}->modify_fg('normal', Gtk2::Gdk::Color->parse('#000000')); $self->{tooltip}->modify_bg('normal', Gtk2::Gdk::Color->parse('#ffffbf')); $self->{tooltip}->set_position('mouse'); $self->{tooltip}->add($self->{tooltipLabel}); $self->{tooltip}->signal_connect('button_press_event' => sub { $self->hideTooltip; if ($self->{results}) { shift; $self->{results}->signal_emit('button_press_event', @_); } }); $self->{tooltip}->signal_connect('motion-notify-event' => sub { my ($widget, $event) = @_; my ($x, $y) = ($event->x_root, $event->y_root); my ($xoffset, $yoffset) = $widget->window->get_root_origin; my $allocation = $widget->allocation(); my $x1 = $xoffset + 2 * $allocation->x; my $y1 = $yoffset + 2 * $allocation->y; my $x2 = $x1 + $allocation->width; my $y2 = $y1 + $allocation->height; my $isInWidget = ($x > $x1 && $x < $x2 && $y > $y1 && $y < $y2); return if $isInWidget; if ($self->{results}) { shift; $self->{results}->signal_emit('motion-notify-event', @_); } }); $self->{tooltipDisplayed} = 0; return $self; } sub setModel { my ($self, $model, $fieldsInfo) = @_; if ($self->{results}) { $self->{scrollPanelList}->remove($self->{results}); $self->{results}->destroy; } $self->{fields} = []; my @cols; foreach my $field(@{$model->{resultsFields}}) { push @cols, ($fieldsInfo->{$field}->{displayed} => 'text'); push @{$self->{fields}}, $field; } # Extra column push @cols, ('' => 'text'); push @{$self->{fields}}, 'extra'; $self->{nbCols} = scalar @{$self->{fields}}; $self->{results} = Gtk2::SimpleList->new(@cols); $self->{results}->set_rules_hint(1); $self->{results}->set_headers_clickable(1); $self->{order} = 1; $self->{sort} = ''; for my $i (0..$self->{nbCols} - 1) { $self->{results}->get_column($i)->set_sort_indicator(0); $self->{results}->get_column($i)->set_resizable(1); $self->{results}->get_column($i)->signal_connect('clicked' => sub { $self->sort($self->{fields}->[$i]); }); $self->{results}->get_column($i)->{column_number} = $i; } $self->{scrollPanelList}->add($self->{results}); $self->{results}->signal_connect(row_activated => sub { my ($sl, $path, $column) = @_; $self->response('ok'); }); $self->{results}->signal_connect('motion-notify-event' => sub { my ($widget, $event) = @_; $self->displayTooltip($event); }); $self->{results}->signal_connect('leave-notify-event' => sub { my ($widget, $event) = @_; # It corresponds to a leave of the whole widget not from a single cell $self->hideTooltip if $event->detail eq 'ancestor'; }); $self->{multipleSelectionLabel}->set_markup(''.$self->{parent}->{lang}->{ResultsInfo}.''); } sub sort { my ($self, $type) = @_; my $col = 0; for my $i (0..$self->{nbCols} - 1) { $self->{results}->get_column($i)->set_sort_indicator(0); $col = $i if $self->{fields}->[$i] eq $type; } my @items = @{$self->{items}}; if ($self->{sort} eq $type) { $self->{order} = 1 - $self->{order} } else { $self->{order} = 1; } @items = sort {$a->{$type} cmp $b->{$type}} @items; @items = reverse @items if ! $self->{order}; $self->{results}->get_column($col)->set_sort_indicator(1); $self->{results}->get_column($col)->set_sort_order($self->{order} ? 'ascending' : 'descending'); $self->setList('',@items); $self->{sort} = $type; } sub setList { my ($self, $title, @items) = @_; $self->set_title($self->get_title . ' - '.$title) if $title; $self->{items} = \@items; @{$self->{results}->{data}} = (); $self->{tooltipsStrings} = {}; my $idx = 0; my $col = 0; foreach my $item (@items) { my $infos = []; $col = 0; foreach my $field(@{$self->{fields}}) { my $value = ''; $value = $item->{$field} if exists $item->{$field}; (my $shortField = $value) =~ s/(.{40}).*/$1.../; push @$infos, $shortField."\n"; # We store a tooltip is the text has been truncated $self->{tooltipsStrings}->{$idx}->{$col} = $value if $value ne $shortField; $col++; } $item->{'#'} = $idx if ! exists $item->{'#'}; push @{$self->{results}->{data}}, $infos; #push @{$self->{tooltipsStrings}}, $item->{$self->{fields}->[0]}; $idx++; } $self->{results}->select(0); $self->{results}->columns_autosize; $self->set_default_size(-1,400); } sub displayTooltip { my ($self, $event) = @_; my ($path, $column, $cell_x, $cell_y) = $self->{results}->get_path_at_pos ($event->x, $event->y); if ($path) { my $model = $self->{results}->get_model; my $col = $column->{column_number}; my $row = $path->to_string(); # If a new cell is selected, then hide the tooltip # It'll be re-shown as required by the code down under if ($self->{selectedRow} ne $row or $self->{selectedCol} != $col) { $self->hideTooltip; $self->{selectedRow} = $row; $self->{selectedCol} = $col; } else { return; } if ($row ne '') { # Pick that popup string from our hash #my $str = $popup_hash->{$row}->{$i}; my $str = $self->{tooltipsStrings}->{$row}->{$col}; if ($str) { $self->{tooltipLabel}->set_label($str); if (!$self->{tooltipDisplayed}) { $self->{tooltip}->show_all; Gtk2->grab_add($self->{tooltip}); Gtk2::Gdk->pointer_grab( $self->{tooltip}->window, 1, [qw/button-press-mask button-release-mask pointer-motion-mask/], undef, undef, 0); Gtk2::Gdk->keyboard_grab ($self->{tooltip}->window, 0, 0); $self->{tooltip}->grab_focus; my ($thisx, $thisy) = $self->{tooltip}->window->get_origin; # The window to be a bit away from the mouse pointer. $self->{tooltip}->move($thisx, $thisy-20); $self->{tooltipDisplayed} = 1; } } } return 0; } } sub hideTooltip { my $self = shift; if ($self->{tooltipDisplayed}) { Gtk2->grab_remove($self->{tooltip}); $self->{tooltip}->hide; $self->{tooltipDisplayed} = 0; } } } { package GCImportFieldsDialog; use base 'GCModalDialog'; sub setReadOnly { my ($self, $value) = @_; $self->{readOnly} = $value; my @children = $self->{table}->get_children; foreach (@children) { $_->set_sensitive(!$value) if ($_->get_name eq 'GtkCheckButton') && (!$_->{mandatory}); } $self->set_title($value ? $self->{parent}->{lang}->{ResultsPreview} : $self->{parent}->{lang}->{ImportWindowTitle}); } sub info { my $self = shift; my $fieldsInfo = $self->{parent}->{model}->{fieldsInfo}; if (@_) { my $info = shift; $self->{info} = $info; my @children = $self->{table}->get_children; foreach (@children) { $_->set_text('') if $_->get_name eq 'GtkEntry'; } my $fieldsInfo = $self->{parent}->{model}->{fieldsInfo}; foreach (keys %{$info}) { my $tmp = $info->{$_}; if ($fieldsInfo->{$_}->{type} =~ /list/) { $tmp = GCPreProcess::multipleList($tmp, $fieldsInfo->{$_}->{type}); } if ($fieldsInfo->{$_}->{values}) { $tmp = $self->{parent}->{model}->getDisplayedValue($fieldsInfo->{$_}->{values}, $tmp); } if ($_ ne $self->{urlField}) { $tmp =~ s/\n/ /g; $tmp =~ s/(.{50}).*/$1.../m; } $self->{$_}->set_text($tmp) if $self->{$_}; } } else { my $ignore = $self->{parent}->{ignoreString}; foreach my $field(@{$self->{parent}->{model}->{fieldsNames}}) { next if $fieldsInfo->{$field}->{imported} ne 'true'; next if ($fieldsInfo->{$field}->{type} eq 'url'); if (! $self->{$field.'Cb'}->get_active) { unlink $self->{info}->{$field} if ($fieldsInfo->{$field}->{type} eq 'image') && ($self->{info}->{$field} !~ m|^http://|); $self->{info}->{$field} = $ignore; } } return $self->{info}; } } sub showImage { use File::Temp qw/ :POSIX /; my ($self, $field) = @_; my $location = $self->{info}->{$field}; if ($location =~ m|^http://|) { my ($name,$path,$suffix) = File::Basename::fileparse($location, "\.gif", "\.jpg", "\.jpeg", "\.png"); $self->window->set_cursor(Gtk2::Gdk::Cursor->new('watch')); GCUtils::updateUI; (my $tmpFile = tmpnam) .= $suffix; GCUtils::downloadFile($location, $tmpFile, $self->{parent}); $self->window->set_cursor(Gtk2::Gdk::Cursor->new('left_ptr')); $self->{parent}->launch($tmpFile, 'image', 0, $self); $self->{info}->{$field} = $tmpFile; } else { $self->{parent}->launch($location, 'image', 0, $self); } } sub show { my $self = shift; $self->SUPER::show(); $self->show_all; if ($self->{readOnly}) { $self->{selectAll}->hide; $self->{selectNone}->hide; ($self->action_area->get_children)[1]->hide; } foreach (keys %{$self->{imagesButton}}) { $self->{$_}->hide if $self->{info}->{$_}; $self->{imagesButton}->{$_}->hide if ! $self->{info}->{$_}; } my $response = $self->run; $self->hide; return ($response eq 'ok'); } sub createItem { my ($self, $field, $row, $mandatory) = @_; my $fieldsInfo = $self->{parent}->{model}->{fieldsInfo}; $self->{$field.'Cb'} = new Gtk2::CheckButton($self->{parent}->{model}->getDisplayedText($fieldsInfo->{$field}->{label})); if ($mandatory) { $self->{$field.'Cb'}->set_sensitive(0); $self->{$field.'Cb'}->set_active(1); $self->{$field.'Cb'}->{mandatory} = 1; } $self->{$field} = new Gtk2::Entry; $self->{$field}->set_editable(0); $self->{table}->attach($self->{$field.'Cb'}, 0, 1, $row, $row + 1, 'fill', ['fill', 'expand'], 0, 0); $self->{table}->attach($self->{$field}, 1, 2, $row, $row + 1, ['fill', 'expand'], 'fill', 0, 0); } sub new { my ($proto, $parent) = @_; my $class = ref($proto) || $proto; my $self = $class->SUPER::new($parent, $parent->{lang}->{ImportWindowTitle} ); bless ($self, $class); $self->{parent} = $parent; $self->set_modal(1); $self->set_position('center'); $self->set_default_size(1,500); $self->{table} = new Gtk2::Table(1, 2, 0); $self->{table}->set_row_spacings($GCUtils::halfMargin); $self->{table}->set_col_spacings($GCUtils::margin); $self->{table}->set_border_width($GCUtils::margin); $self->{scrollPanelList} = new Gtk2::ScrolledWindow; $self->{scrollPanelList}->set_policy ('never', 'automatic'); $self->{scrollPanelList}->set_shadow_type('none'); $self->{scrollPanelList}->add_with_viewport($self->{table}); $self->vbox->pack_start($self->{scrollPanelList},1,1,$GCUtils::margin); $self->setModel($parent->{model}); return $self; } sub setModel { my ($self, $model) = @_; my $parent = $self->{parent}; $self->{model} = $model; my $fieldsInfo = $model->{fieldsInfo}; $self->{urlField} = $self->{parent}->{model}->{commonFields}->{url}; foreach ($self->{table}->get_children) { $self->{table}->remove($_); $_->destroy; } my $row = 0; my @picFields; my $field; foreach $field(@{$model->{fieldsNames}}) { next if $fieldsInfo->{$field}->{imported} ne 'true'; next if ($field eq $self->{urlField}); if ($fieldsInfo->{$field}->{type} eq 'image') { push @picFields, $field; next; } $self->createItem($field, $row); $row++; } foreach $field(@picFields) { $self->createItem($field, $row); $self->{imagesButton}->{$field} = new Gtk2::Button($parent->{lang}->{ImportViewPicture}); $self->{imagesButton}->{$field}->signal_connect('clicked' => sub { $self->showImage($field); }); $self->{table}->attach($self->{imagesButton}->{$field}, 1, 2, $row, $row + 1, 'fill', 'fill', 0, 0); $row++; } if ($self->{urlField}) { $self->createItem($self->{urlField}, $row, 1); $row++; } $row++; $self->{selectAll} = new Gtk2::Button($parent->{lang}->{ImportSelectAll}); $self->{selectAll}->signal_connect('clicked' => sub { my @children = $self->{table}->get_children; foreach (@children) { $_->set_active(1) if $_->get_name eq 'GtkCheckButton'; } }); $self->{table}->attach($self->{selectAll}, 0, 1, $row, $row + 1, 'fill', 'fill', 0, 0); $row++; $self->{selectNone} = new Gtk2::Button($parent->{lang}->{ImportSelectNone}); $self->{selectNone}->signal_connect('clicked' => sub { my @children = $self->{table}->get_children; # Remove 2 items corresponding to website to keep it checked splice @children, 2, 2; foreach (@children) { $_->set_active(0) if $_->get_name eq 'GtkCheckButton'; } }); $self->{table}->attach($self->{selectNone}, 0, 1, $row, $row + 1, 'fill', 'fill', 0, 0); } } 1;