~ubuntu-branches/ubuntu/saucy/padre/saucy-proposed

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Dominique Dumont, gregor herrmann, Dominique Dumont
  • Date: 2012-01-04 12:04:20 UTC
  • mfrom: (1.3.3)
  • Revision ID: package-import@ubuntu.com-20120104120420-i5oybqwf91m1d3il
Tags: 0.92.ds1-1
[ gregor herrmann ]
* Remove debian/source/local-options; abort-on-upstream-changes
  and unapply-patches are default in dpkg-source since 1.16.1.
* Swap order of alternative (build) dependencies after the perl
  5.14 transition.

[ Dominique Dumont ]
* Imported Upstream version 0.92.ds1
* removed fix-spelling patch (applied upstream)
* lintian-override: use wildcard to avoid listing a gazillion files
* updated size of some 'not-real-man-page' entries
* rules: remove dekstop cruft (replaced by a file provided in debian
  directory)
* control: removed Breaks statement. Add /me to uploaders. Updated
  dependencies
* rules: make sure that non-DFSG file (i.e. the cute butterfly, sigh)
  is not distributed

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package Padre::Wx::Replace;
 
2
 
 
3
=pod
 
4
 
 
5
=head1 NAME
 
6
 
 
7
Padre::Wx::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::DB                    ();
 
22
use Padre::Wx                    ();
 
23
use Padre::Wx::Role::Main        ();
 
24
use Padre::Wx::History::ComboBox ();
 
25
our $VERSION = '0.92';
 
26
our @ISA     = qw{
 
27
        Padre::Wx::Role::Main
 
28
        Wx::Dialog
 
29
};
 
30
 
 
31
=pod
 
32
 
 
33
=head2 new
 
34
 
 
35
  my $find = Padre::Wx::Replace->new($main);
 
36
 
 
37
Create and return a C<Padre::Wx::Replace> search and replace widget.
 
38
 
 
39
=cut
 
