#include "cdm_steplistdocexporter.h" #include "ct_step/tools/menu/ct_menulevel.h" #include CDM_StepListDocExporter::CDM_StepListDocExporter(CDM_StepManager *stepManager, CDM_PluginManager *pluginManager, QString svnRevision) : QObject(nullptr) { _svnRevision = svnRevision; _stepManager = stepManager; _pluginManager = pluginManager; _stepListInfo = new CDM_StepListInfoManager(_stepManager, _pluginManager); } CDM_StepListDocExporter::~CDM_StepListDocExporter() { delete _stepListInfo; } void CDM_StepListDocExporter::exportDocumentedScript(QDir& mainDir, QString outDirPath, DocumentatedScriptInfo docInfo) { // export RIS information in subir QString RISPath = QString("%1/%2.ris").arg(outDirPath, docInfo._scriptFileName); QFile exportRISFile(RISPath); if (exportRISFile.open(QFile::WriteOnly | QFile::Text)) { QTextStream stream(&exportRISFile); stream << _stepListInfo->getPluginRIS(); exportRISFile.close(); } // Create sub-folders QDir outDir(outDirPath); outDir.mkdir("content"); outDir.mkdir("content/steps"); outDir.mkdir("content/css"); outDir.mkdir("content/js"); outDir.mkdir("content/text"); outDir.mkdir("content/images"); outDir.mkdir("content/pages"); QDateTime date = QDateTime::currentDateTime(); QString formattedTime = date.toString("dd/MM/yyyy hh:mm"); // export css file createCSS(outDirPath + "/content/css/style.css"); createJSForIframe(outDirPath + "/content/js"); // create index html file QFile findex(outDirPath + "/" + docInfo._scriptFileName + ".html"); if (findex.open(QFile::WriteOnly | QFile::Text)) { QTextStream stream(&findex); stream << "\n"; stream << "\n"; stream << "\n"; stream << "\n"; stream << "Computree Script Documentation\n"; stream << "\n"; stream << "
\n"; stream << "\n"; stream << "\n"; stream << "
\n"; stream << "\n"; stream << "\n"; findex.close(); } QString textContent; textContent.append("

" + docInfo._scriptName + "

\n"); createTextContent(outDirPath, "01_title", textContent); textContent.clear(); textContent.append("

" + docInfo._description + "

\n"); createTextContent(outDirPath, "02_description", textContent); textContent.clear(); textContent.append("

" + tr("Ce script a été créé le ") + "" + formattedTime + ", " + tr("avec la version 6.0.") + _svnRevision + tr(" de Computree") + "

\n"); textContent.append("

" + tr("Auteur : ") + "" + docInfo._author + "

\n"); textContent.append("

" + tr("Fichier script Computree : ") + "" + docInfo._scriptFileName + ".cts

\n"); createTextContent(outDirPath, "03_version", textContent); // Create mainContent.html file QFile fMainContent(outDirPath + "/content/pages/mainContent.html"); if (fMainContent.open(QFile::WriteOnly | QFile::Text)) { QTextStream stream(&fMainContent); stream << "\n"; stream << "\n"; stream << "\n"; stream << "\n"; stream << "Computree Script Documentation\n"; stream << "\n"; stream << "\n"; stream << "
\n"; stream << "\n"; stream << "\n"; stream << "

" << tr("Description") << "

\n"; if (!docInfo._description.isEmpty()) { stream << "\n"; stream << "\n"; } stream << "
\n"; stream << "
\n"; stream << "

" << tr("Version") << "

\n"; if (!docInfo._author.isEmpty()) { stream << "\n"; stream << "\n"; } stream << "
\n"; stream << "
\n"; stream << "

" << tr("Plugins utilisés") << "

\n"; stream << "

" << tr("Ce script utilise les plugins Computree suivants :") << "

