#ifndef SPREAD_SHEET_CELL_H
#define SPREAD_SHEET_CELL_H
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
class Spreadsheet;
class SpreadsheetCell
{
public:
typedef enum {Red=1, Green, Blue, Yellow} Colors;
SpreadsheetCell& operator+=(const SpreadsheetCell& rhs);
SpreadsheetCell& operator-=(const SpreadsheetCell& rhs);
SpreadsheetCell& operator*=(const SpreadsheetCell& rhs);
SpreadsheetCell& operator/=(const SpreadsheetCell& rhs);
const SpreadsheetCell operator-() const;
SpreadsheetCell(double initialValue = 0.0);
explicit SpreadsheetCell(const string& initialValue);
SpreadsheetCell(const SpreadsheetCell& src);
SpreadsheetCell& operator=(const SpreadsheetCell& rhs);
void set(double inValue);
void set(const string& inString);
void setColor(Colors color);
double getValue() const;
string getString() const;
const SpreadsheetCell operator+(const SpreadsheetCell& cell) const;
const SpreadsheetCell operator+(double rhs) const;
SpreadsheetCell& operator++(); //Prefix
SpreadsheetCell& operator--(); //Prefix
SpreadsheetCell operator++(int); //Postfix
SpreadsheetCell operator--(int); //Postfix
friend class Spreadsheet;
//Supply the friend method is not a good idea, it will break the encapsulation.
friend bool checkSpreadsheetCell(const SpreadsheetCell& cell);
friend const SpreadsheetCell operator+(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs);
friend const SpreadsheetCell operator-(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs);
friend const SpreadsheetCell operator*(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs);
friend const SpreadsheetCell operator/(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs);
friend bool operator==(const SpreadsheetCell& lhs,const SpreadsheetCell& rhs);
friend bool operator<(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs);
friend bool operator>(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs);
friend bool operator!=(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs);
friend bool operator<=(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs);
friend bool operator>=(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs);
friend ostream& operator<<(std::ostream& ostr, const SpreadsheetCell& cell);
friend istream& operator>>(std::istream& istr, SpreadsheetCell& cell);
protected:
static string doubleToString(double inValue);
static double stringToDouble(string inString);
double mValue;
string mString;
mutable int mNumAccesses;
Colors mColor;
};
#endif
Spreadsheet.h
#ifndef SPREAD_SHEET_H
#define SPREAD_SHEET_H
#include "SpreadsheetCell.h"
#include "SpreadsheetImpl.h"
class SpreadsheetApplication;
//class SpreadsheetImpl;
class Spreadsheet
{
public:
Spreadsheet(const SpreadsheetApplication& theApp, int inWidth, int inHeight);
~Spreadsheet();
Spreadsheet(const SpreadsheetApplication& theApp);
Spreadsheet(const Spreadsheet& src);
Spreadsheet& operator=(const Spreadsheet& rhs);
void setCellAt(int x, int y, const SpreadsheetCell& inCell);
SpreadsheetCell getCellAt(int x, int y);
int getId() const;
protected:
SpreadsheetImpl* mImpl;
};
#endif
#ifndef SPREAD_SHEET_IMPL_H
#define SPREAD_SHEET_IMPL_H
#include "SpreadsheetCell.h"
class SpreadsheetApplication;
class SpreadsheetImpl
{
public:
static const int kMaxHeight = 100;
static const int kMaxWidth = 100;
explicit SpreadsheetImpl(const SpreadsheetApplication& theApp,
int inWidth = kMaxWidth, int inHeight = kMaxHeight);
SpreadsheetImpl(const SpreadsheetImpl& src);
~SpreadsheetImpl();
SpreadsheetImpl& operator=(const SpreadsheetImpl& rhs);
void setCellAt(int x, int y, const SpreadsheetCell& inCell);
SpreadsheetCell getCellAt(int x, int y);
int getId() const;
private:
bool inRange(int val, int upper);
void copyFrom(const SpreadsheetImpl& src);
int mWidth, mHeight;
int mId;
SpreadsheetCell** mCells;
const SpreadsheetApplication& mTheApp;
static int sCounter;
};
#endif
#include "SpreadsheetCell.h"
SpreadsheetCell::SpreadsheetCell(double initialValue):
mValue(initialValue),mString(doubleToString(initialValue))
{
mNumAccesses =0;
mColor = Red;
}
SpreadsheetCell::SpreadsheetCell(const string& initialValue):
mValue(stringToDouble(initialValue)),mString(initialValue)
{
mNumAccesses =0;
mColor = Red;
}
SpreadsheetCell::SpreadsheetCell(const SpreadsheetCell& src)
:mValue(src.mValue),mString(src.mString)
{
mNumAccesses = src.mNumAccesses;
mColor = src.mColor;
}
SpreadsheetCell& SpreadsheetCell::operator=(const SpreadsheetCell& rhs)
{
if(this == &rhs)
{
return *this;
}
this->mValue = rhs.mValue;
this->mString = rhs.mString;
return *this;
}
void SpreadsheetCell::set(double inValue)
{
mValue = inValue;
mString = doubleToString(inValue);
}
void SpreadsheetCell::set(const string& inString)
{
mString = inString;
mValue = stringToDouble(inString);
}
double SpreadsheetCell::getValue() const
{
++mNumAccesses;
return mValue;
}
string SpreadsheetCell::getString() const
{
++mNumAccesses;
return mString;
}
string SpreadsheetCell::doubleToString(double inValue)
{
ostringstream ostr;
ostr << inValue;
return ostr.str();
}
double SpreadsheetCell::stringToDouble(string inString)
{
double temp;
istringstream istr(inString);
istr >> temp;
if (istr.fail() || !istr.eof())
{
return 0;
}
return temp;
}
void SpreadsheetCell::setColor(Colors color)
{
mColor = color;
}
const SpreadsheetCell SpreadsheetCell::operator+(const SpreadsheetCell& cell) const
{
SpreadsheetCell newCell;
newCell.set(cell.mValue + mValue);
return newCell;
}
const SpreadsheetCell SpreadsheetCell::operator+(double rhs) const
{
return SpreadsheetCell(mValue+rhs);
}
SpreadsheetCell& SpreadsheetCell::operator+=(const SpreadsheetCell& rhs)
{
set(mValue + rhs.mValue);
return *this;
}
SpreadsheetCell& SpreadsheetCell::operator-=(const SpreadsheetCell& rhs)
{
set(mValue - rhs.mValue);
return *this;
}
SpreadsheetCell& SpreadsheetCell::operator*=(const SpreadsheetCell& rhs)
{
set(mValue * rhs.mValue);
return *this;
}
SpreadsheetCell& SpreadsheetCell::operator/=(const SpreadsheetCell& rhs)
{
if (rhs.mValue == 0)
{
throw invalid_argument("Divide by zero.");
}
set(mValue / rhs.mValue);
return *this;
}
const SpreadsheetCell SpreadsheetCell::operator-() const
{
SpreadsheetCell newCell(*this);
newCell.set(-mValue);
return newCell;
}
SpreadsheetCell& SpreadsheetCell::operator++()
{
set(mValue+1);
return *this;
}
SpreadsheetCell& SpreadsheetCell::operator--()
{
set(mValue-1);
return *this;
}
SpreadsheetCell SpreadsheetCell::operator++(int)
{
SpreadsheetCell oldCell(*this);
set(mValue + 1);
return oldCell;
}
SpreadsheetCell SpreadsheetCell::operator--(int)
{
SpreadsheetCell oldCell(*this);
set(mValue - 1);
return oldCell;
}
ostream& operator<<(std::ostream& ostr, const SpreadsheetCell& cell)
{
ostr<<cell.mString;
return ostr;
}
istream& operator>>(std::istream& istr, SpreadsheetCell& cell)
{
string temp;
istr>>temp;
cell.set(temp);
return istr;
}
bool checkSpreadsheetCell(const SpreadsheetCell& cell)
{
return !(cell.mString.empty());
}
const SpreadsheetCell operator+(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs)
{
SpreadsheetCell newCell;
newCell.set(lhs.mValue + rhs.mValue); // update mValue and mString.
return newCell;
}
const SpreadsheetCell operator-(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs)
{
SpreadsheetCell newCell;
newCell.set(lhs.mValue - rhs.mValue); // update mValue and mString.
return newCell;
}
const SpreadsheetCell operator*(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs)
{
SpreadsheetCell newCell;
newCell.set(lhs.mValue * rhs.mValue); // update mValue and mString.
return newCell;
}
const SpreadsheetCell operator/(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs)
{
if (rhs.mValue == 0)
{
throw invalid_argument("Divide by zero.");
}
SpreadsheetCell newCell;
newCell.set(lhs.mValue / rhs.mValue); // update mValue and mString.
return newCell;
}
bool operator==(const SpreadsheetCell& lhs,const SpreadsheetCell& rhs)
{
return (lhs.mValue == rhs.mValue);
}
bool operator<(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs)
{
return (lhs.mValue < rhs.mValue);
}
bool operator>(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs)
{
return (lhs.mValue > rhs.mValue);
}
bool operator!=(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs)
{
return (lhs.mValue != rhs.mValue);
}
bool operator<=(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs)
{
return (lhs.mValue <= rhs.mValue);
}
bool operator>=(const SpreadsheetCell& lhs, const SpreadsheetCell& rhs)
{
return (lhs.mValue >= rhs.mValue);
}
Spreadsheet.cpp
#include "Spreadsheet.h"
Spreadsheet::Spreadsheet(const SpreadsheetApplication& theApp,
int inWidth, int inHeight)
{
mImpl = new SpreadsheetImpl(theApp, inWidth, inHeight);
}
Spreadsheet::~Spreadsheet()
{
delete mImpl;
mImpl = NULL;
}
Spreadsheet::Spreadsheet(const Spreadsheet& src)
{
mImpl = new SpreadsheetImpl(*(src.mImpl));
}
Spreadsheet& Spreadsheet::operator=(const Spreadsheet& rhs)
{
//mImpl = rhs.mImpl; // Incorrect assignment!
*mImpl = *(rhs.mImpl);
return *this;
}
void Spreadsheet::setCellAt(int x, int y, const SpreadsheetCell& inCell)
{
mImpl->setCellAt(x, y, inCell);
}
SpreadsheetCell Spreadsheet::getCellAt(int x, int y)
{
return mImpl->getCellAt(x, y);
}
int Spreadsheet::getId() const
{
return mImpl->getId();
}
#include "SpreadsheetImpl.h"
int SpreadsheetImpl::sCounter = 0;
SpreadsheetImpl::SpreadsheetImpl(const SpreadsheetApplication& theApp,
int inWidth, int inHeight):
mWidth(inWidth<kMaxWidth?inWidth:kMaxWidth),
mHeight(inHeight<kMaxHeight?inHeight:kMaxHeight),
mTheApp(theApp)
{
mId = sCounter++;
mCells = new SpreadsheetCell*[inWidth];
for(int i =0; i<inWidth; ++i)
{
mCells[i] = new SpreadsheetCell[inHeight];
}
}
SpreadsheetImpl::~SpreadsheetImpl()
{
for(int i=0; i<this->mWidth; ++i)
{
delete []this->mCells[i];
}
delete []this->mCells;
mCells = NULL;
}
SpreadsheetImpl::SpreadsheetImpl(const SpreadsheetImpl& src)
:mTheApp(src.mTheApp) //must initialized in the initializer list.
{
mId = sCounter++;
copyFrom(src);
}
SpreadsheetImpl& SpreadsheetImpl::operator=(const SpreadsheetImpl& rhs)
{
if(this == &rhs)
{
return *this;
}
for(int i =0; i<this->mWidth; ++i)
{
delete []this->mCells[i];
}
delete []this->mCells;
this->mCells = NULL;
copyFrom(rhs);
return *this;
}
void SpreadsheetImpl::copyFrom(const SpreadsheetImpl& src)
{
mWidth = src.mWidth;
mHeight = src.mHeight;
mCells = new SpreadsheetCell* [mWidth];
for (int i = 0; i < mWidth; i++)
{
mCells[i] = new SpreadsheetCell[mHeight];
}
for (int i = 0; i < mWidth; i++)
{
for (int j = 0; j < mHeight; j++)
{
mCells[i][j] = src.mCells[i][j];
}
}
}
void SpreadsheetImpl::setCellAt(int x, int y, const SpreadsheetCell& cell)
{
if(!inRange(x,mWidth) || !inRange(y, mHeight))
{
throw std::out_of_range("");
}
mCells[x][y] = cell;
}
SpreadsheetCell SpreadsheetImpl::getCellAt(int x, int y)
{
if(!inRange(x,mWidth) || !inRange(y, mHeight))
{
throw std::out_of_range("");
}
return mCells[x][y];
}
bool SpreadsheetImpl::inRange(int val, int upper)
{
if(val < upper)
{
return true;
}
return false;
}
int SpreadsheetImpl::getId() const
{
return mId;
}