40
 
 
41
sub new {
 
42
        my $class = shift;
 
43
        my $main  = shift;
 
44
 
 
45
        # Create the Wx dialog
 
46
        my $self = $class->SUPER::new(
 
47
                $main,
 
48
                -1,
 
49
                Wx::gettext('Find and Replace'),
 
50
                Wx::DefaultPosition,
 
51
                Wx::DefaultSize,
 
52
                Wx::CAPTION | Wx::CLOSE_BOX | Wx::SYSTEM_MENU | Wx::RESIZE_BORDER
 
53
        );
 
54
 
 
55
        # The text to search for
 
56
        $self->{find_text} = Padre::Wx::History::ComboBox->new(
 
57
                $self,
 
58
                -1,
 
59
                '',
 
60
                Wx::DefaultPosition,
 
61
                Wx::DefaultSize,
 
62
                ['search'],
 
63
        );
 
64
 
 
65
        # The text to replace with
 
66
        $self->{replace_text} = Padre::Wx::History::ComboBox->new(
 
67
                $self,
 
68
                -1,
 
69
                '',
 
70
                Wx::DefaultPosition,
 
71
                Wx::DefaultSize,
 
72
                ['replace'],
 
73
        );
 
74
 
 
75
        # "Case Sensitive" option
 
76
        $self->{find_case} = Wx::CheckBox->new(
 
77
                $self,
 
78
                -1,
 
79
                Wx::gettext('Case &sensitive'),
 
80
        );
 
81
        Wx::Event::EVT_CHECKBOX(
 
82
                $self,
 
83
                $self->{find_case},
 
84
                sub {
 
85
                        $_[0]->{find_text}->SetFocus;
 
86
                }
 
87
        );
 
88
 
 
89
        # "Find as Regex" option
 
90
        $self->{find_regex} = Wx::CheckBox->new(
 
91
                $self,
 
92
                -1,
 
93
                Wx::gettext('Regular &Expression'),
 
94
        );
 
95
        Wx::Event::EVT_CHECKBOX(
 
96
                $self,
 
97
                $self->{find_regex},
 
98
                sub {
 
99
                        $_[0]->{find_text}->SetFocus;
 
100
                }
 
101
        );
 
102
 
 
103
        # "Find First and Close" option
 
104
        $self->{find_first} = Wx::CheckBox->new(
 
105
                $self,
 
106
                -1,
 
107
                Wx::gettext('Close Window on &Hit'),
 
108
        );
 
109
        Wx::Event::EVT_CHECKBOX(
 
110
                $self,
 
111
                $self->{find_first},
 
112
                sub {
 
113
                        $_[0]->{find_text}->SetFocus;
 
114
                }
 
115
        );
 
116
 
 
117
        # "Find in Reverse" option
 
118
        $self->{find_reverse} = Wx::CheckBox->new(
 
119
                $self,
 
120
                -1,
 
121
                Wx::gettext('Search &Backwards'),
 
122
        );
 
123
        Wx::Event::EVT_CHECKBOX(
 
124
                $self,
 
125
                $self->{find_reverse},
 
126
                sub {
 
127
                        $_[0]->{find_text}->SetFocus;
 
128
                }
 
129
        );
 
130
 
 
131
        # The "Replace All" option
 
132
        $self->{replace_all} = Wx::CheckBox->new(
 
133
                $self,
 
134
                -1,
 
135
                Wx::gettext('Replace &All'),
 
136
        );
 
137
        Wx::Event::EVT_CHECKBOX(
 
138
                $self,
 
139
                $self->{replace_all},
 
140
                sub {
 
141
                        $_[0]->{find_text}->SetFocus;
 
142
                }
 
143
        );
 
144
 
 
145
        # The "Find" button
 
146
        $self->{find_button} = Wx::Button->new(
 
147
                $self,
 
148
                Wx::ID_FIND,
 
149
                Wx::gettext('&Find'),
 
150
        );
 
151
        Wx::Event::EVT_BUTTON(
 
152
                $self,
 
153
                $self->{find_button},
 
154
                sub {
 
155
                        $_[0]->find_button;
 
156
                }
 
157
        );
 
158
        Wx::Event::EVT_KEY_DOWN(
 
159
                $self->{find_button},
 
160
                sub {
 
161
                        $self->hotkey( $_[1], $self->{find_button} );
 
162
                }
 
163
        );
 
164
 
 
165
        # The "Replace" button
 
166
        $self->{replace_button} = Wx::Button->new(
 
167
                $self,
 
168
                Wx::ID_REPLACE,
 
169
                Wx::gettext('&Replace'),
 
170
        );
 
171
        Wx::Event::EVT_BUTTON(
 
172
                $self,
 
173
                $self->{replace_button},
 
174
                sub {
 
175
                        $_[0]->replace_button;
 
176
                }
 
177
        );
 
178
        Wx::Event::EVT_KEY_DOWN(
 
179
                $self->{replace_button},
 
180
                sub {
 
181
                        $self->hotkey( $_[1], $self->{replace_button} );
 
182
                }
 
183
        );
 
184
        $self->{replace_button}->SetDefault;
 
185
 
 
186
        # The "Close" button
 
187
        $self->{close_button} = Wx::Button->new(
 
188
                $self,
 
189
                Wx::ID_CANCEL,
 
190
                Wx::gettext('&Close'),
 
191
        );
 
192
        Wx::Event::EVT_BUTTON(
 
193
                $self,
 
194
                $self->{close_button},
 
195
                sub {
 
196
                        $_[0]->close;
 
197
                }
 
198
        );
 
199
 
 
200
        # Tab order
 
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} );
 
210
 
 
211
        # Form Layout
 
212
        # Find sizer begins here
 
213
        my $find = Wx::StaticBoxSizer->new(
 
214
                Wx::StaticBox->new(
 
215
                        $self,
 
216
                        -1,
 
217
                        Wx::gettext('Find'),
 
218
                ),
 
219
                Wx::VERTICAL,
 
220
        );
 
