--- loncom/interface/lonnavmaps.pm 2003/08/07 17:26:44 1.221
+++ loncom/interface/lonnavmaps.pm 2003/09/08 19:53:09 1.224
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Navigate Maps Handler
#
-# $Id: lonnavmaps.pm,v 1.221 2003/08/07 17:26:44 bowersj2 Exp $
+# $Id: lonnavmaps.pm,v 1.224 2003/09/08 19:53:09 bowersj2 Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -61,19 +61,14 @@ my $resObj = "Apache::lonnavmaps::resour
# Keep these mappings in sync with lonquickgrades, which uses the colors
# instead of the icons.
my %statusIconMap =
- ( $resObj->NETWORK_FAILURE => '',
- $resObj->NOTHING_SET => '',
- $resObj->CORRECT => 'navmap.correct.gif',
- $resObj->EXCUSED => 'navmap.correct.gif',
- $resObj->PAST_DUE_NO_ANSWER => 'navmap.wrong.gif',
- $resObj->PAST_DUE_ANSWER_LATER => 'navmap.wrong.gif',
- $resObj->ANSWER_OPEN => 'navmap.wrong.gif',
- $resObj->OPEN_LATER => '',
- $resObj->TRIES_LEFT => 'navmap.open.gif',
- $resObj->INCORRECT => 'navmap.wrong.gif',
- $resObj->OPEN => 'navmap.open.gif',
- $resObj->ATTEMPTED => 'navmap.ellipsis.gif',
- $resObj->ANSWER_SUBMITTED => 'navmap.ellipsis.gif' );
+ (
+ $resObj->CLOSED => '',
+ $resObj->OPEN => 'navmap.open.gif',
+ $resObj->CORRECT => 'navmap.correct.gif',
+ $resObj->INCORRECT => 'navmap.wrong.gif',
+ $resObj->ATTEMPTED => 'navmap.ellipsis.gif',
+ $resObj->ERROR => ''
+ );
my %iconAltTags =
( 'navmap.correct.gif' => 'Correct',
@@ -168,23 +163,17 @@ sub real_handler {
# See if there's only one map in the top-level, if we don't
# already have a filter... if so, automatically display it
+ # (older code; should use retrieveResources)
if ($ENV{QUERY_STRING} !~ /filter/) {
my $iterator = $navmap->getIterator(undef, undef, undef, 0);
- my $depth = 1;
- $iterator->next();
- my $curRes = $iterator->next();
+ my $curRes;
my $sequenceCount = 0;
my $sequenceId;
- while ($depth > 0) {
- if ($curRes == $iterator->BEGIN_MAP()) { $depth++; }
- if ($curRes == $iterator->END_MAP()) { $depth--; }
-
+ while ($curRes = $iterator->next()) {
if (ref($curRes) && $curRes->is_sequence()) {
$sequenceCount++;
$sequenceId = $curRes->map_pc();
}
-
- $curRes = $iterator->next();
}
if ($sequenceCount == 1) {
@@ -202,16 +191,11 @@ sub real_handler {
$jumpToFirstHomework = 1;
# Find the next homework problem that they can do.
my $iterator = $navmap->getIterator(undef, undef, undef, 1);
- my $depth = 1;
- $iterator->next();
- my $curRes = $iterator->next();
+ my $curRes;
my $foundDoableProblem = 0;
my $problemRes;
- while ($depth > 0 && !$foundDoableProblem) {
- if ($curRes == $iterator->BEGIN_MAP()) { $depth++; }
- if ($curRes == $iterator->END_MAP()) { $depth--; }
-
+ while (($curRes = $iterator->next()) && !$foundDoableProblem) {
if (ref($curRes) && $curRes->is_problem()) {
my $status = $curRes->status();
if ($curRes->completable()) {
@@ -229,8 +213,6 @@ sub real_handler {
$ENV{'form.postsymb'} = $curRes->symb();
}
}
- } continue {
- $curRes = $iterator->next();
}
# If we found no problems, print a note to that effect.
@@ -1049,7 +1031,8 @@ sub render_quick_status {
if ($resource->is_problem() &&
!$firstDisplayed) {
- my $icon = $statusIconMap{$resource->status($part)};
+
+ my $icon = $statusIconMap{$resource->simpleStatus($part)};
my $alt = $iconAltTags{$icon};
if ($icon) {
$result .= "
$linkopen $linkclose | \n";
@@ -1185,18 +1168,13 @@ sub render {
# Step three: Ensure the folders are open
my $mapIterator = $navmap->getIterator(undef, undef, undef, 1);
- my $depth = 1;
- $mapIterator->next(); # discard the first BEGIN_MAP
- my $curRes = $mapIterator->next();
+ my $curRes;
my $found = 0;
# We only need to do this if we need to open the maps to show the
# current position. This will change the counter so we can't count
# for the jump marker with this loop.
- while ($depth > 0 && !$found) {
- if ($curRes == $mapIterator->BEGIN_MAP()) { $depth++; }
- if ($curRes == $mapIterator->END_MAP()) { $depth--; }
-
+ while (($curRes = $mapIterator->next()) && !$found) {
if (ref($curRes) && $curRes->symb() eq $here) {
my $mapStack = $mapIterator->getStack();
@@ -1210,8 +1188,6 @@ sub render {
}
$found = 1;
}
-
- $curRes = $mapIterator->next();
}
}
@@ -1249,15 +1225,11 @@ sub render {
# Note this does not take filtering or hidden into account... need
# to be fixed?
my $mapIterator = $navmap->getIterator(undef, undef, $filterHash, 0);
- my $depth = 1;
- $mapIterator->next();
- my $curRes = $mapIterator->next();
+ my $curRes;
my $foundJump = 0;
my $counter = 0;
- while ($depth > 0 && !$foundJump) {
- if ($curRes == $mapIterator->BEGIN_MAP()) { $depth++; }
- if ($curRes == $mapIterator->END_MAP()) { $depth--; }
+ while (($curRes = $mapIterator->next()) && !$foundJump) {
if (ref($curRes)) { $counter++; }
if (ref($curRes) && $jump eq $curRes->symb()) {
@@ -1268,8 +1240,6 @@ sub render {
$args->{'currentJumpIndex'} = $counter;
$foundJump = 1;
}
-
- $curRes = $mapIterator->next();
}
my $showParts = setDefault($args->{'showParts'}, 1);
@@ -1347,7 +1317,7 @@ sub render {
$it->{FIRST_RESOURCE},
$it->{FINISH_RESOURCE},
{}, undef, 1);
- $depth = 0;
+ my $depth = 0;
$dfsit->next();
my $curRes = $dfsit->next();
while ($depth > -1) {
@@ -1379,9 +1349,6 @@ sub render {
my $displayedJumpMarker = 0;
# Set up iteration.
- $depth = 1;
- $it->next(); # discard initial BEGIN_MAP
- $curRes = $it->next();
my $now = time();
my $in24Hours = $now + 24 * 60 * 60;
my $rownum = 0;
@@ -1389,10 +1356,8 @@ sub render {
# export "here" marker information
$args->{'here'} = $here;
- while ($depth > 0) {
- if ($curRes == $it->BEGIN_MAP()) { $depth++; }
- if ($curRes == $it->END_MAP()) { $depth--; }
-
+ $args->{'indentLevel'} = -1; # first BEGIN_MAP takes this to 0
+ while ($curRes = $it->next()) {
# Maintain indentation level.
if ($curRes == $it->BEGIN_MAP() ||
$curRes == $it->BEGIN_BRANCH() ) {
@@ -1545,8 +1510,6 @@ sub render {
$r->rflush();
}
} continue {
- $curRes = $it->next();
-
if ($r) {
# If we have the connection, make sure the user is still connected
my $c = $r->connection;
@@ -2184,18 +2147,9 @@ sub retrieveResources {
my @resources = ();
# Run down the iterator and collect the resources.
- my $depth = 1;
- $it->next();
- my $curRes = $it->next();
-
- while ($depth > 0) {
- if ($curRes == $it->BEGIN_MAP()) {
- $depth++;
- }
- if ($curRes == $it->END_MAP()) {
- $depth--;
- }
-
+ my $curRes;
+
+ while ($curRes = $it->next()) {
if (ref($curRes)) {
if (!&$filterFunc($curRes)) {
next;
@@ -2208,8 +2162,6 @@ sub retrieveResources {
}
}
- } continue {
- $curRes = $it->next();
}
return @resources;
@@ -2285,6 +2237,13 @@ new branch. The possible tokens are:
=over 4
+=item * B:
+
+The iterator has returned all that it's going to. Further calls to the
+iterator will just produce more of these. This is a "false" value, and
+is the only false value the iterator which will be returned, so it can
+be used as a loop sentinel.
+
=item * B:
A new map is being recursed into. This is returned I the map
@@ -2315,12 +2274,33 @@ consisting entirely of empty resources e
ending resource, will cause a lot of BRANCH_STARTs and BRANCH_ENDs,
but only one resource will be returned.
+=head2 Normal Usage
+
+Normal usage of the iterator object is to do the following:
+
+ my $it = $navmap->getIterator([your params here]);
+ my $curRes;
+ while ($curRes = $it->next()) {
+ [your logic here]
+ }
+
+Note that inside of the loop, it's frequently useful to check if
+"$curRes" is a reference or not with the reference function; only
+resource objects will be references, and any non-references will
+be the tokens described above.
+
+Also note there is some old code floating around that trys to track
+the depth of the iterator to see when it's done; do not copy that
+code. It is difficult to get right and harder to understand then
+this. They should be migrated to this new style.
+
=back
=cut
# Here are the tokens for the iterator:
+sub END_ITERATOR { return 0; }
sub BEGIN_MAP { return 1; } # begining of a new map
sub END_MAP { return 2; } # end of the map
sub BEGIN_BRANCH { return 3; } # beginning of a branch
@@ -2406,13 +2386,13 @@ sub new {
# prime the recursion
$self->{$firstResourceName}->{DATA}->{$valName} = 0;
- my $depth = 0;
- $iterator->next();
+ $iterator->next();
my $curRes = $iterator->next();
- while ($depth > -1) {
- if ($curRes == $iterator->BEGIN_MAP()) { $depth++; }
- if ($curRes == $iterator->END_MAP()) { $depth--; }
-
+ my $depth = 1;
+ while ($depth > 0) {
+ if ($curRes == $iterator->BEGIN_MAP()) { $depth++; }
+ if ($curRes == $iterator->END_MAP()) { $depth--; }
+
if (ref($curRes)) {
# If there's only one resource, this will save it
# we have to filter empty resources from consideration here,
@@ -2446,8 +2426,8 @@ sub new {
$curRes->{DATA}->{DISPLAY_DEPTH} = $finalDepth;
if ($finalDepth > $maxDepth) {$maxDepth = $finalDepth;}
}
- } continue {
- $curRes = $iterator->next();
+
+ $curRes = $iterator->next();
}
}
@@ -2468,6 +2448,7 @@ sub new {
$self->{MAX_DEPTH} = $maxDepth;
$self->{STACK} = [];
$self->{RECURSIVE_ITERATOR_FLAG} = 0;
+ $self->{FINISHED} = 0; # When true, the iterator has finished
for (my $i = 0; $i <= $self->{MAX_DEPTH}; $i++) {
push @{$self->{STACK}}, [];
@@ -2485,6 +2466,10 @@ sub new {
sub next {
my $self = shift;
+ if ($self->{FINISHED}) {
+ return END_ITERATOR();
+ }
+
# If we want to return the top-level map object, and haven't yet,
# do so.
if ($self->{RETURN_0} && !$self->{HAVE_RETURNED_0}) {
@@ -2544,6 +2529,7 @@ sub next {
$self->{CURRENT_DEPTH}--;
return END_BRANCH();
} else {
+ $self->{FINISHED} = 1;
return END_MAP();
}
}
@@ -3040,9 +3026,9 @@ sub symb {
my $self=shift;
(my $first, my $second) = $self->{ID} =~ /(\d+).(\d+)/;
my $symbSrc = &Apache::lonnet::declutter($self->src());
- return &Apache::lonnet::declutter(
- $self->navHash('map_id_'.$first))
+ my $symb = &Apache::lonnet::declutter($self->navHash('map_id_'.$first))
. '___' . $second . '___' . $symbSrc;
+ return &Apache::lonnet::symbclean($symb);
}
sub title {
my $self=shift;
@@ -3881,6 +3867,7 @@ sub status {
# dimension and 5 entries on the other, which we want to colorize,
# plus network failure and "no date data at all".
+ #if ($self->{RESOURCE_ERROR}) { return NETWORK_FAILURE; }
if ($completionStatus == NETWORK_FAILURE) { return NETWORK_FAILURE; }
my $suppressFeedback = lc($self->parmval("problemstatus", $part)) eq 'no';
@@ -3927,7 +3914,7 @@ sub status {
if ($completionStatus == INCORRECT || $completionStatus == INCORRECT_BY_OVERRIDE) {
# and there are TRIES LEFT:
if ($self->tries($part) < $self->maxtries($part) || !$self->maxtries($part)) {
- return TRIES_LEFT;
+ return $suppressFeedback ? ANSWER_SUBMITTED : TRIES_LEFT;
}
return $suppressFeedback ? ANSWER_SUBMITTED : INCORRECT; # otherwise, return orange; student can't fix this
}
@@ -3936,6 +3923,64 @@ sub status {
return OPEN;
}
+sub CLOSED { return 23; }
+sub ERROR { return 24; }
+
+=pod
+
+B
+
+Convenience method B provides a "simple status" for the resource.
+"Simple status" corresponds to "which icon is shown on the
+Navmaps". There are six "simple" statuses:
+
+=over 4
+
+=item * B: The problem is currently closed. (No icon shown.)
+
+=item * B: The problem is open and unattempted.
+
+=item * B: The problem is correct for any reason.
+
+=item * B: The problem is incorrect and can still be
+completed successfully.
+
+=item * B: The problem has been attempted, but the student
+does not know if they are correct. (The ellipsis icon.)
+
+=item * B: There is an error retrieving information about this
+problem.
+
+=back
+
+=cut
+
+# This hash maps the composite status to this simple status, and
+# can be used directly, if you like
+my %compositeToSimple =
+ (
+ NETWORK_FAILURE() => ERROR,
+ NOTHING_SET() => CLOSED,
+ CORRECT() => CORRECT,
+ EXCUSED() => CORRECT,
+ PAST_DUE_NO_ANSWER() => INCORRECT,
+ PAST_DUE_ANSWER_LATER() => INCORRECT,
+ ANSWER_OPEN() => INCORRECT,
+ OPEN_LATER() => CLOSED,
+ TRIES_LEFT() => OPEN,
+ INCORRECT() => INCORRECT,
+ OPEN() => OPEN,
+ ATTEMPTED() => ATTEMPTED,
+ ANSWER_SUBMITTED() => ATTEMPTED
+ );
+
+sub simpleStatus {
+ my $self = shift;
+ my $part = shift;
+ my $status = $self->status($part);
+ return $compositeToSimple{$status};
+}
+
=pod
B