|
|
using System;
using ut;
public class testFormula
{
// Next - start on parsing expressions
public void testConstantFormula()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=7");
utx.assert("Formula", "=7", sheet.getLiteral("A1"));
utx.assert("Value", "7", sheet.get("A1"));
}
// More formula tests. You may feel the need to make up
// additional intermediate test cases to drive your code
// better. (For example, you might want to test "2*3"
// before "2*3*4".) That's fine, go ahead and create them.
// Just keep moving one test at a time.
// Order of tests - I'm familiar enough with parsing to think
// it's probably better to do them in this order (highest
// precedence to lowest). For extra credit, you might redo
// this part of the exercise with the tests in a different order
// to see what difference it makes.
public void testParentheses()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=(7)");
utx.assert("Parens", "7", sheet.get("A1"));
}
public void testDeepParentheses()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=((((10))))");
utx.assert("Parends", "10", sheet.get("A1"));
}
public void testMultiply()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=2*3*4");
utx.assert("Times", "24", sheet.get("A1"));
}
public void testAdd()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=71+2+3");
utx.assert("Add", "76", sheet.get("A1"));
}
public void testPrecedenceA()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=2*3+5");
utx.assert("Precedence", "11", sheet.get("A1"));
}
public void testPrecedenceB()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=2*(3+5)");
utx.assert("Precedence", "16", sheet.get("A1"));
}
public void testPrecedenceC()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=2+3*5");
utx.assert("Precedence", "17", sheet.get("A1"));
}
public void testPrecedenceD()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=(2+3)*5");
utx.assert("Precedence", "25", sheet.get("A1"));
}
public void testPrecedence1()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=2*3+7");
utx.assert("Precedence", "13", sheet.get("A1"));
}
public void testPrecedence2()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=7+2*3");
utx.assert("Precedence", "13", sheet.get("A1"));
}
public void testPrecedence3()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=7*(2+3)");
utx.assert("Expr", "35", sheet.get("A1"));
}
public void testPrecedence4()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=7*(2+3*4)");
utx.assert("Expr", (7*(2+3*4)).ToString(), sheet.get("A1"));
}
public void testPrecedence5()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=7*((2+3)*4)");
utx.assert("Expr", "140", sheet.get("A1"));
}
public void testPrecedence6()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=(7*2)+3");
utx.assert("Expr", "17", sheet.get("A1"));
}
public void testFullExpression1()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=((((2+1))))");
utx.assert("Expr", "3", sheet.get("A1"));
}
public void testFullExpression2()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=(2+3)*((((2+1))))");
utx.assert("Expr", "15", sheet.get("A1"));
}
public void testFullExpression()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=7*(2+3)*((((2+1))))");
utx.assert("Expr", "105", sheet.get("A1"));
}
// // Then try your hand at a few test cases: Add "-" and "/"
// // with normal precedence.
public void testPrecedenceSD1()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=12/3-1");
utx.assert("Precedence", "3", sheet.get("A1"));
}
public void testPrecedenceSD2()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=6-12/3");
utx.assert("Precedence", "2", sheet.get("A1"));
}
public void testPrecedenceSD3()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=12/(3-1)");
utx.assert("Expr", "6", sheet.get("A1"));
}
public void testPrecedenceSD4()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=(12-6)/3");
utx.assert("Expr", "2", sheet.get("A1"));
}
public void testFullExpression3()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=8*(2+3)/((2+1-1))");
utx.assert("Expr", (8*(2+3)/((2+1-1))).ToString(), sheet.get("A1"));
}
// Next, error handling.
public void testSimpleFormulaError()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=7*");
utx.assert("Error", "#Error", sheet.get("A1"));
}
public void testParenthesisError1()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=((7))))");
utx.assert("Error", "#Error", sheet.get("A1"));
}
public void testParenthesisError()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=(((((7))");
utx.assert("Error", "#Error", sheet.get("A1"));
}
// Add any more error cases you need. Numeric errors (e.g.,
// divide by 0) can return #Error too.
public void testMissingOperand()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=+");
utx.assert("Error", "#Error", sheet.get("A1"));
}
public void testMissingOperand2()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=5+");
utx.assert("Error", "#Error", sheet.get("A1"));
}
public void testMissingOperand3()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=+5+");
utx.assert("Error", "#Error", sheet.get("A1"));
}
public void testExtraOperand1()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=5+++5");
utx.assert("Error", "#Error", sheet.get("A1"));
}
public void testMiscError1()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=5+(");
utx.assert("Error", "#Error", sheet.get("A1"));
}
public void testMiscError2()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=(");
utx.assert("Error", "#Error", sheet.get("A1"));
}
public void testMiscError3()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=)");
utx.assert("Error", "#Error", sheet.get("A1"));
}
public void testMiscError4()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=7G");
utx.assert("Error", "#Error", sheet.get("A1"));
}
public void testMiscError5()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=7+)");
utx.assert("Error", "#Error", sheet.get("A1"));
}
public void testMiscError6()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=++");
utx.assert("Error", "#Error", sheet.get("A1"));
}
public void testMiscError7()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=5 7");
utx.assert("Error", "#Error", sheet.get("A1"));
}
public void testMiscError8()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=5(7");
utx.assert("Error", "#Error", sheet.get("A1"));
}
public void testMiscError9()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=5 (7");
utx.assert("Error", "#Error", sheet.get("A1"));
}
public void testMiscError10()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=7=");
utx.assert("Error", "#Error", sheet.get("A1"));
}
public void testMiscError11()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=7!");
utx.assert("Error", "#Error", sheet.get("A1"));
}
public void testDivision()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=5/2");
utx.assert("integer dic", "2", sheet.get("A1"));
}
public void testDivisionByZero()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=5/0");
utx.assert("div by 0", "#Error", sheet.get("A1"));
}
public void testBigNumber1()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=" + Int32.MaxValue.ToString());
utx.assert("big", "2147483647", sheet.get("A1"));
}
public void testBigNumber1A()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=" + Int32.MaxValue.ToString() + "+0");
utx.assert("big", "2147483647", sheet.get("A1"));
}
public void testBigNumber1B()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=" + Int32.MaxValue.ToString() + "+1");
utx.assert("big", "#Error", sheet.get("A1"));
}
public void testBigNumber2()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=2147483648");
utx.assert("big", "#Error", sheet.get("A1"));
}
public void testBigNumber2A()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=2147483648+0");
utx.assert("big", "#Error", sheet.get("A1"));
}
public void testBigNumber3()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=2147483649");
utx.assert("big", "#Error", sheet.get("A1"));
}
public void testBigNumber3A()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=2147483649+0");
utx.assert("big", "#Error", sheet.get("A1"));
}
public void testOverflow1()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=2147483646+1");
utx.assert("overflow", "2147483647", sheet.get("A1"));
}
public void testOverflow2()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=2147483647+0");
utx.assert("overflow", "2147483647", sheet.get("A1"));
}
public void testOverflow3()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=2147483647+1");
utx.assert("overflow", "#Error", sheet.get("A1"));
}
public void testOverflow4()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=2147483647+2");
utx.assert("overflow", "#Error", sheet.get("A1"));
}
public void testUnderflow1()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=0-2147483647-0");
utx.assert("underflow", "-2147483647", sheet.get("A1"));
}
public void testUnderflow2()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=0-2147483647-1");
utx.assert("underflow", "-2147483648", sheet.get("A1"));
}
public void testUnderflow3()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=0" + (Int32.MinValue + 1).ToString() + "-1");
utx.assert("underflow", "-2147483648", sheet.get("A1"));
}
public void testUnderflow4()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=0-2147483648-1");
utx.assert("underflow", "#Error", sheet.get("A1"));
}
public void testUnderflow5()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=0" + Int32.MinValue.ToString() + "-1");
utx.assert("underflow", "#Error", sheet.get("A1"));
}
public void testUnderflow6()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=" + Int32.MinValue.ToString() + "-2");
utx.assert("underflow", "#Error", sheet.get("A1"));
}
public void testEmbeddedBlanks1()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=5+ 3");
utx.assert("blanks", "8", sheet.get("A1"));
}
public void testEmbeddedBlanks2()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=5+ 3 ");
utx.assert("blanks", "8", sheet.get("A1"));
}
public void testEmbeddedBlanks3()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=5 + 3 ");
utx.assert("blanks", "8", sheet.get("A1"));
}
public void testEmbeddedBlanks4()
{
Sheet sheet = new Sheet();
sheet.put("A1", "= 5 + 3 ");
utx.assert("blanks", "8", sheet.get("A1"));
}
public void testLeadingBlanks()
{
Sheet sheet = new Sheet();
sheet.put("A1", "= 5");
utx.assert("blanks", "5", sheet.get("A1"));
}
public void testTrailingBlanks()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=5 ");
utx.assert("blanks", "5", sheet.get("A1"));
}
}
|
|
|
using System;
using ut;
public class testReferences
{
//We're going to add dependencies now. This is one of those things that
//makes a spreadsheet a spreadsheet.
public void testThatCellReferenceWorks ()
{
Sheet sheet = new Sheet();
sheet.put("A1", "8");
sheet.put("A2", "=A1");
utx.assert("cell lookup", "8", sheet.get("A2"));
}
public void testThatCellChangesPropagate ()
{
Sheet sheet = new Sheet();
sheet.put("A1", "8");
sheet.put("A2", "=A1");
utx.assert("cell lookup", "8", sheet.get("A2"));
sheet.put("A1", "9");
utx.assert("cell change propagation", "9", sheet.get("A2"));
}
public void testThatFormulasKnowCellsAndRecalculate ()
{
Sheet sheet = new Sheet();
sheet.put("A1", "8");
sheet.put("A2", "3");
sheet.put("B1", "=A1*(A1-A2)+A2/3");
utx.assert("calculation with cells", "41", sheet.get("B1"));
sheet.put("A2", "6");
utx.assert("re-calculation", "18", sheet.get("B1"));
}
public void testThatDeepPropagationWorks ()
{
Sheet sheet = new Sheet();
sheet.put("A1", "8");
sheet.put("A2", "=A1");
sheet.put("A3", "=A2");
sheet.put("A4", "=A3");
utx.assert("deep propagation", "8", sheet.get("A4"));
sheet.put("A2", "6");
utx.assert("deep re-calculation", "6", sheet.get("A4"));
}
// The following test is likely to pass already.
public void testThatFormulaWorksWithManyCells ()
{
Sheet sheet = new Sheet();
sheet.put("A1", "10");
sheet.put("A2", "=A1+B1");
sheet.put("A3", "=A2+B2");
sheet.put("A4", "=A3");
sheet.put("B1", "7");
sheet.put("B2", "=A2");
sheet.put("B3", "=A3-A2");
sheet.put("B4", "=A4+B3");
utx.assert("multiple expressions - A4", "34", sheet.get("A4"));
utx.assert("multiple expressions - B4", "51", sheet.get("B4"));
}
// Just like errors return a special value, it might be nice
// if circular references did too. (See notes below).
public void testThatCircularReferencesAdmitIt ()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=A1");
utx.assert("Detect circularity", "#Circular", sheet.get("A1"));
}
public void testCircularReference()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=A2");
sheet.put("A2", "=A3");
sheet.put("A3", "=A1");
utx.assert("Detect circularity", "#Circular", sheet.get("A1"));
}
public void testMultiReference()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=A2+A3");
sheet.put("A2", "=A3+A3");
sheet.put("A3", "=5");
utx.assert("multiple references", "15", sheet.get("A1"));
}
public void testCircRef2()
{
Sheet sheet = new Sheet();
sheet.put("A1", "=A2");
sheet.put("A2", "=A1");
utx.assert("#Circular", sheet.get("A2"));
}
}
|
|
|
using System;
using ut;
public class testSheetTableModel
{
Sheet sheet;
TableModel table;
int LAST_COLUMN_INDEX = 49;
int LAST_ROW_INDEX = 99;
public void setup()
{
sheet = new Sheet();
table = new SheetTableModel(sheet);
}
public void testTableModelRequiredOverrides()
{
setup();
utx.assert(table.getColumnCount() > LAST_COLUMN_INDEX);
utx.assert(table.getRowCount() > LAST_ROW_INDEX);
utx.assert("", table.getValueAt(10,10));
}
public void testColumnNames()
{
setup();
utx.assert ("", TableModel.getColumnName(0));
utx.assert ("A", TableModel.getColumnName(1));
utx.assert ("Z", TableModel.getColumnName(26));
utx.assert ("AA", TableModel.getColumnName(27));
utx.assert ("AW", TableModel.getColumnName(LAST_COLUMN_INDEX));
}
public void testThatColumn0ContainsIndex()
{
setup();
utx.assert ("1", table.getValueAt(0,0));
utx.assert ("50", table.getValueAt(49, 0));
utx.assert ("100", table.getValueAt(LAST_ROW_INDEX,0));
}
public void testThatMainColumnsHaveContents1()
{
setup();
sheet.put ("A1", "upper left");
utx.assert ("upper left", table.getValueAt(0,1));
}
public void testThatMainColumnsHaveContents2()
{
setup();
sheet.put ("A100", "lower left");
utx.assert ("lower left", table.getValueAt(LAST_ROW_INDEX, 1));
}
public void testThatMainColumnsHaveContents3()
{
setup();
sheet.put ("AW1", "upper right");
utx.assert ("upper right", table.getValueAt(0, LAST_COLUMN_INDEX));
}
public void testThatMainColumnsHaveContents4()
{
setup();
sheet.put ("AW100", "lower right");
utx.assert ("lower right", table.getValueAt(LAST_ROW_INDEX, LAST_COLUMN_INDEX));
}
public void testThatStoresWorkThroughTableModel()
{
setup();
table.setValueAt("21", 0, 1);
table.setValueAt("=A1", 1, 1);
utx.assert("21", table.getValueAt(0,1));
utx.assert("21", table.getValueAt(1,1));
table.setValueAt("22", 0, 1);
utx.assert("22", table.getValueAt(0,1));
utx.assert("22", table.getValueAt(1,1));
}
// We've established that the table model can get and set values.
// But JTable uses an event notification mechanism to find out
// about the changes.
// To test this, we'll introduce a test helper class. It's a very
// simple listener, and will assure us that notifications are
// sent when changes are made.
// There's a couple of design decisions implicit here. One is that
// we won't attempt to be specific about which cells change; we'll
// just say that the table data has changed and let JTable refresh
// its view of whichever cells it wants. (Because of cell
// dependencies, changes in one cell could potentially no others,
// all others, or anything in between.) We might revisit this
// decision during performance tuning, and try to issue
// finer-grained notifications.
// The other decision is that we have no mechanism for our Sheet
// to tell the table model about changes. So changes will either
// need to come in through the table model, or we'll have to
// add some notification mechanism to Sheet. For now, just
// make changes through the table model.
public class TestTableModelListener: TableModelListener
{
public bool wasNotified = false;
public override void TableChanged(TableModelEvent e)
{
wasNotified = true;
}
}
public void testThatTableModelNotifies()
{
setup();
TestTableModelListener listener = new TestTableModelListener();
table.addTableModelListener (listener);
utx.assert (!listener.wasNotified);
table.setValueAt("22", 0, 1);
utx.assert (listener.wasNotified);
}
// Note the cast in our test here. Previous tests have been
// straight implementations of TableModel functions; now
// we're saying that our model has some extra functions. We'll
// face a small tradeoff later when we want access to the feature:
// if we get the model back from JTable, we'll have to cast it;
// if we don't want to cast it we'll have to track it somewhere.
public void testThatSheetTableModelCanGetLiteral()
{
setup();
sheet.put("A1", "=7");
String contents = ((SheetTableModel)table).getLiteralValueAt(0, 1);
utx.assert("=7", contents);
}
}
|
|
|
using System;
using System.Windows.Forms;
using ut;
//--------------------------
class testSpreadSheet
{
//--------------------------
static void Main(string[] args)
{
Application.Run(new SheetFrame(new SheetTableModel(new Sheet())));
}
// One of the first XPlorations articles I wrote was to address
// the question, "Can you do a GUI test-first?" My answer there
// was, "Yes, but..." and this exercise might lead you to the
// same opinion.
//
// Today's goal is to make a simple GUI that looks sort of like this:
//
// +--------+---------------+------+
// | Label | Text entry | OK |
// +--------+---------------+------+
// |^ |
// || Grid (JTable) |
// |v |
// +-------------------------------+
//
//
// The idea is that if you click in the grid, the label tells
// which cell you're in, and the text entry field contains the
// literal value of that cell. You can edit it, and when you click
// "OK", it puts the value back in the cell. Then the whole
// spreadsheet updates accordingly. With this, you should have
// a minimalist but working spreadsheet.
//
// Quick Design
// I'll put everything in a subclass of JFrame, using the Swing
// objects JLabel, JTextField, JButton, and JTable. In my frame,
// I'll have public variables for each of these components
// (exposed for testing purposes). (I won't bother exposing
// intermediate panels or other things not important outside
// the class.)
//
// Most of the problem will be setup and hookup. I'll want to hook
// the table to the model, and set up listeners so that the
// label and textfield know when the selection has changed.
// I'll need a listener on the ok button to tell when to update
// the grid with the edited value. And all these objects have
// various configuration options to set up as well.
// Challenge Tests
//@@@@@@@@@@@@@@@@@@@@@@@@@ YOU ARE HERE
Sheet sheet;
TableModel table;
SheetTableModel model; // New for part 5
SheetFrame frame; // New for part 5
public void setUp()
{
sheet = new Sheet();
table = new SheetTableModel (sheet);
model = new SheetTableModel(sheet);
frame = new SheetFrame(model);
}
public void testThatFrameHasRightParts ()
{
setUp();
utx.assertnot(frame.table, null);
utx.assertnot(frame.label, null);
utx.assertnot(frame.editor, null);
utx.assertnot(frame.okButton, null);
utx.assert(model, frame.table.getModel());
}
public void testThatRowAndColumnSelectionAllowed()
{
setUp();
utx.assert(frame.table.getRowSelectionAllowed());
utx.assert(frame.table.getColumnSelectionAllowed());
}
public class TestSelectionListener : ListSelectionListener
{
public bool wasNotified = false;
public ListSelectionEvent lastEvent;
public void ValueChanged(ListSelectionEvent e)
{
wasNotified = true;
lastEvent = e;
}
}
public void testThatSelectionsNotifyListeners()
{
setUp();
TestSelectionListener listener = new TestSelectionListener();
frame.table.getSelectionModel().addListSelectionListener(listener);
utx.assert(!listener.wasNotified);
frame.table.changeSelection (3, 2, false, false);
utx.assert(listener.wasNotified);
utx.assert(3, listener.lastEvent.Row);
utx.assert(2, listener.lastEvent.Column);
listener.wasNotified = false;
frame.table.changeSelection (1, 1, false, false);
utx.assert (listener.wasNotified);
utx.assert(1, listener.lastEvent.Row);
utx.assert(1, listener.lastEvent.Column);
}
// If you need info on hooking up a selection listener, see
// http://java.sun.com/docs/books/tutorial/uiswing/components/table.html#selection
public void testThatLabelIsUpdatedWhenSelectionChanges()
{
setUp();
utx.assert("", frame.label.Text);
frame.table.changeSelection (0, 1, false, false);
utx.assert("A1", frame.label.Text);
frame.table.changeSelection (10, 10, false, false);
utx.assert("J11", frame.label.Text);
}
public void testThatEditorSeesLiteralValue()
{
model.setValueAt("=7", 1, 1);
frame.table.changeSelection(1,1,false,false);
utx.assert("=7", frame.editor.Text);
}
// We would like to have a way to programmatically let the
// text field click "Enter", but I don't see a mechanism.
// So we'll use the okButton instead.
public void testThatEditedValueGetsSaved()
{
setUp();
model.setValueAt("=7", 1, 1);
frame.table.changeSelection(1,1,false,false);
frame.editor.Text = "=8";
frame.okButton.doClick();
utx.assert("=8", frame.model.getLiteralValueAt(1,1));
utx.assert("8", frame.model.getValueAt(1,1));
}
public void testThatValuePropagationWorks ()
{
setUp();
frame.model.setValueAt("7", 0,1);
frame.model.setValueAt("=A1+2", 2,2);
utx.assert("9", frame.model.getValueAt(2,2));
utx.assert("=A1+2", frame.model.getLiteralValueAt(2,2));
frame.model.setValueAt("10", 0,1);
utx.assert("12", frame.model.getValueAt(2,2));
}
// See discussion below on acceptance tests.
public void testAcceptanceTest1()
{
setUp();
SheetTableModel model;
SheetFrame frame;
model = new SheetTableModel(new Sheet());
frame = new SheetFrame(model);
frame.table.changeSelection(0,1,false,false); // A1
frame.editor.Text = "8";
frame.okButton.doClick();
frame.table.changeSelection(1,1,false,false); // A2
frame.editor.Text = "=A1*A1+A1";
frame.okButton.doClick();
utx.assert("72", frame.model.getValueAt(1,1));
frame.table.changeSelection(0,1,false,false); // A1
frame.editor.Text ="5";
frame.okButton.doClick();
utx.assert("30", frame.model.getValueAt(1,1));
}
//DISCUSSION
//What I've found is that GUI testing works "ok" for some
// things but there tends not to be an easy way to do
// other things. For example, I didn't see an easy way to
// programmatically click "Enter" in the edited box. (I know
// you can set up a Robot and fool around with events,
// but I wasn't willing to try that hard today.) Another example
// is the difficulty of dealing with pop-up menus, tooltips,
// dialogs, etc.
//
// The other problem I have is that I just don't think of everything
// important without actually seeing the GUI grow. So even if I use test-
// first, I'll mix it with running the application and seeing how it
// looks. (For example, we didn't address column widths, or seriously
// look at what happens when you select multiple cells, and my solution
// doesn't leave the grid element selected after an edit.)
//
// I try to keep the GUI work limited to direct setup and hookup of
// objects. It can be very tempting to say "oh, this is GUI so I don't
// need to test it," but don't over-do that. Make sure that the GUI is
// not making application-level or algorithmic decisions.
//
// I do sometimes end up creating programmatic acceptance tests,
// like the last test. I try to minimize my need for these
// because they're a fair bit of work to program, and the
// customer can't really look at them and verify them. In
// this case, the test checks the hookup, which is ok. But
// for other spreadsheet tests, I might automate something
}
|
|
|
using System;
using ut;
public class testNonFormula
{
//--------------------------
public void test1A_EmptyCells()
{
Sheet sheet = new Sheet();
utx.assert("", sheet.get("A1"));
utx.assert("", sheet.get("ZX347"));
}
//--------------------------
public void test1B_TextCells()
{
Sheet sheet = new Sheet();
String theCell = "A21";
sheet.put(theCell, "A string");
utx.assert("A string", sheet.get(theCell));
sheet.put(theCell, "A different string");
utx.assert("A different string", sheet.get(theCell));
sheet.put(theCell, "");
utx.assert("", sheet.get(theCell));
}
//--------------------------
public void test1C_NumericCells()
{
Sheet sheet = new Sheet();
String theCell = "A21";
sheet.put(theCell, "X99"); // "Obvious" string
utx.assert("X99", sheet.get(theCell));
sheet.put(theCell, "14"); // "Obvious" number
utx.assert("14", sheet.get(theCell));
sheet.put(theCell, " 99 X"); // Whole string must be numeric
utx.assert(" 99 X", sheet.get(theCell));
sheet.put(theCell, " 1234 "); // Blanks ignored
utx.assert("1234", sheet.get(theCell));
sheet.put(theCell, " "); // Just a blank
utx.assert(" ", sheet.get(theCell));
}
public void test1D_LiteralValues()
{
Sheet sheet = new Sheet();
String theCell = "A21";
sheet.put(theCell, "Some string");
utx.assert("Some string", sheet.getLiteral(theCell));
sheet.put(theCell, " 1234 ");
utx.assert(" 1234 ", sheet.getLiteral(theCell));
sheet.put(theCell, "=7"); // Foreshadowing formulas:)
utx.assert("=7", sheet.getLiteral(theCell));
}
public void testManyCells()
{
Sheet sheet = new Sheet();
sheet.put("A1", "8");
sheet.put("X27", "10");
sheet.put("ZX901", "4");
utx.assert("A1", "8", sheet.get("A1"));
utx.assert("X27", "10", sheet.get("X27"));
utx.assert("ZX901", "4", sheet.get("ZX901"));
sheet.put("A1", "12");
utx.assert("A1 after", "12", sheet.get("A1"));
utx.assert("X27 same", "10", sheet.get("X27"));
utx.assert("ZX901 same", "4", sheet.get("ZX901"));
}
public void testFormulaSpec()
{
Sheet sheet = new Sheet();
sheet.put("B1", " =7"); // note leading space
utx.assert("Not a formula", " =7", sheet.get("B1"));
utx.assert("Unchanged", " =7", sheet.getLiteral("B1"));
}
}
|
|
|
using System;
//--------------------------
public class BadFormula : System.ApplicationException
{
public BadFormula() {}
}
|
|
|
using System;
using System.Collections;
using System.Text.RegularExpressions;
//--------------------------
class Calculator
{
private string myFormula;
private OperatorStack myOperators = new OperatorStack();
private OperandStack myOperands = new OperandStack();
private CellMatrix myMatrix;
private ArrayList myPrevReferences;
//--------------------------
public Calculator(string theFormula, CellMatrix theMatrix, ArrayList thePrevCells)
{
myFormula = theFormula;
myMatrix = theMatrix;
myPrevReferences = thePrevCells;
}
//--------------------------
public string parse()
{
InputString theInputString = new InputString(myFormula.Substring(1)); //strip off the '='
for(theInputString.reset(); !theInputString.end(); theInputString.next())
{
if (theInputString.isValidOperand())
handle(theInputString.theOperand(myMatrix, myPrevReferences));
else
handle(theInputString.theOperator());
}
evaluateUntilOperatorStackIsEmpty();
if (myOperands.Count() != 1) throw new BadFormula();
return myOperands.Pop().asString();
}
//--------------------------
private void handle(Operand theOperand)
{
myOperands.Push(theOperand);
}
//--------------------------
private void handle(Operator theOperator)
{
if (theOperator.isOpenParens())
myOperators.Push(theOperator);
else if (theOperator.isCloseParens())
evaluateUntilMatchingParensFound();
else
evaluateUntilLowerPrecedenceOperatorFound(theOperator);
}
//--------------------------
private void evaluateUntilMatchingParensFound()
{
while (myOperators.isNotEmpty())
{
if (myOperators.topIsOpenParens()) break;
evaluate();
}
myOperators.Pop();
}
//--------------------------
private void evaluateUntilLowerPrecedenceOperatorFound(Operator theOperator)
{
while (myOperators.isNotEmpty())
{
if (myOperators.precedenceIsLessThan(theOperator)) break;
evaluate();
}
myOperators.Push(theOperator);
}
//--------------------------
private void evaluateUntilOperatorStackIsEmpty()
{
while(myOperators.isNotEmpty())
evaluate();
}
//--------------------------
private void evaluate()
{
//must use temporaries to guarentee order of the Pops!
Operand aRightOperand = myOperands.Pop();
Operand aLeftOperand = myOperands.Pop();
myOperands.Push(myOperators.Pop().evaluate(aLeftOperand, aRightOperand));
}
}
|
|
|
using System;
using System.Collections;
//--------------------------
public abstract class Cell
{
static public Cell Null = new StringCell("", "");
protected string myAddress = "";
protected string myLiteralValue = "";
protected string myValue = "";
static public Cell factory(string theAddress, string theValue, CellMatrix theMatrix)
{
if (isNumeric(theValue))
return new NumericCell(theAddress, theValue);
if (isFormula(theValue))
return new FormulaCell(theAddress, theValue, theMatrix);
return new StringCell(theAddress, theValue);
}
//--------------------------
public abstract string displayValue();
public abstract string calculatedValue(ArrayList thePrevCells);
//--------------------------
public string literalValue()
{
return myLiteralValue;
}
//--------------------------
static private bool isFormula(string theValue)
{
return theValue.StartsWith("=");
}
//--------------------------
static private bool isNumeric(string theValue)
{
bool rc = true;
try
{
Int32.Parse(theValue);
}
catch(FormatException /*ex*/)
{
rc = false;
}
return rc;
}
//--------------------------
private class FormulaCell : Cell
{
CellMatrix myMatrix;
//--------------------------
public FormulaCell(string theAddress, string theValue, CellMatrix theMatrix)
{
myValue = theValue;
myLiteralValue = theValue;
myMatrix = theMatrix;
myAddress = theAddress;
}
//--------------------------
public override string displayValue()
{
ArrayList aList = new ArrayList();
string aResult;
try
{
aResult = evaluate(myValue, myMatrix, aList);
}
catch(DivideByZeroException)
{
aResult = "#Error";
}
catch(OverflowException)
{
aResult = "#Error";
}
catch(BadFormula)
{
aResult = "#Error";
}
catch(CircularReference)
{
aResult = "#Circular";
}
return aResult;
}
//--------------------------
public override string calculatedValue(ArrayList thePrevCells)
{
if (thePrevCells.Contains(myAddress)) throw new CircularReference();
thePrevCells.Add(myAddress);
// {
// Console.WriteLine("myaddr=" + myAddress + " val='" + myValue + "' start-->");
// int count = 1;
// foreach (string addr in thePrevCells )
// {
// Console.WriteLine(count + ": " + addr );
// count++;
// }
// Console.WriteLine("<--end");
// }
string s = evaluate(myValue, myMatrix, thePrevCells);
// Console.WriteLine(" val='"+myValue+"' evals to:" + s);
return s;
}
//--------------------------
private string evaluate(string theFormula, CellMatrix theMatrix, ArrayList thePrevCells)
{
return new Calculator(theFormula, theMatrix, thePrevCells).parse();
}
}
//--------------------------
private class NumericCell : Cell
{
//--------------------------
public NumericCell(string theAddress, string theValue)
{
myValue = theValue.Trim();
myLiteralValue = theValue;
myAddress = theAddress;
}
//--------------------------
public override string displayValue()
{
return myValue;
}
public override string calculatedValue(ArrayList thePrevCells)
{
return myValue;
}
}
//--------------------------
private class StringCell : Cell
{
//--------------------------
public StringCell(string theAddress, string theValue)
{
myValue = theValue;
myLiteralValue = theValue;
myAddress = theAddress;
}
//--------------------------
public override string displayValue()
{
return myValue;
}
public override string calculatedValue(ArrayList thePrevCells )
{
return myValue;
}
}
}
|
|
|
using System;
using System.Collections;
//--------------------------
public class CellMatrix
{
private Hashtable myHash = new Hashtable();
public CellMatrix()
{
}
//--------------------------
public void put(string theAddress, string theValue)
{
myHash[theAddress] = Cell.factory(theAddress, theValue, this);
}
//--------------------------
public Cell get(string theAddress)
{
return myHash.ContainsKey(theAddress) ? (Cell) myHash[theAddress] : Cell.Null;
}
//--------------------------
public void dump()
{
int count = 1;
for (IEnumerator e = myHash.Keys.GetEnumerator(); e.MoveNext(); )
{
string anAddr = (string) e.Current;
Cell c = (Cell) myHash[anAddr];
Console.WriteLine(count + ": " + anAddr + " : '" + c.literalValue().ToString() + "' -> '" + c.displayValue() + "'");
count++;
}
}
}
|
|
|
using System;
//--------------------------
public class CircularReference : System.ApplicationException
{
public CircularReference() {}
}
|
|
|
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 273);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
}
#endregion
private void Form1_Load(object sender, System.EventArgs e)
{
}
}
|
|
|
using System;
using System.Collections;
using System.Text.RegularExpressions;
//--------------------------
class InputString
{
private string myString;
private int myIndex;
//--------------------------
public InputString(string theString)
{
myString = theString;
reset();
}
//--------------------------
public Operator theOperator()
{
return new Operator(myString[myIndex]);
}
//--------------------------
public bool isValidOperand()
{
string aValue = thePossibleOperand();
return aValue.Length > 0;
}
//--------------------------
public Operand theOperand(CellMatrix theMatrix, ArrayList thePrevRefs)
{
string aValue = thePossibleOperand();
skip(aValue.Length - 1);
return Operand.factory(aValue, theMatrix, thePrevRefs);
}
//--------------------------
public void reset()
{
myIndex = 0;
}
//--------------------------
public bool end()
{
return myIndex >= myString.Length;
}
//--------------------------
public void next()
{
skip(1);
}
//--------------------------
private void skip(int theCount)
{
myIndex += theCount;
}
//--------------------------
private string thePossibleOperand()
{
Regex re = new Regex("^\\s*([A-Z]*[0-9]+)\\s*");
return re.Match(myString.Substring(myIndex)).Value;
}
}
|
|
|
using System;
using System.Collections;
//------------------------------------------------
public class ListSelectionEvent
{
private int myRow = 0;
private int myCol = 0;
public ListSelectionEvent(int row, int col)
{
myRow = row;
myCol = col;
}
public int Row
{
get
{
return myRow;
}
}
public int Column
{
get
{
return myCol;
}
}
}
//------------------------------------------------
public interface ListSelectionListener
{
void ValueChanged(ListSelectionEvent e);
}
//------------------------------------------------
public class ListSelectionModel
{
private int myRow = 0;
private int myCol = 0;
private ArrayList myListeners = new ArrayList();
public void addListSelectionListener(ListSelectionListener l)
{
myListeners.Add(l);
}
public void changeSelection(int row, int col)
{
myRow = row;
myCol = col;
Notify();
}
public void Notify()
{
foreach (ListSelectionListener listener in myListeners)
{
ListSelectionEvent e = new ListSelectionEvent(myRow, myCol);
((ListSelectionListener)listener).ValueChanged(e);
}
}
}
|
|
|
using System;
using System.Collections;
using System.Text.RegularExpressions;
//--------------------------
public abstract class Operand
{
//--------------------------
public static Operand factory(string theString, CellMatrix theMatrix, ArrayList thePrevRefs)
{
if (isReference(theString))
return new ReferenceOperand(theString, theMatrix, thePrevRefs);
return new NumericOperand(Int32.Parse(theString));
}
//--------------------------
public static Operand factory(int theValue)
{
return new NumericOperand(theValue);
}
//--------------------------
private static bool isReference(string theString)
{
Regex re = new Regex("^([A-Z]+)");
return re.Match(theString).Value.Length > 0;
}
//--------------------------
public Operand multipliedBy(Operand theOther)
{
return Operand.factory(asInt() * theOther.asInt());
}
//--------------------------
public Operand dividedBy(Operand theOther)
{
return Operand.factory(asInt() / theOther.asInt());
}
//--------------------------
public Operand addedTo(Operand theOther)
{
int aValue = asInt() + theOther.asInt();
if (asInt() > 0 && theOther.asInt() > 0 && aValue < 0) throw new System.OverflowException();
return Operand.factory(aValue);
}
//--------------------------
public Operand subtractedFrom(Operand theOther)
{
return Operand.factory(asInt() - theOther.asInt());
}
//--------------------------
protected abstract int asInt();
public abstract string asString();
//--------------------------
private class NumericOperand : Operand
{
private int myOperand;
public NumericOperand(int theValue)
{
myOperand = theValue;
}
//--------------------------
protected override int asInt()
{
return myOperand;
}
//--------------------------
public override string asString()
{
return myOperand.ToString();
}
}
//--------------------------
private class ReferenceOperand : Operand
{
private string myStringValue;
private string myRefAddress;
private CellMatrix myMatrix;
ArrayList myPrevReferences;
//--------------------------
public ReferenceOperand(string theAddress, CellMatrix theMatrix, ArrayList thePrevRefs)
{
myRefAddress = theAddress;
myStringValue = theAddress;
myMatrix = theMatrix;
myPrevReferences = thePrevRefs;
}
//--------------------------
protected override int asInt()
{
return Int32.Parse(asString());
}
//--------------------------
public override string asString()
{
return myMatrix.get(myRefAddress).calculatedValue(new ArrayList(myPrevReferences));
}
}
}
|
|
|
using System;
using System.Collections;
//--------------------------
class OperandStack
{
private Stack myStack = new Stack();
//--------------------------
public OperandStack()
{
}
//--------------------------
public void Push(Operand theOperand)
{
myStack.Push(theOperand);
}
//--------------------------
public Operand Pop()
{
if (isEmpty()) throw new BadFormula();
return (Operand) myStack.Pop();
}
//--------------------------
bool isEmpty()
{
return Count() == 0;
}
//--------------------------
public int Count()
{
return myStack.Count;
}
}
|
|
|
using System;
using System.Text.RegularExpressions;
//--------------------------
class Operator
{
private char myOperator;
//--------------------------
public Operator(char c)
{
myOperator = c;
}
//--------------------------
public bool isOpenParens()
{
return myOperator == '(';
}
//--------------------------
public bool isCloseParens()
{
return myOperator == ')';
}
//--------------------------
public int precedence()
{
switch(myOperator)
{
case '*' :
case '/' : return 3;
case '+' :
case '-' : return 2;
case '(' : return 1;
default: return 0;
}
}
//--------------------------
public Operand evaluate(Operand theLeftOperand, Operand theRightOperand)
{
switch(myOperator)
{
case '*' : return theLeftOperand.multipliedBy(theRightOperand);
case '/' : return theLeftOperand.dividedBy(theRightOperand);
case '+' : return theLeftOperand.addedTo(theRightOperand);
case '-' : return theLeftOperand.subtractedFrom(theRightOperand);
default : throw new BadFormula();
}
}
}
|
|
|
using System;
using System.Collections;
//--------------------------
class OperatorStack
{
private Stack myStack = new Stack();
//--------------------------
public OperatorStack()
{
}
//--------------------------
public bool isNotEmpty()
{
return !isEmpty();
}
//--------------------------
bool isEmpty()
{
return myStack.Count == 0;
}
//--------------------------
public Operator Pop()
{
if (isEmpty()) throw new BadFormula();
return (Operator) myStack.Pop();
}
//--------------------------
public void Push(Operator theOperator)
{
myStack.Push(theOperator);
}
//--------------------------
public bool topIsOpenParens()
{
return ((Operator) myStack.Peek()).isOpenParens();
}
//--------------------------
public bool precedenceIsLessThan(Operator theOther)
{
return ((Operator) myStack.Peek()).precedence() < theOther.precedence();
}
}
|
|
|
using System;
//--------------------------
public class Sheet
{
private CellMatrix mySheet = new CellMatrix();
//--------------------------
public Sheet()
{
}
//--------------------------
public void dump()
{
mySheet.dump();
}
//--------------------------
public string get(string theAddress)
{
return mySheet.get(theAddress).displayValue();
}
//--------------------------
public string getLiteral(string theAddress)
{
return mySheet.get(theAddress).literalValue();
}
//--------------------------
public void put(string theAddress, string theValue)
{
mySheet.put(theAddress,theValue);
}
}
|
|
|
using System;
using System.Drawing;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
public class MyButton : Button
{
public void doClick()
{
this.OnClick(new System.EventArgs());
}
}
public class SheetFrame : Form, ListSelectionListener
{
private SheetTableModel myTableModel;
private MyButton myOK;
private Label myLabel;
private TextBox myEditor;
private Table myTable;
public SheetFrame(SheetTableModel m)
{
myTableModel = m;
myOK = new MyButton();
myLabel = new Label();
myEditor = new TextBox();
myTable = new Table(myTableModel);
((System.ComponentModel.ISupportInitialize)(myTable)).BeginInit();
SuspendLayout();
myLabel.Text = "";
myLabel.Name = "myLabel";
myLabel.Size = new System.Drawing.Size(72, 24);
myLabel.TabIndex = 0;
Controls.Add(myLabel);
myEditor.Location = new System.Drawing.Point(72, 0);
myEditor.Name = "myEditor";
myEditor.Size = new System.Drawing.Size(168, 20);
myEditor.TabIndex = 1;
myEditor.Text = "";
Controls.Add(myEditor);
myOK.Location = new System.Drawing.Point(248, 0);
myOK.Name = "myOK";
myOK.TabIndex = 4;
myOK.Text = "OK";
//myOK.DialogResult = DialogResult.OK;
myOK.Click += new EventHandler(myOK_Click);
Controls.Add(myOK);
myTable.Bind();
myTable.HeaderForeColor = System.Drawing.SystemColors.ControlText;
myTable.Location = new System.Drawing.Point(0, 24);
myTable.Name = "SpreadSheet";
myTable.Size = new System.Drawing.Size(590, 264);
myTable.TabIndex = 3;
myTable.getSelectionModel().addListSelectionListener(this);
myTable.CurrentCellChanged += new EventHandler(myTable_CurCellChange);
Controls.Add(myTable);
AutoScaleBaseSize = new System.Drawing.Size(5, 13);
ClientSize = new System.Drawing.Size(600, 300);
Name = "SheetFrame";
Text = "SpreadSheet";
Load += new System.EventHandler(Form1_Load);
((System.ComponentModel.ISupportInitialize)(myTable)).EndInit();
ResumeLayout(false);
}
private void Form1_Load(object sender, System.EventArgs e)
{
}
private void myOK_Click(object sender, System.EventArgs e)
{
myTableModel.setValueAt(myEditor.Text, myLabel.Text);
}
private void myTable_CurCellChange(object sender, System.EventArgs e)
{
myTable.changeSelection();
}
public void ValueChanged(ListSelectionEvent e)
{
string addr = TableModel.ToAddress(e.Row, e.Column);
myLabel.Text = addr;
myEditor.Text = myTableModel.getLiteralValueAt(e.Row, e.Column);
}
public MyButton okButton
{
get
{
return myOK;
}
}
public Label label
{
get
{
return myLabel;
}
}
public TextBox editor
{
get
{
return myEditor;
}
}
public Table table
{
get
{
return myTable;
}
}
public SheetTableModel model
{
get
{
return myTableModel;
}
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.myLabel = new System.Windows.Forms.Label();
this.myEditor = new System.Windows.Forms.TextBox();
//this.myOK = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.myTable)).BeginInit();
this.SuspendLayout();
//
// myLabel
//
this.myLabel.Name = "myLabel";
this.myLabel.Size = new System.Drawing.Size(72, 24);
this.myLabel.TabIndex = 0;
//
// myTable
//
this.myTable.DataMember = "";
this.myTable.HeaderForeColor = System.Drawing.SystemColors.ControlText;
this.myTable.Location = new System.Drawing.Point(0, 24);
this.myTable.Name = "myTable";
this.myTable.Size = new System.Drawing.Size(344, 264);
this.myTable.TabIndex = 2;
//
// myEditor
//
this.myEditor.Location = new System.Drawing.Point(72, 0);
this.myEditor.Name = "myEditor";
this.myEditor.Size = new System.Drawing.Size(168, 20);
this.myEditor.TabIndex = 3;
this.myEditor.Text = "";
//
// myOK
//
this.myOK.Location = new System.Drawing.Point(248, 0);
this.myOK.Name = "myOK";
this.myOK.TabIndex = 4;
this.myOK.Text = "OK";
//
// SheetFrame
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(336, 273);
this.Controls.AddRange(new System.Windows.Forms.Control[] {
this.myOK,
this.myEditor,
this.myTable,
this.myLabel});
this.Name = "SheetFrame";
this.Text = "SpreadSheet";
this.Load += new System.EventHandler(this.Form1_Load);
((System.ComponentModel.ISupportInitialize)(this.myTable)).EndInit();
this.ResumeLayout(false);
}
#endregion
}
|
|
|
using System;
public class SheetTableModel : TableModel
{
Sheet mySheet;
public SheetTableModel(Sheet theSheet)
{
mySheet = theSheet;
}
public override string getValueAt(int row, int col)
{
if (col == 0) return (row+1).ToString();
return mySheet.get(ToAddress(row, col));
}
public override void setValueAt(string value, int row, int col)
{
if (col == 0) throw new ArgumentException();
setValueAt(value, ToAddress(row, col));
}
public void setValueAt(string value, string address)
{
mySheet.put(address, value);
Notify();
}
public string getLiteralValueAt(int row, int col)
{
if (col == 0) return (row+1).ToString();
return mySheet.getLiteral(ToAddress(row, col));
}
}
|
|
|
using System;
using System.Collections;
using System.Windows.Forms;
//------------------------------------------------
public class Table : DataGrid
{
private SheetTableModel myModel;
private ListSelectionModel mySelectionModel = new ListSelectionModel();
public Table(SheetTableModel m)
{
myModel = m;
}
public void Bind()
{
myModel.BindTo(this);
}
public SheetTableModel getModel()
{
return myModel;
}
public bool getRowSelectionAllowed() {return true;}
public bool getColumnSelectionAllowed() {return true;}
public ListSelectionModel getSelectionModel()
{
return mySelectionModel;
}
public void changeSelection (int row, int col, bool b1, bool b2)
{
mySelectionModel.changeSelection(row, col);
}
public void changeSelection ()
{
mySelectionModel.changeSelection(this.CurrentCell.RowNumber, this.CurrentCell.ColumnNumber);
}
}
|
|
|
using System;
using System.Data;
using System.Collections;
using System.Windows.Forms;
//------------------------------------------------
public class TableModelEvent
{
}
//------------------------------------------------
public abstract class TableModelListener
{
public abstract void TableChanged(TableModelEvent e);
}
//------------------------------------------------
public abstract class TableModel
{
private DataSet myDataSet;
private ArrayList myListeners = new ArrayList();
static public string ToAddress(int row, int col)
{
return getColumnName(col) + (row+1).ToString();
}
static public string getColumnName(int col)
{
//col is one-based
string name = "";
col--; //make it zero based
while (col >= 0)
{
char c = (char) (col % 26 + (int) 'A');
name = c + name;
col = (col / 26) - 1;
}
return name;
}
public int getColumnCount()
{
return 100;
}
public int getRowCount()
{
return 100;
}
public abstract string getValueAt(int row, int col);
public abstract void setValueAt(string value, int row, int col);
public void Notify()
{
foreach (TableModelListener listener in myListeners)
{
TableModelEvent e = new TableModelEvent();
((TableModelListener)listener).TableChanged(e);
}
}
public void addTableModelListener(TableModelListener listener)
{
myListeners.Add(listener);
}
public void BindTo(Table dg)
{
int maxcols = 10;//27 * 26 + 10;
int maxrows = 9;
DataTable aTable = new DataTable("ParentTable");
myDataSet = new DataSet();
myDataSet.Tables.Add(aTable);
dg.SetDataBinding(myDataSet,"ParentTable");
DataGridTableStyle aTableStyle = new DataGridTableStyle();
aTableStyle.MappingName = "ParentTable";
aTableStyle.ColumnHeadersVisible = true;
aTableStyle.RowHeadersVisible = false;
aTableStyle.AllowSorting = false;
// aTableStyle.SelectionBackColor = System.Drawing.Color.LightGray;
// aTableStyle.SelectionForeColor = System.Drawing.Color.AliceBlue;
MakeColumns(aTableStyle, aTable, maxcols);
dg.TableStyles.Add(aTableStyle);
for(int row = 0; row < maxrows; ++row)
{
DataRow myDataRow = aTable.NewRow();
myDataRow["-"] = (row+1).ToString();
for (int col = 1; col < maxcols; col++)
{
//myDataRow[getColumnName(col)] = "cell " + getColumnName(col) + (row+1);
myDataRow[getColumnName(col)] = getValueAt(row, col);
}
aTable.Rows.Add(myDataRow);
}
}
private void MakeColumns(DataGridTableStyle theTableStyle, DataTable theTable, int theNumCols)
{
MakeColumn0(theTableStyle, theTable);
for(int i = 1; i < theNumCols; ++i)
{
MakeColumn(theTableStyle, theTable, getColumnName(i));
}
}
private void MakeColumn(DataGridTableStyle theTableStyle, DataTable theTable, string theColName)
{
DataColumn aDataColumn = new DataColumn();
aDataColumn.DataType = System.Type.GetType("System.String");
aDataColumn.ColumnName = theColName;
aDataColumn.AutoIncrement = false;
aDataColumn.ReadOnly = false;
aDataColumn.Unique = false;
theTable.Columns.Add(aDataColumn);
DataGridColumnStyle aColumnStyle = new DataGridTextBoxColumn();
aColumnStyle.MappingName = theColName;
aColumnStyle.HeaderText = theColName;
theTableStyle.GridColumnStyles.Add(aColumnStyle);
}
private void MakeColumn0(DataGridTableStyle theTableStyle, DataTable theTable)
{
DataColumn aDataColumn = new DataColumn();
aDataColumn.DataType = System.Type.GetType("System.Int32");
aDataColumn.ColumnName = "-";
aDataColumn.AutoIncrement = false;
aDataColumn.ReadOnly = true;
aDataColumn.Unique = true;
theTable.Columns.Add(aDataColumn);
DataGridColumnStyle aColumnStyle = new DataGridTextBoxColumn();
aColumnStyle.MappingName = "-";
aColumnStyle.ReadOnly = true;
aColumnStyle.Width = 20;
theTableStyle.GridColumnStyles.Add(aColumnStyle);
}
}
|