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

Diff of /Sprout/ResultHelper.pm

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.6, Wed Sep 3 20:54:47 2008 UTC revision 1.7, Mon Jan 19 21:56:19 2009 UTC
# Line 73  Line 73 
73              $rhelp->FeatureName();              $rhelp->FeatureName();
74          } elsif ($type eq 'runTimeValue') {          } elsif ($type eq 'runTimeValue') {
75              # This field does not require a runtime value.              # This field does not require a runtime value.
76            } elsif ($type eq 'valueFromKey') {
77                # Get the feature name from the feature ID.
78                $rhelp->FeatureNameFromID($key);
79          };          };
80          return $retVal;          return $retVal;
81      }      }
# Line 117  Line 120 
120  Return the value to be displayed. This method is only used when the information  Return the value to be displayed. This method is only used when the information
121  is not easily available at the time the result cache is built.  is not easily available at the time the result cache is built.
122    
123    =item valueFromKey
124    
125    Compute the value from a row ID. This method is used when the results are being
126    loaded asynchronously into a WebApplication table.
127    
128  =back  =back
129    
130  The idea behind this somewhat cumbersome design is that new columns can be added  The idea behind this somewhat cumbersome design is that new columns can be added
# Line 132  Line 140 
140  cache is displayed. Because a search can return thousands of results, but only 50 or  cache is displayed. Because a search can return thousands of results, but only 50 or
141  so are displayed at a time, this makes a big difference.  so are displayed at a time, this makes a big difference.
142    
143  =head2 Extra Columns  =head3 Extra Columns
144    
145  It is necessary for individual searches to be able to create output columns specific  It is necessary for individual searches to be able to create output columns specific
146  to the type of search. These are called extra columns.  to the type of search. These are called extra columns.
# Line 152  Line 160 
160  is thawed into the hash so that the various options are identical to what they were  is thawed into the hash so that the various options are identical to what they were
161  when the result cache was created.  when the result cache was created.
162    
163  Extra columns are the most volatile requirement in the whole search system. I will  =head3 Object-Based Columns
164  count myself happy if this implementation of them lasts more than a week.  
165    Some result helpers need to be much more fluid with column definitions than is possible
166    with the standard column-processing model. These helpers should override the L</VirtualCompute>
167    method. The L</Compute> method calls L</VirtualCompute> to give the subclass an opportunity
168    to process the column computation request before it tries working with a built-in column.
169    It is expected that eventually all columns will be converted to this object-based
170    approach, but there is no hurry.
171    
172  =cut  =cut
173    
# Line 888  Line 902 
902  The type of column data requested: C<title> for the column title, C<style> for the  The type of column data requested: C<title> for the column title, C<style> for the
903  column's display style, C<value> for the value to be put in the result cache,  column's display style, C<value> for the value to be put in the result cache,
904  C<download> for the indicator of how the column should be included in  C<download> for the indicator of how the column should be included in
905  downloads, and C<runTimeValue> for the value to be used when the result is  downloads, C<runTimeValue> for the value to be used when the result is
906  displayed. Note that if a run-time value is required, then the normal value  displayed, and C<valueFromKey> for the value when all we have is the object ID. Note
907  must be formatted in a special way (see L<Column Processing>).  that if a run-time value is required, then the normal value must be formatted in
908    a special way (see L<Column Processing>).
909    
910  A little fancy dancing is required for extra columns. For extra columns, only  A little fancy dancing is required for extra columns. For extra columns, only
911  the title, style, and download status are ever requested.  the title, style, and download status are ever requested.
# Line 899  Line 914 
914    
915  Name of the column of interest. The name may contain a colon, in which case  Name of the column of interest. The name may contain a colon, in which case
916  the column name is the part before the colon and the value after it is  the column name is the part before the colon and the value after it is
917  passed to the column method as the run-time key.  passed to the column method as the run-time key. For an extra column, this is
918    the extra-column hash.
919    
920  =item runTimeKey (optional)  =item runTimeKey (optional)
921    
# Line 927  Line 943 
943              # member keyed by column name.              # member keyed by column name.
944              my $realName = $colName->{name};              my $realName = $colName->{name};
945              $retVal = $self->{extras}->{$realName};              $retVal = $self->{extras}->{$realName};
946              Trace("Extra column $realName retrieved value is $retVal.") if T(4);              Trace("Extra column $realName retrieved value is $retVal.") if T(ResultCache => 3);
947          } else {          } else {
948              # The other data items are stored in the column name itself.              # The other data items are stored in the column name itself.
949              $retVal = $colName->{$type};              $retVal = $colName->{$type};
950          }          }
951      } else {      } else {
952          # Here we have a real built-in column. The search helper chooses which of          # Here we have a built-in column or an object-based column. The search
953          # these to use (usually by adding to a default list), and we use static          # helper chooses which of these to use (usually by adding to a default
954          # methods in our subclass to process them. An eval call is used to          # list), and we use static methods in our subclass to process them. An
955          # accomplish the result. First, we do some goofiness so we can deal          # eval call is used to accomplish the result. First, we do some
956          # with the possible absence of a run-time key.          # goofiness so we can deal with the possible absence of a run-time key.
957          my $realRunTimeKey = (defined $runTimeKey ? ", '$runTimeKey'" : "");          my $realRunTimeKey = (defined $runTimeKey ? $runTimeKey : undef);
958          # Check for a complex column name. Note that during run-time expansion, the          # Check for a complex column name. The column name fragment is made
959          # column names will have been simplified (that is, the colon will have been          # part of the run-time key.
         # removed and the parameter attached to the incoming run-time key.  
960          if ($colName =~ /(\S+):(.+)/) {          if ($colName =~ /(\S+):(.+)/) {
961              $colName = $1;              $colName = $1;
962              $realRunTimeKey = ", '$2'";              $realRunTimeKey = $2;
963                if (defined $runTimeKey) {
964                    $realRunTimeKey .= "/$runTimeKey";
965                }
966          }          }
967            # Check to see if this is an object-based column.
968            $retVal = $self->VirtualCompute($colName, $type, $realRunTimeKey);
969            # If we didn't get a result, then the column is truly built-in.
970            if (defined $retVal) {
971                Trace("Virtual compute for \"colName\" type $type is \"$retVal\".") if T(ResultCache => 3);
972            } else {
973                # Format a parameter list containing a self reference and optionally
974                # the run-time key.
975                my @parms = '$self';
976                push @parms, "'$realRunTimeKey'" if defined $realRunTimeKey;
977                my $parms = join(", ", @parms);
978          # Get the result helper type.          # Get the result helper type.
979          my $rhType = $self->{type};          my $rhType = $self->{type};
980          # Create the string for returning the desired results.          # Create the string for returning the desired results.
981          my $expression = "${rhType}::$colName($type => \$self$realRunTimeKey)";              my $expression = "${rhType}::$colName($type => $parms)";
982          # Evaluate to get the result. Note we automatically translate undefined results to              Trace("Evaluating: $expression") if T(ResultCache => 3);
983          # an empty string.              # Evaluate to get the result. Note we automatically translate
984          Trace("Evaluating: $expression") if T(4);              # undefined results to an empty string.
985          $retVal = eval($expression) || "";          $retVal = eval($expression) || "";
986          # Check for an error.          # Check for an error.
987          if ($@) {          if ($@) {
988              Trace("Evaluation failed in Compute of $expression") if T(1);              Trace("Evaluation failed in Compute of $expression") if T(1);
989              Confess("$self->{type} column request failed: $@");              Confess("$self->{type} column request failed: $@");
990          }          }
991                Trace("Found \"$retVal\" for $colName type $type.") if T(ResultCache => 3);
992            }
993      }      }
994      # Return the computed result.      # Return the computed result.
995      return $retVal;      return $retVal;
996  }  }
997    
998    =head3 ColumnMetaData
999    
1000        my $metadata = $rhelp->ColumnMetaData($colHdr, $idx, $visible);
1001    
1002    Compute the [[ColumnDisplayList]] metadata for a column. The column is
1003    identified either by its name or by the hash reference that specifies the
1004    characteristics of an extra column.
1005    
1006    =over 4
1007    
1008    =item colHdr
1009    
1010    Name of the column in question, or the extra column hash for an extra column.
1011    
1012    =item idx
1013    
1014    Index position at which the column is to be displayed.
1015    
1016    =item visible
1017    
1018    If TRUE, the column will be marked visible; otherwise, it will initially be hidden.
1019    
1020    =item RETURN
1021    
1022    Returns a metadata structure suitable for use by the [[DisplayListSelectPm]]
1023    component in manipulating this column.
1024    
1025    =back
1026    
1027    =cut
1028    
1029    sub ColumnMetaData {
1030        # Get the parameters.
1031        my ($self, $colHdr, $idx, $visible) = @_;
1032        # Declare the return variable.
1033        my $retVal = {};
1034        # Get the column label.
1035        my $label = $self->Compute(title => $colHdr);
1036        # Create the table column object.
1037        my $columnThing = { name => $label };
1038        # Get our download type.
1039        my $dlType = $self->Compute(download => $colHdr);
1040        # We use the download type to decide how fancy the column should be. For a
1041        # list-type column we want no fanciness. For numbers we allow inequalities,
1042        # for strings we allow LIKE stuff.
1043        if ($dlType eq 'num') {
1044            $columnThing->{filter} = 1;
1045            $columnThing->{operator} = "equal";
1046            $columnThing->{operators} = [qw(equal unequal less more)];
1047            $columnThing->{sortable} = 1;
1048        } elsif ($dlType eq 'text') {
1049            $columnThing->{filter} = 1;
1050            $columnThing->{operator} = "equal";
1051            $columnThing->{operators} = [qw(equal unequal like unlike)];
1052            $columnThing->{sortable} = 1;
1053        }
1054        # Store the table column object in the metadata we're returning.
1055        $retVal->{header} = $columnThing;
1056        # Now we set the visibility, permanence, and order.
1057        $retVal->{visible} = ($visible ? 1 : 0);
1058        $retVal->{order} = $idx;
1059        $retVal->{permanent} = $self->Permanent($colHdr);
1060        # Return the result.
1061        return $retVal;
1062    }
1063    
1064    =head3 ColumnName
1065    
1066        my $name = $rhelp->ColumnName($colName);
1067    
1068    Return the name of a column. Normally, this involves just returning the
1069    parameter unmodified. If it's an extra column, however, the input is a
1070    hash reference and we have to pull out the name.
1071    
1072    =over 4
1073    
1074    =item colName
1075    
1076    Column name, or the extra column hash.
1077    
1078    =item RETURN
1079    
1080    Returns a string that may be used as a column identifier.
1081    
1082    =back
1083    
1084    =cut
1085    
1086    sub ColumnName {
1087        # Get the parameters.
1088        my ($self, $colName) = @_;
1089        # Declare the return variable.
1090        my $retVal;
1091        # Check the column type.
1092        if (ref $colName eq 'HASH') {
1093            $retVal = $colName->{name};
1094        } else {
1095            $retVal = $colName;
1096        }
1097        # Return the result.
1098        return $retVal;
1099    }
1100    
1101    
1102  =head3 ColumnDownload  =head3 ColumnDownload
1103    
1104      my $flag = $rhelp->ColumnDownload($colName);      my $flag = $rhelp->ColumnDownload($colName);
# Line 1122  Line 1257 
1257      for my $col (@cols) {      for my $col (@cols) {
1258          # Declare a holding variable.          # Declare a holding variable.
1259          my $retVal;          my $retVal;
1260            Trace("Value \"$retVal\" found in column.") if T(ResultCache => 3);
1261          # Parse the column data.          # Parse the column data.
1262          if ($col =~ /^%%(\w+)=(.+)/) {          if ($col =~ /^%%(\w+)=(.+)/) {
1263              # It parsed as a run-time value, so call the Compute method.              # It parsed as a run-time value, so call the Compute method.
# Line 1281  Line 1417 
1417  The information is a string for an ordinary column and a hash for an extra column. The  The information is a string for an ordinary column and a hash for an extra column. The
1418  actual location at which the column is stored will be adjusted so that there are no  actual location at which the column is stored will be adjusted so that there are no
1419  gaps in the list. If the location is undefined, it defaults to the end. Thus, C<0>  gaps in the list. If the location is undefined, it defaults to the end. Thus, C<0>
1420  will always store at the beginning and C<undef> will always store at the end.  will always store at the beginning and C<undef> will always store at the end. If the
1421    column is already in the list this method will have no effect.
1422    
1423  =over 4  =over 4
1424    
# Line 1301  Line 1438 
1438  sub _StoreColumnSpec {  sub _StoreColumnSpec {
1439      # Get the parameters.      # Get the parameters.
1440      my ($self, $column, $location) = @_;      my ($self, $column, $location) = @_;
1441        # Get the current column list.
1442        my $columnList = $self->{columns};
1443      # Compute the current column count.      # Compute the current column count.
1444      my $columnCount = scalar @{$self->{columns}};      my $columnCount = scalar @$columnList;
1445        # See if the column is already present.
1446        my $alreadyPresent;
1447        if (ref $column eq 'HASH') {
1448            Trace("Checking extra column $column->{name}.") if T(3);
1449            my @extras = grep { ref $_ eq 'HASH' } @$columnList;
1450            $alreadyPresent = grep { $_->{name} eq $column->{name} } @extras;
1451        } else {
1452            Trace("Checking optional column $column.") if T(3);
1453            $alreadyPresent = grep { $_ eq $column } @$columnList;
1454        }
1455        # Only proceed if the column is NOT already present.
1456        if ($alreadyPresent) {
1457            Trace("Column is already present.") if T(3);
1458        } else {
1459      # Adjust the location.      # Adjust the location.
1460      if (! defined($location) || $location > $columnCount) {      if (! defined($location) || $location > $columnCount) {
1461          $location = $columnCount;          $location = $columnCount;
1462      }      }
1463      # Insert the column into the list.      # Insert the column into the list.
1464      splice @{$self->{columns}}, $location, 0, $column;      splice @{$self->{columns}}, $location, 0, $column;
1465            Trace("Column inserted at position $location.") if T(3);
1466        }
1467  }  }
1468    
1469    
# Line 1317  Line 1472 
1472  The following methods can be overridden by the subclass. In some cases, they  The following methods can be overridden by the subclass. In some cases, they
1473  must be overridden.  must be overridden.
1474    
1475    =head3 VirtualCompute
1476    
1477        my $dataValue = $rhelp->VirtualCompute($colName, $type, $runTimeKey);
1478    
1479    Retrieve the column data of the specified type for the specified column
1480    using the optional run-time key.
1481    
1482    This method is called after extra columns have been handled but before
1483    built-in columns are processed. The subclass can use this method to
1484    handle columns that are object-based or otherwise too complex or varied
1485    for the standard built-in column protocol. If the column name isn't
1486    recognized, this method should return an undefined value. This will
1487    happen automatically if the base class method is not overridden.
1488    
1489    =over 4
1490    
1491    =item colName
1492    
1493    Name of the relevant column.
1494    
1495    =item type
1496    
1497    The type of column data requested: C<title> for the column title, C<style> for the
1498    column's display style, C<value> for the value to be put in the result cache,
1499    C<download> for the indicator of how the column should be included in
1500    downloads, and C<runTimeValue> for the value to be used when the result is
1501    displayed. Note that if a run-time value is required, then the normal value
1502    must be formatted in a special way (see L<Column Processing>).
1503    
1504    =item runTimeKey (optional)
1505    
1506    If a run-time value is desired, this should be the key taken from the value stored
1507    in the result cache.
1508    
1509    =item RETURN
1510    
1511    Returns the requested value for the named column, or C<undef> if the column
1512    is built in to the subclass using the old protocol.
1513    
1514    =back
1515    
1516    =cut
1517    
1518    sub VirtualCompute {
1519        # Get the parameters.
1520        my ($self, $colName, $type, $runTimeKey) = @_;
1521        # Declare the return variable.
1522        my $retVal;
1523        # Return the result.
1524        return $retVal;
1525    }
1526    
1527  =head3 DefaultResultColumns  =head3 DefaultResultColumns
1528    
1529      my @colNames = $rhelp->DefaultResultColumns();      my @colNames = $rhelp->DefaultResultColumns();
# Line 1410  Line 1617 
1617      Confess("Invalid download type \"$dlType\" specified for result class $self->{type}.");      Confess("Invalid download type \"$dlType\" specified for result class $self->{type}.");
1618  }  }
1619    
1620    =head3 GetColumnNameList
1621    
1622        my @names = $rhelp->GetColumnNameList();
1623    
1624    Return a complete list of the names of columns available for this result
1625    helper. The base class method simply regurgitates the default columns.
1626    
1627    =cut
1628    
1629    sub GetColumnNameList {
1630        # Get the parameters.
1631        my ($self) = @_;
1632        # Return the result.
1633        return $self->DefaultResultColumns();
1634    }
1635    
1636    =head3 Permanent
1637    
1638        my $flag = $rhelp->Permanent($colName);
1639    
1640    Return TRUE if the specified column should be permanent when used in a
1641    Seed Viewer table, else FALSE.
1642    
1643    =over 4
1644    
1645    =item colName
1646    
1647    Name of the column to check.
1648    
1649    =item RETURN
1650    
1651    Returns TRUE if the column should be permanent, else FALSE.
1652    
1653    =back
1654    
1655    =cut
1656    
1657    sub Permanent {
1658        # Get the parameters.
1659        my ($self, $colName) = @_;
1660        # Declare the return variable.
1661        my $retVal;
1662        Confess("Pure virtual method Permanent called.");
1663        # Return the result.
1664        return $retVal;
1665    }
1666    
1667    =head3 Initialize
1668    
1669        $rhelp->Initialize();
1670    
1671    Perform any initialization required after construction of the helper.
1672    
1673    =cut
1674    
1675    sub Initialize {
1676        # The default is to do nothing.
1677    }
1678    
1679    
1680    
1681    
1682  1;  1;

Legend:
Removed from v.1.6  
changed lines
  Added in v.1.7

MCS Webmaster
ViewVC Help
Powered by ViewVC 1.0.3