\n"; stream << "
\n"; stream << _stepListInfo->getUsedPlugins(); stream << "
\n"; stream << "
\n"; stream << "\n"; stream << "\n"; fMainContent.close(); } // Create structure.html file QFile fStructure(outDirPath + "/content/pages/use.html"); if (fStructure.open(QFile::WriteOnly | QFile::Text)) { QTextStream stream(&fStructure); stream << "\n"; stream << "\n"; stream << "\n"; stream << "\n"; stream << "Computree Script Documentation\n"; stream << "\n"; stream << "
\n"; stream << "

" << tr("Structure du script") << "

\n"; stream << "
\n"; stream << "

" << tr("Le script est composé de l'enchaînement d'étapes suivant :") << "

\n"; stream << "
"; stream << _stepListInfo->getScriptStepList(); stream << "
"; stream << "
\n"; stream << "\n"; stream << "\n"; fStructure.close(); } // create step help pages _stepListInfo->generateHTMLDocForAllSteps(outDirPath, "../css", "../pages/configuration.html"); // Create parameters.html file QFile fParametersContent(outDirPath + "/content/pages/configuration.html"); if (fParametersContent.open(QFile::WriteOnly | QFile::Text)) { QTextStream stream(&fParametersContent); stream << "\n"; stream << "\n"; stream << "\n"; stream << "\n"; stream << "Computree Script Documentation\n"; stream << "\n"; stream << "
\n"; stream << "

" << tr("Index des étapes") << "

\n"; stream << "
\n"; stream << _stepListInfo->getScriptClickableStepList("../steps") << "\n"; stream << "
\n"; stream << "
\n"; stream << "\n"; stream << "\n"; fParametersContent.close(); } // Create citation.html file QFile fcitations(outDirPath + "/content/pages/citations.html"); if (fcitations.open(QFile::WriteOnly | QFile::Text)) { QTextStream stream(&fcitations); stream << "\n"; stream << "\n"; stream << "\n"; stream << "\n"; stream << "Computree Script Citation\n"; stream << "\n"; stream << "
\n"; stream << "

" << tr("Comment citer ce script") << "

\n"; stream << "
\n"; stream << "

" << tr("Pour référencer les travaux utilisés dans ce script, il faut citer :
") << "

\n"; stream << "
    \n"; stream << "
  • " + tr("La plateforme Computree") + "
  • \n"; stream << "
  • " + tr("Les plugins utilisés : %1").arg(_stepListInfo->getPluginListToCite()) + "
  • \n"; if (_stepListInfo->hasStepCitation()) { stream << "
  • " + tr("Les citations spécifiques liées à certaines étapes utilisées") + "
  • \n"; } stream << "
\n"; stream << "

" << tr("L'ensemble des références bibliographiques fournies dans cette page, sont disponibles dans le fichier %1.ris (au format bibliographique standard RIS).").arg(docInfo._scriptFileName) << "

\n"; stream << "
\n"; stream << _stepListInfo->getPluginAndStepCitations(); stream << "
\n"; stream << "\n"; stream << "\n"; fcitations.close(); } // Create menu step list QMap stepList; CT_StepsMenu *menu = _pluginManager->stepsMenu(); QList levels = menu->levels(); QListIterator it(levels); while(it.hasNext()) { CT_MenuLevel* level = it.next(); const QString favoritesName = CT_StepsMenu::staticOperationToDisplayableName(CT_StepsMenu::LO_Favorites); if(level->displayableName() != favoritesName) { const QList steps = level->steps(); for(CT_VirtualAbstractStep* step : steps) { stepList.insert(step->name(), step); } QList sublevels = level->levels(); QListIterator its(sublevels); while(its.hasNext()) { CT_MenuLevel* subLevel = its.next(); const QList steps = subLevel->steps(); for(CT_VirtualAbstractStep* step : steps) { stepList.insert(step->name(), step); } } } } // Create Summmary and steps documentation pages QFile f(outDirPath + "/content/pages/summary.html"); if (f.open(QFile::WriteOnly | QFile::Text)) { QTextStream stream(&f); stream << "\n"; stream << "\n"; stream << "\n"; stream << "\n"; stream << "Documentation Summary\n"; stream << "\n"; stream << "\n"; stream << "\n"; stream << "
\n"; stream << "

" << tr("Index") << "

