# +-----------------------------------------------------------------------+ # | pLoader - a Perl photo uploader for Piwigo | # +-----------------------------------------------------------------------+ # | Copyright(C) 2008 Piwigo Team http://piwigo.org | # +-----------------------------------------------------------------------+ # | This program is free software; you can redistribute it and/or modify | # | it under the terms of the GNU General Public License as published by | # | the Free Software Foundation | # | | # | This program is distributed in the hope that it will be useful, but | # | WITHOUT ANY WARRANTY; without even the implied warranty of | # | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | # | General Public License for more details. | # | | # | You should have received a copy of the GNU General Public License | # | along with this program; if not, write to the Free Software | # | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | # | USA. | # +-----------------------------------------------------------------------+ package Uploader::GUI::wxChoiceFilteredPanel; use strict; use Wx qw/ wxDefaultSize wxDefaultPosition wxVERTICAL wxALIGN_CENTER_VERTICAL wxALL wxSHAPED wxALIGN_CENTER wxTE_PROCESS_ENTER wxRA_SPECIFY_ROWS /; use base qw/Wx::Panel Uploader::Object2/; use Wx::Locale qw/:default/; use Data::Dumper; __PACKAGE__->mk_accessors( qw/ frame_callbacks choices selection id_lookup row_lookup id_from_name search listchoices btn_show show_method is_selected creation_callback search_result previous_autocompleted / ); use Wx::Event qw(EVT_CHECKLISTBOX EVT_LISTBOX EVT_SEARCHCTRL_SEARCH_BTN EVT_SEARCHCTRL_CANCEL_BTN EVT_TEXT EVT_TEXT_ENTER EVT_RADIOBOX); sub new { my ($this, $params) = @_; #on recupere le nom de la classe en fonction du type d'appel de la méthode. my $class = ref($this) || $this; my $self = $class->SUPER::new( $params->{parentwnd}, -1, wxDefaultPosition, wxDefaultSize ); $self->_init_panel; $self->_init_properties($params); $self->Refresh; EVT_CHECKLISTBOX( $self, $self->listchoices, \&OnCheck ); EVT_LISTBOX( $self, $self->listchoices, \&OnSelected ); EVT_SEARCHCTRL_SEARCH_BTN( $self, $self->search, \&OnSearch ); EVT_SEARCHCTRL_CANCEL_BTN( $self, $self->search, \&OnCancel ); EVT_TEXT( $self, $self->search, \&OnSearch ); EVT_TEXT_ENTER( $self, $self->search, \&OnSearchEnter ); EVT_RADIOBOX( $self, $self->btn_show, \&OnShow ); $self; } sub _init_properties { my ( $self, $params ) = @_; $self->choices( $params->{choices} ); $self->selection( $params->{selection} ); my $choices = $self->choices->() ||[]; $self->search_result( [] ); $self->is_selected({}); $self->creation_callback( $params->{creation_callback} ) if 'CODE' eq ref($params->{creation_callback}); $self->show_method( { gettext("All") => sub { $self->_show_all(@_) }, gettext("Selected") => sub { $self->_show_selected(@_) }, gettext("Not selected") => sub { $self->_show_notselected(@_) }, } ); } sub _init_panel { my ( $self ) = @_; my( $vsizer ) = Wx::BoxSizer->new( wxVERTICAL ); $self->search( Wx::SearchCtrl->new( $self, -1, "", wxDefaultPosition, [320,-1],wxTE_PROCESS_ENTER ) ); $self->search->ShowCancelButton( 1 ); $vsizer->AddWindow( $self->search, 0, wxALIGN_CENTER_VERTICAL|wxALL, 2 ); $self->btn_show( Wx::RadioBox->new( $self, -1, sprintf("%s :", gettext("Show")), wxDefaultPosition, [320, -1], [gettext("All"),gettext("Selected"),gettext("Not selected")] , 1, wxRA_SPECIFY_ROWS ) ); $vsizer->AddWindow( $self->btn_show, 0, wxALIGN_CENTER_VERTICAL|wxALL, 2 ); $self->listchoices( Wx::CheckListBox->new( $self, -1, wxDefaultPosition, [320,300], [], 0 ) ); $vsizer->AddWindow( $self->listchoices, 0, wxALIGN_CENTER_VERTICAL|wxALL, 2 ); $self->SetSizer( $vsizer ); $vsizer->SetSizeHints( $self ); } sub _init_choices { my ( $self, $choices ) = @_; $self->listchoices->Clear; $self->id_lookup({}); $self->row_lookup({}); $self->id_from_name({}); $self->is_selected({}); my $row = 0; #print Dumper $self->properties; map { $self->listchoices->Append( $_->{name}, ); $self->id_lookup->{$row} = $_->{id}; $self->row_lookup->{$_->{id}} = $row; $self->id_from_name->{$_->{name}} = $_->{id}; $row++; }@{$choices}; } sub Refresh { my ( $self, $choices, $selected ) = @_; if (!defined $choices){ $self->btn_show->SetStringSelection(gettext("All")); $choices = $self->choices->(); } $self->_init_choices($choices); $self->SetSelection($selected); } sub SetSelection { my ( $self, $selected ) = @_; my $selection = $self->selection->()||[]; push @$selection, $self->id_from_name->{$selected} if defined $selected; map { $self->listchoices->Check( $self->row_lookup->{$_}, exists $self->row_lookup->{$_}, ) if defined $self->row_lookup->{$_}; $self->is_selected->{$_} = 1; } @{$selection}; } sub GetSelection { my ( $self ) = @_; my $row = 0; my $selection = []; my $choices = $self->choices->(); map { my $id = $self->id_lookup->{$row}; $self->is_selected->{$id} = $self->listchoices->IsChecked($row) ; $row++; }@$choices; [ grep { $self->is_selected->{$_} } keys %{$self->is_selected} ]; } sub OnCheck { my ( $self ) = @_; $self->selection->( $self->GetSelection ); } sub OnSelected { my ( $self, $event ) = @_; my $row = $event->GetInt; $self->listchoices->Check( $row, !$self->listchoices->IsChecked($row) ); $self->OnCheck; $event->Skip; } sub OnShow { my( $self, $event ) = @_; my $show = $event->GetString(); $self->show_method->{$show}->(); } sub OnSearchEnter { my( $self, $event ) = @_; my $searched = $self->search->GetValue; $searched =~ s/\s+$//; $searched = $searched eq "" ? undef : $searched ; my $cleanup; if(defined($searched)){ my $busy = Wx::BusyCursor->new(); if(!scalar @{$self->search_result}){ $self->creation_callback->( $searched ); $self->_refresh_selected_searched($searched); $cleanup = 1; } if( 1 == scalar @{$self->search_result}){ $self->_refresh_selected_searched($searched); $cleanup = 1; } } else{ $cleanup = 1; } if($cleanup){ $self->search->ChangeValue(""); $self->search->SetFocus; } } sub _refresh_selected_searched { my ( $self, $searched ) = @_; $self->Refresh; $self->SetSelection($searched); $self->_show_selected; $self->btn_show->SetStringSelection(gettext("Selected")); } sub OnSearch { my( $self, $event ) = @_; $self->btn_show->SetStringSelection(gettext("All")); my $searched = $self->search->GetValue; $self->search_result( $self->_filter_choices( $searched ) ); $self->Refresh( $self->search_result ); # autocompletion if(1== scalar @{$self->search_result}){ my $value = $self->search_result->[0]->{name}; unless( $value eq $self->previous_autocompleted ){ my $from = $self->search->GetLastPosition; $self->search->ChangeValue($value); my $to = $self->search->GetLastPosition; $self->search->SetSelection($from, $to); $self->previous_autocompleted($value); } } else{ $self->previous_autocompleted(undef); } } sub OnCancel { my( $self, $event ) = @_; $self->Refresh( $self->choices->() ); $self->btn_show->SetStringSelection(gettext("All")); } sub _filter_choices { my ( $self, $searched ) = @_; my $choices = $self->choices->()||[]; [ grep { $_->{name} =~ /^$searched/} @$choices ] } sub _show_notselected { my ( $self ) = @_; $self->Refresh( $self->_filter_notselected() ); } sub _show_selected { my ( $self ) = @_; $self->Refresh( $self->_filter_selected() ); } sub _show_all { my ( $self ) = @_; $self->Refresh( $self->choices->() ); } sub _filter_selected { my ( $self ) = @_; my $choices = $self->choices->()||[]; [ grep { $self->is_selected->{$_->{id}} } @$choices ] } sub _filter_notselected { my ( $self ) = @_; my $choices = $self->choices->()||[]; [ grep { !$self->is_selected->{$_->{id}} } @$choices ] } 1;