# Iteration 3 aanpak
- multiple displays
- resize events
- event catchen en deelop() oproepen?
- directory views and opening files
- JSON-as-file-system
# Presentatie voorbereiding
- Verdeling:
- Edouard: GRASP over Files, File, Cursor, Buffer + tests
- Victor: GRASP over alles van tree + tests
- Maxim: GRASP over Inputhandler, write, draw, terminalapp +tests
- Cas: sequence diagrams + tests suites
# guisseppe vragen
- moeten interfaces getest worden?
# guisseppe commentaar
- decouple the ui and view nog meer
-> remove link between view and ui
-> does observer really solves problems around coupling and cohesion?
~~- viewtree:
node: children moet een list worden
viewnode should not have children~~
- checking type of object is not good pratice!
# opgave
The main part of the presentation should cover the design. The motivation of
your design decisions must be explained in terms of GRASP principles. Use the
appropriate design diagrams to illustrate how the most important parts of your
software work. Your presentation should cover the following elements. Note that
these are not necessarily all separate sections in the presentation.
1. A discussion of the high level design of the software (use GRASP patterns).
Give a rationale for all the important design decisions your team has made.
2. A more detailed discussion of the parts that you think are the most interest-
ing in terms of design (use GRASP patterns). Again we expect a rationale
here for the important design decisions.
3. A discussion of the testing approach used in the current iteration.
4. An overview of the project management. Give an approximation of how
many hours each team member worked. Use the following categories: group
work, individual work, and study (excluding the classes and exercise ses-
sions). In addition, insert a slide that describes the roles of the team mem-
bers of the current iteration, and the roles for the next iteration. Note that
these slides do not have to be presented, but we need the information.
Your presentation should not consist of slides filled with text, but of slides
with clear design diagrams and keywords or a few short sentences. The goal
of giving a presentation is to communicate a message, not to write a novel. All
design diagrams should be clearly readable and use the correct UML notation. It is
therefore typically a bad idea to create a single class diagram with all information.
Instead, you can for example use an overview class diagram with only the most
important classes, and use more detailed class diagrams to document specific parts
of the system. Similarly, use appropriate interaction diagrams to illustrate the
working of the most important (or complex) parts of the system.
**vragen** voor Guiseppe:
//- trekken onze sequence diagrams (en klassediagram) op iets?
//- wanneer gaat verdediging zijn?
- inleveren: javadoc, diagrams, src-folder, **system.jar**?, (design.pdf)
- moeten we kant en klare GRASP uitleg hebben?
//- "*The number of files specified shall not be greater than the vertical size of the terminal text area (in characters) divided by two.*" Dees kan toch ni?!
//- case 5 alternative cases active
//- tereminal parser geript van Bart, is dat ok? indien ja, moet die dan in een aparte class of ni? (miss kan die mee in de algemene handler)
//- wat als statusbar niet past?
notes bij meeting:
- user mag geen activation bar hebben
- use case 4 filebuffer activation bar ends after saveinfile, how?
- system seq is user system interaction
- andere seq diagram is effectief met classes, we need to show everything, go more into detail, use entry point action from user as a given to start interaction
- rotate functionaliteit moet aangepast worden
to do:
- zorgen dat ons class diagram overeenkomt met de code
- sequence en class diagram fixen -> zie mail guiseppe
Tegen maandag
3) onderste scrollbar (optioneel)
4) Documentatie
5) Encapsulation enz (OGP)
8) rotate layout (victor)
10) default line seperator and flags
11) starten met minstens 1 file en max size_text_area/2
13) tests + defensive approach (throwing Exceptions etc)
mail Guiseppe
Hi all,
I will provide some tips regarding UML notation. For a discussion about your design, we
can organize a meeting early next week.
In the next points I will reference pages of the Larman book.
- In you sequence diagrams, you are modeling both the interaction between external actors
and the system, and the internal chain of events and messages exchanged by the software
components following a request. You can use system sequence diagrams (page 175) to show
the external actors, the events, and the generated output. So, you focus only on the
dynamic behavior of the objects in the related sequence diagram of a use case (page 224).
- Make sure to align the activation bars for method with the actual lifespan of the
method call (usually, they do not start before a method is called, nor finish after a
method returns).
- Return arrows are usually dotted, while method calls are continuous, try to be
consistent. Also, returning a value should not look like a method call.
- Be careful when you have method calls that go back and forth in between classes. This
is a sign of high coupling. In good design, method calls go typically (not always) point
to the right while values are returned the opposite direction.
- I assume Textr is the same as Main in your class diagram (?) Ask yourself how many
responsibilities you are currently assigning to this class.
- Your composite relationship between main and layout is confusing. Do you want to say
that Layout can only be a part of Main?
Best,
Giuseppe
# GRASP
- **Information expert** (also expert or the expert principle) is a principle used to determine where to delegate responsibilities such as methods, computed fields, and so on.
Using the principle of information expert, a general approach to assigning responsibilities is to look at a given responsibility, determine the information needed to fulfill it, and then determine where that information is stored.
This will lead to placing the responsibility on the class with the most information required to fulfill it.
*Related Pattern or Principle: Low Coupling, High Cohesion*
- **Creator**
Which class is responsible for creating objects is a fundamental property of the relationship between objects of particular classes.
Problem: Who creates object A?
Solution: In general, Assign class B the responsibility to create object A if one, or preferably more, of the following apply:
- Instances of B contain or compositely aggregate instances of A
- Instances of B record instances of A
- Instances of B closely use instances of A
- Instances of B have the initializing information for instances of A and pass it on creation.
*Related Pattern or Principle: Low Coupling, Factory Pattern*
- **Controller**
The controller pattern assigns the responsibility of dealing with system events to a non-UI class that represents the overall system or a use case scenario. A controller object is a non-user interface object responsible for receiving or handling a system event.
Problem: Who should be responsible for handling an input system event?
Solution: A use case controller should be used to deal with all system events of a use case, and may be used for more than one use case. For instance, for the use cases Create User and Delete User, one can have a single class called UserController, instead of two separate use case controllers. Alternatively a facade controller would be used; this applies when the object with responsibility for handling the event represents the overall system or a root object.
The controller is defined as the first object beyond the UI layer that receives and coordinates ("controls") a system operation. The controller should delegate the work that needs to be done to other objects; it coordinates or controls the activity. It should not do much work itself. The GRASP Controller can be thought of as being a part of the application/service layer (assuming that the application has made an explicit distinction between the application/service layer and the domain layer) in an object-oriented system with common layers in an information system logical architecture.
*Related Pattern or Principle: Command, Facade, Layers, Pure Fabrication*
- **Indirection**
The indirection pattern supports low coupling and reuses potential between two elements by assigning the responsibility of mediation between them to an intermediate object. An example of this is the introduction of a controller component for mediation between data (model) and its representation (view) in the model-view-controller pattern. This ensures that coupling between them remains low.
Problem: Where to assign responsibility, to avoid direct coupling between two (or more) things? How to de-couple objects so that low coupling is supported and reuse potential remains higher?
Solution: Assign the responsibility to an intermediate object to mediate between other components or services so that they are not directly coupled.
The intermediary creates an indirection between the other components.
*Related Pattern or Principle: Controller*
- **Low Coupling**
Coupling is a measure of how strongly one element is connected to, has knowledge of, or relies on other elements. Low coupling is an evaluative pattern that dictates how to assign responsibilities for the following benefits:
- lower dependency between the classes,
- change in one class having a lower impact on other classes,
- higher reuse potential.
- **High cohesion** is an evaluative pattern that attempts to keep objects appropriately focused, manageable and understandable. High cohesion is generally used in support of low coupling.
High cohesion means that the responsibilities of a given set of elements are strongly related and highly focused on a rather specific topic. Breaking programs into classes and subsystems, if correctly done, is an example of activities that increase the cohesive properties of named classes and subsystems.
Alternatively, low cohesion is a situation in which a set of elements, of e.g., a subsystem, has too many unrelated responsibilities. Subsystems with low cohesion between their constituent elements often suffer from being hard to comprehend, reuse, maintain and change as a whole.
- **Polymorphism**
According to the polymorphism principle, responsibility for defining the variation of behaviors based on type is assigned to the type for which this variation happens. This is achieved using polymorphic operations. The user of the type should use polymorphic operations instead of explicit branching based on type.
Problem: How to handle alternatives based on type? How to create pluggable software components?
Solution: When related alternatives or behaviors vary by type (class), assign responsibility for the behavior—using polymorphic operations—to the types for which the behavior varies. (Polymorphism has several related meanings. In this context, it means "giving the same name to services in different objects".)
- **Protected Variations**
The protected variations pattern protects elements from the variations on other elements (objects, systems, subsystems) by wrapping the focus of instability with an interface and using polymorphism to create various implementations of this interface.
Problem: How to design objects, subsystems, and systems so that the variations or instability in these elements do not have an undesirable impact on other elements?
Solution: Identify points of predicted variation or instability; assign responsibilities to create a stable interface around them.
- **Pure fabrication**
A pure fabrication is a class that does not represent a concept in the problem domain, specially made up to achieve low coupling, high cohesion, and the reuse potential thereof derived (when a solution presented by the information expert pattern does not). This kind of class is called a "service" in domain-driven design.
*Related Patterns and Principles: Low Coupling, High Cohesion.*
# Sequence diagrams
**plant uml code use case 1: hey Victor dit is klaar**
MAIN
@startuml
actor User
participant ":Terminalapp" as Terminalapp
participant ":Inputhandler" as Inputhandler
participant ":Files" as Files
participant ":File" as FileBuffer
participant ":ViewTree" as ViewTree
participant ":Buffer" as Buffer
User -> Terminalapp: launch(filepaths)
activate Terminalapp
Terminalapp -> Terminalapp: getTerminalSize()
Terminalapp -> Terminalapp: check_for_flags(filepaths)
Terminalapp -> Inputhandler: run(filepaths)
activate Inputhandler
alt valid file
Inputhandler -> Files: new Files(filepaths, line separator, terminalsize)
activate Files
Files -> Files: inlezen(filepaths, line separator)
Files -> FileBuffer: new file(file, line separator)
activate FileBuffer
FileBuffer -> FileBuffer: inlezen(file)
FileBuffer -> Buffer: new Buffer(buffer)
activate Buffer
Buffer -> Buffer: setText()
Buffer --> FileBuffer: return Buffer
deactivate Buffer
FileBuffer --> Files: return file
deactivate FileBuffer
Files --> Inputhandler: return files
deactivate Files
Inputhandler -> ViewTree: files.gettree()
activate ViewTree
ViewTree --> Inputhandler: return tree
Inputhandler -> ViewTree: tree.getAllViewNodes().get(0).get_file();
ViewTree --> Inputhandler: return active file
deactivate ViewTree
Inputhandler --> User: display()
else file contains forbidden bytes
Inputhandler -> Files: new Files(files, line separator, terminalsize)
activate Files
Files --> User: exception
deactivate Files
deactivate Inputhandler
deactivate Terminalapp
end
@enduml