221
        $find->Add(
 
222
                Wx::StaticText->new(
 
223
                        $self,
 
224
                        Wx::ID_STATIC,
 
225
                        Wx::gettext('Find Text:'),
 
226
                ),
 
227
                0,
 
228
                Wx::ALIGN_LEFT | Wx::ALIGN_CENTER_VERTICAL | Wx::ALL,
 
229
                5,
 
230
        );
 
231
        $find->Add(
 
232
                $self->{find_text},
 
233
                3,
 
234
                Wx::GROW | Wx::ALIGN_CENTER_VERTICAL | Wx::ALL,
 
235
                5,
 
236
        );
 
237
        $find->Add(
 
238
                $self->{find_regex},
 
239
                0,
 
240
                Wx::ALIGN_LEFT | Wx::LEFT | Wx::RIGHT | Wx::TOP,
 
241
                5,
 
242
        );
 
243
 
 
244
        # Replace sizer begins here
 
245
        my $replace = Wx::StaticBoxSizer->new(
 
246
                Wx::StaticBox->new(
 
247
                        $self,
 
248
                        -1,
 
249
                        Wx::gettext('Replace'),
 
250
                ),
 
251
                Wx::VERTICAL,
 
252
        );
 
253
        $replace->Add(
 
254
                Wx::StaticText->new(
 
255
                        $self,
 
256
                        Wx::ID_STATIC,
 
257
                        Wx::gettext('Replace Text:'),
 
258
                ),
 
259
                0,
 
260
                Wx::ALIGN_LEFT | Wx::ALIGN_CENTER_VERTICAL | Wx::ALL,
 
261
                5,
 
262
        );
 
263
        $replace->Add(
 
264
                $self->{replace_text},
 
265
                3,
 
266
                Wx::GROW | Wx::ALIGN_CENTER_VERTICAL | Wx::ALL,
 
267
                5,
 
268
        );
 
269
 
 
270
        # The layout grid for the options
 
271
        my $grid = Wx::FlexGridSizer->new( 2, 2, 0, 0 );
 
272
        $grid->AddGrowableCol(1);
 
273
        $grid->Add(
 
274
                $self->{find_case},
 
275
                0,
 
276
                Wx::ALIGN_LEFT | Wx::LEFT | Wx::RIGHT | Wx::TOP,
 
277
                5,
 
278
        );
 
279
        $grid->Add(
 
280
                $self->{find_reverse},
 
281
                0,
 
282
                Wx::ALIGN_LEFT | Wx::LEFT | Wx::RIGHT | Wx::TOP,
 
283
                5,
 
284
        );
 
285
        $grid->Add(
 
286
                $self->{find_first},
 
287
                0,
 
288
                Wx::ALIGN_LEFT | Wx::LEFT | Wx::RIGHT | Wx::TOP,
 
289
                5,
 
290
        );
 
291
        $grid->Add(
 
292
                $self->{replace_all},
 
293
                0,
 
294
                Wx::ALIGN_LEFT | Wx::LEFT | Wx::RIGHT | Wx::TOP,
 
295
                5,
 
296
        );
 
297
 
 
298
        # Options sizer begins here
 
299
        my $options = Wx::StaticBoxSizer->new(
 
300
                Wx::StaticBox->new(
 
301
                        $self,
 
302
                        -1,
 
303
                        Wx::gettext('Options')
 
304
                ),
 
305
                Wx::VERTICAL,
 
306
        );
 
307
        $options->Add(
 
308
                $grid,
 
309
                2,
 
310
                Wx::ALIGN_CENTER_HORIZONTAL | Wx::GROW | Wx::ALL,
 
311
                0,
 
312
        );
 
313
 
 
314
        # Sizer for the buttons
 
315
        my $bottom = Wx::BoxSizer->new(Wx::HORIZONTAL);
 
316
        $bottom->Add(
 
317
                $self->{find_button},
 
318
                0,
 
319
                Wx::GROW | Wx::RIGHT,
 
320
                5,
 
321
        );
 
