diff --git a/api/Makefile.am b/api/Makefile.am index 059d355ee7..5483be7894 100644 --- a/api/Makefile.am +++ b/api/Makefile.am @@ -6,10 +6,12 @@ include $(top_srcdir)/Makefile.incl AM_CFLAGS += @GLUT_CFLAGS@ AM_LDFLAGS += @GLUT_LIBS@ +# stuff linked into both main app and graphics app api_files= \ boinc_api.C \ graphics2_util.C +# stuff linked into graphics app graphics2_files = \ gutil.C \ gutil_text.C \ @@ -21,8 +23,8 @@ graphics2_files = \ graphics2_unix.C if OS_DARWIN - api_files += mac_icon.C - graphics2_files += macglutfix.m + graphics2_files += mac_icon.C + graphics2_files += macglutfix.m endif EXTRA_DIST = *.h diff --git a/api/graphics2.C b/api/graphics2.C index 00f55ce129..7c069c88a9 100644 --- a/api/graphics2.C +++ b/api/graphics2.C @@ -1,3 +1,24 @@ +// Berkeley Open Infrastructure for Network Computing +// http://boinc.berkeley.edu +// Copyright (C) 2008 University of California +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// either version 2.1 of the License, or (at your option) any later version. +// +// This software 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 Lesser General Public License for more details. +// +// To view the GNU Lesser General Public License visit +// http://www.gnu.org/copyleft/lesser.html +// or write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +// platform-independent part of graphics library +// #include "util.h" #include "app_ipc.h" #include "shmem.h" diff --git a/api/graphics2_unix.C b/api/graphics2_unix.C index dbb99dbdac..f8b66706eb 100644 --- a/api/graphics2_unix.C +++ b/api/graphics2_unix.C @@ -1,3 +1,24 @@ +// Berkeley Open Infrastructure for Network Computing +// http://boinc.berkeley.edu +// Copyright (C) 2008 University of California +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// either version 2.1 of the License, or (at your option) any later version. +// +// This software 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 Lesser General Public License for more details. +// +// To view the GNU Lesser General Public License visit +// http://www.gnu.org/copyleft/lesser.html +// or write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +// unix-specific graphics stuff +// #include "config.h" #include #include diff --git a/api/graphics2_util.C b/api/graphics2_util.C index d4f0128d29..bde2658f38 100644 --- a/api/graphics2_util.C +++ b/api/graphics2_util.C @@ -1,3 +1,25 @@ +// Berkeley Open Infrastructure for Network Computing +// http://boinc.berkeley.edu +// Copyright (C) 2008 University of California +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// either version 2.1 of the License, or (at your option) any later version. +// +// This software 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 Lesser General Public License for more details. +// +// To view the GNU Lesser General Public License visit +// http://www.gnu.org/copyleft/lesser.html +// or write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +// graphics-related utilities, used both from main applications +// (set create shared mem) and by the graphics app + #ifdef _WIN32 #include "boinc_win.h" #elif (!defined(__EMX__)) diff --git a/api/graphics2_win.C b/api/graphics2_win.C index cd90d81c7f..35afbea86d 100644 --- a/api/graphics2_win.C +++ b/api/graphics2_win.C @@ -375,18 +375,18 @@ void boinc_graphics_loop(int argc, char** argv) { extern int main(int, char**); -static HINSTANCE hInstance = NULL; +static HINSTANCE instance = NULL; // call this with the resource names you compiled the icons with // (16x16 and 48x48 pixel) // -void boinc_set_windows_icon(const char*icon16,const char*icon48) { +void boinc_set_windows_icon(const char* icon16, const char* icon48) { LONG ic; HWND hWnd=FindWindow("BOINC_app",NULL); - if (ic=(LONG)LoadIcon(hInstance,icon48)) { + if (ic=(LONG)LoadIcon(instance,icon48)) { SetClassLongPtr(hWnd,GCLP_HICON,ic); } - if (ic=(LONG)LoadImage(hInstance,icon16, IMAGE_ICON, 16, 16, 0)) { + if (ic=(LONG)LoadImage(instance,icon16, IMAGE_ICON, 16, 16, 0)) { SetClassLongPtr(hWnd,GCLP_HICONSM,ic); } } @@ -396,7 +396,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR Args, int WinMode char* argv[100]; int argc; - hInstance = hInst; + instance = hInst; command_line = GetCommandLine(); argc = parse_command_line(command_line, argv); main(argc, argv); diff --git a/api/graphics_api.C b/api/graphics_api.C index 3826131c05..7f0f819bbe 100644 --- a/api/graphics_api.C +++ b/api/graphics_api.C @@ -17,6 +17,8 @@ // or write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// DEPRECATED - DO NOT USE + #if defined(_WIN32) && !defined(__STDWX_H__) && !defined(_BOINC_WIN_) && !defined(_AFX_STDAFX_H_) #include "boinc_win.h" #else diff --git a/checkin_notes b/checkin_notes index c218e7bbed..c1039dcf94 100644 --- a/checkin_notes +++ b/checkin_notes @@ -822,3 +822,16 @@ David Jan 28 2008 http_curl.C log_flags.C,h scheduler_op.C + +David Jan 28 2008 + - API: fix Win build error + - API: fix Makefile.am + - add LGPL license on some files + + api/ + Makefile.am + graphics_api.C + graphics2_win.C + graphics2_unix.C + graphics2_util.C + graphics2.C diff --git a/db/bolt_schema.sql b/db/bolt_schema.sql index 2fb869eae4..9a7316e97f 100644 --- a/db/bolt_schema.sql +++ b/db/bolt_schema.sql @@ -76,7 +76,7 @@ create table bolt_result ( ); -- represents the result of a completed exercise set, --- where "completed" means the student clicked Next on the final answer page. +-- where "completed" means the last exercise was scored. -- In theory this could be reconstructed from the individual exercise results, -- but this table makes it easier for analytics -- diff --git a/html/inc/bolt.inc b/html/inc/bolt.inc index faf59e6a7e..8587524168 100644 --- a/html/inc/bolt.inc +++ b/html/inc/bolt.inc @@ -1,25 +1,11 @@ top = $top; - $this->state = array(); - } - - function decode_state($encoded_state) { - $this->state = json_decode($encoded_state, true); - } - - function encode_state() { - return json_encode($this->state); - } - - // get current item and fraction done - // - function at() { - $this->xset = null; - $this->top->walk($this, false, $this->frac_done); - } - - // move to the next item, and return it in $this->item - // (null if course finished) - // - function next() { - $this->top->walk($this, true, $this->frac_done); - } -} - class BoltItem extends BoltUnit { public $filename; public $query_string; @@ -113,6 +60,106 @@ class BoltExercise extends BoltItem { } } +// Base class for control structures (i.e. all units that are not items). +// These have the following properties: +// - a set of units +// - an ordering of this set, defined in the derived class +// (i.e., random, student-specific, or identity) +// - an index (state_rec::index) for where we are in this list +// - an index (state_rec::nshown) for how many units completed so far +// - a number "ntoshow" for how many to show +// +class BoltSet extends BoltUnit { + public $units; + function __construct($name, $units, $ntoshow) { + $this->name = $name; + $this->is_item = false; + $this->units = $units; + $this->ntoshow = $ntoshow; + $this->ordered = false; + } + function walk(&$iter, $incr, &$frac_done) { + $n = count($this->units); + if (array_key_exists($this->name, $iter->state)) { + $state_rec = $iter->state[$this->name]; + $child_name = $state_rec['child_name']; + $nshown = $state_rec['nshown']; + if (!$this->ordered) { + $this->order($state_rec); + $this->ordered = true; + } + + // look up unit by name + // + $child = null; + for ($i=0; $i<$n; $i++) { + $c = $this->units[$i]; + if ($c->name == $child_name) { + $child = $c; + break; + } + } + + // if not there, look up by index + // + if (!$child) { + $i = $state_rec['index']; + if ($i >= $n) { + // and if index is too big, use last unit + // + $i = $n-1; + } + $child = $this->units[$i]; + } + + // at this point, $child is the current unit, and $i is its index + // + if ($incr) { + if ($child->is_item) { + $my_inc = true; + } else { + $my_inc = $child->walk($iter, $incr, $frac_done); + } + if ($my_inc) { + $nshown++; + if ($nshown == $this->ntoshow) { + $frac_done = 1; + $state_rec['nshown'] = 0; + $state_rec['child_name'] = null; + $iter->state[$this->name] = $state_rec; + return true; + } else { + $i = ($i+1)%$n; + } + } + } + } else { + // here if no state record; initialize + // + $i = 0; + $nshown = 0; + $state_rec = null; + $this->order($state_rec); + } + + // at this point, $i is index of current child + // + $child = $this->units[$i]; + $frac_done = $nshown/$n; + $state_rec['index'] = $i; + $state_rec['nshown'] = $nshown; + $state_rec['child_name'] = $child->name; + $iter->state[$this->name] = $state_rec; + if ($child->is_item) { + $iter->item = $child; + } else { + $child->walk($iter, false, $f); + $frac_done += $f*(1/$n); + } + return false; + } +} + function name($n) { return array('name', $n); } @@ -185,19 +232,6 @@ function exercise() { return new BoltExercise($name, $title, $file); } -function enum_course($course) { - $iter = new BoltIter($course); - while (1) { - $x = $iter->at(); - if (!$x) break; - echo "at: $x->url\n"; - $x = $iter->next(); - if (!$x) break; - echo "next: $x->filename\n"; - } - echo "course over\n"; -} - require_once('../inc/bolt_seq.inc'); require_once('../inc/bolt_rnd.inc'); require_once('../inc/bolt_xset.inc'); diff --git a/html/inc/bolt_ex.inc b/html/inc/bolt_ex.inc index 4025ab1c4c..bb8212fd9b 100644 --- a/html/inc/bolt_ex.inc +++ b/html/inc/bolt_ex.inc @@ -1,5 +1,7 @@ name = $name; - $this->units = $units; - $this->number = $number; - $this->is_item = false; - $this->shuffled = false; + parent::__construct($name, $units, $number); } - function walk(&$iter, $incr, &$frac_done) { - $n = count($this->units); - if (array_key_exists($this->name, $iter->state)) { - $state_rec = $iter->state[$this->name]; - $child_name = $state_rec['child_name']; - $number_shown = $state_rec['number_shown']; - if (!$this->shuffled) { - srand($state_rec['seed']); - shuffle($this->units); - $this->shuffled = true; - } - - // look up unit by name - // - $child = null; - for ($i=0; $i<$n; $i++) { - $c = $this->units[$i]; - if ($c->name == $child_name) { - $child = $c; - break; - } - } - - // if not there, look up by index - // - if (!$child) { - $i = $state_rec['i']; - if ($i >= $n) { - // and if index is too big, use last unit - // - $i = $n-1; - } - $child = $this->units[$i]; - } - - // at this point, $child is the current unit, and $i is its index - // - if ($incr) { - $my_inc = false; - if ($child->is_item) { - $my_inc = true; - } else { - $my_inc = $child->walk($iter, $incr, $frac_done); - } - if ($my_inc) { - $i = ($i+1)%$n; - $number_shown++; - if ($number_shown >= $this->number) { - $frac_done = 1; - $state_rec['i'] = $i; - $state_rec['number_shown'] = 0; - $state_rec['child_name'] = null; - $iter->state[$this->name] = $state_rec; - return true; - } - } - } + function order(&$state_rec) { + if ($state_rec) { + $seed = $state_rec['seed']; } else { - $i = 0; - $number_shown = 0; - $state_rec = null; $seed = ((double)microtime()*1000000); - srand($seed); - shuffle($this->units); $state_rec['seed'] = $seed; } - $child = $this->units[$i]; - $frac_done = $number_shown/$this->number; - $state_rec['i'] = $i; - $state_rec['number_shown'] = $number_shown; - $state_rec['child_name'] = $child->name; - $iter->state[$this->name] = $state_rec; - if ($child->is_item) { - $iter->item = $child; - } else { - $child->walk($iter, false, $f); - $frac_done += $f*(1/$number); - } + srand($seed); + shuffle($this->units); } } diff --git a/html/inc/bolt_sched.inc b/html/inc/bolt_sched.inc new file mode 100644 index 0000000000..b1a1471b28 --- /dev/null +++ b/html/inc/bolt_sched.inc @@ -0,0 +1,65 @@ +top = $top; + $this->state = array(); + } + + function decode_state($encoded_state) { + $this->state = json_decode($encoded_state, true); + } + + function encode_state() { + return json_encode($this->state); + } + + // get current item and fraction done + // + function at() { + $this->xset = null; + $this->top->walk($this, false, $this->frac_done); + } + + // move to the next item, and return it in $this->item + // (null if course finished) + // + function next() { + $this->top->walk($this, true, $this->frac_done); + } +} + +function enum_course($course) { + $iter = new BoltIter($course); + while (1) { + $x = $iter->at(); + if (!$x) break; + echo "at: $x->url\n"; + $x = $iter->next(); + if (!$x) break; + echo "next: $x->filename\n"; + } + echo "course over\n"; +} + +?> diff --git a/html/inc/bolt_seq.inc b/html/inc/bolt_seq.inc index 55f6d9fc59..31af6e007f 100644 --- a/html/inc/bolt_seq.inc +++ b/html/inc/bolt_seq.inc @@ -1,77 +1,11 @@ name = $name; - $this->units = $units; - $this->is_item = false; + parent::__construct($name, $units, count($units)); } - function walk(&$iter, $incr, &$frac_done) { - $n = count($this->units); - if (array_key_exists($this->name, $iter->state)) { - $state_rec = $iter->state[$this->name]; - $child_name = $state_rec['child_name']; - - // look up unit by name - // - $child = null; - for ($i=0; $i<$n; $i++) { - $c = $this->units[$i]; - if ($c->name == $child_name) { - $child = $c; - break; - } - } - - // if not there, look up by index - // - if (!$child) { - $i = $state_rec['i']; - if ($i >= $n) { - // and if index is too big, use last unit - // - $i = $n-1; - } - $child = $this->units[$i]; - } - - // at this point, $child is the current unit, and $i is its index - // - if ($incr) { - $my_inc = false; - if ($child->is_item) { - $my_inc = true; - } else { - $my_inc = $child->walk($iter, $incr, $frac_done); - } - if ($my_inc) { - $i++; - if ($i == $n) { - $frac_done = 1; - $state_rec['i'] = 0; - $state_rec['child_name'] = null; - $iter->state[$this->name] = $state_rec; - return true; - } - } - } - } else { - $i = 0; - } - $child = $this->units[$i]; - $frac_done = $i/$n; - $state_rec = null; - $state_rec['i'] = $i; - $state_rec['child_name'] = $child->name; - $iter->state[$this->name] = $state_rec; - if ($child->is_item) { - $iter->item = $child; - } else { - $child->walk($iter, false, $f); - $frac_done += $f*(1/$n); - } + function order() { } } diff --git a/html/inc/bolt_xset.inc b/html/inc/bolt_xset.inc index 9d0282ba24..2df0566416 100644 --- a/html/inc/bolt_xset.inc +++ b/html/inc/bolt_xset.inc @@ -1,128 +1,48 @@ name = $name; - $this->units = $units; - $this->number = $number; + parent::__construct($name, $units, $number); $this->repeats = $repeats; - $this->is_item = false; - $this->shuffled = false; } - // the scheduler calls this when an exercise in this set - // has just been graded. + // called when an exercise in this set has just been graded. // - record the score in our state structure // - return a structure saying what navigation info to show: // - review // - repeat now // - next // - function xset_callback($iter, $score, &$is_last, &$nav_info) { + function xset_callback(&$iter, $score, $view_id, &$is_last, &$nav_info) { + echo "XSET_CALLBACK: $score"; + $nav_info = null; $state_rec = $iter->state[$this->name]; - $number_shown = $state_rec['number_shown']; - $state_rec['scores'][$number_shown] = $score; - $is_last = ($number_shown == $this->number); - if ($is_last) { - } else { - } - } + $nshown = $state_rec['nshown']; + $state_rec['scores'][$nshown] = $score; + $iter->state[$this->name] = $state_rec; + $is_last = ($nshown == $this->ntoshow); + if (!$is_last) return; + + // this exercise set is now "completed". + // - create exercise_set_result record + // - optionally create or update bolt_refresh record + // + $total_score = 0; + for ($i=0; $i<$nshown; $i++) { + $total_score += $state_rec['score'][$i]; + } + $avg_score = $total_score/$nshown; - // The user clicked "Next" on last answer page, - // so this exercise set is now "completed". - // - create exercise_set_result record - // - optionally create or update bolt_refresh record - // - function completed($score, $view_id) { $now = time(); - $id = BoincXsetResult::insert("(create_time, user_id, course_id, name, score, view_id) values ($now, $user->id, $course->id, '$this->name', $score, $view_id)"); + $id = BoincXsetResult::insert("(create_time, user_id, course_id, name, score, view_id) values ($now, $user->id, $course->id, '$this->name', $avg_score, $view_id)"); $due_time = $now + 100000; BoincRefresh::replace("create_time=$now, user_id=$user->id, course_id=$course->id, name='$this->name', set_result_id=$id, due_time=$due_time"); } function walk(&$iter, $incr, &$frac_done) { $iter->xset = $this; - $n = count($this->units); - if (array_key_exists($this->name, $iter->state)) { - $state_rec = $iter->state[$this->name]; - $this->state_rec = $state_rec; - $child_name = $state_rec['child_name']; - $number_shown = $state_rec['number_shown']; - if (!$this->shuffled) { - srand($state_rec['seed']); - shuffle($this->units); - $this->shuffled = true; - } - - // look up unit by name - // - $child = null; - for ($i=0; $i<$n; $i++) { - $c = $this->units[$i]; - if ($c->name == $child_name) { - $child = $c; - break; - } - } - - // if not there, look up by index - // - if (!$child) { - $i = $state_rec['i']; - if ($i >= $n) { - // and if index is too big, use last unit - // - $i = $n-1; - } - $child = $this->units[$i]; - } - - // at this point, $child is the current unit, and $i is its index - // - if ($incr) { - $my_inc = false; - if ($child->is_item) { - $my_inc = true; - } else { - $my_inc = $child->walk($iter, $incr, $frac_done); - } - if ($my_inc) { - $i = ($i+1)%$n; - $number_shown++; - if ($number_shown >= $this->number) { - $frac_done = 1; - $state_rec['i'] = $i; - $state_rec['number_shown'] = 0; - $state_rec['child_name'] = null; - $iter->state[$this->name] = $state_rec; - return true; - } - } - } - } else { - $i = 0; - $number_shown = 0; - $state_rec = null; - $seed = ((double)microtime()*1000000); - srand($seed); - shuffle($this->units); - $state_rec['seed'] = $seed; - } - $child = $this->units[$i]; - $frac_done = $number_shown/$this->number; - $state_rec['i'] = $i; - $state_rec['number_shown'] = $number_shown; - $state_rec['child_name'] = $child->name; - $iter->state[$this->name] = $state_rec; - if ($child->is_item) { - $iter->item = $child; - } else { - $child->walk($iter, false, $f); - $frac_done += $f*(1/$number); - } + return parent::walk($iter, $incr, $frac_done); } } diff --git a/html/user/bolt_sched.php b/html/user/bolt_sched.php index e687024764..2cd3b53aa9 100644 --- a/html/user/bolt_sched.php +++ b/html/user/bolt_sched.php @@ -6,6 +6,7 @@ // action: see commands below require_once("../inc/bolt.inc"); +require_once("../inc/bolt_sched.inc"); require_once("../inc/bolt_db.inc"); require_once("../inc/bolt_ex.inc"); require_once("../inc/bolt_util.inc"); @@ -261,11 +262,11 @@ case 'next': // "next" button in lesson or exercise answer page break; case 'answer': // submit answer in exercise $view = finalize_view($user, $view_id, BOLT_ACTION_SUBMIT); - if ($user->bolt->debug) { - echo "
State: $view->state
\n"; - } $iter = new BoltIter($course_doc); $iter->decode_state($view->state); + if ($user->bolt->debug) { + echo "
Initial state:"; print_r($iter->state); echo "
\n"; + } $iter->at(); if ($user->bolt->debug) { @@ -303,6 +304,12 @@ case 'answer': // submit answer in exercise ); $view->update("result_id=$result_id"); + // If this is part of an exercise set, call its callback function + // + if ($iter->xset) { + $iter->xset->xset_callback($iter, $bolt_ex_score, $view->id, $is_last, $nav_info); + } + // show the answer page srand($view_id);