\n"; stream << "\n"; stream << "\n"; stream << "\n"; f.close(); } } void CDM_StepListDocExporter::createStepHelp(QString exportDir, QProgressDialog &progressDialog) { // Create documentation createStepHelpessary and clean doc_xx/steps content QDir dir(exportDir); if (!dir.exists()) {dir.mkpath(".");} QDir dir2(exportDir + "/steps"); if (!dir2.exists()) { dir2.mkpath("."); } else { dir2.setNameFilters(QStringList() << "*.*"); dir2.setFilter(QDir::Files); foreach(QString dirFile, dir2.entryList()) { dir2.remove(dirFile); } } QDir dir3(exportDir + "/css"); if (!dir3.exists()) {dir3.mkpath(".");} // Create index.html QFile findex(exportDir + "/index.html"); if (findex.open(QFile::WriteOnly | QFile::Text)) { QTextStream stream(&findex); stream << "\n"; stream << "\n"; stream << "\n"; stream << "\n"; stream << "Computree Documentation\n"; stream << "\n"; stream << "
\n"; stream << "\n"; stream << "\n"; stream << "
\n"; stream << "\n"; stream << "\n"; findex.close(); } // Create index_default.html QFile findexdefault(exportDir + "/index_default.html"); if (findexdefault.open(QFile::WriteOnly | QFile::Text)) { QTextStream stream(&findexdefault); stream << "\n"; stream << "\n"; stream << "\n"; stream << "\n"; stream << "Computree Documentation\n"; stream << "\n"; stream << "
\n"; stream << "

" << tr("Documentation des étapes Computree") << "

\n"; stream << "

" << tr("Utiliser l'index sur la gauche pour séléctionner l'étape pour laquelle afficher la documentation. ") << "

\n"; stream << "
"; stream << "

" << "" << tr("Site internet officiel de Computree") << "

\n"; stream << "
\n"; stream << "\n"; stream << "\n"; findexdefault.close(); } QFile::copy(exportDir + "/index_default.html", exportDir + "/steps/current.html"); // Create style.css createCSS(exportDir + "/css/style.css"); // Create Summmary and steps documentation pages QFile f(exportDir + "/summary.html"); QFile fst(exportDir + "/status.txt"); if (f.open(QFile::WriteOnly | QFile::Text) && fst.open(QFile::WriteOnly | QFile::Text)) { QTextStream streamFst(&fst); streamFst << "Step\tDescription\tDetailledDescription\tParameters\tInput\tOutput\tDetails\tReferences\n"; QTextStream stream(&f); stream << "\n"; stream << "\n"; stream << "\n"; stream << "\n"; stream << "Documentation Summary"; stream << ""; stream << "\n"; stream << ""; stream << "
"; stream << "

" << tr("Index des étapes") << "