**plant uml code use case 2: klaar**
MAIN
@startuml
actor User
participant ":Cursor" as C
participant ":inputhandler" as UI
participant ":viewTree" as V
participant ":viewNode" as N
participant ":File" as F
User -> UI: press Ctrl+P or Ctrl+N
activate UI
UI -> UI: controlP(index,tree) or controlN(index,tree)
activate UI
UI -> V: tree.getAllViewNodes()
activate V
V-->UI: return viewNodes
deactivate V
UI->N: viewNodes.get(index).get_file()
activate N
N-->UI: return file
deactivate N
UI->UI: change Active
UI-->UI: return index
deactivate UI
UI -> F: active.getCursor().getLine() and active.getCursor().getColumn()
activate F
F->UI: return line and column
deactivate F
UI->UI: moveCursor(line,column)
UI-->User: display moved cursor
User -> UI: presses arrow key
UI -> UI: arrowDirection(myFiles)
activate UI
UI->F: active.getCursor()
activate F
F-->UI: return cursor
deactivate F
UI->C: cursor.moveDirection()
activate C
C->F: getBuffer().getvalues()
activate F
F-->C: return buffer values
C->F: buffer.changeValues()
deactivate F
C->C: modifyOwnValues()
C->UI: return 0 or 1
deactivate C
UI->Files: myFiles.display()
deactivate UI
activate Files
Files-->User: shows updated screen
deactivate Files
deactivate UI
@enduml

