diff options
Diffstat (limited to 'lib/gcstar/GCPlugins.pm')
-rw-r--r-- | lib/gcstar/GCPlugins.pm | 1783 |
1 files changed, 1783 insertions, 0 deletions
diff --git a/lib/gcstar/GCPlugins.pm b/lib/gcstar/GCPlugins.pm new file mode 100644 index 0000000..d7acbd5 --- /dev/null +++ b/lib/gcstar/GCPlugins.pm @@ -0,0 +1,1783 @@ +{ + 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('<i>'.$parent->{lang}->{ResultsInfo}.'</i>'); + $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('<i>'.$self->{parent}->{lang}->{ResultsInfo}.'</i>'); + + } + + 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; |