~ubuntu-branches/ubuntu/wily/padre/wily

« back to all changes in this revision

Viewing changes to lib/Padre/Wx/Dialog/Replace.pm

  • Committer: Bazaar Package Importer
  • Author(s): Damyan Ivanov
  • Date: 2009-08-12 14:44:55 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20090812144455-yvk90oa92khfcnls
Tags: 0.42-1
* New Upstream Version
  + add explicit dependency on libtest-simple-perl (>= 0.88)
  + rules: use dh --with quilt (and bump quilt build-dependency to 0.46-7)
  + rules: no need to re-generate .mo files from .po. Upstream does it now
  + copyright: describe share/icons/padre/16x16/logo.png
    - describe share/icons/padre/16x16/toggle-comments.png
    - Padre license is the same as Perl (i.e. not Perl 5)
    - update list of copright holders
    - also list translators
  + drop libtest-most-perl from build-dependencies
  + add liblocale-msgfmt-perl to build-dependencies
  + add libcapture-tiny-perl to (build-)dependencies
  + add libfile-remove-perl (>= 1.42) to (build-)dependencies
  + drop libmodule-inspector-perl from (build-)dependencies
  + add libppix-editortools-perl to (build-)dependencies
  + add libparse-exuberantctags-perl to (build-)dependencies
  + patches:
    - drop lower-wx-requirement-to-2.8.7.patch and replace it with
      SKIP_WXWIDGETS_VERSION_CHECK=1 when configuring
      adjust README.debian accordingly
    - refresh disable-tcp-server.patch
    - drop don't-require-new-file-path.patch (applied upstream)
    - rework fix-pod2-errors.patch (new release, new errors :))
* add fix-perl-interpreter-path.patch fixing the path to the perl interpreter
  in three examples (thanks lintian)
* add more lintian overrides about script-not-executable for scripts that are
  treated as examples/templates
* add fix-whatis.patch fixing the whatis entry of Padre::Wx
* add menu and .desktop file

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package Padre::Wx::Dialog::Replace;
 
2
 
 
3
=pod
 
4
 
 
5
=head1 NAME
 
6
 
 
7
Padre::Wx::Dialog::Replace - Find and Replace Widget
 
8
 
 
9
=head1 DESCRIPTION
 
10
 
 
11
C<Padre::Wx:Main> implements Padre's Find and Replace dialog box.
 
12
 
 
13
=head1 METHODS
 
14
 
 
15
=cut
 
16
 
 
17
use 5.008;
 
18
use strict;
 
19
use warnings;
 
20
use Params::Util qw{_STRING};
 
21
use Padre::Current               ();
 
22
use Padre::DB                    ();
 
23
use Padre::Wx                    ();
 
24
use Padre::Wx::Role::MainChild   ();
 
25
use Padre::Wx::History::ComboBox ();
 
26
 
 
27
our $VERSION = '0.42';
 
28
our @ISA     = qw{
 
29
        Padre::Wx::Role::MainChild
 
30
        Wx::Dialog
 
31
};
 
32
 
 
33
=pod
 
34
 
 
35
=head2 new
 
36
 
 
37
  my $find = Padre::Wx::Dialog::Replace->new($main);
 
38
 
 
39
Create and return a C<Padre::Wx::Dialog::Replace> search and replace widget.
 
40
 
 
41
=cut
 
