package GCDialogs;

###################################################
#
#  Copyright 2005 Tian
#
#  This file is part of GCfilms.
#
#  GCfilms 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.
#
#  GCfilms 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 GCfilms; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
###################################################

use strict;
use Gtk2;
use utf8;

our @okCancelButtons = ('gtk-cancel'=>'cancel', 'gtk-ok'=>'ok');

eval 'Gtk2::AboutDialog->set_email_hook(undef, undef)';
my $hasAboutDialog = ($@ ? 0 : 1);

{
    package GCAboutDialog;
    if (!$hasAboutDialog)
    {
        use base "Gtk2::Dialog";
    }
    
    sub show
    {
        my $self = shift;

        if ($hasAboutDialog)
        {
            $self->{about}->set_position('center-on-parent');           
            $self->{about}->run;
        }
        else
        {
            $self->SUPER::show();
            $self->show_all;
            my $code = $self->run;
            $self->hide;
        }
    }

    sub changeStyle
    {
        my $self = shift;
        $self->{vBox}->set_border_width(0);
        ($self->{vBox}->get_children)[1]->set_border_width($self->{border});
    }

    sub new
    {
        my ($proto, $parent, $version) = @_;
        my $class = ref($proto) || $proto;
        
        my $self;
        
        my $logoFile = $parent->{logosDir}.'about.png';
        
        if ($hasAboutDialog)
        {
            $self = {
                about => new Gtk2::AboutDialog,
                parent => $parent
            };
            bless ($self, $class);
            
            open LICENSE, "<".$ENV{GCF_SHARE_DIR}.'/LICENSE';
            my $license = do {local $/; <LICENSE>};
            close LICENSE;
            my @authors = split m/\n/, $parent->{lang}->{AboutWho};
            
            $self->{about}->set_transient_for($parent);
            $self->{about}->set_url_hook( sub {
                my ($widget, $url) = @_;
    	        $self->{parent}->openUrl($url);
            });

            if (-f $logoFile)
            {
                my $logo = Gtk2::Gdk::Pixbuf->new_from_file($logoFile);
                $self->{about}->set_logo($logo);
            }
            $self->{about}->set_name('GCfilms');
            $self->{about}->set_comments($parent->{lang}->{AboutDesc});
            $self->{about}->set_version($version);
            $self->{about}->set_authors(@authors);
            $self->{about}->set_documenters(("",'Tian','http://home.gna.org/gcfilms/doc'));
            $self->{about}->set_artists("",$parent->{lang}->{AboutDesign}, 'http://le-spektre.org/');
            $self->{about}->set_copyright($parent->{lang}->{AboutLicense});
            $self->{about}->set_license($license);
            $self->{about}->set_translator_credits("\n".$parent->{lang}->{AboutTranslation});
            $self->{about}->set_website("http://home.gna.org/gcfilms/");
            $self->{vBox} = $self->{about}->get_children;
            $self->{border} = $self->{vBox}->get_border_width;
            if ($self->{about}->signal_query('style_set'))
            {
                $self->{about}->signal_connect('style_set' => sub {$self->changeStyle });
            }
            $self->changeStyle;
        }
        else
        {
            $self  = $class->SUPER::new($parent->{lang}->{AboutTitle},
                                           $parent,
                                           [qw/modal destroy-with-parent/],
                                           'gtk-ok' => 'ok'
                                          );
            bless ($self, $class);
    	    my $labelDesc = Gtk2::Label->new($parent->{lang}->{AboutDesc});
    	    my $labelVersion = Gtk2::Label->new($parent->{lang}->{AboutVersion}.' '.$version);
    	    #my $labelTeam = Gtk2::Label->new($parent->{lang}->{AboutTeam});
            
            my $who = new Gtk2::Label($parent->{lang}->{AboutWho});
            
            my $labelTranslation = Gtk2::Label->new($parent->{lang}->{AboutTranslation});
    	    my $labelLicense = Gtk2::Label->new($parent->{lang}->{AboutLicense});
    	    $labelLicense->set_justify('center');
    	    my $button = Gtk2::Button->new_with_mnemonic('_http://home.gna.org/gcfilms/');
    	    $button->child->set_padding(10,0);
    	    $button->signal_connect('clicked', sub {
    	        my ($widget, $parent) = @_;
    	        (my $url = $widget->get_label) =~ s/^_//;
    	        $parent->openUrl($url);
    	    }, $parent);
       	    my $labelDesign = Gtk2::Label->new($parent->{lang}->{AboutDesign});
    	    my $designButton = Gtk2::Button->new_with_mnemonic('http://www.le-spektre.org/');
    	    $designButton->child->set_padding(10,0);
    	    $designButton->signal_connect('clicked', sub {
    	        my ($widget, $parent) = @_;
    	        (my $url = $widget->get_label) =~ s/^_//;
    	        $parent->openUrl($url);
    	    }, $parent);
    
    	    $self->vbox->set_homogeneous(0);
    	    if (-f $logoFile)
            {
                my $image = Gtk2::Image->new_from_file($logoFile);
                $self->vbox->pack_start($image, 0, 0, 0);
            }
    	    $self->vbox->pack_start($labelDesc, 1, 1, 4);
    	    $self->vbox->pack_start($labelVersion, 1, 1, 4);
    	    $self->vbox->pack_start($labelLicense, 1, 1, 4);
            $self->vbox->pack_start(Gtk2::HSeparator->new, 1, 1, 4);    	    
    	    my $hbox = new Gtk2::HBox(0,0);
    	    $hbox->pack_start($button, 1, 0, 10);
    	    $self->vbox->pack_start($hbox, 0, 0, 4);
    	    my $hboxDesign = new Gtk2::HBox(0,0);
    	    $hboxDesign->pack_start($designButton, 1, 0, 10);
    	    $self->vbox->pack_start($labelDesign, 1, 1, 4);
    	    $self->vbox->pack_start($hboxDesign, 0, 0, 4);
    	
    	    my $teamButton = Gtk2::Button->new($parent->{lang}->{AboutTeam});
    	    $teamButton->signal_connect('clicked' => sub {
    	       my $dialog = Gtk2::MessageDialog->new($self,
							   [qw/modal destroy-with-parent/],
							   'info',
							   'ok',
							   $parent->{lang}->{AboutWho});
    	       $dialog->run;
    	       $dialog->destroy;
    	    });
    	    $self->action_area->pack_start($teamButton,0,0,0);
    	    $self->action_area->reorder_child($teamButton,0);
    	
    	
    	    #$self->vbox->set_size_request(400,-1);
    	    $self->set_resizable(0);
    		$self->set_position('center-always');
        }

	    return $self;
    }
}

