~ubuntu-branches/ubuntu/precise/koffice/precise

« back to all changes in this revision

Viewing changes to kspread/dependencies.cc

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2006-04-20 21:38:53 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20060420213853-j5lxluqvymxt2zny
Tags: 1:1.5.0-0ubuntu2
UbuntuĀ uploadĀ 

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
 
14
14
   You should have received a copy of the GNU Library General Public License
15
15
   along with this library; see the file COPYING.LIB.  If not, write to
16
 
   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17
 
   Boston, MA 02111-1307, USA.
 
16
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 
17
 * Boston, MA 02110-1301, USA.
18
18
*/
19
19
 
20
20
 
38
38
/** d-pointer of DependencyManager */
39
39
class DependencyList {
40
40
 public:
41
 
  DependencyList (KSpreadSheet *s);
 
41
  DependencyList (Sheet *s);
42
42
  ~DependencyList () { reset (); };
43
43
  /** clear internal structures */
44
44
  void reset ();
45
 
  
 
45
 
 
46
  /** handle the fact that a cell has been changed */
 
47
  void cellChanged (const Point &cell);
 
48
 
46
49
  /** generate list of dependencies of a cell */
47
 
  void generateDependencies (const KSpreadPoint &cell);
 
50
  void generateDependencies (const Point &cell);
48
51
  /** generate list of dependencies of a range */
49
 
  void generateDependencies (const KSpreadRange &range);
 
52
  void generateDependencies (const Range &range);
50
53
  /** generate list of dependencies of a range list */
51
54
  void generateDependencies (const RangeList &rangeList);
52
55
 
53
56
  /** update cells dependending on a given cell */
54
 
  void processDependencies (const KSpreadPoint &cell);
 
57
  void processDependencies (const Point &cell);
55
58
  /** update cells dependending on a cell in a given range */
56
 
  void processDependencies (const KSpreadRange &range);
 
59
  void processDependencies (const Range &range);
57
60
  /** update cells dependending on a given range-list */
58
61
  void processDependencies (const RangeList &rangeList);
59
62
 
60
63
  /** get dependencies of a cell */
61
 
  RangeList getDependencies (const KSpreadPoint &cell);
 
64
  RangeList getDependencies (const Point &cell);
62
65
  /** get cells depending on this cell, either through normal or range dependency */
63
 
  QValueList<KSpreadPoint> getDependants (const KSpreadPoint &cell);
 
66
  QValueList<Point> getDependants (const Point &cell);
64
67
 
65
 
 protected:
 
68
  void areaModified (const QString &name);
 
69
  protected:
66
70
  /** update structures: cell 1 depends on cell 2 */
67
 
  void addDependency (const KSpreadPoint &cell1, const KSpreadPoint &cell2);
 
71
  void addDependency (const Point &cell1, const Point &cell2);
68
72
  /** update structures: cell depends on a range */
69
73
  void addRangeDependency (const RangeDependency &rd);
70
74
  /** remove all dependencies of a cell */
71
 
  void removeDependencies (const KSpreadPoint &cell);
72
 
  
 
75
  void removeDependencies (const Point &cell);
 
76
 
73
77
  /** update all cells depending on a range containing this cell */
74
 
  void processRangeDependencies (const KSpreadPoint &cell);
 
78
  void processRangeDependencies (const Point &cell);
75
79
 
76
80
  /** update all cells depending on a range intersecting with this range */
77
 
  void processRangeDependencies (const KSpreadRange &range);
78
 
  
 
81
  void processRangeDependencies (const Range &range);
 
82
 
79
83
  /** update one cell due to changed dependencies */
80
 
  void updateCell (const KSpreadPoint &cell) const;
 
84
  void updateCell (const Point &cell) const;
81
85
 
82
86
  /** return a leading cell for a given cell (used to store range
83
87
  dependencies effectively) */
84
 
  KSpreadPoint leadingCell (const KSpreadPoint &cell) const;
 
88
  Point leadingCell (const Point &cell) const;
85
89
  /** list of leading cells of all cell chunks that this range belongs to */
86
 
  QValueList<KSpreadPoint> leadingCells (const KSpreadRange &range) const;
 
90
  QValueList<Point> leadingCells (const Range &range) const;
87
91
  /** retrieve a list of cells that a given cell depends on */
88
 
  RangeList computeDependencies (const KSpreadPoint &cell) const;
89
 
  
90
 
  /** KSpreadSheet whose dependencies are managed by this instance */
91
 
