author | thufir <thufir> | 2002-07-04 16:58:16 (UTC) |
---|---|---|
committer | thufir <thufir> | 2002-07-04 16:58:16 (UTC) |
commit | d2b982a38091cbc7cd4eba0994ab6c5e3c7f7189 (patch) (unidiff) | |
tree | d1e0a5fa80a12717b46257936ee3f8bb1b3ef89e /noncore/apps/opie-sheet/sheet.cpp | |
parent | a53847b7d27938551bb4f1c8891e7bacc93143ee (diff) | |
download | opie-d2b982a38091cbc7cd4eba0994ab6c5e3c7f7189.zip opie-d2b982a38091cbc7cd4eba0994ab6c5e3c7f7189.tar.gz opie-d2b982a38091cbc7cd4eba0994ab6c5e3c7f7189.tar.bz2 |
added opie-sheet
Diffstat (limited to 'noncore/apps/opie-sheet/sheet.cpp') (more/less context) (show whitespace changes)
-rw-r--r-- | noncore/apps/opie-sheet/sheet.cpp | 849 |
1 files changed, 849 insertions, 0 deletions
diff --git a/noncore/apps/opie-sheet/sheet.cpp b/noncore/apps/opie-sheet/sheet.cpp new file mode 100644 index 0000000..9526937 --- a/dev/null +++ b/noncore/apps/opie-sheet/sheet.cpp | |||
@@ -0,0 +1,849 @@ | |||
1 | #include "sheet.h" | ||
2 | |||
3 | #include <qmainwindow.h> | ||
4 | #include <qmessagebox.h> | ||
5 | #include <math.h> | ||
6 | |||
7 | #define DEFAULT_COL_WIDTH 50 | ||
8 | |||
9 | Sheet::Sheet(int numRows, int numCols, QWidget *parent) | ||
10 | :QTable(numRows, numCols, parent) | ||
11 | { | ||
12 | defaultBorders.right=defaultBorders.bottom=QPen(Qt::gray, 1, Qt::SolidLine); | ||
13 | defaultCellData.data=""; | ||
14 | defaultCellData.background=QBrush(Qt::white, Qt::SolidPattern); | ||
15 | defaultCellData.alignment=(Qt::AlignmentFlags)(Qt::AlignLeft | Qt::AlignTop); | ||
16 | defaultCellData.fontColor=Qt::black; | ||
17 | defaultCellData.font=font(); | ||
18 | defaultCellData.borders=defaultBorders; | ||
19 | |||
20 | selectionNo=-1; | ||
21 | setSelectionMode(QTable::Single); | ||
22 | |||
23 | sheetData.setAutoDelete(TRUE); | ||
24 | clipboardData.setAutoDelete(TRUE); | ||
25 | for (int i=0; i<numCols; ++i) | ||
26 | horizontalHeader()->setLabel(i, getHeaderString(i+1), DEFAULT_COL_WIDTH); | ||
27 | |||
28 | connect(this, SIGNAL(currentChanged(int, int)), this, SLOT(slotCellSelected(int, int))); | ||
29 | connect(this, SIGNAL(valueChanged(int, int)), this, SLOT(slotCellChanged(int, int))); | ||
30 | } | ||
31 | |||
32 | Sheet::~Sheet() | ||
33 | { | ||
34 | } | ||
35 | |||
36 | typeCellData *Sheet::findCellData(int row, int col) | ||
37 | { | ||
38 | typeCellData *tempCellData; | ||
39 | for (tempCellData=sheetData.first(); tempCellData; tempCellData=sheetData.next()) | ||
40 | if (tempCellData->row==row && tempCellData->col==col) | ||
41 | return tempCellData; | ||
42 | return NULL; | ||
43 | } | ||
44 | |||
45 | void Sheet::slotCellSelected(int row, int col) | ||
46 | { | ||
47 | typeCellData *cellData=findCellData(row, col); | ||
48 | if (cellData) | ||
49 | emit currentDataChanged(cellData->data); | ||
50 | else | ||
51 | emit currentDataChanged(""); | ||
52 | } | ||
53 | |||
54 | typeCellData *Sheet::createCellData(int row, int col) | ||
55 | { | ||
56 | if (row<0 || col<0) return NULL; | ||
57 | typeCellData *cellData=new typeCellData; | ||
58 | cellData->row=row; | ||
59 | cellData->col=col; | ||
60 | cellData->data=defaultCellData.data; | ||
61 | cellData->borders=defaultCellData.borders; | ||
62 | cellData->alignment=defaultCellData.alignment; | ||
63 | cellData->font=defaultCellData.font; | ||
64 | cellData->fontColor=defaultCellData.fontColor; | ||
65 | cellData->background=defaultCellData.background; | ||
66 | sheetData.append(cellData); | ||
67 | return cellData; | ||
68 | } | ||
69 | |||
70 | void Sheet::slotCellChanged(int row, int col) | ||
71 | { | ||
72 | typeCellData *cellData=findCellData(row, col); | ||
73 | if (!cellData) cellData=createCellData(row, col); | ||
74 | if (cellData) cellData->data=text(row, col); | ||
75 | for (cellData=sheetData.first(); cellData; cellData=sheetData.next()) | ||
76 | setText(cellData->row, cellData->col, dataParser(cellData->data)); | ||
77 | emit sheetModified(); | ||
78 | } | ||
79 | |||
80 | void Sheet::swapCells(int row1, int col1, int row2, int col2) | ||
81 | { | ||
82 | typeCellData *cellData1=findCellData(row1, col1), *cellData2=findCellData(row2, col2); | ||
83 | if (!cellData1) cellData1=createCellData(row1, col1); | ||
84 | if (!cellData2) cellData2=createCellData(row2, col2); | ||
85 | if (cellData1 && cellData2) | ||
86 | { | ||
87 | QString tempData(cellData1->data); | ||
88 | cellData1->data=cellData2->data; | ||
89 | cellData2->data=tempData; | ||
90 | setText(cellData1->row, cellData1->col, dataParser(cellData1->data)); | ||
91 | setText(cellData2->row, cellData2->col, dataParser(cellData2->data)); | ||
92 | emit sheetModified(); | ||
93 | } | ||
94 | } | ||
95 | |||
96 | QString Sheet::getParameter(const QString ¶meters, int paramNo, bool giveError=FALSE, const QString funcName="") | ||
97 | { | ||
98 | QString params(parameters); | ||
99 | int position; | ||
100 | for (int i=0; i<paramNo; ++i) | ||
101 | { | ||
102 | position=params.find(','); | ||
103 | if (position<0) | ||
104 | { | ||
105 | if (giveError) QMessageBox::critical(this, tr("Error"), tr("Too few arguments to function '"+funcName+'\'')); | ||
106 | return QString(); | ||
107 | } | ||
108 | params=params.mid(position+1); | ||
109 | } | ||
110 | position=params.find(','); | ||
111 | if (position<0) return params; | ||
112 | return params.left(position); | ||
113 | } | ||
114 | |||
115 | bool Sheet::findRange(const QString &variable1, const QString &variable2, int *row1, int *col1, int *row2, int *col2) | ||
116 | { | ||
117 | int row, col; | ||
118 | if (!findRowColumn(variable1, row1, col1, TRUE) || !findRowColumn(variable2, row2, col2, TRUE)) return FALSE; | ||
119 | if (*row1>*row2) | ||
120 | { | ||
121 | row=*row1; | ||
122 | *row1=*row2; | ||
123 | *row2=row; | ||
124 | } | ||
125 | if (*col1>*col2) | ||
126 | { | ||
127 | col=*col1; | ||
128 | *col1=*col2; | ||
129 | *col2=col; | ||
130 | } | ||
131 | return TRUE; | ||
132 | } | ||
133 | |||
134 | bool Sheet::findRowColumn(const QString &variable, int *row, int *col, bool giveError=FALSE) | ||
135 | { | ||
136 | int position=variable.find(QRegExp("\\d")); | ||
137 | if (position<1) | ||
138 | { | ||
139 | if (giveError) QMessageBox::critical(this, tr("Error"), tr("Invalid variable: '"+variable+'\'')); | ||
140 | return FALSE; | ||
141 | } | ||
142 | *row=variable.mid(position).toInt()-1; | ||
143 | *col=getHeaderColumn(variable.left(position))-1; | ||
144 | return TRUE; | ||
145 | } | ||
146 | |||
147 | double Sheet::calculateVariable(const QString &variable) | ||
148 | { | ||
149 | bool ok; | ||
150 | double tempResult=variable.toDouble(&ok); | ||
151 | if (ok) return tempResult; | ||
152 | |||
153 | int row, col; | ||
154 | return (findRowColumn(variable, &row, &col, TRUE) ? text(row, col).toDouble() : 0); | ||
155 | } | ||
156 | |||
157 | double Sheet::functionSum(const QString ¶m1, const QString ¶m2) | ||
158 | { | ||
159 | int row1, col1, row2, col2, row, col; | ||
160 | if (!findRange(param1, param2, &row1, &col1, &row2, &col2)) return 0; | ||
161 | |||
162 | double result=0, tempResult; | ||
163 | bool ok; | ||
164 | for (row=row1; row<=row2; ++row) | ||
165 | for (col=col1; col<=col2; ++col) | ||
166 | { | ||
167 | tempResult=text(row, col).toDouble(&ok); | ||
168 | if (ok) result+=tempResult; | ||
169 | } | ||
170 | |||
171 | return result; | ||
172 | } | ||
173 | |||
174 | double Sheet::functionMin(const QString ¶m1, const QString ¶m2) | ||
175 | { | ||
176 | int row1, col1, row2, col2, row, col; | ||
177 | if (!findRange(param1, param2, &row1, &col1, &row2, &col2)) return 0; | ||
178 | |||
179 | double min=0, tempMin; | ||
180 | bool ok, init=FALSE; | ||
181 | for (row=row1; row<=row2; ++row) | ||
182 | for (col=col1; col<=col2; ++col) | ||
183 | { | ||
184 | tempMin=text(row, col).toDouble(&ok); | ||
185 | if (ok && (!init || tempMin<min)) | ||
186 | { | ||
187 | min=tempMin; | ||
188 | init=TRUE; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | return min; | ||
193 | } | ||
194 | |||
195 | double Sheet::functionMax(const QString ¶m1, const QString ¶m2) | ||
196 | { | ||
197 | int row1, col1, row2, col2, row, col; | ||
198 | if (!findRange(param1, param2, &row1, &col1, &row2, &col2)) return 0; | ||
199 | |||
200 | double max=0, tempMax; | ||
201 | bool ok, init=FALSE; | ||
202 | for (row=row1; row<=row2; ++row) | ||
203 | for (col=col1; col<=col2; ++col) | ||
204 | { | ||
205 | tempMax=text(row, col).toDouble(&ok); | ||
206 | if (ok && (!init || tempMax>max)) | ||
207 | { | ||
208 | max=tempMax; | ||
209 | init=TRUE; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | return max; | ||
214 | } | ||
215 | |||
216 | double Sheet::functionAvg(const QString ¶m1, const QString ¶m2) | ||
217 | { | ||
218 | double resultSum=functionSum(param1, param2), resultCount=functionCount(param1, param2); | ||
219 | return (resultCount>0 ? resultSum/resultCount : 0); | ||
220 | } | ||
221 | |||
222 | double Sheet::functionCount(const QString ¶m1, const QString ¶m2) | ||
223 | { | ||
224 | int row1, col1, row2, col2, row, col; | ||
225 | if (!findRange(param1, param2, &row1, &col1, &row2, &col2)) return 0; | ||
226 | |||
227 | int divider=0; | ||
228 | bool ok; | ||
229 | for (row=row1; row<=row2; ++row) | ||
230 | for (col=col1; col<=col2; ++col) | ||
231 | { | ||
232 | text(row, col).toDouble(&ok); | ||
233 | if (ok) ++divider; | ||
234 | } | ||
235 | |||
236 | return divider; | ||
237 | } | ||
238 | |||
239 | double Sheet::calculateFunction(const QString &function, const QString ¶meters) | ||
240 | { | ||
241 | if (function=="+") | ||
242 | return calculateVariable(getParameter(parameters, 0))+calculateVariable(getParameter(parameters, 1)); | ||
243 | if (function=="-") | ||
244 | return calculateVariable(getParameter(parameters, 0))-calculateVariable(getParameter(parameters, 1)); | ||
245 | if (function=="*") | ||
246 | return calculateVariable(getParameter(parameters, 0))*calculateVariable(getParameter(parameters, 1)); | ||
247 | if (function=="/") | ||
248 | return calculateVariable(getParameter(parameters, 0))/calculateVariable(getParameter(parameters, 1)); | ||
249 | if (function=="SUM") | ||
250 | return functionSum(getParameter(parameters, 0, TRUE, function), getParameter(parameters, 1, TRUE, function)); | ||
251 | if (function=="COUNT") | ||
252 | return functionCount(getParameter(parameters, 0, TRUE, function), getParameter(parameters, 1, TRUE, function)); | ||
253 | if (function=="MIN") | ||
254 | return functionMin(getParameter(parameters, 0, TRUE, function), getParameter(parameters, 1, TRUE, function)); | ||
255 | if (function=="MAX") | ||
256 | return functionMax(getParameter(parameters, 0, TRUE, function), getParameter(parameters, 1, TRUE, function)); | ||
257 | if (function=="AVG") | ||
258 | return functionAvg(getParameter(parameters, 0, TRUE, function), getParameter(parameters, 1, TRUE, function)); | ||
259 | if (function=="ABS") | ||
260 | return fabs(calculateVariable(getParameter(parameters, 0, TRUE, function))); | ||
261 | if (function=="SIN") | ||
262 | return sin(calculateVariable(getParameter(parameters, 0, TRUE, function))); | ||
263 | if (function=="COS") | ||
264 | return cos(calculateVariable(getParameter(parameters, 0, TRUE, function))); | ||
265 | if (function=="TAN") | ||
266 | return tan(calculateVariable(getParameter(parameters, 0, TRUE, function))); | ||
267 | if (function=="ATAN") | ||
268 | return atan(calculateVariable(getParameter(parameters, 0, TRUE, function))); | ||
269 | if (function=="ATAN2") | ||
270 | return atan2(calculateVariable(getParameter(parameters, 0, TRUE, function)), calculateVariable(getParameter(parameters, 1, TRUE, function))); | ||
271 | if (function=="ASIN") | ||
272 | return asin(calculateVariable(getParameter(parameters, 0, TRUE, function))); | ||
273 | if (function=="ACOS") | ||
274 | return acos(calculateVariable(getParameter(parameters, 0, TRUE, function))); | ||
275 | if (function=="EXP") | ||
276 | return exp(calculateVariable(getParameter(parameters, 0, TRUE, function))); | ||
277 | if (function=="LOG") | ||
278 | return log(calculateVariable(getParameter(parameters, 0, TRUE, function))); | ||
279 | if (function=="POW") | ||
280 | return pow(calculateVariable(getParameter(parameters, 0, TRUE, function)), calculateVariable(getParameter(parameters, 1, TRUE, function))); | ||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | int Sheet::getOperatorPriority(char oper) | ||
285 | { | ||
286 | switch (oper) | ||
287 | { | ||
288 | case '+': | ||
289 | case '-': | ||
290 | return 1; | ||
291 | |||
292 | case '*': | ||
293 | case '/': | ||
294 | return 2; | ||
295 | } | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | void Sheet::pushCharStack(QStack<QChar> *stackChars, const QChar &character) | ||
300 | { | ||
301 | QChar *temp=new QChar(character); | ||
302 | stackChars->push(temp); | ||
303 | } | ||
304 | |||
305 | void Sheet::pushStringStack(QStack<QString> *stackStrings, const QString &string) | ||
306 | { | ||
307 | QString *temp=new QString(string); | ||
308 | stackStrings->push(temp); | ||
309 | } | ||
310 | |||
311 | QChar Sheet::popCharStack(QStack<QChar> *stackChars) | ||
312 | { | ||
313 | if (stackChars->isEmpty()) | ||
314 | { | ||
315 | QMessageBox::critical(this, tr("Error"), tr("Syntax error!")); | ||
316 | return '0'; | ||
317 | } | ||
318 | |||
319 | QChar *temp=stackChars->pop(); | ||
320 | QChar temp2(*temp); | ||
321 | delete temp; | ||
322 | return temp2; | ||
323 | } | ||
324 | |||
325 | QString Sheet::popStringStack(QStack<QString> *stackStrings) | ||
326 | { | ||
327 | if (stackStrings->isEmpty()) | ||
328 | { | ||
329 | QMessageBox::critical(this, tr("Error"), tr("Syntax error!")); | ||
330 | return "0"; | ||
331 | } | ||
332 | |||
333 | QString *temp=stackStrings->pop(); | ||
334 | QString temp2(*temp); | ||
335 | delete temp; | ||
336 | return temp2; | ||
337 | } | ||
338 | |||
339 | QString Sheet::dataParserHelper(const QString &data) | ||
340 | { | ||
341 | QStack<QString> stackElements; | ||
342 | QStack<QChar> stackOperators; | ||
343 | QString tempElement(""), temp2Element, firstElement, secondElement; | ||
344 | int paranCount; | ||
345 | |||
346 | for (unsigned int i=0; i<data.length(); ++i) | ||
347 | { | ||
348 | if (data[i]=='+' || data[i]=='-' || data[i]=='*' || data[i]=='/') | ||
349 | { | ||
350 | pushStringStack(&stackElements, tempElement); | ||
351 | tempElement=""; | ||
352 | if (!stackOperators.isEmpty() && getOperatorPriority(*stackOperators.top())>getOperatorPriority(data[i])) | ||
353 | { | ||
354 | secondElement=popStringStack(&stackElements); | ||
355 | firstElement=popStringStack(&stackElements); | ||
356 | pushStringStack(&stackElements, QString::number(calculateFunction(popCharStack(&stackOperators), firstElement+","+secondElement))); | ||
357 | } | ||
358 | pushCharStack(&stackOperators, data[i]); | ||
359 | } | ||
360 | else | ||
361 | if (data[i]==',') | ||
362 | { | ||
363 | if (!tempElement.isEmpty()) pushStringStack(&stackElements, tempElement); | ||
364 | while (!stackOperators.isEmpty()) | ||
365 | { | ||
366 | secondElement=popStringStack(&stackElements); | ||
367 | firstElement=popStringStack(&stackElements); | ||
368 | pushStringStack(&stackElements, QString::number(calculateFunction(popCharStack(&stackOperators), firstElement+","+secondElement))); | ||
369 | } | ||
370 | tempElement=""; | ||
371 | } | ||
372 | else | ||
373 | if (data[i]=='(') | ||
374 | { | ||
375 | paranCount=1; | ||
376 | temp2Element=""; | ||
377 | for (++i; paranCount>0; ++i) | ||
378 | { | ||
379 | temp2Element+=data[i]; | ||
380 | if (data[i]=='(') ++paranCount; | ||
381 | if (data[i]==')') --paranCount; | ||
382 | } | ||
383 | temp2Element=dataParserHelper(temp2Element.left(temp2Element.length()-1)); | ||
384 | if (tempElement.isEmpty()) | ||
385 | tempElement=temp2Element; | ||
386 | else | ||
387 | tempElement.setNum(calculateFunction(tempElement, temp2Element)); | ||
388 | --i; | ||
389 | } | ||
390 | else | ||
391 | tempElement+=data[i]; | ||
392 | } | ||
393 | if (!tempElement.isEmpty()) pushStringStack(&stackElements, tempElement); | ||
394 | while (!stackOperators.isEmpty()) | ||
395 | { | ||
396 | secondElement=popStringStack(&stackElements); | ||
397 | firstElement=popStringStack(&stackElements); | ||
398 | pushStringStack(&stackElements, QString::number(calculateFunction(popCharStack(&stackOperators), firstElement+","+secondElement))); | ||
399 | } | ||
400 | |||
401 | if (!stackElements.isEmpty()) | ||
402 | tempElement=popStringStack(&stackElements); | ||
403 | while (!stackElements.isEmpty()) | ||
404 | tempElement.prepend(popStringStack(&stackElements)+","); | ||
405 | return tempElement; | ||
406 | } | ||
407 | |||
408 | QString Sheet::dataParser(const QString &data) | ||
409 | { | ||
410 | QString strippedData(data); | ||
411 | strippedData.replace(QRegExp("\\s"), ""); | ||
412 | if (strippedData.isEmpty() || strippedData[0]!='=') return data; | ||
413 | strippedData=dataParserHelper(strippedData.remove(0, 1).upper().replace(QRegExp(":"), ",")); | ||
414 | |||
415 | int i=0; | ||
416 | QString tempParameter(getParameter(strippedData, i)), result=""; | ||
417 | do | ||
418 | { | ||
419 | result+=","+QString::number(calculateVariable(tempParameter)); | ||
420 | tempParameter=getParameter(strippedData, ++i); | ||
421 | } | ||
422 | while (!tempParameter.isNull()); | ||
423 | return result.mid(1); | ||
424 | } | ||
425 | |||
426 | void Sheet::setData(const QString &data) | ||
427 | { | ||
428 | setText(currentRow(), currentColumn(), data); | ||
429 | slotCellChanged(currentRow(), currentColumn()); | ||
430 | activateNextCell(); | ||
431 | } | ||
432 | |||
433 | QString Sheet::getData() | ||
434 | { | ||
435 | typeCellData *cellData=findCellData(currentRow(), currentColumn()); | ||
436 | if (cellData) | ||
437 | return cellData->data; | ||
438 | return ""; | ||
439 | } | ||
440 | |||
441 | void Sheet::lockClicks(bool lock=TRUE) | ||
442 | { | ||
443 | clicksLocked=lock; | ||
444 | } | ||
445 | |||
446 | void Sheet::paintCell(QPainter *p, int row, int col, const QRect & cr, bool selected) | ||
447 | { | ||
448 | if (selected && row==currentRow() && col==currentColumn()) selected=FALSE; | ||
449 | |||
450 | int sheetDataCurrent=sheetData.at(); | ||
451 | typeCellData *cellData=findCellData(row, col); | ||
452 | if (sheetDataCurrent>=0) sheetData.at(sheetDataCurrent); | ||
453 | if (!cellData) cellData=&defaultCellData; | ||
454 | if (selected) | ||
455 | p->fillRect(0, 0, cr.width(), cr.height(), colorGroup().highlight()); | ||
456 | else | ||
457 | { | ||
458 | p->fillRect(0, 0, cr.width(), cr.height(), colorGroup().base()); | ||
459 | p->fillRect(0, 0, cr.width(), cr.height(), cellData->background); | ||
460 | } | ||
461 | |||
462 | QTableItem *cellItem=item(row, col); | ||
463 | if (cellItem) | ||
464 | { | ||
465 | p->setPen(selected ? colorGroup().highlightedText() : cellData->fontColor); | ||
466 | p->setFont(cellData->font); | ||
467 | p->drawText(2, 2, cr.width()-4, cr.height()-4, cellData->alignment, cellItem->text()); | ||
468 | } | ||
469 | |||
470 | int rx=cr.width()-1, ry=cr.height()-1; | ||
471 | QPen pen(p->pen()); | ||
472 | p->setPen(cellData->borders.right); | ||
473 | p->drawLine(rx, 0, rx, ry); | ||
474 | p->setPen(cellData->borders.bottom); | ||
475 | p->drawLine(0, ry, rx, ry); | ||
476 | p->setPen(pen); | ||
477 | } | ||
478 | |||
479 | void Sheet::viewportMousePressEvent(QMouseEvent *e) | ||
480 | { | ||
481 | QMouseEvent ce(e->type(), viewportToContents(e->pos()), e->globalPos(), e->button(), e->state()); | ||
482 | if (clicksLocked) | ||
483 | { | ||
484 | if (selectionNo<0) | ||
485 | { | ||
486 | clearSelection(); | ||
487 | QTableSelection newSelection; | ||
488 | newSelection.init(rowAt(ce.pos().y()), columnAt(ce.pos().x())); | ||
489 | newSelection.expandTo(newSelection.anchorRow(), newSelection.anchorCol()); | ||
490 | selectionNo=addSelection(newSelection); | ||
491 | } | ||
492 | } | ||
493 | else | ||
494 | QTable::contentsMousePressEvent(&ce); | ||
495 | } | ||
496 | |||
497 | void Sheet::viewportMouseMoveEvent(QMouseEvent *e) | ||
498 | { | ||
499 | QMouseEvent ce(e->type(), viewportToContents(e->pos()), e->globalPos(), e->button(), e->state()); | ||
500 | if (clicksLocked) | ||
501 | { | ||
502 | if (selectionNo>=0) | ||
503 | { | ||
504 | QTableSelection oldSelection(selection(selectionNo)); | ||
505 | oldSelection.expandTo(rowAt(ce.pos().y()), columnAt(ce.pos().x())); | ||
506 | if (!(oldSelection==selection(selectionNo))) | ||
507 | { | ||
508 | removeSelection(selectionNo); | ||
509 | selectionNo=addSelection(oldSelection); | ||
510 | } | ||
511 | } | ||
512 | } | ||
513 | else | ||
514 | QTable::contentsMouseMoveEvent(&ce); | ||
515 | } | ||
516 | |||
517 | void Sheet::viewportMouseReleaseEvent(QMouseEvent *e) | ||
518 | { | ||
519 | QMouseEvent ce(e->type(), viewportToContents(e->pos()), e->globalPos(), e->button(), e->state()); | ||
520 | if (clicksLocked && selectionNo>=0) | ||
521 | { | ||
522 | QTableSelection oldSelection(selection(selectionNo)); | ||
523 | oldSelection.expandTo(rowAt(ce.pos().y()), columnAt(ce.pos().x())); | ||
524 | removeSelection(selectionNo); | ||
525 | selectionNo=-1; | ||
526 | if (oldSelection.topRow()==oldSelection.bottomRow() && oldSelection.leftCol()==oldSelection.rightCol()) | ||
527 | emit cellClicked(getHeaderString(oldSelection.leftCol()+1)+QString::number(oldSelection.topRow()+1)); | ||
528 | else | ||
529 | emit cellClicked(getHeaderString(oldSelection.leftCol()+1)+QString::number(oldSelection.topRow()+1)+','+getHeaderString(oldSelection.rightCol()+1)+QString::number(oldSelection.bottomRow()+1)); | ||
530 | } | ||
531 | else | ||
532 | QTable::contentsMouseReleaseEvent(&ce); | ||
533 | } | ||
534 | |||
535 | void Sheet::copySheetData(QList<typeCellData> *destSheetData) | ||
536 | { | ||
537 | typeCellData *tempCellData, *newCellData; | ||
538 | destSheetData->clear(); | ||
539 | |||
540 | for (tempCellData=sheetData.first(); tempCellData; tempCellData=sheetData.next()) | ||
541 | { | ||
542 | newCellData=new typeCellData; | ||
543 | *newCellData=*tempCellData; | ||
544 | destSheetData->append(newCellData); | ||
545 | } | ||
546 | } | ||
547 | |||
548 | void Sheet::setSheetData(QList<typeCellData> *srcSheetData) | ||
549 | { | ||
550 | typeCellData *tempCellData, *newCellData; | ||
551 | |||
552 | for (tempCellData=sheetData.first(); tempCellData; tempCellData=sheetData.next()) | ||
553 | { | ||
554 | clearCell(tempCellData->row, tempCellData->col); | ||
555 | updateCell(tempCellData->row, tempCellData->col); | ||
556 | } | ||
557 | sheetData.clear(); | ||
558 | |||
559 | for (tempCellData=srcSheetData->first(); tempCellData; tempCellData=srcSheetData->next()) | ||
560 | { | ||
561 | newCellData=new typeCellData; | ||
562 | *newCellData=*tempCellData; | ||
563 | sheetData.append(newCellData); | ||
564 | setText(newCellData->row, newCellData->col, dataParser(newCellData->data)); | ||
565 | } | ||
566 | emit sheetModified(); | ||
567 | } | ||
568 | |||
569 | void Sheet::setName(const QString &name) | ||
570 | { | ||
571 | sheetName=name; | ||
572 | emit sheetModified(); | ||
573 | } | ||
574 | |||
575 | QString Sheet::getName() | ||
576 | { | ||
577 | return sheetName; | ||
578 | } | ||
579 | |||
580 | void Sheet::setBrush(int row, int col, const QBrush &brush) | ||
581 | { | ||
582 | typeCellData *cellData=findCellData(row, col); | ||
583 | if (!cellData) cellData=createCellData(row, col); | ||
584 | if (cellData) | ||
585 | { | ||
586 | cellData->background=brush; | ||
587 | emit sheetModified(); | ||
588 | } | ||
589 | } | ||
590 | |||
591 | QBrush Sheet::getBrush(int row, int col) | ||
592 | { | ||
593 | typeCellData *cellData=findCellData(row, col); | ||
594 | if (!cellData) cellData=&defaultCellData; | ||
595 | return cellData->background; | ||
596 | } | ||
597 | |||
598 | void Sheet::setTextAlign(int row, int col, Qt::AlignmentFlags flags) | ||
599 | { | ||
600 | typeCellData *cellData=findCellData(row, col); | ||
601 | if (!cellData) cellData=createCellData(row, col); | ||
602 | if (cellData) | ||
603 | { | ||
604 | cellData->alignment=flags; | ||
605 | emit sheetModified(); | ||
606 | } | ||
607 | } | ||
608 | |||
609 | Qt::AlignmentFlags Sheet::getAlignment(int row, int col) | ||
610 | { | ||
611 | typeCellData *cellData=findCellData(row, col); | ||
612 | if (!cellData) cellData=&defaultCellData; | ||
613 | return cellData->alignment; | ||
614 | } | ||
615 | |||
616 | void Sheet::setTextFont(int row, int col, const QFont &font, const QColor &color) | ||
617 | { | ||
618 | typeCellData *cellData=findCellData(row, col); | ||
619 | if (!cellData) cellData=createCellData(row, col); | ||
620 | if (cellData) | ||
621 | { | ||
622 | cellData->font=font; | ||
623 | cellData->fontColor=color; | ||
624 | emit sheetModified(); | ||
625 | } | ||
626 | } | ||
627 | |||
628 | QFont Sheet::getFont(int row, int col) | ||
629 | { | ||
630 | typeCellData *cellData=findCellData(row, col); | ||
631 | if (!cellData) cellData=&defaultCellData; | ||
632 | return cellData->font; | ||
633 | } | ||
634 | |||
635 | QColor Sheet::getFontColor(int row, int col) | ||
636 | { | ||
637 | typeCellData *cellData=findCellData(row, col); | ||
638 | if (!cellData) cellData=&defaultCellData; | ||
639 | return cellData->fontColor; | ||
640 | } | ||
641 | |||
642 | void Sheet::setPen(int row, int col, int vertical, const QPen &pen) | ||
643 | { | ||
644 | typeCellData *cellData=findCellData(row, col); | ||
645 | if (!cellData) cellData=createCellData(row, col); | ||
646 | if (cellData) | ||
647 | { | ||
648 | if (vertical) | ||
649 | cellData->borders.right=pen; | ||
650 | else | ||
651 | cellData->borders.bottom=pen; | ||
652 | emit sheetModified(); | ||
653 | } | ||
654 | } | ||
655 | |||
656 | QPen Sheet::getPen(int row, int col, int vertical) | ||
657 | { | ||
658 | typeCellData *cellData=findCellData(row, col); | ||
659 | if (!cellData) cellData=&defaultCellData; | ||
660 | return (vertical ? cellData->borders.right : cellData->borders.bottom); | ||
661 | } | ||
662 | |||
663 | void Sheet::getSelection(int *row1, int *col1, int *row2, int *col2) | ||
664 | { | ||
665 | int selectionNo=currentSelection(); | ||
666 | if (selectionNo>=0) | ||
667 | { | ||
668 | QTableSelection selection(selection(selectionNo)); | ||
669 | *row1=selection.topRow(); | ||
670 | *row2=selection.bottomRow(); | ||
671 | *col1=selection.leftCol(); | ||
672 | *col2=selection.rightCol(); | ||
673 | } | ||
674 | else | ||
675 | { | ||
676 | *row1=*row2=currentRow(); | ||
677 | *col1=*col2=currentColumn(); | ||
678 | } | ||
679 | } | ||
680 | |||
681 | void Sheet::editClear() | ||
682 | { | ||
683 | int row1, row2, col1, col2; | ||
684 | getSelection(&row1, &col1, &row2, &col2); | ||
685 | |||
686 | int row, col; | ||
687 | for (row=row1; row<=row2; ++row) | ||
688 | for (col=col1; col<=col2; ++col) | ||
689 | { | ||
690 | setText(row, col, ""); | ||
691 | slotCellChanged(row, col); | ||
692 | } | ||
693 | } | ||
694 | |||
695 | void Sheet::editCopy() | ||
696 | { | ||
697 | clipboardData.clear(); | ||
698 | |||
699 | int row1, row2, col1, col2; | ||
700 | getSelection(&row1, &col1, &row2, &col2); | ||
701 | |||
702 | typeCellData *cellData, *newCellData; | ||
703 | int row, col; | ||
704 | for (row=row1; row<=row2; ++row) | ||
705 | for (col=col1; col<=col2; ++col) | ||
706 | { | ||
707 | cellData=findCellData(row, col); | ||
708 | if (cellData) | ||
709 | { | ||
710 | newCellData=new typeCellData; | ||
711 | *newCellData=*cellData; | ||
712 | newCellData->row-=row1; | ||
713 | newCellData->col-=col1; | ||
714 | clipboardData.append(newCellData); | ||
715 | } | ||
716 | } | ||
717 | } | ||
718 | |||
719 | void Sheet::editCut() | ||
720 | { | ||
721 | editCopy(); | ||
722 | editClear(); | ||
723 | } | ||
724 | |||
725 | void Sheet::editPaste(bool onlyContents=FALSE) | ||
726 | { | ||
727 | int row1=currentRow(), col1=currentColumn(); | ||
728 | typeCellData *cellData, *tempCellData; | ||
729 | |||
730 | for (tempCellData=clipboardData.first(); tempCellData; tempCellData=clipboardData.next()) | ||
731 | { | ||
732 | cellData=findCellData(tempCellData->row+row1, tempCellData->col+col1); | ||
733 | if (!cellData) cellData=createCellData(tempCellData->row+row1, tempCellData->col+col1); | ||
734 | if (cellData) | ||
735 | { | ||
736 | if (onlyContents) | ||
737 | cellData->data=tempCellData->data; | ||
738 | else | ||
739 | { | ||
740 | *cellData=*tempCellData; | ||
741 | cellData->row+=row1; | ||
742 | cellData->col+=col1; | ||
743 | } | ||
744 | setText(cellData->row, cellData->col, dataParser(cellData->data)); | ||
745 | emit sheetModified(); | ||
746 | } | ||
747 | } | ||
748 | } | ||
749 | |||
750 | void Sheet::insertRows(int no=1, bool allColumns=TRUE) | ||
751 | { | ||
752 | setNumRows(numRows()+no); | ||
753 | |||
754 | typeCellData *tempCellData; | ||
755 | int row=currentRow(), col=currentColumn(); | ||
756 | |||
757 | for (tempCellData=sheetData.first(); tempCellData; tempCellData=sheetData.next()) | ||
758 | if (tempCellData->row>=row && (allColumns || tempCellData->col==col)) | ||
759 | { | ||
760 | clearCell(tempCellData->row, tempCellData->col); | ||
761 | tempCellData->row+=no; | ||
762 | } | ||
763 | for (tempCellData=sheetData.first(); tempCellData; tempCellData=sheetData.next()) | ||
764 | if (tempCellData->row>=row && (allColumns || tempCellData->col==col)) | ||
765 | { | ||
766 | updateCell(tempCellData->row-no, tempCellData->col); | ||
767 | setText(tempCellData->row, tempCellData->col, dataParser(tempCellData->data)); | ||
768 | } | ||
769 | emit sheetModified(); | ||
770 | } | ||
771 | |||
772 | void Sheet::insertColumns(int no=1, bool allRows=TRUE) | ||
773 | { | ||
774 | int noCols=numCols(); | ||
775 | int newCols=noCols+no; | ||
776 | setNumCols(newCols); | ||
777 | for (int i=noCols; i<newCols; ++i) | ||
778 | horizontalHeader()->setLabel(i, getHeaderString(i+1), DEFAULT_COL_WIDTH); | ||
779 | |||
780 | typeCellData *tempCellData; | ||
781 | int col=currentColumn(), row=currentRow(); | ||
782 | |||
783 | for (tempCellData=sheetData.first(); tempCellData; tempCellData=sheetData.next()) | ||
784 | if (tempCellData->col>=col && (allRows || tempCellData->row==row)) | ||
785 | { | ||
786 | clearCell(tempCellData->row, tempCellData->col); | ||
787 | tempCellData->col+=no; | ||
788 | } | ||
789 | for (tempCellData=sheetData.first(); tempCellData; tempCellData=sheetData.next()) | ||
790 | if (tempCellData->col>=col && (allRows || tempCellData->row==row)) | ||
791 | { | ||
792 | updateCell(tempCellData->row, tempCellData->col-no); | ||
793 | setText(tempCellData->row, tempCellData->col, dataParser(tempCellData->data)); | ||
794 | } | ||
795 | emit sheetModified(); | ||
796 | } | ||
797 | |||
798 | void Sheet::dataFindReplace(const QString &findStr, const QString &replaceStr, bool matchCase=TRUE, bool allCells=TRUE, bool entireCell=FALSE, bool replace=FALSE, bool replaceAll=FALSE) | ||
799 | { | ||
800 | typeCellData *tempCellData; | ||
801 | int row1, col1, row2, col2; | ||
802 | getSelection(&row1, &col1, &row2, &col2); | ||
803 | bool found=FALSE; | ||
804 | |||
805 | for (tempCellData=sheetData.first(); tempCellData; tempCellData=sheetData.next()) | ||
806 | if (allCells || (tempCellData->row>=row1 && tempCellData->row<=row2 && tempCellData->col>=col1 && tempCellData->col<=col2)) | ||
807 | { | ||
808 | QTableItem *cellItem=item(tempCellData->row, tempCellData->col); | ||
809 | if (cellItem && (entireCell ? (matchCase ? cellItem->text()==findStr : cellItem->text().upper()==findStr.upper()) : cellItem->text().find(findStr, 0, matchCase)>=0)) | ||
810 | { | ||
811 | if (!found) | ||
812 | { | ||
813 | found=TRUE; | ||
814 | clearSelection(); | ||
815 | } | ||
816 | setCurrentCell(tempCellData->row, tempCellData->col); | ||
817 | if (replace) | ||
818 | { | ||
819 | tempCellData->data=cellItem->text().replace(QRegExp(findStr, matchCase), replaceStr); | ||
820 | setText(tempCellData->row, tempCellData->col, dataParser(tempCellData->data)); | ||
821 | } | ||
822 | if (!replace || !replaceAll) break; | ||
823 | } | ||
824 | } | ||
825 | |||
826 | if (found) | ||
827 | { | ||
828 | if (replace) | ||
829 | slotCellChanged(currentRow(), currentColumn()); | ||
830 | } | ||
831 | else | ||
832 | QMessageBox::warning(this, tr("Error"), tr("Search key not found!")); | ||
833 | } | ||
834 | |||
835 | // | ||
836 | // Static functions | ||
837 | // | ||
838 | |||
839 | QString Sheet::getHeaderString(int section) | ||
840 | { | ||
841 | if (section<1) return ""; | ||
842 | return getHeaderString((section-1)/26)+QChar('A'+(section-1)%26); | ||
843 | } | ||
844 | |||
845 | int Sheet::getHeaderColumn(const QString §ion) | ||
846 | { | ||
847 | if (section.isEmpty()) return 0; | ||
848 | return (section[section.length()-1]-'A'+1)+getHeaderColumn(section.left(section.length()-1))*26; | ||
849 | } | ||