Ticket #470: Padre.diff

File Padre.diff, 16.7 KB (added by MoC, 5 years ago)

Patch, adding Padre::Wx::Dialog::FindInFiles? and rewritting the menu item.

  • lib/Padre/Wx/Dialog/Find.pm

     
    165165        Wx::StaticText->new( 
    166166            $self, 
    167167            Wx::wxID_STATIC, 
    168             Wx::gettext("Find Text:"), 
     168            Wx::gettext('Find Text:'), 
    169169        ), 
    170170        0, 
    171171        Wx::wxALIGN_LEFT | Wx::wxALIGN_CENTER_VERTICAL | Wx::wxALL, 
  • lib/Padre/Wx/Dialog/FindInFiles.pm

     
     1package Padre::Wx::Dialog::FindInFiles; 
     2 
     3use 5.008; 
     4use strict; 
     5use warnings; 
     6use threads; 
     7use threads::shared; 
     8use Padre::DB                    (); 
     9use Padre::Wx                    (); 
     10use Padre::Wx::History::ComboBox (); 
     11 
     12our $VERSION = '0.40'; 
     13our @ISA     = qw{ 
     14    Padre::Wx::Role::MainChild 
     15    Wx::Dialog 
     16}; 
     17 
     18my $_ack_loaded = 0; 
     19 
     20=pod 
     21 
     22=head2 new 
     23 
     24    my $find_in_files = Padre::Wx::Dialog::FindInFiles->new($main); 
     25     
     26Create and return a C<Padre::Wx::Dialog::FindInFiles> search widget. 
     27 
     28=cut 
     29 
     30sub new { 
     31    my $class = shift; 
     32    my $main  = shift or die("Did not pass parent to dialog constructor"); 
     33     
     34    my $self = $class->SUPER::new( 
     35        $main, 
     36        -1, 
     37        Wx::gettext('Find in Files'), 
     38        Wx::wxDefaultPosition, 
     39        Wx::wxDefaultSize, 
     40        Wx::wxCAPTION | Wx::wxCLOSE_BOX | Wx::wxSYSTEM_MENU | Wx::wxRESIZE_BORDER 
     41    ); 
     42     
     43    $self->{ack_opts}       = {}; 
     44    $self->{ack_iter}       = undef; 
     45    $self->{ack_stats}      = {}; 
     46    $self->{ack_done_event} = Wx::NewEventType; 
     47    $self->{_panel_index}   = 9999999; 
     48    share($self->{ack_done_event}); 
     49     
     50    $self->{_ack_term} = Padre::Wx::History::ComboBox->new( 
     51        $self, 
     52        -1, 
     53        '', 
     54        Wx::wxDefaultPosition, 
     55        Wx::wxDefaultSize, 
     56        'search' 
     57    ); 
     58     
     59    $self->{_ack_dir} = Padre::Wx::History::ComboBox->new( 
     60        $self, 
     61        -1, 
     62        '', 
     63        Wx::wxDefaultPosition, 
     64        Wx::wxDefaultSize, 
     65        'find in' 
     66    ); 
     67     
     68    $self->{_file_types} = Padre::Wx::History::ComboBox->new( 
     69        $self, 
     70        -1, 
     71        '', 
     72        Wx::wxDefaultPosition, 
     73        Wx::wxDefaultSize, 
     74        'find type' 
     75    ); 
     76     
     77    $self->{_find} = Wx::Button->new( 
     78        $self, 
     79        Wx::wxID_FIND, 
     80        Wx::gettext("&Find") 
     81    ); 
     82    Wx::Event::EVT_BUTTON( 
     83        $self, 
     84        $self->{_find}, 
     85        sub { 
     86            $_[0]->find_clicked; 
     87        } 
     88    ); 
     89    $self->{_find}->SetDefault; 
     90     
     91    $self->{_pick_dir} = Wx::Button->new( 
     92        $self, 
     93        Wx::wxID_ANY, 
     94        Wx::gettext('...'), 
     95        Wx::wxDefaultPosition, 
     96        Wx::wxDefaultSize, 
     97        Wx::wxBU_EXACTFIT 
     98    ); 
     99    Wx::Event::EVT_BUTTON( 
     100        $self, 
     101        $self->{_pick_dir}, 
     102        sub { 
     103            $_[0]->on_pick_dir; 
     104        } 
     105    ); 
     106     
     107    $self->{_cancel} = Wx::Button->new( 
     108        $self, 
     109        Wx::wxID_CANCEL, 
     110        Wx::gettext("&Cancel"), 
     111    ); 
     112    Wx::Event::EVT_BUTTON( 
     113        $self, 
     114        $self->{_cancel}, 
     115        sub { 
     116            $_[0]->cancel; 
     117        } 
     118    ); 
     119     
     120    $self->{_case_insensitive} = Wx::CheckBox->new( 
     121        $self, 
     122        -1, 
     123        Wx::gettext('Case &Insensitive'), 
     124    ); 
     125    Wx::Event::EVT_CHECKBOX( 
     126        $self, 
     127        $self->{_case_insensitive}, 
     128        sub { 
     129            $_[0]->{_case_insensitive}->SetFocus; 
     130        } 
     131    ); 
     132     
     133    $self->{_ignore_hidden_subdirs} = Wx::CheckBox->new( 
     134        $self, 
     135        -1, 
     136        Wx::gettext('I&gnore hidden Subdirectories'), 
     137    ); 
     138    Wx::Event::EVT_CHECKBOX( 
     139        $self, 
     140        $self->{_ignore_hidden_subdirs}, 
     141        sub { 
     142            $_[0]->{_ignore_hidden_subdirs}->SetFocus; 
     143        } 
     144    ); 
     145     
     146    # Setting up the grid containing the search criteria 
     147    my $find_grid = Wx::FlexGridSizer->new(3, 2, 5, 5); 
     148    $find_grid->AddGrowableCol(1); 
     149    $find_grid->Add( 
     150        Wx::StaticText->new( 
     151            $self, 
     152            Wx::wxID_STATIC, 
     153            Wx::gettext('Term:') 
     154        ), 
     155        0, 
     156        Wx::wxALIGN_LEFT | Wx::wxALIGN_CENTER_VERTICAL, 
     157        0 
     158    ); 
     159    $find_grid->Add( 
     160        $self->{_ack_term}, 
     161        1, 
     162        Wx::wxEXPAND, 
     163        0 
     164    ); 
     165    $find_grid->Add( 
     166        Wx::StaticText->new( 
     167            $self, 
     168            Wx::wxID_STATIC, 
     169            Wx::gettext('Dir:') 
     170        ), 
     171        0, 
     172        Wx::wxALIGN_LEFT | Wx::wxALIGN_CENTER_VERTICAL, 
     173        0 
     174    ); 
     175    # Setting up a sizer containing the directory picker... 
     176    my $dir_sizer = Wx::BoxSizer->new( 
     177        Wx::wxHORIZONTAL 
     178    ); 
     179    $dir_sizer->Add( 
     180        $self->{_ack_dir}, 
     181        1, 
     182        Wx::wxEXPAND, 
     183        0 
     184    ); 
     185    $dir_sizer->Add( 
     186        $self->{_pick_dir}, 
     187        0, 
     188        Wx::wxLEFT, 
     189        1 
     190    ); 
     191    # ... and adding it to the grid 
     192    $find_grid->Add( 
     193        $dir_sizer, 
     194        1, 
     195        Wx::wxEXPAND | Wx::wxALIGN_LEFT | Wx::wxALIGN_CENTER_VERTICAL, 
     196        0 
     197    ); 
     198    $find_grid->Add( 
     199        Wx::StaticText->new( 
     200            $self, 
     201            Wx::wxID_STATIC, 
     202            Wx::gettext('In Files/Types:') 
     203        ), 
     204        0, 
     205        Wx::wxALIGN_LEFT | Wx::wxALIGN_CENTER_VERTICAL, 
     206        0 
     207    ); 
     208    $find_grid->Add( 
     209        $self->{_file_types}, 
     210        1, 
     211        Wx::wxEXPAND, 
     212        0 
     213    ); 
     214     
     215    # Setting up the box containing the search criteria 
     216    my $find_box = Wx::StaticBoxSizer->new( 
     217        Wx::StaticBox->new( 
     218            $self, 
     219            -1, 
     220            Wx::gettext('Find in Files') 
     221        ), 
     222        Wx::wxVERTICAL 
     223    ); 
     224    $find_box->Add( 
     225        $find_grid, 
     226        1, 
     227        Wx::wxEXPAND | Wx::wxALL, 
     228        5 
     229    ); 
     230     
     231    # Setting up the box containing the search options 
     232    my $option_box = Wx::StaticBoxSizer->new( 
     233        Wx::StaticBox->new( 
     234            $self, 
     235            -1, 
     236            Wx::gettext('Options') 
     237        ), 
     238        Wx::wxVERTICAL 
     239    ); 
     240    $option_box->Add( 
     241        $self->{_case_insensitive}, 
     242        0, 
     243        Wx::wxALIGN_LEFT | Wx::wxALIGN_CENTER_VERTICAL | Wx::wxALL, 
     244        5 
     245    ); 
     246    $option_box->Add( 
     247        $self->{_ignore_hidden_subdirs}, 
     248        0, 
     249        Wx::wxALIGN_LEFT | Wx::wxALIGN_CENTER_VERTICAL | Wx::wxALL, 
     250        5 
     251    ); 
     252     
     253    # Setting up the box containing the buttons 
     254    my $button_box = Wx::BoxSizer->new( 
     255        Wx::wxHORIZONTAL 
     256    ); 
     257    $button_box->Add( 
     258        $self->{_find}, 
     259        0, 
     260        Wx::wxALL, 
     261        5 
     262    ); 
     263    $button_box->Add( 
     264        $self->{_cancel}, 
     265        0, 
     266        Wx::wxALL, 
     267        5 
     268    );   
     269     
     270    # Setting up the dialog's sizer 
     271    my $sizer = Wx::BoxSizer->new( 
     272        Wx::wxVERTICAL 
     273    ); 
     274    $sizer->Add( 
     275        $find_box, 
     276        0, 
     277        Wx::wxEXPAND | Wx::wxALL, 
     278        5 
     279    ); 
     280    $sizer->Add( 
     281        $option_box, 
     282        0, 
     283        Wx::wxEXPAND | Wx::wxALL, 
     284        5 
     285    ); 
     286    $sizer->Add( 
     287        $button_box, 
     288        0, 
     289        Wx::wxALIGN_RIGHT | Wx::wxALL, 
     290        5 
     291    ); 
     292     
     293    # Applying the sizer(s) to the dialog 
     294    $self->SetSizer($sizer); 
     295    $sizer->SetSizeHints($self); 
     296     
     297    # Update the dialog from configuration 
     298    my $config = $self->current->config; 
     299    $self->{_case_insensitive}->SetValue(!($config->find_case)); 
     300    $self->{_ignore_hidden_subdirs}->SetValue($config->find_nohidden); 
     301     
     302    return $self; 
     303} 
     304 
     305=pod 
     306 
     307=head2 cancel 
     308 
     309  $self->cancel 
     310 
     311Hide dialog when pressed cancel button. 
     312 
     313=cut 
     314 
     315sub cancel { 
     316    my $self = shift; 
     317    $self->Hide; 
     318 
     319    # As we leave the Find dialog, return the user to the current editor 
     320    # window so they don't need to click it. 
     321    my $editor = $self->current->editor; 
     322    if ($editor) { 
     323        $editor->SetFocus; 
     324    } 
     325 
     326    return; 
     327} 
     328 
     329=pod 
     330 
     331=head2 find 
     332 
     333    $self->find 
     334     
     335Loading up App::Ack if neccessary, Grabbing currently selected text, placing it 
     336in the find combobox and showing the dialog. 
     337 
     338=cut 
     339 
     340sub find { 
     341    my $self = shift; 
     342     
     343    # Delay App::Ack loading till first use, this reduces memory  usage 
     344    # and init time 
     345    unless($_ack_loaded) { 
     346        my $minver = 1.86; 
     347        my $error  = "App::Ack $minver required for this feature"; 
     348         
     349        # try to load app::ack - we don't require $minver in the eval to 
     350        # provide a meaningful error message if needed. 
     351        eval 'use App::Ack'; ## no critic 
     352        if ($@) { 
     353            $self->main->error("$error (module not installed)"); 
     354            return; 
     355        } elsif( $App::Ack::VERSION < $minver ) { 
     356            $self->main->error("$error (you have $App::Ack::VERSION installed)"); 
     357            return; 
     358        } 
     359        # redefine some app::ack subs to display results in padre's output 
     360        SCOPE: { 
     361            no warnings 'redefine', 'once'; 
     362            *{App::Ack::print_first_filename} = sub { $self->_print_results("$_[0]\n"); }; 
     363            *{App::Ack::print_separator}      = sub { $self->_print_results("--\n"); }; 
     364            *{App::Ack::print}                = sub { $self->_print_results( $_[0] ); }; 
     365            *{App::Ack::print_filename}       = sub { $self->_print_results("$_[0]$_[1]"); }; 
     366            *{App::Ack::print_line_no}        = sub { $self->_print_results("$_[0]$_[1]"); }; 
     367        } 
     368        $_ack_loaded = 1; 
     369    } 
     370     
     371    $self->{_ack_term}->refresh; 
     372    $self->{_ack_term}->SetValue($self->current->text || ''); 
     373    $self->{_ack_term}->SetFocus; 
     374    $self->{_ack_dir}->refresh; 
     375    $self->{_ack_dir}->SetValue($self->current->project->root) if $self->current->project; 
     376     
     377    $self->Show(1) unless $self->IsShown; 
     378     
     379    return; 
     380} 
     381 
     382sub on_pick_dir { 
     383    my $self  = shift; 
     384    my $event = shift; 
     385     
     386    my $default_dir = $self->{_ack_dir}->GetValue; 
     387    unless($default_dir) { 
     388        my $filename = $self->current->filename; 
     389        $default_dir = File::Basename::dirname($filename) if $filename; 
     390    } 
     391     
     392    my $dir_dialog = Wx::DirDialog->new( 
     393        $self->main, 
     394        Wx::gettext("Select directory"), 
     395        $default_dir 
     396    ); 
     397    return if $dir_dialog->ShowModal == Wx::wxID_CANCEL 
     398    $self->{_ack_dir}->SetValue($dir_dialog->GetPath); 
     399     
     400    return; 
     401} 
     402 
     403sub find_clicked { 
     404    my $self   = shift; 
     405    my $event  = shift; 
     406    my $main   = $self->current->main; 
     407    my $config = $self->_sync_config; 
     408     
     409    return unless $self->{_ack_term}->GetValue; 
     410     
     411    # TODO kill the thread before closing the application 
     412    @_ = (); # cargo cult or bug? see Wx::Thread / Creating new threads 
     413     
     414    $self->{ack_opts} = {}; 
     415     
     416    $self->{ack_opts}->{regex} = $self->{_ack_term}->GetValue; 
     417    if($config->find_nohidden) { 
     418        $self->{ack_opts}->{all} = 1; 
     419    } else { 
     420        $self->{ack_opts}->{u} = 1; # unrestricted 
     421    } 
     422     
     423    for my $i ( App::Ack::filetypes_supported() ) { 
     424        $App::Ack::type_wanted{$i} = undef; 
     425    } 
     426    if(my $file_types = $self->{_file_types}) { 
     427        my $is_regex = 1; 
     428        my $wanted = ($file_types =~ s/^no//)? 0 : 1; 
     429        for my $i ( App::Ack::filetypes_supported() ) { 
     430            if ( $i eq $file_types ) { 
     431                $App::Ack::type_wanted{$i} = $wanted; 
     432                $is_regex = 0; 
     433                last; 
     434            } 
     435        } 
     436        $self->{ack_opts}->{G} = quotemeta $file_types if $is_regex; 
     437    } 
     438     
     439    # case_insensitive 
     440    $self->{ack_opts}->{i} = $config->find_case if $config->find_case; 
     441 
     442    my $what = App::Ack::get_starting_points( [ $self->{_ack_dir}->GetValue ], $self->{ack_opts} ); 
     443    $self->{ack_iter} = App::Ack::get_iterator( $what, $self->{ack_opts} ); 
     444    App::Ack::filetype_setup(); 
     445 
     446    unless ( $main->{ack} ) { 
     447        $self->_ack_create_pane; 
     448    } 
     449    $main->show_output(1); 
     450    $self->_ack_show_output(1); 
     451    $main->{ack}->DeleteAllItems; 
     452     
     453    Wx::Event::EVT_COMMAND( $main, -1, $self->{ack_done_event}, sub { $self->_ack_done(@_); } ); 
     454 
     455    my $worker = threads->create( sub { $self->_ack_on_thread(@_); } ); 
     456 
     457    return; 
     458} 
     459 
     460sub _ack_create_pane { 
     461    my $self = shift; 
     462    my $main = $self->current->main; 
     463     
     464    $main->{ack} = Wx::ListCtrl->new( 
     465        $main->bottom, 
     466        -1, 
     467        Wx::wxDefaultPosition, 
     468        Wx::wxDefaultSize, 
     469        Wx::wxLC_SINGLE_SEL | Wx::wxLC_NO_HEADER | Wx::wxLC_REPORT 
     470    ); 
     471 
     472    $main->{ack}->InsertColumn( 0, Wx::gettext('Ack') ); 
     473    $main->{ack}->SetColumnWidth( 0, Wx::wxLIST_AUTOSIZE ); 
     474 
     475    Wx::Event::EVT_LIST_ITEM_ACTIVATED( 
     476        $main, 
     477        $main->{ack}, 
     478        sub { $self->_ack_on_result_selected(@_); }, 
     479    ); 
     480} 
     481 
     482sub _ack_show_output { 
     483    my $self = shift; 
     484    my $main = $self->current->main; 
     485    my $on   = @_ ? $_[0] ? 1 : 0 : 1; 
     486    my $bp   = \$main->{bottom}; 
     487    my $op   = \$main->{ack}; 
     488    my $idx  = ${$bp}->GetPageIndex( ${$op} ); 
     489 
     490    if ( $idx >= 0 ) { 
     491        ${$bp}->SetSelection($idx); 
     492    } else { 
     493        ${$bp}->InsertPage( 
     494            0, 
     495            ${$op}, 
     496            Wx::gettext("Ack"), 
     497            1, 
     498        ); 
     499        ${$op}->Show; 
     500    } 
     501    $main->aui->GetPane('bottom')->Show; 
     502    $main->aui->Update; 
     503 
     504    return; 
     505} 
     506 
     507sub _ack_on_result_selected { 
     508    my ( $self, $event ) = @_; 
     509 
     510    my $text = $event->GetItem->GetText; 
     511    return if not defined $text; 
     512 
     513    my ( $file, $line ) = ( $text =~ /^(.*?)\((\d+)\)\:/ ); 
     514    return unless $line; 
     515 
     516    my $main = $self->current->main; 
     517    my $id   = $main->setup_editor($file); 
     518    $main->on_nth_pane($id) if $id; 
     519 
     520    my $page = $main->current->editor; 
     521    $line--; 
     522    $page->goto_line_centerize($line); 
     523} 
     524 
     525sub _ack_done { 
     526    my ( $self, $main, $event ) = @_; 
     527 
     528    my $data = $event->GetData; 
     529 
     530    $main = $self->current->main; 
     531    $main->{ack}->InsertStringItem( $self->{_panel_index}--, $data ); 
     532    $main->{ack}->SetColumnWidth( 0, Wx::wxLIST_AUTOSIZE ); 
     533 
     534    return; 
     535} 
     536 
     537sub _ack_on_thread { 
     538    my $self = shift; 
     539    # clear $self->{ack_stats}; for every request 
     540    $self->{ack_stats} = { 
     541        cnt_files   => 0, 
     542        cnt_matches => 0, 
     543    }; 
     544 
     545    App::Ack::print_matches( $self->{ack_iter}, $self->{ack_opts} ); 
     546 
     547    # summary 
     548    $self->_send_text( '-' x 39 . "\n" ) if ( $self->{ack_stats}->{cnt_files} ); 
     549    $self->_send_text("Found $self->{ack_stats}->{cnt_files} files and $self->{ack_stats}->{cnt_matches} matches\n"); 
     550} 
     551 
     552sub _print_results { 
     553    my ( $self, $text ) = @_; 
     554 
     555    # the first is filename, the second is line number, the third is matched line text 
     556    # while 'Binary file', there is ONLY filename 
     557    $self->{ack_stats}->{printed_lines}++; 
     558 
     559    # don't print filename again if it's just printed 
     560    return 
     561        if ($self->{ack_stats}->{printed_lines} % 3 == 1 
     562        and $self->{ack_stats}->{last_matched_filename} 
     563        and $self->{ack_stats}->{last_matched_filename} eq $text ); 
     564    if ( $self->{ack_stats}->{printed_lines} % 3 == 1 ) { 
     565        if ( $text =~ /^Binary file/ ) { 
     566            $self->{ack_stats}->{printed_lines} = $self->{ack_stats}->{printed_lines} + 2; 
     567        } 
     568 
     569        $self->{ack_stats}->{last_matched_filename} = $text; 
     570        $self->{ack_stats}->{cnt_files}++; 
     571 
     572        # chop last ':', add \n after $filename 
     573        chop($text); 
     574        $text = "Found '$self->{ack_opts}->{regex}' in '$text':\n"; 
     575 
     576        # new line between different files 
     577        $self->_send_text( '-' x 39 . "\n" ); 
     578    } elsif ( $self->{ack_stats}->{printed_lines} % 3 == 2 ) { 
     579        $self->{ack_stats}->{cnt_matches}++; 
     580 
     581        # use () to wrap the number, an extra space for line number 
     582        $text =~ s/(\d+)/\($1\)/; 
     583        $text .= ' '; 
     584    } 
     585 
     586    #my $end = $result->get_end_iter; 
     587    #$result->insert($end, $text); 
     588 
     589    # just print it when we have \n 
     590    if ( $text =~ /[\r\n]/ ) { 
     591        my $filename = $self->{ack_stats}->{last_matched_filename}; 
     592        chop($filename); 
     593        $text = $filename . $self->{ack_stats}->{last_text} . $text if $self->{ack_stats}->{last_text}; 
     594        delete $self->{ack_stats}->{last_text}; 
     595    } else { 
     596        $self->{ack_stats}->{last_text} .= $text; 
     597        return; 
     598    } 
     599 
     600    $self->_send_text($text); 
     601 
     602    return; 
     603} 
     604 
     605sub _send_text { 
     606    my ( $self, $text) = shift; 
     607     
     608    # Wx documentation states that the value passed must be shared. 
     609    share($text); 
     610     
     611    my $threvent = Wx::PlThreadEvent->new( -1, $self->{ack_done_event}, $text ); 
     612    Wx::PostEvent( $self->current->main, $threvent ); 
     613} 
     614 
     615sub _sync_config { 
     616    my $self   = shift; 
     617    my $config = $self->current->config; 
     618    $config->set(find_case     => !$self->{_case_insensitive}->GetValue); 
     619    $config->set(find_nohidden => $self->{_ignore_hidden_subdirs}->GetValue); 
     620    $config->write; 
     621     
     622    return $config;  
     623} 
     624 
     6251; 
     626 
     627=pod 
     628 
     629=head1 COPYRIGHT & LICENSE 
     630 
     631Copyright 2008-2009 The Padre development team as listed in Padre.pm. 
     632 
     633This program is free software; you can redistribute 
     634it and/or modify it under the same terms as Perl itself. 
     635 
     636The full text of the license can be found in the 
     637LICENSE file included with this module. 
     638 
     639=cut 
     640 
     641# Copyright 2008-2009 The Padre development team as listed in Padre.pm. 
     642# LICENSE 
     643# This program is free software; you can redistribute it and/or 
     644# modify it under the same terms as Perl 5 itself. 
  • lib/Padre/Wx/Main.pm

     
    18961896 
    18971897=pod 
    18981898 
     1899=item * my $find = $main->find_in_files; 
     1900 
     1901Returns the find in files dialog, creating a new one if needed. 
     1902 
     1903=cut 
     1904 
     1905sub find_in_files { 
     1906    my $self = shift; 
     1907 
     1908    unless ( defined $self->{find_in_files} ) { 
     1909        require Padre::Wx::Dialog::FindInFiles; 
     1910        $self->{find_in_files} = Padre::Wx::Dialog::FindInFiles->new($self); 
     1911    } 
     1912 
     1913    return $self->{find_in_files}; 
     1914} 
     1915 
     1916=pod 
     1917 
    18991918=item * my $value = $main->prompt( $title, $subtitle, $key ); 
    19001919 
    19011920Prompt user with a dialog box about the value that C<$key> should have. 
  • lib/Padre/Wx/Menu/Search.pm

     
    126126    $self->AppendSeparator; 
    127127 
    128128    # Recursive Search 
     129    $self->{find_in_files} = $self->Append( 
     130        -1, 
     131        Wx::gettext("Find in Fi&les...") 
     132    ), 
    129133    Wx::Event::EVT_MENU( 
    130134        $main, 
    131         $self->Append( 
    132             -1, 
    133             Wx::gettext("Find in Fi&les...") 
    134         ), 
     135        $self->{find_in_files}, 
    135136        sub { 
    136             require Padre::Wx::Ack; 
    137             Padre::Wx::Ack::on_ack(@_); 
     137            $_[0]->find_in_files->find; 
    138138        }, 
    139139    ); 
    140140