- M: To model the logic related to data of the application.
- V: To present the model to the end user.
- C: To control the view and the model.
Most, if not all, of the classes in the GUI package and its subpackage gui.menu
.
A3: Explain what each of the classes SlotLabel
, SlotLabels
, Editor
, StatusLabel
, CurrentLabel
, and XL
in the provided code does
The classes are located in the gui package.
-
A
SlotLabel
displays the contents of one cell in the spreadsheet.SlotLabel
extendsColoredLabel
, which in turn extendsJLabel
– a Swing GUI element for displaying strings. -
SlotLabels
is the view for all of the cells in the spreadsheet. This class has a field with the correspondingSlotLabel
for each position in the cell grid. -
Editor
extendsJTextField
and as such, it's a textfield that the user can edit text with. It is the users main point of interaction with the application. The purpose of this text field is to enable the user to write values and formulas to be assigned to a cell. TheEditor
view is presented above the cells, next to the status bar. -
The purpose of the
StatusLabel
class is to present status messages to the user. This label is presented next to a label showing the currently selected cell. They are bundled together in theStatusPanel
class. TheStatusLabel
class implementsObserver
to be able to react to changes in the application state and update itself accordingly. -
CurrentLabel
is a view displaying the currently selected cell. It is bundled together with aStatusLabel
instance in aStatusPanel
instance. -
XL
is the main class of the application. It initializes the various Model instances and sets up the views. By having a list of currently active spreadsheets, it supports opening several spreadsheets at once.
A4: Use case: someone types in 42 into Editor
- what should happen for us to be able to see the value in the spreadsheet (which way does this value take through the M, V, and C)?
- The editor (part of the View) registers "42" as an input string by the user.
- The Controller needs to be alerted in some way that the text in the text field has been updated and react to it.
- The Controller will update the model which the rest of the View will react to, making it update.
The path the value takes is therefore View ➡️ Controller ️➡️ ️️Model ➡️ View.
B1: How are addresses represented (this has already been decided upon in the provided code)? Can you come up with an alternative representation?
In the provided code, Strings
are used to represent adresses. This is an easy solution as the TreeMap
will be able to sort the words on the natural ordering of String
. However, we don't fancy bulding a stringly typed application, so we will implement an adress class called Coordinate
We can implement an interface (or abstract class) for cell contents, which is implemented by two classes: Expression
and Comment
. This is dependency inversion. Please note that this representation is used in the model only and is separate from what is displayed in each SlotLabel
, which preferably could still store its contents to be displayed as a simple String
.
A CellFactory
will be used to create Cell
instances.
An instance of the Num
class, which extends the abstract class Expr
We need a Cell
interface/abstract class, that is implemented/subclassed by Expr
and Comment
.
We also need a model for all the cells in the sheet. This could preferably be a class implementing the Environment
interface. This is different from the SlotsLabels
class which is only responsible for displaying the cells. class.
A class implementing the Environment
interface, henceforth called the Sheet
. This enforces dependency inversion.
A TreeMap
is the mest option.
A list or matrix is the data structure that immediately comes to mind, but this would violate the customer requirement that the memory usage only be dependent on the information actually inputted – by doing it this way we need an instance for each location in the sheet regardless of it being filled in or not.
A simple way of doing it would be to have some kind of Map
mapping the cell index to each cell. If the cell index is encapsulated in a Coordinate
class the type of the cell store would be Map<Coordinate, Cell>
. HashMap would be suitable for fast access, but a difficulty is to override hashCode(). We had an interesting discussion about the posibility to guarantee a unique mapping of R^2 to R, continous or discreet. With the finite nature of int
, we are sure that we can't map each unique Coordinate
(row, col
) to a unique hashCode.
However, the HashMap
will create an internal vector (of great length) which violates the customer's requirement of sparse memory need. Thus a TreeMap
is the best option: its a map with low memory need and an acceptable time complexity of log(n)
.
A more absurd representation is a variant of a linked list, where each cell contains references to its four neighbouring nodes. A pro of this implementation would be fast access to neighbouring nodes, and a good basis for implementing algorithms that depend on neighbours. If our sheet were to be the basis for a graph database, this could be used to enable nodes and vectors.
B7: The assignment above contains the following wording. How do we ensure that we do not use more memory than required?
"The customer has expressed the requirement that the memory usage for the spreadsheet model must not depend on the size of the sheet, but only on the amount of information that has been inputted."
This was covered under our B6-discussion. A Treemap doesn't use more memory than necessary.
We use the intercace Environment
in place of its implementation sheet
in order to achieve dependency inversion, an important SOLID principle.
Interface Expr
specifies the method value(Environment): double
, which returnts the value of the expression. The parameter Environment
is used to retrieve the values of the variables that the expression referes to. E.g. a cell in the spreadsheet can contain the logic a1 + a2
. Given that the variable have values, a1 = 3
, a2 = 5
, the call to Expr.value(Environment)
should then return 8
.
Our proposed Sheet
class.
Are we allowed to change the signature of Environment.value(String)
? In that case we would prefer for the method to take one of our own CellCoordinate
values.
Because we are forced to not make the concrete implementation and the rest of the program depend on each other too much, by specifying (a very simple) way for them to communicate. This supports high cohesion and low coupling.
Dependency Inversion Principle (DIP) – by programming against an interface instead of a concrete implementation.
It needs to have access to some class that can give it a String
to put in its SlotLabel
. This can come either from the toString
method in the Cell
class or some kind of facade pattern class implemented specifically for this purpose. By doing it this way we achieve a loose coupling between the various parts of our system.
D2: When our GUI accesses values to write in a SlotLabel
or SlotLabels
, what values and what type do we want to get back?
We want the GUI to be able to access String
representations of all the various Cell
types.
D3: When the user clicks in a cell, and our Editor
gets updated, what value, and what type do we want to get back, to put in the editor?
The Sheet class must have functionality to retrive both value and formulas in it's cells. In the visual representation, a cell should display it's value, but if the user presses it, the forumla should be displayed in the editor instead.
The controller should display a descriptive error message in the status bar.
What in the program is responsible for enforcing this behaviour?
This could eiter be enforced directly in the Editor (which is in the View), or in the Controller, or in the Model. A benefit of doing the check in the Model is that we achieve lower coupling - only the model can be sure about what values are valid.
E2: Use case: the user edits a cell so that division by zero occurs somewhere else in the sheet -- what should happen?
The cell contents should be invalidated (i.e. display something so that the User knows where the error has occured) as well as an error message shown in the status bar.
What in the program is responsible for enforcing this behaviour?
This logic should be imlemented in the Model.
The circular reference should be detected, all cells affected should halt their updates (to prevent infinite loops adversely affecting performance), and an error message displayed in the status bar.
What in the program is responsible for enforcing this behaviour?
This logic should be implemented in the Model.
The model (i.e. the expr
package).
The Controller, because it has access both to the view (to display for example error messages) and the model. The View will only communicate errors to the user. The model only rejects new cell entries.
F1: What kind of synchronization (Flow Synchronization or Observer Synchronization) do you want to use between the M and the V/C?
We want to imlemement Observer Synchronization.
F2: How does the system keep track of which cell is currently selected? (This depends on how the Controller
is implemented)
It should not be dealt with in the model (i,e, not in the Sheet that implements Environment). Either the view or the controller keeps track of this.
Through the Observer Synchronization.
Add a new bomb class
that implements the interface Cell
. The bomb
class has a method value(Environment)
. An expression is submitted for approval. CellFactory will create a new cell of the new expression. The environment will save the old content of the currently selected cell to a temporary variable temp
. The environment adds an instance of the bomb
class in its place. The value of the new expression is calculated as a test for circular dependency. If the calculations run into the bomb
, there is a circular reference. Then deal with it, add the old value temp
back, reject the candidate and let the view or the controller present the error to the user.. If on the other hand you can calculate the new value successfully (without a bomb), then its valid and it can be added as valid, and the temp
value discarded.
An alternative and more fun solution is our first idea: We add the open source version of Neo4J's graph database as a dependency. We let each cell be a node, and any interdependencies are edges in the graph. Once we have a closed loop in the graph, we have a circular dependencies in the spreadsheet.