{
    package GCDependenciesDialog;
    use base "Gtk2::Dialog";

    sub show
    {
        my $self = shift;
        $self->SUPER::show();
        $self->show_all;
        my $code = $self->run;
        $self->hide;
    }

    sub checkDependencies
    {
        my $self = shift;
    
        my $pref = 'GC';
    
        my @optionals = ();
        my $optionalsModules = {};
    
        my @files = glob $ENV{GCF_LIB_DIR}.'/*.pm';
        push @files, glob $ENV{GCF_LIB_DIR}.'/GCPlugins/*.pm';
        push @files, glob $ENV{GCF_LIB_DIR}.'/GCExport/*.pm';
        push @files, glob $ENV{GCF_LIB_DIR}.'/GCImport/*.pm';
        foreach my $file(@files)
        {
            open FILE, $file;
            while (<FILE>)
            {
                if ((/eval.*?[\"\']use\s*(.*?)[\"\'];/) && ($1 !~ /base|vars|locale|integer|^lib|utf8|\$opt|strict|^$pref/))
                #"
                {
                    push (@optionals, $1);
                    push @{$optionalsModules->{$1}}, $file;
                }
    
            }
            close FILE;
        }
    
        my %saw;
        @saw{@optionals} = ();
        @optionals = sort keys %saw;
    
        $self->{tableDepend}->resize(1 +  scalar(@optionals),2);
    
        my @missings = ();
        my @oks = ();
        foreach my $opt(sort @optionals)
        {
            my $label1 = new Gtk2::Label($opt);
            my $label2 = new Gtk2::Label;

            eval "use $opt";
            if ($@)
            {
                my $value;
                foreach my $module (@{$optionalsModules->{$opt}})
                {
                    $module =~ s/.*?GC([^\/]*?)\.pm$/$1/;
                    $value .= $module.",\n";
                }
                $value =~ s/,\n$//;
                $label2->set_markup("<span color='orange' weight='bold'>".$self->{parent}->{lang}->{InstallMissingFor}." $value</span>");
                $label2->set_line_wrap(1);
                $label2->set_justify('left');
                push @missings, [$label1, $label2];
            }
            else
            {
                $label2->set_markup("<span color='green' weight='bold'>".$self->{parent}->{lang}->{InstallOK}."</span>");
                push @oks, [$label1, $label2];
            }

        }

        my $i = 0;
        my $labelOpt = new Gtk2::Label;
        $labelOpt->set_markup('<b>'.$self->{parent}->{lang}->{InstallOptional}.'</b>');
        $self->{tableDepend}->attach($labelOpt, 0, 2, $i, $i+1, 'expand', 'fill', 0, 10);
        $i++;
        
        foreach (@missings)
        {
            $self->{tableDepend}->attach($_->[0], 0, 1, $i, $i+1, 'fill', 'fill', 0, 0);
            $self->{tableDepend}->attach($_->[1], 1, 2, $i, $i+1, 'fill', 'fill', 0, 0);
        
            $i++;
        }
        foreach (@oks)
        {
            $self->{tableDepend}->attach($_->[0], 0, 1, $i, $i+1, 'fill', 'fill', 0, 0);
            $self->{tableDepend}->attach($_->[1], 1, 2, $i, $i+1, 'fill', 'fill', 0, 0);
        
            $i++;
        }
    }

    sub new
    {
        my ($proto, $parent) = @_;
        my $class = ref($proto) || $proto;
        my $self  = $class->SUPER::new($parent->{lang}->{InstallDependencies},
                              $parent,
                              [qw/modal destroy-with-parent/],
                              'gtk-ok' => 'ok'
                              );
        bless($self, $class);

        $self->{parent} = $parent;

        $self->{tableDepend} = new Gtk2::Table(1, 2, 0);
        $self->{tableDepend}->set_row_spacings(10);
        $self->{tableDepend}->set_col_spacings(20);
        $self->{tableDepend}->set_border_width(10);
        $self->{scrollDepend} = new Gtk2::ScrolledWindow;
        $self->{scrollDepend}->set_policy ('automatic', 'automatic');
        $self->{scrollDepend}->add_with_viewport($self->{tableDepend});
        $self->{scrollDepend}->set_size_request(300, 200);
        $self->vbox->pack_start($self->{scrollDepend},1,1,10);

        $self->checkDependencies;

        return $self;
    }
}

{
    package GCImageDialog;
    use base "Gtk2::Dialog";

    sub show
    {
        my $self = shift;
        $self->SUPER::show();
        $self->show_all;
        my $code = $self->run;
        $self->hide;
    }

    sub new
    {
        my ($proto, $parent, $file) = @_;
        my $class = ref($proto) || $proto;
        my $title = $parent->{lang}->{ImportViewPicture};
        $title = $parent->{parent}->{lang}->{ImportViewPicture} if $parent->{parent};
        my $self  = $class->SUPER::new($title,
                                       $parent,
                                       [qw/modal destroy-with-parent/],
                                       'gtk-ok' => 'ok'
                                      );
        bless($self, $class);

        $self->{parent} = $parent;

        my $image = Gtk2::Image->new_from_file($file);
        $self->vbox->pack_start($image,0,0,0);

        return $self;
    }
}


{
    package GCDateSelectionDialog;
    use base "Gtk2::Dialog";

    sub show
    {
        my $self = shift;
        $self->SUPER::show();
 
        my $response = $self->run;
        $self->hide;
        return ($response eq 'ok');
    }

    sub date
    {
        my $self = shift;
        if (@_)
        {
            $_ = shift;
            return if ! $_;
            my ($day, $month, $year) = split m/\//;
            $self->{calendar}->select_month($month - 1, $year);
            $self->{calendar}->select_day($day);
        }
        else
        {
            my ($year, $month, $day) = $self->{calendar}->get_date;
            $day = ($day < 10 ? '0' : '').$day;
            $month++;
            $month = ($month < 10 ? '0' : '').$month;
            return join '/', $day, $month, $year;
        }
    }
    
    sub new
    {
        my ($proto, $parent) = @_;
        my $class = ref($proto) || $proto;
        my $self  = $class->SUPER::new($parent->{lang}->{PanelLendDateSelect},
                              $parent,
                              [qw/modal destroy-with-parent/],
                              @GCDialogs::okCancelButtons
                              );

        $self->{calendar} = new Gtk2::Calendar;
        
        $self->vbox->pack_start($self->{calendar}, 0, 0, 5);
        $self->vbox->show_all;
        
        $self->set_default_size(1,1);

        bless ($self, $class);
        return $self;
    }
}

{
    package GCRenameDialog;
    use base "Gtk2::Dialog";
    
    sub show
    {
        my $self = shift;
        
        $self->setTypes($self->{parent}->{movies}->getHistory('type'));
        
        $self->SUPER::show();
        $self->show_all;
        my $response = $self->run;
        $self->{newName} = undef;
        $self->{oldName} = undef;
        if ($response eq 'ok')
        {
            my @children = $self->{type}->get_children;
            $self->{oldName} = $children[0]->get_text;
            $self->{newName} = $self->{new}->get_text;
        }
        $self->hide;
    }
    
    sub names
    {
        my $self = shift;
        
        return $self->{oldName}, $self->{newName} ;
    }

    sub setTypes
    {
        my ($self, $values) = @_;

        my $current = ($self->{type}->get_children)[0]->get_text;
        $self->{type}->set_popdown_strings(@$values);
        ($self->{type}->get_children)[0]->set_text($current);
    }
    
    sub new
    {
        my ($proto, $parent) = @_;
        my $class = ref($proto) || $proto;
        my $self  = $class->SUPER::new($parent->{lang}->{RenameTitle},
                              $parent,
                              [qw/modal destroy-with-parent/],
                              @GCDialogs::okCancelButtons
                              );

        $self->{parent} = $parent;
                              
        my $table = new Gtk2::Table(2,2,0);
        $table->set_row_spacings(10);
        $table->set_col_spacings(10);
        $table->set_border_width(20);

        my $typeLabel = new Gtk2::Label($parent->{lang}->{RenameOld});
        $typeLabel->set_alignment(0,0.5);
        $self->{type} = Gtk2::Combo->new;
        ($self->{type}->get_children)[0]->set_editable(0);
        $table->attach($typeLabel, 0, 1, 0, 1, 'fill', 'fill', 0, 0);
        $table->attach($self->{type}, 1, 2, 0, 1, 'fill', 'expand', 0, 0);
                              
        my $newLabel = new Gtk2::Label($parent->{lang}->{RenameNew});
        $newLabel->set_alignment(0,0.5);
        $self->{new} = new Gtk2::Entry;
        $table->attach($newLabel, 0, 1, 1, 2, 'fill', 'fill', 0, 0);
        $table->attach($self->{new}, 1, 2, 1, 2, 'fill', 'expand', 0, 0);
        
        $self->vbox->pack_start($table, 1, 1, 5);
        $self->vbox->show_all;

        bless ($self, $class);
        return $self;
    }
}

{
    #Class that is used to let user select
    #item from a list and order them.
    package GCDoubleListDialog;

    use base "Gtk2::Dialog";
    
    sub init
    {
        my $self = shift;
        $self->setListData($self->getData) if !$self->{initialized};
        $self->{initialized} = 1;
    }
    
    sub show
    {
        my $self = shift;

        $self->setListData($self->getData);

	    $self->SUPER::show();
        $self->show_all;
        
        my $response = $self->run;

        if ($response eq 'ok')
        {
           $self->saveList(\@{$self->{usedArray}});
        }
        $self->hide;
        return $response;
    }
    
    
    sub moveFromTo
    {
        my ($self, $from, $to) = @_;
        
        my $fromId = ($self->{$from}->get_selected_indices)[0];
        my $fromString = $self->{$from.'Array'}->[$fromId];
        return if !$fromString;
        my $toId = ($self->{$to}->get_selected_indices)[0];
        my $toTotal = scalar @{$self->{$to.'Array'}};
        $toId = $toTotal if $toId eq '';
        $toId++ if $toId < $toTotal;
        $toId = 0 if ($toId < 0);

        GCUtils::mySimpleListSplice($self->{$from}, $fromId, 1);
        GCUtils::mySimpleListSplice($self->{$to}, $toId, 0, $fromString);
        splice(@{$self->{$from.'Array'}}, $fromId, 1);
        splice(@{$self->{$to.'Array'}}, $toId, 0, $fromString);
        
        if ($to eq 'unused')
        {
            my @tmpSortedArray = sort @{$self->{unusedArray}};
            $self->{unusedArray} = \@tmpSortedArray;
            @{$self->{unused}->{data}} = ();
            my $i = 0;
            $toId = 0;
            foreach (@tmpSortedArray)
            {
                $toId = $i if $_ eq $fromString;
                my @item = [$_];
                push @{$self->{unused}->{data}}, @item;
                $i++;
            }
        }
        $self->{$to}->select($toId);
        $fromId-- if $fromId >= scalar @{$self->{$from.'Array'}};
        $self->{$from}->select($fromId);
        $self->{$from}->grab_focus;
    }
    
    sub moveDownUp
    {
        my ($self, $dir) = @_;
        my $currentId = ($self->{used}->get_selected_indices)[0];
        my $newId = $currentId + $dir;
        return if ($newId < 0) || ($newId >= scalar @{$self->{usedArray}});
        ($self->{usedArray}->[$currentId], $self->{usedArray}->[$newId])
         = ($self->{usedArray}->[$newId], $self->{usedArray}->[$currentId]);
        @{$self->{used}->{data}} = ();
        foreach (@{$self->{usedArray}})
        {
            my @item = [$_];
            push @{$self->{used}->{data}}, @item;
        }
        $self->{used}->select($newId);
    }
    
    sub setListData
    {
        my ($self, $new) = @_;
        my $initial = $self->getInitData;
        $self->{initialized} = 1;
        my %tmpMap;
        $tmpMap{$_} = 1 foreach (@$initial);
        $self->{usedArray} = $new;
        delete $tmpMap{$_} foreach (@$new);
        my @tmpArray = sort keys %tmpMap;
        $self->{unusedArray} = \@tmpArray;
        
        @{$self->{unused}->{data}} = ();
        push @{$self->{unused}->{data}}, $_ foreach (@{$self->{unusedArray}});
        @{$self->{used}->{data}} = ();
        push @{$self->{used}->{data}}, $_ foreach (@{$self->{usedArray}});
    }
           
    sub clearList
    {
        my $self = shift;
        
        $self->setListData(());
    }
    sub fillList
    {
        my $self = shift;
        my @array = sort @{$self->getInitData};
        $self->setListData(\@array);
    }
                            
    sub new
    {
        my ($proto, $parent, $title) = @_;
        my $class = ref($proto) || $proto;
        my $self  = $class->SUPER::new($title,
                              $parent,
                              [qw/modal destroy-with-parent/],
                              @GCDialogs::okCancelButtons
                              );
        bless ($self, $class);

	        $self->{parent} = $parent;
        $self->{options} = $parent->{options};

        $self->{initialized} = 0;

        my $hboxMain = new Gtk2::HBox(0,0);

        #list containing unused items
        $self->{unused} = new Gtk2::SimpleList(
            $self->getUnusedLabel => "text"
        );
        $self->{scrollPanelUnused} = new Gtk2::ScrolledWindow;
        $self->{scrollPanelUnused}->set_policy ('never', 'automatic');
        $self->{scrollPanelUnused}->set_shadow_type('etched-in');
        $self->{scrollPanelUnused}->add($self->{unused});

        my $vboxChange = new Gtk2::VBox(1,1);
        my $tmpVbox = new Gtk2::VBox(0,0);
        my $toRight = new Gtk2::Button('->');
        $toRight->remove($toRight->child);
        $toRight->add(Gtk2::Image->new_from_stock('gtk-go-forward', 'button'));
        $toRight->signal_connect('clicked' => sub {
            $self->moveFromTo('unused', 'used');
        });
        my $toLeft = new Gtk2::Button('<-');
        $toLeft->remove($toLeft->child);
        $toLeft->add(Gtk2::Image->new_from_stock('gtk-go-back', 'button'));
        $toLeft->signal_connect('clicked' => sub {
            $self->moveFromTo('used', 'unused');
        });
        $tmpVbox->pack_start($toRight,0,0,10);
        $tmpVbox->pack_start($toLeft,0,0,10);
        $vboxChange->pack_start($tmpVbox,1,0,0);
        
        #list containing used items
        $self->{used} = new Gtk2::SimpleList(
            $self->getUsedLabel => "text"
        );
        $self->{scrollPanelUsed} = new Gtk2::ScrolledWindow;
        $self->{scrollPanelUsed}->set_policy ('never', 'automatic');
        $self->{scrollPanelUsed}->set_shadow_type('etched-in');
        $self->{scrollPanelUsed}->add($self->{used});

        $self->{unused}->signal_connect ('row-activated' => sub {
            $self->moveFromTo('unused', 'used');
        });
        $self->{used}->signal_connect ('row-activated' => sub {
            $self->moveFromTo('used', 'unused');
        });
                     
        my $vboxMove = new Gtk2::VBox(0,0);
        my $toUp = new Gtk2::Button('^');
        $toUp->remove($toUp->child);
        $toUp->add(Gtk2::Image->new_from_stock('gtk-go-up', 'button'));
        $toUp->signal_connect('clicked' => sub {
            $self->moveDownUp(-1);
        });
        my $toDown = new Gtk2::Button('_');
        $toDown->remove($toDown->child);
        $toDown->add(Gtk2::Image->new_from_stock('gtk-go-down', 'button'));
        $toDown->signal_connect('clicked' => sub {
            $self->moveDownUp(1);
        });
        $vboxMove->pack_start($toUp, 0, 0, 10);
        $vboxMove->pack_start($toDown, 0, 0, 10);
                    
        $hboxMain->pack_start($self->{scrollPanelUnused},1,1,5);
        $hboxMain->pack_start($vboxChange,0,0,5);
        $hboxMain->pack_start($self->{scrollPanelUsed},1,1,5);
        $hboxMain->pack_start($vboxMove,0,0,5);
        
        $self->{hboxAction} = new Gtk2::HBox(1,0);
        
        $self->vbox->pack_start($hboxMain, 1, 1, 10);
        $self->vbox->pack_start($self->{hboxAction}, 0, 0, 5);
        
        $self->set_default_size(-1,400);
        $self->{scrollPanelUnused}->set_size_request(150,-1);
        $self->{scrollPanelUsed}->set_size_request(150,-1);
        
        return $self;
    }
}

{
    #Class that is used to let user select
    #fields needed in export.
    package GCFieldsSelectionDialog;
    use base qw/GCDoubleListDialog/;
    
    sub getInitData
    {
        my $self = shift;
        my @array;
        
        @array = values %{$self->{parent}->{lang}->{FieldsList}};
        return \@array;
    }
    
    sub getData
    {
        my $self = shift;
        
        my @array;
        foreach (@{$self->{parent}->{fields}})
        {
            push @array, $self->{parent}->{lang}->{FieldsList}->{$_};
        }
        
        return \@array;
    }
    
    sub saveList
    {
        my ($self, $list) = @_;
        
        my @array;
        foreach (@{$list})
        {
            push @array, $self->{fieldNameToId}->{$_};
        }
        $self->{parent}->{fields} = \@array;
    }
             
    sub getUnusedLabel
    {
        my $self = shift;
        
        return $self->{parent}->{lang}->{ImportExportFieldsUnused};
    }
    sub getUsedLabel
    {
        my $self = shift;
        
        return $self->{parent}->{lang}->{ImportExportFieldsUsed};
    }           
            
    sub new
    {
        my ($proto, $parent, $title, $preList) = @_;
        my $class = ref($proto) || $proto;
        my $self  = $class->SUPER::new(
                                $parent,
                                $title
                            );

        bless ($self, $class);
        
        my $fillButton = new Gtk2::Button($parent->{lang}->{ImportExportFieldsFill});
        $fillButton->signal_connect('clicked' => sub {
            $self->fillList;
        });
        my $clearButton = new Gtk2::Button($parent->{lang}->{ImportExportFieldsClear});
        $clearButton->signal_connect('clicked' => sub {
            $self->clearList;
        });            
        
        $self->{hboxAction}->pack_start($fillButton,1,1,10);
        $self->{hboxAction}->pack_start($clearButton,1,1,10);
        
        $self->{fieldNameToId} = {};
        while (my ($key, $value) = each %{$self->{parent}->{lang}->{FieldsList}})
        {
            $self->{fieldNameToId}->{$value} = $key;
        }
        
        $self->{scrollPanelUnused}->set_size_request(200,-1);
        $self->{scrollPanelUsed}->set_size_request(200,-1);        
        $self->fillList if ! $preList;
        $self->setListData($preList) if $preList;
        $self->saveList(\@{$self->{usedArray}});
        return $self;
    }
}


{
    package GCExportImportDialog;
    use base "Gtk2::Dialog";

    sub selectFile
    {
        my ($widget, $self) = @_;
        
        my $dialog;
        if ($self->{module}->wantsDirectorySelection)
        {
            $dialog = $self->{directoryDialog};
        }
        else
        {
            $dialog = $self->{fileDialog};
        }        
        
        $dialog->set_filename($self->{file}->get_text);
        $dialog->set_pattern_filter($self->{module}->getFilePatterns)
            if ($self->{type} eq 'import');
        
		my $response = $dialog->run;
		if ($response eq 'ok')
		{
	            $self->{file}->set_text($dialog->get_filename);
		}
        $dialog->hide;
    }

    sub show
    {
        my $self = shift;
        $self->SUPER::show();
        $self->show_all;
        
        $self->{fileVbox}->hide if ! $self->{module}->wantsFileSelection;
        
        $self->resize(1,1);
        my $ok = 0;
        while (!$ok)
        {
            my $response = $self->run;
            if ($response eq 'ok')
            {
                if (($self->{module}->wantsFieldsSelection)
                    && (scalar @{$self->{fields}} == 0))
                {
                    my $dialog = Gtk2::MessageDialog->new($self,
                                                              [qw/modal destroy-with-parent/],
                                                              'error',
                                                              'ok',
                                                              $self->{parent}->{lang}->{ImportExportFieldsEmpty});

                    $dialog->set_position('center-on-parent');
                    $dialog->run();
                    $dialog->destroy;
                    next;
                }
                my $file = $self->{file}->get_text;
                if ($file || ! $self->{module}->wantsFileSelection)
                {
                    my %options = $self->getOptions;     
                    $self->addOptions(\%options);
                    $options{file} = $file;
                    $options{lang} = $self->{parent}->{lang};
                    $options{fields} = $self->{fields};
                    $options{originalList} = $self->{parent}->{movies};
                    $options{parent} = $self->{parent};
                    
                    my $info = $self->{module}->process(\%options);
                    if ($info)
                    {
                        my $dialog = Gtk2::MessageDialog->new($self,
                                                              [qw/modal destroy-with-parent/],
                                                              'info',
                                                              'ok',
                                                              $info);

                        $dialog->set_position('center-on-parent');
                        $dialog->run();
                        $dialog->destroy ;
                    }
                }
                else
                {
                    my $dialog = Gtk2::MessageDialog->new($self,
                                                          [qw/modal destroy-with-parent/],
                                                          'error',
                                                          'ok',
                                                          $self->{parent}->{lang}->{ImportExportFileEmpty});

                    $dialog->set_position('center-on-parent');
                    $dialog->run();
                    $dialog->destroy;
                
                    next;
                }
            }
            $ok = 1;
        }
        $self->hide;
    }

    sub setModule
    {
        my ($self, $module) = @_;

        $self->set_title($self->{title}." [".$module->getName."]");
        
        foreach ($self->{optionsVbox}->get_children)
        {
            $self->{optionsVbox}->remove($_);
        }
        
        $self->{module} = $module;
        my %options;
        my $option;
        foreach $option (@{$module->getOptions})
        {
            my $label = $self->{parent}->{lang}->{$option->{label}};
            my $widget;
            my $vExpand = 0;
            my $type = $option->{type};
            my $value = ((exists $module->{options}) ? $module->{options}->{$option->{name}} : $option->{default});
            if ($type eq 'checkBox')
            {
                $widget = new Gtk2::CheckButton($label);
                $widget->set_active($value);
            }
            elsif ( ($type eq 'shortText') || 
                      ($type eq 'longText') ||
                      ($type eq 'number') ||
                      ($type eq 'list'))
            {
                my $hExpand = 0;
                $widget = new Gtk2::HBox(0,0);
                $widget->pack_start(new Gtk2::Label($label), 0,0,0);
                my $in;

                if ($type eq 'shortText')
                {
                    $in = new Gtk2::Entry;
                    $in->set_text($value);
                    $hExpand = 1;
                }
                elsif ($type eq 'longText')
                {
                    my $text = new Gtk2::TextView;
                    $text->set_editable(1);
                    $text->set_wrap_mode('word');
                    $in = new Gtk2::ScrolledWindow;
                    $in->set_border_width(2);
                    $in->set_shadow_type('in');
                    $in->set_policy('automatic', 'automatic');
                    $in->set_size_request(-1,$option->{height});
                    $in->add($text);
                    $hExpand = 1;
                    $vExpand = 1;
                }
                elsif ($type eq 'number')
                {
                    my  $adj = Gtk2::Adjustment->new($value, $option->{min}, $option->{max}, 1, 1, 0) ;
                    $in = new Gtk2::SpinButton($adj, 0, 0);
                }
                elsif ($type eq 'list')
                {
                    $in = new Gtk2::OptionMenu();
                    my $menu = new Gtk2::Menu();
                    my @values = split m/,/, $option->{valuesList};
                    my $i = 0;
                    my $current;
                    foreach (@values)
                    {
                        my $label = $_;
                        $label = $self->{lang}->{$_}
                            if (exists $self->{lang}->{$_});
                        my $item = Gtk2::MenuItem->new_with_label($label);
                        $current = $i if ($_ eq $value);
                        $menu->append( $item);
                        $i++;
                    }
                    $menu->set_active($current);
                    $in->set_menu($menu);
                }
                $widget->pack_start($in, $hExpand,$hExpand,5);
                if ($option->{buttonLabel})
                {
                    my $button = Gtk2::Button->new($self->{lang}->{$option->{buttonLabel}});
                    $button->signal_connect('clicked' => $option->{buttonCallback}, [$self,$in]);
                    $widget->pack_start($button, 0, 0, 5);
                }
            }
            elsif (($type eq 'fileSelection') || ($type eq 'colorSelection'))
            {
                $widget = new Gtk2::HBox(0,0);
                $widget->pack_start(new Gtk2::Label($label), 0,0,0);
                my $entry = new Gtk2::Entry;
                $entry->set_text($value);
                $widget->pack_start($entry, 1,1,5);
                my $stock;
                my $callback;
                if ($type eq 'fileSelection')
                {
                    $stock = 'gtk-open';
                    $callback = sub {
                        my $dialog = new GCFileChooserDialog($label, $self, 'open');
                        $dialog->set_filename($entry->get_text);
                        my $response = $dialog->run;
                        if ($response eq 'ok')
                        {
                            $entry->set_text($dialog->get_filename);
                        }
                        $dialog->destroy;
                    }
                }
                else
                {
                    $stock = 'gtk-select-color';
                    $callback = sub {
                        my $dialog = new Gtk2::ColorSelectionDialog($label);
                        my $previous = Gtk2::Gdk::Color->parse($entry->get_text);
                        $dialog->colorsel->set_current_color($previous) if $previous;
                        my $response = $dialog->run;
                        if ($response eq 'ok')
                        {
                            my $color = $dialog->colorsel->get_current_color;
                            my $red = $color->red / 257;
                            my $blue = $color->blue / 257;
                            my $green = $color->green / 257;
                            my $colorString = sprintf ("#%X%X%X", $red, $blue, $green);
                            $entry->set_text($colorString);
                        }
                        $dialog->destroy;
                    }
                }
                
                my $button = Gtk2::Button->new_from_stock($stock);
                $button->signal_connect('clicked' => $callback);
                $widget->pack_start($button, 0,0,0);
            }
            
            $self->{optionsVbox}->pack_start($widget,$vExpand,$vExpand,5);
            $options{$option->{name}} = $widget;
        }
        
        $self->{optionsVbox}->pack_start(new Gtk2::HSeparator, 1, 1, 5)
            if ($module->wantsImagesSelection) || ($module->wantsFieldsSelection);
        
        if ($module->wantsImagesSelection)
        {
            my $value = ((exists $module->{options}) ? $module->{options}->{withPictures} : 1);
            $options{withPictures} = new Gtk2::CheckButton($self->{parent}->{lang}->{ExportSQLWithPictures});
            $options{withPictures}->set_active($value);
            $self->{optionsVbox}->pack_start($options{withPictures},0,0,0);
            $options{withPictures}->show;
        }
        
        if ($module->wantsFieldsSelection)
        {
            my $hboxFields = new Gtk2::HBox(0,0);
            $hboxFields->set_border_width(0);
            my $button = new Gtk2::Button($self->{fieldsButtonLabel});
            $self->{parent}->{tooltips}->set_tip($button,
                                     $self->{fieldsTip});
            $hboxFields->pack_start($button,1,1,20);
            my $margin = 0;
            $margin = 5 if ($module->wantsImagesSelection);
            $self->{optionsVbox}->pack_start($hboxFields,0,0,$margin);
            $button->signal_connect('clicked' => sub {
                $self->{fieldsDialog}->show;
            });
        }

        $self->{options} = \%options;
        $self->{optionsVbox}->show_all;
    }
    
    sub getOptions
    {
        my $self = shift;
        my %result;
        
        foreach (keys %{$self->{options}})
        {
            my $value;
            my $widget = $self->{options}->{$_};
            if ($widget->isa('Gtk2::HBox'))
            {
                $widget = ($widget->get_children)[1];
                if ($widget->isa('Gtk2::Entry'))
                {
                    $value = $widget->get_text;
                }
                elsif ($widget->isa('Gtk2::SpinButton'))
                {
                    $value = $widget->get_value;
                }
                elsif ($widget->isa('Gtk2::OptionMenu'))
                {
                    $value = $widget->child->get_label;
                }
                elsif ($widget->isa('Gtk2::ScrolledWindow'))
                {
                    my $buffer = $widget->child->get_buffer;
                    $value = $buffer->get_text($buffer->get_start_iter,
                                               $buffer->get_end_iter, 1);
                }
            }
            elsif ($widget->isa('Gtk2::CheckButton'))
            {
                $value = $widget->get_active
            }
            $result{$_} = $value;
        }
        
        return %result;
    }
    
    sub new
    {
        my ($proto, $parent, $title, $type) = @_;
        my $class = ref($proto) || $proto;
        my $self  = $class->SUPER::new($title,
                              $parent,
                              [qw/modal destroy-with-parent/],
                              @GCDialogs::okCancelButtons
                              );

        $self->{parent} = $parent;
        $self->{title} = $title;
        $self->{lang} = $parent->{lang};
        $self->{fields} = [];
        $self->{type} = $type;
        
        $self->{optionsVbox} = new Gtk2::VBox(0,0);

        $self->{fileVbox} = new Gtk2::VBox(0,0);

        my $sep = new Gtk2::HSeparator;
        my $hbox = new Gtk2::HBox(0,0);
        my $labelFile = new Gtk2::Label($parent->{lang}->{ImportExportFile});
        $self->{file} = new Gtk2::Entry;
        my $button = Gtk2::Button->new_from_stock('gtk-open');
        $button->signal_connect('clicked', \&selectFile, $self);
        $hbox->pack_start($labelFile,0,0,5);
        $hbox->pack_start($self->{file},1,1,5);
        $hbox->pack_start($button,0,0,5);

        $self->{fileVbox}->pack_start($sep, 0, 0, 2);
        $self->{fileVbox}->pack_start($hbox, 0, 0, 10);

        $self->vbox->set_homogeneous(0);
        $self->vbox->pack_start($self->{optionsVbox},1,1,10);
        $self->vbox->pack_start($self->{fileVbox}, 0, 0, 0);
        

        $type = ($type eq 'import') ? 'open' : 'save';
        my $withFilter = ($self->{type} eq 'import') ? 1 : 0;
        $self->{fileDialog} = new GCFileChooserDialog($parent->{lang}->{ImportExportSave}, $parent, $type, $withFilter);
        $self->{directoryDialog} = new GCFileChooserDialog($parent->{lang}->{ImportExportSave}, $parent, 'select-folder', 0);

        bless ($self, $class);
        return $self;
    }
    
}

{
    package GCFileChooserDialog;
    use GCGraphicComponents;
    use File::Basename;
    use File::Spec;

    sub new
    {
        my ($proto, $title, $parent, $action, $withFilter, $autoAppend) = @_;
        my $class = ref($proto) || $proto;
        my $self  = {};
        $self->{action} = $action;
        $self->{parent} = $parent;
        $self->{ignoreFilter} = 1;
        $self->{autoAppend} = 0;
        eval { my $dialog = new Gtk2::FileChooserDialog($title, $parent, $action) };
        if ($@)
        {
            $self->{dialog}  = new Gtk2::FileSelection($title);
            $self->{dialog}->main_vbox->show_all;
            my @vboxChildren = $self->{dialog}->main_vbox->get_children;
            my @buttonBoxChildren = $vboxChildren[0]->get_children;
            if ($action eq 'select-folder')
            {
                $buttonBoxChildren[1]->hide;
                $buttonBoxChildren[2]->hide;
                $self->{dialog}->selection_entry->hide;
                $self->{dialog}->file_list->parent->hide;
            }
            elsif ($action eq 'open')
            {
                $self->{dialog}->hide_fileop_buttons;
                $self->{dialog}->selection_entry->set_editable(0);
            }
            $self->{type} = 'old';
        }
        else
        {
            $self->{dialog} = new Gtk2::FileChooserDialog($title, $parent, $action, @GCDialogs::okCancelButtons);
            $self->{type} = 'new';
            if ($withFilter)
            {
                $self->{autoAppend} = $autoAppend;
                my $filterAll;
                $@ = '';
                eval '$filterAll = new Gtk2::FileFilter';
                if (!$@)
                {
                    $self->{ignoreFilter} = 0;
                    $filterAll->set_name('*.*');
                    $filterAll->add_pattern('*');
                    $self->{dialog}->add_filter($filterAll);
                    $self->{filters} = [];
                }
            }
        }
        bless ($self, $class);
        return $self;
    }

    sub transformFilename
    {
        my ($self, $file) = @_;
        
        if ($self->{autoAppend})
        {
            my $tmpFilter = $self->{dialog}->get_filter;
            if ($tmpFilter)
            {
                my $pattern = $self->{filtersPatterns}->{$tmpFilter->get_name};
                if ($pattern)
                {
                    $pattern =~ s/^.*?([^*]*)$/$1/;
                    $file .= $pattern if $file !~ /\./;
                }
            }
        }
        return $file;
    }

    sub get_filename
    {
        my $self = shift;
        my $filename = $self->{dialog}->get_filename;
        $filename .= (($^O =~ /win32/i) ? '\\' : '/') if ($self->{action} eq 'select-folder');
        return $self->transformFilename($filename);
    }

    sub set_filename
    {
        my ($self, $file) = @_;
        
        my $dir = '.';
		$dir = dirname($self->{parent}->{options}->file)
		if ($self->{parent}->{options})
		&& ($self->{parent}->{options}->file);
        my $empty = 0;
        $empty = 1 if !$file;
        $file = $ENV{HOME}.'/' if !$file;
		$file = $dir.'/'.$file if (! File::Spec->file_name_is_absolute( $file ));
        $file =~ s/\//\\/g if ($^O =~ /win32/i);
        $file = File::Spec->canonpath($file);
        $self->{dialog}->set_filename($file) if (!$empty && !(-d $file));
        $self->{dialog}->set_current_folder($file.'/')
            if (($self->{type} eq 'new') && 
               (($empty) || (-d $file)));
        if ($self->{preview})
        {
            $self->updatePreview($self) if ($self->{type} eq 'old');
            $self->{preview}->setImage($file) if ($self->{type} eq 'new');
        }
    }

    sub set_pattern_filter
    {
        my ($self, @filters) = @_;
        return if $self->{ignoreFilter};
        if ($self->{type} eq 'new')
        {
            $self->{dialog}->remove_filter($_) foreach(@{$self->{filters}});
            $self->{filters} = [];
            $self->{filtersPatterns} = {};
            foreach (@filters)
            {
                my $filter;
                eval '$filter = new Gtk2::FileFilter';
                return if $@;
                $filter->set_name($_->[0]);
                $filter->add_pattern($_->[1]);
                push @{$self->{filters}}, $filter;
                $self->{dialog}->add_filter($filter);
                $self->{filtersPatterns}->{$_->[0]} = $_->[1];
            }
            $self->{dialog}->set_filter($self->{filters}->[0]) if $self->{filters}->[0];
        }
    }

    sub run
    {
        my $self = shift;
        return $self->{dialog}->run if ($self->{action} ne 'save');
        my $response;
        while (1)
        {
            $response = $self->{dialog}->run;
            return $response if ($response ne 'ok');
            my $filename = $self->get_filename;
            if (-e $filename)
            {
                my  $dialog = Gtk2::MessageDialog->new($self->{dialog},
                                                       [qw/modal destroy-with-parent/],
                                                       'question',
                                                       'yes-no',
                                                       $self->{parent}->{lang}->{FileOverwrite});

                $dialog->set_position('center-on-parent');
                my $overwrite = $dialog->run;
                $dialog->destroy;
                return $response if ($overwrite eq 'yes');
            }
            else
            {
                return $response;
            }
        }
    }

    sub hide
    {
        my $self = shift;
        return $self->{dialog}->hide;        
    }

    sub setWithImagePreview
    {
        my ($self, $value) = @_;

        if ($value)
        {
            #$self->{preview} = Gtk2::Image->new_from_file($self->{defaultImage});
            $self->{preview} = new GCMovieImage($self->{parent}->{options}, $self->{parent}->{defaultImage},1);
            if ($self->{type} eq 'new')
            {
                $self->{dialog}->signal_connect('update-preview' => \&updatePreview, $self);
				$self->{dialog}->set_preview_widget($self->{preview});
				$self->{dialog}->set_preview_widget_active(1);
            }
            else
            {
                $self->{dialog}->file_list->signal_connect('cursor-changed' => \&updatePreview, $self);
                $self->{dialog}->file_list->parent->parent->parent->pack_start($self->{preview},0,0,5);
            }
            $self->{preview}->show;
        }
        else
        {
            if ($self->{preview})
            {
                $self->{dialog}->file_list->parent->parent->parent->remove($self->{preview}) if ($self->{type} eq 'old');
                $self->{preview}->destroy;
                $self->{preview} = undef;
            }
        }
    }

    sub updatePreview
    {
        my ($widget, $self, $other) = @_;
        my $file;
        if ($self->{type} eq 'new')
        {
            eval
            {
                $file = $self->{dialog}->get_preview_filename;
            }
        }
        else
        {
            $file = $self->get_filename;
        }
        $self->{preview}->setImage($file) if $file;
    }

    sub destroy
    {
        my $self = shift;
        $self->{dialog}->destroy;
    }
}


1;