42
 
 
43
sub new {
 
44
        my $class = shift;
 
45
        my $main  = shift;
 
46
        unless ($main) {
 
47
                die("Did not pass parent to replace dialog constructor");
 
48
        }
 
49
 
 
50
        # Create the Wx dialog
 
51
        my $self = $class->SUPER::new(
 
52
                $main,
 
53
                -1,
 
54
                Wx::gettext('Find and Replace'),
 
55
                Wx::wxDefaultPosition,
 
56
                Wx::wxDefaultSize,
 
57
                Wx::wxCAPTION | Wx::wxCLOSE_BOX | Wx::wxSYSTEM_MENU | Wx::wxRESIZE_BORDER
 
58
        );
 
59
 
 
60
        # The text to search for
 
61
        $self->{find_text} = Padre::Wx::History::ComboBox->new(
 
62
                $self,
 
63
                -1,
 
64
                '',
 
65
                Wx::wxDefaultPosition,
 
66
                Wx::wxDefaultSize,
 
67
                'search',
 
68
        );
 
69
 
 
70
        # The text to replace with
 
71
        $self->{replace_text} = Padre::Wx::History::ComboBox->new(
 
72
                $self,
 
73
                -1,
 
74
                '',
 
75
                Wx::wxDefaultPosition,
 
76
                Wx::wxDefaultSize,
 
77
                'replace',
 
78
        );
 
79
 
 
80
        # "Case Sensitive" option
 
81
        $self->{find_case} = Wx::CheckBox->new(
 
82
                $self,
 
83
                -1,
 
84
                Wx::gettext('Case &Insensitive'),
 
85
        );
 
86
        Wx::Event::EVT_CHECKBOX(
 
87
                $self,
 
88
                $self->{find_case},
 
89
                sub {
 
90
                        $_[0]->{find_text}->SetFocus;
 
91
                }
 
92
        );
 
93
 
 
94
        # "Find as Regex" option
 
95
        $self->{find_regex} = Wx::CheckBox->new(
 
96
                $self,
 
97
                -1,
 
98
                Wx::gettext('&Use Regex'),
 
99
        );
 
100
        Wx::Event::EVT_CHECKBOX(
 
101
                $self,
 
102
                $self->{find_regex},
 
103
                sub {
 
104
                        $_[0]->{find_text}->SetFocus;
 
105
                }
 
106
        );
 
107
 
 
108
        # "Find First and Close" option
 
109
        $self->{find_first} = Wx::CheckBox->new(
 
110
                $self,
 
111
                -1,
 
112
                Wx::gettext('Close Window on &hit'),
 
113
        );
 
114
        Wx::Event::EVT_CHECKBOX(
 
115
                $self,
 
116
                $self->{find_first},
 
117
                sub {
 
118
                        $_[0]->{find_text}->SetFocus;
 
119
                }
 
120
        );
 
121
 
 
122
        # "Find in Reverse" option
 
123
        $self->{find_reverse} = Wx::CheckBox->new(
 
124
                $self,
 
125
                -1,
 
126
                Wx::gettext('Search &Backwards'),
 
127
        );
 
128
        Wx::Event::EVT_CHECKBOX(
 
129
                $self,
 
130
                $self->{find_reverse},
 
131
                sub {
 
132
                        $_[0]->{find_text}->SetFocus;
 
133
                }
 
134
        );
 
135
 
 
136
        # The "Replace All" option
 
137
        $self->{replace_all} = Wx::CheckBox->new(
 
138
                $self,
 
139
                -1,
 
140
                Wx::gettext('Replace &All'),
 
141
        );
 
142
        Wx::Event::EVT_CHECKBOX(
 
143
                $self,
 
144
                $self->{replace_all},
 
145
                sub {
 
146
                        $_[0]->{find_text}->SetFocus;
 
147
                }
 
148
        );
 
149
 
 
150
        # The "Find" button
 
151
        $self->{find} = Wx::Button->new(
 
152
                $self,
 
153
                Wx::wxID_FIND,
 
154
                Wx::gettext("&Find Next"),
 
155
        );
 
156
        Wx::Event::EVT_BUTTON(
 
157
                $self,
 
158
                $self->{find},
 
159
                sub {
 
160
                        $_[0]->find_clicked;
 
161
                }
 
162
        );
 
163
        Wx::Event::EVT_CHAR(
 
164
                $self->{find},
 
165
                sub {
 
166
                        $self->_on_hotkey( $_[1]->GetKeyCode );
 
167
                }
 
168
        );
 
169
 
 
170
        # The "Replace" button
 
171
        $self->{replace} = Wx::Button->new(
 
172
                $self,
 
173
                Wx::wxID_REPLACE,
 
174
                Wx::gettext("&Replace"),
 
175
        );
 
176
        Wx::Event::EVT_BUTTON(
 
177
                $self,
 
178
                $self->{replace},
 
179
                sub {
 
180
                        $_[0]->replace_clicked;
 
181
                }
 
182
        );
 
183
        Wx::Event::EVT_CHAR(
 
184
                $self->{replace},
 
185
                sub {
 
186
                        $self->_on_hotkey( $_[1]->GetKeyCode );
 
187
                }
 
188
        );
 
189
        $self->{replace}->SetDefault;
 
190
 
 
191
        # The "Cancel" button
 
192
        $self->{cancel} = Wx::Button->new(
 
193
                $self,
 
194
                Wx::wxID_CANCEL,
 
195
                Wx::gettext("&Cancel"),
 
196
        );
 
197
        Wx::Event::EVT_BUTTON(
 
198
                $self,
 
199
                $self->{cancel},
 
200
                sub {
 
201
                        $_[0]->cancel;
 
202
                }
 
203
        );
 
204
 
 
205
        # Find sizer begins here
 
206
        my $find = Wx::StaticBoxSizer->new(
 
207
                Wx::StaticBox->new(
 
208
                        $self,
 
209
                        -1,
 
210
                        Wx::gettext('Find'),
 
211
                ),
 
212
                Wx::wxVERTICAL,
 
213
        );
 
214
        $find->Add(
 
215
                Wx::StaticText->new(
 
216
                        $self,
 
217
                        Wx::wxID_STATIC,
 
218
                        Wx::gettext("Find Text:"),
 
219
                ),
 
220
                0,
 
221
                Wx::wxALIGN_LEFT | Wx::wxALIGN_CENTER_VERTICAL | Wx::wxALL,
 
222
                5,
 
223
        );
 
224
        $find->Add(
 
225
                $self->{find_text},
 
226
                3,
 
227
                Wx::wxGROW | Wx::wxALIGN_CENTER_VERTICAL | Wx::wxALL,
 
228
                5,
 
229
        );
 
230
        $find->Add(
 
231
                $self->{find_regex},
 
232
                0,
 
233
                Wx::wxALIGN_LEFT | Wx::wxLEFT | Wx::wxRIGHT | Wx::wxTOP,
 
234
                5,
 
235
        );
 
236
 
 
237
        # Replace sizer begins here
 
238
        my $replace = Wx::StaticBoxSizer->new(
 
239
                Wx::StaticBox->new(
 
240
                        $self,
 
241
                        -1,
 
242
                        Wx::gettext('Replace'),
 
243
                ),
 
244
                Wx::wxVERTICAL,
 
245
        );
 
246
        $replace->Add(
 
247
                Wx::StaticText->new(
 
248
                        $self,
 
249
                        Wx::wxID_STATIC,
 
250
                        Wx::gettext("Replace Text:"),
 
251
                ),
 
252
                0,
 
253
                Wx::wxALIGN_LEFT | Wx::wxALIGN_CENTER_VERTICAL | Wx::wxALL,
 
254
                5,
 
255
        );
 
256
        $replace->Add(
 
257
                $self->{replace_text},
 
258
                3,
 
259
                Wx::wxGROW | Wx::wxALIGN_CENTER_VERTICAL | Wx::wxALL,
 
260
                5,
 
261
        );
 
262
 
 
263
        # The layout grid for the options
 
264
        my $grid = Wx::FlexGridSizer->new( 2, 2, 0, 0 );
 
265
        $grid->AddGrowableCol(1);
 
266
        $grid->Add(
 
267
                $self->{find_case},
 
268
                0,
 
269
                Wx::wxALIGN_LEFT | Wx::wxLEFT | Wx::wxRIGHT | Wx::wxTOP,
 
270
                5,
 
271
        );
 
272
        $grid->Add(
 
273
                $self->{find_reverse},
 
274
                0,
 
275
                Wx::wxALIGN_LEFT | Wx::wxLEFT | Wx::wxRIGHT | Wx::wxTOP,
 
276
                5,
 
277
        );
 
278
        $grid->Add(
 
279
                $self->{find_first},
 
280
                0,
 
281
                Wx::wxALIGN_LEFT | Wx::wxLEFT | Wx::wxRIGHT | Wx::wxTOP,
 
282
                5,
 
283
        );
 
284
        $grid->Add(
 
285
                $self->{replace_all},
 
286
                0,
 
287
                Wx::wxALIGN_LEFT | Wx::wxLEFT | Wx::wxRIGHT | Wx::wxTOP,
 
288
                5,
 
289
        );
 
290
 
 
291
        # Options sizer begins here
 
292
        my $options = Wx::StaticBoxSizer->new(
 
293
                Wx::StaticBox->new(
 
294
                        $self,
 
295
                        -1,
 
296
                        Wx::gettext('Options')
 
297
                ),
 
298
                Wx::wxVERTICAL,
 
299
        );
 
300
        $options->Add(
 
301
                $grid,
 
302
                2,
 
303
                Wx::wxALIGN_CENTER_HORIZONTAL | Wx::wxGROW | Wx::wxALL,
 
304
                0,
 
305
        );
 
306
 
 
307
        # Sizer for the buttons
 
308
        my $bottom = Wx::BoxSizer->new(Wx::wxHORIZONTAL);
 
309
        $bottom->Add(
 
310
                $self->{find},
 
311
                0,
 
312
                Wx::wxGROW | Wx::wxRIGHT,
 
313
                5,
 
314
        );
 
315
        $bottom->Add(
 
316
                $self->{replace},
 
317
                0,
 
318
                Wx::wxGROW | Wx::wxLEFT | Wx::wxRIGHT,
 
319
                5,
 
320
        );
 
321
        $bottom->Add(
 
322
                $self->{cancel},
 
323
                0,
 
324
                Wx::wxGROW | Wx::wxLEFT,
 
325
                5,
 
326
        );
 
327
 
 
328
        # Fill the sizer for the overall dialog
 
329
        my $sizer = Wx::FlexGridSizer->new( 1, 1, 0, 0 );
 
330
        $sizer->AddGrowableCol(0);
 
331
        $sizer->Add(
 
332
                $find,
 
333
                2,
 
334
                Wx::wxALIGN_CENTER_HORIZONTAL | Wx::wxGROW | Wx::wxALL,
 
335
                5,
 
336
        );
 
337
        $sizer->Add(
 
338
                $replace,
 
339
                2,
 
340
                Wx::wxALIGN_CENTER_HORIZONTAL | Wx::wxGROW | Wx::wxALL,
 
341
                5,
 
342
        );
 
343
        $sizer->Add(
 
344
                $options,
 
345
                2,
 
346
                Wx::wxALIGN_CENTER_HORIZONTAL | Wx::wxGROW | Wx::wxALL,
 
347
                5,
 
348
        );
 
349
        $sizer->Add(
 
350
                $bottom,
 
351
                0,
 
352
                Wx::wxALIGN_RIGHT | Wx::wxALL,
 
353
                5,
 
354
        );
 
355
 
 
356
        # Let the widgets control the dialog size
 
357
        $self->SetSizer($sizer);
 
358
        $sizer->SetSizeHints($self);
 
359
 
 
360
        # Update the dialog from configuration
 
361
        my $config = $self->current->config;
 
362
        $self->{find_case}->SetValue( $config->find_case );
 
363
        $self->{find_regex}->SetValue( $config->find_regex );
 
364
        $self->{find_first}->SetValue( $config->find_first );
 
365
        $self->{find_reverse}->SetValue( $config->find_reverse );
 
366
 
 
367
        return $self;
 
368
}
 
