monotone

monotone Mtn Source Tree

Root/FindFiles.pm

1##############################################################################
2#
3# File Name - FindFiles.pm
4#
5# Description - The find files module for the mtn-browse application. This
6# module contains all the routines for implementing the find
7# files window.
8#
9# Author - A.E.Cooper.
10#
11# Legal Stuff - Copyright (c) 2007 Anthony Edward Cooper
12# <aecooper@coosoft.plus.com>.
13#
14# This program is free software; you can redistribute it
15# and/or modify it under the terms of the GNU General Public
16# License as published by the Free Software Foundation;
17# either version 3 of the License, or (at your option) any
18# later version.
19#
20# This program is distributed in the hope that it will be
21# useful, but WITHOUT ANY WARRANTY; without even the implied
22# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
23# PURPOSE. See the GNU General Public License for more
24# details.
25#
26# You should have received a copy of the GNU General Public
27# License along with this software; if not, write to the Free
28# Software Foundation, Inc., 59 Temple Place - Suite 330,
29# Boston, MA 02111-1307 USA.
30#
31##############################################################################
32#
33##############################################################################
34#
35# Global Data For This Module
36#
37##############################################################################
38
39
40
41# ***** DIRECTIVES *****
42
43require 5.008;
44
45use strict;
46use warnings;
47
48# ***** GLOBAL DATA DECLARATIONS *****
49
50# Constants for the columns within the results listsore widget.
51
52use constant RLS_NAME_COLUMN => 0;
53use constant RLS_MANIFEST_ENTRY_COLUMN => 1;
54
55# Constants for representing combobox values.
56
57use constant DURATION_MINUTES => 0;
58use constant DURATION_HOURS => 1;
59use constant DURATION_DAYS => 2;
60use constant DURATION_MONTHS => 3;
61use constant DURATION_YEARS => 4;
62
63use constant CMP_ANY_SIZE => 0;
64use constant CMP_AT_LEAST => 1;
65use constant CMP_AT_MOST => 2;
66use constant CMP_EQUAL_TO => 3;
67
68use constant SIZE_B => 0;
69use constant SIZE_KB => 1;
70use constant SIZE_MB => 2;
71
72# ***** FUNCTIONAL PROTOTYPES *****
73
74# Public routines.
75
76sub display_find_files($$$$$);
77
78# Private routines.
79
80sub between_range_radiobutton_toggled_cb($$);
81sub date_range_checkbutton_toggled_cb($$);
82sub get_find_files_window();
83sub results_treeview_cursor_changed_cb($$);
84sub results_treeview_row_activated_cb($$$$);
85sub save_query_from_gui($);
86sub search_files_button_clicked_cb($$);
87sub size_comparitor_combobox_changed_cb($$);
88sub validate_query($$);
89#
90##############################################################################
91#
92# Routine - display_find_files
93#
94# Description - Display the find files window.
95#
96# Data - $mtn : The Monotone::AutomateStdio object that
97# is to be used to search for files.
98# $tag : Either a tag name for the specified
99# revision that is to be used in the window
100# title instead of the revision id or undef
101# if the revision id should be used.
102# $revision_id : The id of the revision that is to be
103# searched.
104# $manifest : A reference to the corresponding revision
105# manifest.
106# $starting_point : The directory from which the search is to
107# be started.
108#
109##############################################################################
110
111
112
113sub display_find_files($$$$$)
114{
115
116 my($mtn, $tag, $revision_id, $manifest, $starting_point) = @_;
117
118 my $instance;
119
120 $instance = get_find_files_window();
121 local $instance->{in_cb} = 1;
122
123 $instance->{mtn} = $mtn;
124 $instance->{revision_id} = $revision_id;
125 $instance->{manifest} = $manifest;
126 $instance->{starting_point} = $starting_point;
127
128 $instance->{window}->set_title(__x("Find Files Within Revision {rev}",
129 rev => defined($tag) ?
130 $tag : $revision_id));
131 set_label_value($instance->{searching_from_value_label},
132 $instance->{starting_point});
133
134 $instance->{window}->show_all();
135
136}
137#
138##############################################################################
139#
140# Routine - date_range_checkbutton_toggled_cb
141#
142# Description - Callback routine called when the user changes the value of
143# the date range check button in the find files window.
144#
145# Data - $widget : The widget object that received the signal.
146# $instance : The window instance that is associated with
147# this widget.
148#
149##############################################################################
150
151
152
153sub date_range_checkbutton_toggled_cb($$)
154{
155
156 my($widget, $instance) = @_;
157
158 return if ($instance->{in_cb});
159 local $instance->{in_cb} = 1;
160
161 # Simply enable and disable the appropriate widgets.
162
163 if ($instance->{date_range_checkbutton}->get_active())
164 {
165for my $widget (@{$instance->{date_sensitive_group}})
166{
167 $widget->set_sensitive(TRUE);
168}
169if ($instance->{between_range_radiobutton}->get_active())
170{
171 for my $widget (@{$instance->{during_dates_sensitive_group}})
172 {
173$widget->set_sensitive(FALSE);
174 }
175}
176else
177{
178 for my $widget (@{$instance->{between_dates_sensitive_group}})
179 {
180$widget->set_sensitive(FALSE);
181 }
182}
183 }
184 else
185 {
186for my $widget (@{$instance->{date_sensitive_group}})
187{
188 $widget->set_sensitive(FALSE);
189}
190 }
191
192}
193#
194##############################################################################
195#
196# Routine - between_range_radiobutton_toggled_cb
197#
198# Description - Callback routine called when the user changes the value of
199# the between radio button in the find files window.
200#
201# Data - $widget : The widget object that received the signal.
202# $instance : The window instance that is associated with
203# this widget.
204#
205##############################################################################
206
207
208
209sub between_range_radiobutton_toggled_cb($$)
210{
211
212 my($widget, $instance) = @_;
213
214 return if ($instance->{in_cb});
215 local $instance->{in_cb} = 1;
216
217 # Simply enable and disable the appropriate widgets.
218
219 if ($instance->{between_range_radiobutton}->get_active())
220 {
221for my $widget (@{$instance->{between_dates_sensitive_group}})
222{
223 $widget->set_sensitive(TRUE);
224}
225for my $widget (@{$instance->{during_dates_sensitive_group}})
226{
227 $widget->set_sensitive(FALSE);
228}
229 }
230 else
231 {
232for my $widget (@{$instance->{during_dates_sensitive_group}})
233{
234 $widget->set_sensitive(TRUE);
235}
236for my $widget (@{$instance->{between_dates_sensitive_group}})
237{
238 $widget->set_sensitive(FALSE);
239}
240 }
241
242}
243#
244##############################################################################
245#
246# Routine - size_comparitor_combobox_changed_cb
247#
248# Description - Callback routine called when the user changes the value of
249# the file size combobox by selecting an entry from its
250# pulldown list in the find files window.
251#
252# Data - $widget : The widget object that received the signal.
253# $instance : The window instance that is associated with
254# this widget.
255#
256##############################################################################
257
258
259
260sub size_comparitor_combobox_changed_cb($$)
261{
262
263 my($widget, $instance) = @_;
264
265 return if ($instance->{in_cb});
266 local $instance->{in_cb} = 1;
267
268 # Simply enable and disable the appropriate widgets.
269
270 if ($widget->get_active() == CMP_ANY_SIZE)
271 {
272for my $widget (@{$instance->{size_sensitive_group}})
273{
274 $widget->set_sensitive(FALSE);
275}
276 }
277 else
278 {
279for my $widget (@{$instance->{size_sensitive_group}})
280{
281 $widget->set_sensitive(TRUE);
282}
283 }
284
285}
286#
287##############################################################################
288#
289# Routine - search_files_button_clicked_cb
290#
291# Description - Callback routine called when the user clicks on the find
292# button in a find files window.
293#
294# Data - $widget : The widget object that received the signal.
295# $instance : The window instance that is associated with
296# this widget.
297#
298##############################################################################
299
300
301
302sub search_files_button_clicked_cb($$)
303{
304
305 my($widget, $instance) = @_;
306
307 return if ($instance->{in_cb});
308 local $instance->{in_cb} = 1;
309
310 my($contents_re,
311 $counter,
312 $file_glob_re,
313 $file_prefix_length,
314 $manifest,
315 $matches,
316 $name,
317 $period,
318 $query,
319 $size);
320 my $wm = WindowManager->instance();
321
322 # Get the query from the GUI and validate it.
323
324 $query = save_query_from_gui($instance);
325 return if (! validate_query($instance, $query));
326
327 # Update the comboxentries histories.
328
329 handle_comboxentry_history($instance->{files_named_comboboxentry},
330 "find_files_named",
331 $query->{file_glob});
332 handle_comboxentry_history($instance->{files_containing_comboboxentry},
333 "find_files_containing",
334 $query->{contents_pattern});
335 handle_comboxentry_history($instance->{modified_by_comboboxentry},
336 "find_files_modified_by",
337 $query->{modified_by});
338
339 # Build up a sub-manifest representing the items that we are going to
340 # search.
341
342 $file_prefix_length = 0;
343 if ($query->{file_glob_search_subdirectories}
344&& $instance->{starting_point} eq "")
345 {
346$manifest = $instance->{manifest};
347 }
348 else
349 {
350my @manifest;
351if ($query->{file_glob_search_subdirectories})
352{
353 my $match_re = qr/^$instance->{starting_point}\/.+$/;
354 @manifest =
355grep($_->{name} =~ m/$match_re/, @{$instance->{manifest}});
356}
357else
358{
359 my @result;
360 get_dir_contents($instance->{starting_point},
361 $instance->{manifest},
362 \@result);
363 @manifest = map($_->{manifest_entry}, @result);
364}
365$manifest = \@manifest;
366$file_prefix_length = length($instance->{starting_point});
367++ $file_prefix_length if ($file_prefix_length > 0);
368 }
369
370 # Precompile the regexps and more complex comparison values.
371
372 if ($query->{file_glob} ne "")
373 {
374my $re_text = file_glob_to_regexp($query->{file_glob});
375if ($query->{file_glob_case_sensitive})
376{
377 $file_glob_re = qr/$re_text/;
378}
379else
380{
381 $file_glob_re = qr/$re_text/i;
382}
383 }
384 else
385 {
386$file_glob_re = qr/^.*$/;
387 }
388 if ($query->{contents_pattern} ne "")
389 {
390
391# Need the following pragma as $contents_re could potentially be used
392# against binary data.
393
394use bytes;
395
396if ($query->{contents_pattern_is_regexp})
397{
398 if ($query->{contents_case_sensitive})
399 {
400$contents_re = qr/$query->{contents_pattern}/;
401 }
402 else
403 {
404$contents_re = qr/$query->{contents_pattern}/i;
405 }
406}
407else
408{
409 if ($query->{contents_case_sensitive})
410 {
411$contents_re = qr/\Q$query->{contents_pattern}\E/;
412 }
413 else
414 {
415$contents_re = qr/\Q$query->{contents_pattern}\E/i;
416 }
417}
418
419 }
420 if (exists($query->{period}))
421 {
422
423my($time,
424 @time_val);
425
426# Please note:
427# 1) Values from localtime etc start from 0.
428# 2) You may think that gmtime() should be used instead of
429# localtime(), but what happens when the user jumps back in time
430# by 5 months and goes from say GMT to BST? Would they expect
431# the hours to be adjusted? Probably not.
432
433@time_val = localtime();
434$time = timelocal(@time_val[0 .. 5]);
435if ($query->{period_units} == DURATION_MINUTES)
436{
437 $time -= ($query->{period} * 60);
438}
439elsif ($query->{period_units} == DURATION_HOURS)
440{
441 $time -= ($query->{period} * 60 * 60);
442}
443elsif ($query->{period_units} == DURATION_DAYS)
444{
445 $time -= ($query->{period} * 60 * 60 * 24);
446}
447elsif ($query->{period_units} == DURATION_MONTHS)
448{
449 my($month,
450 $query_months,
451 $year);
452 $query_months = $query->{period};
453 ($month, $year) = (@time_val)[4, 5];
454 if ($query_months > 12)
455 {
456$year -= int($query_months / 12);
457$query_months %= 12;
458 }
459 if ($query_months > $month)
460 {
461-- $year;
462$month = 12 - ($query_months - $month);
463 }
464 else
465 {
466$month -= $query_months;
467 }
468 @time_val[4, 5] = ($month, $year);
469 $time = timegm(@time_val[0 .. 5]);
470}
471else
472{
473 $time_val[5] -= $query->{period};
474 $time = timegm(@time_val[0 .. 5]);
475}
476$period = strftime("%Y-%m-%dT%H:%M:%S", gmtime($time));
477 }
478 if (exists($query->{file_size}))
479 {
480if ($query->{file_size_units} == SIZE_B)
481{
482 $size = $query->{file_size};
483}
484elsif ($query->{file_size_units} == SIZE_KB)
485{
486 $size = $query->{file_size} * 1024;
487}
488else
489{
490 $size = $query->{file_size} * 1024 * 1024;
491}
492 }
493
494 $wm->make_busy($instance, 1);
495 $instance->{appbar}->push($instance->{appbar}->get_status()->get_text());
496 $wm->update_gui();
497
498 $instance->{appbar}->set_status(__("Finding matching files"));
499 $instance->{results_liststore}->clear();
500 set_label_value($instance->{author_value_label}, "");
501 set_label_value($instance->{file_id_value_label}, "");
502 set_label_value($instance->{last_update_value_label}, "");
503 set_label_value($instance->{file_revision_id_value_label}, "");
504 $wm->update_gui();
505
506 $instance->{stop_button}->set_sensitive(TRUE);
507
508 # Now do the search.
509
510 $counter = 1;
511 $matches = 0;
512 foreach my $entry (@$manifest)
513 {
514
515# Check for aborts.
516
517last if ($instance->{stop});
518
519# Exclude entries using the cheapest critera first.
520
521# Name.
522
523next if (basename($entry->{name}) !~ m/$file_glob_re/
524 || ($query->{file_glob} eq "" && $entry->{type} ne "file"));
525
526# The remaining tests only make sense for files.
527
528if ($entry->{type} eq "file")
529{
530
531 # Date and/or modifier.
532
533 if (exists($query->{older_date}) || exists($query->{period})
534|| $query->{modified_by} ne "")
535 {
536my($author,
537 $last_update);
538if (! exists($entry->{author}))
539{
540 cache_extra_file_info($instance->{mtn},
541 $instance->{revision_id},
542 $entry);
543}
544$author = $entry->{author};
545$last_update = $entry->{last_update};
546if (exists($query->{older_date}))
547{
548 next if ($last_update lt $query->{older_date}
549 || $last_update gt $query->{younger_date});
550}
551elsif (exists($query->{period}))
552{
553 next if ($last_update lt $period);
554}
555next if ($query->{modified_by} ne ""
556 && $query->{modified_by} ne $author);
557 }
558
559 # Contents and/or size.
560
561 if (defined($contents_re) || exists($query->{file_size}))
562 {
563my $data;
564if (exists($query->{file_size}))
565{
566 if (! exists($entry->{size}))
567 {
568$instance->{mtn}->get_file(\$data, $entry->{file_id});
569$entry->{size} = length($data);
570 }
571 if ($query->{file_size_operator} == CMP_AT_LEAST)
572 {
573next if ($entry->{size} < $size);
574 }
575 elsif ($query->{file_size_operator} == CMP_AT_MOST)
576 {
577next if ($entry->{size} > $size);
578 }
579 else
580 {
581next if ($entry->{size} != $size);
582 }
583}
584if (defined($contents_re))
585{
586 if (! exists($entry->{is_binary}))
587 {
588$instance->{mtn}->get_file(\$data, $entry->{file_id})
589 if (! defined($data));
590$entry->{is_binary} = data_is_binary(\$data);
591 }
592
593 # Ignore binary files if requested.
594
595 next if ($entry->{is_binary}
596 && ! $query->{contents_search_binary_files});
597
598 $instance->{mtn}->get_file(\$data, $entry->{file_id})
599if (! defined($data));
600 next if ($data !~ m/$contents_re/);
601}
602 }
603
604}
605
606# If we have got this far then it is a match.
607
608++ $matches;
609$name = substr($entry->{name}, $file_prefix_length);
610$instance->{results_liststore}->
611 set($instance->{results_liststore}->append(),
612RLS_NAME_COLUMN, $name,
613RLS_MANIFEST_ENTRY_COLUMN, $entry);
614
615 }
616 continue
617 {
618if (($counter % 10) == 0)
619{
620 $instance->{appbar}->set_progress_percentage
621($counter / scalar(@$manifest));
622 $wm->update_gui();
623}
624++ $counter;
625 }
626 $instance->{appbar}->set_progress_percentage(1);
627 $wm->update_gui();
628
629 $instance->{stop_button}->set_sensitive(FALSE);
630 $instance->{stop} = 0;
631
632 $instance->{results_treeview}->scroll_to_point(0, 0);
633 $instance->{appbar}->set_progress_percentage(0);
634 $instance->{appbar}->set_status("");
635 $wm->update_gui();
636
637 $instance->{appbar}->pop();
638 if ($matches > 0)
639 {
640$instance->{appbar}->set_status(__nx("Found 1 file",
641 "Found {files_found} files",
642 $matches,
643 files_found => $matches));
644 }
645 else
646 {
647my $dialog;
648$dialog = Gtk2::MessageDialog->new
649 ($instance->{window},
650 ["modal"],
651 "info",
652 "close",
653 __("No files matched your query."));
654WindowManager::instance()->allow_input(sub { $dialog->run(); });
655$dialog->destroy();
656$instance->{appbar}->set_status(__("Nothing found"));
657 }
658 $wm->make_busy($instance, 0);
659
660}
661#
662##############################################################################
663#
664# Routine - results_treeview_cursor_changed_cb
665#
666# Description - Callback routine called when the user selects an entry in
667# the results treeview in a find files window.
668#
669# Data - $widget : The widget object that received the signal.
670# $instance : The window instance that is associated with
671# this widget.
672#
673##############################################################################
674
675
676
677sub results_treeview_cursor_changed_cb($$)
678{
679
680 my($widget, $instance) = @_;
681
682 return if ($instance->{in_cb});
683 local $instance->{in_cb} = 1;
684
685 my $manifest_entry;
686
687 # Get the manifest entry details for the item that was selected.
688
689 $widget->get_selection()->selected_foreach
690(sub {
691 my($model, $path, $iter) = @_;
692 $manifest_entry = $model->get($iter, RLS_MANIFEST_ENTRY_COLUMN);
693 });
694
695 if (defined($manifest_entry))
696 {
697my($author,
698 $file_id,
699 $last_changed_revision,
700 $last_update);
701if ($manifest_entry->{type} eq "file")
702{
703 if (! exists($manifest_entry->{author}))
704 {
705cache_extra_file_info($instance->{mtn},
706 $instance->{revision_id},
707 $manifest_entry);
708 }
709 $author = $manifest_entry->{author};
710 $file_id = $manifest_entry->{file_id};
711 $last_changed_revision = $manifest_entry->{last_changed_revision};
712 $last_update = $manifest_entry->{last_update};
713 $last_update =~ s/T/ /;
714}
715else
716{
717 $author = $file_id = $last_changed_revision = $last_update = "";
718}
719set_label_value($instance->{author_value_label}, $author);
720set_label_value($instance->{file_id_value_label}, $file_id);
721set_label_value($instance->{last_update_value_label}, $last_update);
722set_label_value($instance->{file_revision_id_value_label},
723$last_changed_revision);
724 }
725
726}
727#
728##############################################################################
729#
730# Routine - results_treeview_row_activated_cb
731#
732# Description - Callback routine called when the user double clicks on an
733# entry in the results treeview in a find files window.
734#
735# Data - $widget : The widget object that received the
736# signal.
737# $tree_path : A Gtk2::TreePath object for the
738# selected item.
739# $tree_view_column : A Gtk2::TreeViewColumn object for the
740# selected item.
741# $instance : The window instance that is associated
742# with this widget.
743#
744##############################################################################
745
746
747
748sub results_treeview_row_activated_cb($$$$)
749{
750
751 my($widget, $tree_path, $tree_view_column, $instance) = @_;
752
753 return if ($instance->{in_cb});
754 local $instance->{in_cb} = 1;
755
756 my $manifest_entry;
757
758 # Get the manifest entry details for the item that was double-clicked.
759
760 $widget->get_selection()->selected_foreach
761(sub {
762 my($model, $path, $iter) = @_;
763 $manifest_entry = $model->get($iter, RLS_MANIFEST_ENTRY_COLUMN);
764 });
765
766 if (defined($manifest_entry))
767 {
768
769my($branch,
770 @certs_list);
771
772# First find out what branch the revision is on (take the first one).
773
774$instance->{mtn}->certs(\@certs_list, $instance->{revision_id});
775$branch = "";
776foreach my $cert (@certs_list)
777{
778 if ($cert->{name} eq "branch")
779 {
780$branch = $cert->{value};
781last;
782 }
783}
784
785# Either display the file or the directory depending upon the entry's
786# type.
787
788if ($manifest_entry->{type} eq "file")
789{
790 my($dir,
791 $file);
792 $dir = dirname($manifest_entry->{name});
793 $dir = "" if ($dir eq ".");
794 $file = basename($manifest_entry->{name});
795 get_browser_window($instance->{mtn},
796 $branch,
797 $instance->{revision_id},
798 $dir,
799 $file);
800}
801else
802{
803 get_browser_window($instance->{mtn},
804 $branch,
805 $instance->{revision_id},
806 $manifest_entry->{name});
807}
808
809 }
810
811}
812#
813##############################################################################
814#
815# Routine - get_find_files_window
816#
817# Description - Creates or prepares an existing find files window for use.
818#
819# Data - Return Value : A reference to the newly created or unused
820# find files instance record.
821#
822##############################################################################
823
824
825
826sub get_find_files_window()
827{
828
829 my $instance;
830 my $window_type = "find_files_window";
831 my $wm = WindowManager->instance();
832
833 # Create a new find files window if an unused one wasn't found, otherwise
834 # reuse an existing unused one.
835
836 if (! defined($instance = $wm->find_unused($window_type)))
837 {
838
839my($renderer,
840 $tv_column);
841
842$instance = {};
843$instance->{glade} = Gtk2::GladeXML->new($glade_file, $window_type);
844
845# Flag to stop recursive calling of callbacks.
846
847$instance->{in_cb} = 0;
848
849# Connect Glade registered signal handlers.
850
851glade_signal_autoconnect($instance->{glade}, $instance);
852
853# Get the widgets that we are interested in.
854
855$instance->{window} = $instance->{glade}->get_widget($window_type);
856foreach my $widget ("appbar",
857 "execute_button",
858 "stop_button",
859
860 "searching_from_value_label",
861 "files_named_comboboxentry",
862 "name_case_sensitive_checkbutton",
863 "search_subdirectories_checkbutton",
864
865 "files_containing_comboboxentry",
866 "contents_case_sensitive_checkbutton",
867 "regular_expression_checkbutton",
868 "search_binary_files_checkbutton",
869
870 "date_range_checkbutton",
871 "between_range_radiobutton",
872 "older_date_dateedit",
873 "and_label",
874 "younger_date_dateedit",
875 "during_range_radiobutton",
876 "time_spinbutton",
877 "time_units_combobox",
878 "size_comparitor_combobox",
879 "size_spinbutton",
880 "size_units_combobox",
881 "modified_by_comboboxentry",
882
883 "results_scrolledwindow",
884 "results_treeview",
885 "author_value_label",
886 "file_id_value_label",
887 "last_update_value_label",
888 "file_revision_id_value_label")
889{
890 $instance->{$widget} = $instance->{glade}->get_widget($widget);
891}
892
893# Setup widget sensitivity groups.
894
895$instance->{date_sensitive_group} = [];
896foreach my $widget ("between_range_radiobutton",
897 "older_date_dateedit",
898 "and_label",
899 "younger_date_dateedit",
900 "during_range_radiobutton",
901 "time_spinbutton",
902 "time_units_combobox")
903{
904 push(@{$instance->{date_sensitive_group}}, $instance->{$widget});
905}
906$instance->{between_dates_sensitive_group} = [];
907foreach my $widget ("older_date_dateedit",
908 "and_label",
909 "younger_date_dateedit")
910{
911 push(@{$instance->{between_dates_sensitive_group}},
912 $instance->{$widget});
913}
914$instance->{during_dates_sensitive_group} = [];
915foreach my $widget ("time_spinbutton", "time_units_combobox")
916{
917 push(@{$instance->{during_dates_sensitive_group}},
918 $instance->{$widget});
919}
920$instance->{size_sensitive_group} = [];
921foreach my $widget ("size_spinbutton", "size_units_combobox")
922{
923 push(@{$instance->{size_sensitive_group}}, $instance->{$widget});
924}
925
926# Setup the find files callbacks.
927
928$instance->{window}->signal_connect
929 ("delete_event",
930 sub {
931 my($widget, $event, $instance) = @_;
932 return TRUE if ($instance->{in_cb});
933 local $instance->{in_cb} = 1;
934 $widget->hide();
935 $instance->{manifest} = undef;
936 $instance->{mtn} = undef;
937 $instance->{results_liststore}->clear();
938 return TRUE;
939 },
940 $instance);
941$instance->{stop_button}->signal_connect
942 ("clicked", sub { $_[1]->{stop} = 1; }, $instance);
943
944# Setup the comboboxes.
945
946$instance->{files_named_comboboxentry}->
947 set_model(Gtk2::ListStore->new("Glib::String"));
948$instance->{files_named_comboboxentry}->set_text_column(0);
949$instance->{files_containing_comboboxentry}->
950 set_model(Gtk2::ListStore->new("Glib::String"));
951$instance->{files_containing_comboboxentry}->set_text_column(0);
952$instance->{modified_by_comboboxentry}->
953 set_model(Gtk2::ListStore->new("Glib::String"));
954$instance->{modified_by_comboboxentry}->set_text_column(0);
955$instance->{size_comparitor_combobox}->set_active(CMP_ANY_SIZE);
956$instance->{size_units_combobox}->set_active(SIZE_KB);
957$instance->{time_units_combobox}->set_active(DURATION_DAYS);
958
959# Setup the results list browser.
960
961$instance->{results_liststore} = Gtk2::ListStore->new("Glib::String",
962 "Glib::Scalar");
963$instance->{results_treeview}->
964 set_model($instance->{results_liststore});
965$tv_column = Gtk2::TreeViewColumn->new();
966$tv_column->set_sort_column_id(0);
967$renderer = Gtk2::CellRendererText->new();
968$tv_column->pack_start($renderer, FALSE);
969$tv_column->set_attributes($renderer, "text" => 0);
970$instance->{results_treeview}->append_column($tv_column);
971$instance->{results_treeview}->set_search_column(0);
972
973# Disable the approprate widgets by default.
974
975for my $widget (@{$instance->{date_sensitive_group}},
976@{$instance->{size_sensitive_group}})
977{
978 $widget->set_sensitive(FALSE);
979}
980
981# Register the window for management.
982
983$wm->manage($instance,
984 $window_type,
985 $instance->{window},
986 $instance->{stop_button});
987
988 }
989 else
990 {
991
992my($height,
993 $width);
994
995$instance->{in_cb} = 0;
996local $instance->{in_cb} = 1;
997($width, $height) = $instance->{window}->get_default_size();
998$instance->{window}->resize($width, $height);
999$instance->{stop_button}->set_sensitive(FALSE);
1000$instance->{appbar}->set_progress_percentage(0);
1001$instance->{appbar}->clear_stack();
1002
1003 }
1004
1005 $instance->{stop} = 0;
1006 $instance->{results_liststore}->clear();
1007 set_label_value($instance->{author_value_label}, "");
1008 set_label_value($instance->{file_id_value_label}, "");
1009 set_label_value($instance->{last_update_value_label}, "");
1010 set_label_value($instance->{file_revision_id_value_label}, "");
1011
1012 # Load in the comboboxentries histories.
1013
1014 handle_comboxentry_history($instance->{files_named_comboboxentry},
1015 "find_files_named");
1016 handle_comboxentry_history($instance->{files_containing_comboboxentry},
1017 "find_files_containing");
1018 handle_comboxentry_history($instance->{modified_by_comboboxentry},
1019 "find_files_modified_by");
1020
1021 return $instance;
1022
1023}
1024#
1025##############################################################################
1026#
1027# Routine - validate_query
1028#
1029# Description - Check the specified query record, making sure it is valid.
1030#
1031# Data - $instance : The associated window instance.
1032# $query : The query record that is to be validated.
1033# Return Value : True on success, otherwise false on failure.
1034#
1035##############################################################################
1036
1037
1038
1039sub validate_query($$)
1040{
1041
1042 my($instance, $query) = @_;
1043
1044 my($re_text);
1045
1046 # Check that the file name glob is valid.
1047
1048 $re_text = file_glob_to_regexp($query->{file_glob});
1049 eval
1050 {
1051qr/$re_text/;
1052 };
1053 if ($@ ne "")
1054 {
1055my $dialog = Gtk2::MessageDialog->new
1056 ($instance->{window},
1057 ["modal"],
1058 "warning",
1059 "close",
1060 __x("`{pattern}' is an invalid\nfile name pattern.",
1061 pattern => $query->{file_glob}));
1062$dialog->run();
1063$dialog->destroy();
1064return;
1065 }
1066
1067 # Check that the search pattern is valid.
1068
1069 if ($query->{contents_pattern_is_regexp})
1070 {
1071$re_text = file_glob_to_regexp($query->{contents_pattern});
1072eval
1073{
1074 qr/$re_text/;
1075};
1076if ($@ ne "")
1077{
1078 my $dialog = Gtk2::MessageDialog->new
1079($instance->{window},
1080 ["modal"],
1081 "warning",
1082 "close",
1083 __x("`{pattern}' is an invalid\ncontent search pattern.",
1084 pattern => $query->{contents_pattern}));
1085 $dialog->run();
1086 $dialog->destroy();
1087 return;
1088}
1089 }
1090
1091 # Check that any date range is the right way around.
1092
1093 if (exists($query->{older_date})
1094&& $query->{older_date} ge $query->{younger_date})
1095 {
1096my $dialog = Gtk2::MessageDialog->new
1097 ($instance->{window},
1098 ["modal"],
1099 "warning",
1100 "close",
1101 __("The `between' dates are either\n"
1102. "the same or the wrong way round."));
1103$dialog->run();
1104$dialog->destroy();
1105return;
1106 }
1107
1108 # Check that the duration period is not too large.
1109
1110 if (exists($query->{period}))
1111 {
1112my($month, $year) = (localtime())[4, 5];
1113if ($query->{period_units} == DURATION_MONTHS
1114 && $query->{period} > ((($year - 70) * 12) + $month))
1115{
1116 my $dialog = Gtk2::MessageDialog->new
1117($instance->{window},
1118 ["modal"],
1119 "warning",
1120 "close",
1121 __x("A duration of {months} months is too long.",
1122 months => $query->{period}));
1123 $dialog->run();
1124 $dialog->destroy();
1125 return;
1126}
1127elsif ($query->{period_units} == DURATION_YEARS
1128 && $query->{period} > ($year - 70))
1129{
1130 my $dialog = Gtk2::MessageDialog->new
1131($instance->{window},
1132 ["modal"],
1133 "warning",
1134 "close",
1135 __x("A duration of {years} years is too long.",
1136 years => $query->{period}));
1137 $dialog->run();
1138 $dialog->destroy();
1139 return;
1140}
1141 }
1142
1143 return 1;
1144
1145}
1146#
1147##############################################################################
1148#
1149# Routine - save_query_from_gui
1150#
1151# Description - Saves the query information from the find files window into
1152# a record.
1153#
1154# Data - $instance : The associated window instance.
1155# Return Value : A reference to the newly created query
1156# record.
1157#
1158##############################################################################
1159
1160
1161
1162sub save_query_from_gui($)
1163{
1164
1165 my $instance = $_[0];
1166
1167 my %query;
1168
1169 # Do the name page.
1170
1171 $query{file_glob} =
1172$instance->{files_named_comboboxentry}->child()->get_text();
1173 $query{file_glob_case_sensitive} =
1174$instance->{name_case_sensitive_checkbutton}->get_active() ? 1 : 0;
1175 $query{file_glob_search_subdirectories} =
1176$instance->{search_subdirectories_checkbutton}->get_active() ? 1 : 0;
1177
1178 # Do the contents page.
1179
1180 $query{contents_pattern} =
1181$instance->{files_containing_comboboxentry}->child()->get_text();
1182 $query{contents_case_sensitive} =
1183$instance->{contents_case_sensitive_checkbutton}->get_active() ? 1 : 0;
1184 $query{contents_pattern_is_regexp} =
1185$instance->{regular_expression_checkbutton}->get_active() ? 1 : 0;
1186 $query{contents_search_binary_files} =
1187$instance->{search_binary_files_checkbutton}->get_active() ? 1 : 0;
1188
1189 # Do the properties page.
1190
1191 if ($instance->{date_range_checkbutton}->get_active())
1192 {
1193if ($instance->{between_range_radiobutton}->get_active())
1194{
1195 $query{older_date} =
1196strftime("%Y-%m-%dT%H:%M:%S",
1197 localtime($instance->{older_date_dateedit}->
1198 get_time()));
1199 $query{younger_date} =
1200strftime("%Y-%m-%dT%H:%M:%S",
1201 localtime($instance->{younger_date_dateedit}->
1202 get_time()));
1203}
1204else
1205{
1206 $query{period} =
1207$instance->{time_spinbutton}->get_value_as_int();
1208 $query{period_units} =
1209$instance->{time_units_combobox}->get_active();
1210}
1211 }
1212 if ($instance->{size_comparitor_combobox}->get_active() != CMP_ANY_SIZE)
1213 {
1214$query{file_size} = $instance->{size_spinbutton}->get_value_as_int();
1215$query{file_size_operator} =
1216 $instance->{size_comparitor_combobox}->get_active();
1217$query{file_size_units} =
1218 $instance->{size_units_combobox}->get_active();
1219 }
1220 $query{modified_by} =
1221$instance->{modified_by_comboboxentry}->child()->get_text();
1222
1223 return \%query;
1224
1225}
1226
12271;

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status