  KSpreadSheet *sheet;
92
 
  
 
92
  RangeList computeDependencies (const Point &cell) const;
 
93
 
 
94
  QValueList<Point> getCellDeps(const Point& cell) const {
 
95
      CellDepsMap::const_iterator it = cellDeps.find( cell );
 
96
      return it == cellDeps.end() ? QValueList<Point>() : *it;
 
97
  }
 
98
 
 
99
  /** debug */
 
100
  void dump();
 
101
 
 
102
  /** Sheet whose dependencies are managed by this instance */
 
103
  Sheet *sheet;
 
104
 
93
105
  /** dependencies of each cell */
94
 
  QMap<KSpreadPoint, RangeList> dependencies;
 
106
  QMap<Point, RangeList> dependencies;
95
107
  /** list of cells (but NOT ranges) that depend on a cell */
96
 
  QMap<KSpreadPoint, QValueList<KSpreadPoint> > cellDeps;
 
108
  typedef QMap<Point, QValueList<Point> > CellDepsMap;
 
109
  CellDepsMap cellDeps;
97
110
  /** all range dependencies splitted into cell-chunks (TODO: describe) */
98
 
  QMap<KSpreadPoint, QValueList<RangeDependency> > rangeDeps;
 
111
  QMap<Point, QValueList<RangeDependency> > rangeDeps;
 
112
  /** list of cells referencing a given named area */
 
113
  QMap<QString, QMap<Point, bool> > areaDeps;
99
114
};
100
115
 
101
 
}
 
116
} // namespace KSpread
102
117
 
103
118
using namespace KSpread;
104
119
 
105
 
DependencyManager::DependencyManager (KSpreadSheet *s)
 
120
// This is currently not called - but it's really convenient to call it from
 
121
// gdb or from debug output to check that everything is set up ok.
 
122
void DependencyList::dump()
 
123
{
 
124
  QMap<Point, RangeList>::const_iterator it = dependencies.begin();
 
125
  for ( ; it != dependencies.end(); ++it ) {
 
126
    Point p = it.key();
 
127
    kdDebug() << "Cell " << p.sheetName() << " " << p.pos()
 
128
              << " depends on :" << endl;
 
129
    RangeList rl = (*it);
 
130
    QValueList<Point>::const_iterator itp = rl.cells.begin();
 
131
    for ( ; itp != rl.cells.end(); ++itp )
 
132
      kdDebug() << "  cell " << (*itp).pos() << endl;
 
133
    QValueList<Range>::const_iterator itr = rl.ranges.begin();
 
134
    for ( ; itr != rl.ranges.end(); ++itr )
 
135
      kdDebug() << "  range " << (*itr).toString() << endl;
 
136
  }
 
137
 
 
138
  CellDepsMap::const_iterator cit = cellDeps.begin();
 
139
  for ( ; cit != cellDeps.end(); ++cit )
 
140
  {
 
141
    Point p = cit.key();
 
142
    kdDebug() << "The cells that depend on " << p.sheetName() << " " << p.pos()
 
143
              << " are :" << endl;
 
144
    QValueList<Point>::const_iterator itp = (*cit).begin();
 
145
    for ( ; itp != (*cit).end(); ++itp )
 
146
      kdDebug() << "  cell " << (*itp).pos() << endl;
 
147
  }
 
148
 
 
149
}
 
150
 
 
151
DependencyManager::DependencyManager (Sheet *s)
106
152
{
107
153
  deps = new DependencyList (s);
108
154
}
118
164
  deps->reset();
119
165
}
120
166
 
121
 
void DependencyManager::cellChanged (const KSpreadPoint &cell)
 
167
void DependencyManager::cellChanged (const Point &cell)
122
168
{
123
 
  KSpreadCell *c = cell.cell();
124
 
  
125
 
  // empty or default cell? do nothing
126
 
  if( c->isDefault() )
127
 
    return;
128
 
  
129
 
  //if the cell contains the circle error, we mustn't do anything
130
 
  if (c->testFlag (KSpreadCell::Flag_CircularCalculation))
131
 
    return;
132
 
  
133
 
  //kdDebug(36001) << "updating dependencies for cell (" <<
134
 
  //    c->row() << "," << c->column() << ")" << endl;
135
 
  
136
 
  //don't re-generate dependencies if we're updating dependencies
137
 
  if ( !(c->testFlag (KSpreadCell::Flag_Progress)))
138
 
    deps->generateDependencies (cell);
139
 
 
140
 
  deps->processDependencies (cell);
 
169
  deps->cellChanged (cell);
141
170
}
142
171
 
143
 
void DependencyManager::rangeChanged (const KSpreadRange &range)
 