369
 
 
370
=pod
 
371
 
 
372
=head2 cancel
 
373
 
 
374
  $self->cancel
 
375
 
 
376
Hide dialog when pressed cancel button.
 
377
 
 
378
=cut
 
379
 
 
380
sub cancel {
 
381
        my $self = shift;
 
382
        $self->Hide;
 
383
 
 
384
        # As we leave the Find dialog, return the user to the current editor
 
385
        # window so they don't need to click it.
 
386
        my $editor = $self->current->editor;
 
387
        if ($editor) {
 
388
                $editor->SetFocus;
 
389
        }
 
390
 
 
391
        return;
 
392
}
 
393
 
 
394
=pod
 
395
 
 
396
=head2 find
 
397
 
 
398
  $self->find
 
399
 
 
400
Grab currently selected text, if any, and place it in find combo box.
 
401
Bring up the dialog or perform search for strings' next occurence
 
402
if dialog is already displayed.
 
403
 
 
404
If selection is more than one line then consider it as the limit
 
405
of the search and not as the string to be used.
 
406
 
 
407
=cut
 
408
 
 
409
sub find {
 
410
        my $self = shift;
 
411
        my $text = $self->current->text;
 
412
 
 
413
        my $editor = $self->current->editor;
 
414
        return unless $editor; # no replace if no file is open
 
415
 
 
416
        # If selection is more than one line then consider it as the limit
 
417
        # of the search and not as the string to be used (which becomes '')
 
418
        if ( $text =~ /\n/ ) {
 
419
                $self->{text_offset}     = $editor->GetSelectionStart;
 
420
                $self->{text_offset_end} = $editor->GetSelectionEnd;
 
421
                $text                    = '';
 
422
        } else {
 
423
                $self->{text_offset}     = 0;
 
424
                $self->{text_offset_end} = $editor->GetLength;
 
425
        }
 
426
 
 
427
        # Clear out and reset the dialog, then prepare the new find
 
428
        $self->{find_text}->refresh;
 
429
        $self->{find_text}->SetValue($text);
 
430
        $self->{find_text}->SetFocus;
 
431
        $self->{replace_text}->refresh;
 
432
 
 
433
        if ( $self->IsShown ) {
 
434
                $self->find_next;
 
435
        } else {
 
436
                if ( length $text ) {
 
437
 
 
438
                        # Go straight to the replace field
 
439
                        $self->{replace_text}->SetFocus;
 
440
                } else {
 
441
                        $self->{find_text}->SetFocus;
 
442
                }
 
443
                $self->Show(1);
 
444
        }
 
445
 
 
446
        return;
 
447
}
 
