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 <cutRange()>in class <CellSet> in the file <CS2012-P14-Code-110486D.java>) public void cutRange(){ copiedRange = new CellSet(s.endRow-s.startRow+1 , s.endCol-s.startCol+1); for(int i= s.startCol ; i<=s.endCol;i++){ for(int j= s.startRow;j<=s.endRow; j++){ if (this.table[j][i].getValue() instanceof String) copiedRange.table[j-s.startRow][i-s.startCol] = new Cell((String)this.table[j][i].getValue() , copiedRange); else if (this.table[j][i].getValue() instanceof Double) copiedRange.table[j-s.startRow][i-s.startCol] = new Cell((Double)this.table[j][i].getValue() , copiedRange); else copiedRange.table[j-s.startRow][i-s.startCol] = new Cell((Integer)this.table[j][i].getValue() , copiedRange); this.table[j][i] = null; } } }
There are two for loops in this method and those two for loops are used to iterate over the Cell array between the required ranges. Inside the inner for, two if- else clauses are used to determine the value of the data type inside the Cell and then they are assigned to the copiedRange CellSet. Since this is cut operation the line shown in bold in the code fragment is used to make relevent references null in the Cell array.
The implementation of the store spreadsheet operation in an Application was done as follows (the complete code was uploaded as the method <storeSpreadSheet (String name)>in class <Application> in the file <CS2012-P14-Code-110486D.java>)
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; 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 <change(String t)> in class <Cell> in the file <CS2012-P14-Code- 110486D.java>) 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;
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 <assign(double num)> in class <Cell> in the file <CS2012-P14-Code- 110486D.java>) 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:
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
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
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
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 <<constructor>> Cell( n: double , o : CellSet) <<constructor>> Cell( n: int , o : CellSet) <<constructor>> 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[] <<constructor>> 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)
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<Cell> 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;
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<=end[1];i++){ for(int j=start[0]; j<=end[0];j++){ String operandCellDataType = this.obj.table[j][i].dataType; setObservables(obj.table[j][i]); switch(operandCellDataType){ case "Integer": sum = sum + (double)this.obj.table[j][i].intNum; break; case "Double": sum = sum + this.obj.table[j][i].doubleNum; break; } } } assign(sum); 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"; }
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<=s.endCol;i++){ for(int j= s.startRow;j<=s.endRow; j++){ if (this.table[j][i].getValue() instanceof String) copiedRange.table[j-s.startRow][i-s.startCol] = new Cell((String)this.table[j][i].getValue() , copiedRange); else if (this.table[j][i].getValue() instanceof Double) copiedRange.table[j-s.startRow][i-s.startCol] = new Cell((Double)this.table[j][i].getValue() , copiedRange); else copiedRange.table[j-s.startRow][i-s.startCol] = new Cell((Integer)this.table[j][i].getValue() , copiedRange); this.table[j][i] = null; } } } public void copyRange(){ copiedRange = new CellSet(s.endRow-s.startRow+1 , s.endCol-s.startCol+1); for(int i= s.startCol ; i<=s.endCol;i++){ for(int j= s.startRow;j<=s.endRow; j++){ if (this.table[j][i].getValue() instanceof String) copiedRange.table[j-s.startRow][i-s.startCol] = new Cell((String)this.table[j][i].getValue() , copiedRange); else if (this.table[j][i].getValue() instanceof Double) copiedRange.table[j-s.startRow][i-s.startCol] = new Cell((Double)this.table[j][i].getValue() , copiedRange); else copiedRange.table[j-s.startRow][i-s.startCol] = new Cell((Integer)this.table[j][i].getValue() , copiedRange); //this.table[j][i] = null; } } } public void deleteRange(){ for(int i= s.startCol ; i<=s.endCol;i++){ for(int j= s.startRow;j<=s.endRow; j++){ this.table[j][i] = null; } } } public void pasteRange(String st){ int []start; 29 | P a g e
public int[] decodeCell(String code){ //method to get the row and col numbers int[] index = new int[2]; //1,2,3.... like that rows are named //A,B,C..... like that columns are named code = code.toUpperCase(); index[1] = (int)code.charAt(0) - 64; //column index[0] = Integer.parseInt(code.substring(1)); //row return index; } //editing data and adding data are done using same set of functions. public void addData(String cell , String t){ int []index = decodeCell(cell); if(cellPresent(index[0],index[1])) this.table[index[0]][index[1]].changeValue(t); else this.table[index[0]][index[1]] = new Cell(t, this); }
public void addData(String cell , int n){ int []index = decodeCell(cell); if(cellPresent(index[0],index[1])) this.table[index[0]][index[1]].changeValue(n); else this.table[index[0]][index[1]] = new Cell(n, this); } public void addData(String cell , double n){ int []index = decodeCell(cell); if(cellPresent(index[0],index[1])) this.table[index[0]][index[1]].changeValue(n); else this.table[index[0]][index[1]] = new Cell(n, this); } } //////////////////////////////////////////////////////////// package Week14;
import java.io.Serializable;
public class Sheet implements Serializable{ //include a CellSet and sheet properties protected String sheet_name = null; protected CellSet cell_set = null;
public class Application implements Serializable{ protected Sheet worksheet = null; private ArrayList<Sheet> 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 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<=numberOfRows;i++){ for(int j=1;j<=numberOfColumns;j++){ if(this.worksheet.cell_set.table[i][j] != null) this.worksheet.cell_set.table[i][j].show(); Else System.out.format("%-15s","No Cell"); } System.out.print("\n"); } System.out.println(""); } 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;