Files
MI-38/s1000d/Converter_Source/html.cpp
2023-06-14 18:08:32 +03:00

1127 lines
54 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "html.h"
#include <QFile>
#include <QDebug>
#include <QDir>
#include <QtCore/QCoreApplication>
#include <QTime>
#include <QMessageBox>
#include <QTextCodec>
HTML::HTML()
{
}
void HTML::Generate(S1000D_Manager* _SM, bool _toScorm, SplashForm* _splash) {
SM = _SM; toScorm = _toScorm;
ru_const = &SM->ru_const; splash = _splash;
svgUI = 0; paraIdent = true; paraTextAlign = "";
iframeDivCnt = 0;
if(!SM->isConsole)
{splash->Reset(); splash->SetTitle("Генерация HTML...");}
QStringList htmlHead, htmlTail;
QFile blankFile(":new/BlankXML/blank.html");
if (!blankFile.open(QFile::ReadOnly | QFile::Text)) return;
QString s;
bool isHead = true;
while(!blankFile.atEnd()) {
s = QString::fromLocal8Bit(blankFile.readLine()).replace("\n","");
if(isHead) htmlHead.append(s); else htmlTail.append(s);
if(s.contains("<div class=\"main\">")) isHead = false;
}
blankFile.close();
acrList.clear();
for(int i=0;i<SM->items.count();i++)
if(SM->items[i].moduleType == mtDM) {
SM->setCurItem(i);
//qDebug() << "html: " << SM->item->fileName;
if(SM->item->schemeType == stLEARNING) continue;
idList.clear();
ID_pars = ID_tabs = ID_figs = ID_mmos = 0;
SM->item->html.clear();
foreach(QString s, htmlHead) {
// if(!toScorm && s == "</head>") {
// add(1, "<style type='text/css'>");
// add(1, " body {");
// add(1, " font-family: RobotoRegular, Arial, sans-serif;");
// add(1, " font-size: 16px;");
// add(1, " line-height: 20px;");
// add(1, " background: #fff;");
// add(1, " color: #212121;");
// add(1, " }");
// add(1, "</style>");
// }
add(0, s);
}
add(6, "<div id=\"dialog\" title=\"Отклонено\" style=\"display: none;width:400px;height:200px\"><div id=\"dialogText\"></div></div>");
add(6, "<div id=\"tooltip\" display=\"none\" style=\"position: absolute; display: none;\"></div>");
add(6, "<div id=\"tooltipImg\" display=\"none\" style=\"position: absolute; display: none;\"></div>");
add(6, "<div id=\"zoom\" display=\"none\" style=\"position: absolute; display: none; cursor: pointer\" onclick=\"doZoomImg();\"><img src=\"app/dinamika/viewimg.png\" style=\"width: 32px; height: 32px\"></div>");
add(6, "<div class=\"container\" id=\"container\">");
add(6, " <div class=\"container_text\" id=\"container_text\">");
add(6, " <div id=\"S1000D_root\" class=\"S1000D_root\">");
add(6, " <div id=\"S1000D_identandstatus\" class=\"S1000D_mainstructure\">");
QString itemTechName = SM->getNodeText("identAndStatusSection.dmAddress.dmAddressItems.dmTitle.techName");
QString itemInfoName = SM->getNodeText("identAndStatusSection.dmAddress.dmAddressItems.dmTitle.infoName");
itemTechName.replace("'", "\""); itemInfoName.replace("'", "\"");
//if(!toScorm) add(6, " <center>");
add(6, " <h1 class=\"S1000DCenterhead1\" style=\"align: center\">"+itemTechName+"</h1>");
if(itemInfoName != "")
add(6, " <h1 class=\"S1000DCenterhead1\" style=\"align: center\">"+itemInfoName+"</h1>");
//if(!toScorm) add(6, " </center>");
add(6, " </div>");
add(6, " <div class=\"S1000Dcontent\">");
QDomNode rootNode;
if(SM->item->schemeType == stDESCRIPT)
rootNode = SM->findElement("content.description");
if(SM->item->schemeType == stCREW)
rootNode = SM->findElement("content.crew.descrCrew");
if(SM->item->schemeType == stLEARNING)
rootNode = SM->findElement("content.learning.learningAssessment");
for(int j=0;j<rootNode.childNodes().count();j++)
parseNode(rootNode.childNodes().at(j), 7);
add(6, " </div>");
//if(toScorm) {
// add(6, " <center>");
// add(6, " <button id=\"learnedButton\" type=\"button\" class=\"no-print\" onclick=\"onLearnedButton();\">"+ru_const->htmlButtonLearned+"</button>");
// add(6, " </center>");
//}
add(6, " </div>");
add(6, " </div>");
add(6, "</div>");
if(true) { //toScorm
add(6, "<div class=\"S1000DTOC\">"); // содержание
add(6, " <ul>");
for(int j=0;j<idList.count();j++)
if(idList[j].type == "par") {
add(6, " <li>");
add(6, " <a class=\"scrollTo\" href=\"#"+idList[j].id+"\">"+idList[j].title+"</a>");
add(6, " </li>");
}
add(6, " </ul>");
add(6, "</div>");
add(6, "<div class=\"S1000DLOF\">"); // изображения
add(6, " <ul>");
for(int j=0;j<idList.count();j++)
if(idList[j].type == "fig") {
add(6, " <li>");
add(6, " <a class=\"scrollTo\" href=\"#"+idList[j].id+"\">"+idList[j].title+"</a>");
add(6, " </li>");
}
add(6, " </ul>");
add(6, "</div>");
add(6, "<div class=\"S1000DLOM\">"); // мультимедиа
add(6, " <ul>");
for(int j=0;j<idList.count();j++)
if(idList[j].type == "mmo") {
add(6, " <li>");
add(6, " <a class=\"scrollTo\" href=\"#"+idList[j].id+"\">"+idList[j].title+"</a>");
add(6, " </li>");
}
add(6, " </ul>");
add(6, "</div>");
add(6, "<div class=\"S1000DLOT\">"); // таблицы
add(6, " <ul>");
for(int j=0;j<idList.count();j++)
if(idList[j].type == "tab") {
add(6, " <li>");
add(6, " <a class=\"scrollTo\" href=\"#"+idList[j].id+"\">"+idList[j].title+"</a>");
add(6, " </li>");
}
add(6, " </ul>");
add(6, "</div>");
add(6, "<div class=\"toPrint\">");
add(6, " <i> </i>");
add(6, "</div>");
add(6, "<div class=\"toTop\">");
add(6, " <i> </i>");
add(6, "</div>");
}
// переименовываем временные тексты ссылок idTitle_
for(int i=htmlHead.count();i<SM->item->html.count();i++)
while(1) {
int _b = SM->item->html[i].indexOf("idTitle_");
if(_b == -1) break;
int _e = SM->item->html[i].indexOf("<",_b+8);
QString id = SM->item->html[i].mid(_b+8, _e-(_b+8));
QString newTitle = id;
for(int j=0;j<idList.count();j++)
{
if(idList[j].id == id)
{
if(idList[j].title.indexOf(":") != -1)
{
if(idList[j].title.startsWith(ru_const->figureTitle))
newTitle = ru_const->figureShortTitle+" "+idList[j].title.mid(ru_const->figureTitle.length()+1, idList[j].title.indexOf(":")-(ru_const->figureTitle.length()+1));
if(idList[j].title.startsWith(ru_const->tableTitle))
newTitle = ru_const->tableShortTitle+" "+idList[j].title.mid(ru_const->tableTitle.length()+1, idList[j].title.indexOf(":")-(ru_const->tableTitle.length()+1));
//qDebug() << id << "->" << newTitle;
break;
} else {
if(!SM->isConsole) qDebug() << "Неизвестная структура заголовка в idList" << id << idList[j].title;
}
}
}
if(newTitle == id)
if(!SM->isConsole)
qDebug() << "[html: "+QString::number(i)+"] Ссылка не переименована: " + id + " ("+SM->item->fileName+")";
SM->item->html[i].replace(SM->item->html[i].mid(_b, _e-_b), newTitle);
}
//for(int j=0;j<SM->item->html.count();j++)
// if(!SM->item->html[j].contains("\n")) SM->item->html[j] += "\n";
foreach(QString s, htmlTail)
add(0, s);
} //mtDM
}
QString HTML::domElementToXML(const QDomElement& elem, int lvl)
{
QString head = spc(lvl)+"<"+elem.tagName();
QDomNamedNodeMap attrs = elem.attributes();
for(int i = 0; i<attrs.size(); ++i)
{
QDomAttr attr = attrs.item(i).toAttr();
QString val = attr.value();
val.replace(QChar(0xa), "&#xa;");
head +=
QString::fromLatin1(" %0=\"%1\"")
.arg(attr.name())
.arg(val);
}
QString tail = spc(lvl)+"</"+elem.tagName()+">\n";
QString mid = "";
if(elem.childNodes().count() != 0) {
if(elem.childNodes().count() == 1 && elem.childNodes().at(0).isText()) {
head += ">";
mid += elem.childNodes().at(0).toText().nodeValue();
tail = "</"+elem.tagName()+">\n";
}
else {
head += ">\n";
for(int i=0;i<elem.childNodes().count();i++) {
QDomNode chNode = elem.childNodes().at(i);
//if(chNode.nodeType() == QDomNode::TextNode)
// mid += spc(lvl)+chNode.toText().nodeValue() +"\n";
if(chNode.nodeType() == QDomNode::ElementNode)
mid += domElementToXML(chNode.toElement(), lvl+1);
if(chNode.nodeType() != QDomNode::ElementNode && chNode.nodeType() != QDomNode::CommentNode) //&& chNode.nodeType() != QDomNode::TextNode
qDebug() << "domElementToXML: unknown nodetype " << chNode.nodeType();
}
}
}
else {
head += "/>\n"; tail = "";
//head += ">\n";
}
return head + mid + tail;
}
void HTML::parseNode(QDomNode node, int lvl) {
if(!SM->isConsole) splash->Step();
QString name = node.nodeName();
if(name != "acronym") footnoteID = "";
if(name == "#text") {
cat(node.nodeValue().replace("<","&lt;").replace(">","&gt;"));
return;
}
if(name == "para") {
QString ident = "";
QString textStyle = "";
if(paraTextAlign != "")
textStyle = " text-align: "+paraTextAlign+";";
if(node.childNodes().count() > 0)
{
if(node.childNodes().at(0).nodeName() == "multimedia")
ident = " style=\"text-indent: 0px;"+textStyle+"\"";
if(node.childNodes().at(0).nodeName() == "figure")
ident = " style=\"text-indent: 0px;"+textStyle+"\"";
if(!paraIdent)
ident = " style=\"text-indent: 0px;"+textStyle+"\"";
}
if(ident == "" && textStyle != "")
ident = " style=\""+textStyle+"\"";
add(lvl, "<div class=\"S1000Dpara\" id=\"ID_par"+QString::number(ID_pars++)+"\""+ident+">");
for(int j=0;j<node.childNodes().count();j++)
parseNode(node.childNodes().at(j), lvl+1);
if(node.childNodes().count() == 0) cat("<br>");
cat("</div>");
return;
}
if(name == "levelledPara") {
QString id = "ID_par"+QString::number(ID_pars++);
add(lvl, "<div class=\"S1000DSidehead2\" id=\""+id+"\" style=\"text-align: center\"><h3><b>");
QString title = "";
if(node.childNodes().at(0).nodeName() == "title")
title = node.childNodes().at(0).childNodes().at(0).nodeValue();
if(title != "") {
labelStruct lbl; lbl.id = id; lbl.title = title; lbl.type = "par";
idList.append(lbl);
}
cat(title);
cat("</b></h3></div>");
for(int j=0;j<node.childNodes().count();j++)
if(node.childNodes().at(j).nodeName() != "title")
parseNode(node.childNodes().at(j), lvl+1);
return;
}
if(name == "emphasis") {
QString emType = "b";
for(int j=0;j<node.attributes().count();j++)
if(node.attributes().item(j).toAttr().name() == "emphasisType") {
if(node.attributes().item(j).toAttr().value() == "em02") emType = "i";
if(node.attributes().item(j).toAttr().value() == "em03") emType = "u";
}
cat("<"+emType+">");
for(int j=0;j<node.childNodes().count();j++)
parseNode(node.childNodes().at(j), lvl+1);
cat("</"+emType+">");
return;
}
if(name == "internalRef") {
QString id = "", target = "";
for(int j=0;j<node.attributes().count();j++) {
if(node.attributes().item(j).toAttr().name() == "internalRefId")
id = node.attributes().item(j).toAttr().value();
if(node.attributes().item(j).toAttr().name() == "internalRefTargetType") {
QString tt = node.attributes().item(j).toAttr().value();
if(tt == "irtt07") target = "par";
if(tt == "irtt01") target = "fig";
if(tt == "irtt02") target = "tab";
if(tt == "irtt03") target = "mma";
if(tt == "irtt11") target = "hot";
// if(refID.left(3) == "fig" && refID.mid(9,3) == "hot") refTarget = "irtt11";
}
}
id = id.replace(".", "_").replace(":", "_").replace("-", "_").replace(" ", "_"); //normID
//qDebug() << "internalRef: "+id;
cat("<a href=\"#"+id+"\">");
cat("idTitle_"+id); //TODO
cat("</a>");
return;
}
if(name == "dmSegmentRef") {
QString tPath = node.toElement().attribute("targetPath");
//int _b = tPath.indexOf("'");
//QString id = tPath.mid(_b+1, tPath.indexOf("'", _b+1)-(_b+1));
QString refFileCode = SM->dmCodeIdentString(node.toElement().namedItem("dmRefIdent").namedItem("dmCode"));
QString refTechName = node.toElement().namedItem("dmRefAddressItems").namedItem("dmTitle").namedItem("techName").childNodes().at(0).toText().data();
QString refInfoName = node.toElement().namedItem("dmRefAddressItems").namedItem("dmTitle").namedItem("infoName").childNodes().at(0).toText().data();
int refItemInd = -1;
int tmpCurItem = SM->itemIndex;
for(int i=0;i<SM->items.count();i++)
if(SM->items[i].moduleType == mtDM){
SM->setCurItem(i);
QString itemFileCode = SM->dmIdentString("identAndStatusSection.dmAddress.dmIdent");
QString itemTechName = SM->item->doc.namedItem("dmodule").namedItem("identAndStatusSection").namedItem("dmAddress").namedItem("dmAddressItems").namedItem("dmTitle").namedItem("techName").childNodes().at(0).toText().data();
QString itemInfoName = SM->item->doc.namedItem("dmodule").namedItem("identAndStatusSection").namedItem("dmAddress").namedItem("dmAddressItems").namedItem("dmTitle").namedItem("infoName").childNodes().at(0).toText().data();
if(refFileCode == itemFileCode && refTechName == itemTechName && refInfoName == itemInfoName)
{
refItemInd = i; break;
}
}
if(refItemInd == -1) {
qDebug() << "HTML dmSegmentRef: ref item not found ("+refTechName+" "+refFileCode+")";
SM->setCurItem(tmpCurItem);
return;
}
QString labelTitle = "";
QDomNode labelNode = SM->getNodeFromXPath(tPath); //, true
if(labelNode.isNull()) {
qDebug() << "HTML dmSegmentRef: labelNode.isNull ";
qDebug() << " path: " << tPath;
qDebug() << " fileName: " << SM->item->fileName;
SM->setCurItem(tmpCurItem);
return;
}
else {
//qDebug() << "HTML dmSegmentRef: OK - " << tPath;
}
if(labelNode.toElement().namedItem("title").isNull()) {
qDebug() << "HTML dmSegmentRef: labelNode.title.isNull";
//return;
} else {
labelTitle = labelNode.toElement().namedItem("title").toElement().firstChild().toText().data();
}
QString id = labelNode.attributes().namedItem("id").nodeValue();
id = id.replace(".", "_").replace(":", "_").replace("-", "_").replace(" ", "_"); //normID
QString htmlFileName = SM->item->fileName;
htmlFileName = htmlFileName.replace(".xml", ".html");
//***********
//qDebug() << "<a href=\""+htmlFileName+"#"+id+"\">";
SM->setCurItem(tmpCurItem);
cat("<a href=\""+htmlFileName+"#"+id+"\">");
cat(refTechName + " / " + labelTitle);
cat("</a>");
return;
}
if(name == "randomList") {
bool oldParaIdent = paraIdent; paraIdent = false;
if(node.firstChild().nodeName() == "title") {
add(lvl, "<div class=\"S1000Dpara\" id=\"ID_par"+QString::number(ID_pars++)+"\">");
for(int j=0;j<node.firstChild().childNodes().count();j++)
parseNode(node.firstChild().childNodes().at(j), lvl+1);
cat("</div>");
}
add(lvl, "<table class=\"S1000DrandomList\">");
add(lvl, " <tbody>");
for(int j=0;j<node.childNodes().count();j++)
if(node.childNodes().at(j).nodeName() == "listItem")
{
add(lvl, " <tr class=\"S1000Dlistitem\">");
if(node.childNodes().at(j).childNodes().count() > 0)
if(node.childNodes().at(j).childNodes().at(0).childNodes().count() > 0)
{
QString child0name = node.childNodes().at(j).childNodes().at(0).childNodes().at(0).nodeName();
if(child0name == "randomList" || child0name == "sequentialList")
add(lvl, " <td width=\"30px\"></td>");
else
add(lvl, " <td width=\"30px\">-</td>");
}
add(lvl, " <td style=\"padding-left: 5px;\">");
for(int k=0;k<node.childNodes().at(j).childNodes().count();k++)
parseNode(node.childNodes().at(j).childNodes().at(k), lvl+7);
add(lvl, " </td>");
add(lvl, " </tr>");
}
add(lvl, " </tbody>");
add(lvl, "</table>");
//if(oldParaIdent) cat("<br>");
paraIdent = oldParaIdent;
return;
}
if(name == "sequentialList") {
bool oldParaIdent = paraIdent; paraIdent = false;
if(node.firstChild().nodeName() == "title") {
add(lvl, "<div class=\"S1000Dpara\" id=\"ID_par"+QString::number(ID_pars++)+"\">");
for(int j=0;j<node.firstChild().childNodes().count();j++)
parseNode(node.firstChild().childNodes().at(j), lvl+1);
cat("</div>");
}
add(lvl, "<table class=\"S1000DrandomList\">");
add(lvl, " <tbody>");
int cnt = 0;
for(int j=0;j<node.childNodes().count();j++)
if(node.childNodes().at(j).nodeName() == "listItem")
{
add(lvl, " <tr class=\"S1000Dlistitem\">");
if(node.childNodes().at(j).childNodes().count() > 0)
if(node.childNodes().at(j).childNodes().at(0).childNodes().count() > 0)
{
QString child0name = node.childNodes().at(j).childNodes().at(0).childNodes().at(0).nodeName();
if(child0name == "randomList" || child0name == "sequentialList")
add(lvl, " <td width=\"30px\"></td>");
else
add(lvl, " <td width=\"30px\">"+QString::number(++cnt)+".</td>");
}
add(lvl, " <td style=\"padding-left: 5px;\">");
for(int k=0;k<node.childNodes().at(j).childNodes().count();k++)
parseNode(node.childNodes().at(j).childNodes().at(k), lvl+7);
add(lvl, " </td>");
add(lvl, " </tr>");
}
add(lvl, " </tbody>");
add(lvl, "</table>");
//if(oldParaIdent) cat("<br>");
paraIdent = oldParaIdent;
return;
}
if(name == "figure") {
QString id = node.attributes().namedItem("id").nodeValue();
QString title = node.namedItem("title").firstChild().nodeValue();
QString infoEntityIdent = node.namedItem("graphic").attributes().namedItem("infoEntityIdent").nodeValue();
QString reproductionScale = node.namedItem("graphic").attributes().namedItem("reproductionScale").nodeValue();
QString reproductionHeight = node.namedItem("graphic").attributes().namedItem("reproductionHeight").nodeValue();
QString reproductionWidth = node.namedItem("graphic").attributes().namedItem("reproductionWidth").nodeValue();
QString isInlineClass = "";
if(id == "" && title == "") isInlineClass = " class='inlineImg' ";
QString imgStyle = "", scaleStyle = "", wStyle = "", hStyle = "";
//if(reproductionScale != "") scaleStyle = ": "+reproductionScale+";' "; // пока не используется
if(reproductionHeight != "") hStyle = "height: "+reproductionHeight+";";
if(reproductionWidth != "") wStyle = "width: "+reproductionWidth+";";
if(scaleStyle+wStyle+hStyle != "") imgStyle = " style='"+scaleStyle+wStyle+hStyle+"' ";
if(infoEntityIdent == "") {
add(lvl, "<b>Ошибка чтения изображения</b><br>");
return;
}
if(id == "") id = "ID_fig"+QString::number(ID_figs);
ID_figs++;
id = id.replace(".", "_").replace(":", "_").replace("-", "_").replace(" ", "_"); //normID
labelStruct lbl; lbl.id = id; lbl.title = title; lbl.type = "fig";
idList.append(lbl);
QFileInfo svgInfo(SM->projectPath+"/"+infoEntityIdent);
QString svgfile = infoEntityIdent.section("/",-1,-1);
//QString svgdir = infoEntityIdent.section("/",0,-2);
//qDebug() << SM->projectPath+"/"+infoEntityIdent << svgfile.toLower().split(".").last();
QString txtfile = svgInfo.absolutePath()+"/"+svgfile.left(svgfile.length()-3)+"txt";
QFileInfo txtInfo(txtfile);
if(svgInfo.exists() && svgfile.toLower().split(".").last() == "svg" && txtInfo.exists()) { // прописываем хотспоты в svg
QDomDocument svg;
if(!SM->isConsole) splash->SetTitle("Обработка SVG файла: "+infoEntityIdent);
QApplication::processEvents();
//qDebug() << "-- Processing SVG "+infoEntityIdent;
//QElapsedTimer timer; timer.start();
QFile txtFile(txtfile);
if (!txtFile.open(QFile::ReadOnly)) { // | QFile::Text
qDebug() << "html: Ошибка открытия файла "+svgInfo.absolutePath()+"/"+svgfile.left(svgfile.length()-3)+"txt";
return;
}
QByteArray data = txtFile.readAll();
for(int i=0;i < data.length()-2;i++)
{
if(data[i] == (char)10 && (data[i+1] != (char)13)) data[i] = 13;
}
QStringList txtLines = QString(QString(data).toUtf8()).replace("\r\r","\r").split("\r"); //
//qDebug() << txtLines;
txtFile.close();
QFile svgFile(SM->projectPath+"/"+infoEntityIdent);
if (!svgFile.open(QFile::ReadOnly | QFile::Text)){
qDebug() << "html: Ошибка открытия файла "+SM->projectPath+"/"+infoEntityIdent;
return;
}
svg.setContent(svgFile.readAll());
svgFile.close();
QDomNode svgNode = svg.namedItem("svg");
if(svgNode.isNull()) {
qDebug() << "html: Ошибка в svg-файле "+SM->projectPath+"/"+infoEntityIdent;
return;
}
svgNode.attributes().namedItem("width").toAttr().setNodeValue("100%");
svgNode.attributes().removeNamedItem("height");
QStringList txtNums, txtTitles;
foreach(QString s, txtLines)
if(s.indexOf(" - "))
{
txtNums.append(s.mid(0, s.indexOf(" - ")));
txtTitles.append(s.mid(s.indexOf(" - ")+3));
}
//qDebug() << " searchSVGNodeForText: " << (int)timer.elapsed()/1000;
for(int j=0;j<svgNode.childNodes().count();j++)
{
if(!SM->isConsole) splash->Step();
QDomNode g = svgNode.childNodes().at(j);
if(g.nodeName() != "g") continue;
if(!SM->isConsole) splash->Step();
QString title = searchSVGNodeForText(g);
if(title == "") continue;
int ind = txtNums.indexOf(title);
if(ind == -1) continue;
QString hotspotTitle = txtTitles[ind];
QString hotspotImage = txtTitles[ind];
if(hotspotImage.indexOf("} ") != -1) { // вариант {title} filename
int _b = hotspotImage.indexOf("{")+1;
hotspotTitle = hotspotImage.mid(_b, hotspotImage.indexOf("} ")-_b);
hotspotImage = hotspotImage.mid(hotspotImage.indexOf("} ")+2);
}
if(QFile::exists(SM->projectPath+"/"+hotspotImage)) {
g.toElement().setAttribute("style", "cursor: pointer;");
g.toElement().setAttribute("onmouseout", "hideTooltipImg();");
g.toElement().setAttribute("onmousemove", "showTooltipImg(evt, '"+hotspotImage+"', '"+hotspotTitle+"');");
g.toElement().setAttribute("onclick", "viewer.show('"+hotspotImage+"');");
} else {
g.toElement().setAttribute("style", "cursor: pointer;");
g.toElement().setAttribute("onmouseout", "hideTooltip();");
g.toElement().setAttribute("onmousemove", "showTooltip(evt, '"+hotspotTitle+"');");
}
}
//qDebug() << " svg.namedItem(svg).save: " << (int)timer.elapsed()/1000;
QString svgNodeText;
svgNodeText = domElementToXML(svg.namedItem("svg").toElement(), 0); //QTextStream outsvg(&svgNodeText);
//outsvg << svg.namedItem("svg");
//svg.namedItem("svg").save(outsvg, 2);
//qDebug() << " svgNodeText.indexOf(id=): " << (int)timer.elapsed()/1000;
QString svgIDprefix; svgIDprefix.fill('0', 3-QString::number(svgUI).length());
svgIDprefix = "id"+svgIDprefix+QString::number(svgUI++)+"_";
int j, i=0;
QString _id;
while(1) {
i = svgNodeText.indexOf("id=\"", i);
if(i == -1) break;
j = svgNodeText.indexOf("\"", i+4);
_id = svgNodeText.mid(i+4, j-i-4);
for(int k=svgIDprefix.length()-1; k>=0; k--)
svgNodeText.insert(i+4, svgIDprefix[k]);
svgNodeText.replace("#"+_id, "#"+svgIDprefix+_id);
i = j+1;
}
//qDebug() << " final saving to mem: " << (int)timer.elapsed()/1000;
add(lvl, " <div id=\""+id+"\"/>");
add(0, "\n<!-- Begin of SVG "+infoEntityIdent+" -->\n");
add(0, svgNodeText);
//foreach (QString s, svgNodeText.split("\n"))
// add(lvl, s);
add(0, "<!-- End of SVG "+infoEntityIdent+" -->\n");
//qDebug() << "-- End of SVG "+infoEntityIdent+": " << (int)timer.elapsed()/1000;
} else {
QString imgfilename = QString(infoEntityIdent);
add(lvl, " <img "+isInlineClass+"id=\""+id+"\" src=\""+imgfilename+"\" "+imgStyle+"alt=\"Показать\" onmousemove=\"showZoomImg(event, '"+imgfilename+"');\"/>");
//if(toScorm) {
// add(lvl, " <img src=\""+imgfilename+"\" alt=\"Показать\" onmousemove=\"showZoomImg(event, '"+imgfilename+"');\"/>");
// add(lvl, "<div class=\"S1000Dfiguregraphic\" onmousemove=\"showZoomImg(event, '"+imgfilename+"');\" boardNum=\""+infoEntityIdent.left(infoEntityIdent.length()-4)+"\" val=\""+infoEntityIdent+"\" actuate=\"onLoad\" show=\"embed\" id=\""+id+"\">");
// add(lvl, " <img src=\"app/images/drive-drawing.svg\" alt=\"Показать\" />");
// add(lvl, "</div>");
//} else {
// add(lvl, "<div align=\"center\">");
// add(lvl, " <img src=\""+imgfilename+"\" alt=\"Показать\" onmousemove=\"showZoomImg(event, '"+imgfilename+"');\"/>");
// add(lvl, "</div>");
//}
}
//add(lvl, " <div align=\"center\">");
if(title != "") {
add(lvl, " <div class=\"S1000Dpara\" align=\"center\" style=\"text-align: center;\">" + title + "</div>");
cat("<br>");
}
//cat("</div>");
if(!SM->isConsole) splash->SetTitle("Генерация HTML...");
return;
}
if(name == "table") {
bool oldParaIdent = paraIdent; paraIdent = false;
QString id, colsep, rowsep, frame, tocentry, align; id=frame=tocentry=align=""; colsep=rowsep="0";
int cols; //, rows
for(int j=0;j<node.attributes().count();j++) {
if(node.attributes().item(j).toAttr().name() == "id")
id = node.attributes().item(j).toAttr().value();
if(node.attributes().item(j).toAttr().name() == "colsep")
colsep = node.attributes().item(j).toAttr().value();
if(node.attributes().item(j).toAttr().name() == "rowsep")
rowsep = node.attributes().item(j).toAttr().value();
if(node.attributes().item(j).toAttr().name() == "frame")
frame = node.attributes().item(j).toAttr().value();
if(node.attributes().item(j).toAttr().name() == "tocentry")
tocentry = node.attributes().item(j).toAttr().value();
// frame
// • "all" (D), draws a rule above and below the table, and to the left and right.
// • "sides", draws a rule on the left and right of the table, but not on the top and bottom
// • "top", draws a rule above the table, but not below, or to the left or right of the table
// • "topbot", draws a rule above and below the table (this is the setting to be used for S1000D formal tables)
// • "bottom", draws a rule below the table
// • "none", indicates no rules will be drawn for the frame of the table
}
if(id == "") id = "ID_tab"+QString::number(ID_tabs);
ID_tabs++;
id = id.replace(".", "_").replace(":", "_").replace("-", "_").replace(" ", "_"); //normID
cat("<br>");
add(lvl, "<div class=\"divTable\" id=\""+id+"\" align=\"center\">");
add(lvl+1, "<table class=\"S1000Dtable\" border=\"1\" align=\"center\" style=\"text-indent: 0px;\">");
QString title="";
struct colspecStruct {
QString name, align, colwidth; };
QList<colspecStruct> colspec;
struct spanspecStruct {
QString spanname;
int st, end; };
QList<spanspecStruct> spanspec;
for(int j=0;j<node.childNodes().count();j++) { //table
if(node.childNodes().at(j).nodeName() == "title")
if(node.childNodes().at(j).firstChild().nodeName() == "#text") {
title = node.childNodes().at(j).firstChild().nodeValue();
//add(lvl+2, "<caption class=\"S1000Dobjecttitle\">");
//add(lvl+2, " <span>"+title+"</span>");
//add(lvl+2, "</caption>");
}
if(node.childNodes().at(j).nodeName() == "tgroup") {
cols = -1;
for(int k=0;k<node.childNodes().at(j).attributes().count();k++) {
if(node.childNodes().at(j).attributes().item(k).toAttr().name() == "cols")
cols = node.childNodes().at(j).attributes().item(k).toAttr().value().toInt();
if(node.childNodes().at(j).attributes().item(k).toAttr().name() == "colsep")
colsep = node.childNodes().at(j).attributes().item(k).toAttr().value();
if(node.childNodes().at(j).attributes().item(k).toAttr().name() == "rowsep")
rowsep = node.childNodes().at(j).attributes().item(k).toAttr().value();
if(node.childNodes().at(j).attributes().item(k).toAttr().name() == "align")
align = node.childNodes().at(j).attributes().item(k).toAttr().value(); //"left" "right" "center""justify""char"
}
if(cols == -1) {qDebug() << "Ошибка импорта таблицы" << title; add(lvl, " </table>");add(lvl, "</div>"); return; }
for(int k=0;k<node.childNodes().at(j).childNodes().count();k++) {
QDomNode tgNode = node.childNodes().at(j).childNodes().at(k);
if(tgNode.nodeName() == "colspec") {
QString colname="", align="", colwidth="";
for(int l=0;l<tgNode.attributes().count();l++) {
if(tgNode.attributes().item(l).toAttr().name() == "colname")
colname = tgNode.attributes().item(l).toAttr().value();
if(tgNode.attributes().item(l).toAttr().name() == "align")
align = tgNode.attributes().item(l).toAttr().value();
if(tgNode.attributes().item(l).toAttr().name() == "colwidth")
colwidth = tgNode.attributes().item(l).toAttr().value();
}
if(colname != "" || colwidth != "") {
colspecStruct newspec; newspec.name = colname; newspec.align = align; newspec.colwidth = colwidth;
colspec.append(newspec);
}
}
if(tgNode.nodeName() == "spanspec") {
QString namest="", nameend="", spanname="";
for(int l=0;l<tgNode.attributes().count();l++) {
if(tgNode.attributes().item(l).toAttr().name() == "namest")
namest = tgNode.attributes().item(l).toAttr().value();
if(tgNode.attributes().item(l).toAttr().name() == "nameend")
nameend = tgNode.attributes().item(l).toAttr().value();
if(tgNode.attributes().item(l).toAttr().name() == "spanname")
spanname = tgNode.attributes().item(l).toAttr().value();
}
if(namest != "" && spanname != "") {
spanspecStruct newspec; newspec.spanname = spanname;
newspec.end = nameend.mid(3).toInt(); newspec.st = namest.mid(3).toInt();
spanspec.append(newspec);
}
}
if(tgNode.nodeName() == "thead" || tgNode.nodeName() == "tbody") {
int colsWidth=0;
for(int l=0;l<colspec.count();l++)
colsWidth += colspec[l].colwidth.replace("*","").toInt();
for(int l=0;l<colspec.count();l++)
if(colsWidth <= 0)
colspec[l].colwidth = "";
else
colspec[l].colwidth = " style =\"width: "+QString::number(100 * colspec[l].colwidth.toInt()/colsWidth)+"%;\"";
add(lvl+2, "<"+tgNode.nodeName()+">");
for(int l=0;l<tgNode.childNodes().count();l++) { //rows
QDomNode row = tgNode.childNodes().at(l);
QString thisrowsep = rowsep; // пока не используется
for(int m=0;m<row.attributes().count();m++) {
if(row.attributes().item(m).toAttr().name() == "rowsep")
thisrowsep = row.attributes().item(m).toAttr().value();
}
add(lvl+3, "<tr cellpadding=\"0\" cellspacing=\""+colsep+"\">"); // или 0?
for(int m=0;m<row.childNodes().count();m++) { //entrys
QString thisentryalign = align;
if(row.childNodes().at(m).nodeName() == "entry") {
QString thisentryspan = "";
for(int n=0;n<row.childNodes().at(m).attributes().count();n++) {
if(row.childNodes().at(m).attributes().item(n).toAttr().name() == "align")
thisentryalign = row.childNodes().at(m).attributes().item(n).toAttr().value();
if(row.childNodes().at(m).attributes().item(n).toAttr().name() == "spanname")
thisentryspan = row.childNodes().at(m).attributes().item(n).toAttr().value();
}
QString widthStr = "";
if(m < colspec.count())
widthStr = colspec[m].colwidth;
QString td = "<td align=\""+thisentryalign+"\" valign=\"middle\""+widthStr; //width: 20%;
if(thisentryspan != "") {
for(int r=0;r<spanspec.count();r++)
if(spanspec[r].spanname == thisentryspan)
td += " "+thisentryspan.left(3)+"span=\""+QString::number(spanspec[r].end-spanspec[r].st+1)+"\"";
}
td += ">";
add(lvl+4, td);
QString tmp = paraTextAlign;
paraTextAlign = "center";
for(int n=0;n<row.childNodes().at(m).childNodes().count();n++) //para
parseNode(row.childNodes().at(m).childNodes().at(n), lvl+5);
paraTextAlign = tmp;
add(lvl+4, "</td>");
}
} //entrys
add(lvl+3, "</tr>");
}
add(lvl+2, "</"+tgNode.nodeName()+">");
}//thead, tbody
} //tgroup childs
} //tgroup
} //table
add(lvl+1, "</table>");
add(lvl, "</div>");
add(lvl, " <div align=\"center\">");
cat("<div class=\"S1000Dpara\" id=\"\" style=\"text-align: center;\">" + title + "</div>");
cat("</div><br>");
labelStruct lbl; lbl.id = id; lbl.title = title; lbl.type = "tab";
idList.append(lbl);
paraIdent = oldParaIdent;
return;
}
if(name == "warning") {
bool oldParaIdent = paraIdent; paraIdent = false;
add(lvl, "<div class=\"frame_msg warning\">");
for(int j=0;j<node.childNodes().count();j++)
if(node.childNodes().at(j).nodeName() == "warningAndCautionPara") {
add(lvl+1, "<div class=\"S1000Dpara\" id=\"ID_par"+QString::number(ID_pars++)+"\" style=\"text-indent: 0px;\">");
for(int k=0;k<node.childNodes().at(j).childNodes().count();k++)
parseNode(node.childNodes().at(j).childNodes().at(k), lvl+2);
add(lvl+1, "</div>");
}
add(lvl, "</div>");
paraIdent = oldParaIdent;
return;
}
if(name == "caution") {
bool oldParaIdent = paraIdent; paraIdent = false;
add(lvl, "<div class=\"frame_msg caution\">");
for(int j=0;j<node.childNodes().count();j++)
if(node.childNodes().at(j).nodeName() == "warningAndCautionPara") {
add(lvl+1, "<div class=\"S1000Dpara\" id=\"ID_par"+QString::number(ID_pars++)+"\" style=\"text-indent: 0px;\">");
for(int k=0;k<node.childNodes().at(j).childNodes().count();k++)
parseNode(node.childNodes().at(j).childNodes().at(k), lvl+2);
add(lvl+1, "</div>");
}
add(lvl, "</div>");
paraIdent = oldParaIdent;
return;
}
if(name == "note") {
bool oldParaIdent = paraIdent; paraIdent = false;
add(lvl, "<div class=\"grayNote\">");
for(int j=0;j<node.childNodes().count();j++)
for(int k=0;k<node.childNodes().at(j).childNodes().count();k++)
parseNode(node.childNodes().at(j).childNodes().at(k), lvl+1);
cat("</div><br>");
paraIdent = oldParaIdent;
return;
}
if(name == "supScript" || name == "subScript") {
if(node.childNodes().count() == 1)
if(node.childNodes().at(0).nodeName() == "footnote" || node.childNodes().at(0).nodeName() == "footnoteRef") {
parseNode(node.childNodes().at(0), lvl);
return;
}
add(lvl, "<"+name.left(3)+" class=\"script_"+name.left(3)+"script\">");
for(int j=0;j<node.childNodes().count();j++)
parseNode(node.childNodes().at(j), lvl+1);
cat("</"+name.left(3)+">");
return;
}
if(name == "footnote") {
for(int j=0;j<node.attributes().count();j++)
if(node.attributes().item(j).toAttr().nodeName() == "id")
footnoteID = node.attributes().item(j).toAttr().nodeValue();
return;
}
if(name == "acronym") {
acronymStruct newAcr;
if(footnoteID != "")
newAcr.id = footnoteID;
else
newAcr.id = "ID_acr"+QString::number(acrList.count()+1);
newAcr.term = newAcr.definition = "";
//newAcr.term = node.attributes().namedItem("acronymTerm").childNodes().at(0).nodeValue();
//newAcr.definition = node.attributes().namedItem("acronymDefinition").childNodes().at(0).nodeValue();
//qDebug() << newAcr.term << node.attributes().namedItem("acronymTerm").nodeValue();
for(int j=0;j<node.childNodes().count();j++) {
if(node.childNodes().at(j).nodeName() == "acronymTerm")
newAcr.term = node.childNodes().at(j).childNodes().at(0).nodeValue();
if(node.childNodes().at(j).nodeName() == "acronymDefinition")
newAcr.definition = node.childNodes().at(j).childNodes().at(0).nodeValue();
}
acrList.append(newAcr);
cat("<span onmousemove=\"showTooltip(event, '"+newAcr.definition+"');\" onmouseout=\"hideTooltip();\">");
cat("<span class=\"foot_label\">"); //
if(footnoteID != "")
cat(QString::number(acrList.count()));//
else
cat(newAcr.term);
cat("</span></span>");
// cat("<div class=\"foot\" id=\""+newAcr.id+"\">"); //
// cat("<span class=\"foot_label\">"); //
// if(footnoteID != "")
// cat(QString::number(acrList.count()));
// else
// cat(newAcr.term);
// cat("</span>");
// cat("<div class=\"foot_inner\">");
// cat(newAcr.definition);
// cat("</div></div>");
return;
}
if(name == "footnoteRef") {
QString internalRefId = "";
internalRefId = node.attributes().namedItem("internalRefId").nodeValue();
if(internalRefId == "") return;
QString term = "***", definition = "Ссылка на термин ID "+internalRefId+" некорректна";
for(int j=0;j<acrList.count();j++)
if(acrList[j].id == internalRefId) {
term = QString::number(j+1); definition = acrList[j].definition;
break;
}
cat("<span onmousemove=\"showTooltip(event, '"+definition+"');\" onmouseout=\"hideTooltip();\">");
cat("<span class=\"foot_label\">"); //
cat(term);
cat("</span></span>");
// cat("<div class=\"foot\" id=\""+internalRefId+"\">");
// cat("<span class=\"foot_label\">"); //
// cat(term);
// cat("</span>");
// cat("<div class=\"foot_inner\">");
// cat(definition);
// cat("</div></div>");
return;
}
if(name == "externalPubRef") {
QDomNode codeNode, titleNode;
codeNode = node.childNodes().at(0).toElement().namedItem("externalPubCode");
titleNode = node.childNodes().at(0).toElement().namedItem("externalPubTitle");
QString refType="", refName="", refTitle="";
if(codeNode.attributes().item(0).toAttr().nodeName() == "pubCodingScheme")
refType = codeNode.attributes().item(0).toAttr().nodeValue();
refName = codeNode.childNodes().at(0).nodeValue();
refTitle = titleNode.childNodes().at(0).nodeValue();
if(refType == "URL") {
cat("<a href=\""+refName+"\">");
cat(refTitle); cat("</a>");
}
if(refType == "file") { // копируем всю папку с указанным файлом. Если такой нет - игнорируем
refName = refName;
//refTitle = refTitle;
QFileInfo info(SM->item->importedFromLyX);
QString refDir = info.absolutePath() + "/" + refName.split("/")[0];
//QDir dir = QDir(refDir);
if(!QDir(refDir).exists() && !QDir(SM->projectPath+"/"+refName.split("/")[0]).exists()) {
cat("<a href=\""+refName+"\">Гиперссылка: Папка "+refDir+" не найдена. Установите <b>относительный</b> путь к файлу.</a>");
return;
}
if(!QDir(SM->projectPath+"/"+refName.split("/")[0]).exists())
SM->copyDir(refDir, SM->projectPath+"/"+refName.split("/")[0]);
cat("<a href=\""+refName+"\">");
cat(refTitle); cat("</a>");
}
return;
}
if(name == "multimedia") {
QString title="", infoEntityIdent="", multimediaType="", scname = "";
title = node.toElement().namedItem("title").childNodes().at(0).nodeValue();
infoEntityIdent = node.toElement().namedItem("multimediaObject").attributes().namedItem("infoEntityIdent").nodeValue();
multimediaType = node.toElement().namedItem("multimediaObject").attributes().namedItem("multimediaType").nodeValue();
scname = node.toElement().namedItem("multimediaObject").childNodes().at(0).attributes().namedItem("scenario").nodeValue();
if(multimediaType == "3D") {
//infoEntityIdent = infoEntityIdent; // копируем всю папку с указанным файлом. Если такой нет - игнорируем
QFileInfo info(SM->item->importedFromLyX);
QString refDir = info.absolutePath() + "/" + infoEntityIdent.split("/")[0];
// if(!QDir(refDir).exists()) {
// cat("3D: Папка "+refDir+" не найдена. Установите <b>относительный</b> путь к файлу.");
// return;
// }
if(QDir(refDir).exists()) // && !QDir(SM->projectPath+"/"+infoEntityIdent.split("/")[0]).exists()
if(!SM->copyDir(refDir, SM->projectPath+"/"+infoEntityIdent.split("/")[0])) {
QMessageBox::critical(nullptr,"Ошибка", "Ошибка копирования папки '"+refDir+"'",QMessageBox::Ok);
return;
}
iframeDivCnt++;
QString divID = "d"+QString::number(iframeDivCnt);
QString scfilename = SM->projectPath+"/"+ QFileInfo(infoEntityIdent).path()+"/StreamingAssets/Scenario/"+QFileInfo(scname).fileName();
if(scname.toLower() == "freemode") {
QString divScName = scname+QString::number(iframeDivCnt);
QString iframeSrc = infoEntityIdent;
add(lvl, "<div id='"+divID+"'></div><script>scRegister('"+divScName+"', '"+title+"', '"+divID+"', '"+iframeSrc+"');</script>");
//add(lvl, "<iframe src=\""+infoEntityIdent+"\" width=\"938px\" height=\"532px\" align=\"center\" frameBorder=\"0\" style=\"text-indent: 0px;\">Узел <b>iframe</b> не поддерживается браузером</iframe>");
}
else
if(QFile::exists(scfilename) || scname.toLower().startsWith("system_")) {
QString indexfn = SM->projectPath+"/"+ infoEntityIdent;
QString scenariofn = SM->projectPath+"/"+QFileInfo(infoEntityIdent).path() +"/"+ QFileInfo(scname).baseName()+".html";
QFile indexFile(indexfn);
indexFile.open(QFile::ReadOnly | QFile::Text);
QString htmlData = QString(indexFile.readAll());
indexFile.close();
htmlData.replace("FreeMode", scname);
QFile scFile(scenariofn);
if(QFile::exists(scenariofn)) QFile::remove(scenariofn);
scFile.open(QFile::WriteOnly | QFile::Text);
QTextStream out(&scFile); out << htmlData;
scFile.close();
// можно сделать чтение ширины/высоты с htmlData:
// canvas.style.width = "936px"; canvas.style.height = "526px";
// scRegister(scName, scTitle, divID, iframeSrc)
//<div id="d1"></div><script>scRegister("01060301-003.xml", "01060301-003.xml", "d1", "models/sc1.html");</script>
QString divScName = QFileInfo(scname).fileName();
QString iframeSrc = QFileInfo(infoEntityIdent).path()+"/"+QFileInfo(scname).baseName()+".html";
add(lvl, "<div id='"+divID+"'></div><script>scRegister('"+divScName+"', '"+title+"', '"+divID+"', '"+iframeSrc+"');</script>");
//add(lvl, "<iframe src=\""+QFileInfo(infoEntityIdent).path()+"/"+QFileInfo(scname).baseName()+".html"+"\" width=\"938px\" height=\"532px\" align=\"center\" frameBorder=\"0\" style=\"text-indent: 0px;\">Узел <b>iframe</b> не поддерживается браузером</iframe>");
}
else
{
add(lvl, "<div class=\"S1000Dpara\" id=\"\" align=\"center\" style=\"text-indent: 0px;\"> Сценарий " + scfilename + " не найден</div><br>");
}
add(lvl, "<div class=\"S1000Dpara\" id=\"\" align=\"center\" style=\"text-indent: 0px; text-align: center;\">" + title + "</div><br>");
}
if(multimediaType == "video") {
QString id = "ID_mmo"+QString::number(ID_mmos++);
labelStruct lbl; lbl.id = id; lbl.title = title; lbl.type = "mmo";
idList.append(lbl);
add(lvl, "<div class=\"S1000Dmultimedia\" style=\"width: 100%;\" id=\""+id+"\">");
add(lvl, " <div class=\"S1000Dmultimediaobj\" boardNum=\""+QFileInfo(infoEntityIdent).baseName()+"\" val=\""+infoEntityIdent+"\" actuate=\"onLoad\" show=\"embed\">");
add(lvl, " <div class=\"VideoContainer\">");
add(lvl, " <a href=\"JavaScript:void(null)\" actuate=\"onLoad\" class=\"openVideo\" boardNum=\""+QFileInfo(infoEntityIdent).baseName()+"\">");
add(lvl, " <img src=\"app/images/drive-drawing.svg\" />");
add(lvl, " </a>");
add(lvl, " </div>");
add(lvl, " </div>");
add(lvl, " <div class=\"S1000Dpara\" id=\"\" align=\"center\" style=\"text-indent: 0px; text-align: center;\">" + title + "</div><br>");
add(lvl, "</div>");
}
return;
}
QString s = "<b><i>(-unknown-)</i> " + node.nodeName() + " " + node.nodeValue() + "</b><br>";
qDebug() << "Unknown S1000D node: "+node.nodeName();
add(0, s);
//for(int j=0;j<node.childNodes().count();j++)
// parseNode(node.childNodes().at(j), lvl+1);
}
QString HTML::spc(int n) {
QString spc = ""; for(int j=0;j<n;j++) spc += " ";
return spc;
}
void HTML::add(int lvl, QString s) {
SM->item->html.append(spc(lvl)+s);
}
void HTML::cat(QString s) {
int ind = SM->item->html.count()-1;
if(ind < 0) ind = 0;
SM->item->html[ind] += s;
}
QString HTML::searchSVGNodeForText(QDomNode node) {
if(node.nodeName() == "tspan")
return node.childNodes().at(0).nodeValue();
for(int j=0;j<node.childNodes().count();j++) {
QString s = searchSVGNodeForText(node.childNodes().at(j));
if(s != "") return s;
}
return "";
}
//<para>В полете: Величина непревышаемой скорости полета (V<subScript>NE</subScript>
// <footnote id="ftn-0012"/>
// <acronym>
// <acronymTerm>VNE</acronymTerm>
// <acronymDefinition id="ftn-0012"> Величина непревышаемой скорости</acronymDefinition>
// </acronym>) составляет 300 км/ч.
// Величина непревышаемой скорости полета V<subScript>NE</subScript>
// <footnoteRef internalRefId="ftn-0012"/> при работе
//<sub class="script_subscript">NE</sub>
//<div class="foot">
// <span class="foot_label">1</span>
// <div class="foot_inner">
// -----------<div class="plain_layout" id='magicparlabel-405'>
// <a id="fn_VNE" />
// Величина непревышаемой скорости
// ---------</div>
// </div>
//</div>
//void clearDir( const QString path )
//{
// QDir dir( path );
// dir.setFilter( QDir::NoDotAndDotDot | QDir::Files );
// foreach( QString dirItem, dir.entryList() )
// dir.remove( dirItem );
// dir.setFilter( QDir::NoDotAndDotDot | QDir::Dirs );
// foreach( QString dirItem, dir.entryList() )
// {
// QDir subDir( dir.absoluteFilePath( dirItem ) );
// subDir.removeRecursively();
// }
//}
//tmp:
//http://digitalnativestudios.com/textmeshpro/docs/rich-text/#color