--- loncom/interface/Attic/lonspreadsheet.pm 2001/11/06 10:43:57 1.74
+++ loncom/interface/Attic/lonspreadsheet.pm 2002/09/27 18:43:10 1.100.4.1
@@ -1,3 +1,28 @@
+#
+# $Id: lonspreadsheet.pm,v 1.100.4.1 2002/09/27 18:43:10 matthew Exp $
+#
+# Copyright Michigan State University Board of Trustees
+#
+# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
+#
+# LON-CAPA is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# LON-CAPA is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with LON-CAPA; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# /home/httpd/html/adm/gpl.txt
+#
+# http://www.lon-capa.org/
+#
# The LearningOnline Network with CAPA
# Spreadsheet/Grades Display Handler
#
@@ -7,7 +32,34 @@
# 03/05,03/08,03/10,03/12,03/13,03/15,03/17,
# 03/19,03/20,03/21,03/27,04/05,04/09,
# 07/09,07/14,07/21,09/01,09/10,9/11,9/12,9/13,9/14,9/17,
-# 10/16,10/17,10/20,11/05 Gerd Kortemeyer
+# 10/16,10/17,10/20,11/05,11/28,12/27 Gerd Kortemeyer
+# 01/14/02 Matthew
+# 02/04/02 Matthew
+
+# POD required stuff:
+
+=head1 NAME
+
+lonspreadsheet
+
+=head1 SYNOPSIS
+
+Spreadsheet interface to internal LON-CAPA data
+
+=head1 DESCRIPTION
+
+Lonspreadsheet provides course coordinators the ability to manage their
+students grades online. The students are able to view their own grades, but
+not the grades of their peers. The spreadsheet is highly customizable,
+offering the ability to use Perl code to manipulate data, as well as many
+built-in functions.
+
+
+=head2 Functions available to user of lonspreadsheet
+
+=over 4
+
+=cut
package Apache::lonspreadsheet;
@@ -19,7 +71,7 @@ use Apache::lonnet;
use Apache::Constants qw(:common :http);
use GDBM_File;
use HTML::TokeParser;
-
+use Apache::lonhtmlcommon;
#
# Caches for previously calculated spreadsheets
#
@@ -54,6 +106,14 @@ my %courseopt;
my %useropt;
my %parmhash;
+#
+# Some hashes for stats on timing and performance
+#
+
+my %starttimes;
+my %usedtimes;
+my %numbertimes;
+
# Stuff that only the screen handler can know
my $includedir;
@@ -70,6 +130,7 @@ sub initsheet {
$safeeval->permit("sort");
$safeeval->deny(":base_io");
$safehole->wrap(\&Apache::lonnet::EXT,$safeeval,'&EXT');
+ $safeeval->share('$@');
my $code=<<'ENDDEFS';
# ---------------------------------------------------- Inside of the safe space
@@ -113,6 +174,10 @@ $cfn='';
$usymb='';
+# error messages
+
+$errormsg='';
+
sub mask {
my ($lower,$upper)=@_;
@@ -142,16 +207,16 @@ sub mask {
} else {
if (length($ld)!=length($ud)) {
$num.='(';
- map {
+ foreach ($ld=~m/\d/g) {
$num.='['.$_.'-9]';
- } ($ld=~m/\d/g);
+ }
if (length($ud)-length($ld)>1) {
$num.='|\d{'.(length($ld)+1).','.(length($ud)-1).'}';
}
$num.='|';
- map {
+ foreach ($ud=~m/\d/g) {
$num.='[0-'.$_.']';
- } ($ud=~m/\d/g);
+ }
$num.=')';
} else {
my @lda=($ld=~m/\d/g);
@@ -189,12 +254,285 @@ sub mask {
return '^'.$alpha.$num."\$";
}
+#-------------------------------------------------------
+
+=item UWCALC(hashname,modules,units,date)
+
+returns the proportion of the module
+weights not previously completed by the student.
+
+=over 4
+
+=item hashname
+
+name of the hash the module dates have been inserted into
+
+=item modules
+
+reference to a cell which contains a comma deliminated list of modules
+covered by the assignment.
+
+=item units
+
+reference to a cell which contains a comma deliminated list of module
+weights with respect to the assignment
+
+=item date
+
+reference to a cell which contains the date the assignment was completed.
+
+=back
+
+=cut
+
+#-------------------------------------------------------
+sub UWCALC {
+ my ($hashname,$modules,$units,$date) = @_;
+ my @Modules = split(/,/,$modules);
+ my @Units = split(/,/,$units);
+ my $total_weight;
+ foreach (@Units) {
+ $total_weight += $_;
+ }
+ my $usum=0;
+ for (my $i=0; $i<=$#Modules; $i++) {
+ if (&HASH($hashname,$Modules[$i]) eq $date) {
+ $usum += $Units[$i];
+ }
+ }
+ return $usum/$total_weight;
+}
+
+#-------------------------------------------------------
+
+=item CDLSUM(list)
+
+returns the sum of the elements in a cell which contains
+a Comma Deliminate List of numerical values.
+'list' is a reference to a cell which contains a comma deliminated list.
+
+=cut
+
+#-------------------------------------------------------
+sub CDLSUM {
+ my ($list)=@_;
+ my $sum;
+ foreach (split/,/,$list) {
+ $sum += $_;
+ }
+ return $sum;
+}
+
+#-------------------------------------------------------
+
+=item CDLITEM(list,index)
+
+returns the item at 'index' in a Comma Deliminated List.
+
+=over 4
+
+=item list
+
+reference to a cell which contains a comma deliminated list.
+
+=item index
+
+the Perl index of the item requested (first element in list has
+an index of 0)
+
+=back
+
+=cut
+
+#-------------------------------------------------------
+sub CDLITEM {
+ my ($list,$index)=@_;
+ my @Temp = split/,/,$list;
+ return $Temp[$index];
+}
+
+#-------------------------------------------------------
+
+=item CDLHASH(name,key,value)
+
+loads a comma deliminated list of keys into
+the hash 'name', all with a value of 'value'.
+
+=over 4
+
+=item name
+
+name of the hash.
+
+=item key
+
+(a pointer to) a comma deliminated list of keys.
+
+=item value
+
+a single value to be entered for each key.
+
+=back
+
+=cut
+
+#-------------------------------------------------------
+sub CDLHASH {
+ my ($name,$key,$value)=@_;
+ my @Keys;
+ my @Values;
+ # Check to see if we have multiple $key values
+ if ($key =~ /[A-z](\-[A-z])?\d+(\-\d+)?/) {
+ my $keymask = &mask($key);
+ # Assume the keys are addresses
+ my @Temp = grep /$keymask/,keys(%v);
+ @Keys = $v{@Temp};
+ } else {
+ $Keys[0]= $key;
+ }
+ my @Temp;
+ foreach $key (@Keys) {
+ @Temp = (@Temp, split/,/,$key);
+ }
+ @Keys = @Temp;
+ if ($value =~ /[A-z](\-[A-z])?\d+(\-\d+)?/) {
+ my $valmask = &mask($value);
+ my @Temp = grep /$valmask/,keys(%v);
+ @Values =$v{@Temp};
+ } else {
+ $Values[0]= $value;
+ }
+ $value = $Values[0];
+ # Add values to hash
+ for (my $i = 0; $i<=$#Keys; $i++) {
+ my $key = $Keys[$i];
+ if (! exists ($hashes{$name}->{$key})) {
+ $hashes{$name}->{$key}->[0]=$value;
+ } else {
+ my @Temp = sort(@{$hashes{$name}->{$key}},$value);
+ $hashes{$name}->{$key} = \@Temp;
+ }
+ }
+ return "hash '$name' updated";
+}
+
+#-------------------------------------------------------
+
+=item GETHASH(name,key,index)
+
+returns the element in hash 'name'
+reference by the key 'key', at index 'index' in the values list.
+
+=cut
+
+#-------------------------------------------------------
+sub GETHASH {
+ my ($name,$key,$index)=@_;
+ if (! defined($index)) {
+ $index = 0;
+ }
+ if ($key =~ /^[A-z]\d+$/) {
+ $key = $v{$key};
+ }
+ return $hashes{$name}->{$key}->[$index];
+}
+
+#-------------------------------------------------------
+
+=item CLEARHASH(name)
+
+clears all the values from the hash 'name'
+
+=item CLEARHASH(name,key)
+
+clears all the values from the hash 'name' associated with the given key.
+
+=cut
+
+#-------------------------------------------------------
+sub CLEARHASH {
+ my ($name,$key)=@_;
+ if (defined($key)) {
+ if (exists($hashes{$name}->{$key})) {
+ $hashes{$name}->{$key}=undef;
+ return "hash '$name' key '$key' cleared";
+ }
+ } else {
+ if (exists($hashes{$name})) {
+ $hashes{$name}=undef;
+ return "hash '$name' cleared";
+ }
+ }
+ return "Error in clearing hash";
+}
+
+#-------------------------------------------------------
+
+=item HASH(name,key,value)
+
+loads values into an internal hash. If a key
+already has a value associated with it, the values are sorted numerically.
+
+=item HASH(name,key)
+
+returns the 0th value in the hash 'name' associated with 'key'.
+
+=cut
+
+#-------------------------------------------------------
+sub HASH {
+ my ($name,$key,$value)=@_;
+ my @Keys;
+ undef @Keys;
+ my @Values;
+ # Check to see if we have multiple $key values
+ if ($key =~ /[A-z](\-[A-z])?\d+(\-\d+)?/) {
+ my $keymask = &mask($key);
+ # Assume the keys are addresses
+ my @Temp = grep /$keymask/,keys(%v);
+ @Keys = $v{@Temp};
+ } else {
+ $Keys[0]= $key;
+ }
+ # If $value is empty, return the first value associated
+ # with the first key.
+ if (! $value) {
+ return $hashes{$name}->{$Keys[0]}->[0];
+ }
+ # Check to see if we have multiple $value(s)
+ if ($value =~ /[A-z](\-[A-z])?\d+(\-\d+)?/) {
+ my $valmask = &mask($value);
+ my @Temp = grep /$valmask/,keys(%v);
+ @Values =$v{@Temp};
+ } else {
+ $Values[0]= $value;
+ }
+ # Add values to hash
+ for (my $i = 0; $i<=$#Keys; $i++) {
+ my $key = $Keys[$i];
+ my $value = ($i<=$#Values ? $Values[$i] : $Values[0]);
+ if (! exists ($hashes{$name}->{$key})) {
+ $hashes{$name}->{$key}->[0]=$value;
+ } else {
+ my @Temp = sort(@{$hashes{$name}->{$key}},$value);
+ $hashes{$name}->{$key} = \@Temp;
+ }
+ }
+ return $Values[-1];
+}
+
+#-------------------------------------------------------
+
+=item NUM(range)
+
+returns the number of items in the range.
+
+=cut
+
+#-------------------------------------------------------
sub NUM {
my $mask=mask(@_);
- my $num=0;
- map {
- $num++;
- } grep /$mask/,keys %v;
+ my $num= $#{@{grep(/$mask/,keys(%v))}}+1;
return $num;
}
@@ -202,31 +540,49 @@ sub BIN {
my ($low,$high,$lower,$upper)=@_;
my $mask=mask($lower,$upper);
my $num=0;
- map {
+ foreach (grep /$mask/,keys(%v)) {
if (($v{$_}>=$low) && ($v{$_}<=$high)) {
$num++;
}
- } grep /$mask/,keys %v;
+ }
return $num;
}
+#-------------------------------------------------------
+
+=item SUM(range)
+
+returns the sum of items in the range.
+
+=cut
+
+#-------------------------------------------------------
sub SUM {
my $mask=mask(@_);
my $sum=0;
- map {
+ foreach (grep /$mask/,keys(%v)) {
$sum+=$v{$_};
- } grep /$mask/,keys %v;
+ }
return $sum;
}
+#-------------------------------------------------------
+
+=item MEAN(range)
+
+compute the average of the items in the range.
+
+=cut
+
+#-------------------------------------------------------
sub MEAN {
my $mask=mask(@_);
my $sum=0; my $num=0;
- map {
+ foreach (grep /$mask/,keys(%v)) {
$sum+=$v{$_};
$num++;
- } grep /$mask/,keys %v;
+ }
if ($num) {
return $sum/$num;
} else {
@@ -234,58 +590,104 @@ sub MEAN {
}
}
+#-------------------------------------------------------
+
+=item STDDEV(range)
+
+compute the standard deviation of the items in the range.
+
+=cut
+
+#-------------------------------------------------------
sub STDDEV {
my $mask=mask(@_);
my $sum=0; my $num=0;
- map {
+ foreach (grep /$mask/,keys(%v)) {
$sum+=$v{$_};
$num++;
- } grep /$mask/,keys %v;
+ }
unless ($num>1) { return undef; }
my $mean=$sum/$num;
$sum=0;
- map {
+ foreach (grep /$mask/,keys(%v)) {
$sum+=($v{$_}-$mean)**2;
- } grep /$mask/,keys %v;
+ }
return sqrt($sum/($num-1));
}
+#-------------------------------------------------------
+
+=item PROD(range)
+
+compute the product of the items in the range.
+
+=cut
+
+#-------------------------------------------------------
sub PROD {
my $mask=mask(@_);
my $prod=1;
- map {
+ foreach (grep /$mask/,keys(%v)) {
$prod*=$v{$_};
- } grep /$mask/,keys %v;
+ }
return $prod;
}
+#-------------------------------------------------------
+
+=item MAX(range)
+
+compute the maximum of the items in the range.
+
+=cut
+
+#-------------------------------------------------------
sub MAX {
my $mask=mask(@_);
my $max='-';
- map {
+ foreach (grep /$mask/,keys(%v)) {
unless ($max) { $max=$v{$_}; }
if (($v{$_}>$max) || ($max eq '-')) { $max=$v{$_}; }
- } grep /$mask/,keys %v;
+ }
return $max;
}
+#-------------------------------------------------------
+
+=item MIN(range)
+
+compute the minimum of the items in the range.
+
+=cut
+
+#-------------------------------------------------------
sub MIN {
my $mask=mask(@_);
my $min='-';
- map {
+ foreach (grep /$mask/,keys(%v)) {
unless ($max) { $max=$v{$_}; }
if (($v{$_}<$min) || ($min eq '-')) { $min=$v{$_}; }
- } grep /$mask/,keys %v;
+ }
return $min;
}
+#-------------------------------------------------------
+
+=item SUMMAX(num,lower,upper)
+
+compute the sum of the largest 'num' items in the range from
+'lower' to 'upper'
+
+=cut
+
+#-------------------------------------------------------
sub SUMMAX {
my ($num,$lower,$upper)=@_;
my $mask=mask($lower,$upper);
my @inside=();
- map {
- $inside[$#inside+1]=$v{$_};
- } grep /$mask/,keys %v;
+ foreach (grep /$mask/,keys(%v)) {
+ push (@inside,$v{$_});
+ }
@inside=sort(@inside);
my $sum=0; my $i;
for ($i=$#inside;(($i>$#inside-$num) && ($i>=0));$i--) {
@@ -294,13 +696,23 @@ sub SUMMAX {
return $sum;
}
+#-------------------------------------------------------
+
+=item SUMMIN(num,lower,upper)
+
+compute the sum of the smallest 'num' items in the range from
+'lower' to 'upper'
+
+=cut
+
+#-------------------------------------------------------
sub SUMMIN {
my ($num,$lower,$upper)=@_;
my $mask=mask($lower,$upper);
my @inside=();
- map {
+ foreach (grep /$mask/,keys(%v)) {
$inside[$#inside+1]=$v{$_};
- } grep /$mask/,keys %v;
+ }
@inside=sort(@inside);
my $sum=0; my $i;
for ($i=0;(($i<$num) && ($i<=$#inside));$i++) {
@@ -316,32 +728,58 @@ sub expandnamed {
my @vars=split(/\W+/,$formula);
my %values=();
undef %values;
- map {
+ foreach ( @vars ) {
my $varname=$_;
if ($varname=~/\D/) {
$formula=~s/$varname/'$c{\''.$varname.'\'}'/ge;
$varname=~s/$var/\(\\w\+\)/g;
- map {
+ foreach (keys(%c)) {
if ($_=~/$varname/) {
$values{$1}=1;
}
- } keys %c;
+ }
}
- } @vars;
+ }
if ($func eq 'EXPANDSUM') {
my $result='';
- map {
+ foreach (keys(%values)) {
my $thissum=$formula;
$thissum=~s/$var/$_/g;
$result.=$thissum.'+';
- } keys %values;
+ }
$result=~s/\+$//;
return $result;
} else {
return 0;
}
} else {
- return '$c{\''.$expression.'\'}';
+ # it is not a function, so it is a parameter name
+ # We should do the following:
+ # 1. Take the list of parameter names
+ # 2. look through the list for ones that match the parameter we want
+ # 3. If there are no collisions, return the one that matches
+ # 4. If there is a collision, return 'bad parameter name error'
+ my $returnvalue = '';
+ my @matches = ();
+ $#matches = -1;
+ study $expression;
+ foreach $parameter (keys(%c)) {
+ push @matches,$parameter if ($parameter =~ /$expression/);
+ }
+ if ($#matches == 0) {
+ $returnvalue = '$c{\''.$matches[0].'\'}';
+ } elsif ($#matches > 0) {
+ # more than one match. Look for a concise one
+ $returnvalue = "'non-unique parameter name : $expression'";
+ foreach (@matches) {
+ if (/^$expression$/) {
+ $returnvalue = '$c{\''.$_.'\'}';
+ }
+ }
+ } else {
+ $returnvalue = "'bad parameter name : $expression'";
+ }
+ return $returnvalue;
}
}
@@ -353,27 +791,37 @@ sub sett {
} else {
$pattern='[A-Z]';
}
- map {
+
+# Deal with the template row
+ foreach (keys(%f)) {
if ($_=~/template\_(\w)/) {
my $col=$1;
unless ($col=~/^$pattern/) {
- map {
+ foreach (keys(%f)) {
if ($_=~/A(\d+)/) {
my $trow=$1;
if ($trow) {
+ # Get the name of this cell
my $lb=$col.$trow;
+ # Grab the template declaration
$t{$lb}=$f{'template_'.$col};
+ # Replace '#' with the row number
$t{$lb}=~s/\#/$trow/g;
+ # Replace '....' with ','
$t{$lb}=~s/\.\.+/\,/g;
+ # Replace 'A0' with the value from 'A0'
$t{$lb}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$v\{\'$2\'\}/g;
+ # Replace parameters
$t{$lb}=~s/(^|[^\"\'])\[([^\]]+)\]/$1.&expandnamed($2)/ge;
}
}
- } keys %f;
+ }
}
}
- } keys %f;
- map {
+ }
+
+# Deal with the normal cells
+ foreach (keys(%f)) {
if (($f{$_}) && ($_!~/template\_/)) {
my $matches=($_=~/^$pattern(\d+)/);
if (($matches) && ($1)) {
@@ -387,7 +835,24 @@ sub sett {
$t{$_}=~s/(^|[^\"\'])\[([^\]]+)\]/$1.&expandnamed($2)/ge;
}
}
- } keys %f;
+ }
+# For inserted lines, [B-Z] is also valid
+
+ unless ($sheettype eq 'assesscalc') {
+ foreach (keys(%f)) {
+ if ($_=~/[B-Z](\d+)/) {
+ if ($f{'A'.$1}=~/^[\~\-]/) {
+ $t{$_}=$f{$_};
+ $t{$_}=~s/\.\.+/\,/g;
+ $t{$_}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$v\{\'$2\'\}/g;
+ $t{$_}=~s/(^|[^\"\'])\[([^\]]+)\]/$1.&expandnamed($2)/ge;
+ }
+ }
+ }
+ }
+
+ # For some reason 'A0' gets special treatment... This seems superfluous
+ # but I imagine it is here for a reason.
$t{'A0'}=$f{'A0'};
$t{'A0'}=~s/\.\.+/\,/g;
$t{'A0'}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$v\{\'$2\'\}/g;
@@ -395,25 +860,26 @@ sub sett {
}
sub calc {
- %v=();
+ undef %v;
&sett();
my $notfinished=1;
+ my $lastcalc='';
my $depth=0;
while ($notfinished) {
$notfinished=0;
- map {
+ foreach (keys(%t)) {
my $old=$v{$_};
- $v{$_}=eval($t{$_});
+ $v{$_}=eval $t{$_};
if ($@) {
- %v=();
- return $@;
+ undef %v;
+ return $_.': '.$@;
}
- if ($v{$_} ne $old) { $notfinished=1; }
- } keys %t;
+ if ($v{$_} ne $old) { $notfinished=1; $lastcalc=$_; }
+ }
$depth++;
if ($depth>100) {
- %v=();
- return 'Maximum calculation depth exceeded';
+ undef %v;
+ return $lastcalc.': Maximum calculation depth exceeded';
}
}
return '';
@@ -422,14 +888,14 @@ sub calc {
sub templaterow {
my @cols=();
$cols[0]='Template';
- map {
+ foreach ('A','B','C','D','E','F','G','H','I','J','K','L','M',
+ 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
+ 'a','b','c','d','e','f','g','h','i','j','k','l','m',
+ 'n','o','p','q','r','s','t','u','v','w','x','y','z') {
my $fm=$f{'template_'.$_};
$fm=~s/[\'\"]/\&\#34;/g;
$cols[$#cols+1]="'template_$_','$fm'".'___eq___'.$fm;
- } ('A','B','C','D','E','F','G','H','I','J','K','L','M',
- 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
- 'a','b','c','d','e','f','g','h','i','j','k','l','m',
- 'n','o','p','q','r','s','t','u','v','w','x','y','z');
+ }
return @cols;
}
@@ -438,28 +904,30 @@ sub outrowassess {
my @cols=();
if ($n) {
my ($usy,$ufn)=split(/\_\_\&\&\&\_\_/,$f{'A'.$n});
+ if ($rl{$usy}) {
$cols[0]=$rl{$usy}.'
'.
'';
} else {
$cols[0]='Export';
}
- map {
+ foreach ('A','B','C','D','E','F','G','H','I','J','K','L','M',
+ 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
+ 'a','b','c','d','e','f','g','h','i','j','k','l','m',
+ 'n','o','p','q','r','s','t','u','v','w','x','y','z') {
my $fm=$f{$_.$n};
$fm=~s/[\'\"]/\&\#34;/g;
- $cols[$#cols+1]="'$_$n','$fm'".'___eq___'.$v{$_.$n};
- } ('A','B','C','D','E','F','G','H','I','J','K','L','M',
- 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
- 'a','b','c','d','e','f','g','h','i','j','k','l','m',
- 'n','o','p','q','r','s','t','u','v','w','x','y','z');
+ push(@cols,"'$_$n','$fm'".'___eq___'.$v{$_.$n});
+ }
return @cols;
}
@@ -471,23 +939,23 @@ sub outrow {
} else {
$cols[0]='Export';
}
- map {
+ foreach ('A','B','C','D','E','F','G','H','I','J','K','L','M',
+ 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
+ 'a','b','c','d','e','f','g','h','i','j','k','l','m',
+ 'n','o','p','q','r','s','t','u','v','w','x','y','z') {
my $fm=$f{$_.$n};
$fm=~s/[\'\"]/\&\#34;/g;
$cols[$#cols+1]="'$_$n','$fm'".'___eq___'.$v{$_.$n};
- } ('A','B','C','D','E','F','G','H','I','J','K','L','M',
- 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
- 'a','b','c','d','e','f','g','h','i','j','k','l','m',
- 'n','o','p','q','r','s','t','u','v','w','x','y','z');
+ }
return @cols;
}
sub exportrowa {
my @exportarray=();
- map {
+ foreach ('A','B','C','D','E','F','G','H','I','J','K','L','M',
+ 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z') {
$exportarray[$#exportarray+1]=$v{$_.'0'};
- } ('A','B','C','D','E','F','G','H','I','J','K','L','M',
- 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z');
+ }
return @exportarray;
}
@@ -529,7 +997,7 @@ sub setrowlabels {
sub calcsheet {
my $safeeval=shift;
- $safeeval->reval('&calc();');
+ return $safeeval->reval('&calc();');
}
# ------------------------------------------------------------------ Get values
@@ -546,6 +1014,13 @@ sub getformulas {
return %{$safeeval->varglob('f')};
}
+# ----------------------------------------------------- Get value of $f{'A'.$n}
+
+sub getfa {
+ my ($safeeval,$n)=@_;
+ return $safeeval->reval('$f{"A'.$n.'"}');
+}
+
# -------------------------------------------------------------------- Get type
sub gettype {
@@ -684,7 +1159,7 @@ sub rown {
}
my $showf=0;
my $proc;
- my $maxred;
+ my $maxred=1;
my $sheettype=&gettype($safeeval);
if ($sheettype eq 'studentcalc') {
$proc='&outrowassess';
@@ -697,8 +1172,9 @@ sub rown {
} else {
$maxred=26;
}
+ if (&getfa($safeeval,$n)=~/^[\~\-]/) { $maxred=1; }
if ($n eq '-') { $proc='&templaterow'; $n=-1; $dataflag=1; }
- map {
+ foreach ($safeeval->reval($proc.'('.$n.')')) {
my $bgcolor=$defaultbg.((($showf-1)/5==int(($showf-1)/5))?'99':'DD');
my ($fm,$vl)=split(/\_\_\_eq\_\_\_/,$_);
if ((($vl ne '') || ($vl eq '0')) &&
@@ -711,9 +1187,14 @@ sub rown {
if ($vl eq '') {
$vl='#';
}
- $rowdata.=
- '
'; } @@ -799,12 +1280,12 @@ sub outsheet { $r->print("\n
\n"); $r->rflush(); $r->print('
'.$what.' | '); - map { + foreach ('A','B','C','D','E','F','G','H','I','J','K','L','M', + 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', + 'a','b','c','d','e','f','g','h','i','j','k','l','m', + 'n','o','p','q','r','s','t','u','v','w','x','y','z') { $r->print(''.$_.' | '); - } ('A','B','C','D','E','F','G','H','I','J','K','L','M', - 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', - 'a','b','c','d','e','f','g','h','i','j','k','l','m', - 'n','o','p','q','r','s','t','u','v','w','x','y','z'); + } $r->print('