1
1
package Padre::Wx::Dialog::Replace;
7
Padre::Wx::Dialog::Replace - Find and Replace Widget
11
C<Padre::Wx:Main> implements Padre's Find and Replace dialog box.
20
use Params::Util qw{_STRING};
23
use Padre::Wx::Role::Main ();
24
use Padre::Wx::History::ComboBox ();
25
our $VERSION = '0.90';
35
my $find = Padre::Wx::Dialog::Replace->new($main);
37
Create and return a C<Padre::Wx::Dialog::Replace> search and replace widget.
6
use Padre::Wx::FBP::Replace ();
9
our @ISA = 'Padre::Wx::FBP::Replace';
15
######################################################################
45
# Create the Wx dialog
46
my $self = $class->SUPER::new(
49
Wx::gettext('Find and Replace'),
50
Wx::wxDefaultPosition,
52
Wx::wxCAPTION | Wx::wxCLOSE_BOX | Wx::wxSYSTEM_MENU | Wx::wxRESIZE_BORDER
55
# The text to search for
56
$self->{find_text} = Padre::Wx::History::ComboBox->new(
60
Wx::wxDefaultPosition,
65
# The text to replace with
66
$self->{replace_text} = Padre::Wx::History::ComboBox->new(
70
Wx::wxDefaultPosition,
75
# "Case Sensitive" option
76
$self->{find_case} = Wx::CheckBox->new(
79
Wx::gettext('Case &sensitive'),
81
Wx::Event::EVT_CHECKBOX(
85
$_[0]->{find_text}->SetFocus;
89
# "Find as Regex" option
90
$self->{find_regex} = Wx::CheckBox->new(
93
Wx::gettext('Regular &Expression'),
95
Wx::Event::EVT_CHECKBOX(
99
$_[0]->{find_text}->SetFocus;
103
# "Find First and Close" option
104
$self->{find_first} = Wx::CheckBox->new(
107
Wx::gettext('Close Window on &Hit'),
109
Wx::Event::EVT_CHECKBOX(
113
$_[0]->{find_text}->SetFocus;
117
# "Find in Reverse" option
118
$self->{find_reverse} = Wx::CheckBox->new(
121
Wx::gettext('Search &Backwards'),
123
Wx::Event::EVT_CHECKBOX(
125
$self->{find_reverse},
127
$_[0]->{find_text}->SetFocus;
131
# The "Replace All" option
132
$self->{replace_all} = Wx::CheckBox->new(
135
Wx::gettext('Replace &All'),
137
Wx::Event::EVT_CHECKBOX(
139
$self->{replace_all},
141
$_[0]->{find_text}->SetFocus;
146
$self->{find_button} = Wx::Button->new(
149
Wx::gettext('&Find'),
151
Wx::Event::EVT_BUTTON(
153
$self->{find_button},
158
Wx::Event::EVT_KEY_DOWN(
159
$self->{find_button},
161
$self->hotkey( $_[1], $self->{find_button} );
165
# The "Replace" button
166
$self->{replace_button} = Wx::Button->new(
169
Wx::gettext('&Replace'),
171
Wx::Event::EVT_BUTTON(
173
$self->{replace_button},
175
$_[0]->replace_button;
178
Wx::Event::EVT_KEY_DOWN(
179
$self->{replace_button},
181
$self->hotkey( $_[1], $self->{replace_button} );
184
$self->{replace_button}->SetDefault;
187
$self->{close_button} = Wx::Button->new(
190
Wx::gettext('&Close'),
192
Wx::Event::EVT_BUTTON(
194
$self->{close_button},
201
$self->{find_regex}->MoveAfterInTabOrder( $self->{find_text} );
202
$self->{replace_text}->MoveAfterInTabOrder( $self->{find_regex} );
203
$self->{find_case}->MoveAfterInTabOrder( $self->{replace_regex} );
204
$self->{find_reverse}->MoveAfterInTabOrder( $self->{find_case} );
205
$self->{find_first}->MoveAfterInTabOrder( $self->{find_reverse} );
206
$self->{replace_all}->MoveAfterInTabOrder( $self->{find_first} );
207
$self->{find_button}->MoveAfterInTabOrder( $self->{replace_all} );
208
$self->{replace_button}->MoveAfterInTabOrder( $self->{find_button} );
209
$self->{close_button}->MoveAfterInTabOrder( $self->{replace_button} );
212
# Find sizer begins here
213
my $find = Wx::StaticBoxSizer->new(
225
Wx::gettext('Find Text:'),
228
Wx::wxALIGN_LEFT | Wx::wxALIGN_CENTER_VERTICAL | Wx::wxALL,
234
Wx::wxGROW | Wx::wxALIGN_CENTER_VERTICAL | Wx::wxALL,
240
Wx::wxALIGN_LEFT | Wx::wxLEFT | Wx::wxRIGHT | Wx::wxTOP,
244
# Replace sizer begins here
245
my $replace = Wx::StaticBoxSizer->new(
249
Wx::gettext('Replace'),
257
Wx::gettext('Replace Text:'),
260
Wx::wxALIGN_LEFT | Wx::wxALIGN_CENTER_VERTICAL | Wx::wxALL,
264
$self->{replace_text},
266
Wx::wxGROW | Wx::wxALIGN_CENTER_VERTICAL | Wx::wxALL,
270
# The layout grid for the options
271
my $grid = Wx::FlexGridSizer->new( 2, 2, 0, 0 );
272
$grid->AddGrowableCol(1);
276
Wx::wxALIGN_LEFT | Wx::wxLEFT | Wx::wxRIGHT | Wx::wxTOP,
280
$self->{find_reverse},
282
Wx::wxALIGN_LEFT | Wx::wxLEFT | Wx::wxRIGHT | Wx::wxTOP,
288
Wx::wxALIGN_LEFT | Wx::wxLEFT | Wx::wxRIGHT | Wx::wxTOP,
292
$self->{replace_all},
294
Wx::wxALIGN_LEFT | Wx::wxLEFT | Wx::wxRIGHT | Wx::wxTOP,
298
# Options sizer begins here
299
my $options = Wx::StaticBoxSizer->new(
303
Wx::gettext('Options')
310
Wx::wxALIGN_CENTER_HORIZONTAL | Wx::wxGROW | Wx::wxALL,
314
# Sizer for the buttons
315
my $bottom = Wx::BoxSizer->new(Wx::wxHORIZONTAL);
317
$self->{find_button},
319
Wx::wxGROW | Wx::wxRIGHT,
323
$self->{replace_button},
325
Wx::wxGROW | Wx::wxLEFT | Wx::wxRIGHT,
329
$self->{close_button},
331
Wx::wxGROW | Wx::wxLEFT,
335
# Fill the sizer for the overall dialog
336
my $sizer = Wx::FlexGridSizer->new( 1, 1, 0, 0 );
337
$sizer->AddGrowableCol(0);
341
Wx::wxALIGN_CENTER_HORIZONTAL | Wx::wxGROW | Wx::wxALL,
347
Wx::wxALIGN_CENTER_HORIZONTAL | Wx::wxGROW | Wx::wxALL,
353
Wx::wxALIGN_CENTER_HORIZONTAL | Wx::wxGROW | Wx::wxALL,
359
Wx::wxALIGN_RIGHT | Wx::wxALL,
363
# Let the widgets control the dialog size
364
$self->SetSizer($sizer);
365
$sizer->SetSizeHints($self);
20
my $self = $class->SUPER::new(@_);
23
$self->CenterOnParent;
376
Grab currently selected text, if any, and place it in find combo box.
377
Bring up the dialog or perform search for string's next occurrence
378
if dialog is already displayed.
380
TO DO: if selection is more than one line then consider it as the limit
381
of the search and not as the string to be used.
387
my $text = $self->current->text;
389
# No search if no file is open (TO DO ??)
390
return unless $self->current->editor;
392
# TO DO: if selection is more than one lines then consider it as the
393
# limit of the search and not as the string to be used.
394
$text = '' if $text =~ /\n/;
396
# Clear out and reset the dialog, then prepare the new find
397
$self->{find_text}->refresh($text);
398
$self->{replace_text}->refresh;
399
if ( $self->IsShown ) {
32
######################################################################
37
my $main = $self->main;
38
my $current = $self->current;
39
my $config = $current->config;
41
# Do they have a specific search term in mind?
42
my $text = $current->text;
43
unless ( defined $text ) {
46
unless ( length $text ) {
47
if ( $main->has_findfast ) {
48
my $fast = $main->findfast->find_term;
49
$text = $fast if length $fast;
52
if ( $text =~ /\n/ ) {
56
# Clear out and reset the search term box
57
$self->{find_term}->refresh($text);
59
$self->{replace_term}->SetFocus;
402
if ( length $text ) {
404
# Go straight to the replace field
405
$self->{replace_text}->SetFocus;
407
$self->{find_text}->SetFocus;
418
######################################################################
427
Executed when Find button is clicked.
429
Performs search on the term specified in the dialog.
435
my $main = $self->main;
437
# Generate the search object
438
my $search = $self->as_search;
440
$main->error('Not a valid search');
442
# Move the focus back to the search text
443
# so they can tweak their search.
444
$self->{find_text}->SetFocus;
448
# Apply the search to the current editor
449
$main->search_next($search);
451
# If we're only searching once, we won't need the dialog any more
452
if ( $self->{find_first}->GetValue ) {
61
$self->{find_term}->SetFocus;
64
# Hide the Fast Find if visible
65
$main->show_findfast(0);
68
my $result = $self->ShowModal;
473
70
# As we leave the Find dialog, return the user to the current editor
474
71
# window so they don't need to click it.
483
=head2 replace_button
485
$self->replace_button;
487
Executed when the Replace button is clicked.
489
Replaces one appearance of the Find Text with the Replace Text.
491
If search window is still open, run C<search> on the whole text,
496
# TO DO: The change to this function that turned it into a dual-purpose function
497
# unintentionally transfered responsibility for the implementation of
498
# "Replace All" from the main class to a dialog class.
499
# This was a mistake, the dialog should not be where this is implemented.
500
# Revert this change and restore the independent "Replace All" code, so
501
# that the dialog goes back to acting only as controller.
504
my $main = $self->main;
506
# Generate the search object
507
my $search = $self->as_search;
509
$main->error('Not a valid search');
511
# Move the focus back to the search text
512
# so they can tweak their search.
513
$self->{find_text}->SetFocus;
517
# If we are replacing everything, hand off to the other method
518
if ( $self->{replace_all}->GetValue ) {
519
return $self->replace_all;
523
my $changed = $main->replace_next($search);
526
sprintf( Wx::gettext('No matches found for "%s".'), $self->{find_text}->GetValue ),
527
Wx::gettext('Search and Replace'),
531
# Move the focus back to the search text
532
# so they can change it if they want.
533
$self->{find_text}->SetFocus;
543
Executed when Replace All button is clicked.
545
Replace all appearances of given string in the current document.
551
my $main = $self->main;
553
# Generate the search object
554
my $search = $self->as_search;
556
$main->error('Not a valid search');
560
# Apply the search to the current editor
561
my $number_of_changes = $main->replace_all($search);
562
if ($number_of_changes) {
564
$number_of_changes == 1 ? Wx::gettext('Replaced %d match') : Wx::gettext('Replaced %d matches');
566
# remark: It would be better to use gettext for plural handling, but wxperl does not seem to support this at the moment.
568
sprintf( $message_text, $number_of_changes ),
569
Wx::gettext('Search and Replace')
573
sprintf( Wx::gettext('No matches found for "%s".'), $self->{find_text}->GetValue ),
574
Wx::gettext('Search and Replace'),
578
# Move the focus back to the search text
579
# so they can change it if they want.
580
$self->{find_text}->SetFocus;
588
#####################################################################
595
Integration with L<Padre::Search>. Generates a search instance for the
596
currently configured information in the Find dialog.
598
Returns a L<Padre::Search> object, or C<undef> if current state of the
599
dialog does not result in a valid search.
78
# Makes sure the find button is only enabled when the field
82
my $show = $self->{find_term}->GetValue ne '';
83
$self->{find_term}->Enable($show);
84
$self->{replace_term}->Enable($show);
87
# Generate a search object for the current dialog state
605
90
require Padre::Search;
606
91
Padre::Search->new(
607
find_term => $self->{find_text}->GetValue,
92
find_term => $self->{find_term}->SaveValue,
608
93
find_case => $self->{find_case}->GetValue,
609
94
find_regex => $self->{find_regex}->GetValue,
610
find_reverse => $self->{find_reverse}->GetValue,
611
replace_term => $self->{replace_text}->GetValue,
95
replace_term => $self->{replace_term}->GetValue,
615
# Adds Ultraedit-like hotkeys for quick find/replace triggering
621
$self->find_button if $event->GetKeyCode == ord 'F';
622
$self->replace_button if $event->GetKeyCode == ord 'R';
623
$self->close if $event->GetKeyCode == Wx::WXK_ESCAPE;
625
if ( $event->GetKeyCode == Wx::WXK_TAB ) {
627
$index = 1 if $sender->GetId == $self->{find_button}->GetId;
628
$index = 2 if $sender->GetId == $self->{replace_button}->GetId;
629
$index = 3 if $sender->GetId == $self->{close_button}->GetId;
631
if ( $event->ShiftDown ) {
637
my @elements = qw(replace_all find_button replace_button close_button find_regex);
638
$self->{ $elements[$index] }->SetFocus;
648
=head1 COPYRIGHT & LICENSE
650
Copyright 2008-2011 The Padre development team as listed in Padre.pm.
651
This program is free software; you can redistribute
652
it and/or modify it under the same terms as Perl itself.
653
The full text of the license can be found in the
654
LICENSE file included with this module.
658
103
# Copyright 2008-2011 The Padre development team as listed in Padre.pm.
660
105
# This program is free software; you can redistribute it and/or
661
106
# modify it under the same terms as Perl 5 itself.