source: trunk/gsdl/perllib/classify/DateList.pm@ 6976

Last change on this file since 6976 was 6968, checked in by kjdon, 20 years ago

all classifiers now use BasClas.buttonname for their buttonname option description.
removed the old print_usage methods and old usage notes.
added in a test for $self->{'info_only'} in new(): if this is set, don't try and parse the arguments cos we are only running classinfo.pl.

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 10.6 KB
Line 
1###########################################################################
2#
3# DateList.pm --
4# A component of the Greenstone digital library software
5# from the New Zealand Digital Library Project at the
6# University of Waikato, New Zealand.
7#
8# Copyright (C) 1999 New Zealand Digital Library Project
9#
10# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License as published by
12# the Free Software Foundation; either version 2 of the License, or
13# (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License
21# along with this program; if not, write to the Free Software
22# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23#
24###########################################################################
25
26# classifier plugin for sorting by date
27
28# always sorts by 'Date' metadata
29
30# date is assumed to be in the form yyyymmdd
31
32# at present dates are split by year - this should change
33# jrm21 - added option "bymonth", which splits by year and month.
34
35# 12/05/02 Added usage datastructure - John Thompson
36
37# 23/09/03 Added some more options -kjdon.
38# these include:
39# -nogroup, which makes each year (or year+month) an individual entry in
40# the horizontal list and prevents compaction
41# -datemeta, use a different metadata for the date (instead of Date), still expects yyyymmdd format. this affects display cos greenstone displays Date metadata as dd month yyyy, whereas any other date metadata is displayed as yyyymmdd - this needs fixing
42# -sortmeta specifies an additional metadata to use in sorting, will take affect when two docs have the same date.
43
44package DateList;
45
46use BasClas;
47use sorttools;
48
49sub BEGIN {
50 @ISA = ('BasClas');
51}
52
53my $arguments =
54 [ { 'name' => "bymonth",
55 'desc' => "{DateList.bymonth}",
56 'type' => "flag",
57 'reqd' => "no" },
58 { 'name' => "nogroup",
59 'desc' => "{DateList.nogroup}",
60 'type' => "flag",
61 'reqd' => "no" },
62 { 'name' => "datemeta",
63 'desc' => "{DateList.datemeta}",
64 'type' => "metadata",
65 'deft' => "Date",
66 'reqd' => "no" } ,
67 { 'name' => "sortmeta",
68 'desc' => "{DateList.sortmeta}",
69 'type' => "metadata",
70 'reqd' => "no" } ,
71
72 ];
73
74my $options = { 'name' => "DateList",
75 'desc' => "{DateList.desc}",
76 'abstract' => "no",
77 'inherits' => "yes",
78 'args' => $arguments };
79
80
81sub new {
82 my $class = shift (@_);
83 my $self = new BasClas($class, @_);
84
85 # 14-05-02 To allow for proper inheritance of arguments - John Thompson
86 my $option_list = $self->{'option_list'};
87 push( @{$option_list}, $options );
88
89 if ($self->{'info_only'}) {
90 # created from classinfo.pl - don't need to parse the arguments
91 return bless $self, $class;
92 }
93
94 $self->{'list'} = {};
95
96 my ($datemeta, $sortmeta);
97 $self->{'nogroup'}=0;
98 if (!parsargv::parse(\@_,
99 q^bymonth^, \$self->{'bymonth'},
100 q^nogroup^, \$self->{'nogroup'},
101 q^datemeta/.*/^, \$datemeta,
102 q^sortmeta/.*/^, \$sortmeta,
103 "allow_extra_options")) {
104 $self->print_txt_usage(""); # Use default resource bundle
105 die "\n";
106 }
107
108 if (!defined $datemeta || $datemeta eq "") {
109 $datemeta = "Date";
110 }
111 $self->{'datemeta'} = $datemeta;
112
113 if (defined $sortmeta && $sortmeta ne "") {
114 $self->{'sortmeta'} = $sortmeta;
115 }
116 return bless $self, $class;
117}
118
119sub init {
120 my $self = shift (@_);
121
122 $self->{'list'} = {};
123}
124
125sub classify {
126 my $self = shift (@_);
127 my ($doc_obj) = @_;
128
129 my $doc_OID = $doc_obj->get_OID();
130 my $date = $doc_obj->get_metadata_element ($doc_obj->get_top_section(), $self->{'datemeta'});
131
132 my $sort_other = "";
133 if (defined $self->{'sortmeta'} && $self->{'sortmeta'} ne "") {
134 $sort_other = $doc_obj->get_metadata_element ($doc_obj->get_top_section(), $self->{'sortmeta'});
135 }
136 # if this document doesn't contain Date element we won't
137 # include it in this classification
138 if (defined $date && $date =~ /\d/) {
139 if (defined $self->{'list'}->{$doc_OID}) {
140 my $outhandle = $self->{'outhandle'};
141 print $outhandle "WARNING: DateList::classify called multiple times for $doc_OID\n";
142 }
143
144
145 $self->{'list'}->{$doc_OID} = "$date$sort_other";
146 }
147}
148
149
150sub get_classify_info {
151 my $self = shift (@_);
152
153 my @classlist = sort {$self->{'list'}->{$a} cmp $self->{'list'}->{$b};} keys %{$self->{'list'}};
154
155 return $self->splitlist (\@classlist);
156}
157
158
159sub get_entry {
160 my $self = shift (@_);
161 my ($title, $childtype, $thistype) = @_;
162
163 # organise into classification structure
164 my %classifyinfo = ('childtype'=>$childtype,
165 'Title'=>$title,
166 'contains'=>[],
167 'mdtype'=>$self->{'datemeta'});
168 $classifyinfo{'thistype'} = $thistype
169 if defined $thistype && $thistype =~ /\w/;
170
171 return \%classifyinfo;
172}
173
174# splitlist takes an ordered list of classifications (@$classlistref) and
175# splits it up into sub-sections by date
176sub splitlist {
177 my $self = shift (@_);
178 my ($classlistref) = @_;
179 my $classhash = {};
180
181 # top level
182 my $childtype = "HList";
183
184 if (scalar (@$classlistref) <= 39 &&
185 !$self->{'nogroup'}) {$childtype = "DateList";}
186 my $classifyinfo = $self->get_entry ("Date", $childtype, "Invisible");
187 # don't need to do any splitting if there are less than 39 (max + min -1)
188 # classifications, unless nogroup is specified
189 if ((scalar @$classlistref) <= 39 && !$self->{'nogroup'}) {
190 foreach $subOID (@$classlistref) {
191 push (@{$classifyinfo->{'contains'}}, {'OID'=>$subOID});
192 }
193 return $classifyinfo;
194 }
195
196
197 if ($self->{'bymonth'}) {
198 # first split up the list into separate year+month classifications
199
200 if (!$self->{'nogroup'}) { # hlist of year+month pairs
201 # single level of classifications
202 foreach $classification (@$classlistref) {
203 my $date = $self->{'list'}->{$classification};
204 $date =~ s/^(\d\d\d\d)(\d\d).*$/$1&nbsp;_textmonth$2_/;
205 # sanity check if month is zero
206 if ($date =~ /00_$/) {
207 $date =~ s/^(\d\d\d\d).*$/$1/g;
208 }
209 $classhash->{$date} = [] unless defined $classhash->{$date};
210 push (@{$classhash->{$date}}, $classification);
211 }
212
213 } else { # don't group - individual years and months
214 foreach $classification (@$classlistref) {
215 my $date = $self->{'list'}->{$classification};
216 $date =~ s/^(\d\d\d\d)(\d\d).*$/$1&nbsp;_textmonth$2_/;
217 my ($year, $month)=($1,$2);
218 # sanity check if month is zero
219 if ($date =~ /00_$/) {
220 $date =~ s/^(\d\d\d\d).*$/$1/g;
221 }
222 # create subclass if it doesn't already exist
223 $classhash->{$year} = () unless defined $classhash->{$year};
224 $classhash->{$year}->{$month} = []
225 unless defined $classhash->{$year}->{$month};
226 push (@{$classhash->{$year}->{$month}}, $classification);
227 }
228 # create hlist of years containing hlists of months
229
230 foreach my $subclass (sort {$a <=> $b} keys %$classhash) {
231 my $yearclassify = $self->get_entry($subclass, "HList");
232 foreach my $subsubclass (sort {$a <=> $b}
233 (keys %{$classhash->{$subclass}})) {
234 my $monthname=$subsubclass;
235 if ($monthname >= 1 && $monthname <= 12) {
236 $monthname="_textmonth" . $monthname . "_";
237 }
238 my $monthclassify=$self->get_entry($monthname, "DateList");
239 push (@{$yearclassify->{'contains'}}, $monthclassify);
240
241 foreach $subsubOID
242 (@{$classhash->{$subclass}->{$subsubclass}}) {
243 push (@{$monthclassify->{'contains'}},
244 {'OID'=>$subsubOID});
245 }
246 }
247 push (@{$classifyinfo->{'contains'}}, $yearclassify);
248 }
249 return $classifyinfo;
250 } # nogroup
251 } else {
252 # not by month
253 # first split up the list into separate year classifications
254 foreach $classification (@$classlistref) {
255 my $date = $self->{'list'}->{$classification};
256 $date =~ s/^(\d\d\d\d).*$/$1/;
257 $classhash->{$date} = [] unless defined $classhash->{$date};
258 push (@{$classhash->{$date}}, $classification);
259 }
260 }
261
262 # only compact the list if nogroup not specified
263 if (!$self->{'nogroup'}) {
264 $classhash = $self->compactlist ($classhash);
265 }
266 foreach $subclass (sort keys %$classhash) {
267 my $tempclassify = $self->get_entry($subclass, "DateList");
268 foreach $subsubOID (@{$classhash->{$subclass}}) {
269 push (@{$tempclassify->{'contains'}}, {'OID'=>$subsubOID});
270 }
271 push (@{$classifyinfo->{'contains'}}, $tempclassify);
272 }
273
274 return $classifyinfo;
275}
276
277sub compactlist {
278 my $self = shift (@_);
279 my ($classhashref) = @_;
280 my $compactedhash = {};
281 my @currentOIDs = ();
282 my $currentfirstdate = "";
283 my $currentlastdate = "";
284 my $lastkey = "";
285
286 # minimum and maximum documents to be displayed per page.
287 # the actual maximum will be max + (min-1).
288 # the smallest sub-section is a single letter at present
289 # so in this case there may be many times max documents
290 # displayed on a page.
291 my $min = 10;
292 my $max = 30;
293 foreach my $subsection (sort keys %$classhashref) {
294 $currentfirstdate = $subsection if $currentfirstdate eq "";
295 if ((scalar (@currentOIDs) < $min) ||
296 ((scalar (@currentOIDs) + scalar (@{$classhashref->{$subsection}})) <= $max)) {
297 push (@currentOIDs, @{$classhashref->{$subsection}});
298 $currentlastdate = $subsection;
299 } else {
300
301 if ($currentfirstdate eq $currentlastdate) {
302 @{$compactedhash->{$currentfirstdate}} = @currentOIDs;
303 $lastkey = $currentfirstdate;
304 } else {
305 @{$compactedhash->{"$currentfirstdate-$currentlastdate"}} = @currentOIDs;
306 $lastkey = "$currentfirstdate-$currentlastdate";
307 }
308 if (scalar (@{$classhashref->{$subsection}}) >= $max) {
309 $compactedhash->{$subsection} = $classhashref->{$subsection};
310 @currentOIDs = ();
311 $currentfirstdate = "";
312 $lastkey = $subsection;
313 } else {
314 @currentOIDs = @{$classhashref->{$subsection}};
315 $currentfirstdate = $subsection;
316 $currentlastdate = $subsection;
317 }
318 }
319 }
320
321 # add final OIDs to last sub-classification if there aren't many otherwise
322 # add final sub-classification
323 if ((scalar (@currentOIDs) < $min) && (scalar (@currentOIDs) > 0)) {
324 # want every thing in previous up to the dash
325 my ($newkey) = $lastkey =~ /^([^\-]+)/;
326 @currentOIDs = (@{$compactedhash->{$lastkey}}, @currentOIDs);
327 delete $compactedhash->{$lastkey};
328 @{$compactedhash->{"$newkey-$currentlastdate"}} = @currentOIDs;
329 } else {
330 if ($currentfirstdate eq $currentlastdate) {
331 @{$compactedhash->{$currentfirstdate}} = @currentOIDs;
332 } else {
333 @{$compactedhash->{"$currentfirstdate-$currentlastdate"}} = @currentOIDs;
334 }
335 }
336
337 return $compactedhash;
338}
339
3401;
Note: See TracBrowser for help on using the repository browser.