5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
22 #include "helpers_html.h"
23 #include "multimodelprinter.h"
26 MultiModelPrinter::MultiColumns::MultiColumns(int count
):
30 columns
= new QString
[count
];
33 MultiModelPrinter::MultiColumns::~MultiColumns()
38 void MultiModelPrinter::MultiColumns::append(const QString
& str
)
40 for (int i
=0; i
<count
; i
++) {
45 void MultiModelPrinter::MultiColumns::appendTitle(const QString
& name
)
47 append("<b>" + name
+ "</b> ");
50 void MultiModelPrinter::MultiColumns::append(int idx
, const QString
& str
)
53 compareColumns
[idx
].append(str
);
55 columns
[idx
].append(str
);
58 void MultiModelPrinter::MultiColumns::beginCompare()
60 compareColumns
= new QString
[count
];
63 void MultiModelPrinter::MultiColumns::endCompare(const QString
& color
)
65 for (int i
=0; i
<count
; i
++) {
66 QString cellColor
= color
;
67 if (i
==0 && count
>1 && compareColumns
[0]!=compareColumns
[1])
69 else if (i
>0 && compareColumns
[i
]!=compareColumns
[0])
71 columns
[i
].append(QString("<font color='%1'>%2</font>").arg(cellColor
).arg(compareColumns
[i
]));
73 delete[] compareColumns
;
74 compareColumns
= NULL
;
78 void MultiModelPrinter::MultiColumns::append(int idx
, T val
)
80 append(idx
, QString("%1").arg(val
));
83 QString
MultiModelPrinter::MultiColumns::print()
85 QString result
= "<tr>";
86 for (int i
=0; i
<count
; i
++) {
87 result
.append(QString("<td width='%1%'>%2</td>").arg(100.0/count
).arg(columns
[i
]));
89 result
.append("</tr>");
93 bool MultiModelPrinter::MultiColumns::isEmpty()
95 for (int i
=0; i
<count
; i
++) {
96 if (!columns
[i
].isEmpty())
102 #define COMPARE(what) \
103 columns.beginCompare(); \
104 for (int cc=0; cc < modelPrinterMap.size(); cc++) { \
105 ModelPrinter * modelPrinter = modelPrinterMap.value(cc).second; \
106 const ModelData * model = modelPrinterMap.value(cc).first; \
107 (void)(model); (void)(modelPrinter); \
108 columns.append(cc, (what)); \
110 columns.endCompare();
112 QString
MultiModelPrinter::printTitle(const QString
& label
)
114 return QString("<tr><td colspan='%1'><h2>").arg(modelPrinterMap
.count()) + label
+ "</h2></td></tr>";
117 MultiModelPrinter::MultiModelPrinter(Firmware
* firmware
):
122 MultiModelPrinter::~MultiModelPrinter()
127 void MultiModelPrinter::setModel(int idx
, const ModelData
* model
, const GeneralSettings
* generalSettings
)
129 if (modelPrinterMap
.contains(idx
) && modelPrinterMap
.value(idx
).second
) {
130 // free existing model printer
131 delete modelPrinterMap
.value(idx
).second
;
132 modelPrinterMap
[idx
].second
= NULL
;
135 QPair
<const ModelData
*, ModelPrinter
*> pair(model
, new ModelPrinter(firmware
, *generalSettings
, *model
));
136 modelPrinterMap
.insert(idx
, pair
); // QMap.insert will replace any existing key
139 void MultiModelPrinter::setModel(int idx
, const ModelData
* model
)
141 setModel(idx
, model
, &defaultSettings
);
144 void MultiModelPrinter::clearModels()
146 for(int i
=0; i
< modelPrinterMap
.size(); i
++) {
147 if (modelPrinterMap
.value(i
).second
)
148 delete modelPrinterMap
.value(i
).second
;
150 modelPrinterMap
.clear();
153 QString
MultiModelPrinter::print(QTextDocument
* document
)
155 if (document
) document
->clear();
157 QString str
= "<table border='1' cellspacing='0' cellpadding='3' width='100%' style='font-family: monospace;'>";
159 if (firmware
->getCapability(Heli
))
160 str
+= printHeliSetup();
161 if (firmware
->getCapability(FlightModes
))
162 str
+= printFlightModes();
163 str
+= printInputs();
164 str
+= printMixers();
165 str
+= printLimits();
166 str
+= printCurves(document
);
167 if (firmware
->getCapability(Gvars
) && !firmware
->getCapability(GvarsFlightModes
))
169 str
+= printLogicalSwitches();
170 str
+= printCustomFunctions();
171 str
+= printTelemetry();
176 QString
MultiModelPrinter::printSetup()
178 QString str
= printTitle(tr("General Model Settings"));
180 MultiColumns
columns(modelPrinterMap
.size());
181 columns
.appendTitle(tr("Name:"));
182 COMPARE(model
->name
);
183 columns
.append("<br/>");
184 columns
.appendTitle(tr("EEprom Size:"));
185 COMPARE(modelPrinter
->printEEpromSize());
186 columns
.append("<br/>");
187 for (int i
=0; i
<firmware
->getCapability(Timers
); i
++) {
188 columns
.appendTitle(tr("Timer%1:").arg(i
+1));
189 COMPARE(modelPrinter
->printTimer(i
));
190 columns
.append("<br/>");
192 for (int i
=0; i
<firmware
->getCapability(NumModules
); i
++) {
193 columns
.appendTitle(firmware
->getCapability(NumModules
) > 1 ? tr("Module%1:").arg(i
+1) : tr("Module:"));
194 COMPARE(modelPrinter
->printModule(i
));
195 columns
.append("<br/>");
197 if (IS_HORUS_OR_TARANIS(firmware
->getBoard())) {
198 columns
.appendTitle(tr("Trainer port:"));
199 COMPARE(modelPrinter
->printTrainerMode());
200 columns
.append("<br/>");
202 columns
.appendTitle(tr("Throttle Trim:"));
203 COMPARE(modelPrinter
->printThrottleTrimMode());
204 columns
.append("<br/>");
205 columns
.appendTitle(tr("Trim Increment:"));
206 COMPARE(modelPrinter
->printTrimIncrementMode());
207 columns
.append("<br/>");
208 columns
.appendTitle(tr("Center Beep:"));
209 COMPARE(modelPrinter
->printCenterBeep());
210 str
.append(columns
.print());
215 QString
MultiModelPrinter::printHeliSetup()
217 bool heliEnabled
= false;
218 for (int k
=0; k
< modelPrinterMap
.size(); k
++) {
219 heliEnabled
= heliEnabled
|| modelPrinterMap
.value(k
).first
->swashRingData
.type
!= HELI_SWASH_TYPE_NONE
;
225 QString str
= printTitle(tr("Helicopter Setup"));
226 MultiColumns
columns(modelPrinterMap
.size());
227 columns
.appendTitle (tr("Swash Type:"));
228 COMPARE(modelPrinter
->printHeliSwashType());
229 columns
.append ("<br/>");
231 columns
.appendTitle (tr("Swash Ring:"));
232 COMPARE(model
->swashRingData
.value
);
234 columns
.append ("<table cellspacing='0' cellpadding='1' width='100%' border='0' style='border-collapse:collapse'>");
235 columns
.append("<tr>");
236 columns
.append("<td></td><td><b>" + tr("Input") + "</b></td><td><b>" + tr("Weight") + "</b></td>");
237 columns
.append("</tr>");
239 columns
.append("<tr><td><b>" + tr("Long. cyc") + "</b></td><td>");
240 COMPARE(model
->swashRingData
.elevatorSource
.toString(model
));
241 columns
.append("</td><td>");
242 COMPARE(model
->swashRingData
.elevatorWeight
)
243 columns
.append("</td></tr>");
245 columns
.append("<tr><td><b>" + tr("Lateral cyc") + "</b></td><td>");
246 COMPARE(model
->swashRingData
.aileronSource
.toString(model
));
247 columns
.append("</td><td>");
248 COMPARE(model
->swashRingData
.aileronWeight
)
249 columns
.append("</td></tr>");
252 columns
.append("<tr><td><b>" + tr("Collective") + "</b></td><td>");
253 COMPARE(model
->swashRingData
.collectiveSource
.toString(model
));
254 columns
.append("</td><td>");
255 COMPARE(model
->swashRingData
.collectiveWeight
)
256 columns
.append("</td></tr>");
257 columns
.append("</table>");
261 str
.append(columns
.print());
265 QString
MultiModelPrinter::printFlightModes()
267 QString str
= printTitle(tr("Flight modes"));
271 MultiColumns
columns(modelPrinterMap
.size());
272 columns
.append("<table cellspacing='0' cellpadding='1' width='100%' border='0' style='border-collapse:collapse'>");
273 columns
.append("<tr>");
274 columns
.append("<td><b>" + tr("Flight mode") + "</b></td>");
275 columns
.append("<td><b>" + tr("Switch") + "</b></td>");
276 columns
.append("<td><b>" + tr("Fade IN") + "</b></td>");
277 columns
.append("<td><b>" + tr("Fade OUT") + "</b></td>");
278 for (int i
=0; i
< getBoardCapability(getCurrentBoard(), Board::NumTrims
); i
++) {
279 columns
.append("<td><b>" + RawSource(SOURCE_TYPE_TRIM
, i
).toString() + "</b></td>");
281 columns
.append("</tr>");
283 for (int i
=0; i
<firmware
->getCapability(FlightModes
); i
++) {
284 columns
.append("<tr><td><b>" + tr("FM%1").arg(i
) + "</b> ");
285 COMPARE(model
->flightModeData
[i
].name
);
286 columns
.append("</td><td>");
287 COMPARE(modelPrinter
->printFlightModeSwitch(model
->flightModeData
[i
].swtch
));
288 columns
.append("</td><td>");
289 COMPARE(model
->flightModeData
[i
].fadeIn
);
290 columns
.append("</td><td>");
291 COMPARE(model
->flightModeData
[i
].fadeOut
);
292 columns
.append("</td>");
293 for (int k
=0; k
< getBoardCapability(getCurrentBoard(), Board::NumTrims
); k
++) {
294 columns
.append("<td>");
295 COMPARE(modelPrinter
->printTrim(i
, k
));
296 columns
.append("</td>");
298 columns
.append("</tr>");
301 columns
.append("</table>");
302 str
.append(columns
.print());
305 // GVars and Rotary Encoders
306 int gvars
= firmware
->getCapability(Gvars
);
307 if ((gvars
&& firmware
->getCapability(GvarsFlightModes
)) || firmware
->getCapability(RotaryEncoders
)) {
308 MultiColumns
columns(modelPrinterMap
.size());
309 columns
.append("<table cellspacing='0' cellpadding='1' width='100%' border='0' style='border-collapse:collapse'>");
310 columns
.append("<tr><td><b>" + tr("Flight mode") + "</b></td>");
311 if (firmware
->getCapability(GvarsFlightModes
)) {
312 for (int i
=0; i
<gvars
; i
++) {
313 columns
.append("<td><b>" + tr("GV%1").arg(i
+1) + "</b><br/>");
314 COMPARE(model
->gvars_names
[i
]);
315 columns
.append("</td>");
318 for (int i
=0; i
<firmware
->getCapability(RotaryEncoders
); i
++) {
319 columns
.append("<td><b>" + tr("RE%1").arg(i
+1) + "</b></td>");
321 columns
.append("</tr>");
322 for (int i
=0; i
<firmware
->getCapability(FlightModes
); i
++) {
323 columns
.append("<tr><td><b>" + tr("FM%1").arg(i
) + "</b> ");
324 COMPARE(model
->flightModeData
[i
].name
);
325 columns
.append("</td>");
326 if (firmware
->getCapability(GvarsFlightModes
)) {
327 for (int k
=0; k
<gvars
; k
++) {
328 columns
.append("<td>");
329 COMPARE(modelPrinter
->printGlobalVar(i
, k
));
330 columns
.append("</td>");
333 for (int k
=0; k
<firmware
->getCapability(RotaryEncoders
); k
++) {
334 columns
.append("<td>");
335 COMPARE(modelPrinter
->printRotaryEncoder(i
, k
));
336 columns
.append("</td>");
338 columns
.append("</tr>");
340 columns
.append("</table>");
341 str
.append(columns
.print());
347 QString
MultiModelPrinter::printLimits()
349 QString str
= printTitle(tr("Limits"));
350 MultiColumns
columns(modelPrinterMap
.size());
351 columns
.append("<table border='0' cellspacing='0' cellpadding='1' width='100%'>" \
353 " <td><b>" + tr("Channel") + "</b></td>" \
354 " <td><b>" + tr("Offset") + "</b></td>" \
355 " <td><b>" + tr("Min") + "</b></td>" \
356 " <td><b>" + tr("Max") + "</b></td>" \
357 " <td><b>" + tr("Invert") + "</b></td>" \
359 for (int i
=0; i
<firmware
->getCapability(Outputs
); i
++) {
361 for (int k
=0; k
< modelPrinterMap
.size(); k
++)
362 count
= std::max(count
, modelPrinterMap
.value(k
).first
->mixes(i
).size());
365 columns
.append("<tr><td><b>");
366 COMPARE(modelPrinter
->printChannelName(i
));
367 columns
.append("</td><td>");
368 COMPARE(model
->limitData
[i
].offsetToString());
369 columns
.append("</td><td>");
370 COMPARE(model
->limitData
[i
].minToString());
371 columns
.append("</td><td>");
372 COMPARE(model
->limitData
[i
].maxToString());
373 columns
.append("</td><td>");
374 COMPARE(model
->limitData
[i
].revertToString());
375 columns
.append("</td></tr>");
378 columns
.append("</table>");
379 str
.append(columns
.print());
383 QString
MultiModelPrinter::printGvars()
385 QString str
= printTitle(tr("Global Variables"));
386 int gvars
= firmware
->getCapability(Gvars
);
387 MultiColumns
columns(modelPrinterMap
.size());
388 columns
.append("<table border='0' cellspacing='0' cellpadding='1' width='100%'><tr>");
389 for (int i
=0; i
<gvars
; i
++) {
390 columns
.append(QString("<td><b>") + tr("GV%1").arg(i
+1) + "</b></td>");
392 columns
.append("</tr><tr>");
393 for (int i
=0; i
<gvars
; i
++) {
394 columns
.append("<td>");
395 COMPARE(model
->flightModeData
[0].gvars
[i
]);
396 columns
.append("</td>");
398 columns
.append("</tr>");
399 str
.append(columns
.print());
403 QString
MultiModelPrinter::printInputs()
405 QString str
= printTitle(tr("Inputs"));
406 MultiColumns
columns(modelPrinterMap
.size());
407 columns
.append("<table cellspacing='0' cellpadding='1' width='100%' border='0' style='border-collapse:collapse'>");
408 for (int i
=0; i
<std::max(4, firmware
->getCapability(VirtualInputs
)); i
++) {
410 for (int k
=0; k
< modelPrinterMap
.size(); k
++) {
411 count
= std::max(count
, modelPrinterMap
.value(k
).first
->expos(i
).size());
414 columns
.append("<tr><td width='20%'><b>");
415 COMPARE(modelPrinter
->printInputName(i
));
416 columns
.append("</b></td><td>");
417 for (int j
=0; j
<count
; j
++) {
419 columns
.append("<br/>");
420 COMPARE(j
<model
->expos(i
).size() ? modelPrinter
->printInputLine(*model
->expos(i
)[j
]) : "");
422 columns
.append("</td></tr>");
425 str
.append(columns
.print());
429 QString
MultiModelPrinter::printMixers()
431 QString str
= printTitle(tr("Mixers"));
432 MultiColumns
columns(modelPrinterMap
.size());
433 columns
.append("<table cellspacing='0' cellpadding='1' width='100%' border='0' style='border-collapse:collapse'>");
434 for (int i
=0; i
<firmware
->getCapability(Outputs
); i
++) {
436 for (int k
=0; k
< modelPrinterMap
.size(); k
++) {
437 count
= std::max(count
, modelPrinterMap
.value(k
).first
->mixes(i
).size());
440 columns
.append("<tr><td width='20%'><b>");
441 COMPARE(modelPrinter
->printChannelName(i
));
442 columns
.append("</b></td><td>");
443 for (int j
=0; j
<count
; j
++) {
445 columns
.append("<br/>");
446 COMPARE((j
< model
->mixes(i
).size()) ? modelPrinter
->printMixerLine(*model
->mixes(i
)[j
], (j
>0)) : " ");
448 columns
.append("</td></tr>");
451 str
.append(columns
.print());
455 QString
MultiModelPrinter::printCurves(QTextDocument
* document
)
458 MultiColumns
columns(modelPrinterMap
.size());
460 columns
.append("<table cellspacing='0' cellpadding='1' width='100%' border='0' style='border-collapse:collapse'>");
461 for (int i
=0; i
<firmware
->getCapability(NumCurves
); i
++) {
462 bool curveEmpty
= true;
463 for (int k
=0; k
< modelPrinterMap
.size(); k
++) {
464 if (!modelPrinterMap
.value(k
).first
->curves
[i
].isEmpty()) {
471 columns
.append("<tr><td width='20%'><b>");
472 COMPARE(modelPrinter
->printCurveName(i
));
473 columns
.append("</b></td><td>");
474 COMPARE(modelPrinter
->printCurve(i
));
475 for (int k
=0; k
< modelPrinterMap
.size(); k
++)
476 columns
.append(k
, QString("<br/><img src='%1' border='0' />").arg(modelPrinterMap
.value(k
).second
->createCurveImage(i
, document
)));
477 columns
.append("</td></tr>");
480 columns
.append("</table><br/>");
482 str
.append(printTitle(tr("Curves")));
483 str
.append(columns
.print());
488 QString
MultiModelPrinter::printLogicalSwitches()
491 MultiColumns
columns(modelPrinterMap
.size());
493 columns
.append("<table cellspacing='0' cellpadding='1' width='100%' border='0' style='border-collapse:collapse'>");
494 for (int i
=0; i
<firmware
->getCapability(LogicalSwitches
); i
++) {
496 for (int k
=0; k
< modelPrinterMap
.size(); k
++) {
497 if (!modelPrinterMap
.value(k
).first
->logicalSw
[i
].isEmpty()) {
504 columns
.append("<tr><td width='20%'><b>" + tr("L%1").arg(i
+1) + "</b></td><td>");
505 COMPARE(modelPrinter
->printLogicalSwitchLine(i
));
506 columns
.append("</td></tr>");
509 columns
.append("</table>");
511 str
.append(printTitle(tr("Logical Switches")));
512 str
.append(columns
.print());
517 QString
MultiModelPrinter::printCustomFunctions()
520 MultiColumns
columns(modelPrinterMap
.size());
522 columns
.append("<table cellspacing='0' cellpadding='1' width='100%' border='0' style='border-collapse:collapse'>");
523 for (int i
=0; i
< firmware
->getCapability(CustomFunctions
); i
++) {
525 for (int k
=0; k
< modelPrinterMap
.size(); k
++) {
526 if (!modelPrinterMap
.value(k
).first
->customFn
[i
].isEmpty()) {
533 columns
.append("<tr><td width='20%'><b>" + tr("SF%1").arg(i
+1) + "</b></td><td>");
534 COMPARE(modelPrinter
->printCustomFunctionLine(i
));
535 columns
.append("</td></tr>");
538 columns
.append("</table>");
540 str
.append(printTitle(tr("Special Functions")));
541 str
.append(columns
.print());
546 QString
MultiModelPrinter::printTelemetry()
548 QString str
= printTitle(tr("Telemetry Settings"));
550 // Analogs on non ARM boards
551 if (!IS_ARM(firmware
->getBoard())) {
552 MultiColumns
columns(modelPrinterMap
.size());
553 columns
.append("<table border='0' cellspacing='0' cellpadding='1' width='100%'>" \
554 "<tr><td width='22%'><b>" + tr("Analogs") + "</b></td><td width='26%'><b>" + tr("Unit") + "</b></td><td width='26%'><b>" + tr("Scale") + "</b></td><td width='26%'><b>" + tr("Offset") + "</b></td></tr>");
555 for (int i
=0; i
<2; i
++) {
556 columns
.append("<tr><td><b>"+tr("A%1").arg(i
+1)+"</b></td><td>");
557 COMPARE(getFrSkyUnits(model
->frsky
.channels
[i
].type
));
558 columns
.append("</td><td>");
559 COMPARE(QString::number((model
->frsky
.channels
[i
].ratio
/ (model
->frsky
.channels
[i
].type
==0 ? 10.0 : 1)), 10, (model
->frsky
.channels
[i
].type
==0 ? 1 : 0)));
560 columns
.append("</td><td>");
561 COMPARE(QString::number((model
->frsky
.channels
[i
].offset
*(model
->frsky
.channels
[i
].ratio
/ (model
->frsky
.channels
[i
].type
==0 ?10.0 : 1)))/255, 10, (model
->frsky
.channels
[i
].type
==0 ? 1 : 0)));
562 columns
.append("</td></tr>");
564 columns
.append("</table><br/>");
565 str
.append(columns
.print());
566 // TODO I remove the analogs alarms for now
571 MultiColumns
columns(modelPrinterMap
.size());
572 columns
.append("<table border='0' cellspacing='0' cellpadding='1' width='100%'>");
573 for (int i
=0; i
<2; i
++) {
574 columns
.append("<tr><td><b>" + QString(i
==0 ? tr("RSSI Alarms") : "") + "</b></td><td>");
575 if (IS_ARM(getCurrentBoard())) {
576 COMPARE(i
==0 ? tr("Low Alarm") : tr("Critical Alarm"));
579 COMPARE(getFrSkyAlarmType(model
->rssiAlarms
.level
[i
]));
581 columns
.append("</td><td><</td><td>");
583 COMPARE(QString::number(model
->rssiAlarms
.warning
, 10));
586 COMPARE(QString::number(model
->rssiAlarms
.critical
, 10));
588 columns
.append("</td></tr>");
590 columns
.append("</table><br/>");
591 str
.append(columns
.print());