#include "export-html.h"
#include <QMessageBox>
#include "branchobj.h"
#include "mainwindow.h"
#include "warningdialog.h"
extern QString flagsPath;
extern Main *mainWindow;
extern QString vymVersion;
extern QString vymHome;
ExportHTML::ExportHTML():ExportBase()
{
init();
}
ExportHTML::ExportHTML(VymModel *m):ExportBase(m)
{
init();
}
void ExportHTML::init()
{
exportName="HTML";
extension=".html";
frameURLs=true;
}
QString ExportHTML::getBranchText(BranchItem *current)
{
if (current)
{
bool vis = false;
QRectF hr;
LinkableMapObj *lmo = current->getLMO();
if (lmo)
{
hr = ((BranchObj*)lmo)->getBBoxHeading();
vis = lmo->isVisibleObj();
}
QString col;
QString id = model->getSelectString(current);
if (dia.useTextColor)
col = QString("style='color:%1'").arg(current->getHeadingColor().name());
QString s = QString("<span class='vym-branch-%1' %2 id='%3'>")
.arg(current->depth())
.arg(col)
.arg(id);
QString url = current->getURL();
QString heading = quotemeta(current->getHeadingPlain());
// Task flags
QString taskFlags;
if (dia.useTaskFlags)
{
Task *task = current->getTask();
if (task)
{
QString taskName = task->getIconString();
taskFlags += QString("<img src=\"flags/flag-%1.png\" alt=\"%2\">")
.arg(taskName)
.arg(QObject::tr("Flag: %1","Alt tag in HTML export").arg(taskName));
}
}
// User flags
QString userFlags;
if (dia.useUserFlags)
{
foreach (QString flag, current->activeStandardFlagNames())
userFlags += QString("<img src=\"flags/flag-%1.png\" alt=\"%2\">")
.arg(flag)
.arg(QObject::tr("Flag: %1","Alt tag in HTML export").arg(flag));
}
// Numbering
QString number;
if (dia.useNumbering) number = getSectionString(current) + " ";
// URL
if (!url.isEmpty())
{
s += QString ("<a href=\"%1\">%2<img src=\"flags/flag-url.png\" alt=\"%3\"></a>")
.arg(url)
.arg(number + taskFlags + heading + userFlags)
.arg(QObject::tr("Flag: url","Alt tag in HTML export"));
QRectF fbox = current->getBBoxURLFlag ();
if (vis)
imageMap += QString(" <area shape='rect' coords='%1,%2,%3,%4' href='%5' alt='%6'>\n")
.arg(fbox.left() - offset.x())
.arg(fbox.top() - offset.y())
.arg(fbox.right() - offset.x())
.arg(fbox.bottom() - offset.y())
.arg(url)
.arg(QObject::tr("External link: %1","Alt tag in HTML export").arg(heading));
} else
s += number + taskFlags + heading + userFlags;
s += "</span>";
// Create imagemap
if (vis && dia.includeMapImage)
imageMap += QString(" <area shape='rect' coords='%1,%2,%3,%4' href='#%5' alt='%6'>\n")
.arg(hr.left() - offset.x())
.arg(hr.top() - offset.y())
.arg(hr.right() - offset.x())
.arg(hr.bottom() - offset.y())
.arg(id)
.arg(heading);
// Include images experimental
if (dia.includeImages)
{
int imageCount = current->imageCount();
ImageItem *image;
QString imagePath;
for (int i=0; i< imageCount; i++)
{
image = current->getImageNum(i);
imagePath = "image-" + image->getUuid().toString() + ".png";
image->save( dirPath + "/" + imagePath, "PNG");
s += "</br><img src=\"" + imagePath;
s += "\" alt=\"" + QObject::tr("Image: %1","Alt tag in HTML export").arg(image->getOriginalFilename());
s += "\"></br>";
}
}
// Include note
if (!current->isNoteEmpty())
{
VymNote note = current->getNote();
QString n;
if (note.isRichText())
{
n = note.getText();
QRegExp re("<p.*>");
re.setMinimal (true);
if (current->getNote().getFontHint() == "fixed")
n.replace(re,"<p class=\"vym-fixed-note-paragraph\">");
else
n.replace(re,"<p class=\"vym-note-paragraph\">");
re.setPattern("</?html>");
n.replace(re,"");
re.setPattern("</?head.*>");
n.replace(re,"");
re.setPattern("</?body.*>");
n.replace(re,"");
re.setPattern("</?meta.*>");
n.replace(re,"");
re.setPattern("<style.*>.*</style>");
n.replace(re,"");
//re.setPattern("<!DOCTYPE.*>");
//n.replace(re,"");
}
else
{
n = current->getNoteASCII().replace ("<","<").replace (">",">");
n.replace("\n","<br/>");
if (current->getNote().getFontHint()=="fixed")
n = "<pre>" + n + "</pre>";
}
s += "\n<table class=\"vym-note\"><tr><td class=\"vym-note-flag\">\n<td>\n" + n + "\n</td></tr></table>\n";
}
return s;
}
return QString();
}
QString ExportHTML::buildList (BranchItem *current)
{
QString r;
uint i = 0;
uint visChilds = 0;
BranchItem *bi = current->getFirstBranch();
QString ind = "\n" + indent(current->depth() + 1, false);
QString sectionBegin;
QString sectionEnd;
QString itemBegin;
QString itemEnd;
switch (current->depth() + 1)
{
case 0:
sectionBegin = "";
sectionEnd = "";
itemBegin = "<h1>";
itemEnd = "</h1>";
break;
case 1:
sectionBegin = "";
sectionEnd = "";
itemBegin = "<h2>";
itemEnd = "</h2>";
break;
default:
sectionBegin = "<ul " + QString("class=\"vym-list-ul-%1\"").arg(current->depth() + 1) +">";
sectionEnd = "</ul>";
itemBegin = " <li>";
itemEnd = " </li>";
break;
}
if (bi && !bi->hasHiddenExportParent() && !bi->isHidden() )
{
r += ind + sectionBegin;
while (bi)
{
if (!bi->hasHiddenExportParent() && !bi->isHidden())
{
visChilds++;
r += ind + itemBegin;
r += getBranchText (bi);
if (itemBegin.startsWith("<h") )
r += itemEnd + buildList (bi);
else
r += buildList (bi) + itemEnd;
}
i++;
bi = current->getBranchNum(i);
}
r += ind + sectionEnd;
}
return r;
}
QString ExportHTML::createTOC()
{
QString toc;
QString number;
toc += "<table class=\"vym-toc\">\n";
toc += "<tr><td class=\"vym-toc-title\">\n";
toc += QObject::tr("Contents:","Used in HTML export");
toc += "\n";
toc += "</td></tr>\n";
toc += "<tr><td>\n";
BranchItem *cur = NULL;
BranchItem *prev = NULL;
model->nextBranch(cur, prev);
while (cur)
{
if (!cur->hasHiddenExportParent() && !cur->hasScrolledParent() )
{
if (dia.useNumbering) number = getSectionString(cur);
toc += QString("<div class=\"vym-toc-branch-%1\">").arg(cur->depth());
toc += QString("<a href=\"#%1\"> %2 %3</a></br>\n")
.arg(model->getSelectString(cur))
.arg(number)
.arg(quotemeta( cur->getHeadingPlain() ));
toc += "</div>";
}
model->nextBranch(cur,prev);
}
toc += "</td></tr>\n";
toc += "</table>\n";
return toc;
}
void ExportHTML::doExport(bool useDialog)
{
// Setup dialog and read settings
dia.setMapName (model->getMapName());
dia.setFilePath (model->getFilePath());
dia.readSettings();
if (dirPath != defaultDirPath)
dia.setDirectory(dirPath);
if (useDialog)
{
if (dia.exec() != QDialog::Accepted) return;
model->setChanged();
}
// Check, if warnings should be used before overwriting
// the output directory
if (dia.getDir().exists() && dia.getDir().count()>0)
{
WarningDialog warn;
warn.showCancelButton (true);
warn.setText(QString(
"The directory %1 is not empty.\n"
"Do you risk to overwrite some of its contents?").arg(dia.getDir().absolutePath() ));
warn.setCaption("Warning: Directory not empty");
warn.setShowAgainName("mainwindow/export-XML-overwrite-dir");
if (warn.exec()!=QDialog::Accepted)
{
mainWindow->statusMessage(QString(QObject::tr("Export aborted.")));
return;
}
}
dirPath=dia.getDir().absolutePath();
filePath=getFilePath();
// Copy CSS file
if (dia.css_copy)
{
cssSrc=dia.getCssSrc();
cssDst=dirPath + "/" + basename(dia.getCssDst());
if (cssSrc.isEmpty() )
{
QMessageBox::critical( 0,
QObject:: tr( "Critical" ),
QObject::tr("Could not find stylesheet %1").arg(cssSrc));
return;
}
QFile src(cssSrc);
QFile dst(cssDst);
if (dst.exists() ) dst.remove();
if (!src.copy(cssDst))
{
QMessageBox::critical (0,
QObject::tr( "Error","ExportHTML" ),
QObject::tr("Could not copy\n%1 to\n%2","ExportHTML").arg(cssSrc).arg(cssDst));
return;
}
}
// Copy flags
QDir flagsDst(dia.getDir().absolutePath() + "/flags");
if (!flagsDst.exists())
{
if (!dia.getDir().mkdir("flags"))
{
QMessageBox::critical( 0,
QObject::tr( "Critical" ),
QObject::tr("Trying to create directory for flags:") + "\n\n" +
QObject::tr("Could not create %1").arg(flagsDst.absolutePath()));
return;
}
}
QDir flagsSrc(flagsPath); // FIXME-3 don't use flagsPath as source anymore, but copy required flags directly from memory
if (!copyDir(flagsSrc, flagsDst, true))
{
QMessageBox::critical( 0,
QObject::tr( "Critical" ),
QObject::tr("Could not copy %1 to %2").arg(flagsSrc.absolutePath()).arg(flagsDst.absolutePath()));
return;
}
// Open file for writing
QFile file (filePath);
if ( !file.open( QIODevice::WriteOnly ) )
{
QMessageBox::critical (0,
QObject::tr("Critical Export Error"),
QObject::tr("Trying to save HTML file:") + "\n\n"+
QObject::tr("Could not write %1").arg(filePath));
mainWindow->statusMessage(QString(QObject::tr("Export failed.")));
return;
}
QTextStream ts( &file );
ts.setCodec("UTF-8");
// Hide stuff during export
model->setExportMode (true);
// Write header
ts << "<html>";
ts << "\n<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\"> ";
ts << "\n<meta name=\"generator=\" content=\" vym - view your mind - " + vymVersion + " - " + vymHome + "\">";
ts << "\n<meta name=\"author\" content=\"" + quotemeta(model->getAuthor()) + "\"> ";
ts << "\n<meta name=\"description\" content=\"" + quotemeta(model->getComment()) + "\"> ";
ts << "\n<link rel='stylesheet' id='css.stylesheet' href='" << basename(cssDst) << "' />\n";
QString title=model->getTitle();
if (title.isEmpty()) title=model->getMapName();
ts << "\n<head><title>" + quotemeta(title) + "</title></head>";
ts << "\n<body>\n";
// Include image
// (be careful: this resets Export mode, so call before exporting branches)
if (dia.includeMapImage)
{
QString mapName = getMapName();
ts << "<center><img src=\"" << mapName << ".png\"";
ts << "alt=\"" << QObject::tr("Image of map: %1.vym","Alt tag in HTML export").arg(mapName) << "\"";
ts << " usemap='#imagemap'></center>\n";
offset = model->exportImage (dirPath + "/" + mapName + ".png", false, "PNG");
}
// Include table of contents
if (dia.useTOC) ts << createTOC();
// Main loop over all mapcenters
ts << buildList(model->getRootItem()) << "\n";
// Imagemap
ts << "<map name='imagemap'>\n" + imageMap + "</map>\n";
// Write footer
ts << "<hr/>\n";
ts << "<table class=\"vym-footer\"> \n\
<tr> \n\
<td class=\"vym-footerL\">" + filePath + "</td> \n\
<td class=\"vym-footerC\">" + model->getDate() + "</td> \n\
<td class=\"vym-footerR\"> <a href='" + vymHome + "'>vym " + vymVersion + "</a></td> \n\
</tr> \n \
</table>\n";
ts << "</body></html>";
file.close();
if (!dia.postscript.isEmpty())
{
VymProcess p;
p.runScript (dia.postscript,dirPath + "/" + filePath);
}
destination = filePath;
success = true;
QMap <QString, QString> args;
args["filePath"] = filePath;
args["dirPath"] = dirPath;
completeExport( args );
dia.saveSettings();
model->setExportMode (false);
}