21#include "dependencies.h"
25#include "kspread_cell.h"
26#include "kspread_sheet.h"
32#define CELLCHUNK_ROWS 128
33#define CELLCHUNK_COLS 16
41 DependencyList (Sheet *s);
42 ~DependencyList () { reset (); };
47 void cellChanged (
const Point &cell);
50 void generateDependencies (
const Point &cell);
52 void generateDependencies (
const Range &range);
54 void generateDependencies (
const RangeList &rangeList);
57 void processDependencies (
const Point &cell);
59 void processDependencies (
const Range &range);
61 void processDependencies (
const RangeList &rangeList);
66 TQValueList<Point> getDependants (
const Point &cell);
68 void areaModified (
const TQString &name);
71 void addDependency (
const Point &cell1,
const Point &cell2);
75 void removeDependencies (
const Point &cell);
78 void processRangeDependencies (
const Point &cell);
81 void processRangeDependencies (
const Range &range);
84 void updateCell (
const Point &cell)
const;
90 TQValueList<Point> leadingCells (
const Range &range)
const;
94 TQValueList<Point> getCellDeps(
const Point& cell)
const {
95 CellDepsMap::const_iterator it = cellDeps.find( cell );
96 return it == cellDeps.end() ? TQValueList<Point>() : *it;
106 TQMap<Point, RangeList> dependencies;
108 typedef TQMap<Point, TQValueList<Point> > CellDepsMap;
109 CellDepsMap cellDeps;
111 TQMap<Point, TQValueList<RangeDependency> > rangeDeps;
113 TQMap<TQString, TQMap<Point, bool> > areaDeps;
122void DependencyList::dump()
124 TQMap<Point, RangeList>::const_iterator it = dependencies.begin();
125 for ( ; it != dependencies.end(); ++it ) {
127 kdDebug() <<
"Cell " << p.sheetName() <<
" " << p.pos()
128 <<
" depends on :" << endl;
130 TQValueList<Point>::const_iterator itp = rl.cells.begin();
131 for ( ; itp != rl.cells.end(); ++itp )
132 kdDebug() <<
" cell " << (*itp).pos() << endl;
133 TQValueList<Range>::const_iterator itr = rl.ranges.begin();
134 for ( ; itr != rl.ranges.end(); ++itr )
135 kdDebug() <<
" range " << (*itr).toString() << endl;
138 CellDepsMap::const_iterator cit = cellDeps.begin();
139 for ( ; cit != cellDeps.end(); ++cit )
142 kdDebug() <<
"The cells that depend on " << p.sheetName() <<
" " << p.pos()
144 TQValueList<Point>::const_iterator itp = (*cit).begin();
145 for ( ; itp != (*cit).end(); ++itp )
146 kdDebug() <<
" cell " << (*itp).pos() << endl;
153 deps =
new DependencyList (s);
169 deps->cellChanged (cell);
174 deps->generateDependencies (range);
175 deps->processDependencies (range);
180 deps->generateDependencies (rangeList);
181 deps->processDependencies (rangeList);
186 deps->areaModified (name);
191 return deps->getDependencies (cell);
196 return deps->getDependants (cell);
199DependencyList::DependencyList (Sheet *s)
204void DependencyList::reset ()
206 dependencies.clear();
211void DependencyList::cellChanged (
const Point &cell)
213 Cell *c = cell.cell();
220 if (c->testFlag (Cell::Flag_CircularCalculation))
224 if ( !(c->testFlag (Cell::Flag_Progress)))
225 generateDependencies (cell);
227 processDependencies (cell);
234 if (!dependencies.contains (cell))
238 return dependencies[cell];
241TQValueList<Point> DependencyList::getDependants (
const Point &cell)
244 TQValueList<Point> list = getCellDeps( cell );
246 Point leading = leadingCell (cell);
247 TQValueList<RangeDependency>::iterator it;
248 if (!rangeDeps.count (leading))
251 for (it = rangeDeps[leading].begin();
252 it != rangeDeps[leading].end(); ++it)
256 if ((*it).range.contains (cell))
259 c.setRow ((*it).cellrow);
260 c.setColumn ((*it).cellcolumn);
269void DependencyList::areaModified (
const TQString &name)
275 if (!areaDeps.contains (name))
278 TQMap<Point, bool>::iterator it;
279 for (it = areaDeps[name].begin(); it != areaDeps[name].end(); ++it)
281 Cell *c = it.key().cell();
288void DependencyList::addDependency (
const Point &cell1,
292 Sheet *sh = cell2.sheet();
296 dependencies[cell1].cells.push_back (cell2);
297 sh->dependencies()->deps->cellDeps[cell2].push_back (cell1);
303 Sheet *sh = rd.range.sheet();
308 cell.setSheet (rd.cellsheet);
309 cell.setRow (rd.cellrow);
310 cell.setColumn (rd.cellcolumn);
311 dependencies[cell].ranges.push_back (rd.range);
313 TQValueList<Point> leadings = leadingCells (rd.range);
314 TQValueList<Point>::iterator it;
315 for (it = leadings.begin(); it != leadings.end(); ++it)
316 sh->dependencies()->deps->rangeDeps[*it].push_back (rd);
320 areaDeps[rd.range.
namedArea()][cell] =
true;
323void DependencyList::removeDependencies (
const Point &cell)
326 if (!dependencies.contains (cell))
330 TQValueList<Point> cells = dependencies[cell].cells;
331 TQValueList<Point>::iterator it1;
332 for (it1 = cells.begin(); it1 != cells.end(); ++it1)
335 Sheet *sh = (*it1).sheet();
339 if (!sh->dependencies()->deps->cellDeps.contains (*it1))
343 TQValueList<Point>::iterator cit;
344 cit = sh->dependencies()->deps->cellDeps[*it1].find (cell);
345 if (cit != sh->dependencies()->deps->cellDeps[*it1].end())
346 sh->dependencies()->deps->cellDeps[*it1].erase (cit);
350 TQValueList<Range> ranges = dependencies[cell].ranges;
351 TQValueList<Range>::iterator it2;
352 TQValueList<Point> leads;
353 for (it2 = ranges.begin(); it2 != ranges.end(); ++it2)
357 TQValueList<Point> leadings = leadingCells (*it2);
358 for (it1 = leadings.begin(); it1 != leadings.end(); ++it1)
359 if (!leads.contains (*it1))
360 leads.push_back (*it1);
362 for (it1 = leads.begin(); it1 != leads.end(); ++it1)
365 Sheet *sh = (*it1).sheet();
369 if (sh->dependencies()->deps->rangeDeps.contains (*it1))
371 TQValueList<RangeDependency>::iterator it3;
372 it3 = sh->dependencies()->deps->rangeDeps[*it1].begin();
374 while (it3 != sh->dependencies()->deps->rangeDeps[*it1].end())
375 if (((*it3).cellrow == cell.
row()) &&
376 ((*it3).cellcolumn == cell.
column()))
377 it3 = sh->dependencies()->deps->rangeDeps[*it1].erase (it3);
381 if (sh->dependencies()->deps->rangeDeps[*it1].empty())
382 sh->dependencies()->deps->rangeDeps.erase (*it1);
387 TQMap<TQString, TQMap<Point, bool> >::iterator itr;
388 for (itr = areaDeps.begin(); itr != areaDeps.end(); ++itr) {
389 if (itr.data().contains (cell))
390 itr.data().remove (cell);
394 dependencies[cell].cells.clear();
395 dependencies[cell].ranges.clear();
396 dependencies.erase (cell);
399void DependencyList::generateDependencies (
const Point &cell)
402 removeDependencies (cell);
412 RangeList rl = computeDependencies (cell);
416 TQValueList<Point>::iterator it1;
417 TQValueList<Range>::iterator it2;
419 for (it1 = rl.cells.begin(); it1 != rl.cells.end(); ++it1)
420 addDependency (cell, *it1);
421 for (it2 = rl.ranges.begin(); it2 != rl.ranges.end(); ++it2)
424 rd.cellrow = cell.
row();
425 rd.cellcolumn = cell.
column();
426 rd.cellsheet = sheet;
429 if (rd.range.sheet() == 0)
432 addRangeDependency (rd);
436void DependencyList::generateDependencies (
const Range &range)
438 for (
int row = range.startRow(); row <= range.endRow(); row++)
439 for (
int col = range.startCol(); col <= range.endCol(); col++)
445 generateDependencies (c);
449void DependencyList::generateDependencies (
const RangeList &rangeList)
451 TQValueList<Point>::const_iterator it1;
452 TQValueList<Range>::const_iterator it2;
454 for (it1 = rangeList.cells.begin(); it1 != rangeList.cells.end(); ++it1)
455 generateDependencies (*it1);
456 for (it2 = rangeList.ranges.begin(); it2 != rangeList.ranges.end(); ++it2)
457 generateDependencies (*it2);
460void DependencyList::processDependencies (
const Point &cell)
462 const TQValueList<Point> d = getCellDeps(cell);
463 TQValueList<Point>::const_iterator it = d.begin();
464 const TQValueList<Point>::const_iterator end = d.end();
465 for (; it != end; ++it)
468 processRangeDependencies (cell);
471void DependencyList::processRangeDependencies (
const Point &cell)
473 Point leading = leadingCell (cell);
474 if (!rangeDeps.count (leading))
477 const TQValueList<RangeDependency> rd = rangeDeps[leading];
479 TQValueList<RangeDependency>::const_iterator it;
480 for (it = rd.begin(); it != rd.end(); ++it)
484 if ((*it).range.contains (cell))
487 c.setRow ((*it).cellrow);
488 c.setColumn ((*it).cellcolumn);
495void DependencyList::processDependencies (
const Range &range)
499 for (
int row = range.startRow(); row <= range.endRow(); row++)
500 for (
int col = range.startCol(); col <= range.endCol(); col++)
507 const TQValueList<Point> d = getCellDeps(c);
508 TQValueList<Point>::const_iterator it = d.begin();
509 const TQValueList<Point>::const_iterator end = d.end();
510 for (; it != end; ++it)
514 processRangeDependencies (range);
517void DependencyList::processRangeDependencies (
const Range &range)
524 TQValueList<Point> leadings = leadingCells (range);
525 TQValueList<Point>::iterator it;
526 for (it = leadings.begin(); it != leadings.end(); ++it)
528 if (!rangeDeps.count (*it))
530 TQValueList<RangeDependency>::iterator it2;
531 for (it2 = rangeDeps[*it].begin(); it2 != rangeDeps[*it].end(); ++it2)
535 if ((*it2).range.intersects (range))
538 c.setRow ((*it2).range.startRow());
539 c.setColumn ((*it2).range.startCol());
547void DependencyList::processDependencies (
const RangeList &rangeList)
549 TQValueList<Point>::const_iterator it1;
550 TQValueList<Range>::const_iterator it2;
552 for (it1 = rangeList.cells.begin(); it1 != rangeList.cells.end(); ++it1)
553 processDependencies (*it1);
554 for (it2 = rangeList.ranges.begin(); it2 != rangeList.ranges.end(); ++it2)
555 processDependencies (*it2);
558void DependencyList::updateCell (
const Point &cell)
const
560 Cell *c = cell.cell();
562 if (c->testFlag (Cell::Flag_Progress) ||
563 c->testFlag (Cell::Flag_CircularCalculation))
565 kdError(36001) <<
"ERROR: Circle, cell " << c->
fullName() <<
566 ", in dep.manager for sheet " << sheet->name() << endl;
572 if (!c->testFlag (Cell::Flag_CircularCalculation))
574 c->setFlag(Cell::Flag_CircularCalculation);
579 c->clearFlag (Cell::Flag_Progress);
583 c->setFlag (Cell::Flag_Progress);
592 c->clearFlag (Cell::Flag_Progress);
595Point DependencyList::leadingCell (
const Point &cell)
const
598 c.setRow (cell.
row() - cell.
row() % CELLCHUNK_ROWS + 1);
599 c.setColumn (cell.
column() - cell.
column() % CELLCHUNK_COLS + 1);
604TQValueList<Point> DependencyList::leadingCells (
const Range &range)
const
606 TQValueList<Point> cells;
607 Point cell1, cell2, cell;
609 cell1.setRow (range.startRow());
610 cell1.setColumn (range.startCol());
611 cell2.setRow (range.endRow());
612 cell2.setColumn (range.endCol());
616 cell1 = leadingCell (cell1);
617 cell2 = leadingCell (cell2);
618 for (
int row = cell1.row(); row <= cell2.row(); row += CELLCHUNK_ROWS)
619 for (
int col = cell1.column(); col <= cell2.column();
620 col += CELLCHUNK_COLS)
623 cell.setColumn (col);
624 cell.setSheet(range.sheet());
625 cells.push_back (cell);
630RangeList DependencyList::computeDependencies (
const Point &cell)
const
632 Cell *c = cell.cell();
647 kdDebug() <<
"Cell at row " << cell.
row() <<
", col " << cell.
column() <<
" marked as formula, but formula is NULL" << endl;
658 for(
unsigned i = 0; i < tokens.count(); i++ )
660 Token token = tokens[i];
666 TQString text = token.
text();
667 Point cell (text, sheet->workbook(), sheet);
669 rl.cells.push_back (cell);
673 TQString text = token.
text();
674 Range range (text, sheet->workbook(), sheet);
676 rl.ranges.push_back (range);
For every cell in the spread sheet there is a Cell object.
bool calc(bool delay=true)
Starts calculating.
int row() const
Returns the cell's row.
TQString fullName() const
Returns the full name of the cell, i.e.
const Value value() const
Returns the value that this cell holds.
Sheet * sheet() const
Returns the worksheet which owns this cell.
void setValue(const Value &value)
Sets the value for this cell.
int column() const
Returns the cell's column.
bool isFormula() const
Returns true if this cell holds a formula.
void setCalcDirtyFlag()
Set the calcDirtyFlag.
bool isDefault() const
Returns true if this is a default cell (with row and column equal to zero).
void cellChanged(const Point &cell)
handle the fact that cell's contents have changed
void areaModified(const TQString &name)
a named area was somehow modified
DependencyList * deps
local d-pointer
TQValueList< Point > getDependants(const Point &cell)
get cells depending on this cell, either through normal or range dependency
void rangeListChanged(const RangeList &rangeList)
handle the fact that a range list has been changed
RangeList getDependencies(const Point &cell)
get dependencies of a cell
~DependencyManager()
destructor
void reset()
clear all data
void rangeChanged(const Range &range)
handle the fact that a range has been changed
DependencyManager(Sheet *s)
constructor
Represents the position of a single cell in a workbook.
void setSheet(Sheet *sheet)
Sets the sheet which this point lies on.
Represents a region within a workbook.
bool isValid() const
Returns true if this Range represents a valid region of a spreadsheet.
void setSheet(Sheet *sheet)
Sets the Sheet object associated with this range.
TQString namedArea() const
Returns the named area represented by this range or an empty string otherwise.
TQString text() const
Returns text associated with the token.
Type type() const
Returns type of the token.
@ Cell
$A$1, F4, Sheet2!B5, 'Sales Forecast'!Sum
Class Tokens represents array of tokens.
Provides a wrapper for cell value.
void setError(const TQString &msg)
Sets this value to hold error message.
Range dependency - stores information about one dependency of one cell on one range of cells.
range-list and cell-list TODO: move to a separate file, improve structure, add iterators and all that...