00001 #include <qpainter.h>
00002 #include <qimage.h>
00003 #include <qlineedit.h>
00004 #include <qpalette.h>
00005 #include <typeinfo>
00006 #include "iis.h"
00007 #include "value.h"
00008 #include "vars.h"
00009 #include "refs.h"
00010 #include "ranges.h"
00011 #include "runtime.h"
00012 #include "spreadsheet.h"
00013 #include "text.h"
00014 #include "parser.h"
00015 #include "status.h"
00016
00017
00018
00019
00020 bool equals(QString a, QString b)
00021 {
00022 return a==b;
00023 }
00024
00025 bool equals(bool a, bool b)
00026 {
00027 return a==b;
00028 }
00029
00030 bool equals(QImage a, QImage b)
00031 {
00032 if (a.isNull() && b.isNull()) return true;
00033 if (a.isNull() || b.isNull()) return false;
00034 return a==b;
00035 }
00036
00037 bool equals(Value * v1, Value * v2)
00038 {
00039 if (v1==v2) return true;
00040 if (v1==NULL || v2==NULL)
00041 return false;
00042 if (v1->equals(v2))
00043 return true;
00044 return false;
00045 }
00046
00047 class CallMember: public PlaceListener
00048 {
00049 public:
00050 IisCell::member F;
00051 IisCell& o;
00052 CallMember(IisCell &ob, IisCell::member i) : o(ob)
00053 {
00054 F=i;
00055 };
00056 virtual void setChanged()
00057 {
00058 if (!changed)
00059 {
00060 o.queueCall(this);
00061 }
00062 PlaceListener::setChanged();
00063 }
00064 void execute()
00065 {
00066 ((o).*(F))();
00067 };
00068 };
00069
00070 void IisCell::link(AbstractPlace& l, IisCell::member m)
00071 {
00072 CallMember * em;
00073 em = new CallMember(*this,m);
00074 l.notify(em);
00075 };
00076
00077 static vector<CallMember*> queued_calls;
00078
00079 void IisCell::queueCall(CallMember * m)
00080 {
00081 queued_calls.push_back(m);
00082 }
00083
00084 void IisCell::flushCalls()
00085 {
00086 static bool flushing = false;
00087 if (flushing) return;
00088 flushing = true;
00089 while(queued_calls.size())
00090 {
00091 CallMember * m = queued_calls.front();
00092 queued_calls.erase(queued_calls.begin());
00093 m->clearChanged();
00094 m->execute();
00095 };
00096 flushing = false;
00097 }
00098
00099
00100
00101
00102 IisCell::IisCell(QTable * table, EditType et) :
00103 QTableItem(table,et)
00104 {
00105 link(entered, &IisCell::entered_changed);
00106 link(value, &IisCell::value_changed);
00107 link(formule, &IisCell::formule_changed);
00108 link(image, &IisCell::image_changed);
00109 link(show, &IisCell::show_changed);
00110 link(needs_recalculation,&IisCell::recalc_changed);
00111
00112 link(entered, &IisCell::show_status_changed);
00113 link(show_status, &IisCell::show_status_changed);
00114
00115 link(image, &IisCell::visual_changed);
00116 link(show, &IisCell::visual_changed);
00117 link(needs_recalculation,&IisCell::visual_changed);
00118
00119 entered = "";
00120 formule = NULL;
00121 value = NULL;
00122 needs_recalculation = false;
00123 user_input_allowed = false;
00124 image = QImage();
00125 scaled = QImage();
00126 scale_xs = 0;
00127 scale_ys = 0;
00128 setWordWrap(true);
00129 show_status = true;
00130
00131 flushCalls();
00132 };
00133
00134 void IisCell::load(Data initfrom)
00135 {
00136 Token content = initfrom;
00137 String E = content["entered"];
00138 entered = E;
00139 Data F = content["formule"];
00140 if (!F.isNull())
00141 formule = Value::load(F);
00142 Data R = content["result"];
00143 if (!R.isNull())
00144 value = Value::load(R);
00145
00146 set_inputs();
00147
00148 flushCalls();
00149 };
00150
00151 Data IisCell::saveFile(QString prefix)
00152 {
00153 Token content;
00154 content["entered"]=String(entered);
00155 Value * F = formule;
00156 if (F)
00157 content["formule"]=F->getSaveDescription(prefix);
00158 Value * result = value;
00159 if (result)
00160 content["result"]=result->getSaveDescription(prefix);
00161 return content;
00162 }
00163
00164 QWidget * IisCell::createEditor () const
00165 {
00166 QWidget * res = QTableItem::createEditor();
00167 QLineEdit * le = (QLineEdit*)(void*)res;
00168 le->setText(entered);
00169 return le;
00170 };
00171
00172 void IisCell::add_listener(IisCell * who)
00173 {
00174 for(list<IisCell*>::iterator it=listeners.begin() ; it!=listeners.end() ; it++)
00175 {
00176 IisCell * c = *it;
00177 if (c==who) return;
00178 }
00179 listeners.push_back(who);
00180 }
00181
00182 void IisCell::image_changed()
00183 {
00184 QImage I = image;
00185 scaled = QImage();
00186 if (!I.isNull())
00187 show = NULL;
00188 }
00189
00190 void IisCell::show_changed()
00191 {
00192 QString S = show;
00193 QTableItem::setText(S);
00194 if (!S.isEmpty())
00195 image = QImage();
00196 }
00197
00198 void IisCell::visual_changed()
00199 {
00200 table()->updateCell(row(),col());
00201 }
00202
00203 void IisCell::del_listener(IisCell * who)
00204 {
00205 for(list<IisCell*>::iterator it=listeners.begin() ; it!=listeners.end() ; it++)
00206 if ((*it)==who)
00207 {
00208 listeners.erase(it);
00209 return;
00210 }
00211 }
00212
00213 class CellShifter: public ReferenceFixer
00214 {
00215 protected: int from, nr;
00216 public: CellShifter(int r, int c) : from(r), nr(c) {};
00217 };
00218
00219
00220 class CellDownShifter: public CellShifter
00221 {
00222 public:
00223 CellDownShifter(int f, int c) : CellShifter(f,c)
00224 {
00225 };
00226 protected:
00227 Reference* copyRef(Reference * ref)
00228 {
00229 assert(ref);
00230 if (ref->row>=from) ref->row+=nr;
00231 return ref;
00232 }
00233 };
00234
00235 class CellRightShifter: public CellShifter
00236 {
00237 public:
00238 CellRightShifter(int f, int c) : CellShifter(f,c)
00239 {
00240 };
00241 protected:
00242 Reference* copyRef(Reference * ref)
00243 {
00244 if (ref->column>=from) ref->column+=nr;
00245 return ref;
00246 }
00247 };
00248
00249 void IisCell::rowsInserted(int row, int nr)
00250 {
00251 if (formule)
00252 {
00253 CellDownShifter shifter(row,nr);
00254 shifter.copy(formule);
00255 }
00256 }
00257
00258 void IisCell::colsInserted(int col, int nr)
00259 {
00260 if (formule)
00261 {
00262 CellRightShifter shifter(col,nr);
00263 shifter.copy(formule);
00264 }
00265 }
00266
00267 class RelativeShifter: public ReferenceFixer
00268 {
00269 int x,y;
00270 public: RelativeShifter(int X, int Y) : x(X), y(Y) {};
00271 protected: Reference* copyRef(Reference *ref)
00272 {
00273 Reference *result=new Reference(*ref);
00274 if (!ref->absolute_col)
00275 result->column+=x;
00276 if (!ref->absolute_row)
00277 result->row+=y;
00278 return result;
00279 }
00280 };
00281
00282
00283 QString IisCell::getFormuleTextForCell(int x, int y)
00284 {
00285 if (!formule) return "";
00286 RelativeShifter shifter(x-col(),y-row());
00287 return shifter.copy(formule)->toString();
00288 }
00289
00290 void IisCell::setText(const QString & str)
00291 {
00292 entered = str;
00293 flushCalls();
00294 }
00295
00296 void IisCell::entered_changed()
00297 {
00298 QString e = entered;
00299 if (e.isEmpty())
00300 formule = NULL;
00301 else
00302 {
00303 try
00304 {
00305 ParseText p(e);
00306 formule = p.expr();
00307 }
00308 catch (Error * p)
00309 {
00310 formule = NULL;
00311 value = p;
00312 }
00313 }
00314 }
00315
00316 void IisCell::formule_changed()
00317 {
00318 clear_inputs();
00319 set_inputs();
00320 if (will_loop())
00321 {
00322 clear_inputs();
00323 value = new Error("<loop>");
00324 formule = NULL;
00325 return;
00326 }
00327
00328 mark_recalc();
00329
00330
00331
00332 Value * F = formule;
00333 if (F)
00334 entered = F->toString();
00335 }
00336
00337 Value * IisCell::fetch_value()
00338 {
00339 if (needs_recalculation) return NULL;
00340 Value * v = value;
00341 if (v &&
00342 (typeid(*v) == typeid(Status)
00343 || typeid(*v) == typeid(Error)
00344 || typeid(*v) == typeid(ParseError)))
00345 return NULL;
00346 return v;
00347 }
00348
00349 void IisCell::updated()
00350 {
00351 printf(" Updated cell %d,%d\n",col(),row());
00352 for(list<IisCell*>::iterator it=listeners.begin(); it!=listeners.end(); it++)
00353 {
00354 assert(*it);
00355 printf(" Marking recalc at %d,%d\n",(*it)->col(),(*it)->row());
00356 (*it)->mark_recalc();
00357 }
00358 }
00359
00360 void IisCell::value_changed()
00361 {
00362 if (!show_status)
00363 show_value();
00364 updated();
00365 }
00366
00367 void IisCell::show_value()
00368 {
00369 Value * result = value;
00370 if (!result)
00371 {
00372 show_status = true;
00373 }
00374 else
00375 {
00376 if (typeid(*result)==typeid(ImageValue))
00377 image = ((ImageValue*)result)->getQImage(true);
00378 else
00379 show = result->toString();
00380 }
00381 }
00382
00383 void IisCell::show_status_changed()
00384 {
00385 if (show_status)
00386 show = entered;
00387 else
00388 show_value();
00389 }
00390
00391 void IisCell::paint(QPainter * p, const QColorGroup & cg, const QRect & cr, bool selected)
00392 {
00393
00394 QColorGroup ncg(cg);
00395 Value * v = value;
00396 if (v && typeid(*v)==typeid(ParseError))
00397 ncg.setColor(QColorGroup::Base,QColor(255,0,0));
00398 else if (v && typeid(*v)==typeid(Error))
00399 ncg.setColor(QColorGroup::Base,QColor(255,192,192));
00400 else if (user_input_allowed)
00401 ncg.setColor(QColorGroup::Base,QColor(128,255,128));
00402 else if (needs_user_input())
00403 {
00404 if (needs_recalculation || show_status)
00405 ncg.setColor(QColorGroup::Base,QColor(255,192,128));
00406 else
00407 ncg.setColor(QColorGroup::Base,QColor(255,255,128));
00408 }
00409 else if (needs_recalculation || show_status)
00410 ncg.setColor(QColorGroup::Base,QColor(192,192,192));
00411
00412
00413 QImage I = image;
00414 if (I.isNull())
00415 {
00416 QTableItem::paint(p,ncg,cr,selected);
00417 return;
00418 }
00419
00420
00421 int height = table()->rowHeight(row());
00422 int width = table()->columnWidth(col());
00423 if (scaled.isNull() ||
00424 width!=scale_xs ||
00425 height!=scale_ys ||
00426 scaled.isNull())
00427 {
00428 scale_xs = width;
00429 scale_ys = height;
00430 scaled = I.smoothScale(scale_xs,scale_ys,QImage::ScaleMin);
00431
00432
00433 if (value)
00434 {
00435 Value * v = value;
00436 if (typeid(*v)==typeid(ImageValue))
00437 {
00438 ImageValue* V = (ImageValue*)v;
00439 V->drawAxes(&scaled);
00440 }
00441 }
00442 }
00443 int xs = scaled.width();
00444 int ys = scaled.height();
00445
00446 int xl = (width - xs) / 2;
00447 int xr = xl + xs;
00448 int yt = (height - ys) / 2;
00449 int yb = yt + ys;
00450 QBrush b(ncg.color(QColorGroup::Base));
00451 p->fillRect(0,0,xl,height,b);
00452 p->fillRect(xr,0,width-xr+1,height,b);
00453 p->fillRect(xl,0,xs,yt,b);
00454 p->fillRect(xl,yb,xs,height-yb+1,b);
00455 p->drawImage(xl,yt,scaled);
00456 };
00457
00458 void IisCell::recalc_changed()
00459 {
00460 if (needs_recalculation)
00461 {
00462 value = NULL;
00463 show_status = true;
00464 SpreadSheetTable * ss = (SpreadSheetTable*)table();
00465 assert(ss);
00466 printf(" Queueing recalc at %d,%d\n",col(),row());
00467 ss->queue_recalculation(this);
00468 updated();
00469 }
00470 }
00471
00472 void IisCell::mark_recalc()
00473 {
00474 needs_recalculation = true;
00475 flushCalls();
00476 }
00477
00478 void IisCell::mark_allow_ui()
00479 {
00480 if (needs_user_input())
00481 user_input_allowed=true;
00482 }
00483
00484 void IisCell::clear_inputs()
00485 {
00486 mark_inputs(false);
00487 inputs.clear();
00488 }
00489
00490 void IisCell::set_inputs()
00491 {
00492 gather_inputs(formule);
00493 mark_inputs(true);
00494 };
00495
00496 void IisCell::gather_inputs(Value * v)
00497 {
00498 if (!v) return;
00499 if (typeid(*v)==typeid(TextValue)) return;
00500 if (typeid(*v)==typeid(ImageValue)) return;
00501 if (typeid(*v)==typeid(Reference))
00502 {
00503
00504 Reference *vv = (Reference*)v;
00505 assert(vv);
00506 SpreadSheetTable * ss = (SpreadSheetTable*)table();
00507 assert(ss);
00508 IisCell * sc = ss->findItem(vv->row,vv->column);
00509 assert(sc);
00510 inputs.push_back(sc);
00511 return;
00512 }
00513 if (typeid(*v)==typeid(Range))
00514 {
00515
00516 Range * r = (Range*)v;
00517 SpreadSheetTable * ss = (SpreadSheetTable*)table();
00518 assert(ss);
00519 for(int x = r->from->column ; x <= r->to->column ; x++)
00520 for(int y = r->from->row ; y <= r->to->row ; y++)
00521 {
00522 IisCell * sc = ss->findItem(y,x);
00523 assert(sc);
00524 inputs.push_back(sc);
00525 }
00526 return;
00527 }
00528 if (typeid(*v)==typeid(Expression))
00529 {
00530 Expression * e = (Expression*)v;
00531 for(int i = 0 ; i < e->argc() ; i++)
00532 gather_inputs(e->argv(i));
00533 return;
00534 }
00535 assert(0);
00536 }
00537
00538
00539 bool IisCell::needs_user_input()
00540 {
00541 return runtime.requires_user_input(formule);
00542 }
00543
00544 bool IisCell::can_be_calculated_now()
00545 {
00546
00547 for (list<IisCell*>::iterator it = inputs.begin();
00548 it!=inputs.end() ; it++)
00549 {
00550 bool nr = (*it)->needs_recalculation;
00551
00552 if ((*it)->needs_recalculation)
00553 return false;
00554 }
00555 if (user_input_allowed) return true;
00556 return (!needs_user_input());
00557 }
00558
00559 void IisCell::mark_inputs(bool add)
00560 {
00561 for (list<IisCell*>::iterator it = inputs.begin() ;
00562 it!=inputs.end() ; it++)
00563 {
00564 IisCell * sc = *it;
00565 if (add)
00566 sc->add_listener(this);
00567 else
00568 sc->del_listener(this);
00569 }
00570 }
00571
00572 bool IisCell::will_loop()
00573 {
00574 for (list<IisCell*>::iterator it = listeners.begin() ;
00575 it!=listeners.end() ; it++)
00576 {
00577 IisCell * sc = *it;
00578 assert(sc);
00579 if (sc->will_influence(this)) return true;
00580 }
00581 return false;
00582 };
00583
00584 bool IisCell::will_influence(IisCell * target)
00585 {
00586 if (this == target) return true;
00587 for (list<IisCell*>::iterator it = listeners.begin() ;
00588 it!=listeners.end() ; it++)
00589 {
00590 IisCell * sc = *it;
00591 assert(sc);
00592 if (sc->will_influence(target)) return true;
00593 }
00594 return false;
00595 }
00596
00597 void IisCell::recalc()
00598 {
00599 needs_recalculation = false;
00600 user_input_allowed = false;
00601 printf("Recalcing %d,%d\n",col(),row());
00602 if (formule != NULL)
00603 {
00604 try
00605 {
00606 value = evaluate(formule);
00607 }
00608 catch (Error * e)
00609 {
00610 value = e;
00611 }
00612 }
00613 else
00614 {
00615 value = NULL;
00616 }
00617 show_status = false;
00618 flushCalls();
00619 }
00620
00621 Value * IisCell::lookup(Reference* var)
00622 {
00623 if (!var) return NULL;
00624 SpreadSheetTable * ss = (SpreadSheetTable*)table();
00625 IisCell * i = (IisCell*)(ss->item(var->row,var->column));
00626 if (!i) return new TextValue("");
00627 return i->fetch_value();
00628 }
00629
00630 Value * IisCell::lookup(Range* var)
00631 {
00632 if (!var) return NULL;
00633 SpreadSheetTable * ss = (SpreadSheetTable*)table();
00634 int mx = var->from->column;
00635 int my = var->from->row;
00636 ValueArray * result = new ValueArray(var->to->column - var->from->column + 1,
00637 var->to->row - var->from->row + 1);
00638 for(int x = mx ; x <= var->to->column ; x++)
00639 for(int y = my ; y <= var->to->row ; y++)
00640 {
00641 Value * val;
00642 IisCell * i = (IisCell*)(ss->item(y,x));
00643 if (!i) val = new TextValue("");
00644 else val = i->fetch_value();
00645 if (!val) return NULL;
00646 result->set(x-mx,y-my,val);
00647 }
00648 return result;
00649 }
00650
00651 Value *IisCell::evaluate(Value * what)
00652 {
00653 if (!what) throw new Error("Empty formule");
00654 if (typeid(*what)==typeid(TextValue))
00655 return what;
00656 if (typeid(*what)==typeid(ImageValue))
00657 return what;
00658
00659
00660 if (typeid(*what)==typeid(Reference))
00661 return lookup((Reference*)what);
00662 if (typeid(*what)==typeid(Range))
00663 return lookup((Range*)what);
00664 if (typeid(*what)==typeid(Expression))
00665 return apply((Expression*)what);
00666 assert(0);
00667 return NULL;
00668 }
00669
00670 Value *IisCell::apply(Expression * app)
00671 {
00672 assert(app);
00673
00674 vector<Value*> evaluated;
00675 for(int i = 0 ; i < app->argc() ; i++)
00676 evaluated.push_back(evaluate(app->argv(i)));
00677
00678 return runtime.apply(app->op(),evaluated);
00679 }
00680