448
 
 
449
=pod
 
450
 
 
451
=head2 find_clicked
 
452
 
 
453
  $self->find_clicked
 
454
 
 
455
Executed when Find button is clicked.
 
456
 
 
457
Performs search on the term specified in the dialog.
 
458
 
 
459
=cut
 
460
 
 
461
sub find_clicked {
 
462
        my $self   = shift;
 
463
        my $config = $self->_sync_config;
 
464
 
 
465
        # If we're only searching once, we won't need the dialog any more
 
466
        if ( $config->find_first ) {
 
467
                $self->Hide;
 
468
        }
 
469
 
 
470
        # Return false if we don't have anything to search for
 
471
        my $search = $self->{find_text}->GetValue;
 
472
        return unless defined _STRING($search);
 
473
 
 
474
        # Get the replace term
 
475
        my $replace = $self->{replace_text}->GetValue;
 
476
 
 
477
        # Save the terms
 
478
        Padre::DB::History->create(
 
479
                type => 'search',
 
480
                name => $search,
 
481
        ) if $search;
 
482
        Padre::DB::History->create(
 
483
                type => 'replace',
 
484
                name => $replace,
 
485
        ) if $replace;
 
486
 
 
487
        # Execute the first search
 
488
        $self->search;
 
489
 
 
490
        return;
 
491
}
 