**plant uml code use case 3: klaar**
MAIN
@startuml
actor User
participant ":inputhandler" as UI
participant ":viewTree" as V
participant ":viewNode" as N
participant ":File" as F
participant ":Cursor" as C
participant ":Write" as W
User -> UI: press Ctrl+P or Ctrl+N
activate UI
UI -> UI: controlP(index,tree) or controlN(index,tree)
activate UI
UI -> V: tree.getAllViewNodes()
activate V
V-->UI: return viewNodes
deactivate V
UI->N: viewNodes.get(index).get_file()
activate N
N-->UI: return file
deactivate N
UI->UI: change Active
UI-->UI: return index
deactivate UI
UI -> F: active.getCursor().getLine() and active.getCursor().getColumn()
activate F
F->UI: return line and column
deactivate F
UI->UI: moveCursor(line,column)
UI-->User: display moved cursor
User -> UI: presses arrow key
UI -> UI: arrowDirection(myFiles)
activate UI
UI->F: active.getCursor()
activate F
F-->UI: return cursor
deactivate F
UI->C: cursor.moveDirection()
activate C
C->F: getBuffer().getvalues()
activate F
F-->C: return buffer values
C->F: buffer.changeValues()
deactivate F
C->C: modifyOwnValues()
C->UI: return 0 or 1
deactivate C
UI->Files: myFiles.display()
deactivate UI
activate Files
Files-->User: shows updated screen, including scrollbar
deactivate Files
User -> UI: presses ASCII char
UI->UI: writeKey(key)
activate UI
UI->W: addWrite(char, active)
activate W
W->F: getBuffer()
activate F
F-->W: return buffer
W->F:modifyBufferValues()
W-->UI: modified buffer
deactivate F
deactivate W
UI->Files: myFiles.display()
deactivate UI
activate Files
Files-->User: shows updated screen, including dirty asterix
deactivate Files
deactivate UI
@enduml

