новые иконки в OpenBoard
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
OpenBoard/plugins/cffadaptor/src/UBCFFAdaptor.cpp

2075 lines
67 KiB

/*
* Copyright (C) 2010-2013 Groupement d'Intérêt Public pour l'Education Numérique en Afrique (GIP ENA)
*
* This file is part of Open-Sankoré.
*
* Open-Sankoré is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License,
* with a specific linking exception for the OpenSSL project's
* "OpenSSL" library (or with modified versions of it that use the
* same license as the "OpenSSL" library).
*
* Open-Sankoré is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Open-Sankoré. If not, see <http://www.gnu.org/licenses/>.
*/
#include "UBCFFAdaptor.h"
#include <QtCore>
#include <QtXml>
#include <QTransform>
#include <QGraphicsItem>
#include <QSvgRenderer>
#include <QPainter>
#include "UBGlobals.h"
#include "UBCFFConstants.h"
//THIRD_PARTY_WARNINGS_DISABLE
#ifdef Q_OS_OSX
#include <quazip.h>
#include <quazipfile.h>
#include <quazipfileinfo.h>
#else
#include "quazip.h"
#include "quazipfile.h"
#include "quazipfileinfo.h"
#endif
//THIRD_PARTY_WARNINGS_ENABLE
UBCFFAdaptor::UBCFFAdaptor()
{}
bool UBCFFAdaptor::convertUBZToIWB(const QString &from, const QString &to)
{
qDebug() << "starting converion from" << from << "to" << to;
QString source = QString();
if (QFileInfo(from).isDir() && QFile::exists(from)) {
qDebug() << "File specified is dir, continuing convertion";
source = from;
} else {
source = uncompressZip(from);
if (!source.isNull()) qDebug() << "File specified is zip file. Uncompressed to tmp dir, continuing convertion";
}
if (source.isNull()) {
qDebug() << "File specified is not a dir or a zip file, stopping covretion";
return false;
}
QString tmpDestination = createNewTmpDir();
if (tmpDestination.isNull()) {
qDebug() << "can't create temp destination folder. Stopping parsing...";
return false;
}
UBToCFFConverter tmpConvertrer(source, tmpDestination);
if (!tmpConvertrer) {
qDebug() << "The convertrer class is invalid, stopping conversion. Error message" << tmpConvertrer.lastErrStr();
return false;
}
bool bParceRes = tmpConvertrer.parse();
mConversionMessages << tmpConvertrer.getMessages();
if (!bParceRes) {
return false;
}
if (!compressZip(tmpDestination, to))
qDebug() << "error in compression";
//Cleanning tmp souces in filesystem
if (!QFileInfo(from).isDir())
if (!freeDir(source))
qDebug() << "can't delete tmp directory" << QDir(source).absolutePath() << "try to delete them manually";
if (!freeDir(tmpDestination))
qDebug() << "can't delete tmp directory" << QDir(tmpDestination).absolutePath() << "try to delete them manually";
return true;
}
QString UBCFFAdaptor::uncompressZip(const QString &zipFile)
{
QuaZip zip(zipFile);
if(!zip.open(QuaZip::mdUnzip)) {
qWarning() << "Import failed. Cause zip.open(): " << zip.getZipError();
return QString();
}
zip.setFileNameCodec("UTF-8");
QuaZipFileInfo info;
QuaZipFile file(&zip);
//create unique cff document root fodler
QString documentRootFolder = createNewTmpDir();
if (documentRootFolder.isNull()) {
qDebug() << "can't create tmp directory for zip file" << zipFile;
return QString();
}
QDir rootDir(documentRootFolder);
QFile out;
char c;
bool allOk = true;
for(bool more = zip.goToFirstFile(); more; more=zip.goToNextFile()) {
if(!zip.getCurrentFileInfo(&info)) {
qWarning() << "Import failed. Cause: getCurrentFileInfo(): " << zip.getZipError();
allOk = false;
break;
}
if(!file.open(QIODevice::ReadOnly)) {
allOk = false;
break;
}
if(file.getZipError()!= UNZ_OK) {
qWarning() << "Import failed. Cause: file.getFileName(): " << zip.getZipError();
allOk = false;
break;
}
QString newFileName = documentRootFolder + "/" + file.getActualFileName();
QFileInfo newFileInfo(newFileName);
rootDir.mkpath(newFileInfo.absolutePath());
out.setFileName(newFileName);
out.open(QIODevice::WriteOnly);
while(file.getChar(&c))
out.putChar(c);
out.close();
if(file.getZipError()!=UNZ_OK) {
qWarning() << "Import failed. Cause: " << zip.getZipError();
allOk = false;
break;
}
if(!file.atEnd()) {
qWarning() << "Import failed. Cause: read all but not EOF";
allOk = false;
break;
}
file.close();
if(file.getZipError()!=UNZ_OK) {
qWarning() << "Import failed. Cause: file.close(): " << file.getZipError();
allOk = false;
break;
}
}
if (!allOk) {
out.close();
file.close();
zip.close();
return QString();
}
if(zip.getZipError()!=UNZ_OK) {
qWarning() << "Import failed. Cause: zip.close(): " << zip.getZipError();
return QString();
}
return documentRootFolder;
}
bool UBCFFAdaptor::compressZip(const QString &source, const QString &destination)
{
QDir toDir = QFileInfo(destination).dir();
if (!toDir.exists())
if (!QDir().mkpath(toDir.absolutePath())) {
qDebug() << "can't create destination folder to uncompress file";
return false;
}
QuaZip zip(destination);
zip.setFileNameCodec("UTF-8");
if(!zip.open(QuaZip::mdCreate)) {
qDebug("Export failed. Cause: zip.open(): %d", zip.getZipError());
return false;
}
QuaZipFile outZip(&zip);
QFileInfo sourceInfo(source);
if (sourceInfo.isDir()) {
if (!compressDir(QFileInfo(source).absoluteFilePath(), "", &outZip))
return false;
} else if (sourceInfo.isFile()) {
if (!compressFile(QFileInfo(source).absoluteFilePath(), "", &outZip))
return false;
}
return true;
}
bool UBCFFAdaptor::compressDir(const QString &dirName, const QString &parentDir, QuaZipFile *outZip)
{
QFileInfoList dirFiles = QDir(dirName).entryInfoList(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
QListIterator<QFileInfo> iter(dirFiles);
while (iter.hasNext()) {
QFileInfo curFile = iter.next();
if (curFile.isDir()) {
if (!compressDir(curFile.absoluteFilePath(), parentDir + curFile.fileName() + "/", outZip)) {
qDebug() << "error at compressing dir" << curFile.absoluteFilePath();
return false;
}
} else if (curFile.isFile()) {
if (!compressFile(curFile.absoluteFilePath(), parentDir, outZip)) {
return false;
}
}
}
return true;
}
bool UBCFFAdaptor::compressFile(const QString &fileName, const QString &parentDir, QuaZipFile *outZip)
{
QFile sourceFile(fileName);
if(!sourceFile.open(QIODevice::ReadOnly)) {
qDebug() << "Compression of file" << sourceFile.fileName() << " failed. Cause: inFile.open(): " << sourceFile.errorString();
return false;
}
if(!outZip->open(QIODevice::WriteOnly, QuaZipNewInfo(parentDir + QFileInfo(fileName).fileName(), sourceFile.fileName()))) {
qDebug() << "Compression of file" << sourceFile.fileName() << " failed. Cause: outFile.open(): " << outZip->getZipError();
sourceFile.close();
return false;
}
outZip->write(sourceFile.readAll());
if(outZip->getZipError() != UNZ_OK) {
qDebug() << "Compression of file" << sourceFile.fileName() << " failed. Cause: outFile.write(): " << outZip->getZipError();
sourceFile.close();
outZip->close();
return false;
}
if(outZip->getZipError() != UNZ_OK)
{
qWarning() << "Compression of file" << sourceFile.fileName() << " failed. Cause: outFile.close(): " << outZip->getZipError();
sourceFile.close();
outZip->close();
return false;
}
outZip->close();
sourceFile.close();
return true;
}
QString UBCFFAdaptor::createNewTmpDir()
{
int tmpNumber = 0;
QDir systemTmp = QDir::temp();
while (true) {
QString dirName = QString("CFF_adaptor_filedata_store%1.%2")
.arg(QDateTime::currentDateTime().toString("dd_MM_yyyy_HH-mm"))
.arg(tmpNumber++);
if (!systemTmp.exists(dirName)) {
if (systemTmp.mkdir(dirName)) {
QString result = systemTmp.absolutePath() + "/" + dirName;
tmpDirs.append(result);
return result;
} else {
qDebug() << "Can't create temporary dir maybe due to permissions";
return QString();
}
} else if (tmpNumber == 10) {
qWarning() << "Import failed. Failed to create temporary file ";
return QString();
}
tmpNumber++;
}
return QString();
}
bool UBCFFAdaptor::deleteDir(const QString& pDirPath) const
{
if (pDirPath == "" || pDirPath == "." || pDirPath == "..")
return false;
QDir dir(pDirPath);
if (dir.exists())
{
foreach(QFileInfo dirContent, dir.entryInfoList(QDir::Files | QDir::Dirs
| QDir::NoDotAndDotDot | QDir::Hidden | QDir::System, QDir::Name))
{
if (dirContent.isDir())
{
deleteDir(dirContent.absoluteFilePath());
}
else
{
if (!dirContent.dir().remove(dirContent.fileName()))
{
return false;
}
}
}
}
return dir.rmdir(pDirPath);
}
QList<QString> UBCFFAdaptor::getConversionMessages()
{
return mConversionMessages;
}
bool UBCFFAdaptor::freeDir(const QString &dir)
{
bool result = true;
if (!deleteDir(dir))
result = false;
tmpDirs.removeAll(QDir(dir).absolutePath());
return result;
}
void UBCFFAdaptor::freeTmpDirs()
{
foreach (QString dir, tmpDirs)
freeDir(dir);
}
UBCFFAdaptor::~UBCFFAdaptor()
{
freeTmpDirs();
}
UBCFFAdaptor::UBToCFFConverter::UBToCFFConverter(const QString &source, const QString &destination)
{
sourcePath = source;
destinationPath = destination;
errorStr = noErrorMsg;
mDataModel = new QDomDocument;
mDocumentToWrite = new QDomDocument;
mDocumentToWrite->setContent(QString("<doc></doc>"));
mIWBContentWriter = new QXmlStreamWriter;
mIWBContentWriter->setAutoFormatting(true);
iwbSVGItemsAttributes.insert(tIWBImage, iwbSVGImageAttributes);
iwbSVGItemsAttributes.insert(tIWBVideo, iwbSVGVideoAttributes);
iwbSVGItemsAttributes.insert(tIWBText, iwbSVGTextAttributes);
iwbSVGItemsAttributes.insert(tIWBTextArea, iwbSVGTextAreaAttributes);
iwbSVGItemsAttributes.insert(tIWBPolyLine, iwbSVGPolyLineAttributes);
iwbSVGItemsAttributes.insert(tIWBPolygon, iwbSVGPolygonAttributes);
iwbSVGItemsAttributes.insert(tIWBRect, iwbSVGRectAttributes);
iwbSVGItemsAttributes.insert(tIWBLine, iwbSVGLineAttributes);
iwbSVGItemsAttributes.insert(tIWBTspan, iwbSVGTspanAttributes);
}
bool UBCFFAdaptor::UBToCFFConverter::parse()
{
if(!isValid()) {
qDebug() << "document metadata is not valid. Can't parse";
return false;
}
qDebug() << "begin parsing ubz";
QFile outFile(contentIWBFileName());
if (!outFile.open(QIODevice::WriteOnly| QIODevice::Text)) {
qDebug() << "can't open output file for writing";
errorStr = "createXMLOutputPatternError";
return false;
}
mIWBContentWriter->setDevice(&outFile);
mIWBContentWriter->writeStartDocument();
mIWBContentWriter->writeStartElement(tIWBRoot);
fillNamespaces();
mIWBContentWriter->writeAttribute(aIWBVersion, avIWBVersionNo);
if (!parseMetadata()) {
if (errorStr == noErrorMsg)
errorStr = "MetadataParsingError";
outFile.close();
return false;
}
if (!parseContent()) {
if (errorStr == noErrorMsg)
errorStr = "ContentParsingError";
outFile.close();
return false;
}
mIWBContentWriter->writeEndElement();
mIWBContentWriter->writeEndDocument();
outFile.close();
qDebug() << "finished with success";
return true;
}
bool UBCFFAdaptor::UBToCFFConverter::parseMetadata()
{
int errorLine, errorColumn;
QFile metaDataFile(sourcePath + "/" + fMetadata);
if (!metaDataFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
errorStr = "can't open" + QFileInfo(sourcePath + "/" + fMetadata).absoluteFilePath();
qDebug() << errorStr;
return false;
} else if (!mDataModel->setContent(metaDataFile.readAll(), true, &errorStr, &errorLine, &errorColumn)) {
qWarning() << "Error:Parseerroratline" << errorLine << ","
<< "column" << errorColumn << ":" << errorStr;
return false;
}
QDomElement nextInElement = mDataModel->documentElement();
nextInElement = nextInElement.firstChildElement(tDescription);
if (!nextInElement.isNull()) {
mIWBContentWriter->writeStartElement(iwbNS, tIWBMeta);
mIWBContentWriter->writeAttribute(aIWBName, aCreator);
mIWBContentWriter->writeAttribute(aIWBContent, avCreator);
mIWBContentWriter->writeEndElement();
mIWBContentWriter->writeStartElement(iwbNS, tIWBMeta);
mIWBContentWriter->writeAttribute(aIWBName, aOwner);
mIWBContentWriter->writeAttribute(aIWBContent, avOwner);
mIWBContentWriter->writeEndElement();
mIWBContentWriter->writeStartElement(iwbNS, tIWBMeta);
mIWBContentWriter->writeAttribute(aIWBName, aDescription);
mIWBContentWriter->writeAttribute(aIWBContent, avDescription);
mIWBContentWriter->writeEndElement();
mIWBContentWriter->writeStartElement(iwbNS, tIWBMeta);
mIWBContentWriter->writeAttribute(aIWBName, aAbout);
mIWBContentWriter->writeAttribute(aIWBContent, nextInElement.attribute(aAbout));
mIWBContentWriter->writeEndElement();
nextInElement = nextInElement.firstChildElement();
while (!nextInElement.isNull()) {
QString textContent = nextInElement.text();
if (!textContent.trimmed().isEmpty()) {
if (nextInElement.tagName() == tUBZSize) { //taking main viewbox rect since for CFF specificaton we have static viewbox
QSize tmpSize = getSVGDimentions(nextInElement.text());
if (!tmpSize.isNull()) {
mSVGSize = tmpSize;
} else {
qDebug() << "can't interpret svg section size";
errorStr = "InterpretSvgSizeError";
return false;
}
} else {
mIWBContentWriter->writeStartElement(iwbNS, tIWBMeta);
mIWBContentWriter->writeAttribute(aIWBName, nextInElement.tagName());
mIWBContentWriter->writeAttribute(aIWBContent, textContent);
mIWBContentWriter->writeEndElement();
}
}
nextInElement = nextInElement.nextSiblingElement();
}
}
metaDataFile.close();
return true;
}
bool UBCFFAdaptor::UBToCFFConverter::parseContent() {
QDir sourceDir(sourcePath);
QStringList fileFilters;
fileFilters << QString(pageAlias + "???." + pageFileExtentionUBZ);
QStringList pageList = sourceDir.entryList(fileFilters, QDir::Files, QDir::Name | QDir::IgnoreCase);
QDomElement svgDocumentSection = mDataModel->createElementNS(svgIWBNS, ":"+tSvg);
if (!pageList.count()) {
qDebug() << "can't find any content file";
errorStr = "ErrorContentFile";
return false;
} else
{
QDomElement pageset = parsePageset(pageList);
if (pageset.isNull())
return false;
else
svgDocumentSection.appendChild(pageset);
}
if (QRect() == mViewbox)
{
mViewbox.setRect(0,0, mSVGSize.width(), mSVGSize.height());
}
svgDocumentSection.setAttribute(aIWBViewBox, rectToIWBAttr(mViewbox));
svgDocumentSection.setAttribute(aWidth, QString("%1").arg(mViewbox.width()));
svgDocumentSection.setAttribute(aHeight, QString("%1").arg(mViewbox.height()));
writeQDomElementToXML(svgDocumentSection);
if (!writeExtendedIwbSection()) {
if (errorStr == noErrorMsg)
errorStr = "writeExtendedIwbSectionError";
return false;
}
return true;
}
QDomElement UBCFFAdaptor::UBToCFFConverter::parsePage(const QString &pageFileName)
{
qDebug() << "begin parsing page" + pageFileName;
mSvgElements.clear(); //clean Svg elements map before parsing new page
int errorLine, errorColumn;
QFile pageFile(sourcePath + "/" + pageFileName);
if (!pageFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "can't open file" << pageFileName << "for reading";
return QDomElement();
} else if (!mDataModel->setContent(pageFile.readAll(), true, &errorStr, &errorLine, &errorColumn)) {
qWarning() << "Error:Parseerroratline" << errorLine << ","
<< "column" << errorColumn << ":" << errorStr;
pageFile.close();
return QDomElement();
}
QDomElement page;
QDomElement group;
QDomElement nextTopElement = mDataModel->firstChildElement();
while (!nextTopElement.isNull()) {
QString tagname = nextTopElement.tagName();
if (tagname == tSvg) {
page = parseSvgPageSection(nextTopElement);
if (page.isNull()) {
qDebug() << "The page is empty.";
pageFile.close();
return QDomElement();
}
} else if (tagname == tUBZGroups) {
group = parseGroupsPageSection(nextTopElement);
if (group.isNull()) {
qDebug() << "Page doesn't contains any groups.";
pageFile.close();
return QDomElement();
}
}
nextTopElement = nextTopElement.nextSiblingElement();
}
pageFile.close();
return page.hasChildNodes() ? page : QDomElement();
}
QDomElement UBCFFAdaptor::UBToCFFConverter::parsePageset(const QStringList &pageFileNames)
{
QMultiMap<int, QDomElement> pageList;
int iPageNo = 1;
QStringListIterator curPage(pageFileNames);
while (curPage.hasNext()) {
QString curPageFile = curPage.next();
QDomElement iterElement = parsePage(curPageFile);
if (!iterElement.isNull())
{
iterElement.setAttribute(tId, iPageNo);
addSVGElementToResultModel(iterElement, pageList, iPageNo);
iPageNo++;
}
else
return QDomElement();
}
if (!pageList.count())
return QDomElement();
QDomElement svgPagesetElement = mDocumentToWrite->createElementNS(svgIWBNS,":"+ tIWBPageSet);
QMapIterator<int, QDomElement> nextSVGElement(pageList);
nextSVGElement.toFront();
while (nextSVGElement.hasNext())
svgPagesetElement.appendChild(nextSVGElement.next().value());
return svgPagesetElement.hasChildNodes() ? svgPagesetElement : QDomElement();
}
QDomElement UBCFFAdaptor::UBToCFFConverter::parseSvgPageSection(const QDomElement &element)
{
//we don't know about page number, so return QDomElement.
//Parsing top level tag attributes
//getting current page viewbox to be able to convert coordinates to global viewbox parameter
if (element.hasAttribute(aUBZViewBox)) {
setViewBox(getViewboxRect(element.attribute(aUBZViewBox)));
}
QMultiMap<int, QDomElement> svgElements;
QDomElement svgElementPart = mDocumentToWrite->createElementNS(svgIWBNS,":"+ tIWBPage);
if (element.hasAttribute(aDarkBackground)) {
createBackground(element, svgElements);
}
//Parsing svg children attributes
// Elements can know about its layer, so it must add result QDomElements to ordrered list.
QDomElement nextElement = element.firstChildElement();
while (!nextElement.isNull()) {
QString tagName = nextElement.tagName();
if (tagName == tUBZG) parseSVGGGroup(nextElement, svgElements);
else if (tagName == tUBZImage) parseUBZImage(nextElement, svgElements);
else if (tagName == tUBZVideo) parseUBZVideo(nextElement, svgElements);
else if (tagName == tUBZAudio) parseUBZAudio(nextElement, svgElements);
else if (tagName == tUBZForeignObject) parseForeignObject(nextElement, svgElements);
else if (tagName == tUBZLine) parseUBZLine(nextElement, svgElements);
else if (tagName == tUBZPolygon) parseUBZPolygon(nextElement, svgElements);
else if (tagName == tUBZPolyline) parseUBZPolyline(nextElement, svgElements);
else if (tagName == tUBZGroups) parseGroupsPageSection(nextElement);
nextElement = nextElement.nextSiblingElement();
}
if (0 == svgElements.count())
return QDomElement();
// to do:
// there we must to sort elements (take elements from list and assign parent ordered like in parseSVGGGroup)
// we returns just element because we don't care about layer.
QMapIterator<int, QDomElement> nextSVGElement(svgElements);
nextSVGElement.toFront();
while (nextSVGElement.hasNext())
svgElementPart.appendChild(nextSVGElement.next().value());
return svgElementPart.hasChildNodes() ? svgElementPart : QDomElement();
}
void UBCFFAdaptor::UBToCFFConverter::writeQDomElementToXML(const QDomNode &node)
{
if (!node.isNull()) {
if (node.isText())
mIWBContentWriter->writeCharacters(node.nodeValue());
else {
mIWBContentWriter->writeStartElement(node.namespaceURI(), node.toElement().tagName());
for (int i = 0; i < node.toElement().attributes().count(); i++) {
QDomAttr attr = node.toElement().attributes().item(i).toAttr();
mIWBContentWriter->writeAttribute(attr.name(), attr.value());
}
QDomNode child = node.firstChild();
while(!child.isNull()) {
writeQDomElementToXML(child);
child = child.nextSibling();
}
mIWBContentWriter->writeEndElement();
}
}
}
bool UBCFFAdaptor::UBToCFFConverter::writeExtendedIwbSection()
{
if (!mExtendedElements.count()) {
qDebug() << "extended iwb content list is empty";
errorStr = "EmptyExtendedIwbSectionContentError";
return false;
}
QListIterator<QDomElement> nextExtendedIwbElement(mExtendedElements);
while (nextExtendedIwbElement.hasNext()) {
writeQDomElementToXML(nextExtendedIwbElement.next());
//TODO write iwb extended element to mIWBContentWriter
}
return true;
}
// extended element options
// editable, background, locked are supported for now
QDomElement UBCFFAdaptor::UBToCFFConverter::parseGroupsPageSection(const QDomElement &groupRoot)
{
// First sankore side implementation needed. TODO in Sankore 1.5
if (!groupRoot.hasChildNodes()) {
qDebug() << "Group root is empty";
return QDomElement();
}
QDomElement groupElement = groupRoot.firstChildElement();
while (!groupElement.isNull()) {
QDomElement extendedElement = mDataModel->createElementNS(iwbNS, groupElement.tagName());
QDomElement groupChildElement = groupElement.firstChildElement();
while (!groupChildElement.isNull()) {
QDomElement extSubElement = mDataModel->createElementNS(iwbNS, groupChildElement.tagName());
extSubElement.setAttribute(aRef, groupChildElement.attribute(aID, QUuid().toString()));
extendedElement.appendChild(extSubElement);
groupChildElement = groupChildElement.nextSiblingElement();
}
mExtendedElements.append(extendedElement);
groupElement = groupElement.nextSiblingElement();
}
qDebug() << "parsing ubz group section";
return groupRoot;
}
QString UBCFFAdaptor::UBToCFFConverter::getDstContentFolderName(const QString &elementType)
{
QString sRet;
QString sDstContentFolderName;
// widgets must be saved as .png images.
if ((tIWBImage == elementType) || (tUBZForeignObject == elementType))
sDstContentFolderName = cfImages;
else
if (tIWBVideo == elementType)
sDstContentFolderName = cfVideos;
else
if (tIWBAudio == elementType)
sDstContentFolderName = cfAudios;
sRet = sDstContentFolderName;
return sRet;
}
QString UBCFFAdaptor::UBToCFFConverter::getSrcContentFolderName(QString href)
{
QString sRet;
QStringList ls = href.split("/");
for (int i = 0; i < ls.count()-1; i++)
{
QString sPart = ls.at(i);
if (ubzContentFolders.contains(sPart))
{
sRet = sPart;
}
}
// if (0 < ls.count())
// sRet = ls.at(ls.count()-1);
//
// sRet = href.remove(sRet);
//
// if (sRet.endsWith("/"))
// sRet.remove("/");
return sRet;
}
QString UBCFFAdaptor::UBToCFFConverter::getFileNameFromPath(const QString sPath)
{
QString sRet;
QStringList sl = sPath.split("/",QString::SkipEmptyParts);
if (0 < sl.count())
{
QString name = sl.at(sl.count()-1);
QString extention = getExtentionFromFileName(name);
if (feWgt == extention)
{
name.remove("{");
name.remove("}");
}
name.remove(name.length()-extention.length(), extention.length());
name += convertExtention(extention);
sRet = name;
}
return sRet;
}
QString UBCFFAdaptor::UBToCFFConverter::getExtentionFromFileName(const QString &filename)
{
QStringList sl = filename.split("/",QString::SkipEmptyParts);
if (0 < sl.count())
{
QString name = sl.at(sl.count()-1);
QStringList tl = name.split(".");
return tl.at(tl.count()-1);
}
return QString();
}
QString UBCFFAdaptor::UBToCFFConverter::convertExtention(const QString &ext)
{
QString sRet;
if (feSvg == ext)
sRet = fePng;
else
if (feWgt == ext)
sRet = fePng;
else
sRet = ext;
return sRet;
}
QString UBCFFAdaptor::UBToCFFConverter::getElementTypeFromUBZ(const QDomElement &element)
{
QString sRet;
if (tUBZForeignObject == element.tagName())
{
QString sPath;
if (element.hasAttribute(aUBZType))
{
if (avUBZText == element.attribute(aUBZType))
sRet = tIWBTextArea;
else
sRet = element.attribute(aUBZType);
}
else
{
if (element.hasAttribute(aSrc))
sPath = element.attribute(aSrc);
else
if (element.hasAttribute(aUBZHref))
sPath = element.attribute(aUBZHref);
QStringList tsl = sPath.split(".", QString::SkipEmptyParts);
if (0 < tsl.count())
{
QString elementType = tsl.at(tsl.count()-1);
if (iwbElementImage.contains(elementType))
sRet = tIWBImage;
else
if (iwbElementAudio.contains(elementType))
sRet = tIWBAudio;
else
if (iwbElementVideo.contains(elementType))
sRet = tIWBVideo;
}
}
}
else
sRet = element.tagName();
return sRet;
}
int UBCFFAdaptor::UBToCFFConverter::getElementLayer(const QDomElement &element)
{
int iRetLayer = 0;
if (element.hasAttribute(aZLayer))
iRetLayer = (int)element.attribute(aZLayer).toDouble();
else
iRetLayer = DEFAULT_LAYER;
return iRetLayer;
}
bool UBCFFAdaptor::UBToCFFConverter::itIsSupportedFormat(const QString &format) const
{
bool bRet;
QStringList tsl = format.split(".", QString::SkipEmptyParts);
if (0 < tsl.count())
bRet = cffSupportedFileFormats.contains(tsl.at(tsl.count()-1).toLower());
else
bRet = false;
return bRet;
}
bool UBCFFAdaptor::UBToCFFConverter::itIsFormatToConvert(const QString &format) const
{
foreach (QString f, ubzFormatsToConvert.split(","))
{
if (format == f)
return true;
}
return false;
}
bool UBCFFAdaptor::UBToCFFConverter::itIsSVGElementAttribute(const QString ItemType, const QString &AttrName)
{
QString allowedElementAttributes = iwbSVGItemsAttributes[ItemType];
allowedElementAttributes.remove("/t");
allowedElementAttributes.remove(" ");
foreach(QString attr, allowedElementAttributes.split(","))
{
if (AttrName == attr.trimmed())
return true;
}
return false;
}
bool UBCFFAdaptor::UBToCFFConverter::itIsIWBAttribute(const QString &attribute) const
{
foreach (QString attr, iwbElementAttributes.split(","))
{
if (attribute == attr.trimmed())
return true;
}
return false;
}
bool UBCFFAdaptor::UBToCFFConverter::itIsUBZAttributeToConvert(const QString &attribute) const
{
foreach (QString attr, ubzElementAttributesToConvert.split(","))
{
if (attribute == attr.trimmed())
return true;
}
return false;
}
bool UBCFFAdaptor::UBToCFFConverter::ibwAddLine(int x1, int y1, int x2, int y2, QString color, int width, bool isBackground)
{
bool bRet = true;
QDomDocument doc;
QDomElement svgBackgroundCrossPart = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":line");
QDomElement iwbBackgroundCrossPart = doc.createElementNS(iwbNS,iwbNsPrefix + ":" + tElement);
QString sUUID = QUuid::createUuid().toString();
svgBackgroundCrossPart.setTagName(tIWBLine);
svgBackgroundCrossPart.setAttribute(aX+"1", x1);
svgBackgroundCrossPart.setAttribute(aY+"1", y1);
svgBackgroundCrossPart.setAttribute(aX+"2", x2);
svgBackgroundCrossPart.setAttribute(aY+"2", y2);
svgBackgroundCrossPart.setAttribute(aStroke, color);
svgBackgroundCrossPart.setAttribute(aStrokeWidth, width);
svgBackgroundCrossPart.setAttribute(aID, sUUID);
if (isBackground)
{
iwbBackgroundCrossPart.setAttribute(aRef, sUUID);
iwbBackgroundCrossPart.setAttribute(aLocked, avTrue);
addIWBElementToResultModel(iwbBackgroundCrossPart);
}
addSVGElementToResultModel(svgBackgroundCrossPart, mSvgElements, DEFAULT_BACKGROUND_CROSS_LAYER);
if (!bRet)
{
qDebug() << "|error at creating crosses on background";
errorStr = "CreatingCrossedBackgroundParsingError.";
}
return bRet;
}
QTransform UBCFFAdaptor::UBToCFFConverter::getTransformFromUBZ(const QDomElement &ubzElement)
{
QTransform trRet;
QStringList transformParameters;
QString ubzTransform = ubzElement.attribute(aTransform);
ubzTransform.remove("matrix");
ubzTransform.remove("(");
ubzTransform.remove(")");
transformParameters = ubzTransform.split(",", QString::SkipEmptyParts);
if (6 <= transformParameters.count())
{
QTransform *tr = NULL;
tr = new QTransform(transformParameters.at(0).toDouble(),
transformParameters.at(1).toDouble(),
transformParameters.at(2).toDouble(),
transformParameters.at(3).toDouble(),
transformParameters.at(4).toDouble(),
transformParameters.at(5).toDouble());
trRet = *tr;
delete tr;
}
if (6 <= transformParameters.count())
{
QTransform *tr = NULL;
tr = new QTransform(transformParameters.at(0).toDouble(),
transformParameters.at(1).toDouble(),
transformParameters.at(2).toDouble(),
transformParameters.at(3).toDouble(),
transformParameters.at(4).toDouble(),
transformParameters.at(5).toDouble());
trRet = *tr;
delete tr;
}
return trRet;
}
qreal UBCFFAdaptor::UBToCFFConverter::getAngleFromTransform(const QTransform &tr)
{
qreal angle = -(atan(tr.m21()/tr.m11())*180/PI);
if (tr.m21() > 0 && tr.m11() < 0)
angle += 180;
else
if (tr.m21() < 0 && tr.m11() < 0)
angle += 180;
return angle;
}
void UBCFFAdaptor::UBToCFFConverter::setGeometryFromUBZ(const QDomElement &ubzElement, QDomElement &iwbElement)
{
setCoordinatesFromUBZ(ubzElement,iwbElement);
}
void UBCFFAdaptor::UBToCFFConverter::setCoordinatesFromUBZ(const QDomElement &ubzElement, QDomElement &iwbElement)
{
QTransform tr;
if (QString() != ubzElement.attribute(aTransform))
tr = getTransformFromUBZ(ubzElement);
qreal x = ubzElement.attribute(aX).toDouble();
qreal y = ubzElement.attribute(aY).toDouble();
qreal height = ubzElement.attribute(aHeight).toDouble();
qreal width = ubzElement.attribute(aWidth).toDouble();
qreal alpha = getAngleFromTransform(tr);
QRectF itemRect;
QGraphicsRectItem item;
item.setRect(0,0, width, height);
item.setTransform(tr);
item.setRotation(-alpha);
QMatrix sceneMatrix = item.sceneMatrix();
iwbElement.setAttribute(aX, x);
iwbElement.setAttribute(aY, y);
iwbElement.setAttribute(aHeight, height*sceneMatrix.m22());
iwbElement.setAttribute(aWidth, width*sceneMatrix.m11());
iwbElement.setAttribute(aTransform, QString("rotate(%1) translate(%2,%3)").arg(alpha)
.arg(sceneMatrix.dx())
.arg(sceneMatrix.dy()));
}
bool UBCFFAdaptor::UBToCFFConverter::setContentFromUBZ(const QDomElement &ubzElement, QDomElement &svgElement)
{
bool bRet = true;
QString srcPath;
if (tUBZForeignObject != ubzElement.tagName())
srcPath = ubzElement.attribute(aUBZHref);
else
srcPath = ubzElement.attribute(aSrc);
QString sSrcContentFolder = getSrcContentFolderName(srcPath);
QString sSrcFileName = sourcePath + "/" + srcPath ;
QString fileExtention = getExtentionFromFileName(sSrcFileName);
QString sDstContentFolder = getDstContentFolderName(ubzElement.tagName());
QString sDstFileName(QString(QUuid::createUuid().toString()+"."+convertExtention(fileExtention)));
if (itIsSupportedFormat(fileExtention)) // format is supported and we can copy src. files without changing.
{
sSrcFileName = sourcePath + "/" + sSrcContentFolder + "/" + getFileNameFromPath(srcPath); // some elements must be exported as images, so we take hes existing thumbnails.
QFile srcFile;
srcFile.setFileName(sSrcFileName);
QDir dstDocFolder(destinationPath);
if (!dstDocFolder.exists(sDstContentFolder))
bRet &= dstDocFolder.mkdir(sDstContentFolder);
if (bRet)
{
QString dstFilePath = destinationPath+"/"+sDstContentFolder+"/"+sDstFileName;
bRet &= srcFile.copy(dstFilePath);
}
if (bRet)
{
svgElement.setAttribute(aSVGHref, sDstContentFolder+"/"+sDstFileName);
// NOT by standard! Enable it later!
// validator http://validator.imsglobal.org/iwb/index.jsp?validate=package
//svgElement.setAttribute(aSVGRequiredExtension, svgRequiredExtensionPrefix+convertExtention(fileExtention));
}
}
else
if (itIsFormatToConvert(fileExtention)) // we cannot copy that source files. We need to create dst. file from src. file without copy.
{
if (feSvg == fileExtention)
{
QDir dstDocFolder(destinationPath);
if (!dstDocFolder.exists(sDstContentFolder))
bRet &= dstDocFolder.mkdir(sDstContentFolder);
if (bRet)
{
if (feSvg == fileExtention) // svg images must be converted to PNG.
{
QString dstFilePath = destinationPath+"/"+sDstContentFolder+"/"+sDstFileName;
bRet &= createPngFromSvg(sSrcFileName, dstFilePath, getTransformFromUBZ(ubzElement));
}
else
bRet = false;
}
if (bRet)
{
svgElement.setAttribute(aSVGHref, sDstContentFolder+"/"+sDstFileName);
// NOT by standard! Enable it later!
// validator http://validator.imsglobal.org/iwb/index.jsp?validate=package
//svgElement.setAttribute(aSVGRequiredExtension, svgRequiredExtensionPrefix+fePng);
}
}
}else
{
addLastExportError(QObject::tr("Element ID = ") + QString("%1 \r\n").arg(ubzElement.attribute(aUBZUuid))
+ QString("Source file = ") + QString("%1 \r\n").arg(ubzElement.attribute(aUBZSource))
+ QObject::tr("Content is not supported in destination format."));
bRet = false;
}
if (!bRet)
{
qDebug() << "format is not supported by CFF";
}
return bRet;
}
void UBCFFAdaptor::UBToCFFConverter::setCFFTextFromHTMLTextNode(const QDomElement htmlTextNode, QDomElement &iwbElement)
{
QDomDocument textDoc;
QDomElement textParentElement = iwbElement;
QString textString;
QDomNode htmlPNode = htmlTextNode.firstChild();
bool bTbreak = false;
// reads HTML text strings - each string placed in separate <p> section
while(!htmlPNode.isNull())
{
// add <tbreak> for split strings
if (bTbreak)
{
bTbreak = false;
QDomElement tbreakNode = textDoc.createElementNS(svgIWBNS, svgIWBNSPrefix+":"+tIWBTbreak);
textParentElement.appendChild(tbreakNode.cloneNode(true));
}
QDomNode spanNode = htmlPNode.firstChild();
while (!spanNode.isNull())
{
if (spanNode.isText())
{
QDomText nodeText = textDoc.createTextNode(spanNode.nodeValue());
textParentElement.appendChild(nodeText.cloneNode(true));
}
else
if (spanNode.isElement())
{
QDomElement pElementIwb;
QDomElement spanElement = textDoc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + tIWBTspan);
setCommonAttributesFromUBZ(htmlPNode.toElement(), pElementIwb, spanElement);
if (spanNode.hasAttributes())
{
int attrCount = spanNode.attributes().count();
if (0 < attrCount)
{
for (int i = 0; i < attrCount; i++)
{
// html attributes like: style="font-size:40pt; color:"red";".
QStringList cffAttributes = spanNode.attributes().item(i).nodeValue().split(";", QString::SkipEmptyParts);
{
for (int i = 0; i < cffAttributes.count(); i++)
{
QString attr = cffAttributes.at(i).trimmed();
QStringList AttrVal = attr.split(":", QString::SkipEmptyParts);
if(1 < AttrVal.count())
{
QString sAttr = ubzAttrNameToCFFAttrName(AttrVal.at(0));
if (itIsSVGElementAttribute(spanElement.tagName(), sAttr))
spanElement.setAttribute(sAttr, ubzAttrValueToCFFAttrName(AttrVal.at(1)));
}
}
}
}
}
}
QDomText nodeText = textDoc.createTextNode(spanNode.firstChild().nodeValue());
spanElement.appendChild(nodeText);
textParentElement.appendChild(spanElement.cloneNode(true));
}
spanNode = spanNode.nextSibling();
}
bTbreak = true;
htmlPNode = htmlPNode.nextSibling();
}
}
QString UBCFFAdaptor::UBToCFFConverter::ubzAttrNameToCFFAttrName(QString cffAttrName)
{
QString sRet = cffAttrName;
if (QString("color") == cffAttrName)
sRet = QString("fill");
if (QString("align") == cffAttrName)
sRet = QString("text-align");
return sRet;
}
QString UBCFFAdaptor::UBToCFFConverter::ubzAttrValueToCFFAttrName(QString cffValue)
{
QString sRet = cffValue;
if (QString("text") == cffValue)
sRet = QString("normal");
return sRet;
}
bool UBCFFAdaptor::UBToCFFConverter::setCFFAttribute(const QString &attributeName, const QString &attributeValue, const QDomElement &ubzElement, QDomElement &iwbElement, QDomElement &svgElement)
{
bool bRet = true;
bool bNeedsIWBSection = false;
if (itIsIWBAttribute(attributeName))
{
if (!((aBackground == attributeName) && (avFalse == attributeValue)))
{
iwbElement.setAttribute(attributeName, attributeValue);
bNeedsIWBSection = true;
}
}
else
if (itIsUBZAttributeToConvert(attributeName))
{
if (aTransform == attributeName)
{
setGeometryFromUBZ(ubzElement, svgElement);
}
else
if (attributeName.contains(aUBZUuid))
{
QString parentId = ubzElement.attribute(aUBZParent);
QString id;
if (!parentId.isEmpty())
id = "{" + parentId + "}" + "{" + ubzElement.attribute(aUBZUuid)+"}";
else
id = "{" + ubzElement.attribute(aUBZUuid)+"}";
svgElement.setAttribute(aID, id);
}
else
if (attributeName.contains(aUBZHref)||attributeName.contains(aSrc))
{
bRet &= setContentFromUBZ(ubzElement, svgElement);
bNeedsIWBSection = bRet||bNeedsIWBSection;
}
}
else
if (itIsSVGElementAttribute(svgElement.tagName(),attributeName))
{
svgElement.setAttribute(attributeName, attributeValue);
}
if (bNeedsIWBSection)
{
if (0 < iwbElement.attributes().count())
{
QStringList tl = ubzElement.attribute(aSVGHref).split("/");
QString id = tl.at(tl.count()-1);
// if element already have an ID, we use it. Else we create new id for element.
if (QString() == id)
id = QUuid::createUuid().toString();
svgElement.setAttribute(aID, id);
iwbElement.setAttribute(aRef, id);
}
}
return bRet;
}
bool UBCFFAdaptor::UBToCFFConverter::setCommonAttributesFromUBZ(const QDomElement &ubzElement, QDomElement &iwbElement, QDomElement &svgElement)
{
bool bRet = true;
for (int i = 0; i < ubzElement.attributes().count(); i++)
{
QDomNode attribute = ubzElement.attributes().item(i);
QString attributeName = ubzAttrNameToCFFAttrName(attribute.nodeName().remove("ub:"));
bRet &= setCFFAttribute(attributeName, ubzAttrValueToCFFAttrName(attribute.nodeValue()), ubzElement, iwbElement, svgElement);
if (!bRet) break;
}
return bRet;
}
void UBCFFAdaptor::UBToCFFConverter::setViewBox(QRect viewbox)
{
mViewbox |= viewbox;
}
QDomNode UBCFFAdaptor::UBToCFFConverter::findTextNode(const QDomNode &node)
{
QDomNode iterNode = node;
while (!iterNode.isNull())
{
if (iterNode.isText())
{
if (!iterNode.isNull())
return iterNode;
}
else
{
if (!iterNode.firstChild().isNull())
{
QDomNode foundNode = findTextNode(iterNode.firstChild());
if (!foundNode.isNull())
if (foundNode.isText())
return foundNode;
}
}
if (!iterNode.nextSibling().isNull())
iterNode = iterNode.nextSibling();
else
break;
}
return iterNode;
}
QDomNode UBCFFAdaptor::UBToCFFConverter::findNodeByTagName(const QDomNode &node, QString tagName)
{
QDomNode iterNode = node;
while (!iterNode.isNull())
{
QString t = iterNode.toElement().tagName();
if (tagName == t)
return iterNode;
else
{
if (!iterNode.firstChildElement().isNull())
{
QDomNode foundNode = findNodeByTagName(iterNode.firstChildElement(), tagName);
if (!foundNode.isNull()){
if (foundNode.isElement())
{
if (tagName == foundNode.toElement().tagName())
return foundNode;
}
else
break;
}
}
}
if (!iterNode.nextSibling().isNull())
iterNode = iterNode.nextSibling();
else
break;
}
return QDomNode();
}
bool UBCFFAdaptor::UBToCFFConverter::createBackground(const QDomElement &element, QMultiMap<int, QDomElement> &dstSvgList)
{
qDebug() << "|creating element background";
QDomDocument doc;
//QDomElement svgBackgroundElementPart = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + tUBZImage);
QDomElement svgBackgroundElementPart = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + tIWBRect);
QDomElement iwbBackgroundElementPart = doc.createElementNS(iwbNS,iwbNsPrefix + ":" + tElement);
QRect bckRect(mViewbox);
if (0 <= mViewbox.topLeft().x())
bckRect.topLeft().setX(0);
if (0 <= mViewbox.topLeft().y())
bckRect.topLeft().setY(0);
if (QRect() != bckRect)
{
QString sElementID = QUuid::createUuid().toString();
bool darkBackground = (avTrue == element.attribute(aDarkBackground));
svgBackgroundElementPart.setAttribute(aFill, darkBackground ? "black" : "white");
svgBackgroundElementPart.setAttribute(aID, sElementID);
svgBackgroundElementPart.setAttribute(aX, bckRect.x());
svgBackgroundElementPart.setAttribute(aY, bckRect.y());
svgBackgroundElementPart.setAttribute(aHeight, bckRect.height());
svgBackgroundElementPart.setAttribute(aWidth, bckRect.width());
//svgBackgroundElementPart.setAttribute(aSVGHref, backgroundImagePath);
iwbBackgroundElementPart.setAttribute(aRef, sElementID);
iwbBackgroundElementPart.setAttribute(aBackground, avTrue);
//iwbBackgroundElementPart.setAttribute(aLocked, avTrue);
addSVGElementToResultModel(svgBackgroundElementPart, dstSvgList, DEFAULT_BACKGROUND_LAYER);
addIWBElementToResultModel(iwbBackgroundElementPart);
return true;
}
else
{
qDebug() << "|error at creating element background";
errorStr = "CreatingElementBackgroundParsingError.";
return false;
}
}
QString UBCFFAdaptor::UBToCFFConverter::createBackgroundImage(const QDomElement &element, QSize size)
{
QString sRet;
QString sDstFileName(fIWBBackground);
bool bDirExists = true;
QDir dstDocFolder(destinationPath);
if (!dstDocFolder.exists(cfImages))
bDirExists &= dstDocFolder.mkdir(cfImages);
QString dstFilePath;
if (bDirExists)
dstFilePath = destinationPath+"/"+cfImages+"/"+sDstFileName;
if (!QFile().exists(dstFilePath))
{
QRect rect(0,0, size.width(), size.height());
QImage *bckImage = new QImage(size, QImage::Format_RGB888);
QPainter *painter = new QPainter(bckImage);
bool darkBackground = (avTrue == element.attribute(aDarkBackground));
QColor bCrossColor;
bCrossColor = darkBackground?QColor(Qt::white):QColor(Qt::blue);
int penAlpha = (int)(255/2); // default Sankore value for transform.m11 < 1
bCrossColor.setAlpha(penAlpha);
painter->setPen(bCrossColor);
painter->setBrush(darkBackground?QColor(Qt::black):QColor(Qt::white));
painter->drawRect(rect);
if (avTrue == element.attribute(aCrossedBackground))
{
qreal firstY = ((int) (rect.y () / iCrossSize)) * iCrossSize;
for (qreal yPos = firstY; yPos <= rect.y () + rect.height (); yPos += iCrossSize)
{
painter->drawLine (rect.x (), yPos, rect.x () + rect.width (), yPos);
}
qreal firstX = ((int) (rect.x () / iCrossSize)) * iCrossSize;
for (qreal xPos = firstX; xPos <= rect.x () + rect.width (); xPos += iCrossSize)
{
painter->drawLine (xPos, rect.y (), xPos, rect.y () + rect.height ());
}
}
painter->end();
painter->save();
if (QString() != dstFilePath)
if (bckImage->save(dstFilePath))
sRet = cfImages+"/"+sDstFileName;
delete bckImage;
delete painter;
}
else
sRet = cfImages+"/"+sDstFileName;
return sRet;
}
bool UBCFFAdaptor::UBToCFFConverter::createPngFromSvg(QString &svgPath, QString &dstPath, QTransform transformation, QSize size)
{
if (QFile().exists(svgPath))
{
QImage i(svgPath);
QSize iSize = (QSize() == size)?QSize(i.size().width()*transformation.m11(), i.size().height()*transformation.m22()):size;
QImage image(iSize, QImage::Format_ARGB32_Premultiplied);
image.fill(0);
QPainter imagePainter(&image);
QSvgRenderer renderer(svgPath);
renderer.render(&imagePainter);
return image.save(dstPath);
}
else
return false;
}
bool UBCFFAdaptor::UBToCFFConverter::parseSVGGGroup(const QDomElement &element, QMultiMap<int, QDomElement> &dstSvgList)
{
qDebug() << "|parsing g section";
QDomElement nextElement = element.firstChildElement();
if (nextElement.isNull()) {
qDebug() << "Empty g element";
errorStr = "EmptyGSection";
return false;
}
QMultiMap<int, QDomElement> svgElements;
QDomDocument doc;
QDomElement svgElementPart = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + tIWBG);
QDomElement iwbElementPart = doc.createElementNS(iwbNS,iwbNsPrefix + ":" + tElement);
// Elements can know about its layer, so it must add result QDomElements to ordrered list.
while (!nextElement.isNull()) {
QString tagName = nextElement.tagName();
if (tagName == tUBZLine) parseUBZLine(nextElement, svgElements);
else if (tagName == tUBZPolygon) parseUBZPolygon(nextElement, svgElements);
else if (tagName == tUBZPolyline) parseUBZPolyline(nextElement, svgElements);
nextElement = nextElement.nextSiblingElement();
}
QList<int> layers;
QMapIterator<int, QDomElement> nextSVGElement(svgElements);
while (nextSVGElement.hasNext())
layers << nextSVGElement.next().key();
qSort(layers);
int layer = layers.at(0);
nextSVGElement.toFront();
while (nextSVGElement.hasNext())
svgElementPart.appendChild(nextSVGElement.next().value());
addSVGElementToResultModel(svgElementPart, dstSvgList, layer);
return true;
}
bool UBCFFAdaptor::UBToCFFConverter::parseUBZImage(const QDomElement &element, QMultiMap<int, QDomElement> &dstSvgList)
{
qDebug() << "|parsing image";
QDomDocument doc;
QDomElement svgElementPart = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + getElementTypeFromUBZ(element));
QDomElement iwbElementPart = doc.createElementNS(iwbNS,iwbNsPrefix + ":" + tElement);
if (setCommonAttributesFromUBZ(element, iwbElementPart, svgElementPart))
{
addSVGElementToResultModel(svgElementPart, dstSvgList, getElementLayer(element));
if (0 < iwbElementPart.attributes().count())
addIWBElementToResultModel(iwbElementPart);
return true;
}
else
{
qDebug() << "|error at image parsing";
errorStr = "ImageParsingError";
return false;
}
}
bool UBCFFAdaptor::UBToCFFConverter::parseUBZVideo(const QDomElement &element, QMultiMap<int, QDomElement> &dstSvgList)
{
qDebug() << "|parsing video";
QDomDocument doc;
QDomElement svgElementPart = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + getElementTypeFromUBZ(element));
QDomElement iwbElementPart = doc.createElementNS(iwbNS,iwbNsPrefix + ":" + tElement);
if (setCommonAttributesFromUBZ(element, iwbElementPart, svgElementPart))
{
QDomElement svgSwitchSection = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + tIWBSwitch);
svgSwitchSection.appendChild(svgElementPart);
// if viewer cannot open that content - it must use that:
QDomElement svgText = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + tIWBTextArea);
svgText.setAttribute(aX, svgElementPart.attribute(aX));
svgText.setAttribute(aY, svgElementPart.attribute(aY));
svgText.setAttribute(aWidth, svgElementPart.attribute(aWidth));
svgText.setAttribute(aHeight, svgElementPart.attribute(aHeight));
svgText.setAttribute(aTransform, svgElementPart.attribute(aTransform));
QDomText text = doc.createTextNode("Cannot Open Content");
svgText.appendChild(text);
svgSwitchSection.appendChild(svgText);
addSVGElementToResultModel(svgSwitchSection, dstSvgList, getElementLayer(element));
if (0 < iwbElementPart.attributes().count())
addIWBElementToResultModel(iwbElementPart);
return true;
}
else
{
qDebug() << "|error at video parsing";
errorStr = "VideoParsingError";
return false;
}
}
bool UBCFFAdaptor::UBToCFFConverter::parseUBZAudio(const QDomElement &element, QMultiMap<int, QDomElement> &dstSvgList)
{
qDebug() << "|parsing audio";
// audio file must be linked to cff item excluding video.
// to do:
// 1 add image for audio element.
// 2 set id for this element
// 3 add <svg:a> section with xlink:href to audio file
// 4 add shild to a section with id of the image
QDomDocument doc;
QDomElement svgElementPart = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + getElementTypeFromUBZ(element));
QDomElement iwbElementPart = doc.createElementNS(iwbNS,iwbNsPrefix + ":" + tElement);
if (setCommonAttributesFromUBZ(element, iwbElementPart, svgElementPart))
{
//we must create image-containers for audio files
int audioImageDimention = qMin(svgElementPart.attribute(aWidth).toInt(), svgElementPart.attribute(aHeight).toInt());
QString srcAudioImageFile(sAudioElementImage);
QString elementId = QString(QUuid::createUuid().toString());
QString sDstAudioImageFileName = elementId+"."+fePng;
QString dstAudioImageFilePath = destinationPath+"/"+cfImages+"/"+sDstAudioImageFileName;
QString dstAudioImageRelativePath = cfImages+"/"+sDstAudioImageFileName;
QFile srcFile(srcAudioImageFile);
//creating folder for audioImage
QDir dstDocFolder(destinationPath);
bool bRes = true;
if (!dstDocFolder.exists(cfImages))
bRes &= dstDocFolder.mkdir(cfImages);
// CFF cannot show SVG images, so we need to convert it to png.
if (bRes && createPngFromSvg(srcAudioImageFile, dstAudioImageFilePath, getTransformFromUBZ(element), QSize(audioImageDimention, audioImageDimention)))
{
// switch section disabled because of imcompatibility with validator http://validator.imsglobal.org/iwb/index.jsp?validate=package
// QDomElement svgSwitchSection = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + tIWBSwitch);
// first we place content
QDomElement svgASection = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + tIWBA);
svgASection.setAttribute(aSVGHref, svgElementPart.attribute(aSVGHref));
svgElementPart.setTagName(tIWBImage);
svgElementPart.setAttribute(aSVGHref, dstAudioImageRelativePath);
svgElementPart.setAttribute(aHeight, audioImageDimention);
svgElementPart.setAttribute(aWidth, audioImageDimention);
svgASection.appendChild(svgElementPart);
// switch section disabled because of imcompatibility with validator http://validator.imsglobal.org/iwb/index.jsp?validate=package
// svgSwitchSection.appendChild(svgASection);
// if viewer cannot open that content - it must use that:
QDomElement svgText = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + tIWBTextArea);
svgText.setAttribute(aX, svgElementPart.attribute(aX));
svgText.setAttribute(aY, svgElementPart.attribute(aY));
svgText.setAttribute(aWidth, svgElementPart.attribute(aWidth));
svgText.setAttribute(aHeight, svgElementPart.attribute(aHeight));
svgText.setAttribute(aTransform, svgElementPart.attribute(aTransform));
QDomText text = doc.createTextNode("Cannot Open Content");
svgText.appendChild(text);
// switch section disabled because of imcompatibility with validator http://validator.imsglobal.org/iwb/index.jsp?validate=package
// svgSwitchSection.appendChild(svgText);
// switch section disabled because of imcompatibility with validator http://validator.imsglobal.org/iwb/index.jsp?validate=package
addSVGElementToResultModel(svgASection/*svgSwitchSection*/, dstSvgList, getElementLayer(element));
if (0 < iwbElementPart.attributes().count())
addIWBElementToResultModel(iwbElementPart);
return true;
}
return false;
}
else
{
qDebug() << "|error at audio parsing";
errorStr = "AudioParsingError";
return false;
}
}
bool UBCFFAdaptor::UBToCFFConverter::parseForeignObject(const QDomElement &element, QMultiMap<int, QDomElement> &dstSvgList)
{
if (element.attribute(aUBZType) == avUBZText) {
return parseUBZText(element, dstSvgList);
}
qDebug() << "|parsing foreign object";
QDomDocument doc;
QDomElement svgElementPart = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + getElementTypeFromUBZ(element));
QDomElement iwbElementPart = doc.createElementNS(iwbNS,iwbNsPrefix + ":" + tElement);
if (setCommonAttributesFromUBZ(element, iwbElementPart, svgElementPart))
{
addSVGElementToResultModel(svgElementPart, dstSvgList, getElementLayer(element));
if (0 < iwbElementPart.attributes().count())
addIWBElementToResultModel(iwbElementPart);
return true;
}
else
{
qDebug() << "|error at parsing foreign object";
errorStr = "ForeignObjectParsingError";
return false;
}
}
bool UBCFFAdaptor::UBToCFFConverter::parseUBZText(const QDomElement &element, QMultiMap<int, QDomElement> &dstSvgList)
{
qDebug() << "|parsing text";
QDomDocument doc;
QDomElement svgElementPart = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + getElementTypeFromUBZ(element));
QDomElement iwbElementPart = doc.createElementNS(iwbNS,iwbNsPrefix + ":" + tElement);
if (element.hasChildNodes())
{
QDomDocument htmlDoc;
htmlDoc.setContent(findTextNode(element).nodeValue());
QDomNode bodyNode = findNodeByTagName(htmlDoc.firstChildElement(), "body");
setCFFTextFromHTMLTextNode(bodyNode.toElement(), svgElementPart);
if (setCommonAttributesFromUBZ(element, iwbElementPart, svgElementPart))
{
QString commonParams;
for (int i = 0; i < bodyNode.attributes().count(); i++)
{
commonParams += " " + bodyNode.attributes().item(i).nodeValue();
}
commonParams.remove(" ");
commonParams.remove("'");
QStringList commonAttributes = commonParams.split(";", QString::SkipEmptyParts);
for (int i = 0; i < commonAttributes.count(); i++)
{
QStringList AttrVal = commonAttributes.at(i).split(":", QString::SkipEmptyParts);
if (1 < AttrVal.count())
{
QString sAttr = ubzAttrNameToCFFAttrName(AttrVal.at(0));
QString sVal = ubzAttrValueToCFFAttrName(AttrVal.at(1));
setCFFAttribute(sAttr, sVal, element, iwbElementPart, svgElementPart);
}
}
addSVGElementToResultModel(svgElementPart, dstSvgList, getElementLayer(element));
if (0 < iwbElementPart.attributes().count())
addIWBElementToResultModel(iwbElementPart);
return true;
}
return false;
}
else
{
qDebug() << "|error at text parsing";
errorStr = "TextParsingError";
return false;
}
}
bool UBCFFAdaptor::UBToCFFConverter::parseUBZPolygon(const QDomElement &element, QMultiMap<int, QDomElement> &dstSvgList)
{
qDebug() << "||parsing polygon";
QDomDocument doc;
QDomElement svgElementPart = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + getElementTypeFromUBZ(element));
QDomElement iwbElementPart = doc.createElementNS(iwbNS,iwbNsPrefix + ":" + tElement);
if (setCommonAttributesFromUBZ(element, iwbElementPart, svgElementPart))
{
svgElementPart.setAttribute(aStroke, svgElementPart.attribute(aFill));
addSVGElementToResultModel(svgElementPart, dstSvgList, getElementLayer(element));
if (0 < iwbElementPart.attributes().count())
{
QString id = svgElementPart.attribute(aUBZUuid);
if (id.isEmpty())
id = QUuid::createUuid().toString();
svgElementPart.setAttribute(aID, id);
iwbElementPart.setAttribute(aRef, id);
addIWBElementToResultModel(iwbElementPart);
}
return true;
}
else
{
qDebug() << "||error at parsing polygon";
errorStr = "PolygonParsingError";
return false;
}
}
bool UBCFFAdaptor::UBToCFFConverter::parseUBZPolyline(const QDomElement &element, QMultiMap<int, QDomElement> &dstSvgList)
{
qDebug() << "||parsing polyline";
QDomElement resElement;
QDomDocument doc;
QDomElement svgElementPart = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + getElementTypeFromUBZ(element));
QDomElement iwbElementPart = doc.createElementNS(iwbNS,iwbNsPrefix + ":" + tElement);
if (setCommonAttributesFromUBZ(element, iwbElementPart, svgElementPart))
{
svgElementPart.setAttribute(aStroke, svgElementPart.attribute(aFill));
addSVGElementToResultModel(svgElementPart, dstSvgList, getElementLayer(element));
if (0 < iwbElementPart.attributes().count())
{
QString id = QUuid::createUuid().toString();
svgElementPart.setAttribute(aID, id);
iwbElementPart.setAttribute(aRef, id);
addIWBElementToResultModel(iwbElementPart);
}
return true;
}
else
{
qDebug() << "||error at parsing polygon";
errorStr = "PolylineParsingError";
return false;
}
}
bool UBCFFAdaptor::UBToCFFConverter::parseUBZLine(const QDomElement &element, QMultiMap<int, QDomElement> &dstSvgList)
{
qDebug() << "||parsing line";
QDomElement resElement;
QDomDocument doc;
QDomElement svgElementPart = doc.createElementNS(svgIWBNS,svgIWBNSPrefix + ":" + getElementTypeFromUBZ(element));
QDomElement iwbElementPart = doc.createElementNS(iwbNS,iwbNsPrefix + ":" + tElement);
if (setCommonAttributesFromUBZ(element, iwbElementPart, svgElementPart))
{
svgElementPart.setAttribute(aStroke, svgElementPart.attribute(aFill));
addSVGElementToResultModel(svgElementPart, dstSvgList, getElementLayer(element));
if (0 < iwbElementPart.attributes().count())
{
QString id = QUuid::createUuid().toString();
svgElementPart.setAttribute(aID, id);
iwbElementPart.setAttribute(aRef, id);
addIWBElementToResultModel(iwbElementPart);
}
}
else
{
qDebug() << "||error at parsing polygon";
errorStr = "LineParsingError";
return false;
}
return true;
}
void UBCFFAdaptor::UBToCFFConverter::addSVGElementToResultModel(const QDomElement &element, QMultiMap<int, QDomElement> &dstList, int layer)
{
int elementLayer = (DEFAULT_LAYER == layer) ? DEFAULT_LAYER : layer;
QDomElement rootElement = element.cloneNode(true).toElement();
mDocumentToWrite->firstChildElement().appendChild(rootElement);
dstList.insert(elementLayer, rootElement);
}
void UBCFFAdaptor::UBToCFFConverter::addIWBElementToResultModel(const QDomElement &element)
{
QDomElement rootElement = element.cloneNode(true).toElement();
mDocumentToWrite->firstChildElement().appendChild(rootElement);
mExtendedElements.append(rootElement);
}
UBCFFAdaptor::UBToCFFConverter::~UBToCFFConverter()
{
if (mDataModel)
delete mDataModel;
if (mIWBContentWriter)
delete mIWBContentWriter;
if (mDocumentToWrite)
delete mDocumentToWrite;
}
bool UBCFFAdaptor::UBToCFFConverter::isValid() const
{
bool result = QFileInfo(sourcePath).exists()
&& QFileInfo(sourcePath).isDir()
&& errorStr == noErrorMsg;
if (!result) {
qDebug() << "specified data is not valid";
errorStr = "ValidateDataError";
}
return result;
}
void UBCFFAdaptor::UBToCFFConverter::fillNamespaces()
{
mIWBContentWriter->writeDefaultNamespace(svgUBZNS);
mIWBContentWriter->writeNamespace(iwbNS, iwbNsPrefix);
mIWBContentWriter->writeNamespace(svgIWBNS, svgIWBNSPrefix);
mIWBContentWriter->writeNamespace(xlinkNS, xlinkNSPrefix);
}
QString UBCFFAdaptor::UBToCFFConverter::digitFileFormat(int digit) const
{
return QString("%1").arg(digit, 3, 10, QLatin1Char('0'));
}
QString UBCFFAdaptor::UBToCFFConverter::contentIWBFileName() const
{
return destinationPath + "/" + fIWBContent;
}
//setting SVG dimenitons
QSize UBCFFAdaptor::UBToCFFConverter::getSVGDimentions(const QString &element)
{
QStringList dimList;
dimList = element.split(dimensionsDelimiter1, QString::KeepEmptyParts);
if (dimList.count() != 2) // row unlike 0x0
return QSize();
bool ok;
int width = dimList.takeFirst().toInt(&ok);
if (!ok || !width)
return QSize();
int height = dimList.takeFirst().toInt(&ok);
if (!ok || !height)
return QSize();
return QSize(width, height);
}
//Setting viewbox rectangle
QRect UBCFFAdaptor::UBToCFFConverter::getViewboxRect(const QString &element) const
{
QStringList dimList;
dimList = element.split(dimensionsDelimiter2, QString::KeepEmptyParts);
if (dimList.count() != 4) // row unlike 0 0 0 0
return QRect();
bool ok = false;
int x = dimList.takeFirst().toInt(&ok);
if (!ok || !x)
return QRect();
int y = dimList.takeFirst().toInt(&ok);
if (!ok || !y)
return QRect();
int width = dimList.takeFirst().toInt(&ok);
if (!ok || !width)
return QRect();
int height = dimList.takeFirst().toInt(&ok);
if (!ok || !height)
return QRect();
return QRect(x, y, width, height);
}
QString UBCFFAdaptor::UBToCFFConverter::rectToIWBAttr(const QRect &rect) const
{
if (rect.isNull()) return QString();
return QString("%1 %2 %3 %4").arg(rect.topLeft().x())
.arg(rect.topLeft().y())
.arg(rect.width())
.arg(rect.height());
}
UBCFFAdaptor::UBToUBZConverter::UBToUBZConverter()
{
}