\n"; CT_StepsMenu *menu = _pluginManager->stepsMenu(); QList levels = menu->levels(); QListIterator it(levels); progressDialog.setMaximum(levels.size()); int cpt = 0; while(it.hasNext()) { CT_MenuLevel* level = it.next(); const QString favoritesName = CT_StepsMenu::staticOperationToDisplayableName(CT_StepsMenu::LO_Favorites); if(level->displayableName() != favoritesName) { stream << "
"; stream << "" << level->displayableName() << ""; const QList steps = level->steps(); if (steps.size() > 0) {stream << "
";} for(CT_VirtualAbstractStep* step : steps) { stream << "name() << ".html\">" << step->description() << "
\n"; // Create documentation page for this step step->generateHTMLDocumentation(exportDir + "/steps", "../css"); streamFst << step->name() << "\t"; streamFst << step->description() << "\t"; if (step->detailledDescription() == "No detailled description for this step") {streamFst << "0\t";} else {streamFst << (step->detailledDescription().size()) << "\t";} streamFst << (step->parametersDescription().isEmpty()?"0":"1") << "\t"; streamFst << (step->inputDescription().isEmpty()?"0":"1") << "\t"; streamFst << (step->outputDescription().isEmpty()?"0":"1") << "\t"; streamFst << (step->detailsDescription().isEmpty()?"0":"1") << "\t"; streamFst << (step->getStepRISCitations().isEmpty()?"0":"1") << "\n"; } if (steps.size() > 0) {stream << "
";} QList sublevels = level->levels(); QListIterator its(sublevels); while(its.hasNext()) { CT_MenuLevel* subLevel = its.next(); stream << "
"; stream << "" << subLevel->displayableName() << ""; const QList steps = subLevel->steps(); if (steps.size() > 0) {stream << "
";} for(CT_VirtualAbstractStep* step : steps) { stream << "name() << ".html\">" << step->description() << "
\n"; // Create documentation page for this step step->generateHTMLDocumentation(exportDir + "/steps", "../css"); streamFst << step->name() << "\t"; streamFst << step->description() << "\t"; if (step->detailledDescription() == "No detailled description for this step") {streamFst << "0\t";} else {streamFst << (step->detailledDescription().size()) << "\t";} streamFst << (step->parametersDescription().isEmpty()?"0":"1") << "\t"; streamFst << (step->inputDescription().isEmpty()?"0":"1") << "\t"; streamFst << (step->outputDescription().isEmpty()?"0":"1") << "\t"; streamFst << (step->detailsDescription().isEmpty()?"0":"1") << "\t"; streamFst << (step->getStepRISCitations().isEmpty()?"0":"1") << "\n"; } if (steps.size() > 0) {stream << "
";} stream << "
\n"; } stream << "
\n"; } progressDialog.setValue(++cpt); } stream << "
\n"; stream << "\n"; stream << ""; f.close(); fst.close(); } } void CDM_StepListDocExporter::createCSS(QString filename) { QFile fcss(filename); if (fcss.open(QFile::WriteOnly | QFile::Text)) { QTextStream stream(&fcss); stream << ".mainBlock\n"; stream << "{\n"; stream << " display: block;\n"; stream << " margin-left: auto;\n"; stream << " margin-right: auto;\n"; stream << " padding-left: 1.25rem;\n"; stream << " padding-right: 1.25rem;\n"; stream << "}\n"; stream << "\n"; stream << "h1\n"; stream << "{\n"; stream << " color:darkred;\n"; stream << "}\n"; stream << "h2\n"; stream << "{\n"; stream << " color:black;\n"; stream << "}\n"; stream << "h3\n"; stream << "{\n"; stream << " color:darkblue;\n"; stream << "}\n"; stream << ".parameterDescr\n"; stream << "{\n"; stream << " color:darkblue;\n"; stream << "}\n"; stream << ".resultInDescr\n"; stream << "{\n"; stream << " color:darkblue;\n"; stream << "}\n"; stream << ".resultOutDescr\n"; stream << "{\n"; stream << " color:darkblue;\n"; stream << "}\n"; stream << ".descBlock\n"; stream << "{\n"; stream << " margin-left:10px;\n"; stream << "}\n"; stream << ".descBlocklvl2\n"; stream << "{\n"; stream << " margin-left:30px;\n"; stream << "}\n"; stream << "summary {\n"; stream << " display: flex;\n"; stream << " cursor: pointer;\n"; stream << "}\n"; stream << "summary::marker\n"; stream << "{\n"; stream << " display: none;\n"; stream << "}\n"; stream << ".h1summary\n"; stream << "{\n"; stream << " color:darkred;\n"; stream << "}\n"; stream << ".h2summary\n"; stream << "{\n"; stream << " font-weight: 700;\n"; stream << " margin-left: 20px;\n"; stream << "}\n"; stream << ".linksummary01\n"; stream << "{\n"; stream << " margin-left: 20px;\n"; stream << "}\n"; stream << ".linksummary02\n"; stream << "{\n"; stream << " margin-left: 40px;\n"; stream << "}\n"; stream << ".insertedhtml\n"; stream << "{\n"; stream << " width: 1px;\n"; stream << " min-width: 100%;\n"; stream << " margin: 0;\n"; stream << " padding: 0;\n"; stream << " border: 0 none;\n"; stream << "}\n"; stream << "body\n"; stream << "{\n"; stream << " margin: 0;\n"; stream << " padding: 0;\n"; stream << "}\n"; stream << "\n"; stream << "/* Style pour la balise */\n"; stream << ".tooltip\n"; stream << "{\n"; stream << " position: relative;\n"; stream << " display: inline-block;\n"; stream << " cursor: pointer;\n"; stream << " color: #333; /* Couleur du texte */\n"; stream << " text-decoration: none; /* Supprimer le soulignement du lien */\n"; stream << " background-color: #f0f0f0; /* Fond gris clair */\n"; stream << " border: 1px solid #4d4d4d; /* Bordure gris très foncé */\n"; stream << " padding: 6px 12px; /* Espacement autour du texte */\n"; stream << " border-radius: 4px; /* Coins légèrement arrondis */\n"; stream << " font-size: 14px; /* Taille de police standard */\n"; stream << " transition: background-color 0.3s ease; /* Transition douce pour l'arrière-plan */\n"; stream << "}\n"; stream << ".tooltip:hover\n"; stream << "{\n"; stream << " background-color: #e0e0e0; /* Légèrement plus foncé au survol */\n"; stream << "}\n"; stream << "\n"; stream << "/* Style pour la balise active */\n"; stream << ".tooltipactive\n"; stream << "{\n"; stream << " position: relative;\n"; stream << " display: inline-block;\n"; stream << " cursor: pointer;\n"; stream << " color: #333; /* Couleur du texte */\n"; stream << " text-decoration: none; /* Supprimer le soulignement du lien */\n"; stream << " background-color: #b4e5a2; /* Fond vert pas trop clair */\n"; stream << " border: 1px solid #4d4d4d; /* Bordure gris très foncé */\n"; stream << " padding: 6px 12px; /* Espacement autour du texte */\n"; stream << " border-radius: 4px; /* Coins légèrement arrondis */\n"; stream << " font-size: 14px; /* Taille de police standard */\n"; stream << " font-weight: bold; /* Texte en gras */\n"; stream << " transition: background-color 0.3s ease; /* Transition douce pour l'arrière-plan */\n"; stream << "}\n"; stream << ".tooltipactive:hover\n"; stream << "{\n"; stream << " background-color: #adde9b; /* Légèrement plus foncé au survol */\n"; stream << "}\n"; stream << "\n"; stream << "/* Style pour le tooltip */\n"; stream << ".tooltip .tooltiptext, .tooltipactive .tooltiptext\n"; stream << "{\n"; stream << " visibility: hidden;\n"; stream << " width: 500px;\n"; stream << " background-color: #f0f0f0;\n"; stream << " color: #000000;\n"; stream << " text-align: left;\n"; stream << " border-radius: 4px;\n"; stream << " padding: 8px;\n"; stream << " position: absolute;\n"; stream << " z-index: 1;\n"; stream << " top: 100%; /* Positionne en dessous du lien */\n"; stream << " left: 50%;\n"; stream << " margin-top: 8px;\n"; stream << " opacity: 0;\n"; stream << " transition: opacity 0.3s;\n"; stream << " /* Permet d'afficher du contenu HTML dans le tooltip */\n"; stream << " white-space: normal;\n"; stream << " overflow-wrap: break-word; /* Gérer les très longues lignes */\n"; stream << " box-sizing: border-box;\n"; stream << " border: 1px solid #ccc;\n"; stream << " box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1); /* Ombre légère */\n"; stream << "}\n"; stream << "\n"; stream << "/* Flèche du tooltip */\n"; stream << ".tooltip .tooltiptext::after, .tooltipactive .tooltiptext::after\n"; stream << "{\n"; stream << " content: '';\n"; stream << " position: absolute;\n"; stream << " bottom: 100%;\n"; stream << " left: 50%;\n"; stream << " margin-left: -5px;\n"; stream << " border-width: 5px;\n"; stream << " border-style: solid;\n"; stream << " border-color: transparent transparent #333 transparent;\n"; stream << "}\n"; stream << "\n"; stream << "/* Affiche le tooltip au survol */\n"; stream << ".tooltip:hover .tooltiptext, .tooltipactive:hover .tooltiptext\n"; stream << "{\n"; stream << " visibility: visible;\n"; stream << " opacity: 1;\n"; stream << "}\n"; stream << "\n"; fcss.close(); } } void CDM_StepListDocExporter::createJSForIframe(QString dir) { QFile fjs1(QString("%1/%2").arg(dir).arg("iframeResizer_parent.js")); if (fjs1.open(QFile::WriteOnly | QFile::Text)) { QTextStream stream(&fjs1); stream << "/*! iFrame Resizer (iframeSizer.min.js ) - v4.3.9 - 2023-11-10\n"; stream << " * Desc: Force cross domain iframes to size to content.\n"; stream << " * Requires: iframeResizer.contentWindow.min.js to be loaded into the target frame.\n"; stream << " * Copyright: (c) 2023 David J. Bradshaw - dave@bradshaw.net\n"; stream << " * License: MIT\n"; stream << " */\n"; stream << "!function(d){var c,u,a,v,x,I,M,r,f,k,i,l,z;function m(){return window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver}function F(e,n,i){e.addEventListener(n,i,!1)}function B(e,n,i){e.removeEventListener(n,i,!1)}function p(e){return x+\"[\"+(n=\"Host page: \"+(e=e),n=window.top!==window.self?window.parentIFrame&&window.parentIFrame.getId?window.parentIFrame.getId()+\": \"+e:\"Nested host page: \"+e:n)+\"]\";var n}function t(e){return k[e]?k[e].log:u}function O(e,n){o(\"log\",e,n,t(e))}function E(e,n){o(\"info\",e,n,t(e))}function R(e,n){o(\"warn\",e,n,!0)}function o(e,n,i,t){!0===t&&\"object\"==typeof window.console&&console[e](p(n),i)}function w(e){function i(){t(\"Height\"),t(\"Width\"),P(function(){H(w),C(b),l(\"onResized\",w)},w,\"init\")}function n(){var e=p.slice(I).split(\":\"),n=e[1]?parseInt(e[1],10):0,i=k[e[0]]&&k[e[0]].iframe,t=getComputedStyle(i);return{iframe:i,id:e[0],height:n+function(e){if(\"border-box\"!==e.boxSizing)return 0;var n=e.paddingTop?parseInt(e.paddingTop,10):0,e=e.paddingBottom?parseInt(e.paddingBottom,10):0;return n+e}(t)+function(e){if(\"border-box\"!==e.boxSizing)return 0;var n=e.borderTopWidth?parseInt(e.borderTopWidth,10):0,e=e.borderBottomWidth?parseInt(e.borderBottomWidth,10):0;return n+e}(t),width:e[2],type:e[3]}}function t(e){var n=Number(k[b][\"max\"+e]),i=Number(k[b][\"min\"+e]),e=e.toLowerCase(),t=Number(w[e]);O(b,\"Checking \"+e+\" is in range \"+i+\"-\"+n),tk[r][\"max\"+e])throw new Error(\"Value for min\"+e+\" can not be greater than max\"+e)}}function h(e,n){null===i&&(i=setTimeout(function(){i=null,e()},n))}function e(){\"hidden\"!==document.visibilityState&&(O(\"document\",\"Trigger event: Visibility change\"),h(function(){b(\"Tab Visible\",\"resize\")},16))}function b(i,t){Object.keys(k).forEach(function(e){var n;k[n=e]&&\"parent\"===k[n].resizeFrom&&k[n].autoResize&&!k[n].firstRun&&A(i,t,k[e].iframe,e)})}function y(){F(window,\"message\",w),F(window,\"resize\",function(){var e;O(\"window\",\"Trigger event: \"+(e=\"resize\")),h(function(){b(\"Window \"+e,\"resize\")},16)}),F(document,\"visibilitychange\",e),F(document,\"-webkit-visibilitychange\",e)}function n(){function t(e,n){if(n){if(!n.tagName)throw new TypeError(\"Object is not a valid DOM element\");if(\"IFRAME\"!==n.tagName.toUpperCase())throw new TypeError(\"Expected