322
        $bottom->Add(
 
323
                $self->{replace_button},
 
324
                0,
 
325
                Wx::GROW | Wx::LEFT | Wx::RIGHT,
 
326
                5,
 
327
        );
 
328
        $bottom->Add(
 
329
                $self->{close_button},
 
330
                0,
 
331
                Wx::GROW | Wx::LEFT,
 
332
                5,
 
333
        );
 
334
 
 
335
        # Fill the sizer for the overall dialog
 
336
        my $sizer = Wx::FlexGridSizer->new( 1, 1, 0, 0 );
 
337
        $sizer->AddGrowableCol(0);
 
338
        $sizer->Add(
 
339
                $find,
 
340
                2,
 
341
                Wx::ALIGN_CENTER_HORIZONTAL | Wx::GROW | Wx::ALL,
 
342
                5,
 
343
        );
 
344
        $sizer->Add(
 
345
                $replace,
 
346
                2,
 
347
                Wx::ALIGN_CENTER_HORIZONTAL | Wx::GROW | Wx::ALL,
 
348
                5,
 
349
        );
 
350
        $sizer->Add(
 
351
                $options,
 
352
                2,
 
353
                Wx::ALIGN_CENTER_HORIZONTAL | Wx::GROW | Wx::ALL,
 
354
                5,
 
355
        );
 
356
        $sizer->Add(
 
357
                $bottom,
 
358
                0,
 
359
                Wx::ALIGN_RIGHT | Wx::ALL,
 
360
                5,
 
361
        );
 
362
 
 
363
        # Let the widgets control the dialog size
 
364
        $self->SetSizer($sizer);
 
365
        $sizer->SetSizeHints($self);
 
366
 
 
367
        return $self;
 
368
}
 
369
 
 
370
=pod
 
371
 
 
372
=head2 find
 
373
 
 
374
  $self->find
 
375
 
 
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.
 
379
 
 
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.
 
382
 
 
383
=cut
 
384
 
 
385
sub find {
 
386
        my $self    = shift;
 
387
        my $main    = $self->main;
 
388
        my $current = $self->current;
 
389
 
 
390
        # No search if no file is open (TO DO ??)
 
391
        return unless $current->editor;
 
392
 
 
393
        # Do we have a default search term?
 
394
        my $text = $current->text;
 
395
        unless ( defined $text ) {
 
396
                $text = '';
 
397
        }
 
398
        unless ( length $text ) {
 
399
                if ( $main->has_findfast ) {
 
400
                        my $fast = $main->findfast->find_term;
 
401
                        $text = $fast if length $fast;  
 
402
                }
 
403
        }
 
404
 
 
405
        # TO DO: if selection is more than one lines then consider it as the
 
406
        # limit of the search and not as the string to be used.
 
407
        $text = '' if $text =~ /\n/;
 
408
 
 
409
        # Hide the Fast Find if visible
 
410
        $self->main->show_findfast(0);
 
411
 
 
412
        # Clear out and reset the dialog, then prepare the new find
 
413
        $self->{find_text}->refresh($text);
 
414
        $self->{replace_text}->refresh;
 
415
        if ( $self->IsShown ) {
 
416
                return $self->find_button;
 
417
        }
 
418
 
 
419
        if ( length $text ) {
 
420
                # Go straight to the replace field
 
421
                $self->{replace_text}->SetFocus;
 
422
        } else {
 
423
                $self->{find_text}->SetFocus;
 
424
        }
 
425
        
 
426
        $self->Show(1);
 
427
}
 
428
 
 
429
 
 
430
 
 
431
 
 
432
 
 
433
######################################################################
 
434
# Button Events
 
435
 
 
436
=pod
 
437
 
 
438
=head2 find_button
 
439
 
 
440
  $self->find_button
 
441
 
 
442
Executed when Find button is clicked.
 
443
 
 
444
Performs search on the term specified in the dialog.
 
445
 
 
446
=cut
 
