module LectureDB; (**** * The core object of the Eclass application is a Lecture, which is modeled as a series of slides. * Slides are comprised of HTML and EclassML tag blocks with start and end indexes within the * XHTML source file for the Lecture. The Lecture is also represented internally as three different * pools of tag blocks for the purposes of filtering. They are the SourcePool (complete source), * OutlineVisibles (Outline version) and SlideVisibles (Slide version). The UserWorkSpace object * ties together objects from various modules making them easily accesible to File and Edit operations. *) from View import PublicLayer, PrivateLayer; from roster_specs import RosterDB; from QandA_specs import QuestionLogDB; from Tools import PostItLog; from StudentVersion import Notepad; from file import File; export CurrentSlide, EclassML, EndIndex, EndPosition, GlobalSlideSetup, LastClicked, Lecture, MaxSize, NumberOfSlides, OutlineVisibles, PreviousState, Scrollable, Source, Slide, SlideNumber, SlideName, SequenceBlock, SequenceItemBlock, SlideBreak, Size, SourcePool, SlideVisibles, StartIndex, SlideData, SlideSetup, UserWorkSpace, HTML, TitleBlock, ParagraphBlock, LineBreak, IndentBlock, Heading1Block, Heading2Block, Heading3Block, Heading4Block, Heading5Block, Heading6Block, UnorderedListBlock, OrderedListBlock, DefinitionListBlock, ListItemBlock, EmphasisBlock, ItalicsBlock, UnderlineBlock, ImageBlock, EclassML, SlideTitle, HideBlock, ReplaceBlock, SubstitutionBlock, SelectBlock, StartIndex, EndIndex, StartTag, EndTag, StartPosition, EndPosition; object Lectures is LectureFileName*; object LectureFileName is string; object RequiresSaving is boolean description: (* The Source file requires saving whenever XHTML tags are inserted or text is added or deleted in the Outline window. *); end RequiresSaving; object Source is components: text:string and file:File and requires_saving:RequiresSaving; description: (* The Source is a long character string containing the entire XHTML source for the Lecture. It contains all the tag blocks that make up the SourcePool but it must be saved as a separate file from the Lecture so the instructor can edit it manually. *); end Source; object Lecture is components: slides:Slide* and myCurrentPosition:CurrentSlide and clsCurrentPosition:CurrentSlide and total:NumberOfSlides and and source:Source and sourcePool:SourcePool and outlineVisibles:OutlineVisibles and slideVisibles:SlideVisibles and setup:GlobalSlideSetup; description: (* The object lecture is composed of Slide objects and a slide marker for individual students called myCurrentPosition and another marker for the class set by the instructor called clsCurrentPosition and an integer storing the total number of slides in this lecture. It also contains the XHTML source for the Lecture and the three tag block pools which represent what tag blocks are visible in the Source file, Outline window and Slides window. *); end Lecture; object CurrentSlide is integer; object NumberOfSlides is integer; object Slide is components: data:SlideData and number:SlideNumber and name:SlideName; description: (* Each slide consists of its own data, number, and title. *); end Slide; object SlideNumber is integer; object SlideName is string; object SlideDefaultName is string; object SlideData is components: startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and endPos:EndPosition and maxPos:EndPosition and size:Size and slideSetup:SlideSetup; description: (* Each slide can contain data in the form of HTML or EclassML. A slide's data is part of a long master string of characters containing the entire XHTML source for the Lecture. StartIndex and endIndex are indexes within that string denoting where a slide's XHTML data begins and ends. A slide's data must also be represented graphically in the Slides window. For the purposes of this model the graphical representation of the Lecture within the Slides window is treated as one giant mapped display or scrolling grid with a fixed number of columns and a fixed row height. This simplification makes it easy to deal with screen geography inside the slides window. StartPos and endPos are indexes within the display map denoting where a slide's graphical representation begins and ends. Size can be derived by subtracting startPos from endPos. maxPos is the highest endPos a slide can handle. It is equivalent to startPos plus the slideSetup's maxSize. *); end SlideData; object StartIndex is integer; object EndIndex is integer; object StartPosition is integer; object EndPosition is integer; object Size is integer; object UserWorkSpace is components: lect:Lecture and private:PrivateLayer and public:PublicLayer and prev_state:PreviousState and clipboard:Clipboard and selection:Selection and context:SelectionContext and postIts:PostItLog or roster:RosterDB or qanda:QuestionLogDB or notePad:Notepad; description: (* Every users workspace contains the Lecture, PublicLayer, PrivateLayer, PreviousState, Clipboard, Selection and SelectionContext. Additionally, instructors get the QandA and Roster and students get their own NotePad. *); end UserWorkSpace; object PreviousState is components: PrivateLayer or PublicLayer; description: (* PreviousState is the snapshot of the space that the user last worked on. It could be the private layer or the public layer. *); end PreviousState; object HTML is components: titleBlocks:TitleBlock* or pBlocks:ParagraphBlock* or lineBreaks:LineBreak* or bqBlocks:IndentBlock* or h1Blocks:Heading1Block* or h2Blocks:Heading2Block* or h3Blocks:Heading3Block* or h4Blocks:Heading4Block* or h5Blocks:Heading5Block* or h6Blocks:Heading6Block* or ulBlocks:UnorderedListBlock* or olBlocks:OrderedListBlock* or dlBlocks:DefinitionListBlock* or liBlocks:ListItemBlock* or emBlocks:EmphasisBlock* or iBlocks:ItalicsBlock* or aBlocks:UnderlineBlock* or imgBlocks:ImageBlock*; description: (* The pool of blocks in the source within W3C compliant HTML tags. Only the most commonly used HTML tag blocks are specified. There are many more. Refer to W3C for details. *); end HTML; object EclassML is components: slideBreaks:SlideBreak* or slideTitles:SlideTitle* or seqBlocks:SequenceBlock* or siBlocks:SequenceItemBlock* or hideBlocks:HideBlock* or repBlocks:ReplaceBlock* or subsBlocks:SubstitutionBlock* or selectBlocks:SelectBlock*; description: (* The pool of blocks in the source within EclassML tags. *); end EclassML; object StartTag is string and startIndex:StartIndex and endIndex:EndIndex; object EndTag is string and startIndex:StartIndex and endIndex:EndIndex; (* Tags do not have position information since they do not appear in the Slides window. *) object TitleBlock is components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex; description: (* A TitleBlock is anything within HTML title tags. TitleBlocks have no size or positioning information because titles normally appear on the title bar of the browser window rather than in the document itself. *); end TitleBlock; object ParagraphBlock is components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and endPos:EndPosition and size:Size; description: (* A ParagraphBlock is anything within HTML paragraph tags. *); end ParagraphBlock; object LineBreak is components: startTag:StartTag and startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and endPos:EndPosition and size:Size; description: (* A LineBreak corresponds to a single HTML break tag, hence no endTag. *); end LineBreak; object IndentBlock is components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and endPos:EndPosition and size:Size; description: (* An IndentBlock is anything within HTML block quote tags. *); end IndentBlock; object Heading1Block is components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and endPos:EndPosition and size:Size; description: (* A Heading1Block is anything within HTML h1 tags. *); end Heading1Block; object Heading2Block is components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and endPos:EndPosition and size:Size; description: (* A Heading1Block is anything within HTML h2 tags. *); end Heading2Block; object Heading3Block is components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and endPos:EndPosition and size:Size; description: (* A Heading1Block is anything within HTML h3 tags. *); end Heading3Block; object Heading4Block is components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and endPos:EndPosition and size:Size; description: (* A Heading1Block is anything within HTML h4 tags. *); end Heading4Block; object Heading5Block is components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and endPos:EndPosition and size:Size; description: (* A Heading1Block is anything within HTML h5 tags. *); end Heading5Block; object Heading6Block is components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and endPos:EndPosition and size:Size; description: (* A Heading1Block is anything within HTML h6 tags. *); end Heading6Block; object UnorderedListBlock is components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and endPos:EndPosition and size:Size; description: (* An UnorderedListBlock is anything within HTML unordered list tags. *); end UnorderedListBlock; object OrderedListBlock is components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and endPos:EndPosition and size:Size; description: (* An OrderedListBlock is anything within HTML ordered list tags. *); end OrderedListBlock; object DefinitionListBlock is components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and endPos:EndPosition and size:Size; description: (* An DefinitionListBlock is anything within HTML definition list tags. *); end DefinitionListBlock; object ListItemBlock is components: startTag:StartTag and startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and endPos:EndPosition and size:Size; description: (* Since line items do not employ endTags, a ListItemBlock can be anything between and HTML list item start tag and the next list item start tag. In the case of the last item in a list, the next list item tag is replaced by the closing unordered, ordered or definition list endTag. *); end ListItemBlock; object EmphasisBlock is components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and endPos:EndPosition and size:Size; description: (* An EmphasisBlock is anything within HTML emphasis tags. *); end EmphasisBlock; object ItalicsBlock is components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and endPos:EndPosition and size:Size; description: (* An ItalicsBlock is anything within HTML italics tags. *); end ItalicsBlock; object UnderlineBlock is components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and endPos:EndPosition and size:Size; description: (* An UnderlineBlock is anything within HTML 'a' tags which are normally used for hypertext links. The default is not to link to anything so the 'a' tags are used solely for underlining unless the instructor edits the starTag manually. *); end UnderlineBlock; object ImageBlock is components: startTag:StartTag and startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and endPos:EndPosition and size:Size; description: (* An ImageBlock is an HTML image tag which contains a 'src' attribute pointing to the location of the image file. Other attributes such as width, height and alignment can also be specified within the image tag. *); end ImageBlock; object SlideTitle is components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex; description: (* SlideTitle is the EclassML representation of Slide.name. SlideTitles have no size or positioning information becuase they do not appear in the Slides window. They only appear in the Outline windown as headers for each Slide. *); end SlideTitle; object SlideBreak is components: startTag:StartTag and startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and endPos:EndPosition and size:Size; description: (* A SlideBreak corresponds to a single EclassML slidebreak tag, hence no EndTag. *); end Slidebreak; object SequenceBlock is components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and endPos:EndPosition and numberingType:NumberingType and expanded:Expanded and collapsed:Collapsed and size:Size; description: (* SequenceTags are similar to the Ordered List tags in HTML. They are used to define lecture content hierarchically. Eclass uses these hierarchical sequence structures to display lecture content in outline format and to implement expand and collapse. The NumberingType corresponds to HTML's numbering conventions for ordered list types (ie. arabic numbers, upper case alphabetial, lower case roman numerals, etc). *); end SequenceBlock; object NumberingType is string; object Expanded is boolean; object Collapsed is boolean; object SequenceItemBlock is components: startTag:StartTag and startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and endPos:EndPosition and size:Size and lastClicked:LastClicked; description: (* SequenceItems are just like LineItems in HTML ordered lists. Notice the EndTag is omitted. *); end SequenceItemBlock; object LastClicked is boolean; object SelectBlock is components: startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and endPos:EndPosition and size:Size; description: (* SelectBlocks are all the HTML and EclassML that is not within HideBlocks hence the omission of start and endTags. Characters within SelectBlocks appear as regular text in the Outline and Slides windows. *); end SelectBlock; object HideBlock is components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and endPos:EndPosition and size:Size; description: (* HideBlocks appear highlighted in yellow within the Outline window. Hideblocks do not appear in the Slides window. In theory, the size and positioning fields aren't necessary since HideBlocks never appear in the Slides window but this information is kept in case the hide tags are removed. *); end HideBlock; object ReplaceBlock is components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and endPos:EndPosition and size:Size; description: (* ReplaceBlocks appear highlighted in blue within the Outline window. ReplaceBlocks do not appear in the Slides window but their corresponding SubstitutionBlocks do. In theory, the size and positioning fields aren't necessary since ReplaceBlocks never appear in the Slides window but this information is kept in case the replace tags are removed.*); end ReplaceBlock; object SubstitutionBlock is components: startTag:StartTag and endTag:EndTag and startIndex:StartIndex and endIndex:EndIndex and startPos:StartPosition and endPos:EndPosition and size:Size; description: (* SubstitutionBlocks appear highlighted in green within the Outline window. They appear in the Slides window in place of their corresponding ReplaceBlocks. *); end SubstitutionBlock; object Scope is integer*; object SlideSetup is components: scope:Scope and margins:Margins and lineHeight:LineHeight and numberOfLines:NumberOfLines and maxSize:MaxSize and scrollable:Scrollable; description: (* Template values every slide must have. Scope is the list of slide numbers the setup applies to. MaxSize represents the maximum amount of space available for a nonscrollable slide. For the purposes of this model each slide is treated as a mapped display or grid with a fixed number of rows and columns dependent on the values of Margins and LineHeight. MaxSize is the total number of grid units a slide can accomodate. This simplification does not take into account the fact that certain character heights require more than one line height to display correctly. It also assumes that images can be treated as blocks of grid units as far as their location on a slide is concerned. *); end SlideSetup; object Margins is components: left:LeftMargin and right:RightMargin and top:TopMargin and bottom:BottomMargin; description: (* Margins measured in inches that determine where lecture content appears on a slide. *); end Margins; object LeftMargin is integer; object RightMargin is integer; object TopMargin is integer; object BottomMargin is integer; object SlideWidth is integer; object SlideHeight is integer; object NumberOfLines is integer; (* The user cannot enter anything in this field. It is calculated automatically by Eclass and provided only for feedback. *) object LineHeight is integer; (* Measured in typographical points. *) object MaxSize is integer; (* MaxSize does not apply to slides that are Scrollable. In the cases where a slide is scrollable the slide's endPoint can exceed actually exceed MaxSize which triggers the addition of a scrollbar on the right edge of the Slides window. *) object Scrollable is boolean; (* Determines whether a slide object AllSlides is Scope; (* Not as simple as might be imagined because existing slide setups must be preserved. AllSlides includes SelectedSlides plus any new slides that are subsequently created. If the user really wants to apply the setup to all the slides he/she must select them all first in the Outline window. *) object ThisSlide is Scope; object SelectedSlides is Scope; (* SelectedSlides are all the slides in the Outline window that have been selected by shift clicking or CTRL-A. *) object GlobalSlideSetup is SlideSetup; (* Scope of GlobalSlideSetup is AllSlides which includes the current selection of slides plus any new slides that are subsequently created.*) object SourcePool is components: hML:HTML and eML:EclassML; description: (* A pool of character string indexes and screen locations for all the HTML and EclassML tagged blocks contained in the Lecture. *); end SourcePool; object SlideVisibles is components: hML:HTML and eML:EclassML; description: (* A pool of character string indexes and screen locations for all the HTML and EclassML tagged blocks that are visible in the Slides window. EclassML Hide and Replace tag blocks never appear in the Slides window. *); end SlideVisibles; object OutlineVisibles is components: hML:HTML and eML:EclassML; description: (* A pool of character string indexes and screen locations for all the HTML and EclassML tagged blocks that are visible in the Outline window. *); end OutlineVisibles; operation ShowSlides is inputs: lect:Lecture, sourcePool:SourcePool, slideVisibles:SlideVisibles, outlineVisibles:OutlineVisibles, setup:GlobalSlideSetup; outputs: lect':Lecture, sourcePool':SourcePool, slideVisibles':SlideVisibles, outlineVisibles':OutlineVisibles; description: (* Illustrates how filtering and expand and collapse work within the Slides window. Postconditions ensure that HideBlocks and ReplaceBlocks do not appear in the Slides window. Postconditions also ensure that only expanded sequences are visible in the Slides window. *); precondition: ; postcondition: ( forall (slct in sourcePool.eML.selectBlocks) (slct in slideVisibles'.eML.selectBlocks) (* SelectBlocks appear in the Slides window. SelectBlocks are everything that is not within EclassML hide tags. *) and forall (sub in sourcePool.eML.subsBlocks) (sub in slideVisibles'.eML.subsBlocks) (* SubstitutionBlocks appear in the Slides window. Substitution blocks are meant to replace the ReplaceBlocks that appear in the Outline window. *) and forall (seq in sourcePool.eML.seqBlocks) ((seq in slideVisibles'.eML.seqBlocks) iff (seq.expanded = true)) (* If SequenceBlock is still in slideVisibles and SequenceBlock is expanded then the SequenceBlock appears in the Slides window. *) and forall (hb in sourcePool.eML.hideBlocks) (not (hb in slideVisibles'.eML.hideBlocks)) (* HideBlocks are filtered from the Slides window. *) and forall (rb in sourcePool.eML.repBlocks) (not (rb in slideVisibles'.eML.repBlocks)) (* ReplaceBlocks are filtered from the Slides window. *) and RecalcSlideBreaks(lect, sourcePool', slideVisibles', outlineVisibles', setup) (* If any SlideBreaks need to be adjusted they should be adjusted in the sourcePool, and outlineVisibles as well as slideVisibles. *) ); end ShowSlides; function DeleteSlides(lect:Lecture, startIndex:StartIndex, endIndex:EndIndex) = (forall (slide:Slide) ( (slide in lect.slides) iff ((slide.data.endIndex < startIndex) or (slide.data.startIndex > endIndex)) ) (* Slides whose data lies between the start and endIndex parameters are excluded from lect.slides. *) ); function Slidify(lect:Lecture, slideToExpand:Slide, sourcePool:SourcePool, slideVisibles:SlideVisibles, outlineVisibles:OutlineVisibles, setup:SlideSetup) = ( exists (offset:integer) (offset = (slideToExpand.data.endPos - slideToExpand.data.maxPos) / setup.maxSize) (* The offset in grid units is calculated by subtracting slideToExpand maxPos from slideToExpand endPos. This will not produce a negative value since endPos being larger than maxPos is a precondition for this function. The difference between endPos and maxPos is then divided by setup.maxSize to get the number of slides to be inserted. *) and forall (i:integer | (i > slideToExpand.number) and (i <= #(lect.slides))) (lect.slides[i + offset] = lect.slides[i]) (* All the existing slides after the slideToExpand need to be shifted over to make room for the new ones. The start and endPositions of all the tag blocks affected need to be increased by the difference between slideToExpand.endPos and slideToExpand.maxPos. *) and forall (i:integer | (i > slideToExpand.number) and (i <= slideToExpand.number + offset)) ( (* New Slides must be generated to fill the space left by shifting the existing slides. Every new slide is maxSize by default so it's start and endPos can be derived using simple arithmetic. *) (* To derive each new Slide's start and endIndexes the tag block with the highest endPos in the new Slide's data must be identified and its endIndex retrieved. A SlideBreak must then be inserted after that tag block. The endIndex of that SlideBreak becomes the endIndex of the new Slide. Adding one to that gives us the startIndex of the next new Slide and so on. No new changes need to be made to new Slide's start and endPos each time a SlideBreak is added because SlideBreaks don't take up any space in the Slides window. *) ) ); (* End Slidify. *) function RecalcSlideBreaks(lect:Lecture, srcPool:SourcePool, slideVisibles:SlideVisibles, outlineVisibles:OutlineVisibles, setup:GlobalSlideSetup) = true; (* Eclass uses data from SlideVisibles, GlobalSlideSetup and any individual SlideSetups to calculate where to place SlideBreaks. When a SlideBreak is moved or inserted the data for all the affected Slides needs to be updated along with the slides and currentSlide components of Lecture. Changes in the locations of prexisting SlideBreaks as well as the creation of any new SlideBreaks must also be reflected in the SourcePool, SlideVisibles and OutlineVisibles. *) end LectureDB;