492
 
 
493
=pod
 
494
 
 
495
=head2 find_next
 
496
 
 
497
  $self->find_next
 
498
 
 
499
Search for given string's next occurence.  If no string is available
 
500
(either as a selected text in editor, if Quick Find is on, or from
 
501
search history) run C<find> method.
 
502
 
 
503
=cut
 
504
 
 
505
sub find_next {
 
506
        my $self = shift;
 
507
        my $term = Padre::DB::History->previous('search');
 
508
        if ($term) {
 
509
                $self->search;
 
510
        } else {
 
511
                $self->find;
 
512
        }
 
513
        return;
 
514
}
 
515
 
 
516
=pod
 
517
 
 
518
=head2 find_previous
 
519
 
 
520
  $self->find_previous
 
521
 
 
522
Perform backward search for string fetched from search history
 
523
or run C<find> method if search history is empty.
 
524
 
 
525
=cut
 
526
 
 
527
sub find_previous {
 
528
        my $self = shift;
 
529
        my $term = Padre::DB::History->previous('search');
 
530
        if ($term) {
 
531
                $self->search( rev => 1 );
 
532
        } else {
 
533
                $self->find;
 
534
        }
 
535
        return;
 
536
}
 
537
 
 
538
=pod
 
539
 
 
540
=head2 search
 