172
void DependencyManager::rangeChanged (const Range &range)
144
173
{
145
174
  deps->generateDependencies (range);
146
175
  deps->processDependencies (range);
152
181
  deps->processDependencies (rangeList);
153
182
}
154
183
 
155
 
RangeList DependencyManager::getDependencies (const KSpreadPoint &cell)
 
184
void DependencyManager::areaModified (const QString &name)
 
185
{
 
186
  deps->areaModified (name);
 
187
}
 
188
 
 
189
RangeList DependencyManager::getDependencies (const Point &cell)
156
190
{
157
191
  return deps->getDependencies (cell);
158
192
}
159
193
 
160
 
QValueList<KSpreadPoint> DependencyManager::getDependants (const KSpreadPoint &cell)
 
194
QValueList<Point> DependencyManager::getDependants (const Point &cell)
161
195
{
162
196
  return deps->getDependants (cell);
163
197
}
164
198
 
165
 
DependencyList::DependencyList (KSpreadSheet *s)
 
199
DependencyList::DependencyList (Sheet *s)
166
200
    : sheet (s)
167
201
{
168
202
}
174
208
  rangeDeps.clear();
175
209
}
176
210
 
177
 
RangeList DependencyList::getDependencies (const KSpreadPoint &cell)
 
211
void DependencyList::cellChanged (const Point &cell)
 
212
{
 
213
  Cell *c = cell.cell();
 
214
 
 
215
  // empty or default cell? do nothing
 
216
  if( c->isDefault() )
 
217
    return;
 
218
 
 
219
  //if the cell contains the circle error, we mustn't do anything
 
220
  if (c->testFlag (Cell::Flag_CircularCalculation))
 
221
    return;
 
222
 
 
223
  //don't re-generate dependencies if we're updating dependencies
 
224
  if ( !(c->testFlag (Cell::Flag_Progress)))
 
225
    generateDependencies (cell);
 
226
 
 
227
  processDependencies (cell);
 
228
}
 
229
 
 
230
RangeList DependencyList::getDependencies (const Point &cell)
178
231
{
179
232
  RangeList rl;
180
233
  //look if the cell has any dependencies
181
234
  if (!dependencies.contains (cell))
182
235
    return rl;  //it doesn't - return an empty list
183
 
  
 
236
 
184
237
  //the cell does have dependencies - return them!
185
238
  return dependencies[cell];
186
239
}
187
240
 
188
 
QValueList<KSpreadPoint> DependencyList::getDependants (const KSpreadPoint &cell)
 
241
QValueList<Point> DependencyList::getDependants (const Point &cell)
189
242
{
190
 
  QValueList<KSpreadPoint> list;
191
 
  
192
243
  //cell dependencies go first
193
 
  if (cellDeps.contains (cell))
194
 
    list = cellDeps[cell];
195
 
  
 
244
  QValueList<Point> list = getCellDeps( cell );
196
245
  //next, append range dependencies
197
 
  KSpreadPoint leading = leadingCell (cell);
 
246
  Point leading = leadingCell (cell);
198
247
  QValueList<RangeDependency>::iterator it;
199
248
  if (!rangeDeps.count (leading))
200
249
    return list;  //no range dependencies in this cell chunk -> nothing more to do
201
 
  
 
250
 
202
251
  for (it = rangeDeps[leading].begin();
203
252
      it != rangeDeps[leading].end(); ++it)
204
253
  {
206
255
    //add the depending cell to the list
207
256
    if ((*it).range.contains (cell))
208
257
    {
209
 
      KSpreadPoint c;
 
258
      Point c;
210
259
      c.setRow ((*it).cellrow);
211
260
      c.setColumn ((*it).cellcolumn);
212
 
      c.sheet = (*it).cellsheet;
 
261
      c.setSheet ( (*it).cellsheet );
213
262
      list.push_back (c);
214
263
    }
215
264
  }
216
 
  
 
265
 
217
266
  return list;
218
267
}
219
268
 
220
 
void DependencyList::addDependency (const KSpreadPoint &cell1,
221
 
    const KSpreadPoint &cell2)
222
 