447
 
 
448
sub find_button {
 
449
        my $self = shift;
 
450
        my $main = $self->main;
 
451
 
 
452
        # Generate the search object
 
453
        my $search = $self->as_search;
 
454
        unless ($search) {
 
455
                $main->error('Not a valid search');
 
456
 
 
457
                # Move the focus back to the search text
 
458
                # so they can tweak their search.
 
459
                $self->{find_text}->SetFocus;
 
460
                return;
 
461
        }
 
462
 
 
463
        # Apply the search to the current editor
 
464
        $main->search_next($search);
 
465
 
 
466
        # If we're only searching once, we won't need the dialog any more
 
467
        if ( $self->{find_first}->GetValue ) {
 
468
                $self->Hide;
 
469
        }
 
470
 
 
471
        return;
 
472
}
 
473
 
 
474
=pod
 
475
 
 
476
=head2 close
 
477
 
 
478
  $self->close
 
479
 
 
480
Hide dialog.
 
481
 
 
482
=cut
 
483
 
 
484
sub close {
 
485
        my $self = shift;
 
486
        $self->Hide;
 
487
 
 
488
        # As we leave the Find dialog, return the user to the current editor
 
489
        # window so they don't need to click it.
 
490
        my $editor = $self->current->editor;
 
491
        $editor->SetFocus if $editor;
 
492
 
 
493
        return;
 
494
}
 
495
 
 
496
=pod
 
497
 
 
498
=head2 replace_button
 
499
 
 
500
  $self->replace_button;
 
501
 
 
502
Executed when the Replace button is clicked.
 
503
 
 
504
Replaces one appearance of the Find Text with the Replace Text.
 
505
 
 
506
If search window is still open, run C<search> on the whole text,
 
507
again.
 
508
 
 
509
=cut
 
510
 
 
511
# TO DO: The change to this function that turned it into a dual-purpose function
 
512
#       unintentionally transfered responsibility for the implementation of
 
513
#       "Replace All" from the main class to a dialog class.
 
514
#       This was a mistake, the dialog should not be where this is implemented.
 
515
#       Revert this change and restore the independent "Replace All" code, so
 
516
#       that the dialog goes back to acting only as controller.
 
517
sub replace_button {
 
518
        my $self = shift;
 
519
        my $main = $self->main;
 
520
 
 
521
        # Generate the search object
 
522
        my $search = $self->as_search;
 
523
        unless ($search) {
 
524
                $main->error('Not a valid search');
 
525
 
 
526
                # Move the focus back to the search text
 
527
                # so they can tweak their search.
 
528
                $self->{find_text}->SetFocus;
 
529
                return;
 
530
        }
 
531
 
 
532
        # If we are replacing everything, hand off to the other method
 
533
        if ( $self->{replace_all}->GetValue ) {
 
534
                return $self->replace_all;
 
535
        }
 
536
 
 
537
        # Just replace once
 
538
        my $changed = $main->replace_next($search);
 
539
        unless ($changed) {
 
540
                $main->message(
 
541
                        sprintf( Wx::gettext('No matches found for "%s".'), $self->{find_text}->GetValue ),
 
542
                        Wx::gettext('Search and Replace'),
 
543
                );
 
544
        }
 
545
 
 
546
        # Move the focus back to the search text
 
547
        # so they can change it if they want.
 
548
        $self->{find_text}->SetFocus;
 
549
        return;
 
550
}
 
551
 
 
552
=pod
 
553
 
 
554
=head2 replace_all
 
555
 
 
556
  $self->replace_all;
 
557
 
 
558
Executed when Replace All button is clicked.
 
559
 
 
560
Replace all appearances of given string in the current document.
 
561
 
 
562
=cut
 