541
 
 
542
  $self->search
 
543
 
 
544
Perform actual search. Highlight (set as selected) found string.
 
545
 
 
546
=cut
 
547
 
 
548
sub search {
 
549
        my $self  = shift;
 
550
        my %args  = @_;
 
551
        my $regex = $self->_get_search or return;
 
552
 
 
553
        # Forwards or backwards
 
554
        my $backwards = $self->config->find_reverse;
 
555
        if ( $args{rev} ) {
 
556
                $backwards = not $backwards;
 
557
        }
 
558
 
 
559
        # Find the range to search within
 
560
        my $editor = $self->current->editor;
 
561
        $self->{text} = $editor->GetTextRange( $self->{text_offset}, $self->{text_offset_end} );
 
562
        my ( $from, $to ) = $editor->GetSelection;
 
563
 
 
564
        # Execute the search and move to the resulting location
 
565
        my ( $start, $end, @matches ) = Padre::Util::get_matches(
 
566
                $self->{text}, $regex, $from - $self->{text_offset}, $to - $self->{text_offset},
 
567
                $backwards
 
568
        );
 
569
        return unless defined $start;
 
570
        $editor->SetSelection( $start + $self->{text_offset}, $end + $self->{text_offset} );
 
571
 
 
572
        return;
 
573
}
 
574
 
 
575
=pod
 
576
 
 
577
=head2 replace_clicked
 
578
 
 
579
  $self->replace_clicked;
 
580
 
 
581
Executed when the Replace button is clicked.
 
582
 
 
583
Replaces one appearance of the Find Text with the Replace Text.
 
584
 
 
585
If search window is still open, run C<search> on the whole text,
 
586
again.
 
587
 
 
588
=cut
 