**plant uml code use case 4 hey dit is ook klaar Victor**
@startuml
actor User
participant ":Inputhandler" as Inputhandler
participant ":File" as FileBuffer
participant ":Files" as Files
participant ":ViewTree" as ViewTree
participant ":ViewNode" as ViewNode
participant ":Buffer" as Buffer
User -> Inputhandler: Press Ctrl+P or Ctrl+N
activate Inputhandler
Inputhandler -> Inputhandler: ControlP(index, tree) or ControlN(index,tree)
activate Inputhandler
Inputhandler -> ViewTree: tree.getAllViewNodes()
activate ViewTree
ViewTree --> Inputhandler: return viewNodes
deactivate ViewTree
Inputhandler -> ViewNode: viewNodes.get(index).get_file()
activate ViewNode
ViewNode --> Inputhandler: return file
deactivate ViewNode
Inputhandler -> Inputhandler: change Active
Inputhandler --> Inputhandler: return index
deactivate Inputhandler
User -> Inputhandler: Press(Ctrl+S)
Inputhandler -> Buffer: getBuffer().getdirty()
activate Buffer
Buffer --> Inputhandler: dirty
deactivate Buffer
alt good
Inputhandler -> Files: exists(file)
activate Files
Files --> Inputhandler: true
deactivate Files
Inputhandler -> FileBuffer: save()
activate FileBuffer
FileBuffer -> FileBuffer: write(line)
FileBuffer -> Buffer: setdirty(false)
activate Buffer
deactivate Buffer
FileBuffer -> FileBuffer: inlezen()
FileBuffer --> User: display
deactivate FileBuffer
else bad
Inputhandler -> Files: exists(file)
activate Files
Files --> Inputhandler: False
deactivate Files
Inputhandler -> Inputhandler: saveerror()
Inputhandler --> User: error "Failed saving the file"
end
deactivate Inputhandler
@enduml

