Lexi Case Study A WYSIWYG document editor.

Slides:



Advertisements
Similar presentations
[Course Title] [Module Title]
Advertisements

GoF Sections 2.7 – 2.9 More Fun with Lexi. Lexi Document Editor Lexi tasks discussed:  Document structure  Formatting  Embellishing the user interface.
Linzhang Wang Dept. of Computer Sci&Tech, Nanjing University The Bridge Pattern.
Design Patterns Copyright © Vyacheslav Mukhortov, Nikita Nyanchuk-Tatarskiy, Copyright © INTEKS LLC,
Iterators T.J. Niglio Computer & Systems Engineering Fall 2003 Software Design & Documentation Object Behavioral.
GoF: Document Editor Example
Design Patterns David Talby. This Lecture n Representing Data Structures u Composite, Flyweight, Decorator n Traversing Data Structures u Iterator, Visitor.
Adapted from Prof. Necula CS 169, Berkeley1 Design Patterns V Software Engineering Lecture 9, Spring 2006 Clark Barrett, New York University.
Design Patterns David Talby. This Lecture n Patterns for a User Interface u Representing a Document F Composite, Flyweight, Decorator u Writing Portable.
GoF: Document Editor Example A Case Study.
User Interface Design: Methods of Interaction. Accepted design principles Interface design needs to consider the following issues: 1. Visual clarity 2.
Design Patterns. CS351 - Software Engineering (AY2007)Slide 2 Behavioral patterns Suppose we have an aggregate data structure and we wish to access the.
Basic Design Patterns 2. Designing a Document Editor Gabriel Mañana Ed. 453 Of. 120 Ext unal.edu.co.
Software Design and Documentation Individual Presentation: Composite Pattern 9/11/03.
Design Patterns Based on Design Patterns. Elements of Reusable Object-Oriented Software. by E.Gamma, R. Helm, R. Johnson,J. Vlissides.
The Composite Pattern.. Composite Pattern Intent –Compose objects into tree structures to represent part-whole hierarchies. –Composite lets clients treat.
Lecture 4: More UML Diagrams, Patterns MISM Summer 2001.
Object-Oriented Analysis and Design
GoF Sections 2.7 – 2.9 More Fun with Lexi. Lexi Document Editor Lexi tasks discussed:  Document structure  Formatting  Embellishing the user interface.
Copyright © Active Frameworks Inc. - All Rights Reserved - V2.0Document Editor - Page L2-5 PS95&96-MEF-L9-5 Dr. M.E. Fayad  Document Structure.
Lecture 4: More UML Diagrams, Patterns MISM/MSIT Fall 2001.
ECE450 - Software Engineering II1 ECE450 – Software Engineering II Today: Design Patterns VI Composite, Iterator, and Visitor Patterns.
© 2008 Hewlett-Packard Development Company, L.P. The information contained herein is subject to change without notice Design Patterns Case Study: Designing.
More OOP Design Patterns
1 An introduction to design patterns Based on material produced by John Vlissides and Douglas C. Schmidt.
Composite Design Pattern. Motivation – Dynamic Structure.
Linzhang Wang Dept. of Computer Sci&Tech, Nanjing University The Composit Pattern.
BDP Behavioral Pattern. BDP-2 Behavioral Patters Concerned with algorithms & assignment of responsibilities Patterns of Communication between Objects.
Design Patterns and Graphical User Interfaces Horstmann ,
UNIT-II1 Chapter-II A Case Study: Designing a Document Editor:
Prof. Aiken CS 169 Lecture 51 Design Patterns CS169 Lecture 5.
05 - Patterns Intro.CSC4071 Design Patterns Designing good and reusable OO software is hard. –Mix of specific + general –Impossible to get it right the.
Design a Document Editor Oksana Protsyk Yaroslav Kaplunskiy.
A Case Study: Designing a Document Editor “ Lexi ”
Lexi case study (Part 2) Presentation by Matt Deckard.
Design Patterns Gang Qian Department of Computer Science University of Central Oklahoma.
Chapter 38 Persistence Framework with Patterns 1CS6359 Fall 2011 John Cole.
GoF: Document Editor Example Rebecca Miller-Webster.
CSE 403 Lecture 14 Design Patterns. Today’s educational objective Understand the basics of design patterns Be able to distinguish them from design approaches.
Design Patterns CS 124 Reference: Gamma et al (“Gang-of-4”), Design Patterns.
1 Lexi Case Study A WYSIWYG document editor. Mix text and graphics freely in various formatting styles. The usual –Pull-down menus –Scroll bars –Page.
Structural Design Patterns
Linzhang Wang Dept. of Computer Sci&Tech, Nanjing University The Command Pattern.
08 - StructuralCSC4071 Structural Patterns concerned with how classes and objects are composed to form larger structures –Adapter interface converter Bridge.
Structural Patterns1 Nour El Kadri SEG 3202 Software Design and Architecture Notes based on U of T Design Patterns class.
STAT 598W Lecture 18 Design Patterns. A "hot topic" in O-O research Started by the book Design Patterns: Elements of Reusable Object-Oriented Software.
Linzhang Wang Dept. of Computer Sci&Tech, Nanjing University The Strategy Pattern.
OO Methodology Elaboration Iteration 2 - Design Patterns -
Behavioral Patterns CSE301 University of Sunderland Harry R Erwin, PhD.
BEHAVIORAL PATTERNS 13-Sep-2012 Presenters Sanjeeb Kumar Nanda & Shankar Gogada.
CS212: Object Oriented Analysis and Design Lecture 39: Design Pattern-III.
Chapter 5 Introduction To Form Builder. Lesson A Objectives  Display Forms Builder forms in a Web browser  Use a data block form to view, insert, update,
Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.
1 Classes II Chapter 7 2 Introduction Continued study of –classes –data abstraction Prepare for operator overloading in next chapter Work with strings.
Example to motivate discussion We have two lists (of menu items) one implemented using ArrayList and another using Arrays. How does one work with these.
CS 5150 Software Engineering Lecture 16 Program Design 3.
Design Patterns. Outline Purpose Purpose Useful Definitions Useful Definitions Pattern Overview Pattern Overview.
Copyright © 2012 Pearson Education, Inc. Chapter 10 Advanced Topics.
CLASSIFICATION OF DESIGN PATTERNS Hladchuk Maksym.
Command Pattern. Intent encapsulate a request as an object  can parameterize clients with different requests, queue or log requests, support undoable.
Chapter 10 Design Patterns.
Case Study 1: Designing a Document Editor
Behavioral Design Patterns
Design Patterns (cont.) and Coding
Chapter-II A Case Study:
Design Patterns, conclusion
Design Patterns A Case Study: Designing a Document Editor
Jim Fawcett CSE776 – Design Patterns Summer 2003
PH Chapter 3 Thanks for the Memory Leaks Pushme-Pullyu (pp
A Case Study: Designing a Document Editor
Presentation transcript:

Lexi Case Study A WYSIWYG document editor. Mix text and graphics freely in various formatting styles. The usual Pull-down menus Scroll bars Page icons for jumping around the document. Going through the design, we will see many patterns in action. History: Ph.D. thesis of Paul Calder (s. Mark Linton) 1993 LEXI CmpE196G

Document Structure A hierarchical arrangement of shapes. Viewed as lines, columns, figures, tables, … UI should allow manipulations as a group E.g. refer to a table as a whole Internal representation should support Maintaining the physical structure Generating and presenting the visuals Reverse mapping positions to elements Want to treat text and graphics uniformly No distinction between single elements or groups. E.g. the 10th element in line 5 could be an atomic character, or a complex figure comprising nested sub-parts. LEXI CmpE196G

Recursive Composition Building more complex elements out of simpler ones. Implications: Each object type needs a corresponding class All must have compatible interfaces (inheritance) Performance issues. LEXI CmpE196G

Glyph Class An Abstract class for all objects that can appear in a document. Both primitive and composed. Composite LEXI CmpE196G

Glyph Interface and responsibilities public abstract class Glyph { // appearance public abstract void draw(Window w); public abstract Rect getBounds(); // hit detection public abstract boolean intersects(Point); // structure public abstract void insert(Glyph g, int i); public abstract void remove(Glyph g); public abstract Glyph child(int i); public abstract Glyph parent(); } Glyphs know how to draw themselves Glyphs know what space they occupy Glyphs know their children and parents LEXI CmpE196G

Formatting Breaking up a document into lines. Many different algorithms trade off quality for speed Complex algorithms Want to keep the formatting algorithm well-encapsulated. independent of the document structure can add formatting algorithm without modifying Glyphs can add Glyphs without modifying the formatting algorithm. Want to make it dynamically changeable. LEXI CmpE196G

Composition & Compositor Initially, an unformatted Composition object contains only the visible child Glyphs. After running a Compositor, it will also contain invisible, structural glyphs that define the format. LEXI CmpE196G

Compositor & Composition Compositor class will encapsulate a formatting algorithm. Glyphs it formats are all children of Composition Strategy LEXI CmpE196G

Embellishments Wish to add visible borders and scroll-bars around pages. Inheritance is one way to do it. leads to class proliferation BorderedComposition, ScrollableComposition, BorderedScrollableComposition inflexible at run-time Will have classes Border Scroller They will be Glyphs they are visible clients shouldn’t care if a page has a border or not They will be composed. but in what order? LEXI CmpE196G

Transparent Enclosure single-child composition compatible interfaces Enclosure will delegate operations to single child, but can add state augment by doing work before or after delegating to the child. LEXI CmpE196G

Decorator MonoGlyph Border calls { MonoGlyph.draw(); drawBorder(); } LEXI CmpE196G

Supporting Multiple Window Systems Want the application to be portable across diverse user interface libraries. Every user interface element will be a Glyph. Some will delegate to appropriate platform-specific operations. LEXI CmpE196G

Multiple Look-and-Feel Standards Goal is to make porting to a different windowing system as easy as possible. one obstacle is the diverse look-and-feel standards want to support run-time switching of l&f. Win, Motif, OpenLook, Mac, … Need 2 sets of widget glyph classes abstract ScrollBar, Button, … concrete MotifScrollBar, WinScrollBar, MacScrollBar, MotifButton, … Need indirect instantiation. LEXI CmpE196G

Object Factories Usual method: Factory method: ScrollBar sb = new MotifScrollBar(); Factory method: ScrollBar sb = guiFactory.createScrollBar(); LEXI CmpE196G

Abstract Factory Product Objects The output of a factory is a product. concrete LEXI CmpE196G

Singleton Building the Factory If known at compile time (e.g., Lexi v1.0 – only Motif implemented). GUIFactory guiFactory = new MotifFactory(); Set at startup (Lexi v2.0) String LandF = appProps.getProperty("LandF"); GUIFactory guiFactory; if( LandF.equals("Motif") ) guiFactory = new MotifFactory(); ... Changeable by a menu command (Lexi v3.0) re-initialize ‘guiFactory’ re-build the UI Singleton LEXI CmpE196G

Multiple GUI Libraries Can we apply Abstract Factory? Each GUI library will define its own concrete classes. Cannot have them all inherit from a common, abstract base. but, all have common principles Start with an abstract Window hierarchy (does not depend on GUI library) LEXI CmpE196G

Window Implementations Defined interface Lexi deals with, but where does the real windowing library come into it? Could define alternate Window classes & subclasses. At build time can substitute the appropriate one Could subclass the Window hierarchy. Or … Bridge LEXI CmpE196G

Window Implementation Code Sample public class Rectangle extends Glyph { public void draw(Window w) { w.drawRect(x0,y0,x1,y1); } ... } public class Window { public void drawRect(Coord x0,y0,x1,y1) { imp.drawRect(x0,y0,x1,y1); public class XWindowImp extends WindowImp { XDrawRectangle(display, windowId, graphics, x,y,w,h); LEXI CmpE196G

Abstract Factory Configuring ‘imp’ public abstract class WindowSystemFactory { public abstract WindowImp createWindowImp(); public abstract ColorImp createColorImp(); ... } public class XWindowSystemFactory extends WindowSystemFactory { public WIndowImp createWindowImp() { return new XWindowImp(); public class Window { Window() { imp = windowSystemFactory.createWindowImp(); Abstract Factory well-known object LEXI CmpE196G

XWindowSystemFactory Recap Glyph WindowSystemFactory XWindowSystemFactory 1 Rectangle uses uses Window WindowImp XWindowImp imp uses instantiates LEXI CmpE196G

User Operations Operations UI mechanisms create new, save, cut, paste, quit, … UI mechanisms mousing & typing in the document pull-down menus, pop-up menus, buttons, kbd accelerators, … Wish to de-couple operations from UI mechanism re-use same mechanism for many operations re-use same operation by many mechanisms Operations have many different classes wish to de-couple knowledge of these classes from the UI Wish to support multi-level undo and redo LEXI CmpE196G

Commands A button or a pull-down menu is just a Glyph. Could… Will… but have actions command associated with user input e.g., MenuItem extends Glyph, Button extends Glyph, … Could… PageFwdMenuItem extends MenuItem PageFwdButton extends Button Have a MenuItem attribute which is a function call. Will… Have a MenuItem attribute which is a command object. LEXI CmpE196G

Command Hierarchy Command is an abstract class for issuing requests. LEXI CmpE196G

Command Invoking Commands When an interactive Glyph is tickled, it calls the Command object with which it has been initialized. Command LEXI CmpE196G

Undo/Redo Add an unexecute() method to Command Reverses the effects of a preceding execute() operation using whatever undo information execute() stored into the Command object. Add a isUndoable() and a hadnoEffect() method Maintain Command history: LEXI CmpE196G

Spell Checking & Hyphenation Textual analysis checking for misspellings introducing hyphenation points where needed for good formatting. Want to support multiple algorithms. Want to make it easy to add new algorithms. Want to make it easy to add new types of textual analysis word count grammar legibility Wish to de-couple textual analysis from the Glyph classes. LEXI CmpE196G

Accessing Scattered Information Need to access the text letter-by-letter. Our design has text scattered all over the Glyph hierarchy. Different Glyphs have different data structures for storing their children (lists, trees, arrays, …). Sometimes need alternate access patterns: spell check: forward search back: backwards evaluating equations: inorder tree traversal LEXI CmpE196G

Encapsulating Access & Traversals Could replace index-oriented access (as shown before) by more general accessors that aren’t biased towards arrays. Glyph g = … for(g.first(PREORDER); !g.done(); g->next()) { Glyph current = g->getCurrent(); … } Problems: can’t support new traversals without extending enum and modifying all parent Glyph types. Can’t re-use code to traverse other object structures (e.g., Command history). LEXI CmpE196G

Iterator Hierarchy Iterator LEXI CmpE196G

Using Iterators Glyph* g; Iterator<Glyph*>* i = g->CreateIterator(); for (i->First(); !i->IsDone(); i->Next()) { Glyph* child = i->CurrentItem(); // do something with current child } LEXI CmpE196G

Initializing Iterators Iterator<Glyph*>* Row::CreateIterator () { return new ListIterator<Glyph*>(_children); } LEXI CmpE196G

Pre-order Iterator root 1 2 6 3 4 5 LEXI CmpE196G

Approach Will maintain a stack of iterators. Each iterator in the stack will correspond to a level in the tree. The top iterator on the stack will point to the current node We will rely on the ability of leaves to produce “null iterators” (iterators that always return they are done) to make the code more orthogonal. LEXI CmpE196G

Implementing a Complex Iterator void PreorderIterator::First () { Iterator<Glyph*>* i = _root->CreateIterator(); if (i) { i->First(); _iterators.RemoveAll(); _iterators.Push(i); } Glyph* PreorderIterator::CurrentItem () const { return _iterators.Size() > 0 ? _iterators.Top()->CurrentItem() : 0; LEXI CmpE196G

Implementing a Complex Iterator (cont’d) void PreorderIterator::Next () { Iterator<Glyph*>* i = _iterators.Top()->CurrentItem()->CreateIterator(); i->First(); _iterators.Push(i); while ( _iterators.Size() > 0 && _iterators.Top()->IsDone() ) { delete _iterators.Pop(); _iterators.Top()->Next(); } LEXI CmpE196G

Pre-order Iterator i1 void PreorderIterator::Next () { root Pre-order Iterator i1 void PreorderIterator::Next () { Iterator<Glyph*>* i = _iterators.Top()->CurrentItem()->CreateIterator(); i->First(); _iterators.Push(i); while ( _iterators.Size() > 0 && _iterators.Top()->IsDone() ) { delete _iterators.Pop(); _iterators.Top()->Next(); } 1 2 6 i3 3 4 5 i4 Glyph* PreorderIterator::CurrentItem () const { return _iterators.Size() > 0 ? _iterators.Top()->CurrentItem() : 0; } i4 i3 i1 LEXI CmpE196G

Pre-order Iterator i1 void PreorderIterator::Next () { root Pre-order Iterator i1 void PreorderIterator::Next () { Iterator<Glyph*>* i = _iterators.Top()->CurrentItem()->CreateIterator(); i->First(); _iterators.Push(i); while ( _iterators.Size() > 0 && _iterators.Top()->IsDone() ) { delete _iterators.Pop(); _iterators.Top()->Next(); } 1 2 6 i3 3 4 5 Glyph* PreorderIterator::CurrentItem () const { return _iterators.Size() > 0 ? _iterators.Top()->CurrentItem() : 0; } i3 i1 LEXI CmpE196G

Pre-order Iterator i1 void PreorderIterator::Next () { root Pre-order Iterator i1 void PreorderIterator::Next () { Iterator<Glyph*>* i = _iterators.Top()->CurrentItem()->CreateIterator(); i->First(); _iterators.Push(i); while ( _iterators.Size() > 0 && _iterators.Top()->IsDone() ) { delete _iterators.Pop(); _iterators.Top()->Next(); } 1 2 6 i3 3 4 5 Glyph* PreorderIterator::CurrentItem () const { return _iterators.Size() > 0 ? _iterators.Top()->CurrentItem() : 0; } i3 i1 LEXI CmpE196G

Pre-order Iterator i1 void PreorderIterator::Next () { root Pre-order Iterator i1 void PreorderIterator::Next () { Iterator<Glyph*>* i = _iterators.Top()->CurrentItem()->CreateIterator(); i->First(); _iterators.Push(i); while ( _iterators.Size() > 0 && _iterators.Top()->IsDone() ) { delete _iterators.Pop(); _iterators.Top()->Next(); } 1 2 6 i3 3 4 5 i5 Glyph* PreorderIterator::CurrentItem () const { return _iterators.Size() > 0 ? _iterators.Top()->CurrentItem() : 0; } i5 i3 i1 LEXI CmpE196G

Pre-order Iterator i1 void PreorderIterator::Next () { root Pre-order Iterator i1 void PreorderIterator::Next () { Iterator<Glyph*>* i = _iterators.Top()->CurrentItem()->CreateIterator(); i->First(); _iterators.Push(i); while ( _iterators.Size() > 0 && _iterators.Top()->IsDone() ) { delete _iterators.Pop(); _iterators.Top()->Next(); } 1 2 6 i3 3 4 5 Glyph* PreorderIterator::CurrentItem () const { return _iterators.Size() > 0 ? _iterators.Top()->CurrentItem() : 0; } i3 i1 LEXI CmpE196G

Pre-order Iterator i1 void PreorderIterator::Next () { root Pre-order Iterator i1 void PreorderIterator::Next () { Iterator<Glyph*>* i = _iterators.Top()->CurrentItem()->CreateIterator(); i->First(); _iterators.Push(i); while ( _iterators.Size() > 0 && _iterators.Top()->IsDone() ) { delete _iterators.Pop(); _iterators.Top()->Next(); } 1 2 6 i3 3 4 5 Glyph* PreorderIterator::CurrentItem () const { return _iterators.Size() > 0 ? _iterators.Top()->CurrentItem() : 0; } i3 i1 LEXI CmpE196G

Pre-order Iterator i1 void PreorderIterator::Next () { root Pre-order Iterator i1 void PreorderIterator::Next () { Iterator<Glyph*>* i = _iterators.Top()->CurrentItem()->CreateIterator(); i->First(); _iterators.Push(i); while ( _iterators.Size() > 0 && _iterators.Top()->IsDone() ) { delete _iterators.Pop(); _iterators.Top()->Next(); } 1 2 6 3 4 5 Glyph* PreorderIterator::CurrentItem () const { return _iterators.Size() > 0 ? _iterators.Top()->CurrentItem() : 0; } i1 LEXI CmpE196G

Pre-order Iterator i1 void PreorderIterator::Next () { root Pre-order Iterator i1 void PreorderIterator::Next () { Iterator<Glyph*>* i = _iterators.Top()->CurrentItem()->CreateIterator(); i->First(); _iterators.Push(i); while ( _iterators.Size() > 0 && _iterators.Top()->IsDone() ) { delete _iterators.Pop(); _iterators.Top()->Next(); } 1 2 6 3 4 5 Glyph* PreorderIterator::CurrentItem () const { return _iterators.Size() > 0 ? _iterators.Top()->CurrentItem() : 0; } i1 LEXI CmpE196G

Traversal Actions Now that we can traverse, we need to add actions while traversing that have state spelling, hyphenation, … Could augment the Iterator classes… …but that would reduce their reusability Could augment the Glyph classes… …but will need to change Glyph classes for each new analysis Will need to encapsulate the analysis in a separate object LEXI CmpE196G

Actions in Iterators Iterator will carry the analysis object along with it as it iterates. The analyzer will accumulate state. e.g., characters for a spell check LEXI CmpE196G

Avoiding Downcasts How can the analysis object distinguish different kinds of Glyphs without resorting to switch statements and downcasts. e.g., avoid: public class SpellingChecker extends … { public void check(Glyph g) { if( g instanceof CharacterGlyph ) { CharacterGlyph cg = (CharacterGlyph)g; // analyze the character } else if( g instanceof RowGlyph ) { rowGlyph rg = (RowGlyph)g; // prepare to analyze the child glyphs } else … } LEXI CmpE196G

Accepting Visitors public abstract class Glyph { public abstract void accept(Visitor v); … } public class CharacterGlyph extends Glyph { public void accept(Visitor v) { v.visitCharacterGlyph(this); LEXI CmpE196G

Visitor Visitor & Subclasses public abstract class Visitor { public void visitCharacterGlyph(CharacterGlyph cg) { /* do nothing */ } public abstract void visitRowGlyph(RowGlyph rg); … } public class SpellingVisitor extends Visitor { public void visitCharacterGlyph(CharacterGlyph cg) { Visitor LEXI CmpE196G

SpellingVisitor public class SpellingVisitor extends Visitor { private Vector misspellings = new Vector(); private String currentWord = “”; public void visitCharacterGlyph(CharacterGlyph cg) { char c = cg->getChar(); if( isalpha(c) ) { currentWord += c; } else { if( isMispelled(currentWord) ) { // add misspelling to list misspelling.addElement(currentWord); } currentWord = “”; public Vector getMisspellings { return misspellings; … LEXI CmpE196G

Using SpellingVisitor PreorderIterator i = new PreorderIterator(); i.setVisitor(new SpellingVisitor()); i.visitAll(rootGlyph); Vector misspellings = ((SpellingVisitor)i.getVisistor()).getMisspellings(); public class Iterator { private Visitor v; public void visitAll(Glyph start) { for(first(); !isDone(); next()) { currentItem().visit(v); } … LEXI CmpE196G

Visitor Activity Diagram CharacterGlyph(‘a’) CharacterGlyph(‘ ’) spell:SpellingVisitor visit(spell) visitCharacterGlyph(this) getChar() visit(spell) visitCharacterGlyph(this) getChar() isMispelled(currentWord) getMisspellings() LEXI CmpE196G

HyphenationVisitor Visit words, and then insert “discretionary hyphen” Glyphs. LEXI CmpE196G

Summary In the design of LEXI, saw the following patterns. Composite represent physical structure Strategy to allow different formatting algorithms Decorator to embellish the UI Abstract Factory for supporting multiple L&F standards Bridge for supporting multiple windowing platforms Command for undoable operations Iterator for traversing object structures Visitor for allowing open-ended analytical capabilities without complicating the document structure LEXI CmpE196G