{
223
 
  //kdDebug(36001) << "Dep. manager: added a dependency" << endl;
224
 
  
 
269
void DependencyList::areaModified (const QString &name)
 
270
{
 
271
  // since area names are something like aliases, modifying an area name
 
272
  // basically means that all cells referencing this area should be treated
 
273
  // as modified - that will retrieve updated area ranges and also update
 
274
  // everything as necessary ...
 
275
  if (!areaDeps.contains (name))
 
276
    return;
 
277
 
 
278
  QMap<Point, bool>::iterator it;
 
279
  for (it = areaDeps[name].begin(); it != areaDeps[name].end(); ++it)
 
280
  {
 
281
    Cell *c = it.key().cell();
 
282
    // this forces the cell to regenerate everything - new range dependencies
 
283
    // and so on
 
284
    c->setValue (c->value ());
 
285
  }
 
286
}
 
287
 
 
288
void DependencyList::addDependency (const Point &cell1,
 
289
    const Point &cell2)
 
290
{
225
291
  //cell2 can be in another sheet (inter-sheet dependency)
226
 
  KSpreadSheet *sh = cell2.sheet;
 
292
  Sheet *sh = cell2.sheet();
227
293
  if (!sh)
228
294
    sh = sheet;
229
295
 
234
300
void DependencyList::addRangeDependency (const RangeDependency &rd)
235
301
{
236
302
  //target range can be in another sheet (inter-sheet dependency)
237
 
  KSpreadSheet *sh = rd.range.sheet;
 
303
  Sheet *sh = rd.range.sheet();
238
304
  if (!sh)
239
305
    sh = sheet;
240
 
  
241
 
  KSpreadPoint cell;
242
 
  cell.sheet = rd.cellsheet;
 
306
 
 
307
  Point cell;
 
308
  cell.setSheet (rd.cellsheet);
243
309
  cell.setRow (rd.cellrow);
244
310
  cell.setColumn (rd.cellcolumn);
245
311
  dependencies[cell].ranges.push_back (rd.range);
246
 
  
247
 
  QValueList<KSpreadPoint> leadings = leadingCells (rd.range);
248
 
  QValueList<KSpreadPoint>::iterator it;
 
312
 
 
313
  QValueList<Point> leadings = leadingCells (rd.range);
 
314
  QValueList<Point>::iterator it;
249
315
  for (it = leadings.begin(); it != leadings.end(); ++it)
250
316
    sh->dependencies()->deps->rangeDeps[*it].push_back (rd);
 
317
 
 
318
  // the target range could be a named area ...
 
319
  if (!rd.range.namedArea().isNull())
 
320
    areaDeps[rd.range.namedArea()][cell] = true;
251
321
}
252
322
 
253
 
void DependencyList::removeDependencies (const KSpreadPoint &cell)
 
323
void DependencyList::removeDependencies (const Point &cell)
254
324
{
255
325
  //look if the cell has any dependencies
256
326
  if (!dependencies.contains (cell))
257
327
    return;  //it doesn't - nothing more to do
258
 
  
 
328
 
259
329
  //first we remove cell-dependencies
260
 
  QValueList<KSpreadPoint> cells = dependencies[cell].cells;
261
 
  QValueList<KSpreadPoint>::iterator it1;
 
330
  QValueList<Point> cells = dependencies[cell].cells;
 
331
  QValueList<Point>::iterator it1;
262
332
  for (it1 = cells.begin(); it1 != cells.end(); ++it1)
263
333
  {
264
334
    //get sheet-pointer - needed to handle inter-sheet dependencies correctly
265
 
    KSpreadSheet *sh = (*it1).sheet;
 
335
    Sheet *sh = (*it1).sheet();
266
336
    if (!sh)
267
337
      sh = sheet;
268
 
    
 
338
 
269
339
    if (!sh->dependencies()->deps->cellDeps.contains (*it1))
270
340
      continue;  //this should never happen
271
 
    
 
341
 
272
342
    //we no longer depend on this cell
273
 
    QValueList<KSpreadPoint>::iterator cit;
 
343
    QValueList<Point>::iterator cit;
274
344
    cit = sh->dependencies()->deps->cellDeps[*it1].find (cell);
275
345
    if (cit != sh->dependencies()->deps->cellDeps[*it1].end())
276
346
      sh->dependencies()->deps->cellDeps[*it1].erase (cit);
277
347
  }
278
 
  
 
348
 
279
349
  //then range-dependencies are removed
280
 
  QValueList<KSpreadRange> ranges = dependencies[cell].ranges;
281
 
  QValueList<KSpreadRange>::iterator it2;
282
 
  QValueList<KSpreadPoint> leads;
 
350
  QValueList<Range> ranges = dependencies[cell].ranges;
 
351
  QValueList<Range>::iterator it2;
 
352
  QValueList<Point> leads;
283
353
  for (it2 = ranges.begin(); it2 != ranges.end(); ++it2)
284
354
  {
285
355
    //we construct a list of cell-chunks containing a range and merge it
286
356
    //with lists generated from all previous ranges (duplicates are removed)
287
 
    QValueList<KSpreadPoint> leadings = leadingCells (*it2);
 
357
    QValueList<Point> leadings = leadingCells (*it2);
288
358
    for (it1 = leadings.begin(); it1 != leadings.end(); ++it1)
289
359
      if (!leads.contains (*it1))
290
360
        leads.push_back (*it1);
292
362
  for (it1 = leads.begin(); it1 != leads.end(); ++it1)
293
363
  {
294
364
    //get sheet-pointer - needed to handle inter-sheet dependencies correctly
295
 
    KSpreadSheet *sh = (*it1).sheet;
 
365
    Sheet *sh = (*it1).sheet();
296
366
    if (!sh)
297
367
      sh = sheet;
298
368
 
299
369
    if (sh->dependencies()->deps->rangeDeps.contains (*it1))
300
370
    {
301
371
      QValueList<RangeDependency>::iterator it3;
302
 
      QValueList<RangeDependency> rdeps =
303
 
          sh->dependencies()->deps->rangeDeps[*it1];
304
 
      it3 = rdeps.begin();
 
372
      it3 = sh->dependencies()->deps->rangeDeps[*it1].begin();
305
373
      //erase all range dependencies of this cell in this cell-chunk
306
 
      while (it3 != rdeps.end())
 
374
      while (it3 != sh->dependencies()->deps->rangeDeps[*it1].end())
307
375
        if (((*it3).cellrow == cell.row()) &&
308
376
            ((*it3).cellcolumn == cell.column()))
309
 
          it3 = rdeps.erase (it3);
 
377
          it3 = sh->dependencies()->deps->rangeDeps[*it1].erase (it3);
310
378
        else
311
379
          ++it3;
312
380
      //erase the list if we no longer need it
313
 
      if (rdeps.empty())
 
381
      if (sh->dependencies()->deps->rangeDeps[*it1].empty())
314
382
        sh->dependencies()->deps->rangeDeps.erase (*it1);
315
383
    }
316
384
  }
317
 
  
318
 
  //finally, remove the entry about this cell
 
385
 
 
386
  // remove information about named area dependencies
 
387
  QMap<QString, QMap<Point, bool> >::iterator itr;
 
388
  for (itr = areaDeps.begin(); itr != areaDeps.end(); ++itr) {
 
389
    if (itr.data().contains (cell))
 
390
      itr.data().remove (cell);
 
391
  }
 
392
 
 
393
  // finally, remove the entry about this cell
319
394
  dependencies[cell].cells.clear();
320
395
  dependencies[cell].ranges.clear();
321
396
  dependencies.erase (cell);
322
397
}
323
398
 
324
 
void DependencyList::generateDependencies (const KSpreadPoint &cell)
 
399
void DependencyList::generateDependencies (const Point &cell)
325
400
{
326
401
  //get rid of old dependencies first
327
402
  removeDependencies (cell);
328
403
 
329
404
  //new dependencies only need to be generated if the cell contains a formula
330
 
  KSpreadCell *c = sheet->cellAt (cell.column(), cell.row());
 
405
  Cell *c = sheet->cellAt (cell.column(), cell.row());
331
406
  if( c->isDefault() )
332
407
    return;
333
408
  if (!c->isFormula())
334
409
    return;
335
 
  
 
410
 
336
411
  //now we need to generate dependencies
337
412
  RangeList rl = computeDependencies (cell);
338
 
  
 
413
 
339
414
  //now that we have the new dependencies, we put them into our data structures
340
415
  //and we're done
341
 
  QValueList<KSpreadPoint>::iterator it1;
342
 
  QValueList<KSpreadRange>::iterator it2;
343
 
  
 
416
  QValueList<Point>::iterator it1;
 
417
  QValueList<Range>::iterator it2;
 
418
 
344
419
  for (it1 = rl.cells.begin(); it1 != rl.cells.end(); ++it1)
345
420
    addDependency (cell, *it1);
346
421
  for (it2 = rl.ranges.begin(); it2 != rl.ranges.end(); ++it2)
350
425
    rd.cellcolumn = cell.column();
351
426
    rd.cellsheet = sheet;
352
427
    rd.range = *it2;
353
 
    if (rd.range.sheet == 0) rd.range.sheet = sheet;
 
428
 
 
429
    if (rd.range.sheet() == 0)
 
430
        rd.range.setSheet(sheet);
 
431
 
354
432
    addRangeDependency (rd);
355
433
  }
356
434
}
357
435
 
358
 
void DependencyList::generateDependencies (const KSpreadRange &range)
 
436
void DependencyList::generateDependencies (const Range &range)
359
437
{
360
438
  for (int row = range.startRow(); row <= range.endRow(); row++)
361
439
    for (int col = range.startCol(); col <= range.endCol(); col++)
362
440
    {
363
 
      KSpreadPoint c;
 
441
      Point c;
364
442
      c.setRow (row);
365
443
      c.setColumn (col);
366
 
      c.sheet = sheet;
 
444
      c.setSheet(sheet);
367
445
      generateDependencies (c);
368
446
    }
369
447
}
370
448
 
371
449
void DependencyList::generateDependencies (const RangeList &rangeList)
372
450
{
373
 
  QValueList<KSpreadPoint>::const_iterator it1;
374
 
  QValueList<KSpreadRange>::const_iterator it2;
375
 
  
 
451
  QValueList<Point>::const_iterator it1;
 
452
  QValueList<Range>::const_iterator it2;
 
453
 
376
454
  for (it1 = rangeList.cells.begin(); it1 != rangeList.cells.end(); ++it1)
377
455
    generateDependencies (*it1);
378
456
  for (it2 = rangeList.ranges.begin(); it2 != rangeList.ranges.end(); ++it2)
379
457
    generateDependencies (*it2);
380
458
}
381
459
 
382
 
void DependencyList::processDependencies (const KSpreadPoint &cell)
 
460
void DependencyList::processDependencies (const Point &cell)
383
461
{
384
 
  if (cellDeps.contains (cell))
385
 
  {
386
 
    QValueList<KSpreadPoint> d = cellDeps[cell];
387
 
    QValueList<KSpreadPoint>::iterator it;
388
 
    for (it = d.begin(); it != d.end(); ++it)
 
462
  const QValueList<Point> d = getCellDeps(cell);
 
463
  QValueList<Point>::const_iterator it = d.begin();
 
464
  const QValueList<Point>::const_iterator end = d.end();
 
465
  for (; it != end; ++it)
389
466
      updateCell (*it);
390
 
  }
391
 
  
 
467
 
392
468
  processRangeDependencies (cell);
393
469
}
394
470
 
395
 
void DependencyList::processRangeDependencies (const KSpreadPoint &cell)
 
471
void DependencyList::processRangeDependencies (const Point &cell)
396
472
{
397
 
  KSpreadPoint leading = leadingCell (cell);
398
 
  QValueList<RangeDependency>::iterator it;
 
473
  Point leading = leadingCell (cell);
399
474
  if (!rangeDeps.count (leading))
400
475
    return;  //no range dependencies in this cell chunk
401
476
 
402
 
  for (it = rangeDeps[leading].begin();
403
 
      it != rangeDeps[leading].end(); ++it)
 
477
  const QValueList<RangeDependency> rd = rangeDeps[leading];
 
478
 
 
479
  QValueList<RangeDependency>::const_iterator it;
 
480
  for (it = rd.begin(); it != rd.end(); ++it)
404
481
  {
405
482
    //process all range dependencies, and for each range including the modified cell,
406
483
    //recalc the depending cell
407
484
    if ((*it).range.contains (cell))
408
485
    {
409
 
      KSpreadPoint c;
 
486
      Point c;
410
487
      c.setRow ((*it).cellrow);
411
488
      c.setColumn ((*it).cellcolumn);
412
 
      c.sheet = (*it).cellsheet;
 
489
      c.setSheet ( (*it).cellsheet );
413
490
      updateCell (c);
414
491
    }
415
492
  }
416
493
}
417
494
 
418
 
void DependencyList::processDependencies (const KSpreadRange &range)
 
495
void DependencyList::processDependencies (const Range &range)
419
496
{
420
497
  //each cell's dependencies need to be updated - that cannot be helped - having a range
421
498
  //only helps with range dependencies
422
499
  for (int row = range.startRow(); row <= range.endRow(); row++)
423
500
    for (int col = range.startCol(); col <= range.endCol(); col++)
424
501
    {
425
 
      KSpreadPoint c;
 
502
      Point c;
426
503
      c.setRow (row);
427
504
      c.setColumn (col);
428
 
      c.sheet = sheet;
429
 
      if (cellDeps.contains (c))
430
 
      {
431
 
        QValueList<KSpreadPoint> d = cellDeps[c];
432
 
        QValueList<KSpreadPoint>::iterator it;
433
 
        for (it = d.begin(); it != d.end(); ++it)
 
505
      c.setSheet( sheet );
 
506
 
 
507
      const QValueList<Point> d = getCellDeps(c);
 
508
      QValueList<Point>::const_iterator it = d.begin();
 
509
      const QValueList<Point>::const_iterator end = d.end();
 
510
      for (; it != end; ++it)
434
511
          updateCell (*it);
435
 
      }
436
512
    }
437
 
  
 
513
 
438
514
  processRangeDependencies (range);
439
515
}
440
516
 
441
 
void DependencyList::processRangeDependencies (const KSpreadRange &range)
 
517
void DependencyList::processRangeDependencies (const Range &range)
442
518
{
443
519
  //TODO: some optimization, so that we don't recompute cells depending of huge
444
520
  //ranges more than once (now we recompute them once per cell-chunk used by their dependency)
445
521
  //This will probably happen as a part of splitting this into dep manager
446
522
  //and recalc manager
447
 
  
448
 
  QValueList<KSpreadPoint> leadings = leadingCells (range);
449
 
  QValueList<KSpreadPoint>::iterator it;
 
523
 
 
524
  QValueList<Point> leadings = leadingCells (range);
 
525
  QValueList<Point>::iterator it;
450
526
  for (it = leadings.begin(); it != leadings.end(); ++it)
451
527
  {
452
528
    if (!rangeDeps.count (*it))
458
534
      //recalc the depending cell
459
535
      if ((*it2).range.intersects (range))
460
536
      {
461
 
        KSpreadPoint c;
 
537
        Point c;
462
538
        c.setRow ((*it2).range.startRow());
463
539
        c.setColumn ((*it2).range.startCol());
464
 
        c.sheet = sheet;
 
540
        c.setSheet(sheet);
465
541
        updateCell (c);
466
542
      }
467
543
    }
470
546
 
471
547
void DependencyList::processDependencies (const RangeList &rangeList)
472
548
{
473
 
  QValueList<KSpreadPoint>::const_iterator it1;
474
 
  QValueList<KSpreadRange>::const_iterator it2;
475
 
  
 
549
  QValueList<Point>::const_iterator it1;
 
550
  QValueList<Range>::const_iterator it2;
 
551
 
476
552
  for (it1 = rangeList.cells.begin(); it1 != rangeList.cells.end(); ++it1)
477
553
    processDependencies (*it1);
478
554
  for (it2 = rangeList.ranges.begin(); it2 != rangeList.ranges.end(); ++it2)
479
555
    processDependencies (*it2);
480
556
}
481
557
 
482
 
void DependencyList::updateCell (const KSpreadPoint &cell) const
 
558
void DependencyList::updateCell (const Point &cell) const
483
559
{
484
 
  KSpreadCell *c = cell.cell();
485
 
 
 
560
  Cell *c = cell.cell();
486
561
  //prevent infinite recursion (circular dependencies)
487
 
  if (c->testFlag (KSpreadCell::Flag_Progress))
 
562
  if (c->testFlag (Cell::Flag_Progress) ||
 
563
      c->testFlag (Cell::Flag_CircularCalculation))
488
564
  {
489
 
    kdError(36001) << "ERROR: Circle" << endl;
490
 
    c->setFlag(KSpreadCell::Flag_CircularCalculation);
491
 
    KSpreadValue v;
492
 
    v.setError ( "####" );
493
 
    c->setValue (v);
 
565
    kdError(36001) << "ERROR: Circle, cell " << c->fullName() <<
 
566
        ", in dep.manager for sheet " << sheet->name() << endl;
 
567
    Value v;
 
568
    // don't set anything if the cell already has all these things set
 
569
    // this prevents endless loop for inter-sheet curcular dependencies,
 
570
    // where the usual mechanisms fail doe to having multiple dependency
 
571
    // managers ...
 
572
    if (!c->testFlag (Cell::Flag_CircularCalculation))
 
573
    {
 
574
      c->setFlag(Cell::Flag_CircularCalculation);
 
575
      v.setError ( "####" );
 
576
      c->setValue (v);
 
577
    }
494
578
    //clear the computing-dependencies flag
495
 
    c->clearFlag (KSpreadCell::Flag_Progress);
 
579
    c->clearFlag (Cell::Flag_Progress);
496
580
    return;
497
581
  }
498
 
  //kdDebug() << "Updating depending cell (" <<
499
 
  //    c->row() << "," << c->column() << ")" << endl;
500
582
  //set the computing-dependencies flag
501
 
  c->setFlag (KSpreadCell::Flag_Progress);
502
 
  
 
583
  c->setFlag (Cell::Flag_Progress);
 
584
 
503
585
  //mark the cell as calc-dirty
504
586
  c->setCalcDirtyFlag();
505
 
  
 
587
 
506
588
  //recalculate the cell
507
589
  c->calc (false);
508
 
  
 
590
 
509
591
  //clear the computing-dependencies flag
510
 
  c->clearFlag (KSpreadCell::Flag_Progress);
 
592
  c->clearFlag (Cell::Flag_Progress);
511
593
}
512
594
 
513
 
KSpreadPoint DependencyList::leadingCell (const KSpreadPoint &cell) const
 
595
Point DependencyList::leadingCell (const Point &cell) const
514
596
{
515
 
  KSpreadPoint c;
 
597
  Point c;
516
598
  c.setRow (cell.row() - cell.row() % CELLCHUNK_ROWS + 1);
517
599
  c.setColumn (cell.column() - cell.column() % CELLCHUNK_COLS + 1);
518
 
  c.sheet = cell.sheet;
 
600
  c.setSheet(cell.sheet());
519
601
  return c;
520
602
}
521
603
 
522
 
QValueList<KSpreadPoint> DependencyList::leadingCells (const KSpreadRange &range) const
 
604
QValueList<Point> DependencyList::leadingCells (const Range &range) const
523
605
{
524
 
  QValueList<KSpreadPoint> cells;
525
 
  KSpreadPoint cell1, cell2, cell;
526
 
  
 
606
  QValueList<Point> cells;
 
607
  Point cell1, cell2, cell;
 
608
 
527
609
  cell1.setRow (range.startRow());
528
610
  cell1.setColumn (range.startCol());
529
611
  cell2.setRow (range.endRow());
530
612
  cell2.setColumn (range.endCol());
531
 
  cell1.sheet = range.sheet;
532
 
  cell2.sheet = range.sheet;
533
 
  
 
613
  cell1.setSheet(range.sheet());
 
614
  cell2.setSheet(range.sheet());
 
615
 
534
616
  cell1 = leadingCell (cell1);
535
617
  cell2 = leadingCell (cell2);
536
618
  for (int row = cell1.row(); row <= cell2.row(); row += CELLCHUNK_ROWS)
539
621
    {
540
622
      cell.setRow (row);
541
623
      cell.setColumn (col);
542
 
      cell.sheet = range.sheet;
 
624
      cell.setSheet(range.sheet());
543
625
      cells.push_back (cell);
544
626
    }
545
627
  return cells;
546
628
}
547
629
 
548
 
RangeList DependencyList::computeDependencies (const KSpreadPoint &cell) const
 
630
RangeList DependencyList::computeDependencies (const Point &cell) const
549
631
{
550
 
  KSpreadCell *c = cell.cell();
 
632
  Cell *c = cell.cell();
 
633
 
 
634
  // Not a formula -> no dependencies
551
635
  if (!c->isFormula())
552
 
    return RangeList();   //not a formula -> no dependencies
553
 
 
554
 
  QString expr = c->text();
555
 
 
556
 
  //TODO: when the new parser is in use, KSpreadCell will hold a Formula
557
 
  //instance, hence we'll be able to use that one directly
558
 
  Tokens tokens = Formula::scan( expr );
 
636
    return RangeList();
 
637
 
 
638
  // Broken formula -> meaningless dependencies
 
639
  // (tries to avoid c->formula() being null)
 
640
  if (c->hasError())
 
641
    return RangeList();
 
642
 
 
643
  Formula* f = c->formula();
 
644
  Q_ASSERT(f);
 
645
  if (f==NULL)
 
646
  {
 
647
    kdDebug() << "Cell at row " << cell.row() << ", col " << cell.column() << " marked as formula, but formula is NULL" << endl;
 
648
    return RangeList();
 
649
  }
 
650
 
 
651
  Tokens tokens = f->tokens();
559
652
 
560
653
  //return empty list if the tokens aren't valid
561
654
  if (!tokens.valid())
562
655
    return RangeList();
563
656
 
564
 
  kdDebug(36001) << "Retrieving dependencies for cell with text \"" << expr << "\"" << endl;
565
 
 
566
657
  RangeList rl;
567
658
  for( unsigned i = 0; i < tokens.count(); i++ )
568
659
  {
573
664
    if (tokenType == Token::Cell)
574
665
    {
575
666
      QString text = token.text();
576
 
      KSpreadPoint cell (text, sheet->workbook(), sheet);
 
667
      Point cell (text, sheet->workbook(), sheet);
577
668
      if (cell.isValid())
578
669
        rl.cells.push_back (cell);
579
670
    }
580
671
    else if (tokenType == Token::Range)
581
672
    {
582
673
      QString text = token.text();
583
 
      KSpreadRange range (text, sheet->workbook(), sheet);
 
674
      Range range (text, sheet->workbook(), sheet);
584
675
      if (range.isValid())
585
676
        rl.ranges.push_back (range);
586
677
    }
587
678
  }
588
 
  
 
679
 
589
680
  return rl;
590
681
}
591
682