**plant uml code use case 5: final**
@startuml
actor User
participant ":Inputhandler" as I
participant ":File" as V
participant ":Files" as F
participant ":FileBuffer" as FB
participant ":viewNode" as N
participant ":Viewtree" as T
User -> I: press Ctrl+P or Ctrl+N
activate I
I -> I: controlP(index,tree) or controlN(index,tree)
activate I
I -> T: tree.getAllViewNodes()
activate T
T-->I: return viewNodes
deactivate T
I->N: viewNodes.get(index).get_file()
activate N
N--> I: return file
deactivate N
I->I: change Active
I-->I: return index
deactivate I
I -> F: active.getCursor().getLine() and active.getCursor().getColumn()
activate F
F->I: return line and column
deactivate F
I->I: moveCursor(line,column)
I-->User: display moved cursor
User -> I: Press F4
activate I
I -> I: f4(tree, myfiles, running)
activate I
I -> V: Check_Dirty()
activate V
V --> I: dirty
deactivate V
alt Buffer is not dirty
I -> V: close(active)
activate V
V -> T: removenode(active node)
activate T
T --> V: updated tree
deactivate T
V -> V: deelop()
V--> User: updated view
deactivate V
I --> User: updated view
else Buffer is dirty
I --> User: ask confirmation
User -> I: Press Y
I-> F: exists(file)
activate F
F--> I: true
deactivate F
I-> FB: save()
activate FB
FB-> FB: write(line)
FB-> Buffer: setdirty(false)
activate Buffer
deactivate Buffer
FB-> FB: inlezen()
FB--> User: display
deactivate FB
I -> V: close(active)
activate V
V -> T: removenode(active node)
activate T
T --> V: updated tree
deactivate T
V -> V: deelop()
V--> User: updated view
deactivate V
I --> User: updated view
else Buffer is dirty
I --> User: ask confirmation
User -> I: Press N
I --> User: unchanged view
end
deactivate I
deactivate User
@endumlate User
@enduml

**plant uml code use case 6: final**
@startuml
actor User
participant ":inputhandler" as I
participant ":viewTree" as T
participant ":files" as F
participant ":debug" as D
participant ":viewnode" as N
User -> I: press Ctrl+P or Ctrl+N
activate I
I -> I: controlP(index,tree) or controlN(index,tree)
activate I
I -> T: tree.getAllViewNodes()
activate T
T-->I: return viewNodes
deactivate T
I->N: viewNodes.get(index).get_file()
activate N
N--> I: return file
deactivate N
I->I: change Active
I-->I: return index
deactivate I
I -> F: active.getCursor().getLine() and active.getCursor().getColumn()
activate F
F->I: return line and column
deactivate F
I->I: moveCursor(line,column)
I-->User: display moved cursor
User -> I: Ctrl+R/Ctrl+T
activate I
alt not the last view in layout
I -> T: rotate_counter/clockwise(node1,node2)
activate T
T --> I: updated tree
deactivate T
I -> F: deelOp(Terminalapp.getTerminalSize())
activate F
F --> User: updated view
deactivate F
else last view in the layout
I -> D: testSound()
deactivate I
activate D
D --> User: sound bell, unchanged view
deactivate D
end
@end
@enduml

# Class diagram
@startuml
class Main {
- fileBuffers: List<FileBuffer>
+ launchTextr(filePaths: String[])
+ inspectBufferContents()
+ editBufferContents()
+ saveBuffer()
+ closeBuffer()
+ rearrangeLayout()
}
class FileBuffer {
- filePath: String
- contents: String
- dirty: boolean
+ loadFile(filePath: String)
+ saveToFile()
+ isDirty(): boolean
+ closeBuffer()
}
class View {
- buffer: FileBuffer
+ focus()
+ moveInsertionPoint()
+ updateScrollState()
}
class UserInputHandler {
+ handleUserInput()
}
class Layout {
- bufferViews: List<FileBuffer>
+ create_layout()
}
Main "1" -d- "0..*" FileBuffer
FileBuffer "1" -l- "0..*" View
Layout –* Main
View "0..*" -l- "1"Layout
Main – UserInputHandler
UserInputHandler –> Main
@enduml