563
 
 
564
sub replace_all {
 
565
        my $self = shift;
 
566
        my $main = $self->main;
 
567
 
 
568
        # Generate the search object
 
569
        my $search = $self->as_search;
 
570
        unless ($search) {
 
571
                $main->error('Not a valid search');
 
572
                return;
 
573
        }
 
574
 
 
575
        # Apply the search to the current editor
 
576
        my $number_of_changes = $main->replace_all($search);
 
577
        if ($number_of_changes) {
 
578
                my $message_text =
 
579
                        $number_of_changes == 1 ? Wx::gettext('Replaced %d match') : Wx::gettext('Replaced %d matches');
 
580
 
 
581
                # remark: It would be better to use gettext for plural handling, but wxperl does not seem to support this at the moment.
 
582
                $main->info(
 
583
                        sprintf( $message_text, $number_of_changes ),
 
584
                        Wx::gettext('Search and Replace')
 
585
                );
 
586
        } else {
 
587
                $main->info(
 
588
                        sprintf( Wx::gettext('No matches found for "%s".'), $self->{find_text}->GetValue ),
 
589
                        Wx::gettext('Search and Replace'),
 
590
                );
 
591
        }
 
592
 
 
593
        # Move the focus back to the search text
 
594
        # so they can change it if they want.
 
595
        $self->{find_text}->SetFocus;
 
596
        return;
 
597
}
 
598
 
 
599
 
 
600
 
 
601
 
 
602
 
 
603
#####################################################################
 
604
# Support Methods
 
605
 
 
606
=pod
 
607
 
 
608
=head2 as_search
 
609
 
 
610
Integration with L<Padre::Search>. Generates a search instance for the
 
611
currently configured information in the Find dialog.
 
612
 
 
613
Returns a L<Padre::Search> object, or C<undef> if current state of the
 
614
dialog does not result in a valid search.
 
615
 
 
616
=cut
 
617
 
 
618
sub as_search {
 
619
        my $self = shift;
 
620
        require Padre::Search;
 
621
        Padre::Search->new(
 
622
                find_term    => $self->{find_text}->GetValue,
 
623
                find_case    => $self->{find_case}->GetValue,
 
624
                find_regex   => $self->{find_regex}->GetValue,
 
625
                find_reverse => $self->{find_reverse}->GetValue,
 
626
                replace_term => $self->{replace_text}->GetValue,
 
627
        );
 
628
}
 
629
 
 
630
# Adds Ultraedit-like hotkeys for quick find/replace triggering
 
631
sub hotkey {
 
632
        my $self   = shift;
 
633
        my $event  = shift;
 
634
        my $sender = shift;
 
635
 
 
636
        $self->find_button    if $event->GetKeyCode == ord 'F';
 
637
        $self->replace_button if $event->GetKeyCode == ord 'R';
 
638
        $self->close          if $event->GetKeyCode == Wx::K_ESCAPE;
 
639
 
 
640
        if ( $event->GetKeyCode == Wx::K_TAB ) {
 
641
                my $index;
 
642
                $index = 1 if $sender->GetId == $self->{find_button}->GetId;
 
643
                $index = 2 if $sender->GetId == $self->{replace_button}->GetId;
 
644
                $index = 3 if $sender->GetId == $self->{close_button}->GetId;
 
645
 
 
646
                if ( $event->ShiftDown ) {
 
647
                        $index--;
 
648
                } else {
 
649
                        $index++;
 
650
                }
 
651
 
 
652
                my @elements = qw(replace_all find_button replace_button close_button find_regex);
 
653
                $self->{ $elements[$index] }->SetFocus;
 
654
        }
 
655
 
 
656
        return;
 
657
}
 
658
 
 
659
1;
 
660
 
 
661
=pod
 
662
 
 
663
=head1 COPYRIGHT & LICENSE
 
664
 
 
665
Copyright 2008-2011 The Padre development team as listed in Padre.pm.
 
666
This program is free software; you can redistribute
 
667
it and/or modify it under the same terms as Perl itself.
 
668
The full text of the license can be found in the
 
669
LICENSE file included with this module.
 
670
 
 
671
=cut
 
672
 
 
673
# Copyright 2008-2011 The Padre development team as listed in Padre.pm.
 
674
# LICENSE
 
675
# This program is free software; you can redistribute it and/or
 
676
# modify it under the same terms as Perl 5 itself.