589
 
 
590
sub replace_clicked {
 
591
        my $self   = shift;
 
592
        my $config = $self->_sync_config;
 
593
 
 
594
        # If we're only searching once, we won't need the dialog any more
 
595
        if ( $config->find_first ) {
 
596
                $self->Hide;
 
597
        }
 
598
 
 
599
        # Return false if we don't have anything to search for
 
600
        my $search = $self->{find_text}->GetValue;
 
601
        return unless defined _STRING($search);
 
602
 
 
603
        # Get the replace term
 
604
        my $replace = $self->{replace_text}->GetValue;
 
605
 
 
606
        # Save the terms
 
607
        Padre::DB::History->create(
 
608
                type => 'search',
 
609
                name => $search,
 
610
        ) if $search;
 
611
        Padre::DB::History->create(
 
612
                type => 'replace',
 
613
                name => $replace,
 
614
        ) if $replace;
 
615
 
 
616
        # Execute the replace
 
617
        if ( $self->{replace_all}->GetValue ) {
 
618
                $self->replace_all;
 
619
        } else {
 
620
                $self->replace;
 
621
        }
 
622
 
 
623
        return;
 
624
}
 
625
 
 
626
=pod
 
627
 
 
628
=head2 replace_all
 
629
 
 
630
  $self->replace_all;
 
631
 
 
632
Executed when Replace All button is clicked.
 
633
 
 
634
Replace all appearances of given string in the current document.
 
635
 
 
636
=cut
 
637
 
 
638
sub replace_all {
 
639
        my $self = shift;
 
640
 
 
641
        # Prepare the search and replace values
 
642
        my $regex = $self->_get_search or return;
 
643
        my $replace = $self->_get_replace;
 
644
        $replace =~ s/\\t/\t/g if length $replace;
 
645
 
 
646
        # Execute the search for all matches
 
647
        my $editor = $self->current->editor;
 
648
        my $text = $editor->GetTextRange( $self->{text_offset}, $self->{text_offset_end} );
 
649
        my ( undef, undef, @matches ) = Padre::Util::get_matches( $text, $regex, 0, 0 );
 
650
 
 
651
        # Replace all matches as a single undo
 
652
        if (@matches) {
 
653
                $editor->BeginUndoAction;
 
654
                foreach my $match ( reverse @matches ) {
 
655
                        $editor->SetTargetStart( $match->[0] + $self->{text_offset} );
 
656
                        $editor->SetTargetEnd( $match->[1] + $self->{text_offset} );
 
657
                        $editor->ReplaceTarget($replace);
 
658
                }
 
659
                $editor->EndUndoAction;
 
660
 
 
661
                $self->main->message(
 
662
                        sprintf(
 
663
                                Wx::gettext('%s occurences were replaced'),
 
664
                                scalar @matches
 
665
                        )
 
666
                );
 
667
        } else {
 
668
                $self->main->message( Wx::gettext("Nothing to replace") );
 
669
        }
 
670
 
 
671
        return;
 
672
}
 
673
 
 
674
=pod
 
675
 
 
676
  $self->replace;
 
677
 
 
678
Perform actual single replace. Highlight (set as selected) found string.
 
679
 
 
680
=cut
 
681
 
 
682
sub replace {
 
683
        my $self    = shift;
 
684
        my $current = $self->current;
 
685
        my $text    = $current->text;
 
686
 
 
687
        # Prepare the search and replace values
 
688
        my $regex = $self->_get_search or return;
 
689
        my $replace = $self->_get_replace;
 
690
        $replace =~ s/\\t/\t/g if length $replace;
 
691
 
 
692
        # Get current search condition and check if they match
 
693
        my ( $start, $end, @matches ) = Padre::Util::get_matches( $text, $regex, 0, 0 );
 
694
 
 
695
        # If they match replace it
 
696
        if ( defined $start and $start == 0 and $end == length($text) ) {
 
697
                $current->editor->ReplaceSelection($replace);
 
698
 
 
699
                # If replaced text is smaller or larger than original,
 
700
                # change our offset end accordingly
 
701
                if ( length($replace) != ( $end - $start ) ) {
 
702
                        $self->{text_offset_end} += ( length($replace) - ( $end - $start ) );
 
703
                }
 
704
 
 
705
                # Update text to search with replaced values
 
706
                ###################     $self->{text} = $current->editor->GetTextRange( $self->{text_offset}, $self->{text_offset_end} );
 
707
        }
 
708
 
 
709
        # If search window is still open, run a search on the whole text again
 
710
        unless ( $current->config->find_first ) {
 
711
                $self->search;
 
712
        }
 
713
 
 
714
        return;
 
715
}
 
