[Bio] / Sprout / ResultHelper.pm Repository:
ViewVC logotype

Annotation of /Sprout/ResultHelper.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (view) (download) (as text)

1 : parrello 1.1 #!/usr/bin/perl -w
2 :    
3 :     package ResultHelper;
4 :    
5 :     use strict;
6 :     use Tracer;
7 :     use FIG;
8 :     use URI::Escape;
9 :    
10 :     =head1 Search Result Display Helper
11 :    
12 :     =head2 Introduction
13 :    
14 :     This is the base class for search output. It provides common methods for formatting the
15 :     output and providing options to the caller. This class is never used by itself.
16 :     Instead, a subclass (whose name begins with C<RH> is constructed.
17 :    
18 :     The following fields are maintained by this object.
19 :    
20 :     =over 4
21 :    
22 :     =item parent
23 :    
24 :     The parent search helper.
25 :    
26 :     =item record
27 :    
28 :     An B<ERDBObject> representing the current data.
29 :    
30 :     =item columns
31 :    
32 :     Reference to a hash specifying the different possible columns that can be
33 :     included in the result.
34 :    
35 :     =back
36 :    
37 :     Additional fields may be appended by the subclasses.
38 :    
39 :     =head2 Column Processing
40 :    
41 :     The subclass will generally have multiple column names defined. For each column,
42 :     several bits of information are needed-- how to format the column, how to compute
43 :     the column value at search time, how to compute it at run time (which is optional),
44 :     the column title to be used, and whether or not the column should be included in
45 :     a download. The orthodox object-oriented method for doing this would be to define
46 :     a B<Column> class and define each possible column using a subclass. To make things
47 :     a little less cumbersome, we instead define each column using a static method in
48 :     the subclass. The method gets as its parameters the result helper object and
49 :     the type of information required. For example, the following call would ask for
50 :     the title of a column called C<orgName>.
51 :    
52 :     my $title = RHFeatures::orgName(title => $rhelp);
53 :    
54 :     The B<orgName> method itself would look like this.
55 :    
56 :     sub orgName {
57 :     # Get the parameters.
58 :     my ($type, $rhelp, $key) = @_;
59 :     # Declare the return variable.
60 :     my $retVal;
61 :     # Process according to the information requested.
62 :     if ($type eq 'title' {
63 :     # Return the title for this column.
64 :     $retVal = 'Organism and Gene ID';
65 :     } elsif ($type eq 'download') {
66 :     # This field should be included in a download.
67 :     $retVal = 'text'; # or 'num', or 'list', or ''
68 :     } elsif ($type eq 'style') {
69 :     # This is a text field, so it's left-aligned.
70 :     $retVal = "leftAlign";
71 :     } elsif ($type eq 'value') {
72 :     # Get the organism and feature name.
73 :     $rhelp->FeatureName();
74 :     } elsif ($type eq 'runTimeValue') {
75 :     # This field does not require a runtime value.
76 :     };
77 :     return $retVal;
78 :     }
79 :    
80 :     The method is essentially a giant case statement based on the type of data desired. The
81 :     types are
82 :    
83 :     =over 4
84 :    
85 :     =item title
86 :    
87 :     Return the title of the column to be used when it is displayed.
88 :    
89 :     =item download
90 :    
91 :     Identifies how the column should be downloaded. An empty string means it should not
92 :     be downloaded at all. The other values are C<num>, indicating that the column contains
93 :     numeric data, C<text>, indicating that the column contains an html-escaped string,
94 :     C<link>, indicating that the column contains a L</Formlet>, C<list>, indicating that
95 :     the column contains a comma-separated list with optional hyperlinks, or C<align>,
96 :     indicating that the column contains multi-line aligned text with individual lines
97 :     separated by a C<br> tag.
98 :    
99 :     =item style
100 :    
101 :     Return the style to be used to display each table cell in the column. The return
102 :     value is a valid C<TD> class name from the style sheet. The style sheet should
103 :     contain styles for C<leftAlign>, C<rightAlign>, and C<center> to accomodate the
104 :     most common requirements.
105 :    
106 :     =item value
107 :    
108 :     Return the value to be stored in the result cache. In most cases, this should be an
109 :     html string. If the value is to be computed when the data is displayed (which is
110 :     sometimes necessary for performance reasons), then the return value should be of
111 :     the form C<%%>I<colName>C<=>I<key>, where I<colName> is the column name and
112 :     I<key> is a value used to compute the result at display time. The key value will
113 :     be passed as a third parameter to the column method.
114 :    
115 :     =item runTimeValue
116 :    
117 :     Return the value to be displayed. This method is only used when the information
118 :     is not easily available at the time the result cache is built.
119 :    
120 :     =back
121 :    
122 :     The idea behind this somewhat cumbersome design is that new columns can be added
123 :     very easily by simply adding a new method to the result helper.
124 :    
125 :     Note that a column name must be a valid PERL method name! This means no spaces
126 :     or other fancy stuff.
127 :    
128 :     Run-time values are a bit tricky, and require some explanation. The normal procedure
129 :     during a search is to compute the values to be displayed as soon as an item is found
130 :     and store them directly in the result cache. Run-time values are those that are too
131 :     expensive to compute during the search, so they are not computed until the result
132 :     cache is displayed. Because a search can return thousands of results, but only 50 or
133 :     so are displayed at a time, this makes a big difference.
134 :    
135 :     =head2 Extra Columns
136 :    
137 :     It is necessary for individual searches to be able to create output columns specific
138 :     to the type of search. These are called extra columns.
139 :    
140 :     To create extra columns, you use the L</AddExtraColumn> method. This method
141 :     specifies the location of an extra column in the column list, its name, and its format.
142 :    
143 :     The extra columns are put in whatever positions the user specifies, although if
144 :     you try to put two columns in the same place or add a column before another added
145 :     column, this could cause the position to shift.
146 :    
147 :     Unlike regular columns, there is no need to compute a value or run-time value. The
148 :     other column properties (title, style, etc.) are stored in the extra column's
149 :     definition in this object. When the column headers are written, the header for an
150 :     extra column is in the form C<X=>I<something>. The I<something> is a frozen copy
151 :     of the extra column's hash. When the headers are read back in, the extra column data
152 :     is thawed into the hash so that the various options are identical to what they were
153 :     when the result cache was created.
154 :    
155 :     Extra columns are the most volatile requirement in the whole search system. I will
156 :     count myself happy if this implementation of them lasts more than a week.
157 :    
158 :     =cut
159 :    
160 :     # This value is used to do a single indent level in the XML output.
161 :     use constant XML_INDENT => " ";
162 :    
163 :     =head2 Public Methods
164 :    
165 :     =head3 new
166 :    
167 :     C<< my $rhelp = ResultHelper->new($shelp); >>
168 :    
169 :     Construct a new ResultHelper object to serve the specified search helper.
170 :    
171 :     =over 4
172 :    
173 :     =item shelp
174 :    
175 :     Parent search helper that is generating the output.
176 :    
177 :     =item type
178 :    
179 :     Classname used to format requests for columns.
180 :    
181 :     =item extras
182 :    
183 :     Reference to a hash of extra column data keyed on extra column name. For each extra column,
184 :     it contains the column's current value.
185 :    
186 :     =item cache
187 :    
188 :     A hash for use by the run-time value methods, to save time when multiple run-time values
189 :     use the same base object.
190 :    
191 :     =item columns
192 :    
193 :     The list of the columns to displayed in the search results. Normal columns are stored as
194 :     strings. Extra columns are stored as hash references.
195 :    
196 :     =item record
197 :    
198 :     Data record for the current output row.
199 :    
200 :     =item id
201 :    
202 :     ID for the current output row.
203 :    
204 :     =item RETURN
205 :    
206 :     Returns a newly-constructed result helper.
207 :    
208 :     =back
209 :    
210 :     =cut
211 :    
212 :     sub new {
213 :     # Get the parameters.
214 :     my ($class, $shelp) = @_;
215 :     # Save the result type in the CGI parms.
216 :     my $cgi = $shelp->Q();
217 :     $cgi->param(-name => 'ResultType', -value => substr($class, 2));
218 :     Trace("Result helper created of type $class.") if T(3);
219 :     # Create the $rhelp object.
220 :     my $retVal = {
221 :     parent => $shelp,
222 :     record => undef,
223 :     id => undef,
224 :     type => $class,
225 :     extras => {},
226 :     cache => {},
227 :     columns => [],
228 :     };
229 :     # Return it.
230 :     return $retVal;
231 :     }
232 :    
233 :     =head3 DB
234 :    
235 :     C<< my $sprout = $rhelp->DB(); >>
236 :    
237 :     Return the Sprout object for accessing the database.
238 :    
239 :     =cut
240 :    
241 :     sub DB {
242 :     # Get the parameters.
243 :     my ($self) = @_;
244 :     # Return the parent helper's database object.
245 :     return $self->Parent()->DB();
246 :     }
247 :    
248 :     =head3 PutData
249 :    
250 :     C<< $rhelp->PutData($sortKey, $id, $record); >>
251 :    
252 :     Store a line of data in the result file.
253 :    
254 :     =over 4
255 :    
256 :     =item sortKey
257 :    
258 :     String to be used for sorting this line of data among the others.
259 :    
260 :     =item id
261 :    
262 :     ID string for the result line. This is not shown in the results, but
263 :     is used by some of the download methods.
264 :    
265 :     =item record
266 :    
267 :     An B<ERDBObject> containing data to be used by the column methods.
268 :    
269 :     =back
270 :    
271 :     =cut
272 :    
273 :     sub PutData {
274 :     # Get the parameters.
275 :     my ($self, $sortKey, $id, $record) = @_;
276 :     # Save the data record and ID so the column methods can get to it.
277 :     $self->{record} = $record;
278 :     $self->{id} = $id;
279 :     # Loop through the columns, producing output data.
280 :     my @outputCols = ();
281 :     for my $column (@{$self->{columns}}) {
282 :     push @outputCols, $self->ColumnValue($column);
283 :     }
284 :     # Get the parent search helper.
285 :     my $shelp = $self->{parent};
286 :     # Write the column data.
287 :     $shelp->WriteColumnData($sortKey, $id, @outputCols);
288 :     }
289 :    
290 :     =head3 GetColumnHeaders
291 :    
292 :     C<< my $colHdrs = $rhelp->GetColumnHeaders(); >>
293 :    
294 :     Return the list of column headers for this session. The return value is a
295 :     reference to the live column header list.
296 :    
297 :     =cut
298 :    
299 :     sub GetColumnHeaders {
300 :     # Get the parameters.
301 :     my ($self) = @_;
302 :     # Return the column headers.
303 :     return $self->{columns};
304 :     }
305 :    
306 :     =head3 DownloadFormatsAvailable
307 :    
308 :     C<< my %dlTypes = $rhelp->DownloadFormatsAvailable(); >>
309 :    
310 :     Return a hash mapping each download type to a download description. The default is
311 :     the C<tbl> format, which is a tab-delimited download, and the C<xml> format,
312 :     which is XML. If you want additional formats, override L</MoreDownloadFormats>.
313 :    
314 :     =cut
315 :    
316 :     sub DownloadFormatsAvailable {
317 :     # Get the parameters.
318 :     my ($self) = @_;
319 :     Trace("Creating download type hash.") if T(3);
320 :     # Declare the return variable.
321 :     my %retVal = ( tbl => 'Results table as a tab-delimited file',
322 :     xml => 'Results table in XML format');
323 :     Trace("Asking for download formats from the helper.") if T(3);
324 :     # Ask for more formats.
325 :     $self->MoreDownloadFormats(\%retVal);
326 :     # Return the resulting hash.
327 :     return %retVal;
328 :     }
329 :    
330 :     =head3 DownloadDataLine
331 :    
332 :     C<< $rhelp->DownloadDataLine($objectID, $dlType, \@cols, \@colHdrs); >>
333 :    
334 :     Return one or more lines of download data. The exact data returned depends on the
335 :     download type.
336 :    
337 :     =over 4
338 :    
339 :     =item objectID
340 :    
341 :     ID of the object whose data is in this line of results.
342 :    
343 :     =item dlType
344 :    
345 :     The type of download (e.g. C<tbl>, C<fasta>).
346 :    
347 :     =item eol
348 :    
349 :     The end-of-line character to use.
350 :    
351 :     =item cols
352 :    
353 :     A reference to a list of the data columns, or a string containing
354 :     C<header> or C<footer>. The strings will cause the header lines
355 :     or footer lines to be output rather than a data line.
356 :    
357 :     =item colHdrs
358 :    
359 :     A reference to a list of the column headers. Each header describes the data found
360 :     in the corresponding column of the I<cols> list.
361 :    
362 :     =item RETURN
363 :    
364 :     Returns a list of strings that can be written to the download output.
365 :    
366 :     =back
367 :    
368 :     =cut
369 :    
370 :     sub DownloadDataLine {
371 :     # Get the parameters.
372 :     my ($self, $objectID, $dlType, $cols, $colHdrs) = @_;
373 :     # Declare the return variable.
374 :     my @retVal = ();
375 :     # Check the download type.
376 :     if ($dlType eq 'tbl' || $dlType eq 'xml') {
377 :     # Check for headers or footers.
378 :     if ($cols eq 'header') {
379 :     # Here we want headers. Only the XML type has them.
380 :     if ($dlType eq 'xml') {
381 :     @retVal = ('<?xml version="1.0" encoding="utf-8" ?>',
382 :     '<Results>');
383 :     }
384 :     } elsif ($cols eq 'footer') {
385 :     # Here we want footers. Again, only the XML type requires them.
386 :     if ($dlType eq 'xml') {
387 :     @retVal = ('</Results>');
388 :     }
389 :     } else {
390 :     # Here we are downloading the displayed columns as a tab-delimited file or
391 :     # as XML and we are tasked with producing the output lines for the current
392 :     # row of data. The first thing is to get the download format information
393 :     # about the columns.
394 :     my @keepCols = map { $self->ColumnDownload($_) } @{$colHdrs};
395 :     # Remove the columns that are not being kept. The list we create here
396 :     # will contain the name of each column, its value, and its download format.
397 :     my @actualCols = ();
398 :     for (my $i = 0; $i <= $#keepCols; $i++) {
399 :     if ($keepCols[$i]) {
400 :     push @actualCols, [$colHdrs->[$i], $self->GetRunTimeValues($cols->[$i]), $keepCols[$i]];
401 :     }
402 :     }
403 :     # Now it's time to do the actual writing, so we need to know if this
404 :     # is XML or tab-delimited.
405 :     if ($dlType eq 'tbl') {
406 :     # Clean up the HTML.
407 :     my @actual = map { HtmlCleanup($_->[1], $_->[2]) } @actualCols;
408 :     # Return the line of data.
409 :     push @retVal, join("\t", @actual);
410 :     } elsif ($dlType eq 'xml') {
411 :     # Convert to XML. Since a single XML tag can contain multiple lines, we re-split them.
412 :     # This is important, because when the lines are output we need to insure the correct
413 :     # EOL character is used.
414 :     my @actual = map { split /\n/, "<$_->[0]>" . XmlCleanup($_->[1], $_->[2]) . "</$_->[0]>" } @actualCols;
415 :     # Return the XML object.
416 :     push @retVal, XML_INDENT x 1 . "<Item id=\"$objectID\">";
417 :     push @retVal, map { XML_INDENT x 2 . $_ } @actual;
418 :     push @retVal, XML_INDENT x 1 . "</Item>";
419 :     }
420 :     }
421 :     } else {
422 :     # Now we have a special-purpose download format, so we let the subclass deal
423 :     # with it.
424 :     @retVal = $self->MoreDownloadDataMethods($objectID, $dlType, $cols, $colHdrs);
425 :     }
426 :     # Return the result.
427 :     return @retVal;
428 :     }
429 :    
430 :     =head3 Formlet
431 :    
432 :     C<< my $html = $rhelp->Formlet($caption, $url, $target, %parms); >>
433 :    
434 :     Create a mini-form that posts to the specified URL with the specified parameters. The
435 :     parameters will be stored in hidden fields, and the form's only visible control will
436 :     be a submit button with the specified caption.
437 :    
438 :     Note that we don't use B<CGI.pm> services here because they generate forms with extra characters
439 :     and tags that we don't want to deal with.
440 :    
441 :     This method is tightly bound to L</FormletToLink>, which converts a formlet to a URL. A
442 :     change here will require a change to the other method.
443 :    
444 :     =over 4
445 :    
446 :     =item caption
447 :    
448 :     Caption to be put on the form button.
449 :    
450 :     =item url
451 :    
452 :     URL to be put in the form's action parameter.
453 :    
454 :     =item target
455 :    
456 :     Frame or target in which the form results should appear. If C<undef> is specified,
457 :     the default target will be used.
458 :    
459 :     =item parms
460 :    
461 :     Hash containing the parameter names as keys and the parameter values as values.
462 :    
463 :     =back
464 :    
465 :     =cut
466 :    
467 :     sub Formlet {
468 :     # Get the parameters.
469 :     my ($self, $caption, $url, $target, %parms) = @_;
470 :     # Compute the target HTML.
471 :     my $targetHtml = ($target ? " target=\"$target\"" : "");
472 :     # Start the form.
473 :     my $retVal = "<form method=\"POST\" action=\"$url\"$target>";
474 :     # Add the parameters.
475 :     for my $parm (keys %parms) {
476 :     $retVal .= "<input type=\"hidden\" name=\"$parm\" value=\"$parms{$parm}\" />";
477 :     }
478 :     # Put in the button.
479 :     $retVal .= "<input type=\"submit\" name=\"submit\" value=\"$caption\" class=\"button\" />";
480 :     # Close the form.
481 :     $retVal .= "</form>";
482 :     # Return the result.
483 :     return $retVal;
484 :     }
485 :    
486 :     =head3 HtmlCleanup
487 :    
488 :     C<< my $text = ResultHelper::HtmlCleanup($htmlText, $type); >>
489 :    
490 :     Take a string of Html text and clean it up so it appears as real text.
491 :     Note that this method is not yet sophisticated enough to detect right-angle brackets
492 :     inside tag parameters, nor can it handle style or script tags. Its only sophistication
493 :     is that it knows how to convert a formlet to a URL. Otherwise, it is a dirt simple
494 :     method that suffices for search result processing.
495 :    
496 :     =over 4
497 :    
498 :     =item htmlText
499 :    
500 :     Html text to clean up.
501 :    
502 :     =item type
503 :    
504 :     Type of column: C<num> for a number, C<text> for a string, C<list> for a
505 :     comma-separated list, and C<link> for a formlet link.
506 :    
507 :     =item RETURN
508 :    
509 :     Returns the downloadable form of the Html string.
510 :    
511 :     =back
512 :    
513 :     =cut
514 :    
515 :     sub HtmlCleanup {
516 :     # Get the parameters.
517 :     my ($htmlText, $type) = @_;
518 :     # Declare the return variable.
519 :     my $retVal;
520 :     # Check for a formlet.
521 :     if ($type eq 'link') {
522 :     # Here we have a formlet and we want to convert it to a URL.
523 :     $retVal = FormletToLink($htmlText);
524 :     } elsif ($type eq 'align') {
525 :     # Here we have multiple lines. Convert the new-lines to serial commas.
526 :     $retVal =~ s/<br\s*\/?>/, /g;
527 :     } else {
528 :     # Here we have normal HTML. Start by taking the raw text.
529 :     $retVal = $htmlText;
530 :     # Delete any tags. This is a very simplistic algorithm that will fail if there
531 :     # is a right angle bracket inside a parameter string.
532 :     $retVal =~ s/<[^>]+>//g;
533 :     # Unescape the & tags.
534 :     $retVal = CGI::unescapeHTML($retVal);
535 :     }
536 :     # Return the result.
537 :     return $retVal;
538 :     }
539 :    
540 :     =head3 XmlCleanup
541 :    
542 :     C<< my $text = ResultHelper::XmlCleanup($htmlText, $type); >>
543 :    
544 :     Take a string of Html text and clean it up so it appears as html.
545 :    
546 :     =over 4
547 :    
548 :     =item htmlText
549 :    
550 :     Html text to clean up.
551 :    
552 :     =item type
553 :    
554 :     Type of column: C<num> for a number, C<text> for a string, C<list> for a
555 :     comma-separated list, and C<link> for a formlet link.
556 :    
557 :     =item RETURN
558 :    
559 :     Returns the column data in XML format.
560 :    
561 :     =back
562 :    
563 :     =cut
564 :    
565 :     sub XmlCleanup {
566 :     # Get the parameters.
567 :     my ($htmlText, $type) = @_;
568 :     # Declare the return variable.
569 :     my $retVal;
570 :     # Check for a formlet.
571 :     if ($type eq 'link') {
572 :     # Here we have a formlet and we want to convert it to a URL. We begin
573 :     # with the action.
574 :     if ($htmlText =~ /action="([^"]+)"/i) {
575 :     $retVal = $1;
576 :     # Now, parse out the parameters, all of which are stored in the formlet as hidden
577 :     # input fields. This is the point where we assume that the formlet generates things
578 :     # in a well-defined format.
579 :     my @parms = ();
580 :     while ($htmlText =~ /<input\s+type="hidden"\s+name="([^"]+)"\s+value="([^"]+)"/ig) {
581 :     push @parms, "$1=" . uri_escape($2);
582 :     }
583 :     # If there were any parameters, assemble them into the URL.
584 :     if (scalar(@parms)) {
585 :     $retVal .= "?" . join(";", @parms);
586 :     }
587 :     } else {
588 :     # Here the column is empty. We output an empty string.
589 :     $retVal = '';
590 :     }
591 :     } elsif ($type eq 'num' || $type eq 'text') {
592 :     # Here we have a number or text. Return the raw value.
593 :     $retVal = $htmlText;
594 :     } elsif ($type eq 'align') {
595 :     # Here we have aligned text. This is converted into an XML array of lines.
596 :     # First, we find the break tags.
597 :     my @lines = split /<br[^>]+>/, $htmlText;
598 :     # Format the lines as an XML array. The extra new-line causes the first array
599 :     # element to be on a separate line from the first item tag.
600 :     $retVal = "\n" . map { XML_INDENT . "<line>$_</line>\n" } @lines;
601 :     } elsif ($type eq 'list') {
602 :     # Here we have a comma-delimited list of possibly-linked strings. We will convert it to
603 :     # an XML array. First, we get the pieces.
604 :     my @entries = split /\s*,\s*/, $htmlText;
605 :     # Each piece is processed individually, so we can check for hyperlinks.
606 :     # The return value starts with a new-line, so that the first list element
607 :     # is not on the same line as the open tag.
608 :     $retVal = "\n";
609 :     for my $entry (@entries) {
610 :     # Check for a hyperlink.
611 :     if ($entry =~ /<a[^>]+(href="[^"]+")[^>]*>(.+)<\/a>/) {
612 :     # Put the URL in the tag.
613 :     $retVal .= XML_INDENT . "<value $1>$2</value>\n";
614 :     } else {
615 :     # No URL, so the tag is unadorned.
616 :     $retVal .= XML_INDENT . "<value>$entry</value>\n";
617 :     }
618 :     }
619 :     }
620 :     # Return the result.
621 :     return $retVal;
622 :     }
623 :    
624 :     =head3 FormletToLink
625 :    
626 :     C<< my $url = ResultHelper::FormletToLink($htmlText); >>
627 :    
628 :     Convert a formlet to a link. This process is bound very tightly with
629 :     the way L</Formlet> generates Html. A change there requires a change
630 :     here.
631 :    
632 :     =over 4
633 :    
634 :     =item htmlText
635 :    
636 :     HTML text for the formlet.
637 :    
638 :     =item RETURN
639 :    
640 :     Returns a URL that will produce the same result as clicking the formlet button.
641 :    
642 :     =back
643 :    
644 :     =cut
645 :    
646 :     sub FormletToLink {
647 :     # Get the parameters.
648 :     my ($htmlText) = @_;
649 :     # Declare the return variable.
650 :     my $retVal;
651 :     # We begin with the action.
652 :     $htmlText =~ /action="([^"]+)"/i;
653 :     $retVal = $1;
654 :     # Now, parse out the parameters, all of which are stored in the formlet as hidden
655 :     # input fields. This is the point where we assume that the formlet generates things
656 :     # in a well-defined format.
657 :     my @parms = ();
658 :     while ($htmlText =~ /<input\s+type="hidden"\s+name="([^"]+)"\s+value="([^"]+)"/ig) {
659 :     push @parms, "$1=" . uri_escape($2);
660 :     }
661 :     # If there were any parameters, assemble them into the URL.
662 :     if (scalar(@parms)) {
663 :     $retVal .= "?" . join(";", @parms);
664 :     }
665 :     # Return the result.
666 :     return $retVal;
667 :     }
668 :    
669 :     =head3 FakeButton
670 :    
671 :     C<< my $html = $rhelp->FakeButton($caption, $url, $target, %parms); >>
672 :    
673 :     Create a fake button that hyperlinks to the specified URL with the specified parameters.
674 :     Unlike a real button, this one won't visibly click, but it will take the user to the
675 :     correct place.
676 :    
677 :     The parameters of this method are deliberately identical to L</Formlet> so that we
678 :     can switch easily from real buttons to fake ones in the code.
679 :    
680 :     =over 4
681 :    
682 :     =item caption
683 :    
684 :     Caption to be put on the button.
685 :    
686 :     =item url
687 :    
688 :     URL for the target page or script.
689 :    
690 :     =item target
691 :    
692 :     Frame or target in which the new page should appear. If C<undef> is specified,
693 :     the default target will be used.
694 :    
695 :     =item parms
696 :    
697 :     Hash containing the parameter names as keys and the parameter values as values.
698 :     These will be appended to the URL.
699 :    
700 :     =back
701 :    
702 :     =cut
703 :    
704 :     sub FakeButton {
705 :     # Get the parameters.
706 :     my ($self, $caption, $url, $target, %parms) = @_;
707 :     # Declare the return variable.
708 :     my $retVal;
709 :     # Compute the target URL.
710 :     my $targetUrl = "$url?" . join(";", map { "$_=" . uri_escape($parms{$_}) } keys %parms);
711 :     # Compute the target-frame HTML.
712 :     my $targetHtml = ($target ? " target=\"$target\"" : "");
713 :     # Assemble the result.
714 :     return "<a href=\"$targetUrl\" $targetHtml><div class=\"button2 button\">$caption</div></a>";
715 :     }
716 :    
717 :     =head3 Parent
718 :    
719 :     C<< my $shelp = $rhelp->Parent(); >>
720 :    
721 :     Return this helper's parent search helper.
722 :    
723 :     =cut
724 :    
725 :     sub Parent {
726 :     # Get the parameters.
727 :     my ($self) = @_;
728 :     # Return the parent.
729 :     return $self->{parent};
730 :     }
731 :    
732 :     =head3 Record
733 :    
734 :     C<< my $erdbObject = $rhelp->Record(); >>
735 :    
736 :     Return the record currently stored in this object. The record contains the data for
737 :     the result output line being built, and is in the form of a B<ERDBObject>.
738 :    
739 :     =cut
740 :    
741 :     sub Record {
742 :     # Get the parameters.
743 :     my ($self) = @_;
744 :     # Get the record.
745 :     my $retVal = $self->{record};
746 :     # If it does not exist, trace a message.
747 :     Trace("No record found in result helper.") if T(3) && ! defined($retVal);
748 :     # Return the record.
749 :     return $retVal;
750 :     }
751 :    
752 :     =head3 ID
753 :    
754 :     C<< my $id = $rhelp->ID(); >>
755 :    
756 :     Return the ID for the record currently stored in this object (if any).
757 :    
758 :    
759 :     =cut
760 :    
761 :     sub ID {
762 :     # Get the parameters.
763 :     my ($self) = @_;
764 :     # Get the record.
765 :     my $retVal = $self->{id};
766 :     # If it does not exist, trace a message. We say "no record found" because a
767 :     # missing ID implies a missing record.
768 :     Trace("No record found in result helper.") if T(3) && ! defined($retVal);
769 :     # Return the ID.
770 :     return $retVal;
771 :     }
772 :    
773 :    
774 :    
775 :     =head3 Cache
776 :    
777 :     C<< my $cacheHash = $rhelp->Cache(); >>
778 :    
779 :     Return a reference to the internal cache. The internal cache is used by the
780 :     run-time value methods to keep stuff in memory between calls for the same
781 :     output line.
782 :    
783 :     =cut
784 :    
785 :     sub Cache {
786 :     # Get the parameters.
787 :     my ($self) = @_;
788 :     # Return the cache.
789 :     return $self->{cache};
790 :     }
791 :    
792 :     =head3 PreferredID
793 :    
794 :     C<< my $featureID = $rhelp->PreferredID($featureObject); >>
795 :    
796 :     Return the preferred ID for the specified feature. The feature passed in must be in the
797 :     form of an ERDB feature object. The preferred alias type will be determined using the
798 :     CGI C<AliasType> parameter, and then cached in the feature object using the name
799 :     C<Feature(alias)> so this method can find it easily if it is needed again.
800 :    
801 :     =over 4
802 :    
803 :     =item featureObject
804 :    
805 :     An B<ERDBObject> for the relevant feature.
806 :    
807 :     =item RETURN
808 :    
809 :     The preferred ID for the feature (Locus Tag, Uniprot ID, etc.) if one exists, otherwise
810 :     the FIG ID.
811 :    
812 :     =back
813 :    
814 :     =cut
815 :    
816 :     sub PreferredID {
817 :     # Get the parameters.
818 :     my ($self, $featureObject) = @_;
819 :     # Declare the return variable.
820 :     my $retVal;
821 :     # Check for a cached value.
822 :     if ($featureObject->HasField('Feature(alias)')) {
823 :     $retVal = $featureObject->PrimaryValue('Feature(alias)');
824 :     } else {
825 :     # Here we need to compute the alias. First, get the preferred type.
826 :     my $aliasType = $self->Parent()->GetPreferredAliasType();
827 :     # The fallback is to use the FIG ID.
828 :     my $fid = $featureObject->PrimaryValue('Feature(id)');
829 :     $retVal = $fid;
830 :     # We only need to proceed if the preferred type is NOT FIG.
831 :     if ($aliasType ne 'FIG') {
832 :     # Here we need to find a real alias of the specified type. To start,
833 :     # we need a Sprout object.
834 :     my $sprout = $self->DB();
835 :     # Ask for all the aliases connected to this feature ID.
836 :     my @aliases = $sprout->GetFlat(['IsAliasOf'], 'IsAliasOf(to-link) = ?',
837 :     [$fid], 'IsAliasOf(from-link)');
838 :     # Extract an alias of the preferred type.
839 :     my $foundAlias = AliasAnalysis::Find($aliasType, \@aliases);
840 :     # If an alias was found, use it. Otherwise, the FIG ID will stay in place.
841 :     if (defined($foundAlias)) {
842 :     $retVal = $foundAlias;
843 :     }
844 :     }
845 :     # Save the alias type for future calls.
846 :     $featureObject->AddValues('Feature(alias)', $retVal);
847 :     }
848 :     # Return the ID computed.
849 :     return $retVal;
850 :     }
851 :    
852 :    
853 :     =head2 Column-Related Methods
854 :    
855 :     =head3 Compute
856 :    
857 :     C<< my $retVal = $rhelp->Compute($type, $colName, $runTimeKey); >>
858 :    
859 :     Call a column method to return a result. This involves some fancy C<eval> stuff.
860 :     The column method is called as a static method of the relevant subclass.
861 :    
862 :     =over 4
863 :    
864 :     =item type
865 :    
866 :     The type of column data requested: C<title> for the column title, C<style> for the
867 :     column's display style, C<value> for the value to be put in the result cache,
868 :     C<download> for the indicator of how the column should be included in
869 :     downloads, and C<runTimeValue> for the value to be used when the result is
870 :     displayed. Note that if a run-time value is required, then the normal value
871 :     must be formatted in a special way (see L<Column Processing>).
872 :    
873 :     A little fancy dancing is required for extra columns. For extra columns, only
874 :     the title, style, and download status are ever requested.
875 :    
876 :     =item colName
877 :    
878 :     Name of the column of interest. The name may contain a colon, in which case
879 :     the column name is the part before the colon and the value after it is
880 :     passed to the column method as the run-time key.
881 :    
882 :     =item runTimeKey (optional)
883 :    
884 :     If a run-time value is desired, this should be the key taken from the value stored
885 :     in the result cache.
886 :    
887 :     =item RETURN
888 :    
889 :     Returns the desired result for the specified column.
890 :    
891 :     =back
892 :    
893 :     =cut
894 :    
895 :     sub Compute {
896 :     # Get the parameters.
897 :     my ($self, $type, $colName, $runTimeKey) = @_;
898 :     # Declare the return variable.
899 :     my $retVal;
900 :     # Check for an extra column.
901 :     if (ref $colName eq 'HASH') {
902 :     # Look for the appropriate data from the hash.
903 :     if ($type eq 'value') {
904 :     # The caller wants the column value, which is stored in the "extras"
905 :     # member keyed by column name.
906 :     my $realName = $colName->{name};
907 :     $retVal = $self->{extras}->{$realName};
908 :     Trace("Extra column $realName retrieved value is $retVal.") if T(4);
909 :     } else {
910 :     # The other data items are stored in the column name itself.
911 :     $retVal = $colName->{$type};
912 :     }
913 :     } else {
914 :     # Here we have a real built-in column. The search helper chooses which of
915 :     # these to use (usually by adding to a default list), and we use static
916 :     # methods in our subclass to process them. An eval call is used to
917 :     # accomplish the result. First, we do some goofiness so we can deal
918 :     # with the possible absence of a run-time key.
919 :     my $realRunTimeKey = (defined $runTimeKey ? ", '$runTimeKey'" : "");
920 :     # Check for a complex column name. Note that during run-time expansion, the
921 :     # column names will have been simplified (that is, the colon will have been
922 :     # removed and the parameter attached to the incoming run-time key.
923 :     if ($colName =~ /(\S+):(.+)/) {
924 :     $colName = $1;
925 :     $realRunTimeKey = $2;
926 :     }
927 :     # Get the result helper type.
928 :     my $rhType = $self->{type};
929 :     # Create the string for returning the desired results.
930 :     my $expression = "${rhType}::$colName($type => \$self$realRunTimeKey)";
931 :     # Evaluate to get the result. Note we automatically translate undefined results to
932 :     # an empty string.
933 :     Trace("Evaluating: $expression") if T(4);
934 :     $retVal = eval($expression) || "";
935 :     # Check for an error.
936 :     if ($@) {
937 :     Trace("Evaluation failed in Compute of $expression") if T(1);
938 :     Confess("$self->{type} column request failed: $@");
939 :     }
940 :     }
941 :     # Return the computed result.
942 :     return $retVal;
943 :     }
944 :    
945 :     =head3 ColumnDownload
946 :    
947 :     C<< my $flag = $rhelp->ColumnDownload($colName); >>
948 :    
949 :     Return the type of data in the column, or an empty string if it should
950 :     not be downloaded. In general, all columns are downloaded except those
951 :     that are graphic representations of something.
952 :    
953 :     =over 4
954 :    
955 :     =item colName
956 :    
957 :     Name of the column in question.
958 :    
959 :     =item RETURN
960 :    
961 :     Returns one of the download data types discussed in L</Column Processing>.
962 :    
963 :     =back
964 :    
965 :     =cut
966 :    
967 :     sub ColumnDownload {
968 :     # Get the parameters.
969 :     my ($self, $colName) = @_;
970 :     # Compute the result.
971 :     my $retVal = $self->Compute(download => $colName);
972 :     # Return it.
973 :     return $retVal;
974 :     }
975 :    
976 :     =head3 ColumnTitle
977 :    
978 :     C<< my $titleHtml = $rhelp->ColumnTitle($colName); >>
979 :    
980 :     Return the title to be used in the result table for the specified column.
981 :    
982 :     =over 4
983 :    
984 :     =item colName
985 :    
986 :     Name of the relevant column.
987 :    
988 :     =item RETURN
989 :    
990 :     Returns the html to be used for the column title.
991 :    
992 :     =back
993 :    
994 :     =cut
995 :    
996 :     sub ColumnTitle {
997 :     # Get the parameters.
998 :     my ($self, $colName) = @_;
999 :     # Compute the result.
1000 :     my $retVal = $self->Compute(title => $colName);
1001 :     # Return it.
1002 :     return $retVal;
1003 :     }
1004 :    
1005 :     =head3 ColumnValue
1006 :    
1007 :     C<< my $htmlValue = $rhelp->ColumnValue($colName); >>
1008 :    
1009 :     Return the display value for a column. This could be HTML text or it
1010 :     could be a run-time value specification. The column value is computed
1011 :     using the data record currently stored in the result helper.
1012 :    
1013 :     =over 4
1014 :    
1015 :     =item colName
1016 :    
1017 :     Name of the column whose value is desired.
1018 :    
1019 :     =item RETURN
1020 :    
1021 :     Returns the value to be stored in the result cache.
1022 :    
1023 :     =back
1024 :    
1025 :     =cut
1026 :    
1027 :     sub ColumnValue {
1028 :     # Get the parameters.
1029 :     my ($self, $colName) = @_;
1030 :     # Compute the return value.
1031 :     my $retVal = $self->Compute(value => $colName);
1032 :     # Return it.
1033 :     return $retVal;
1034 :     }
1035 :    
1036 :     =head3 ColumnStyle
1037 :    
1038 :     C<< my $className = $rhelp->ColumnStyle($colName); >>
1039 :    
1040 :     Return the display style for the specified column. This must be a classname
1041 :     defined for C<TD> tags in the active style sheet.
1042 :    
1043 :     =over 4
1044 :    
1045 :     =item colName
1046 :    
1047 :     Name of the relevant column.
1048 :    
1049 :     =item RETURN
1050 :    
1051 :     Returns the name of the style class to be used for this column's cells.
1052 :    
1053 :     =back
1054 :    
1055 :     =cut
1056 :    
1057 :     sub ColumnStyle {
1058 :     # Get the parameters.
1059 :     my ($self, $colName) = @_;
1060 :     # Compute the return value.
1061 :     my $retVal = $self->Compute(style => $colName);
1062 :     # Return it.
1063 :     return $retVal;
1064 :     }
1065 :    
1066 :     =head3 GetRunTimeValues
1067 :    
1068 :     C<< my @valueHtml = $rhelp->GetRunTimeValues(@cols); >>
1069 :    
1070 :     Return the run-time values of a row of columns. The incoming values contain
1071 :     the actual column contents. Run-time columns will be identified by the
1072 :     leading C<%%> marker. The run-time columns are converted in sequence
1073 :     using methods in the base class.
1074 :    
1075 :     =over 4
1076 :    
1077 :     =item cols
1078 :    
1079 :     A list of columns. Runtime columns will be of the format C<%%>I<colName>C<=>I<key>,
1080 :     where I<colName> is the actual column name and I<key> is the key to be passed to
1081 :     the evaluator. Columns that do not have this format are unchanged.
1082 :    
1083 :     =item RETURN
1084 :    
1085 :     Returns a list of the final values for all the run-time columns.
1086 :    
1087 :     =back
1088 :    
1089 :     =cut
1090 :    
1091 :     sub GetRunTimeValues {
1092 :     # Get the parameters.
1093 :     my ($self, @cols) = @_;
1094 :     # Declare the return value.
1095 :     my @retVal = ();
1096 :     # Clear the cache. The run-time value methods can store stuff
1097 :     # in here to save computation time.
1098 :     $self->{cache} = {};
1099 :     # Loop through the columns.
1100 :     for my $col (@cols) {
1101 :     # Declare a holding variable.
1102 :     my $retVal;
1103 :     # Parse the column data.
1104 :     if ($col =~ /^%%(\w+)=(.+)/) {
1105 :     # It parsed as a run-time value, so call the Compute method.
1106 :     $retVal = $self->Compute(runTimeValue => $1, $2);
1107 :     } else {
1108 :     # Here it's a search-time value, so we leave it unchanged.
1109 :     $retVal = $col;
1110 :     }
1111 :     # Add this column to the result list.
1112 :     push @retVal, $retVal;
1113 :     }
1114 :     # Return the result.
1115 :     return @retVal;
1116 :     }
1117 :    
1118 :     =head3 SetColumns
1119 :    
1120 :     C<< $rhelp->SetColumns(@cols); >>
1121 :    
1122 :     Store the specified object columns. These are the columns computed by the search
1123 :     framework, and should generally be specified first. If the search itself is
1124 :     going to generate additional data, the columns for displaying this additional
1125 :     data should be specified by a subsequent call to L</AddExtraColumn>.
1126 :    
1127 :     =over 4
1128 :    
1129 :     =item cols
1130 :    
1131 :     A list of column names. These must correspond to names defined in the result
1132 :     helper subclass (see L</Column Processing>).
1133 :    
1134 :     =back
1135 :    
1136 :     =cut
1137 :    
1138 :     sub SetColumns {
1139 :     # Get the parameters.
1140 :     my ($self, @cols) = @_;
1141 :     # Store the columns in the column list. Note that this erases any
1142 :     # previous column information.
1143 :     $self->{columns} = \@cols;
1144 :     }
1145 :    
1146 :     =head3 AddExtraColumn
1147 :    
1148 :     C<< $rhelp->AddExtraColumn($name => $loc, %data); >>
1149 :    
1150 :     Add an extra column to the column list at a specified location.
1151 :    
1152 :     =over 4
1153 :    
1154 :     =item name
1155 :    
1156 :     The name of the column to add.
1157 :    
1158 :     =item loc
1159 :    
1160 :     The location at which the column should be displayed. The column is added
1161 :     at the specified column location in the column list. It may be moved,
1162 :     however, if subsequent column additions are placed at or before its
1163 :     specified location. To put a column at the beginning, specify C<0>;
1164 :     to put it at the end specify C<undef>.
1165 :    
1166 :     =item data
1167 :    
1168 :     A hash specifying the title, style, and download flag for the extra
1169 :     column. The download flag (key C<download>) should specify the type
1170 :     of data in the column. The title (key C<title>) should be the name
1171 :     displayed for the column in the result display table. The style
1172 :     (key C<style>) should be the style class used for displaying the cells
1173 :     in the column.
1174 :    
1175 :     =back
1176 :    
1177 :     =cut
1178 :    
1179 :     sub AddExtraColumn {
1180 :     # Get the parameters.
1181 :     my ($self, $name, $loc, %data) = @_;
1182 :     # Add the name to the column hash.
1183 :     $data{name} = $name;
1184 :     # Store the result in the column list.
1185 :     $self->_StoreColumnSpec(\%data, $loc);
1186 :     }
1187 :    
1188 :     =head3 AddOptionalColumn
1189 :    
1190 :     C<< $rhelp->AddOptionalColumn($name => $loc); >>
1191 :    
1192 :     Store the specified column name in the column list at the
1193 :     specified location. The column name must be one that
1194 :     is known to the result helper subclass. This method
1195 :     allows ordinary columns (as opposed to extra columns)
1196 :     to be added after the initial L</SetColumns> call.
1197 :    
1198 :     =over 4
1199 :    
1200 :     =item name
1201 :    
1202 :     Name of the desired column.
1203 :    
1204 :     =item location
1205 :    
1206 :     Location at which the desired column should be stored.
1207 :    
1208 :     =back
1209 :    
1210 :     =cut
1211 :    
1212 :     sub AddOptionalColumn {
1213 :     # Get the parameters.
1214 :     my ($self, $name => $loc) = @_;
1215 :     # Currently, there is no extra work required here, but that
1216 :     # may change.
1217 :     $self->_StoreColumnSpec($name, $loc);
1218 :     }
1219 :    
1220 :     =head3 PutExtraColumns
1221 :    
1222 :     C<< $rhelp->PutExtraColumns(name1 => value1, name2 => value2, ...); >>
1223 :    
1224 :     Store the values of one or more extra columns. If a search produces extra columns (that is,
1225 :     columns whose data is determined by the search instead of queries against the database), then
1226 :     for each row of output, the search must call this method to specify the values of the various
1227 :     extra columns. Multiple calls to this method are allowed, in which case each call either
1228 :     overrides or adds to the values specified by the prior call.
1229 :    
1230 :     =over 4
1231 :    
1232 :     =item extraColumnMap
1233 :    
1234 :     A hash keyed on extra column name that maps the column names to the column's values for the current
1235 :     row of table data.
1236 :    
1237 :     =back
1238 :    
1239 :     =cut
1240 :    
1241 :     sub PutExtraColumns {
1242 :     # Get the parameters.
1243 :     my ($self, %extraColumnMap) = @_;
1244 :     # Copy the hash values into the extra column hash.
1245 :     my $counter = 0;
1246 :     for my $name (keys %extraColumnMap) {
1247 :     $self->{extras}->{$name} = $extraColumnMap{$name};
1248 :     Trace("Extra column $name has value $extraColumnMap{$name}.") if T(4);
1249 :     }
1250 :     }
1251 :    
1252 :     =head2 Internal Utilities
1253 :    
1254 :     =head3 StoreColumnSpec
1255 :    
1256 :     C<< $rhelp->_StoreColumnSpec($column, $location); >>
1257 :    
1258 :     Store the specified column information at the specified location in the column name list.
1259 :     The information is a string for an ordinary column and a hash for an extra column. The
1260 :     actual location at which the column is stored will be adjusted so that there are no
1261 :     gaps in the list. If the location is undefined, it defaults to the end. Thus, C<0>
1262 :     will always store at the beginning and C<undef> will always store at the end.
1263 :    
1264 :     =over 4
1265 :    
1266 :     =item column
1267 :    
1268 :     A column name or extra-column hash to be stored in the column list.
1269 :    
1270 :     =item location
1271 :    
1272 :     The index at which the column name should be stored, or C<undef> to store it
1273 :     at the end.
1274 :    
1275 :     =back
1276 :    
1277 :     =cut
1278 :    
1279 :     sub _StoreColumnSpec {
1280 :     # Get the parameters.
1281 :     my ($self, $column, $location) = @_;
1282 :     # Compute the current column count.
1283 :     my $columnCount = scalar @{$self->{columns}};
1284 :     # Adjust the location.
1285 :     if (! defined($location) || $location > $columnCount) {
1286 :     $location = $columnCount;
1287 :     }
1288 :     # Insert the column into the list.
1289 :     splice @{$self->{columns}}, $location, 0, $column;
1290 :     }
1291 :    
1292 :    
1293 :     =head2 Virtual Methods
1294 :    
1295 :     The following methods can be overridden by the subclass. In some cases, they
1296 :     must be overridden.
1297 :    
1298 :     =head3 DefaultResultColumns
1299 :    
1300 :     C<< my @colNames = $rhelp->DefaultResultColumns(); >>
1301 :    
1302 :     Return a list of the default columns to be used by searches with this
1303 :     type of result. Note that the actual default columns are computed by
1304 :     the search helper. This method is only needed if the search helper doesn't
1305 :     care.
1306 :    
1307 :     The columns returned should be in the form of column names, all of which
1308 :     must be defined by the result helper class.
1309 :    
1310 :     =cut
1311 :    
1312 :     sub DefaultResultColumns {
1313 :     # This method must be overridden.
1314 :     Confess("Pure virtual call to DefaultResultColumns.");
1315 :     }
1316 :    
1317 :     =head3 MoreDownloadFormats
1318 :    
1319 :     C<< $rhelp->MoreDownloadFormats(\%dlTypes); >>
1320 :    
1321 :     Add additional supported download formats to the type table. The table is a
1322 :     hash keyed on the download type code for which the values are the download
1323 :     descriptions. There is a special syntax that allows the placement of text
1324 :     fields inside the description. Use square brackets containing the name
1325 :     for the text field. The field will come in to the download request as
1326 :     a GET-type field.
1327 :    
1328 :     =over 4
1329 :    
1330 :     =item dlTypes
1331 :    
1332 :     Reference to a download-type hash. The purpose of this method is to add more
1333 :     download types relevant to the particular result type. Each type is described
1334 :     by a key (the download type itself) and a description. The description can
1335 :     contain a single text field that may be used to pass a parameter to the
1336 :     download. The text field is of the format C<[>I<fieldName>C<]>,
1337 :     where I<fieldName> is the name to give the text field's parameter in the
1338 :     generated download URL.
1339 :    
1340 :     =back
1341 :    
1342 :     =cut
1343 :    
1344 :     sub MoreDownloadFormats {
1345 :     Trace("Pure virtual call to MoreDownloadFormats.") if T(3);
1346 :     # Take no action.
1347 :     }
1348 :    
1349 :     =head3 MoreDownloadDataMethods
1350 :    
1351 :     C<< my @lines = $rhelp->MoreDownloadDataMethods($objectID, $dlType, \@cols, \@colHdrs); >>
1352 :    
1353 :     Create one or more lines of download data for a download of the specified type. Override
1354 :     this method if you need to process more download types than the default C<tbl> method.
1355 :    
1356 :     =over 4
1357 :    
1358 :     =item objectID
1359 :    
1360 :     ID of the object for this data row.
1361 :    
1362 :     =item dlType
1363 :    
1364 :     Download type (e.g. C<fasta>, etc.)
1365 :    
1366 :     =item cols
1367 :    
1368 :     Reference to a list of the data columns from the result cache, or alternatively
1369 :     the string C<header> (indicating that header lines are desired) or C<footer>
1370 :     (indicating that footer lines are desired).
1371 :    
1372 :     =item colHdrs
1373 :    
1374 :     The list of column headers from the result cache.
1375 :    
1376 :     =item RETURN
1377 :    
1378 :     Returns an array of data lines to output to the download file.
1379 :    
1380 :     =back
1381 :    
1382 :     =cut
1383 :    
1384 :     sub MoreDownloadDataMethods {
1385 :     # Get the parameters.
1386 :     my ($self, $objectID, $dlType, $cols, $colHdrs) = @_;
1387 :     # If we need to call this method, then the subclass should have overridden it.
1388 :     Confess("Invalid download type \"$dlType\" specified for result class $self->{type}.");
1389 :     }
1390 :    
1391 :     1;

MCS Webmaster
ViewVC Help
Powered by ViewVC 1.0.3