Rev 514 | Rev 575 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 514 | Rev 515 | ||
---|---|---|---|
1 | Redirecting to URL 'https://iland.boku.ac.at/svn/iland/tags/release_1.0/src/core/modelcontroller.cpp': |
1 | Redirecting to URL 'https://iland.boku.ac.at/svn/iland/tags/release_1.0/src/core/modelcontroller.cpp': |
2 | /** ModelController is a helper class used to
|
2 | /** ModelController is a helper class used to
|
3 | control the flow of operations during a model run.
|
3 | control the flow of operations during a model run.
|
4 | Really useful???? or a dispatcher???
|
4 | Really useful???? or a dispatcher???
|
5 | */
|
5 | */
|
6 | 6 | ||
7 | #include "global.h"
|
7 | #include "global.h"
|
8 | #include "modelcontroller.h"
|
8 | #include "modelcontroller.h"
|
9 | #include <QObject>
|
9 | #include <QObject>
|
10 | 10 | ||
11 | #include "model.h"
|
11 | #include "model.h"
|
12 | #include "helper.h"
|
12 | #include "helper.h"
|
13 | #include "expression.h"
|
13 | #include "expression.h"
|
14 | #include "expressionwrapper.h"
|
14 | #include "expressionwrapper.h"
|
15 | #include "../output/outputmanager.h"
|
15 | #include "../output/outputmanager.h"
|
16 | 16 | ||
17 | #include "species.h"
|
17 | #include "species.h"
|
18 | #include "speciesset.h"
|
18 | #include "speciesset.h"
|
19 | 19 | ||
20 | #include "mainwindow.h" // for the debug message buffering
|
20 | #include "mainwindow.h" // for the debug message buffering
|
21 | 21 | ||
22 | ModelController::ModelController() |
22 | ModelController::ModelController() |
23 | {
|
23 | {
|
24 | mModel = NULL; |
24 | mModel = NULL; |
25 | mPaused = false; |
25 | mPaused = false; |
26 | mRunning = false; |
26 | mRunning = false; |
27 | mYearsToRun = 0; |
27 | mYearsToRun = 0; |
28 | }
|
28 | }
|
29 | 29 | ||
30 | ModelController::~ModelController() |
30 | ModelController::~ModelController() |
31 | {
|
31 | {
|
32 | destroy(); |
32 | destroy(); |
33 | }
|
33 | }
|
34 | 34 | ||
35 | /// prepare a list of all (active) species
|
35 | /// prepare a list of all (active) species
|
36 | QHash<QString, QString> ModelController::availableSpecies() |
36 | QHash<QString, QString> ModelController::availableSpecies() |
37 | {
|
37 | {
|
38 | QHash<QString, QString> list; |
38 | QHash<QString, QString> list; |
39 | if (mModel) { |
39 | if (mModel) { |
40 | SpeciesSet *set = mModel->speciesSet(); |
40 | SpeciesSet *set = mModel->speciesSet(); |
41 | if (!set) |
41 | if (!set) |
42 | throw IException("there are 0 or more than one species sets."); |
42 | throw IException("there are 0 or more than one species sets."); |
43 | foreach (const Species *s, set->activeSpecies()) { |
43 | foreach (const Species *s, set->activeSpecies()) { |
44 | list[s->id()] = s->name(); |
44 | list[s->id()] = s->name(); |
45 | }
|
45 | }
|
46 | }
|
46 | }
|
47 | return list; |
47 | return list; |
48 | }
|
48 | }
|
49 | 49 | ||
50 | bool ModelController::canCreate() |
50 | bool ModelController::canCreate() |
51 | {
|
51 | {
|
52 | if (mModel) |
52 | if (mModel) |
53 | return false; |
53 | return false; |
54 | return true; |
54 | return true; |
55 | }
|
55 | }
|
56 | 56 | ||
57 | bool ModelController::canDestroy() |
57 | bool ModelController::canDestroy() |
58 | {
|
58 | {
|
59 | return mModel != NULL; |
59 | return mModel != NULL; |
60 | }
|
60 | }
|
61 | 61 | ||
62 | bool ModelController::canRun() |
62 | bool ModelController::canRun() |
63 | {
|
63 | {
|
64 | if (mModel && mModel->isSetup()) |
64 | if (mModel && mModel->isSetup()) |
65 | return true; |
65 | return true; |
66 | return false; |
66 | return false; |
67 | }
|
67 | }
|
68 | 68 | ||
69 | bool ModelController::isRunning() |
69 | bool ModelController::isRunning() |
70 | {
|
70 | {
|
71 | return mRunning; |
71 | return mRunning; |
72 | }
|
72 | }
|
73 | 73 | ||
74 | bool ModelController::isFinished() |
74 | bool ModelController::isFinished() |
75 | {
|
75 | {
|
76 | if (!mModel) |
76 | if (!mModel) |
77 | return false; |
77 | return false; |
78 | return canRun() && !isRunning() && mFinished; |
78 | return canRun() && !isRunning() && mFinished; |
79 | }
|
79 | }
|
80 | 80 | ||
81 | int ModelController::currentYear() const |
81 | int ModelController::currentYear() const |
82 | {
|
82 | {
|
83 | return GlobalSettings::instance()->currentYear(); |
83 | return GlobalSettings::instance()->currentYear(); |
84 | }
|
84 | }
|
85 | 85 | ||
86 | void ModelController::setFileName(QString initFileName) |
86 | void ModelController::setFileName(QString initFileName) |
87 | {
|
87 | {
|
88 | mInitFile = initFileName; |
88 | mInitFile = initFileName; |
89 | try { |
89 | try { |
90 | GlobalSettings::instance()->loadProjectFile(mInitFile); |
90 | GlobalSettings::instance()->loadProjectFile(mInitFile); |
91 | } catch(const IException &e) { |
91 | } catch(const IException &e) { |
92 | QString error_msg = e.toString(); |
92 | QString error_msg = e.toString(); |
93 | Helper::msg(error_msg); |
93 | Helper::msg(error_msg); |
94 | qDebug() << error_msg; |
94 | qDebug() << error_msg; |
95 | }
|
95 | }
|
96 | }
|
96 | }
|
97 | 97 | ||
98 | void ModelController::create() |
98 | void ModelController::create() |
99 | {
|
99 | {
|
100 | if (!canCreate()) |
100 | if (!canCreate()) |
101 | return; |
101 | return; |
102 | MainWindow::bufferedLog(true); |
102 | MainWindow::bufferedLog(true); |
103 | try { |
103 | try { |
104 | DebugTimer::clearAllTimers(); |
104 | DebugTimer::clearAllTimers(); |
105 | mModel = new Model(); |
105 | mModel = new Model(); |
106 | mModel->loadProject(); |
106 | mModel->loadProject(); |
107 | if (!mModel->isSetup()) |
107 | if (!mModel->isSetup()) |
108 | return; |
108 | return; |
109 | 109 | ||
110 | // reset clock...
|
110 | // reset clock...
|
111 | GlobalSettings::instance()->setCurrentYear(1); // reset clock |
111 | GlobalSettings::instance()->setCurrentYear(1); // reset clock |
112 | // initialization of trees, output on startup
|
112 | // initialization of trees, output on startup
|
113 | mModel->beforeRun(); |
113 | mModel->beforeRun(); |
114 | } catch(const IException &e) { |
114 | } catch(const IException &e) { |
115 | QString error_msg = e.toString(); |
115 | QString error_msg = e.toString(); |
116 | Helper::msg(error_msg); |
116 | Helper::msg(error_msg); |
117 | qDebug() << error_msg; |
117 | qDebug() << error_msg; |
118 | }
|
118 | }
|
119 | MainWindow::bufferedLog(false); |
119 | MainWindow::bufferedLog(false); |
120 | qDebug() << "Model created."; |
120 | qDebug() << "Model created."; |
121 | }
|
121 | }
|
122 | 122 | ||
123 | void ModelController::destroy() |
123 | void ModelController::destroy() |
124 | {
|
124 | {
|
125 | if (canDestroy()) { |
125 | if (canDestroy()) { |
126 | delete mModel; |
126 | delete mModel; |
127 | mModel = 0; |
127 | mModel = 0; |
128 | GlobalSettings::instance()->setCurrentYear(0); |
128 | GlobalSettings::instance()->setCurrentYear(0); |
129 | qDebug() << "ModelController: Model destroyed."; |
129 | qDebug() << "ModelController: Model destroyed."; |
130 | }
|
130 | }
|
131 | }
|
131 | }
|
132 | 132 | ||
133 | void ModelController::runloop() |
133 | void ModelController::runloop() |
134 | {
|
134 | {
|
135 | - | ||
- | 135 | static QTime sLastTime = QTime::currentTime(); |
|
136 | QApplication::processEvents(); |
136 | QApplication::processEvents(); |
137 | if (mPaused) |
137 | if (mPaused) |
138 | return; |
138 | return; |
139 | bool doStop = false; |
139 | bool doStop = false; |
140 | bool hasError = false; |
140 | bool hasError = false; |
- | 141 | if (GlobalSettings::instance()->currentYear()<=1) { |
|
- | 142 | sLastTime = QTime::currentTime(); // reset clock at the beginning of the simulation |
|
- | 143 | }
|
|
141 | 144 | ||
142 | if (!mCanceled && GlobalSettings::instance()->currentYear() < mYearsToRun) { |
145 | if (!mCanceled && GlobalSettings::instance()->currentYear() < mYearsToRun) { |
143 | MainWindow::bufferedLog(true); // start buffering |
146 | MainWindow::bufferedLog(true); // start buffering |
144 | hasError = runYear(); // do the work |
147 | hasError = runYear(); // do the work |
145 | mRunning = true; |
148 | mRunning = true; |
146 | emit year(GlobalSettings::instance()->currentYear()); |
149 | emit year(GlobalSettings::instance()->currentYear()); |
147 | if (!hasError) { |
150 | if (!hasError) { |
- | 151 | int elapsed = sLastTime.msecsTo(QTime::currentTime()); |
|
148 | int time=0; |
152 | int time=0; |
149 | if (currentYear()%50==0) |
- | |
- | 153 | if (currentYear()%50==0 && elapsed>10000) |
|
150 | time = 100; // a 100ms pause... |
154 | time = 100; // a 100ms pause... |
151 | if (currentYear()%100==0) { |
- | |
- | 155 | if (currentYear()%100==0 && elapsed>10000) { |
|
152 | time = 500; // a 500ms pause... |
156 | time = 500; // a 500ms pause... |
- | 157 | }
|
|
- | 158 | if (time>0) { |
|
- | 159 | sLastTime = QTime::currentTime(); // reset clock |
|
- | 160 | qDebug() << "--- little break ---- (after " << elapsed << "ms)."; |
|
153 | }
|
161 | }
|
154 | QTimer::singleShot(time,this, SLOT(runloop())); |
162 | QTimer::singleShot(time,this, SLOT(runloop())); |
155 | }
|
163 | }
|
156 | else
|
164 | else
|
157 | doStop = true; // an error occured |
165 | doStop = true; // an error occured |
158 | 166 | ||
159 | } else { |
167 | } else { |
160 | doStop = true; // all years simulated |
168 | doStop = true; // all years simulated |
161 | }
|
169 | }
|
162 | 170 | ||
163 | if (doStop || mCanceled) { |
171 | if (doStop || mCanceled) { |
164 | // finished
|
172 | // finished
|
165 | mRunning = false; |
173 | mRunning = false; |
166 | GlobalSettings::instance()->outputManager()->save(); |
174 | GlobalSettings::instance()->outputManager()->save(); |
167 | DebugTimer::printAllTimers(); |
175 | DebugTimer::printAllTimers(); |
168 | mFinished = true; |
176 | mFinished = true; |
169 | MainWindow::bufferedLog(false); // stop buffering |
177 | MainWindow::bufferedLog(false); // stop buffering |
170 | emit finished(QString()); |
178 | emit finished(QString()); |
171 | }
|
179 | }
|
172 | 180 | ||
173 | QApplication::processEvents(); |
181 | QApplication::processEvents(); |
174 | }
|
182 | }
|
175 | 183 | ||
176 | void ModelController::run(int years) |
184 | void ModelController::run(int years) |
177 | {
|
185 | {
|
178 | if (!canRun()) |
186 | if (!canRun()) |
179 | return; |
187 | return; |
180 | MainWindow::bufferedLog(true); |
188 | MainWindow::bufferedLog(true); |
181 | DebugTimer many_runs(QString("Timer for %1 runs").arg(years)); |
189 | DebugTimer many_runs(QString("Timer for %1 runs").arg(years)); |
182 | mPaused = false; |
190 | mPaused = false; |
183 | mFinished = false; |
191 | mFinished = false; |
184 | mCanceled = false; |
192 | mCanceled = false; |
185 | mYearsToRun = years; |
193 | mYearsToRun = years; |
186 | //GlobalSettings::instance()->setCurrentYear(1); // reset clock
|
194 | //GlobalSettings::instance()->setCurrentYear(1); // reset clock
|
187 | 195 | ||
188 | DebugTimer::clearAllTimers(); |
196 | DebugTimer::clearAllTimers(); |
189 | 197 | ||
190 | runloop(); // start the running loop |
198 | runloop(); // start the running loop |
191 | 199 | ||
192 | 200 | ||
193 | 201 | ||
194 | }
|
202 | }
|
195 | 203 | ||
196 | bool ModelController::runYear() |
204 | bool ModelController::runYear() |
197 | {
|
205 | {
|
198 | if (!canRun()) return false; |
206 | if (!canRun()) return false; |
199 | DebugTimer t("ModelController:runYear"); |
207 | DebugTimer t("ModelController:runYear"); |
200 | qDebug() << "ModelController: run year" << currentYear(); |
208 | qDebug() << "ModelController: run year" << currentYear(); |
201 | 209 | ||
202 | if (GlobalSettings::instance()->settings().paramValueBool("debug_clear")) |
210 | if (GlobalSettings::instance()->settings().paramValueBool("debug_clear")) |
203 | GlobalSettings::instance()->clearDebugLists(); // clear debug data |
211 | GlobalSettings::instance()->clearDebugLists(); // clear debug data |
204 | bool err=false; |
212 | bool err=false; |
205 | try { |
213 | try { |
206 | MainWindow::bufferedLog(true); |
214 | MainWindow::bufferedLog(true); |
207 | mModel->runYear(); |
215 | mModel->runYear(); |
208 | fetchDynamicOutput(); |
216 | fetchDynamicOutput(); |
209 | } catch(const IException &e) { |
217 | } catch(const IException &e) { |
210 | QString error_msg = e.toString(); |
218 | QString error_msg = e.toString(); |
211 | Helper::msg(error_msg); |
219 | Helper::msg(error_msg); |
212 | qDebug() << error_msg; |
220 | qDebug() << error_msg; |
213 | err=true; |
221 | err=true; |
214 | }
|
222 | }
|
215 | MainWindow::bufferedLog(false); |
223 | MainWindow::bufferedLog(false); |
216 | return err; |
224 | return err; |
217 | }
|
225 | }
|
218 | 226 | ||
219 | bool ModelController::pause() |
227 | bool ModelController::pause() |
220 | {
|
228 | {
|
221 | if(!isRunning()) |
229 | if(!isRunning()) |
222 | return mPaused; |
230 | return mPaused; |
223 | 231 | ||
224 | if (mPaused) { |
232 | if (mPaused) { |
225 | // currently in pause - mode -> continue
|
233 | // currently in pause - mode -> continue
|
226 | mPaused = false; |
234 | mPaused = false; |
227 | QTimer::singleShot(0,this, SLOT(runloop())); // continue loop |
235 | QTimer::singleShot(0,this, SLOT(runloop())); // continue loop |
228 | } else { |
236 | } else { |
229 | // currently running -> set to pause mode
|
237 | // currently running -> set to pause mode
|
230 | GlobalSettings::instance()->outputManager()->save(); |
238 | GlobalSettings::instance()->outputManager()->save(); |
231 | mPaused = true; |
239 | mPaused = true; |
232 | MainWindow::bufferedLog(false); |
240 | MainWindow::bufferedLog(false); |
233 | }
|
241 | }
|
234 | return mPaused; |
242 | return mPaused; |
235 | }
|
243 | }
|
236 | 244 | ||
237 | void ModelController::cancel() |
245 | void ModelController::cancel() |
238 | {
|
246 | {
|
239 | mCanceled = true; |
247 | mCanceled = true; |
240 | }
|
248 | }
|
241 | 249 | ||
242 | //////////////////////////////////////
|
250 | //////////////////////////////////////
|
243 | // dynamic outut
|
251 | // dynamic outut
|
244 | //////////////////////////////////////
|
252 | //////////////////////////////////////
|
245 | //////////////////////////////////////
|
253 | //////////////////////////////////////
|
246 | void ModelController::setupDynamicOutput(QString fieldList) |
254 | void ModelController::setupDynamicOutput(QString fieldList) |
247 | {
|
255 | {
|
248 | mDynFieldList.clear(); |
256 | mDynFieldList.clear(); |
249 | if (!fieldList.isEmpty()) { |
257 | if (!fieldList.isEmpty()) { |
250 | QRegExp rx("((?:\\[.+\\]|\\w+)\\.\\w+)"); |
258 | QRegExp rx("((?:\\[.+\\]|\\w+)\\.\\w+)"); |
251 | int pos=0; |
259 | int pos=0; |
252 | while ((pos = rx.indexIn(fieldList, pos)) != -1) { |
260 | while ((pos = rx.indexIn(fieldList, pos)) != -1) { |
253 | mDynFieldList.append(rx.cap(1)); |
261 | mDynFieldList.append(rx.cap(1)); |
254 | pos += rx.matchedLength(); |
262 | pos += rx.matchedLength(); |
255 | }
|
263 | }
|
256 | 264 | ||
257 | //mDynFieldList = fieldList.split(QRegExp("(?:\\[.+\\]|\\w+)\\.\\w+"), QString::SkipEmptyParts);
|
265 | //mDynFieldList = fieldList.split(QRegExp("(?:\\[.+\\]|\\w+)\\.\\w+"), QString::SkipEmptyParts);
|
258 | mDynFieldList.prepend("count"); |
266 | mDynFieldList.prepend("count"); |
259 | mDynFieldList.prepend("year"); // fixed fields. |
267 | mDynFieldList.prepend("year"); // fixed fields. |
260 | }
|
268 | }
|
261 | mDynData.clear(); |
269 | mDynData.clear(); |
262 | mDynData.append(mDynFieldList.join(";")); |
270 | mDynData.append(mDynFieldList.join(";")); |
263 | }
|
271 | }
|
264 | 272 | ||
265 | QString ModelController::dynamicOutput() |
273 | QString ModelController::dynamicOutput() |
266 | {
|
274 | {
|
267 | return mDynData.join("\n"); |
275 | return mDynData.join("\n"); |
268 | }
|
276 | }
|
269 | 277 | ||
270 | const QStringList aggList = QStringList() << "mean" << "sum" << "min" << "max" << "p25" << "p50" << "p75" << "p5"<< "p10" << "p90" << "p95"; |
278 | const QStringList aggList = QStringList() << "mean" << "sum" << "min" << "max" << "p25" << "p50" << "p75" << "p5"<< "p10" << "p90" << "p95"; |
271 | void ModelController::fetchDynamicOutput() |
279 | void ModelController::fetchDynamicOutput() |
272 | {
|
280 | {
|
273 | if (mDynFieldList.isEmpty()) |
281 | if (mDynFieldList.isEmpty()) |
274 | return; |
282 | return; |
275 | DebugTimer t("dynamic output"); |
283 | DebugTimer t("dynamic output"); |
276 | QStringList var;
|
284 | QStringList var;
|
277 | QString lastVar = ""; |
285 | QString lastVar = ""; |
278 | QVector<double> data; |
286 | QVector<double> data; |
279 | AllTreeIterator at(mModel); |
287 | AllTreeIterator at(mModel); |
280 | TreeWrapper tw;
|
288 | TreeWrapper tw;
|
281 | int var_index; |
289 | int var_index; |
282 | StatData stat;
|
290 | StatData stat;
|
283 | double value; |
291 | double value; |
284 | QStringList line;
|
292 | QStringList line;
|
285 | Expression custom_expr;
|
293 | Expression custom_expr;
|
286 | bool simple_expression; |
294 | bool simple_expression; |
287 | foreach (QString field, mDynFieldList) { |
295 | foreach (QString field, mDynFieldList) { |
288 | if (field=="count" || field=="year") |
296 | if (field=="count" || field=="year") |
289 | continue; |
297 | continue; |
290 | if (field.count()>0 && field.at(0)=='[') { |
298 | if (field.count()>0 && field.at(0)=='[') { |
291 | QRegExp rex("\\[(.+)\\]\\.(\\w+)"); |
299 | QRegExp rex("\\[(.+)\\]\\.(\\w+)"); |
292 | rex.indexIn(field); |
300 | rex.indexIn(field); |
293 | var = rex.capturedTexts(); |
301 | var = rex.capturedTexts(); |
294 | var.pop_front(); // drop first element (contains the full string) |
302 | var.pop_front(); // drop first element (contains the full string) |
295 | simple_expression = false; |
303 | simple_expression = false; |
296 | } else { |
304 | } else { |
297 | var = field.split(QRegExp("\\W+"), QString::SkipEmptyParts); |
305 | var = field.split(QRegExp("\\W+"), QString::SkipEmptyParts); |
298 | simple_expression = true; |
306 | simple_expression = true; |
299 | }
|
307 | }
|
300 | if (var.count()!=2) |
308 | if (var.count()!=2) |
301 | throw IException(QString("Invalid variable name for dynamic output:") + field); |
309 | throw IException(QString("Invalid variable name for dynamic output:") + field); |
302 | if (var.first()!=lastVar) { |
310 | if (var.first()!=lastVar) { |
303 | // load new field
|
311 | // load new field
|
304 | data.clear(); |
312 | data.clear(); |
305 | at.reset(); var_index = 0; |
313 | at.reset(); var_index = 0; |
306 | if (simple_expression) { |
314 | if (simple_expression) { |
307 | var_index = tw.variableIndex(var.first()); |
315 | var_index = tw.variableIndex(var.first()); |
308 | if (var_index<0) |
316 | if (var_index<0) |
309 | throw IException(QString("Invalid variable name for dynamic output:") + var.first()); |
317 | throw IException(QString("Invalid variable name for dynamic output:") + var.first()); |
310 | 318 | ||
311 | } else { |
319 | } else { |
312 | custom_expr.setExpression(var.first()); |
320 | custom_expr.setExpression(var.first()); |
313 | custom_expr.setModelObject(&tw); |
321 | custom_expr.setModelObject(&tw); |
314 | }
|
322 | }
|
315 | while (Tree *t = at.next()) { |
323 | while (Tree *t = at.next()) { |
316 | tw.setTree(t); |
324 | tw.setTree(t); |
317 | if (simple_expression) |
325 | if (simple_expression) |
318 | value = tw.value(var_index); |
326 | value = tw.value(var_index); |
319 | else
|
327 | else
|
320 | value = custom_expr.execute(); |
328 | value = custom_expr.execute(); |
321 | data.push_back(value); |
329 | data.push_back(value); |
322 | }
|
330 | }
|
323 | stat.setData(data); |
331 | stat.setData(data); |
324 | }
|
332 | }
|
325 | // fetch data
|
333 | // fetch data
|
326 | var_index = aggList.indexOf(var[1]); |
334 | var_index = aggList.indexOf(var[1]); |
327 | switch (var_index) { |
335 | switch (var_index) { |
328 | case 0: value = stat.mean(); break; |
336 | case 0: value = stat.mean(); break; |
329 | case 1: value = stat.sum(); break; |
337 | case 1: value = stat.sum(); break; |
330 | case 2: value = stat.min(); break; |
338 | case 2: value = stat.min(); break; |
331 | case 3: value = stat.max(); break; |
339 | case 3: value = stat.max(); break; |
332 | case 4: value = stat.percentile25(); break; |
340 | case 4: value = stat.percentile25(); break; |
333 | case 5: value = stat.median(); break; |
341 | case 5: value = stat.median(); break; |
334 | case 6: value = stat.percentile75(); break; |
342 | case 6: value = stat.percentile75(); break; |
335 | case 7: value = stat.percentile(5); break; |
343 | case 7: value = stat.percentile(5); break; |
336 | case 8: value = stat.percentile(10); break; |
344 | case 8: value = stat.percentile(10); break; |
337 | case 9: value = stat.percentile(90); break; |
345 | case 9: value = stat.percentile(90); break; |
338 | case 10: value = stat.percentile(95); break; |
346 | case 10: value = stat.percentile(95); break; |
339 | default: throw IException(QString("Invalid aggregate expression for dynamic output: %1\nallowed:%2") |
347 | default: throw IException(QString("Invalid aggregate expression for dynamic output: %1\nallowed:%2") |
340 | .arg(var[1]).arg(aggList.join(" "))); |
348 | .arg(var[1]).arg(aggList.join(" "))); |
341 | }
|
349 | }
|
342 | line+=QString::number(value); |
350 | line+=QString::number(value); |
343 | }
|
351 | }
|
344 | line.prepend( QString::number(data.size()) ); |
352 | line.prepend( QString::number(data.size()) ); |
345 | line.prepend( QString::number(GlobalSettings::instance()->currentYear()) ); |
353 | line.prepend( QString::number(GlobalSettings::instance()->currentYear()) ); |
346 | mDynData.append(line.join(";")); |
354 | mDynData.append(line.join(";")); |
347 | }
|
355 | }
|
348 | 356 |