716
 
 
717
#####################################################################
 
718
# Support Methods
 
719
 
 
720
# Save the dialog settings to configuration. Returns the config object
 
721
# as a convenience.
 
722
sub _sync_config {
 
723
        my $self = shift;
 
724
 
 
725
        # Save the search settings to config
 
726
        my $config = $self->current->config;
 
727
        $config->set( find_case    => !$self->{find_case}->GetValue );
 
728
        $config->set( find_regex   => $self->{find_regex}->GetValue );
 
729
        $config->set( find_first   => $self->{find_first}->GetValue );
 
730
        $config->set( find_reverse => $self->{find_reverse}->GetValue );
 
731
        $config->write;
 
732
 
 
733
        return $config;
 
734
}
 
735
 
 
736
# Internal method. $self->_get_search( $regex )
 
737
# Prepare and return search term defined as a regular expression.
 
738
sub _get_search {
 
739
        my $self   = shift;
 
740
        my $config = $self->config;
 
741
        my $term   = Padre::DB::History->previous('search');
 
742
 
 
743
        # Escape the raw search term
 
744
        if ( $config->find_regex ) {
 
745
 
 
746
                # Escape non-trailing $ so they won't interpolate
 
747
                $term =~ s/\$(?!\z)/\\\$/g;
 
748
        } else {
 
749
 
 
750
                # Escape everything
 
751
                $term = quotemeta $term;
 
752
        }
 
753
 
 
754
        # Compile the regex
 
755
        my $regex = eval { $config->find_case ? qr/$term/m : qr/$term/mi };
 
756
        if ($@) {
 
757
                Wx::MessageBox(
 
758
                        sprintf( Wx::gettext("Cannot build regex for '%s'"), $term ),
 
759
                        Wx::gettext('Search error'),
 
760
                        Wx::wxOK,
 
761
                        $self->main,
 
762
                );
 
763
                return;
 
764
        }
 
765
 
 
766
        return $regex;
 
767
}
 
768
 
 
769
# Internal method. $self->_get_replace
 
770
# Returns previous replacement string from history
 
771
# or empty if _replace_choice_ widget is empty.
 
772
# Added to be able to use empty string as a replacement text
 
773
# but without storing in (the empty string) in history.
 
774
sub _get_replace {
 
775
        my $self = shift;
 
776
        if ( $self->{replace_text} ) {
 
777
                return $self->{replace_text}->GetValue;
 
778
        } else {
 
779
                return Padre::DB::History->previous('replace');
 
780
        }
 
781
}
 
782
 
 
783
# Adds Ultraedit-like hotkeys for quick find/replace triggering
 
784
sub _on_hotkey {
 
785
        my $self = shift;
 
786
        my $code = shift;
 
787
 
 
788
        $self->find_clicked    if $code == 102; # pressed 'f' hotkey
 
789
        $self->replace_clicked if $code == 114; # pressed 'r' hotkey
 
790
 
 
791
        return;
 
792
}
 
793
 
 
794
1;
 
795
 
 
796
=pod
 
797
 
 
798
=head1 COPYRIGHT & LICENSE
 
799
 
 
800
Copyright 2008-2009 The Padre development team as listed in Padre.pm.
 
801
 
 
802
This program is free software; you can redistribute
 
803
it and/or modify it under the same terms as Perl itself.
 
804
 
 
805
The full text of the license can be found in the
 
806
LICENSE file included with this module.
 
807
 
 
808
=cut
 
809
 
 
810
# Copyright 2008-2009 The Padre development team as listed in Padre.pm.
 
811
# LICENSE
 
812
# This program is free software; you can redistribute it and/or
 
813
# modify it under the same terms as Perl 5 itself.