34
Design and Implementation of the Spreadsheet Application J.M Rajind Ruparathna 110486D

Design of Spreadsheet Aplication

Embed Size (px)

DESCRIPTION

This is a document that covers design and implementation of a spreadsheet application in java. (No GUI)

Citation preview

  • Design and Implementation of the Spreadsheet Application

    J.M Rajind Ruparathna 110486D

  • 1 | P a g e

    Table of Contents

    1. Introduction ................................................................... 2

    2. Design of Objects ........................................................... 3

    3. Java Implementation ..................................................... 7

    4. Application Testing ...................................................... 11

    5. Conclusion .................................................................... 17

    Appendixes

    Appendix A ................................................................ 19

    Appendix B ................................................................ 20

    Appendix C ................................................................ 22

  • 2 | P a g e

    1. Introduction

    Step 1:

    A cell in the spreadsheet application must be able to hold many different types of values at

    different times. Such as a text string, a number or a string giving a function to manipulate

    text or number. There must be methods to manipulate text and number inside the cell.

    Step 2:

    The cell must further more provide the capability to store a simple equation or an address

    of another cell. An example of a simple equation is "=A1+10". Each cell must be addressable

    using a unique address for each cell within a spreadsheet. It is required to design and

    implement manipulation of a collection of cells which is a row or a column.

    Step 3:

    As the third step, it is required to design and implement manipulation of a region of cells

    which is in this step considered as a rectangular collection of cells, preserving the

    capabilities of a cell from the earlier steps.

    Step 4:

    In this step spreadsheet application requires the ability to manipulate a region of cells

    within a spreadsheet. A region of cells is a rectangular collection of cells and the required

    manipulations are selecting, copying, cutting, pasting and deleting.

    Step 5:

    As fifth step, spreadsheet application requires the ability to create a new spreadsheet, load

    and store a spreadsheet to/from persistent storage.

    Step 6:

    In the final step, the spreadsheet application requires the Observer-Observable paradigm

    used for a cell objects in the spreadsheet.

  • 3 | P a g e

    2.Design of Objects

    Step 1:

    Uploaded Design Document - CS2012-P05-Design-110486D

    Cell Object

    A cell object was designed as the first step. Cell was designed using an abstract class called

    Cell and then inheriting the abstract Cell class into more specific types of Cell classes namely

    NumCell, TextCell, and GeneralCell. NumCell class includes a new attribute called number

    a double variable, and methods relevant to arithmetic functions which are there to

    manipulate the value of variable called number. TextCell includes a new attribute called text

    a String variable, and methods to manipulate the variable named text. GeneralCell has

    three new attributes namely intNum -an integer variable, doubleNum a double variable,

    text a String variable.

    However at the end of step 2, this design of Cell was completely altered since I found

    difficulties in continuing the design process with keeping the ability to hold many different

    types of values at different times in a Cell. The Cell design before altering will be called Cell

    Design 1 and after altering will be called Cell Design 2.

    Step 2:

    Uploaded Design Document - CS2012-P07-Design-110486D

    In this step Cell Design 1 was further extended with a few changes. Since the Cell Design 1

    was discarded and Cell Design 2 was used after this step, from here on Cell Design 2

    (Appendix A) will be discussed.

    In this design there is class named Cell and a class named CellSet.

    Cell Object

    Cell object includes five attributes and four of them are text- a String variable, doubleNum-

    a double variable, intNum- an integer variable, dataType- a char variable. dataType variable

    is used to keep record of the data type of value currently stored in the Cell object. Above

    mentioned other three intNum, doubleNum, text are to provide the capability to hold many

    different types of values at different times within a Cell object. The sixth attribute is a

    variable named obj which is there to keep a reference of the collection of cells (a row or a

    column) of which the Cell object belongs.

  • 4 | P a g e

    There are three overloaded constructors for the Cell class to create a Cell object. All three

    constructors take two arguments with one always being a CellSet object. Cell object

    contains a method called show() which is used to print the value stored in the Cell object .

    The value stored in the Cell object can be changed using a method called change( ).

    CellSet Object

    CellSet object is representing a collection of Cell objects (a row or a column). It has a Cell

    object array of which the size is determined using the constructor of the CellSet class.

    Step 3:

    Uploaded Design Document - CS2012-P11-Design-110486D

    CellSet Object

    In this step, CellSet class is modified to hold a two dimensional array of Cell objects to

    represent a region of cells which is a rectangular collection of cells according to the

    application requirements.

    Step 4:

    Uploaded Design Document - CS2012-P13-Design-110486D

    In this step a new class called IndexData was added to the design.

    The improvements and modifications done under this step are described in two parts. First

    part is improvements and modifications for the purpose of forth step's requirements and

    second part is general improvements.

    First Part for the purpose of Step 4 requirements

    Cell Object

    A new method called getValue() is added to the Cell class. It is used in designing the paste

    operation.

    IndexData

    IndexData object is used in designing select range operation.

    CellSet

    There is a new method called decodeCell() in CellSet object and it is used to determine the

    position of a particular Cell in the two dimentional array of cells when a Cell's address is

    given as a string. CellSet object has a IndexData object. Starting point and end point of the

    selected rectangular region is stored in that IndexData object. CellSet object also has

    another CellSet object named as copiedRange. CellSet object has new methods namely

  • 5 | P a g e

    selectRange(), copyRange(), cutRange(), deleteRange() and pasteRange() for range

    manipulations. The copyRange() method stores copied cells in copiedRange object. The

    pasteRange() method uses a an address of a Cell (String variable) to determine where to

    paste the selected set of Cells.

    Second Part general improvements

    CellSet

    Three changeValue() methods are added (one for each data type String, integer and

    double) in this step apart from the method called change() which was already there.

    Methods called add(), substract(), multiply(), divide(), are added to provide capability of

    arithmetic operations. A method called concatenate() is added to provide capability to

    concatenate two strings. Methods called sumOfRange() and avgOfRange() are included to

    calculate sum and average of a range. A method called assign() is added to check and store a

    integer as an integer and a double value as a double value after doing a function on the

    numeric value inside the Cell object. A method called getOperandCell() is used to identify

    the relevant Cells and their indexes in the CellSet array using the provided equation.

    Step 5:

    Uploaded Design Document - CS2012-P14-Design-110486D

    Coming from step four to step five two new classes were included to the design. They are

    called Sheet and Application. In this step the classes Cell, CellSet, IndexData, Sheet, were set

    to implement Serializable interface.

    Sheet Object

    Idea of creating class called Sheet was to give an object of Sheet class a similar meaning of a

    spreadsheet in a spreadsheet application. The ability to add any property a programmer

    wants to a sheet is provided with this improvement. Here an attribute sheet_name is

    included in the Sheet object to give the sheet a name. A Sheet object has a CellSet object

    which includes the collection of cells.

    Application Object

    Idea of creating a class called Application was to create an object of Application class an

    treat it the same way as a spreadsheet application. An Application object has an ArrayList of

    Sheet objects as opened tabs of spreadsheets in a spreadsheet application. There are

    methods called createSpreadSheet(), storeSpreadsheet(), loadSpreadsheet() to create, save

    and load a spreadsheet. loadSpreadsheet() method takes a String variable( name of the

    spreadsheet to be loaded) as an argument and storeSpreadsheet() method takes a String

    variable (name which the spreadsheet to be saved) as an argument. Methods called

    loadFile() and saveFile() in the Application object are to support storeSpreadsheet(),

  • 6 | P a g e

    loadSpreadsheet() methods. Application object has a Sheet object called worksheet which is

    used to store working spreadsheet from the ArrayList using the method called

    selectWorkSheet(). An attribute called opened_file_index is there in the Application object

    to store the index value in the ArrayList of Sheet object which is to be opened as the

    working spreadsheet. A method called showData() is there to print out the values of the

    spreadsheet.

    Step 6:

    Uploaded Design Document - CS2012-P14-Design-110486D

    Cell class is set to extend Observable class and set to implement Observer interface.

    Cell Object

    To set the Observer-Observable paradigm to the Cell objects, a String variable callled

    equation and an integer variable called maxObservables is added to the attributes of Cell

    object. When an equation is entered to a Cell it is stored in the variable called equation.

    When values are calculated according to the equation provided relevant Observers are set

    using setObservables() method. After that when a value changes, informChange() method is

    called. update() method is used with the change() method to make the relevant changes.

    There is a ArrayList in the Cell object to keep track of the other Cell objects which the first

    Cell object has become an Observer to. A method called clearObservables() in Cell object

    removes itself from being an Observer when being an Observer is no longer needed.

  • 7 | P a g e

    3. Java Implementation

    Spreadsheet application final java implementation Appendix C The implementation of the cut region operation in a CellSet was done as follows (the

    complete code was uploaded as the method in class in the file

    )

    public void cutRange(){

    copiedRange = new CellSet(s.endRow-s.startRow+1 , s.endCol-s.startCol+1);

    for(int i= s.startCol ; i

  • 8 | P a g e

    case "N": name = c.nextLine();

    f = new File(name+".ser");

    saveFile(f,name);

    break;

    case "C": break;

    default : System.out.println("Not a valid choice");

    break;

    }

    }else {

    saveFile(f,name);

    }

    }

    In this method first the extension .ser is added to the file name (name which the file is to be saved).

    Then it checks whether a file in the same name already exists and if it does them a choice is asked

    from the user. Then process is continued according to the choice form the user.

    The implementation of function evaluation in a Cell was done as follows (the complete code was

    uploaded as the method in class in the file )

    public void change(String t){ //equations are handled by this method

    int select =0;

    int[] in; //in[1] = col in[0] = row

    String operandCellDataType;

    //function formats: sum of range "=SUM(A1:B3)"

    // average of range "=AVG(A1:B3)"

    // sum of a cell value and other value "=A3+other_value"

    // assigning another cell's value "=C3"

    equation = t;

    if(t.length() > 4){

    t = t.toUpperCase(Locale.ENGLISH);

    if(t.startsWith("=SUM"))

    select = 1;

    if(t.startsWith("=AVG"))

    select = 2;

    if(t.charAt(0) == '=' && t.charAt(4) != '('){

    select = 4;

    maxObservables = 1;

    }

    }else{

    if(t.charAt(0) == '=' && t.length()== 3){

    select = 3;

    maxObservables = 1;

    }

    }

    switch (select){

    case 1:

    sumOfRange(t);

    break;

    case 2:

  • 9 | P a g e

    avgOfRange(t);

    break;

    case 3:

    in = getOperandCell(t,1);

    operandCellDataType = this.obj.table[in[0]][in[1]].dataType;

    setObservables(obj.table[in[0]][in[1]]);

    switch (operandCellDataType){

    case "Integer":

    this.intNum = this.obj.table[in[0]][in[1]].intNum;

    this.dataType = "Integer";

    break;

    case "Double":

    this.doubleNum = this.obj.table[in[0]][in[1]].doubleNum;

    this.dataType = "Double";

    break;

    case "String":

    this.text = this.obj.table[in[0]][in[1]].text;

    this.dataType = "String";

    break;

    }

    break;

    case 4:

    in = getOperandCell(t,1);

    operandCellDataType = this.obj.table[in[0]][in[1]].dataType;

    char operation = t.charAt(3); //checks the operation to be done

    String newVal = t.substring(4);

    setObservables(obj.table[in[0]][in[1]]);

    switch (operandCellDataType){

    case "String":

    concatenate(obj.table[in[0]][in[1]] ,newVal);

    break;

    case "Integer":

    case "Double":

    double num = Double.parseDouble(newVal);

    switch (operation){

    case '+':

    add(this.obj.table[in[0]][in[1]] , num);

    break;

    case '-':

    substract(this.obj.table[in[0]][in[1]] , num);

    break;

    case '*':

    multiply(this.obj.table[in[0]][in[1]] , num);

    break;

    case '/':

    divide(this.obj.table[in[0]][in[1]] , num);

    break;

    }

    break;

    }

    break;

    default:

    this.text = "#VALUE";

    this.dataType = "Error";

    break;

    }

    }

  • 10 | P a g e

    If-else condition at the beginning of the method determine the function to be done using the string

    of function provided and a suitable value is assigned to the integer variable called select. Then the

    select variable is used in a switch case to evaluate the relevant function. If the string of function does

    not represent any identifiable function then text value of the cell is set to show that an error has

    occurred using default part of the switch case.

    The implementation of method called assign() in a Cell was done as follows (the complete code

    was uploaded as the method in class in the file )

    public void assign(double num){

    if(Math.ceil(num) == num || Math.floor(num) == num){

    this.intNum = (int)num;

    this.dataType = "Integer";

    }else{

    this.doubleNum = num;

    this.dataType = "Double";

    }

    }

    When a number is in double format, its value can be an integer or a floating point value. In the Cell

    class when evaluating functions a value of a double variable being integer is possible. In such cases

    this method checks if the number in double variable is really a floating point value or not. If it is an

    integer, then the value is assigned to the intNum variable in the Cell.

  • 11 | P a g e

    4. Application Testing

    Step 3:

    Testing of -SUM function evaluated on a range

    -String concatenation

    -simple equation

    Input:

    At the initialization:

    12 "Wasted" "=A1-10.7" 56 98 444

    3.5 32.5 "=A2" 89 56 "=F1"

    "Let me b" 10 "MAD" 23 34 "oooo"

    At the editing point:

    Test Results:

    Spreadsheet:

    12 Wasted 1.3 56 98 444

    3.5 32.5 3.5 89 56 444

    Let me b 10 MAD 23 34 oooo

    Spreadsheet:

    356 Wasted now 6.9 56 98 555

    3.5 32.5 Wasted now 89 56 444

    Let me b 10 MADHAWEEE 23 34 oooo

    "SUM(D1:E3)" 6.89875 555

    "=B1+ now"

    "=C3+HAWEEE"

  • 12 | P a g e

    Step 4:

    Testing of -select range

    -copy range

    -paste range

    -delete range

    Input:

    At the initialization:

    At the editing point:

    Test Results:

    Spreadsheet:

    10.500 Mad 10.560 10.670 10 kadkas

    20.500 aloalo 20.340 20.340 20.110 20.110

    11 nana 30.560 30 30.778 30.778

    Spreadsheet:

    No Cell No Cell 10.560 10.670 10.500 Mad

    No Cell No Cell 20.340 20.340 20.500 aloalo

    No Cell No Cell 30.560 30 11 nana

    10.5 "Mad" 10.56 10.67 10 "kadkas"

    20.5 "aloalo" 20.34 20.34 20.11 20.11

    "=A1+0.5" "nana" 30.56 30 30.778 30.778

    "askldlnkjnkj"

  • 13 | P a g e

    Step 5:

    Testing of -create spreadsheet

    -save spreadsheet

    -load spreadsheet

    Input:

    At the initialization:

    At the editing point:

    Test Results:

    Initializing, Editing and Saving:

    Spreadsheet "sheet1" created and opened in a tab.

    Spreadsheet "sheet2" created and opened in a tab.

    Spreadsheet "sheet3" created and opened in a tab.

    Spreadsheet "sheet2" selected for work.

    Spreadsheet "sheet2":

    No Cell No Cell 10.560 10.670 10.500 Mad

    No Cell No Cell 20.340 20.340 20.500 aloalo

    No Cell No Cell 30.560 30 11 nana

    Spreadsheet "sheet1" selected for work.

    Spreadsheet "sheet1":

    10.500 Mad 10.560 10.670 10 kadkas

    20.500 aloalo 20.340 20.340 20.110 20.110

    11 nana 30.560 30 30.778 30.778

    10.5 "Mad" 10.56 10.67 10 "kadkas"

    20.5 "aloalo" 20.34 20.34 20.11 20.11

    "=A1+0.5" "nana" 30.56 30 30.778 30.778

    "askldlnkjnkj"

  • 14 | P a g e

    File already exists. Press:

    Y to overwrite

    C to cancel

    N to save in another file name

    Enter Choice:Y

    Spreadsheet "sheet1" selected for work.

    Spreadsheet "sheet1" saved to disk successfully.

    File already exists. Press:

    Y to overwrite

    C to cancel

    N to save in another file name

    Enter Choice:Y

    Spreadsheet "sheet2" selected for work.

    Spreadsheet "sheet2" saved to disk successfully.

    Spreadsheet "sheet3" selected for work.

    Spreadsheet "sheet3":

    No Cell No Cell No Cell No Cell No Cell No Cell

    No Cell No Cell No Cell No Cell No Cell No Cell

    No Cell No Cell No Cell No Cell No Cell No Cell

    Loading a saved file:

    Spreadsheet "sheet2" selected for work.

    Spreadsheet "sheet2" loaded form disk successfully.

    Spreadsheet "sheet2":

    No Cell No Cell 10.560 10.670 10.500 Mad

    No Cell No Cell 20.340 20.340 20.500 aloalo

  • 15 | P a g e

    No Cell No Cell 30.560 30 11 nana

    Spreadsheet "sheet1" selected for work.

    Spreadsheet "sheet1" loaded form disk successfully.

    Spreadsheet "sheet1":

    10.500 Mad 10.560 10.670 10 kadkas

    20.500 aloalo 20.340 20.340 20.110 20.110

    11 nana 30.560 30 30.778 30.778

    Step 6:

    Testing of -Observer-Observable paradigm

    Input:

    At the initialization:

    At the editing point :

    Test Results:

    Spreadsheet "sheet1" created and opened in a tab.

    Spreadsheet "sheet1" selected for work.

    Spreadsheet "sheet1":

    10.500 Mad 10.560 10.670 10 183.358

    20.500 aloalo 20.340 20.340 20.110 20.110

    11 nana 30.560 30 30.778 30.778

    10.5 "Mad" 10.56 10.67 10 "kadkas"

    20.5 "aloalo" 20.34 20.34 20.11 20.11

    "=A1+0.5" "nana" 30.56 30 30.778 30.778

    16.88 1000

  • 16 | P a g e

    Spreadsheet "sheet1":

    16.880 Mad 1000 10.670 10 1172.798

    20.500 aloalo 20.340 20.340 20.110 20.110

    17.380 nana 30.560 30 30.778 30.778

  • 17 | P a g e

    5. Conclusion

    I believe that I have used many of the object oriented concepts and methodologies

    throughout this design process of the spreadsheet application. The foundation of object

    orientation is to have a set of well-behaved data objects do the task for the user by passing

    messages to one another. Each data object deciding for itself whether to accept the

    message and how to interpret what it means. When the project developed step by step, i

    understood how to develop the design from one object to another.

    Let's consider some examples. The first object set was a Cell. When it came to step 2, it was

    clear that i had to step into a new object to continue the process. It is like considering the

    required elements as real world objects. In the project I have used a class called CellSet and

    a class called Sheet. Both of them are very much close to each other but I felt that coding

    looks more organized when you separate the Cell collection and the properties of the

    spreadsheet. My goal was to use the CellSet class as the Cell collection and Sheet class as

    the real spreadsheet with all the properties and Cell collection. At that point composition is

    used.

    As moving forward to step five when it was asked to design the capability to create new

    spreadsheet, then I moved to a new object called Application. Control of the sheet objects

    were given to the Application object.

    Up to now discussion was about the foundation of object orientation which is the using a set

    of interacting objects. Basic principles of object orientation will be discussed from here on. I

    have learned four basic principles of object orientation. They are encapsulation, inheritance,

    abstraction and polymorphism. I tried to get the maximum use of them when in need and I

    think I succeeded in doing that. I have used encapsulation in almost every class. I

    understood that encapsulation is not all about simply using getters and setters to a private

    attribute but to use access modifiers properly and using getters and setter when in need

    and with suitable conditions. Encapsulation was used to limit the possible occurrences of

    errors where the input could corrupt the accuracy of the program.

    I have used polymorphism as well. It was used in designing the cut and copy operations.

    There is a method called getValue() in Cell class of which the return type is java.lang.Object.

    This getValue() method returns data inside the Cell as an object of type java.lang.Object. In

    the copyRange() , cutRange() methods in the CellSet class getValue() method is used and the

    object returned by getValue() method is cast into the correct type (to a String, Double or an

    Integer). This is called dynamic binding or late binding which is a form of polymorphism. I

    have used overloaded constructors in the Cell class and I have used method overloading in

    the Cell class (changeValue() method) as well. This is also some form of polymorphism.

    Inheritance is another important basic object oriented principle. I haven't used it directly

    but I have used it in some way when the Observer-Observable concept is added to the Cell

  • 18 | P a g e

    class. I have extended the Cell class from the java.util.Observable class. I have implemented

    the Cell class with Observer interface and that is using multiple inheritance. Adding this

    Observer-Observable concept was easy because of the use of object orientation. All I had to

    do was go to the Cell class and modify it inside the Cell class. So I believe that I have

    understood and analyzed object oriented concepts and methodologies while completing the

    project to a great extent.

  • 19 | P a g e

    Appendixes

    Appendix A

    Cell

    -text : String -doubleNum : double -intNum : int -dataType : char -obj : CellSet

    Cell( n: double , o : CellSet) Cell( n: int , o : CellSet) Cell( t: String , o : CellSet) + change( t: String , o : CellSet) : void + show() : void

    TestClass

    -a :CellSet - A1,A2,A3 : Cell

    + createCell() : void + showCell() : void + editCell() : void

    CellSet

    #table : Cell[]

    CellSet(Num :int)

    TestClass

    CellSet Cell (Cell objects

    A1,A2,A3,B1,B2,B3)

  • 20 | P a g e

    Appendix B (Uploaded Design Document - CS2012-P14-Design-110486D)

    Cell :: Serializable

    - text : String - doubleNum : double - intNum : int - maxObservables : int - dataType : String - equation : String - obj : CellSet - observables : ArrayList

    - Cell( n: double , o : CellSet) - Cell( n: int , o : CellSet) - Cell( t: String , o : CellSet) +changeValue(n : int) : void +changeValue(n : double) : void +changeValue(t : String) : void +change( t: String) : void -clearObservables() : void -setObservables(obs : Cell) : void +informChange( Observable o, Object arg) : void +update(Observable o, Object arg) : void +getOperandCell(s : String, ad : int) : int[] +assign( num : double) : void +sumOfRange( t : String) : int +avgOfRange(t : String) : void +add(cell : Cell , num: double) : void +substract(cell : Cell , num: double) : void +multiply(cell : Cell , num: double) : void +divide(cell : Cell , num: double) : void +concatenate(cell : Cell, s : String) : void -clear() : void +clean() : void +getValue() : Object +show() : void

    CellSet :: Serializable

    #table : Cell[][] #copiedRange : CellSet -s : IndexData

    - CellSet(r :int ,c: int) +selectRange(st : String , en :String) : IndexData +cutRange() : void +copyRange() : void +pasteRange(st : String) : void +deleteRange() : void +cellPrsent( row : int, col : int) : void +decodeCell(code : String) : int[] +addData(cell : String , n : int) : void +addData(cell : String , n : double) : void +addData(cell : String , t : String) : void

    IndexData :: Serializable

    startRow : int startCol : int endRow : int endCol : int

    Sheet :: Serializable

    -sheet_name : String -cell_set : CellSet

    Sheet(name : String)

    Application

    -sheet_array : ArrayList -opened_file_index : int #worksheet : Sheet

    +createSpreadSheet(name : String) : void +isAlreadyOpened(name :String) : boolean +selectWorkSheet(name : String) : void +showdata(numberOfRows :int, numberOfColumns :int) : void +saveFile(f : File, name :String) : void +storeSpreadSheet(name : String) : void +laodFile(f : File , name: String) : void +loadSpreadSheet()name : String) : void

  • 21 | P a g e

    Serializable

    CellSet Cell IndexData Sheet

    IndexData CellSet //copiedRange

    Sheet

    CellSet

    Cell (Cell objects

    A1,A2,A3,B1,B2,B3)

    Application

    TestApp

    Cell (Cell objects

    A1,A2,A3,B1,B2,B3)

    Observable Observer

  • 22 | P a g e

    Appendix C (Uploaded Code - CS2012-P14-Code-110486D.java)

    Spreadsheet application final java code

    package Week14;

    import java.io.Serializable;

    import java.util.Observable;

    import java.util.Observer;

    import java.util.ArrayList;

    import java.util.Locale;

    public class Cell extends Observable implements Observer ,Serializable{

    private String text;

    private double doubleNum;

    private int intNum;

    private String dataType;

    private CellSet obj;

    private ArrayList observables = new ArrayList();

    private int maxObservables;

    private String equation;

    public Cell(int n ,CellSet o ){ //constructor for integers

    this.obj = o;

    clear();

    this.intNum = n;

    this.dataType = "Integer";

    }

    public Cell(double n , CellSet o){ //constructor for double values

    this.obj = o;

    clear();

    this.doubleNum = n;

    this.dataType = "Double";

    }

    public Cell(String t,CellSet o){ //constructor for integers & equations

    this.obj = o;

    clear();

    this.changeValue(t);

    }

    public void changeValue(int n){ //method to edit integer value

    this.dataType = "Integer";

    this.intNum = n;

    equation = null;

    clearObservables();

    informChange("A");

    }

    public void changeValue(double n){ //method to edit double value

    this.dataType = "Double";

    this.doubleNum = n;

    equation = null;

    clearObservables();

    informChange("A");

    }

  • 23 | P a g e

    public void changeValue(String t){

    if(t.charAt(0) != '='){

    equation = null;

    clearObservables();

    this.text = t;

    this.dataType = "String";

    }else{

    clearObservables();

    this.change(t); //once the equation changes change() method his has to be called

    }

    informChange("A");

    }

    public void change(String t){ //equations are handled by this method

    int select =0;

    int[] in; //in[1] = col in[0] = row

    String operandCellDataType;

    //function formats: sum of range "=SUM(A1:B3)"

    // average of range "=AVG(A1:B3)"

    // sum of a cell value and other value "=A3+other_value"

    // assigning another cell's value "=C3"

    equation = t;

    if(t.length() > 4){

    t = t.toUpperCase(Locale.ENGLISH);

    if(t.startsWith("=SUM"))

    select = 1;

    if(t.startsWith("=AVG"))

    select = 2;

    if(t.charAt(0) == '=' && t.charAt(4) != '('){

    select = 4;

    maxObservables = 1;

    }

    }else{

    if(t.charAt(0) == '=' && t.length()== 3){

    select = 3;

    maxObservables = 1;

    }

    }

    switch (select){

    case 1:

    sumOfRange(t);

    break;

    case 2:

    avgOfRange(t);

    break;

    case 3:

    in = getOperandCell(t,1);

    operandCellDataType = this.obj.table[in[0]][in[1]].dataType;

    setObservables(obj.table[in[0]][in[1]]);

    switch (operandCellDataType){

    case "Integer":

    this.intNum = this.obj.table[in[0]][in[1]].intNum;

    this.dataType = "Integer";

    break;

  • 24 | P a g e

    case "Double":

    this.doubleNum = this.obj.table[in[0]][in[1]].doubleNum;

    this.dataType = "Double";

    break;

    case "String":

    this.text = this.obj.table[in[0]][in[1]].text;

    this.dataType = "String";

    break;

    }

    break;

    case 4:

    in = getOperandCell(t,1);

    operandCellDataType = this.obj.table[in[0]][in[1]].dataType;

    char operation = t.charAt(3); //checks the operation to be done

    String newVal = t.substring(4);

    setObservables(obj.table[in[0]][in[1]]);

    switch (operandCellDataType){

    case "String":

    concatenate(obj.table[in[0]][in[1]] ,newVal);

    break;

    case "Integer":

    case "Double":

    double num = Double.parseDouble(newVal);

    switch (operation){

    case '+':

    add(this.obj.table[in[0]][in[1]] , num);

    break;

    case '-':

    substract(this.obj.table[in[0]][in[1]] , num);

    break;

    case '*':

    multiply(this.obj.table[in[0]][in[1]] , num);

    break;

    case '/':

    divide(this.obj.table[in[0]][in[1]] , num);

    break;

    }

    break;

    }

    break;

    default:

    this.text = "#VALUE";

    this.dataType = "Error";

    break;

    }

    }

    private void clearObservables(){ //to stop from being an observer

    if(observables.size() > 0){

    for(Cell temp : observables){

    temp.deleteObserver(this);

    observables.remove(obj);

    }

    maxObservables = 0;

    }

    }

    private void setObservables(Cell obs){

  • 25 | P a g e

    if(!observables.contains(obs)){

    System.out.println("maxObservers value "+maxObservables);

    obs.addObserver(this);

    observables.add(obs);

    }

    }

    public void informChange(String type){ //informs the change to observers

    if(this.countObservers()>0){ //if cell has any observers

    this.setChanged();

    this.notifyObservers(type);

    }

    }

    @Override

    public void update(Observable o, Object arg) {

    if( equation != null){

    change(equation);

    }

    }

    public int[] getOperandCell(String s , int ad){ //ad = address strating point

    int[] index = new int[2];

    index[0] = Integer.parseInt(s.substring((ad+1),(ad+2)));

    index[1] = (int)s.charAt(ad) - 64;

    return index;

    }

    public void assign(double num){

    if(Math.ceil(num) == num || Math.floor(num) == num){

    this.intNum = (int)num;

    this.dataType = "Integer";

    }else{

    this.doubleNum = num;

    this.dataType = "Double";

    }

    }

    public int sumOfRange(String t){ // fprmat is SUM(A1:B3)

    int[] start = getOperandCell(t,5); //[0] - row [1] - col

    int[] end = getOperandCell(t,8);

    int numOfCells = (end[0]-start[0]+1)*(end[1]-start[1]+1);

    maxObservables = numOfCells;

    double sum=0;

    for(int i=start[1];i

  • 26 | P a g e

    return numOfCells;

    }

    public void avgOfRange(String t){

    int numOfCells = sumOfRange(t);

    if(this.dataType.equalsIgnoreCase("Integer"))

    assign(this.intNum/numOfCells);

    else

    assign(this.doubleNum/numOfCells);

    }

    public void add(Cell cell , double num){

    if(cell.dataType.equalsIgnoreCase("Integer"))

    num = (double)cell.intNum + (double)num;

    else

    num = cell.doubleNum + (double)num;

    assign(num);

    }

    public void substract(Cell cell , double num){

    if(cell.dataType.equalsIgnoreCase("Integer"))

    num = (double)cell.intNum - (double)num;

    else

    num = cell.doubleNum - (double)num;

    assign(num);

    }

    public void multiply(Cell cell , double num){

    if(cell.dataType.equalsIgnoreCase("Integer"))

    num = (double)cell.intNum*(double)num;

    else

    num = cell.doubleNum*(double)num;

    assign(num);

    }

    public void divide(Cell cell , double num){

    if(cell.dataType.equalsIgnoreCase("Integer"))

    num = (double)cell.intNum/(double)num;

    else

    num = cell.doubleNum/(double)num;

    assign(num);

    }

    public void concatenate(Cell cell , String s){

    this.text = cell.text + s;

    this.dataType = "String";

    }

    private void clear(){

    this.dataType = "Empty";

    this.doubleNum = 0;

    this.intNum = 0;

    this.text = null;

    this.equation = null;

    clearObservables();

    }

    public void clean(){

    switch(dataType){

    case "String":

    this.doubleNum = 0;

    this.intNum = 0;

  • 27 | P a g e

    break;

    case "Double":

    this.intNum = 0;

    this.text = null;

    break;

    case "Integer":

    this.doubleNum = 0;

    this.text = null;

    break;

    }

    }

    public Object getValue(){

    switch (dataType){

    case "Integer":

    return this.intNum;

    case "Double":

    return this.doubleNum;

    case "String":

    return this.text;

    case "Error":

    return this.text;

    default:

    return "Empty";

    }

    }

    public void show(){

    switch (dataType){

    case "Integer":

    System.out.format("%-15d",intNum);

    break;

    case "Double":

    System.out.format("%-15.3f",doubleNum);

    break;

    case "String":

    System.out.format("%-15s",text);

    break;

    case "Error":

    System.out.printf("%-15s",text);

    break;

    default:

    System.out.format("%-15s","Cell is empty");

    break;

    }

    }

    }

    //////////////////////////////////////////////////////////////

    package Week14;

    import java.io.Serializable;

    public class CellSet implements Serializable{

    protected Cell[][] table; //2D array of cells

    private IndexData s = new IndexData();

    protected CellSet copiedRange;

    public class IndexData implements Serializable{

    int startRow;

    int startCol;

    int endRow;

  • 28 | P a g e

    int endCol;

    }

    public CellSet(int r, int c){

    table = new Cell[r][c];

    }

    public IndexData selectRange(String st, String en){

    int []one;

    int []two;

    one = decodeCell(st);

    two = decodeCell(en);

    s.startRow = one[0];

    s.startCol = one[1];

    s.endRow = two[0];

    s.endCol = two[1];

    return s;

    }

    public void cutRange(){

    copiedRange = new CellSet(s.endRow-s.startRow+1 , s.endCol-s.startCol+1);

    for(int i= s.startCol ; i

  • 29 | P a g e

    start = decodeCell(st);

    for(int i=start[1];i

  • 30 | P a g e

    this.sheet_name = name;

    this.cell_set = new CellSet(26,100);

    }

    }

    ////////////////////////////////////////////////////////////

    package Week14;

    import java.io.*;

    import java.util.ArrayList;

    import java.util.Locale;

    import java.util.Scanner;

    public class Application implements Serializable{

    protected Sheet worksheet = null;

    private ArrayList sheet_array = new ArrayList();

    private int opened_file_index = -1;

    public void createSpreadSheet(String name){

    Sheet temp = new Sheet(name);

    sheet_array.add(temp);

    System.out.format("Spreadsheet \"%s\" created and opened in a tab."

    + "%n",name);

    }

    public boolean isAlreadyOpened(String name){

    opened_file_index = -1;

    for(Sheet temp : sheet_array){

    if(temp.sheet_name.equals(name)){

    opened_file_index = sheet_array.indexOf(temp);

    return true;

    }

    }

    return false;

    }

    public void selectWorkSheet(String name){ //method to select currently-

    if(isAlreadyOpened(name)){ //working sheet

    worksheet = sheet_array.get(opened_file_index);

    System.out.format("Spreadsheet \"%s\" selected for work."

    + "%n",name);

    }else {

    System.out.println("No spreadsheet in that name found");

    }

    }

    public void showData(int numberOfRows , int numberOfColumns){

    System.out.format("Spreadsheet \"%s\": %n",worksheet.sheet_name);

    for(int i=1;i

  • 31 | P a g e

    public void saveFile(File f, String name) throws IOException{

    FileOutputStream file = null;

    ObjectOutputStream output = null;

    try{

    file = new FileOutputStream(f);

    output = new ObjectOutputStream(file);

    this.selectWorkSheet(name);

    output.writeObject(this.worksheet);

    System.out.format("Spreadsheet \"%s\" saved to disk successfully."

    + "%n",name);

    } finally{

    if(output !=null)

    output.close();

    if(file != null)

    file.close();

    }

    }

    public void storeSpreadSheet (String name) throws IOException{

    String name_with_extention = name +".ser";

    File f = new File(name_with_extention);

    if(f.exists()){

    System.out.printf("File already exists. Press: %n Y to overwrite %n "

    + "C to cancel %n N to save in another file name"

    + "%nEnter Choice:");

    Scanner c = new Scanner(System.in);

    String choice = c.nextLine();

    choice = choice.toUpperCase();

    switch (choice){

    case "Y": saveFile(f,name);

    break;

    case "N": name = c.nextLine();

    f = new File(name+".ser");

    saveFile(f,name);

    break;

    case "C": break;

    default : System.out.println("Not a valid choice");

    break;

    }

    }else {

    saveFile(f,name);

    }

    }

    public void loadFile(File f, String name) throws IOException{

    FileInputStream file = null;

    ObjectInputStream input = null;

    try{

    file = new FileInputStream(f);

    input = new ObjectInputStream(file);

    sheet_array.add((Sheet)input.readObject());

    this.selectWorkSheet(name);

    System.out.format("Spreadsheet \"%s\" loaded form disk "

    + "successfully.%n",name);

    }catch ( FileNotFoundException | ClassNotFoundException e){

    e.printStackTrace();

    }finally{

  • 32 | P a g e

    if(input != null)

    input.close();

    if(file !=null)

    file.close();

    }

    }

    public void loadSpreadSheet(String name) throws IOException {

    String name_with_extention = name +".ser";

    File f = new File(name_with_extention);

    Sheet temp;

    if(f.exists()){

    if(!isAlreadyOpened(name)){

    loadFile(f,name);

    }else{

    System.out.printf("A file with the same name is already open. "

    + "Press:%n O to open above it %n Enter C to cancel"

    + "%n Enter Choice: ");

    Scanner c = new Scanner(System.in);

    String choice = c.nextLine();

    choice = choice.toUpperCase();

    switch (choice){

    case "O": sheet_array.remove(opened_file_index);

    loadFile(f,name);

    break;

    case "C": break;

    default : System.out.println("Not a valid choice");

    }

    }

    }else {

    System.out.println("Incorrect File name. File doesn't exist!");

    }

    }

    }

    ////////////////////////////////////////////////////////////////////

    package Week14;

    import java.io.IOException;

    public class TestApp {

    Application app = new Application();

    public void test_enter_data(){

    app.worksheet.cell_set.addData("A1" , 10.5);app.worksheet.cell_set.addData("A2" , 20.5);app.worksheet.cell_set.addData("A3", "=A1+0.5");

    app.worksheet.cell_set.addData("B1" , "Mad");app.worksheet.cell_set.addData("B2" , "aloalo");app.worksheet.cell_set.addData("B3" , "nana");

    app.worksheet.cell_set.addData("C1" , 10.56);app.worksheet.cell_set.addData("C2" , 20.34);app.worksheet.cell_set.addData("C3" , 30.56);

    app.worksheet.cell_set.addData("D1" , 10.67);app.worksheet.cell_set.addData("D2" , 20.34);app.worksheet.cell_set.addData("D3" , 30);

    app.worksheet.cell_set.addData("E1" , 10);app.worksheet.cell_set.addData("E2" , 20.11);app.worksheet.cell_set.addData("E3" , 30.778);

  • 33 | P a g e

    app.worksheet.cell_set.addData("F1", "=SUM(C1:E3)");app.worksheet.cell_set.addData("F2" , 20.11);app.worksheet.cell_set.addData("F3" , 30.778);

    }

    public void test_edit_data(){

    app.worksheet.cell_set.addData("A1", 16.88);

    app.worksheet.cell_set.addData("C1", 1000);

    /*app.worksheet.cell_set.selectRange("C1", "B3");

    app.worksheet.cell_set.copyRange();

    app.worksheet.cell_set.pasteRange("E1");

    app.worksheet.cell_set.addData("B1", "askldlnkjnkj");

    app.worksheet.cell_set.deleteRange();*/

    }

    public static void main(String args[]) throws IOException {

    TestApp test = new TestApp();

    test.app.createSpreadSheet("sheet1");

    test.app.selectWorkSheet("sheet1");

    test.test_enter_data();

    test.app.showData(3, 6);

    test.test_edit_data();

    test.app.showData(3, 6);

    }

    }