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 section
+ while(!htmlPNode.isNull())
+ {
+ // add 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 &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 &dstSvgList)
+{
+ qDebug() << "|parsing g section";
+ QDomElement nextElement = element.firstChildElement();
+ if (nextElement.isNull()) {
+ qDebug() << "Empty g element";
+ errorStr = "EmptyGSection";
+ return false;
+ }
+
+ QMultiMap 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 layers;
+ QMapIterator 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 &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 &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 &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 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 &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 &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 &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 &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 &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 &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()
+{
+
+}
diff --git a/plugins/cffadaptor/src/UBCFFAdaptor.h b/plugins/cffadaptor/src/UBCFFAdaptor.h
new file mode 100644
index 00000000..99f57396
--- /dev/null
+++ b/plugins/cffadaptor/src/UBCFFAdaptor.h
@@ -0,0 +1,175 @@
+/*
+ * 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 .
+ */
+
+
+#ifndef UBCFFADAPTOR_H
+#define UBCFFADAPTOR_H
+
+#include "UBCFFAdaptor_global.h"
+
+#include
+
+class QTransform;
+class QDomDocument;
+class QDomElement;
+class QDomNode;
+class QuaZipFile;
+
+class UBCFFADAPTORSHARED_EXPORT UBCFFAdaptor {
+ class UBToCFFConverter;
+
+public:
+ UBCFFAdaptor();
+ ~UBCFFAdaptor();
+
+ bool convertUBZToIWB(const QString &from, const QString &to);
+ bool deleteDir(const QString& pDirPath) const;
+ QList getConversionMessages();
+
+private:
+ QString uncompressZip(const QString &zipFile);
+ bool compressZip(const QString &source, const QString &destination);
+ bool compressDir(const QString &dirName, const QString &parentDir, QuaZipFile *outZip);
+ bool compressFile(const QString &fileName, const QString &parentDir, QuaZipFile *outZip);
+
+ QString createNewTmpDir();
+ bool freeDir(const QString &dir);
+ void freeTmpDirs();
+
+private:
+ QStringList tmpDirs;
+ QList mConversionMessages;
+
+private:
+
+ class UBToCFFConverter {
+
+ static const int DEFAULT_LAYER = -100000;
+
+ public:
+ UBToCFFConverter(const QString &source, const QString &destination);
+ ~UBToCFFConverter();
+ bool isValid() const;
+ QString lastErrStr() const {return errorStr;}
+ bool parse();
+ QList getMessages() {return mExportErrorList;}
+
+ private:
+
+ void addLastExportError(QString error) {mExportErrorList.append(error);}
+
+ void fillNamespaces();
+
+ bool parseMetadata();
+ bool parseContent();
+ QDomElement parsePageset(const QStringList &pageFileNames);
+ QDomElement parsePage(const QString &pageFileName);
+ QDomElement parseSvgPageSection(const QDomElement &element);
+ void writeQDomElementToXML(const QDomNode &node);
+ bool writeExtendedIwbSection();
+ QDomElement parseGroupsPageSection(const QDomElement &groupRoot);
+
+ bool createBackground(const QDomElement &element, QMultiMap &dstSvgList);
+ QString createBackgroundImage(const QDomElement &element, QSize size);
+ bool createPngFromSvg(QString &svgPath, QString &dstPath, QTransform transformation, QSize size = QSize());
+
+ bool parseSVGGGroup(const QDomElement &element, QMultiMap &dstSvgList);
+ bool parseUBZImage(const QDomElement &element, QMultiMap &dstSvgList);
+ bool parseUBZVideo(const QDomElement &element, QMultiMap &dstSvgList);
+ bool parseUBZAudio(const QDomElement &element, QMultiMap &dstSvgList);
+ bool parseForeignObject(const QDomElement &element, QMultiMap &dstSvgList);
+ bool parseUBZText(const QDomElement &element, QMultiMap &dstSvgList);
+
+ bool parseUBZPolygon(const QDomElement &element, QMultiMap &dstSvgList);
+ bool parseUBZPolyline(const QDomElement &element, QMultiMap &dstSvgList);
+ bool parseUBZLine(const QDomElement &element, QMultiMap &dstSvgList);
+ void addSVGElementToResultModel(const QDomElement &element, QMultiMap &dstList, int layer = DEFAULT_LAYER);
+ void addIWBElementToResultModel(const QDomElement &element);
+
+ qreal getAngleFromTransform(const QTransform &tr);
+ QString getDstContentFolderName(const QString &elementType);
+ QString getSrcContentFolderName(QString href);
+ QString getFileNameFromPath(QString sPath);
+ QString getExtentionFromFileName(const QString &filename);
+ QString convertExtention(const QString &ext);
+ QString getElementTypeFromUBZ(const QDomElement &element);
+
+ int getElementLayer(const QDomElement &element);
+
+ bool itIsSupportedFormat(const QString &format) const;
+ bool itIsFormatToConvert(const QString &format) const;
+ bool itIsSVGElementAttribute(const QString ItemType, const QString &AttrName);
+ bool itIsIWBAttribute(const QString &attribute) const;
+ bool itIsUBZAttributeToConvert(const QString &attribute) const;
+
+ bool ibwAddLine(int x1, int y1, int x2, int y2, QString color=QString(), int width=1, bool isBackground=false);
+
+ QTransform getTransformFromUBZ(const QDomElement &ubzElement);
+ void setGeometryFromUBZ(const QDomElement &ubzElement, QDomElement &iwbElement);
+ void setCoordinatesFromUBZ(const QDomElement &ubzElement, QDomElement &iwbElement);
+ bool setContentFromUBZ(const QDomElement &ubzElement, QDomElement &svgElement);
+ void setCFFTextFromUBZ(const QDomElement &ubzElement, QDomElement &iwbElement, QDomElement &svgElement);
+ void setCFFTextFromHTMLTextNode(const QDomElement htmlTextNode, QDomElement &iwbElement);
+ QString ubzAttrNameToCFFAttrName(QString cffAttrName);
+ QString ubzAttrValueToCFFAttrName(QString cffAttrValue);
+
+ bool setCFFAttribute(const QString &attributeName, const QString &attributeValue, const QDomElement &ubzElement, QDomElement &iwbElement, QDomElement &svgElement);
+ bool setCommonAttributesFromUBZ(const QDomElement &ubzElement, QDomElement &iwbElement, QDomElement &svgElement);
+ void setViewBox(QRect viewbox);
+
+ QDomNode findTextNode(const QDomNode &node);
+ QDomNode findNodeByTagName(const QDomNode &node, QString tagName);
+
+ QSize getSVGDimentions(const QString &element);
+
+ inline QRect getViewboxRect(const QString &element) const;
+ inline QString rectToIWBAttr(const QRect &rect) const;
+ inline QString digitFileFormat(int num) const;
+ inline bool strToBool(const QString &in) const {return in == "true";}
+ QString contentIWBFileName() const;
+
+ private:
+ QList mExportErrorList;
+ QMap iwbSVGItemsAttributes;
+ QDomDocument *mDataModel; //model for reading indata
+ QXmlStreamWriter *mIWBContentWriter; //stream to write outdata
+ QSize mSVGSize; //svg page size
+ QRect mViewbox; //Main viewbox parameter for CFF
+ QString sourcePath; // dir with unpacked source data (ubz)
+ QString destinationPath; //dir with unpacked destination data (iwb)
+ QDomDocument *mDocumentToWrite; //document for saved QDomElements from mSvgElements and mExtendedElements
+ QMultiMap mSvgElements; //Saving svg elements to have a sorted by z order list of elements to write;
+ QList mExtendedElements; //Saving extended options of elements to be able to add them to the end of result iwb document;
+ mutable QString errorStr; // last error string message
+
+ public:
+ operator bool() const {return isValid();}
+ };
+
+ class UBToUBZConverter {
+ public:
+ UBToUBZConverter();
+ };
+
+
+};
+
+#endif // UBCFFADAPTOR_H
diff --git a/plugins/cffadaptor/src/UBCFFAdaptor_global.h b/plugins/cffadaptor/src/UBCFFAdaptor_global.h
new file mode 100644
index 00000000..3f060b96
--- /dev/null
+++ b/plugins/cffadaptor/src/UBCFFAdaptor_global.h
@@ -0,0 +1,34 @@
+/*
+ * 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 .
+ */
+
+
+#ifndef UBCFFADAPTOR_GLOBAL_H
+#define UBCFFADAPTOR_GLOBAL_H
+
+#include
+
+#if defined(UBCFFADAPTOR_LIBRARY)
+# define UBCFFADAPTORSHARED_EXPORT Q_DECL_EXPORT
+#else
+# define UBCFFADAPTORSHARED_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // UBCFFADAPTOR_GLOBAL_H
diff --git a/plugins/cffadaptor/src/UBCFFConstants.h b/plugins/cffadaptor/src/UBCFFConstants.h
new file mode 100644
index 00000000..588ea699
--- /dev/null
+++ b/plugins/cffadaptor/src/UBCFFConstants.h
@@ -0,0 +1,405 @@
+/*
+ * 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 .
+ */
+
+
+#ifndef UBCFFCONSTANTS_H
+#define UBCFFCONSTANTS_H
+
+#define PI 3.1415926535
+
+const int DEFAULT_BACKGROUND_LAYER = -20000002;
+const int DEFAULT_BACKGROUND_CROSS_LAYER = -20000001;
+
+// Constant names. Use only them instead const char* in each function
+
+// Constant fileNames;
+const QString fMetadata = "metadata.rdf";
+const QString fIWBContent = "content.xml";
+const QString fIWBBackground = "background.png";
+const QString sAudioElementImage = ":images/soundOn.svg";
+
+// Constant messages;
+const QString noErrorMsg = "NoError";
+
+// Tag names
+const QString tDescription = "Description";
+const QString tIWBRoot = "iwb";
+const QString tIWBMeta = "meta";
+const QString tUBZSize = "size";
+const QString tSvg = "svg";
+const QString tIWBPage = "page";
+const QString tIWBPageSet = "pageset";
+const QString tId = "id";
+const QString tElement = "element";
+const QString tUBZGroup = "group";
+const QString tUBZGroups = "groups";
+const QString tUBZG = "g";
+const QString tUBZPolygon = "polygon";
+const QString tUBZPolyline = "polyline";
+const QString tUBZLine = "line";
+const QString tUBZAudio = "audio";
+const QString tUBZVideo = "video";
+const QString tUBZImage = "image";
+const QString tUBZForeignObject = "foreignObject";
+const QString tUBZTextContent = "itemTextContent";
+
+const QString tIWBA = "a";
+const QString tIWBG = "g";
+const QString tIWBSwitch = "switch";
+const QString tIWBImage = "image";
+const QString tIWBVideo = "video";
+const QString tIWBAudio = "audio";
+const QString tIWBText = "text";
+const QString tIWBTextArea = "textarea";
+const QString tIWBPolyLine = "polyline";
+const QString tIWBPolygon = "polygon";
+const QString tIWBFlash = "video";
+const QString tIWBRect = "rect";
+const QString tIWBLine = "line";
+const QString tIWBTbreak = "tbreak";
+const QString tIWBTspan = "tspan";
+
+// Attributes names
+const QString aIWBVersion = "version";
+const QString aOwner = "owner";
+const QString aDescription = "description";
+const QString aCreator = "creator";
+const QString aAbout = "about";
+const QString aIWBViewBox = "viewbox";
+const QString aUBZViewBox = "viewBox";
+const QString aDarkBackground = "dark-background";
+const QString aBackground = "background";
+const QString aCrossedBackground = "crossed-background";
+const QString aUBZType = "type";
+const QString aUBZUuid = "uuid";
+const QString aUBZParent = "parent";
+const QString aFill = "fill"; // IWB attribute contans color to fill
+
+const QString aID = "id"; // ID of any svg element can be placed in to iwb section
+const QString aRef = "ref"; // as reference for applying additional attributes
+const QString aSVGHref = "xlink:href"; // reference to file
+const QString aIWBHref = "ref"; // reference to element ID
+const QString aUBZHref = "href";
+const QString aUBZSource = "source";
+const QString aSrc = "src";
+const QString aSVGRequiredExtension = "requiredExtensions";
+
+const QString aX = "x";
+const QString aY = "y";
+const QString aWidth = "width";
+const QString aHeight = "height";
+const QString aStroke = "stroke";
+const QString aStrokeWidth = "stroke-width";
+const QString aPoints = "points";
+const QString aZLayer = "z-value";
+const QString aLayer = "layer";
+const QString aTransform = "transform";
+const QString aLocked = "locked";
+const QString aIWBName = "name";
+const QString aIWBContent = "content";
+
+
+// Attribute values
+const QString avIWBVersionNo = "1.0";
+const QString avUBZText = "text";
+const QString avFalse = "false";
+const QString avTrue = "true";
+
+// Namespaces and prefixes
+const QString svgRequiredExtensionPrefix = "http://www.imsglobal.org/iwb/";
+const QString dcNS = "http://purl.org/dc/elements/1.1/";
+const QString ubNS = "http://uniboard.mnemis.com/document";
+const QString svgUBZNS = "http://www.imsglobal.org/xsd/iwb_v1p0";
+const QString svgIWBNS = "http://www.w3.org/2000/svg";
+const QString xlinkNS = "http://www.w3.org/1999/xlink";
+const QString iwbNS = "http://www.imsglobal.org/xsd/iwb_v1p0";
+const QString xsiNS = "http://www.w3.org/2001/XMLSchema-instance";
+const QString xsiShemaLocation = "\
+http://www.imsglobal.org/xsd/iwb_v1p0 \
+http://www.imsglobal.org/profile/iwb/iwbv1p0_v1p0.xsd \
+http://www.w3.org/2000/svg http://www.imsglobal.org/profile/iwb/svgsubsetv1p0_v1p0.xsd \
+http://www.w3.org/1999/xlink http://www.imsglobal.org/xsd/w3/1999/xlink.xsd";
+const QString dcNSPrefix = "dc";
+const QString ubNSPrefix = "ub";
+const QString svgIWBNSPrefix = "svg";
+const QString xlinkNSPrefix = "xlink";
+const QString iwbNsPrefix = "iwb";
+const QString xsiPrefix = "xsi";
+const QString xsiSchemaLocationPrefix = "schemaLocation";
+
+const QString avOwner = "";
+const QString avCreator = "";
+const QString avDescription = "";
+
+//constant symbols and words etc
+const QString dimensionsDelimiter1 = "x";
+const QString dimensionsDelimiter2 = " ";
+const QString pageAlias = "page";
+const QString pageFileExtentionUBZ = "svg";
+
+//content folder names
+const QString cfImages = "images";
+const QString cfVideos = "video";
+const QString cfAudios = "audio";
+const QString cfFlash = "flash";
+
+//known file extentions
+const QString feSvg = "svg";
+const QString feWgt = "wgt";
+const QString fePng = "png";
+
+const int iCrossSize = 32;
+const int iCrossWidth = 1;
+
+// Image formats supported by CFF exclude wgt. Wgt is Sankore widget, which is considered as a .png preview.
+const QString iwbElementImage(" \
+wgt, \
+jpeg, \
+jpg, \
+bmp, \
+gif, \
+wmf, \
+emf, \
+png, \
+tif, \
+tiff \
+");
+
+// Video formats supported by CFF
+const QString iwbElementVideo(" \
+mpg, \
+mpeg, \
+swf, \
+");
+
+// Audio formats supported by CFF
+const QString iwbElementAudio(" \
+mp3, \
+wav \
+");
+
+const QString cffSupportedFileFormats(iwbElementImage + iwbElementVideo + iwbElementAudio);
+const QString ubzFormatsToConvert("svg");
+
+
+const QString iwbSVGImageAttributes(" \
+id, \
+xlink:href, \
+x, \
+y, \
+height, \
+width, \
+fill-opacity, \
+requiredExtentions, \
+transform \
+");
+
+
+const QString iwbSVGAudioAttributes(" \
+id, \
+xlink:href, \
+x, \
+y, \
+height, \
+width, \
+fill-opacity, \
+requiredExtentions, \
+transform \
+");
+
+const QString iwbSVGVideoAttributes(" \
+id, \
+xlink:href, \
+x, \
+y, \
+height, \
+width, \
+fill-opacity, \
+requiredExtentions, \
+transform \
+");
+
+const QString iwbSVGRectAttributes(" \
+id, \
+x, \
+y, \
+height, \
+width, \
+fill, \
+fill-opacity, \
+stroke, \
+stroke-dasharray, \
+stroke-linecap, \
+stroke-linejoin, \
+stroke-opacity, \
+stroke-width, \
+transform \
+");
+
+
+
+const QString iwbSVGTextAttributes(" \
+id, \
+x, \
+y, \
+fill, \
+font-family, \
+font-size, \
+font-style, \
+font-weight, \
+font-stretch, \
+transform \
+");
+
+const QString iwbSVGTextAreaAttributes(" \
+id, \
+x, \
+y, \
+height, \
+width, \
+fill, \
+font-family, \
+font-size, \
+font-style, \
+font-weight, \
+font-stretch, \
+text-align, \
+transform \
+");
+
+const QString iwbSVGTspanAttributes(" \
+id, \
+fill, \
+font-family, \
+font-size, \
+font-style, \
+font-weight, \
+font-stretch, \
+text-align, \
+");
+
+const QString iwbSVGLineAttributes(" \
+id, \
+x1, \
+y1, \
+x2, \
+y2, \
+stroke, \
+stroke-dasharray, \
+stroke-width, \
+stroke-opacity, \
+stroke-linecap, \
+transform \
+");
+
+const QString iwbSVGPolyLineAttributes(" \
+id, \
+points, \
+stroke, \
+stroke-width, \
+stroke-dasharray, \
+stroke-opacity, \
+stroke-linecap, \
+transform \
+");
+
+const QString iwbSVGPolygonAttributes(" \
+id, \
+points, \
+fill, \
+fill-opacity, \
+stroke, \
+stroke-dasharray, \
+stroke-width, \
+stroke-linecap, \
+stroke-linejoin, \
+stroke-opacity, \
+stroke-width, \
+transform \
+");
+
+// 1 to 1 copy to SVG section
+const QString iwbElementAttributes(" \
+background, \
+background-fill, \
+background-posture, \
+flip, \
+freehand, \
+highlight, \
+highlight-fill, \
+list-style-type, \
+list-style-type-fill, \
+locked, \
+replicate, \
+revealer, \
+stroke-lineshape-start, \
+stroke-lineshape-end \
+");
+
+// cannot be copied 1 to 1 to SVG section
+const QString ubzElementAttributesToConvert(" \
+xlink:href, \
+src, \
+transform, \
+uuid \
+"
+);
+
+// additional attributes. Have references in SVG section.
+const QString svgElementAttributes(" \
+points, \
+fill, \
+fill-opacity, \
+stroke, \
+stroke-dasharray, \
+stroke-linecap, \
+stroke-opacity, \
+stroke-width, \
+stroke_linejoin, \
+requiredExtensions, \
+viewbox, \
+x, \
+y, \
+x1, \
+y1, \
+x2, \
+y2, \
+height, \
+width, \
+font-family, \
+font-size, \
+font-style, \
+font-weight, \
+font-stretch, \
+text-align \
+");
+
+const QString ubzContentFolders("audios,videos,images,widgets");
+
+struct UBItemLayerType
+{
+ enum Enum
+ {
+ FixedBackground = -2000, Object = -1000, Graphic = 0, Tool = 1000, Control = 2000
+ };
+};
+
+#endif // UBCFFCONSTANTS_H
diff --git a/plugins/cffadaptor/src/UBGlobals.h b/plugins/cffadaptor/src/UBGlobals.h
new file mode 100644
index 00000000..1c2864d3
--- /dev/null
+++ b/plugins/cffadaptor/src/UBGlobals.h
@@ -0,0 +1,69 @@
+/*
+ * 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 .
+ */
+
+
+#ifndef UBGLOBALS_H
+#define UBGLOBALS_H
+
+#define DELETEPTR(ptr) if(NULL != ptr){ \
+ delete ptr; \
+ ptr = NULL; \
+ }
+
+#ifdef Q_WS_WIN
+
+#define WARNINGS_DISABLE __pragma(warning(push, 0));
+#define WARNINGS_ENABLE __pragma(warning(pop));
+
+#ifdef NO_THIRD_PARTY_WARNINGS
+// disabling warning level to 0 and save old state
+#define THIRD_PARTY_WARNINGS_DISABLE WARNINGS_DISABLE
+#else
+// just save old state (needs for not empty define)
+#define THIRD_PARTY_WARNINGS_DISABLE __pragma(warning(push));
+#endif //#ifdef NO_THIRD_PARTY_WARNINGS
+// anyway on WIN
+#define THIRD_PARTY_WARNINGS_ENABLE WARNINGS_ENABLE
+
+#else //#ifdef Q_WS_WIN
+
+#define WARNINGS_DISABLE _Pragma("GCC diagnostic push"); \
+_Pragma("GCC diagnostic ignored \"-Wunused-parameter\""); \
+_Pragma("GCC diagnostic ignored \"-Wunused-variable\""); \
+_Pragma("GCC diagnostic ignored \"-Wsign-compare\"");
+
+#define WARNINGS_ENABLE _Pragma("GCC diagnostic pop");
+
+#ifdef NO_THIRD_PARTY_WARNINGS
+//disabling some warnings
+#define THIRD_PARTY_WARNINGS_DISABLE WARNINGS_DISABLE
+
+#define THIRD_PARTY_WARNINGS_ENABLE WARNINGS_ENABLE
+#else
+// just save old state (needs for not empty define)
+#define THIRD_PARTY_WARNINGS_ENABLE WARNINGS_ENABLE
+
+#endif //#ifdef NO_THIRD_PARTY_WARNINGS
+
+#endif //#ifdef Q_WS_WIN
+
+#endif // UBGLOBALS_H
+
diff --git a/plugins/plugins.pri b/plugins/plugins.pri
new file mode 100644
index 00000000..ddf3113a
--- /dev/null
+++ b/plugins/plugins.pri
@@ -0,0 +1,6 @@
+HEADERS += plugins/cffadaptor/src/UBCFFAdaptor_global.h \
+ plugins/cffadaptor/src/UBCFFAdaptor.h \
+ plugins/cffadaptor/src/UBCFFConstants.h \
+ plugins/cffadaptor/src/UBGlobals.h
+
+SOURCES += plugins/cffadaptor/src/UBCFFAdaptor.cpp
diff --git a/resources/OpenBoard.qrc b/resources/OpenBoard.qrc
index 18c33750..d67ff3d5 100644
--- a/resources/OpenBoard.qrc
+++ b/resources/OpenBoard.qrc
@@ -360,5 +360,7 @@
images/ungroupItems.svg
images/setAsBackground.svg
images/backgroundPalette/resetDefaultGridSize.svg
+ images/collapse-all.png
+ images/expand-all.png
diff --git a/resources/forms/documents.ui b/resources/forms/documents.ui
index af48a648..90dc4476 100644
--- a/resources/forms/documents.ui
+++ b/resources/forms/documents.ui
@@ -28,50 +28,142 @@
-
- -
-
-
- QFrame::NoFrame
-
-
- QFrame::Raised
-
-
- 0
-
+
+
-
+
-
-
+
+
+ Qt::Horizontal
+
+
+ true
+
+
+ 6
+
+
0
0
-
- QFrame::Panel
-
-
- QFrame::Plain
-
-
- 0
-
-
- 0
-
-
-
-
-
- 0
- 0
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Collapse All
+
+
+
+
+
+
+ :/images/collapse-all.png:/images/collapse-all.png
+
+
+ true
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Expand All
+
+
+
+
+
+
+ :/images/expand-all.png:/images/expand-all.png
+
+
+ true
+
+
+
+ -
+
+
+
+ 4
+ 0
+
+
+
-
+
+ Select a sort
+
+
+ -
+
+ Creation date
+
+
+ -
+
+ Update date
+
+
+ -
+
+ Alphabetical order
+
+
+
+
+ -
+
+
+
+ 2
+ 0
+
+
+
-
+
+ Ascending order
+
+
+ -
+
+ Descending order
+
+
+
+
+
+
+ -
+
+
+
+ 400
+ 0
+
-
-
+
+
+ 16777215
+ 16777215
+
QFrame::NoFrame
@@ -79,14 +171,23 @@
QFrame::Plain
-
- 1
+
+ true
+
+
+ 65
-
- QAbstractItemView::ScrollPerPixel
+
+ QAbstractItemView::ExtendedSelection
-
- 2
+
+ QAbstractItemView::SelectRows
+
+
+ QAbstractItemView::ScrollPerItem
+
+
+ true
true
@@ -94,25 +195,15 @@
false
-
-
- 1
-
-
-
- -
-
+
-
- 0
-
-
@@ -147,7 +238,16 @@
0
-
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
0
-
@@ -224,6 +324,7 @@
+
@@ -238,9 +339,9 @@
gui/UBDocumentThumbnailWidget.h
- UBDocumentTreeWidget
- QTreeWidget
- gui/UBDocumentTreeWidget.h
+ UBDocumentTreeView
+ QTreeView
+ document/UBDocumentController.h
diff --git a/resources/forms/webPublishing.ui b/resources/forms/webPublishing.ui
new file mode 100644
index 00000000..d71282e5
--- /dev/null
+++ b/resources/forms/webPublishing.ui
@@ -0,0 +1,132 @@
+
+
+ documentPublishingDialog
+
+
+ Qt::WindowModal
+
+
+
+ 0
+ 0
+ 607
+ 405
+
+
+
+ Dialog
+
+
+ -
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
-
+
+
+ Title
+
+
+
+ -
+
+
+ 60
+
+
+
+ -
+
+
+ E-mail
+
+
+
+ -
+
+
+ -
+
+
+ Author
+
+
+
+ -
+
+
+ -
+
+
+ Description
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 168
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 10
+
+
+
+
+ -
+
+
+ Attach Downloadable PDF Version
+
+
+
+ -
+
+
+ Attach Downloadable Uniboard File (UBZ)
+
+
+
+ -
+
+
+ Warning: This documents contains video, which will not be displayed properly on the Web
+
+
+ true
+
+
+
+ -
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/images/collapse-all.png b/resources/images/collapse-all.png
new file mode 100755
index 00000000..9d4df9c9
Binary files /dev/null and b/resources/images/collapse-all.png differ
diff --git a/resources/images/expand-all.png b/resources/images/expand-all.png
new file mode 100755
index 00000000..b4045892
Binary files /dev/null and b/resources/images/expand-all.png differ
diff --git a/src/adaptors/UBCFFSubsetAdaptor.cpp b/src/adaptors/UBCFFSubsetAdaptor.cpp
new file mode 100644
index 00000000..474e4cc7
--- /dev/null
+++ b/src/adaptors/UBCFFSubsetAdaptor.cpp
@@ -0,0 +1,1549 @@
+/*
+ * 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 .
+ */
+
+
+
+#include
+#include
+#include
+#include
+#include
+
+#include "core/UBPersistenceManager.h"
+
+#include "document/UBDocumentProxy.h"
+
+#include "domain/UBItem.h"
+#include "domain/UBGraphicsPolygonItem.h"
+#include "domain/UBGraphicsStroke.h"
+#include "domain/UBGraphicsTextItem.h"
+#include "domain/UBGraphicsSvgItem.h"
+#include "domain/UBGraphicsPixmapItem.h"
+#include "domain/UBGraphicsMediaItem.h"
+#include "domain/UBGraphicsWidgetItem.h"
+#include "domain/UBGraphicsTextItem.h"
+#include "domain/UBGraphicsTextItemDelegate.h"
+#include "domain/UBGraphicsWidgetItem.h"
+#include "domain/UBGraphicsGroupContainerItem.h"
+
+#include "frameworks/UBFileSystemUtils.h"
+
+#include "UBCFFSubsetAdaptor.h"
+#include "UBMetadataDcSubsetAdaptor.h"
+#include "UBThumbnailAdaptor.h"
+#include "UBSvgSubsetAdaptor.h"
+
+#include "core/UBApplication.h"
+#include "QFile"
+
+#include "core/memcheck.h"
+//#include "qtlogger.h"
+
+//tag names definition. Use them everiwhere!
+static QString tElement = "element";
+static QString tGroup = "group";
+static QString tEllipse = "ellipse";
+static QString tIwb = "iwb";
+static QString tMeta = "meta";
+static QString tPage = "page";
+static QString tPageset = "pageset";
+static QString tG = "g";
+static QString tSwitch = "switch";
+static QString tPolygon = "polygon";
+static QString tPolyline = "polyline";
+static QString tRect = "rect";
+static QString tSvg = "svg";
+static QString tText = "text";
+static QString tTextarea = "textarea";
+static QString tTspan = "tspan";
+static QString tBreak = "tbreak";
+static QString tImage = "image";
+static QString tFlash = "flash";
+static QString tAudio = "a";
+static QString tVideo = "video";
+
+//attribute names definition
+static QString aFill = "fill";
+static QString aFillopacity = "fill-opacity";
+static QString aX = "x";
+static QString aY = "y";
+static QString aWidth = "width";
+static QString aHeight = "height";
+static QString aStroke = "stroke";
+static QString aStrokewidth = "stroke-width";
+static QString aCx = "cx";
+static QString aCy = "cy";
+static QString aRx = "rx";
+static QString aRy = "ry";
+static QString aTransform = "transform";
+static QString aViewbox = "viewbox";
+static QString aFontSize = "font-size";
+static QString aFontfamily = "font-family";
+static QString aFontstretch = "font-stretch";
+static QString aFontstyle = "font-style";
+static QString aFontweight = "font-weight";
+static QString aTextalign = "text-align";
+static QString aPoints = "points";
+static QString svgNS = "http://www.w3.org/2000/svg";
+static QString iwbNS = "http://www.imsglobal.org/xsd/iwb_v1p0";
+static QString aId = "id";
+static QString aRef = "ref";
+static QString aHref = "href";
+static QString aBackground = "background";
+static QString aLocked = "locked";
+static QString aEditable = "editable";
+
+//attributes part names
+static QString apRotate = "rotate";
+static QString apTranslate = "translate";
+
+
+UBCFFSubsetAdaptor::UBCFFSubsetAdaptor()
+{}
+
+bool UBCFFSubsetAdaptor::ConvertCFFFileToUbz(QString &cffSourceFile, UBDocumentProxy* pDocument)
+{
+ //TODO
+ // fill document proxy metadata
+ // create persistance manager to save data using proxy
+ // create UBCFFSubsetReader and make it parse cffSourceFolder
+ QFile file(cffSourceFile);
+
+ if (!file.open(QIODevice::ReadOnly))
+ {
+ qWarning() << "Cannot open file " << cffSourceFile << " for reading ...";
+ return false;
+ }
+
+ UBCFFSubsetReader cffReader(pDocument, &file);
+ bool result = cffReader.parse();
+ file.close();
+
+ return result;
+}
+UBCFFSubsetAdaptor::UBCFFSubsetReader::UBCFFSubsetReader(UBDocumentProxy *proxy, QFile *content)
+ : mProxy(proxy)
+ , mGSectionContainer(NULL)
+{
+ int errorLine, errorColumn;
+ QString errorStr;
+ if(!mDOMdoc.setContent(content, true, &errorStr, &errorLine, &errorColumn)){
+ qWarning() << "Error:Parseerroratline" << errorLine << ","
+ << "column" << errorColumn << ":" << errorStr;
+ } else {
+ qDebug() << "well parsed to DOM";
+ pwdContent = QFileInfo(content->fileName()).dir().absolutePath();
+ }
+ qDebug() << "tmp path is" << pwdContent;
+}
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parse()
+{
+ UBMetadataDcSubsetAdaptor::persist(mProxy);
+
+ mIndent = "";
+ if (!getTempFileName() || !createTempFlashPath())
+ return false;
+
+ if (mDOMdoc.isNull())
+ return false;
+
+ bool result = parseDoc();
+ if (result)
+ result = mProxy->pageCount() != 0;
+
+ if (QFile::exists(mTempFilePath))
+ QFile::remove(mTempFilePath);
+
+// if (mTmpFlashDir.exists())
+// UBFileSystemUtils::deleteDir(mTmpFlashDir.path());
+
+ return result;
+}
+
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseGSection(const QDomElement &element)
+{
+ mGSectionContainer = new UBGraphicsGroupContainerItem();
+
+ QDomElement currentSvgElement = element.firstChildElement();
+ while (!currentSvgElement.isNull()) {
+ parseSvgElement(currentSvgElement);
+ currentSvgElement = currentSvgElement.nextSiblingElement();
+ }
+
+ if (mGSectionContainer->childItems().count())
+ {
+ mCurrentScene->addGroup(mGSectionContainer);
+ }
+ else
+ {
+ delete mGSectionContainer;
+ }
+ mGSectionContainer = NULL;
+
+ return true;
+}
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgSwitchSection(const QDomElement &element)
+{
+
+ QDomElement currentSvgElement = element.firstChildElement();
+ while (!currentSvgElement.isNull()) {
+ if (parseSvgElement(currentSvgElement))
+ return true;
+ }
+
+ return false;
+}
+
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgRect(const QDomElement &element)
+{
+ qreal x1 = element.attribute(aX).toDouble();
+ qreal y1 = element.attribute(aY).toDouble();
+ //rect dimensions
+ qreal width = element.attribute(aWidth).toDouble();
+ qreal height = element.attribute(aHeight).toDouble();
+
+ QString textFillColor = element.attribute(aFill);
+ QString textStrokeColor = element.attribute(aStroke);
+ QString textStrokeWidth = element.attribute(aStrokewidth);
+
+ QColor fillColor = !textFillColor.isNull() ? colorFromString(textFillColor) : QColor();
+ QColor strokeColor = !textStrokeColor.isNull() ? colorFromString(textStrokeColor) : QColor();
+ int strokeWidth = textStrokeWidth.toInt();
+
+ x1 -= strokeWidth/2;
+ y1 -= strokeWidth/2;
+ width += strokeWidth;
+ height += strokeWidth;
+
+ //init svg generator with temp file
+ QSvgGenerator *generator = createSvgGenerator(width, height);
+
+ //init painter to paint to svg
+ QPainter painter;
+
+ painter.begin(generator);
+
+ //fill rect
+ if (fillColor.isValid()) {
+ painter.setBrush(QBrush(fillColor));
+ painter.fillRect(0, 0, width, height, fillColor);
+ }
+ QPen pen;
+ if (strokeColor.isValid()) {
+ pen.setColor(strokeColor);
+ }
+ if (strokeWidth)
+ pen.setWidth(strokeWidth);
+ painter.setPen(pen);
+ painter.drawRect(0, 0, width, height);
+
+ painter.end();
+
+ UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName()));
+
+ QString uuid = QUuid::createUuid().toString();
+ mRefToUuidMap.insert(element.attribute(aId), uuid);
+ svgItem->setUuid(QUuid(uuid));
+
+ QTransform transform;
+ QString textTransform = element.attribute(aTransform);
+
+ svgItem->resetTransform();
+ if (!textTransform.isNull()) {
+ transform = transformFromString(textTransform, svgItem);
+ }
+
+ repositionSvgItem(svgItem, width, height, x1, y1, transform);
+ hashSceneItem(element, svgItem);
+
+ if (mGSectionContainer)
+ {
+ addItemToGSection(svgItem);
+ }
+
+ delete generator;
+
+ return true;
+}
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgEllipse(const QDomElement &element)
+{
+ //ellipse horisontal and vertical radius
+ qreal rx = element.attribute(aRx).toDouble();
+ qreal ry = element.attribute(aRy).toDouble();
+ QSvgGenerator *generator = createSvgGenerator(rx * 2, ry * 2);
+
+ //fill and stroke color
+ QColor fillColor = colorFromString(element.attribute(aFill));
+ QColor strokeColor = colorFromString(element.attribute(aStroke));
+ int strokeWidth = element.attribute(aStrokewidth).toInt();
+
+ //ellipse center coordinates
+ qreal cx = element.attribute(aCx).toDouble();
+ qreal cy = element.attribute(aCy).toDouble();
+
+ //init painter to paint to svg
+ QPainter painter;
+ painter.begin(generator);
+
+ QPen pen(strokeColor);
+ pen.setWidth(strokeWidth);
+ painter.setPen(pen);
+ painter.setBrush(QBrush(fillColor));
+
+ painter.drawEllipse(0, 0, rx * 2, ry * 2);
+
+ painter.end();
+
+ UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName()));
+
+ QString uuid = QUuid::createUuid().toString();
+ mRefToUuidMap.insert(element.attribute(aId), uuid);
+ svgItem->setUuid(QUuid(uuid));
+
+ QTransform transform;
+ QString textTransform = element.attribute(aTransform);
+
+ svgItem->resetTransform();
+ if (!textTransform.isNull()) {
+ transform = transformFromString(textTransform, svgItem);
+ }
+
+
+ repositionSvgItem(svgItem, rx * 2, ry * 2, cx - 2*rx, cy+ry, transform);
+ hashSceneItem(element, svgItem);
+
+ if (mGSectionContainer)
+ {
+ addItemToGSection(svgItem);
+ }
+
+ delete generator;
+
+ return true;
+}
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPolygon(const QDomElement &element)
+{
+ QString svgPoints = element.attribute(aPoints);
+ QPolygonF polygon;
+
+ if (!svgPoints.isNull()) {
+ QStringList ts = svgPoints.split(QLatin1Char(' '), QString::SkipEmptyParts);
+
+ foreach(const QString sPoint, ts) {
+ QStringList sCoord = sPoint.split(QLatin1Char(','), QString::SkipEmptyParts);
+ if (sCoord.size() == 2) {
+ QPointF point;
+ point.setX(sCoord.at(0).toFloat());
+ point.setY(sCoord.at(1).toFloat());
+ polygon << point;
+ }
+ else if (sCoord.size() == 4){
+ //This is the case on system were the "," is used to seperate decimal
+ QPointF point;
+ QString x = sCoord.at(0) + "." + sCoord.at(1);
+ QString y = sCoord.at(2) + "." + sCoord.at(3);
+ point.setX(x.toFloat());
+ point.setY(y.toFloat());
+ polygon << point;
+ }
+ else {
+ qWarning() << "cannot make sense of a 'point' value" << sCoord;
+ }
+ }
+ }
+
+ //bounding rect lef top corner coordinates
+ qreal x1 = polygon.boundingRect().topLeft().x();
+ qreal y1 = polygon.boundingRect().topLeft().y();
+ //bounding rect dimensions
+ qreal width = polygon.boundingRect().width();
+ qreal height = polygon.boundingRect().height();
+
+ QString strokeColorText = element.attribute(aStroke);
+ QString fillColorText = element.attribute(aFill);
+ QString strokeWidthText = element.attribute(aStrokewidth);
+
+ QColor strokeColor = !strokeColorText.isEmpty() ? colorFromString(strokeColorText) : QColor();
+ QColor fillColor = !fillColorText.isEmpty() ? colorFromString(fillColorText) : QColor();
+ int strokeWidth = strokeWidthText.toDouble();
+
+ QPen pen;
+ pen.setColor(strokeColor);
+ pen.setWidth(strokeWidth);
+
+ QBrush brush;
+ brush.setColor(fillColor);
+ brush.setStyle(Qt::SolidPattern);
+
+
+ QUuid itemUuid(element.attribute(aId).right(QUuid().toString().length()));
+ QUuid itemGroupUuid(element.attribute(aId).left(QUuid().toString().length()-1));
+ if (!itemUuid.isNull() && (itemGroupUuid!=itemUuid)) // reimported from UBZ
+ {
+ UBGraphicsPolygonItem *graphicsPolygon = mCurrentScene->polygonToPolygonItem(polygon);
+
+ graphicsPolygon->setBrush(brush);
+
+ QTransform transform;
+ QString textTransform = element.attribute(aTransform);
+
+ graphicsPolygon->resetTransform();
+ if (!textTransform.isNull()) {
+ transform = transformFromString(textTransform, graphicsPolygon);
+ }
+ mCurrentScene->addItem(graphicsPolygon);
+
+ graphicsPolygon->setUuid(itemUuid);
+ mRefToUuidMap.insert(element.attribute(aId), itemUuid.toString());
+
+ }
+ else // single CFF
+ {
+ QSvgGenerator *generator = createSvgGenerator(width + pen.width(), height + pen.width());
+ QPainter painter;
+
+ painter.begin(generator); //drawing to svg tmp file
+
+ painter.translate(pen.widthF() / 2 - x1, pen.widthF() / 2 - y1);
+ painter.setBrush(brush);
+ painter.setPen(pen);
+ painter.drawPolygon(polygon);
+
+ painter.end();
+
+ //add resulting svg file to scene
+ UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName()));
+ QTransform transform;
+ QString textTransform = element.attribute(aTransform);
+
+ QUuid uuid = QUuid::createUuid().toString();
+ mRefToUuidMap.insert(element.attribute(aId), uuid.toString());
+ svgItem->setUuid(uuid);
+
+ svgItem->resetTransform();
+ if (!textTransform.isNull()) {
+ transform = transformFromString(textTransform, svgItem);
+ }
+ repositionSvgItem(svgItem, width +strokeWidth, height + strokeWidth, x1 - strokeWidth/2 + transform.m31(), y1 + strokeWidth/2 + transform.m32(), transform);
+ hashSceneItem(element, svgItem);
+
+ if (mGSectionContainer)
+ {
+ addItemToGSection(svgItem);
+ }
+
+ delete generator;
+ }
+ return true;
+}
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPolyline(const QDomElement &element)
+{
+ QString svgPoints = element.attribute(aPoints);
+ QPolygonF polygon;
+
+ if (!svgPoints.isNull()) {
+ QStringList ts = svgPoints.split(QLatin1Char(' '),
+ QString::SkipEmptyParts);
+
+ foreach(const QString sPoint, ts) {
+ QStringList sCoord = sPoint.split(QLatin1Char(','), QString::SkipEmptyParts);
+ if (sCoord.size() == 2) {
+ QPointF point;
+ point.setX(sCoord.at(0).toFloat());
+ point.setY(sCoord.at(1).toFloat());
+ polygon << point;
+ }
+ else if (sCoord.size() == 4){
+ //This is the case on system were the "," is used to seperate decimal
+ QPointF point;
+ QString x = sCoord.at(0) + "." + sCoord.at(1);
+ QString y = sCoord.at(2) + "." + sCoord.at(3);
+ point.setX(x.toFloat());
+ point.setY(y.toFloat());
+ polygon << point;
+ }
+ else {
+ qWarning() << "cannot make sense of a 'point' value" << sCoord;
+ }
+ }
+ }
+
+ //bounding rect lef top corner coordinates
+ qreal x1 = polygon.boundingRect().topLeft().x();
+ qreal y1 = polygon.boundingRect().topLeft().y();
+
+ //bounding rect dimensions
+ qreal width = polygon.boundingRect().width();
+ qreal height = polygon.boundingRect().height();
+
+ QString strokeColorText = element.attribute(aStroke);
+ QString strokeWidthText = element.attribute(aStrokewidth);
+
+ QColor strokeColor = !strokeColorText.isEmpty() ? colorFromString(strokeColorText) : QColor();
+ int strokeWidth = strokeWidthText.toDouble();
+
+ width += strokeWidth;
+ height += strokeWidth;
+
+ QPen pen;
+ pen.setColor(strokeColor);
+ pen.setWidth(strokeWidth);
+
+ QBrush brush;
+ brush.setColor(strokeColor);
+ brush.setStyle(Qt::SolidPattern);
+
+ QUuid itemUuid(element.attribute(aId).right(QUuid().toString().length()));
+ QUuid itemGroupUuid(element.attribute(aId).left(QUuid().toString().length()-1));
+ if (!itemUuid.isNull() && (itemGroupUuid!=itemUuid)) // reimported from UBZ
+ {
+ UBGraphicsPolygonItem *graphicsPolygon = new UBGraphicsPolygonItem(polygon);
+
+ UBGraphicsStroke *stroke = new UBGraphicsStroke();
+ graphicsPolygon->setStroke(stroke);
+
+ graphicsPolygon->setBrush(brush);
+ QTransform transform;
+ QString textTransform = element.attribute(aTransform);
+
+ graphicsPolygon->resetTransform();
+ if (!textTransform.isNull()) {
+ transform = transformFromString(textTransform, graphicsPolygon);
+ }
+ mCurrentScene->addItem(graphicsPolygon);
+
+ graphicsPolygon->setUuid(itemUuid);
+ mRefToUuidMap.insert(element.attribute(aId), itemUuid.toString());
+
+ }
+ else // simple CFF
+ {
+ QSvgGenerator *generator = createSvgGenerator(width + pen.width(), height + pen.width());
+ QPainter painter;
+
+ painter.begin(generator); //drawing to svg tmp file
+
+ painter.translate(pen.widthF() / 2 - x1, pen.widthF() / 2 - y1);
+ painter.setBrush(brush);
+ painter.setPen(pen);
+ painter.drawPolygon(polygon);
+
+ painter.end();
+
+ //add resulting svg file to scene
+ UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName()));
+
+ QString uuid = QUuid::createUuid().toString();
+ mRefToUuidMap.insert(element.attribute(aId), uuid);
+ svgItem->setUuid(QUuid(uuid));
+
+ QTransform transform;
+ QString textTransform = element.attribute(aTransform);
+
+ svgItem->resetTransform();
+ if (!textTransform.isNull()) {
+ transform = transformFromString(textTransform, svgItem);
+ }
+ repositionSvgItem(svgItem, width +strokeWidth, height + strokeWidth, x1 - strokeWidth/2 + transform.m31(), y1 + strokeWidth/2 + transform.m32(), transform);
+ hashSceneItem(element, svgItem);
+
+ if (mGSectionContainer)
+ {
+ addItemToGSection(svgItem);
+ }
+
+ delete generator;
+ }
+
+
+ return true;
+}
+void UBCFFSubsetAdaptor::UBCFFSubsetReader::parseTextAttributes(const QDomElement &element,
+ qreal &fontSize, QColor &fontColor, QString &fontFamily,
+ QString &fontStretch, bool &italic, int &fontWeight,
+ int &textAlign, QTransform &fontTransform)
+{
+ //consider inch has 72 liens
+ //since svg font size is given in pixels, divide it by pixels per line
+ QString fontSz = element.attribute(aFontSize);
+ if (!fontSz.isNull()) fontSize = fontSz.toDouble() * 72 / QApplication::desktop()->physicalDpiY();
+
+ QString fontColorText = element.attribute(aFill);
+ if (!fontColorText.isNull()) fontColor = colorFromString(fontColorText);
+
+ QString fontFamilyText = element.attribute(aFontfamily);
+ if (!fontFamilyText.isNull()) fontFamily = fontFamilyText;
+
+ QString fontStretchText = element.attribute(aFontstretch);
+ if (!fontStretchText.isNull()) fontStretch = fontStretchText;
+
+ if (!element.attribute(aFontstyle).isNull())
+ italic = (element.attribute(aFontstyle) == "italic");
+
+ QString weight = element.attribute(aFontweight);
+ if (!weight.isNull()) {
+ if (weight == "normal") fontWeight = QFont::Normal;
+ else if (weight == "light") fontWeight = QFont::Light;
+ else if (weight == "demibold") fontWeight = QFont::DemiBold;
+ else if (weight == "bold") fontWeight = QFont::Bold;
+ else if (weight == "black") fontWeight = QFont::Black;
+ }
+ QString align = element.attribute(aTextalign);
+ if (!align.isNull()) {
+ if (align == "middle" || align == "center") textAlign = Qt::AlignHCenter;
+ else if (align == "start") textAlign = Qt::AlignLeft;
+ else if (align == "end") textAlign = Qt::AlignRight;
+ }
+
+ if (!element.attribute(aTransform).isNull())
+ fontTransform = transformFromString(element.attribute(aTransform));
+}
+void UBCFFSubsetAdaptor::UBCFFSubsetReader::readTextBlockAttr(const QDomElement &element, QTextBlockFormat &format)
+{
+ QString fontStretchText = element.attribute(aFontstretch);
+ if (!fontStretchText.isNull()) format.setAlignment(Qt::AlignJustify);
+
+ QString align = element.attribute(aTextalign);
+ if (!align.isNull()) {
+ if (align == "middle" || align == "center") format.setAlignment(Qt::AlignHCenter);
+ else if (align == "start") format.setAlignment(Qt::AlignLeft);
+ else if (align == "end") format.setAlignment(Qt::AlignRight);
+ else if (align == "justify") format.setAlignment(Qt::AlignJustify);
+ }
+}
+void UBCFFSubsetAdaptor::UBCFFSubsetReader::readTextCharAttr(const QDomElement &element, QTextCharFormat &format)
+{
+ QString fontSz = element.attribute(aFontSize);
+ if (!fontSz.isNull()) {
+ qreal fontSize = fontSz.remove("pt").toDouble();
+ format.setFontPointSize(fontSize);
+ }
+ QString fontColorText = element.attribute(aFill);
+ if (!fontColorText.isNull()) {
+ QColor fontColor = colorFromString(fontColorText);
+ if (fontColor.isValid()) format.setForeground(fontColor);
+ }
+ QString fontFamilyText = element.attribute(aFontfamily);
+ if (!fontFamilyText.isNull()) {
+ format.setFontFamily(fontFamilyText);
+ }
+ if (!element.attribute(aFontstyle).isNull()) {
+ bool italic = (element.attribute(aFontstyle) == "italic");
+ format.setFontItalic(italic);
+ }
+ QString weight = element.attribute(aFontweight);
+ if (!weight.isNull()) {
+ if (weight == "normal") format.setFontWeight(QFont::Normal);
+ else if (weight == "light") format.setFontWeight(QFont::Light);
+ else if (weight == "demibold") format.setFontWeight(QFont::DemiBold);
+ else if (weight == "bold") format.setFontWeight(QFont::Bold);
+ else if (weight == "black") format.setFontWeight(QFont::Black);
+ }
+}
+
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgText(const QDomElement &element)
+{
+ qreal x = element.attribute(aX).toDouble();
+ qreal y = element.attribute(aY).toDouble();
+ qreal width = element.attribute(aWidth).toDouble();
+ qreal height = element.attribute(aHeight).toDouble();
+
+
+ qreal fontSize = 12;
+ QColor fontColor(qApp->palette().foreground().color());
+ QString fontFamily = "Arial";
+ QString fontStretch = "normal";
+ bool italic = false;
+ int fontWeight = QFont::Normal;
+ int textAlign = Qt::AlignLeft;
+ QTransform fontTransform;
+ parseTextAttributes(element, fontSize, fontColor, fontFamily, fontStretch, italic, fontWeight, textAlign, fontTransform);
+
+ QFont startFont(fontFamily, fontSize, fontWeight, italic);
+ height = QFontMetrics(startFont).height();
+ width = QFontMetrics(startFont).width(element.text()) + 5;
+
+ QSvgGenerator *generator = createSvgGenerator(width, height);
+ QPainter painter;
+ painter.begin(generator);
+ painter.setFont(startFont);
+
+ qreal curY = 0.0;
+ qreal curX = 0.0;
+ qreal linespacing = QFontMetricsF(painter.font()).leading();
+
+// remember if text area has transform
+// QString transformString;
+ QTransform transform = fontTransform;
+
+ QRectF lastDrawnTextBoundingRect;
+ //parse text area tags
+
+ //recursive call any tspan in text svg element
+ parseTSpan(element, painter
+ , curX, curY, width, height, linespacing, lastDrawnTextBoundingRect
+ , fontSize, fontColor, fontFamily, fontStretch, italic, fontWeight, textAlign, fontTransform);
+
+ painter.end();
+
+ //add resulting svg file to scene
+ UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName()));
+
+ QString uuid = QUuid::createUuid().toString();
+ mRefToUuidMap.insert(element.attribute(aId), uuid);
+ svgItem->setUuid(QUuid(uuid));
+
+ svgItem->resetTransform();
+ repositionSvgItem(svgItem, width, height, x + transform.m31(), y + transform.m32(), transform);
+ hashSceneItem(element, svgItem);
+
+ if (mGSectionContainer)
+ {
+ addItemToGSection(svgItem);
+ }
+
+ delete generator;
+ return true;
+}
+
+void UBCFFSubsetAdaptor::UBCFFSubsetReader::parseTSpan(const QDomElement &parent, QPainter &painter
+ , qreal &curX, qreal &curY, qreal &width, qreal &height, qreal &linespacing, QRectF &lastDrawnTextBoundingRect
+ , qreal &fontSize, QColor &fontColor, QString &fontFamily, QString &fontStretch, bool &italic
+ , int &fontWeight, int &textAlign, QTransform &fontTransform)
+{
+ QDomNode curNode = parent.firstChild();
+ while (!curNode.isNull()) {
+ if (curNode.toElement().tagName() == tTspan) {
+ QDomElement curTSpan = curNode.toElement();
+ parseTextAttributes(curTSpan, fontSize, fontColor, fontFamily, fontStretch, italic
+ , fontWeight, textAlign, fontTransform);
+ painter.setFont(QFont(fontFamily, fontSize, fontWeight, italic));
+ painter.setPen(fontColor);
+ linespacing = QFontMetricsF(painter.font()).leading();
+ parseTSpan(curTSpan, painter
+ , curX, curY, width, height, linespacing, lastDrawnTextBoundingRect
+ , fontSize, fontColor, fontFamily, fontStretch, italic, fontWeight, textAlign, fontTransform);
+ } else if (curNode.nodeType() == QDomNode::CharacterDataNode
+ || curNode.nodeType() == QDomNode::CDATASectionNode
+ || curNode.nodeType() == QDomNode::TextNode) {
+
+ QDomCharacterData textData = curNode.toCharacterData();
+ QString text = textData.data().trimmed();
+// width = painter.fontMetrics().width(text);
+ //get bounding rect to obtain desired text height
+ lastDrawnTextBoundingRect = painter.boundingRect(QRectF(curX, curY, width, height - curY), textAlign|Qt::TextWordWrap, text);
+ painter.drawText(curX, curY, width, lastDrawnTextBoundingRect.height(), textAlign|Qt::TextWordWrap, text);
+ curX += lastDrawnTextBoundingRect.x() + lastDrawnTextBoundingRect.width();
+ } else if (curNode.nodeType() == QDomNode::ElementNode
+ && curNode.toElement().tagName() == tBreak) {
+
+ curY += lastDrawnTextBoundingRect.height() + linespacing;
+ curX = 0.0;
+ lastDrawnTextBoundingRect = QRectF(0,0,0,0);
+ }
+ curNode = curNode.nextSibling();
+ }
+}
+void UBCFFSubsetAdaptor::UBCFFSubsetReader::parseTSpan(const QDomElement &element, QTextCursor &cursor
+ , QTextBlockFormat &blockFormat, QTextCharFormat &charFormat)
+{
+ QDomNode curNode = element.firstChild();
+ while (!curNode.isNull()) {
+ if (curNode.toElement().tagName() == tTspan) {
+ QDomElement curTspan = curNode.toElement();
+ readTextBlockAttr(curTspan, blockFormat);
+ readTextCharAttr(curTspan, charFormat);
+ cursor.setBlockFormat(blockFormat);
+ cursor.setCharFormat(charFormat);
+ parseTSpan(curTspan, cursor, blockFormat, charFormat);
+
+ } else if (curNode.nodeType() == QDomNode::CharacterDataNode
+ || curNode.nodeType() == QDomNode::CDATASectionNode
+ || curNode.nodeType() == QDomNode::TextNode) {
+
+ QDomCharacterData textData = curNode.toCharacterData();
+ QString text = textData.data().trimmed();
+ cursor.insertText(text, charFormat);
+
+ } else if (curNode.nodeType() == QDomNode::ElementNode
+ && curNode.toElement().tagName() == tBreak) {
+ cursor.insertBlock();
+ }
+ curNode = curNode.nextSibling();
+ }
+}
+
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgTextarea(const QDomElement &element)
+{
+ qreal x = element.attribute(aX).toDouble();
+ qreal y = element.attribute(aY).toDouble();
+ qreal width = element.attribute(aWidth).toDouble();
+ qreal height = element.attribute(aHeight).toDouble();
+
+ QTextBlockFormat blockFormat;
+ blockFormat.setAlignment(Qt::AlignLeft);
+
+ QTextCharFormat textFormat;
+ // default values
+ textFormat.setFontPointSize(12);
+ textFormat.setForeground(qApp->palette().foreground().color());
+ textFormat.setFontFamily("Arial");
+ textFormat.setFontItalic(false);
+ textFormat.setFontWeight(QFont::Normal);
+
+ // readed values
+ readTextBlockAttr(element, blockFormat);
+ readTextCharAttr(element, textFormat);
+
+ QTextDocument doc;
+ doc.setPlainText("");
+ QTextCursor tCursor(&doc);
+ tCursor.setBlockFormat(blockFormat);
+ tCursor.setCharFormat(textFormat);
+
+ parseTSpan(element, tCursor, blockFormat, textFormat);
+
+ UBGraphicsTextItem *svgItem = mCurrentScene->addTextHtml(doc.toHtml());
+ svgItem->resize(width, height);
+
+ QString uuid = QUuid::createUuid().toString();
+ mRefToUuidMap.insert(element.attribute(aId), uuid);
+ svgItem->setUuid(QUuid(uuid));
+
+ QTransform transform;
+ QString textTransform = element.attribute(aTransform);
+
+ svgItem->resetTransform();
+ if (!textTransform.isNull()) {
+ transform = transformFromString(textTransform, svgItem);
+ }
+
+ //by default all the textAreas are not editable
+ UBGraphicsTextItemDelegate *curDelegate = dynamic_cast(svgItem->Delegate());
+ if (curDelegate) {
+ curDelegate->setEditable(false);
+ }
+
+ repositionSvgItem(svgItem, width, height, x + transform.m31(), y + transform.m32(), transform);
+ hashSceneItem(element, svgItem);
+
+ if (mGSectionContainer)
+ {
+ addItemToGSection(svgItem);
+ }
+
+ return true;
+}
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgImage(const QDomElement &element)
+{
+ qreal x = element.attribute(aX).toDouble();
+ qreal y = element.attribute(aY).toDouble();
+ qreal width = element.attribute(aWidth).toDouble();
+ qreal height = element.attribute(aHeight).toDouble();
+
+ QString itemRefPath = element.attribute(aHref);
+
+ QPixmap pix;
+ if (!itemRefPath.isNull()) {
+ QString imagePath = pwdContent + "/" + itemRefPath;
+ if (!QFile::exists(imagePath)) {
+ qDebug() << "can't load file" << pwdContent + "/" + itemRefPath << "maybe file corrupted";
+ return false;
+ } else {
+// qDebug() << "size of file" << itemRefPath << QFileInfo(itemRefPath).size();
+ }
+ pix.load(imagePath);
+ if (pix.isNull()) {
+ qDebug() << "can't create pixmap for file" << pwdContent + "/" + itemRefPath << "maybe format does not supported";
+ }
+ }
+
+ UBGraphicsPixmapItem *pixItem = mCurrentScene->addPixmap(pix, NULL);
+
+ QString uuid = QUuid::createUuid().toString();
+ mRefToUuidMap.insert(element.attribute(aId), uuid);
+ pixItem->setUuid(QUuid(uuid));
+
+ QTransform transform;
+ QString textTransform = element.attribute(aTransform);
+
+ pixItem->resetTransform();
+ if (!textTransform.isNull()) {
+ transform = transformFromString(textTransform, pixItem);
+ }
+ repositionSvgItem(pixItem, width, height, x + transform.m31(), y + transform.m32(), transform);
+ hashSceneItem(element, pixItem);
+
+ if (mGSectionContainer)
+ {
+ addItemToGSection(pixItem);
+ }
+
+ return true;
+}
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgFlash(const QDomElement &element)
+{
+ QString itemRefPath = element.attribute(aHref);
+
+ qreal x = element.attribute(aX).toDouble();
+ qreal y = element.attribute(aY).toDouble();
+ qreal width = element.attribute(aWidth).toDouble();
+ qreal height = element.attribute(aHeight).toDouble();
+
+ QUrl urlPath;
+ QString flashPath;
+ if (!itemRefPath.isNull()) {
+ flashPath = pwdContent + "/" + itemRefPath;
+ if (!QFile::exists(flashPath)) {
+ qDebug() << "can't load file" << pwdContent + "/" + itemRefPath << "maybe file corrupted";
+ return false;
+ }
+ urlPath = QUrl::fromLocalFile(flashPath);
+ }
+ QDir tmpFlashDir(mTmpFlashDir);
+ if (!tmpFlashDir.exists()) {
+ qDebug() << "Can't create temporary directory to put flash";
+ return false;
+ }
+
+ QString flashUrl = UBGraphicsW3CWidgetItem::createNPAPIWrapperInDir(flashPath, tmpFlashDir, "application/x-shockwave-flash"
+ ,QSize(mCurrentSceneRect.width(), mCurrentSceneRect.height()));
+ UBGraphicsWidgetItem *flashItem = mCurrentScene->addW3CWidget(QUrl::fromLocalFile(flashUrl));
+ flashItem->setSourceUrl(urlPath);
+
+ QString uuid = QUuid::createUuid().toString();
+ mRefToUuidMap.insert(element.attribute(aId), uuid);
+ flashItem->setUuid(QUuid(uuid));
+
+ QTransform transform;
+ QString textTransform = element.attribute(aTransform);
+
+ flashItem->resetTransform();
+ if (!textTransform.isNull()) {
+ transform = transformFromString(textTransform, flashItem);
+ }
+ repositionSvgItem(flashItem, width, height, x + transform.m31(), y + transform.m32(), transform);
+ hashSceneItem(element, flashItem);
+
+ if (mGSectionContainer)
+ {
+ addItemToGSection(flashItem);
+ }
+
+ return true;
+}
+
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgAudio(const QDomElement &element)
+{
+ QDomElement parentOfAudio = element.firstChild().toElement();
+
+ qreal x = parentOfAudio.attribute(aX).toDouble();
+ qreal y = parentOfAudio.attribute(aY).toDouble();
+
+ QString itemRefPath = element.attribute(aHref);
+
+ QUrl concreteUrl;
+ if (!itemRefPath.isNull()) {
+ QString audioPath = pwdContent + "/" + itemRefPath;
+ if (!QFile::exists(audioPath)) {
+ qDebug() << "can't load file" << pwdContent + "/" + itemRefPath << "maybe file corrupted";
+ return false;
+ }
+ concreteUrl = QUrl::fromLocalFile(audioPath);
+ }
+
+ QString uuid = QUuid::createUuid().toString();
+ mRefToUuidMap.insert(element.attribute(aId), uuid);
+
+ QString destFile;
+ bool b = UBPersistenceManager::persistenceManager()->addFileToDocument(
+ mCurrentScene->document(),
+ concreteUrl.toLocalFile(),
+ UBPersistenceManager::audioDirectory,
+ QUuid(uuid),
+ destFile);
+ if (!b)
+ {
+ return false;
+ }
+ concreteUrl = QUrl::fromLocalFile(destFile);
+
+ UBGraphicsMediaItem *audioItem = mCurrentScene->addAudio(concreteUrl, false);
+
+ QTransform transform;
+ QString textTransform = parentOfAudio.attribute(aTransform);
+
+ audioItem->resetTransform();
+ if (!textTransform.isNull()) {
+ transform = transformFromString(textTransform, audioItem);
+ }
+ repositionSvgItem(audioItem, audioItem->boundingRect().width(), audioItem->boundingRect().height(), x + transform.m31(), y + transform.m32(), transform);
+ hashSceneItem(element, audioItem);
+
+ if (mGSectionContainer)
+ {
+ addItemToGSection(audioItem);
+ }
+
+ return true;
+}
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgVideo(const QDomElement &element)
+{
+ QString itemRefPath = element.attribute(aHref);
+ if (itemRefPath.startsWith(tFlash + "/") && itemRefPath.endsWith(".swf")) {
+ if (parseSvgFlash(element)) return true;
+ else return false;
+ }
+ qreal x = element.attribute(aX).toDouble();
+ qreal y = element.attribute(aY).toDouble();
+
+ QUrl concreteUrl;
+ if (!itemRefPath.isNull()) {
+ QString videoPath = pwdContent + "/" + itemRefPath;
+ if (!QFile::exists(videoPath)) {
+ qDebug() << "can't load file" << pwdContent + "/" + itemRefPath << "maybe file corrupted";
+ return false;
+ }
+ concreteUrl = QUrl::fromLocalFile(videoPath);
+ }
+
+ QString uuid = QUuid::createUuid().toString();
+ mRefToUuidMap.insert(element.attribute(aId), uuid);
+
+ QString destFile;
+ bool b = UBPersistenceManager::persistenceManager()->addFileToDocument(
+ mCurrentScene->document(),
+ concreteUrl.toLocalFile(),
+ UBPersistenceManager::videoDirectory,
+ QUuid(uuid),
+ destFile);
+ if (!b)
+ {
+ return false;
+ }
+ concreteUrl = QUrl::fromLocalFile(destFile);
+
+ UBGraphicsMediaItem *videoItem = mCurrentScene->addVideo(concreteUrl, false);
+
+ QTransform transform;
+ QString textTransform = element.attribute(aTransform);
+
+ videoItem->resetTransform();
+ if (!textTransform.isNull()) {
+ transform = transformFromString(textTransform, videoItem);
+ }
+ repositionSvgItem(videoItem, videoItem->boundingRect().width(), videoItem->boundingRect().height(), x + transform.m31(), y + transform.m32(), transform);
+ hashSceneItem(element, videoItem);
+
+ if (mGSectionContainer)
+ {
+ addItemToGSection(videoItem);
+ }
+
+ return true;
+}
+
+void UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgSectionAttr(const QDomElement &svgSection)
+{
+ getViewBoxDimenstions(svgSection.attribute(aViewbox));
+ mSize = QSize(svgSection.attribute(aWidth).toInt(),
+ svgSection.attribute(aHeight).toInt());
+}
+
+void UBCFFSubsetAdaptor::UBCFFSubsetReader::addItemToGSection(QGraphicsItem *item)
+{
+ mGSectionContainer->addToGroup(item);
+}
+
+void UBCFFSubsetAdaptor::UBCFFSubsetReader::hashSceneItem(const QDomElement &element, UBGraphicsItem *item)
+{
+// adding element pointer to hash to refer if needed
+ QString key = element.attribute(aId);
+ if (!key.isNull()) {
+ persistedItems.insert(key, item);
+ }
+}
+
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgElement(const QDomElement &parent)
+{
+ QString tagName = parent.tagName();
+ if (parent.namespaceURI() != svgNS) {
+ qWarning() << "Incorrect namespace, error at content file, line number" << parent.lineNumber();
+ //return false;
+ }
+
+ if (tagName == tG && !parseGSection(parent)) return false;
+ else if (tagName == tSwitch && !parseSvgSwitchSection(parent)) return false;
+ else if (tagName == tRect && !parseSvgRect(parent)) return false;
+ else if (tagName == tEllipse && !parseSvgEllipse(parent)) return false;
+ else if (tagName == tPolygon && !parseSvgPolygon(parent)) return false;
+ else if (tagName == tPolyline && !parseSvgPolyline(parent)) return false;
+ else if (tagName == tText && !parseSvgText(parent)) return false;
+ else if (tagName == tTextarea && !parseSvgTextarea(parent)) return false;
+ else if (tagName == tImage && !parseSvgImage(parent)) return false;
+ else if (tagName == tFlash && !parseSvgFlash(parent)) return false;
+ else if (tagName == tAudio && !parseSvgAudio(parent)) return false;
+ else if (tagName == tVideo && !parseSvgVideo(parent)) return false;
+
+ return true;
+}
+
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPage(const QDomElement &parent)
+{
+ createNewScene();
+ QDomElement currentSvgElement = parent.firstChildElement();
+ while (!currentSvgElement.isNull()) {
+ if (!parseSvgElement(currentSvgElement))
+ return false;
+
+ currentSvgElement = currentSvgElement.nextSiblingElement();
+ }
+
+ return true;
+}
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvgPageset(const QDomElement &parent)
+{
+ QDomElement currentPage = parent.firstChildElement(tPage);
+ while (!currentPage.isNull()) {
+ if (!parseSvgPage(currentPage))
+ return false;
+ currentPage = currentPage.nextSiblingElement(tPage);
+ }
+ return true;
+}
+
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseIwbMeta(const QDomElement &element)
+{
+ if (element.namespaceURI() != iwbNS) {
+ qWarning() << "incorrect meta namespace, incorrect document";
+ //return false;
+ }
+
+ return true;
+}
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvg(const QDomElement &svgSection)
+{
+ if (svgSection.namespaceURI() != svgNS) {
+ qWarning() << "incorrect svg namespace, incorrect document";
+ // return false;
+ }
+
+ parseSvgSectionAttr(svgSection);
+ QDomElement currentSvg = svgSection.firstChildElement();
+
+ if (currentSvg.tagName() != tPageset) {
+ parseSvgPage(svgSection);
+ } else if (currentSvg.tagName() == tPageset){
+ parseSvgPageset(currentSvg);
+ }
+
+ return true;
+}
+
+UBGraphicsGroupContainerItem *UBCFFSubsetAdaptor::UBCFFSubsetReader::parseIwbGroup(QDomElement &parent)
+{
+ //TODO. Create groups from elements parsed by parseIwbElement() function
+ if (parent.namespaceURI() != iwbNS) {
+ qWarning() << "incorrect iwb group namespace, incorrect document";
+ // return false;
+ }
+
+ UBGraphicsGroupContainerItem *group = new UBGraphicsGroupContainerItem();
+ QMultiMap strokesGroupsContainer;
+ QList groupContainer;
+ QString currentStrokeIdentifier;
+
+ QDomElement currentStrokeElement = parent.firstChildElement();
+ while (!currentStrokeElement.isNull())
+ {
+ if (tGroup == currentStrokeElement.tagName())
+ group->addToGroup(parseIwbGroup(currentStrokeElement));
+ else
+ {
+
+ QString ref = currentStrokeElement.attribute(aRef);
+ QString uuid = mRefToUuidMap[ref];
+ if (!uuid.isEmpty())
+ {
+ if (ref.size() > QUuid().toString().length()) // create stroke group
+ {
+ currentStrokeIdentifier = ref.left(QUuid().toString().length()-1);
+ UBGraphicsPolygonItem *strokeByUuid = qgraphicsitem_cast(mCurrentScene->itemForUuid(QUuid(ref.right(QUuid().toString().length()))));
+
+ if (strokeByUuid)
+ strokesGroupsContainer.insert(currentStrokeIdentifier, strokeByUuid);
+ }
+ else // single elements in group
+ groupContainer.append(mCurrentScene->itemForUuid(QUuid(uuid)));
+ }
+ }
+ currentStrokeElement = currentStrokeElement.nextSiblingElement();
+ }
+
+
+
+ foreach (QString key, strokesGroupsContainer.keys().toSet())
+ {
+ UBGraphicsStrokesGroup* pStrokesGroup = new UBGraphicsStrokesGroup();
+ UBGraphicsStroke *currentStroke = new UBGraphicsStroke();
+ foreach(UBGraphicsPolygonItem* poly, strokesGroupsContainer.values(key))
+ {
+ if (poly)
+ {
+ mCurrentScene->removeItem(poly);
+ mCurrentScene->removeItemFromDeletion(poly);
+ poly->setStrokesGroup(pStrokesGroup);
+ poly->setStroke(currentStroke);
+ pStrokesGroup->addToGroup(poly);
+ }
+ }
+ if (currentStroke->polygons().empty())
+ delete currentStroke;
+
+ if (pStrokesGroup->childItems().count())
+ mCurrentScene->addItem(pStrokesGroup);
+ else
+ delete pStrokesGroup;
+
+ if (pStrokesGroup)
+ {
+ QGraphicsItem *strokeGroup = qgraphicsitem_cast(pStrokesGroup);
+ groupContainer.append(strokeGroup);
+ }
+ }
+
+ foreach(QGraphicsItem* item, groupContainer)
+ group->addToGroup(item);
+
+ if (group->childItems().count())
+ {
+ mCurrentScene->addItem(group);
+
+ if (1 == group->childItems().count())
+ {
+ group->destroy(false);
+ }
+ }
+
+ return group;
+}
+
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::strToBool(QString str)
+{
+ return str == "true";
+}
+
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseIwbElement(QDomElement &element)
+{
+ if (element.namespaceURI() != iwbNS) {
+ qWarning() << "incorrect iwb element namespace, incorrect document";
+ // return false;
+ }
+
+ bool locked = false;
+ bool isEditableItem = false;
+ bool isEditable = false; //Text items to convert to UBGraphicsTextItem only
+
+ QString IDRef = element.attribute(aRef);
+ if (!IDRef.isNull()) {
+ element.hasAttribute(aBackground) ? strToBool(element.attribute(aBackground)) : false;
+ locked = element.hasAttribute(aBackground) ? strToBool(element.attribute(aBackground)) : false;
+ isEditableItem = element.hasAttribute(aEditable);
+ if (isEditableItem)
+ isEditable = strToBool(element.attribute(aEditable));
+
+ UBGraphicsItem *referedItem(0);
+ QHash::iterator iReferedItem;
+ iReferedItem = persistedItems.find(IDRef);
+ if (iReferedItem != persistedItems.end()) {
+ referedItem = *iReferedItem;
+ referedItem->Delegate()->lock(locked);
+ }
+ if (isEditableItem) {
+ UBGraphicsTextItemDelegate *textDelegate = dynamic_cast(referedItem->Delegate());
+ if (textDelegate) {
+ textDelegate->setEditable(isEditable);
+ }
+ }
+ }
+
+ return true;
+}
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseDoc()
+{
+ QDomElement currentTopElement = mDOMdoc.documentElement().firstChildElement();
+ while (!currentTopElement.isNull()) {
+ QString tagName = currentTopElement.tagName();
+ if (tagName == tMeta && !parseIwbMeta(currentTopElement)) return false;
+ else if (tagName == tSvg && !parseSvg(currentTopElement)) return false;
+ else if (tagName == tGroup && !parseIwbGroup(currentTopElement)) return false;
+ else if (tagName == tElement && !parseIwbElement(currentTopElement)) return false;
+
+ currentTopElement = currentTopElement.nextSiblingElement();
+ }
+ if (!persistScenes()) return false;
+
+ return true;
+}
+
+void UBCFFSubsetAdaptor::UBCFFSubsetReader::repositionSvgItem(QGraphicsItem *item, qreal width, qreal height,
+ qreal x, qreal y,
+ QTransform &transform)
+{
+ //First using viebox coordinates, then translate them to scene coordinates
+
+ QRectF itemBounds = item->boundingRect();
+
+ qreal xScale = width / itemBounds.width();
+ qreal yScale = height / itemBounds.height();
+
+ qreal fullScaleX = mVBTransFactor * xScale;
+ qreal fullScaleY = mVBTransFactor * yScale;
+
+ QPointF oldVector((x - transform.dx()), (y - transform.dy()));
+ QTransform rTransform;
+ QPointF newVector = rTransform.map(oldVector);
+
+ QTransform tr = item->sceneTransform();
+ item->setTransform(rTransform.scale(fullScaleX, fullScaleY), true);
+ tr = item->sceneTransform();
+ QPoint pos;
+ if (UBGraphicsTextItem::Type == item->type())
+ pos = QPoint((int)((x + mShiftVector.x() + (newVector - oldVector).x())), (int)((y +mShiftVector.y() + (newVector - oldVector).y()) * mVBTransFactor));
+ else
+ pos = QPoint((int)((x + mShiftVector.x() + (newVector - oldVector).x()) * mVBTransFactor), (int)((y +mShiftVector.y() + (newVector - oldVector).y()) * mVBTransFactor));
+
+
+ item->setPos(pos);
+}
+
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::createNewScene()
+{
+ mCurrentScene = UBPersistenceManager::persistenceManager()->createDocumentSceneAt(mProxy, mProxy->pageCount(), false);
+ mCurrentScene->setSceneRect(mViewBox);
+ if ((mCurrentScene->sceneRect().topLeft().x() >= 0) || (mCurrentScene->sceneRect().topLeft().y() >= 0)) {
+ mShiftVector = -mViewBox.center();
+ }
+ mCurrentSceneRect = mViewBox;
+ mVBTransFactor = qMin(mCurrentScene->normalizedSceneRect().width() / mViewPort.width(),
+ mCurrentScene->normalizedSceneRect().height() / mViewPort.height());
+ return true;
+}
+
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::persistCurrentScene()
+{
+ if (mCurrentScene != 0 && mCurrentScene->isModified())
+ {
+ UBThumbnailAdaptor::persistScene(mProxy, mCurrentScene, mProxy->pageCount() - 1);
+ UBSvgSubsetAdaptor::persistScene(mProxy, mCurrentScene, mProxy->pageCount() - 1);
+
+ mCurrentScene->setModified(false);
+ mCurrentScene = 0;
+ }
+ return true;
+}
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::persistScenes()
+{
+ if (!mProxy->pageCount()) {
+ qDebug() << "No pages created";
+ return false;
+ }
+ for (int i = 0; i < mProxy->pageCount(); i++) {
+ mCurrentScene = UBPersistenceManager::persistenceManager()->getDocumentScene(mProxy, i);
+ if (!mCurrentScene) {
+ qDebug() << "can't allocate scene, loading failed";
+ return false;
+ }
+
+ UBSvgSubsetAdaptor::persistScene(mProxy, mCurrentScene, i);
+ UBGraphicsScene *tmpScene = UBSvgSubsetAdaptor::loadScene(mProxy, i);
+ tmpScene->setModified(true);
+ UBThumbnailAdaptor::persistScene(mProxy, tmpScene, i);
+ mCurrentScene->setModified(false);
+ }
+
+ return true;
+}
+
+QColor UBCFFSubsetAdaptor::UBCFFSubsetReader::colorFromString(const QString& clrString)
+{
+ //init regexp with pattern
+ //pattern corresponds to strings like 'rgb(1,2,3) or rgb(10%,20%,30%)'
+ QRegExp regexp("rgb\\(([0-9]+%{0,1}),([0-9]+%{0,1}),([0-9]+%{0,1})\\)");
+ if (regexp.exactMatch(clrString))
+ {
+ if (regexp.capturedTexts().count() == 4 && regexp.capturedTexts().at(0).length() == clrString.length())
+ {
+ int r = regexp.capturedTexts().at(1).toInt();
+ if (regexp.capturedTexts().at(1).indexOf("%") != -1)
+ r = r * 255 / 100;
+ int g = regexp.capturedTexts().at(2).toInt();
+ if (regexp.capturedTexts().at(2).indexOf("%") != -1)
+ g = g * 255 / 100;
+ int b = regexp.capturedTexts().at(3).toInt();
+ if (regexp.capturedTexts().at(3).indexOf("%") != -1)
+ b = b * 255 / 100;
+ return QColor(r, g, b);
+ }
+ else
+ return QColor();
+ }
+ else
+ return QColor(clrString);
+}
+
+QTransform UBCFFSubsetAdaptor::UBCFFSubsetReader::transformFromString(const QString trString, QGraphicsItem *item)
+{
+ qreal dxr = 0.0;
+ qreal dyr = 0.0;
+ qreal dx = 0.0;
+ qreal dy = 0.0;
+ qreal angle = 0.0;
+ QTransform tr;
+
+ foreach(QString trStr, trString.split(" ", QString::SkipEmptyParts))
+ {
+ //check pattern for strings like 'rotate(10)'
+ QRegExp regexp("rotate\\( *([-+]{0,1}[0-9]*\\.{0,1}[0-9]*) *\\)");
+ if (regexp.exactMatch(trStr)) {
+ angle = regexp.capturedTexts().at(1).toDouble();
+ if (item)
+ {
+ item->setTransformOriginPoint(QPointF(0, 0));
+ item->setRotation(angle);
+ }
+ continue;
+ };
+
+ //check pattern for strings like 'rotate(10,20,20)' or 'rotate(10.1,10.2,34.2)'
+ regexp.setPattern("rotate\\( *([-+]{0,1}[0-9]*\\.{0,1}[0-9]*) *, *([-+]{0,1}[0-9]*\\.{0,1}[0-9]*) *, *([-+]{0,1}[0-9]*\\.{0,1}[0-9]*) *\\)");
+ if (regexp.exactMatch(trStr)) {
+ angle = regexp.capturedTexts().at(1).toDouble();
+ dxr = regexp.capturedTexts().at(2).toDouble();
+ dyr = regexp.capturedTexts().at(3).toDouble();
+ if (item)
+ {
+ item->setTransformOriginPoint(QPointF(dxr, dyr)-item->pos());
+ item->setRotation(angle);
+ }
+ continue;
+ }
+
+ //check pattern for strings like 'translate(11.0, 12.34)'
+ regexp.setPattern("translate\\( *([-+]{0,1}[0-9]*\\.{0,1}[0-9]*) *,*([-+]{0,1}[0-9]*\\.{0,1}[0-9]*)*\\)");
+ if (regexp.exactMatch(trStr)) {
+ dx = regexp.capturedTexts().at(1).toDouble();
+ dy = regexp.capturedTexts().at(2).toDouble();
+ tr.translate(dx,dy);
+ continue;
+ }
+ }
+ return tr;
+}
+
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::getViewBoxDimenstions(const QString& viewBox)
+{
+ QStringList capturedTexts = viewBox.split(" ", QString::SkipEmptyParts);
+ if (capturedTexts.count())
+ {
+ if (4 == capturedTexts.count())
+ {
+ mViewBox = QRectF(capturedTexts.at(0).toDouble(), capturedTexts.at(1).toDouble(), capturedTexts.at(2).toDouble(), capturedTexts.at(3).toDouble());
+ mViewPort = mViewBox;
+ mViewPort.translate(- mViewPort.center());
+ mViewBoxCenter.setX(mViewBox.width() / 2);
+ mViewBoxCenter.setY(mViewBox.height() / 2);
+
+ return true;
+ }
+ }
+
+ mViewBox = QRectF(0, 0, 1000, 1000);
+ mViewBoxCenter = QPointF(500, 500);
+ return false;
+}
+
+QSvgGenerator* UBCFFSubsetAdaptor::UBCFFSubsetReader::createSvgGenerator(qreal width, qreal height)
+{
+ QSvgGenerator* generator = new QSvgGenerator();
+// qWarning() << QString("Making generator with file %1, size (%2, %3) and viewbox (%4 %5 %6 %7)").arg(mTempFilePath)
+// .arg(width).arg(height).arg(0.0).arg(0.0).arg(width).arg(width);
+ generator->setResolution(QApplication::desktop()->physicalDpiY());
+ generator->setFileName(mTempFilePath);
+ generator->setSize(QSize(width, height));
+ generator->setViewBox(QRectF(0, 0, width, height));
+
+ return generator;
+}
+
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::getTempFileName()
+{
+ int tmpNumber = 0;
+ QDir rootDir;
+ while (true)
+ {
+ mTempFilePath = QString("%1/sanksvg%2.%3")
+ .arg(rootDir.tempPath())
+ .arg(QDateTime::currentDateTime().toString("dd_MM_yyyy_HH-mm"))
+ .arg(tmpNumber);
+ if (!QFile::exists(mTempFilePath))
+ return true;
+ tmpNumber++;
+ if (tmpNumber == 100000)
+ {
+ qWarning() << "Import failed. Failed to create temporary file for svg objects";
+ return false;
+ }
+ }
+}
+bool UBCFFSubsetAdaptor::UBCFFSubsetReader::createTempFlashPath()
+{
+ int tmpNumber = 0;
+ QDir systemTmp = QDir::temp();
+
+ while (true) {
+ QString dirName = QString("SankTmpFlash%1.%2")
+ .arg(QDateTime::currentDateTime().toString("dd_MM_yyyy_HH-mm"))
+ .arg(tmpNumber++);
+ if (!systemTmp.exists(dirName)) {
+ if (systemTmp.mkdir(dirName)) {
+ mTmpFlashDir = QDir(systemTmp.absolutePath() + "/" + dirName);
+ return true;
+ } else {
+ qDebug() << "Can't create temporary dir maybe due to permissions";
+ return false;
+ }
+ } else if (tmpNumber == 1000) {
+ qWarning() << "Import failed. Failed to create temporary file for svg objects";
+ return false;
+ }
+ }
+
+ return true;
+}
+UBCFFSubsetAdaptor::UBCFFSubsetReader::~UBCFFSubsetReader()
+{
+// QList pages;
+// for (int i = 0; i < mProxy->pageCount(); i++) {
+// pages << i;
+// }
+// UBPersistenceManager::persistenceManager()->deleteDocumentScenes(mProxy, pages);
+}
diff --git a/src/adaptors/UBCFFSubsetAdaptor.h b/src/adaptors/UBCFFSubsetAdaptor.h
new file mode 100644
index 00000000..68f741e9
--- /dev/null
+++ b/src/adaptors/UBCFFSubsetAdaptor.h
@@ -0,0 +1,153 @@
+/*
+ * 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 .
+ */
+
+
+
+#ifndef UBCFFSUBSETADAPTOR_H
+#define UBCFFSUBSETADAPTOR_H
+
+#include
+#include
+#include
+#include
+#include
+
+class UBDocumentProxy;
+class UBGraphicsScene;
+class QSvgGenerator;
+class UBGraphicsSvgItem;
+class UBGraphicsPixmapItem;
+class UBGraphicsItemDelegate;
+class QTransform;
+class QPainter;
+class UBGraphicsItem;
+class QGraphicsItem;
+class QTextBlockFormat;
+class QTextCharFormat;
+class QTextCursor;
+class UBGraphicsStrokesGroup;
+
+
+class UBCFFSubsetAdaptor
+{
+public:
+ UBCFFSubsetAdaptor();
+ static bool ConvertCFFFileToUbz(QString &cffSourceFile, UBDocumentProxy* pDocument);
+
+private:
+ class UBCFFSubsetReader
+ {
+ public:
+ UBCFFSubsetReader(UBDocumentProxy *proxy, QFile *content);
+ ~UBCFFSubsetReader();
+
+ UBDocumentProxy *mProxy;
+ QString pwdContent;
+
+ bool parse();
+
+ private:
+ QString mTempFilePath;
+ UBGraphicsScene *mCurrentScene;
+ QRectF mCurrentSceneRect;
+ QString mIndent;
+ QRectF mViewBox;
+ QRectF mViewPort;
+ qreal mVBTransFactor;
+ QPointF mViewBoxCenter;
+ QSize mSize;
+ QPointF mShiftVector;
+ bool mSvgGSectionIsOpened;
+ UBGraphicsGroupContainerItem *mGSectionContainer;
+
+ private:
+ QDomDocument mDOMdoc;
+ QDomNode mCurrentDOMElement;
+ QHash persistedItems;
+ QMap mRefToUuidMap;
+ QDir mTmpFlashDir;
+
+ void addItemToGSection(QGraphicsItem *item);
+ bool hashElements();
+ void addExtentionsToHash(QDomElement *parent, QDomElement *topGroup);
+
+ void hashSvg(QDomNode *parent, QString prefix = "");
+ void hashSiblingIwbElements(QDomElement *parent, QDomElement *topGroup = 0);
+
+ inline void parseSvgSectionAttr(const QDomElement &);
+ bool parseSvgPage(const QDomElement &parent);
+ bool parseSvgPageset(const QDomElement &parent);
+ bool parseSvgElement(const QDomElement &parent);
+ bool parseIwbMeta(const QDomElement &element);
+ bool parseSvg(const QDomElement &svgSection);
+
+ inline bool parseGSection(const QDomElement &element);
+ inline bool parseSvgSwitchSection(const QDomElement &element);
+ inline bool parseSvgRect(const QDomElement &element);
+ inline bool parseSvgEllipse(const QDomElement &element);
+ inline bool parseSvgPolygon(const QDomElement &element);
+ inline bool parseSvgPolyline(const QDomElement &element);
+ inline bool parseSvgText(const QDomElement &element);
+ inline bool parseSvgTextarea(const QDomElement &element);
+ inline bool parseSvgImage(const QDomElement &element);
+ inline bool parseSvgFlash(const QDomElement &element);
+ inline bool parseSvgAudio(const QDomElement &element);
+ inline bool parseSvgVideo(const QDomElement &element);
+ inline UBGraphicsGroupContainerItem *parseIwbGroup(QDomElement &parent);
+ inline bool parseIwbElement(QDomElement &element);
+ inline void parseTSpan(const QDomElement &parent, QPainter &painter
+ , qreal &curX, qreal &curY, qreal &width, qreal &height, qreal &linespacing, QRectF &lastDrawnTextBoundingRect
+ , qreal &fontSize, QColor &fontColor, QString &fontFamily, QString &fontStretch, bool &italic
+ , int &fontWeight, int &textAlign, QTransform &fontTransform);
+ inline void parseTSpan(const QDomElement &element, QTextCursor &cursor
+ , QTextBlockFormat &blockFormat, QTextCharFormat &charFormat);
+ inline void hashSceneItem(const QDomElement &element, UBGraphicsItem *item);
+
+ // to kill
+ inline void parseTextAttributes(const QDomElement &element, qreal &fontSize, QColor &fontColor,
+ QString &fontFamily, QString &fontStretch, bool &italic,
+ int &fontWeight, int &textAlign, QTransform &fontTransform);
+ inline void parseTextAttributes(const QDomElement &element, QFont &font, QColor);
+ inline void readTextBlockAttr(const QDomElement &element, QTextBlockFormat &format);
+ inline void readTextCharAttr(const QDomElement &element, QTextCharFormat &format);
+
+ //elements parsing methods
+ bool parseDoc();
+
+ bool createNewScene();
+ bool persistCurrentScene();
+ bool persistScenes();
+
+// helper methods
+ void repositionSvgItem(QGraphicsItem *item, qreal width, qreal height,
+ qreal x, qreal y,
+ QTransform &transform);
+ QColor colorFromString(const QString& clrString);
+ QTransform transformFromString(const QString trString, QGraphicsItem *item = 0);
+ bool getViewBoxDimenstions(const QString& viewBox);
+ QSvgGenerator* createSvgGenerator(qreal width, qreal height);
+ bool getTempFileName();
+ inline bool strToBool(QString);
+ bool createTempFlashPath();
+ };
+};
+
+#endif // UBCFFSUBSETADAPTOR_H
diff --git a/src/adaptors/UBExportAdaptor.h b/src/adaptors/UBExportAdaptor.h
index d80f34f9..a7e7ff6a 100644
--- a/src/adaptors/UBExportAdaptor.h
+++ b/src/adaptors/UBExportAdaptor.h
@@ -36,7 +36,7 @@ class UBDocumentProxy;
class UBExportAdaptor : public QObject
{
- Q_OBJECT;
+ Q_OBJECT
public:
UBExportAdaptor(QObject *parent = 0);
@@ -46,6 +46,9 @@ class UBExportAdaptor : public QObject
virtual QString exportExtention() { return "";}
virtual void persist(UBDocumentProxy* pDocument) = 0;
virtual bool persistsDocument(UBDocumentProxy* pDocument, const QString& filename);
+ virtual bool associatedActionactionAvailableFor(const QModelIndex &selectedIndex) {Q_UNUSED(selectedIndex); return false;}
+ QAction *associatedAction() {return mAssociatedAction;}
+ void setAssociatedAction(QAction *pAssociatedAction) {mAssociatedAction = pAssociatedAction;}
virtual void setVerbose(bool verbose)
{
@@ -66,6 +69,7 @@ class UBExportAdaptor : public QObject
void showErrorsList(QList errorsList);
bool mIsVerbose;
+ QAction* mAssociatedAction;
};
diff --git a/src/adaptors/UBExportCFF.cpp b/src/adaptors/UBExportCFF.cpp
new file mode 100644
index 00000000..b036b2a1
--- /dev/null
+++ b/src/adaptors/UBExportCFF.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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 .
+ */
+
+
+
+#include "UBExportCFF.h"
+#include "UBCFFAdaptor.h"
+#include "document/UBDocumentProxy.h"
+#include "core/UBDocumentManager.h"
+#include "core/UBApplication.h"
+#include "core/memcheck.h"
+#include "document/UBDocumentController.h"
+
+#include
+#include
+
+
+UBExportCFF::UBExportCFF(QObject *parent)
+: UBExportAdaptor(parent)
+{
+
+}
+
+UBExportCFF::~UBExportCFF()
+{
+
+}
+QString UBExportCFF::exportName()
+{
+ return tr("Export to IWB");
+}
+
+QString UBExportCFF::exportExtention()
+{
+ return QString(".iwb");
+}
+
+void UBExportCFF::persist(UBDocumentProxy* pDocument)
+{
+ QString src = pDocument->persistencePath();
+
+ if (!pDocument)
+ return;
+
+ QString filename = askForFileName(pDocument, tr("Export as IWB File"));
+
+ if (filename.length() > 0)
+ {
+ QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+
+ if (mIsVerbose)
+ UBApplication::showMessage(tr("Exporting document..."));
+
+ UBCFFAdaptor toIWBExporter;
+ if (toIWBExporter.convertUBZToIWB(src, filename))
+ {
+ if (mIsVerbose)
+ UBApplication::showMessage(tr("Export successful."));
+ }
+ else
+ if (mIsVerbose)
+ UBApplication::showMessage(tr("Export failed."));
+
+ showErrorsList(toIWBExporter.getConversionMessages());
+
+ QApplication::restoreOverrideCursor();
+
+ }
+
+
+}
+
+bool UBExportCFF::associatedActionactionAvailableFor(const QModelIndex &selectedIndex)
+{
+ const UBDocumentTreeModel *docModel = qobject_cast(selectedIndex.model());
+ if (!selectedIndex.isValid() || docModel->isCatalog(selectedIndex)) {
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/adaptors/UBExportCFF.h b/src/adaptors/UBExportCFF.h
new file mode 100644
index 00000000..ce103e28
--- /dev/null
+++ b/src/adaptors/UBExportCFF.h
@@ -0,0 +1,49 @@
+/*
+ * 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 .
+ */
+
+
+
+#ifndef UBExportCFF_H_
+#define UBExportCFF_H_
+
+#include
+
+#include "UBExportAdaptor.h"
+
+#include "frameworks/UBFileSystemUtils.h"
+
+class UBDocumentProxy;
+
+class UBExportCFF : public UBExportAdaptor
+{
+ Q_OBJECT
+
+public:
+ UBExportCFF(QObject *parent = 0);
+ virtual ~UBExportCFF();
+
+ virtual QString exportName();
+ virtual QString exportExtention();
+ virtual void persist(UBDocumentProxy* pDocument);
+ virtual bool associatedActionactionAvailableFor(const QModelIndex &selectedIndex);
+};
+
+#endif /* UBExportCFF_H_ */
diff --git a/src/adaptors/UBExportDocumentSetAdaptor.cpp b/src/adaptors/UBExportDocumentSetAdaptor.cpp
new file mode 100644
index 00000000..87738391
--- /dev/null
+++ b/src/adaptors/UBExportDocumentSetAdaptor.cpp
@@ -0,0 +1,198 @@
+/*
+ * 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 .
+ */
+
+
+#include "UBExportDocumentSetAdaptor.h"
+#include "UBExportDocument.h"
+
+#include "frameworks/UBPlatformUtils.h"
+
+#include "core/UBDocumentManager.h"
+#include "core/UBApplication.h"
+
+#include "document/UBDocumentProxy.h"
+#include "document/UBDocumentController.h"
+
+#include "globals/UBGlobals.h"
+#include "core/UBPersistenceManager.h"
+#include "core/UBForeignObjectsHandler.h"
+
+THIRD_PARTY_WARNINGS_DISABLE
+#include "quazip.h"
+#include "quazipfile.h"
+THIRD_PARTY_WARNINGS_ENABLE
+
+#include "core/memcheck.h"
+
+UBExportDocumentSetAdaptor::UBExportDocumentSetAdaptor(QObject *parent)
+ : UBExportAdaptor(parent)
+{
+
+}
+
+UBExportDocumentSetAdaptor::~UBExportDocumentSetAdaptor()
+{
+ // NOOP
+}
+
+void UBExportDocumentSetAdaptor::persist(UBDocumentProxy* pDocumentProxy)
+{
+ QModelIndex treeViewParentIndex;
+ UBPersistenceManager *persistenceManager = UBPersistenceManager::persistenceManager();
+ UBDocumentTreeModel *treeModel = persistenceManager->mDocumentTreeStructureModel;
+ QString filename;
+
+ if (pDocumentProxy) {
+ treeViewParentIndex = treeModel->indexForProxy(pDocumentProxy);
+ if (!treeViewParentIndex.isValid()) {
+ qDebug() << "failed to export";
+ UBApplication::showMessage(tr("Failed to export..."));
+ return;
+ }
+ filename = askForFileName(pDocumentProxy, tr("Export as UBX File"));
+
+ } else {
+ treeViewParentIndex = UBApplication::documentController->firstSelectedTreeIndex();
+ if (!treeViewParentIndex.isValid()) {
+ qDebug() << "failed to export";
+ UBApplication::showMessage(tr("Failed to export..."));
+ return;
+ }
+
+ UBDocumentTreeNode* node = treeModel->nodeFromIndex(treeViewParentIndex);
+ UBDocumentProxy proxy;
+ proxy.setMetaData(UBSettings::documentName,node->displayName());
+ filename = askForFileName(&proxy, tr("Export as UBX File"));
+ }
+
+ if (filename.length() > 0)
+ {
+ QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+
+ if (mIsVerbose)
+ UBApplication::showMessage(tr("Exporting document..."));
+
+ if (persistData(treeViewParentIndex, filename)) {
+ if (mIsVerbose) {
+ UBApplication::showMessage(tr("Export successful."));
+ }
+ } else {
+ if (mIsVerbose) {
+ UBApplication::showMessage(tr("Export failed."));
+ }
+ }
+
+ QApplication::restoreOverrideCursor();
+ }
+}
+
+bool UBExportDocumentSetAdaptor::persistData(const QModelIndex &pRootIndex, QString filename)
+{
+ UBPersistenceManager *persistenceManager = UBPersistenceManager::persistenceManager();
+ UBDocumentTreeModel *treeModel = persistenceManager->mDocumentTreeStructureModel;
+
+ QModelIndex index = pRootIndex;
+
+ if (!index.isValid()) {
+ return false;
+ }
+
+ QuaZip zip(filename);
+ zip.setFileNameCodec("UTF-8");
+
+ if(!zip.open(QuaZip::mdCreate))
+ {
+ qWarning("Export failed. Cause: zip.open(): %d", zip.getZipError());
+ return false;
+ }
+
+ if (!addDocumentToZip(pRootIndex, treeModel, zip)) {
+ zip.close();
+ return false;
+ }
+
+ zip.close();
+ UBPlatformUtils::setFileType(filename, 0x5542647A /* UBdz */);
+
+ return true;
+}
+
+QString UBExportDocumentSetAdaptor::exportExtention()
+{
+ return QString(".ubx");
+}
+
+QString UBExportDocumentSetAdaptor::exportName()
+{
+ return tr("Export to Sankore UBX Format");
+}
+
+bool UBExportDocumentSetAdaptor::addDocumentToZip(const QModelIndex &pIndex, UBDocumentTreeModel *model, QuaZip &zip)
+{
+ static int i = 0;
+ i++;
+
+ QModelIndex parentIndex = pIndex;
+ if (!parentIndex.isValid()) {
+ return false;
+ }
+
+ UBDocumentProxy *pDocumentProxy = model->proxyForIndex(parentIndex);
+ if (pDocumentProxy) {
+
+// Q_ASSERT(QFileInfo(pDocumentProxy->persistencePath()).exists());
+// UBForeighnObjectsHandler cleaner;
+// cleaner.cure(pDocumentProxy->persistencePath());
+
+ //UniboardSankoreTransition document;
+ QString documentPath(pDocumentProxy->persistencePath());
+ //document.checkDocumentDirectory(documentPath);
+
+ QDir documentDir = QDir(pDocumentProxy->persistencePath());
+ QuaZipFile zipFile(&zip);
+ UBFileSystemUtils::compressDirInZip(documentDir, QFileInfo(documentPath).fileName() + "/", &zipFile, false);
+
+ if(zip.getZipError() != 0)
+ {
+ qWarning("Export failed. Cause: zip.close(): %d", zip.getZipError());
+ }
+ }
+
+ for (int i = 0; i < model->rowCount(parentIndex); ++i) {
+ QModelIndex curIndex = model->index(i, 0, parentIndex);
+ if (!addDocumentToZip(curIndex, model, zip)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool UBExportDocumentSetAdaptor::associatedActionactionAvailableFor(const QModelIndex &selectedIndex)
+{
+ const UBDocumentTreeModel *docModel = qobject_cast(selectedIndex.model());
+ if (!selectedIndex.isValid() || docModel->isDocument(selectedIndex)) {
+ return false;
+ }
+
+ return true;
+}
+
diff --git a/src/adaptors/UBExportDocumentSetAdaptor.h b/src/adaptors/UBExportDocumentSetAdaptor.h
new file mode 100644
index 00000000..8e463377
--- /dev/null
+++ b/src/adaptors/UBExportDocumentSetAdaptor.h
@@ -0,0 +1,60 @@
+/*
+ * 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 .
+ */
+
+
+#ifndef UBEXPORTDOCUMENTSETADAPTOR_H
+#define UBEXPORTDOCUMENTSETADAPTOR_H
+
+#include
+#include "UBExportAdaptor.h"
+#include "frameworks/UBFileSystemUtils.h"
+#include "globals/UBGlobals.h"
+
+THIRD_PARTY_WARNINGS_DISABLE
+#include "quazip.h"
+#include "quazipfile.h"
+THIRD_PARTY_WARNINGS_ENABLE
+
+class UBDocumentProxy;
+class UBDocumentTreeModel;
+
+
+class UBExportDocumentSetAdaptor : public UBExportAdaptor
+{
+ Q_OBJECT
+
+ public:
+ UBExportDocumentSetAdaptor(QObject *parent = 0);
+ virtual ~UBExportDocumentSetAdaptor();
+
+ virtual QString exportName();
+ virtual QString exportExtention();
+
+ virtual void persist(UBDocumentProxy* pDocument);
+ bool persistData(const QModelIndex &pRootIndex, QString filename);
+ bool addDocumentToZip(const QModelIndex &pIndex, UBDocumentTreeModel *model, QuaZip &zip);
+
+ virtual bool associatedActionactionAvailableFor(const QModelIndex &selectedIndex);
+
+
+};
+
+#endif // UBEXPORTDOCUMENTSETADAPTOR_H
diff --git a/src/adaptors/UBExportFullPDF.cpp b/src/adaptors/UBExportFullPDF.cpp
index 9b6684f0..d9bb03bc 100644
--- a/src/adaptors/UBExportFullPDF.cpp
+++ b/src/adaptors/UBExportFullPDF.cpp
@@ -43,6 +43,7 @@
#include "domain/UBGraphicsPDFItem.h"
#include "document/UBDocumentProxy.h"
+#include "document/UBDocumentController.h"
#include "pdf/GraphicsPDFItem.h"
@@ -265,6 +266,16 @@ bool UBExportFullPDF::persistsDocument(UBDocumentProxy* pDocumentProxy, const QS
return true;
}
+bool UBExportFullPDF::associatedActionactionAvailableFor(const QModelIndex &selectedIndex)
+{
+ const UBDocumentTreeModel *docModel = qobject_cast(selectedIndex.model());
+ if (!selectedIndex.isValid() || docModel->isCatalog(selectedIndex)) {
+ return false;
+ }
+
+ return true;
+}
+
QString UBExportFullPDF::exportExtention()
{
diff --git a/src/adaptors/UBExportFullPDF.h b/src/adaptors/UBExportFullPDF.h
index ffe214f1..e43886f8 100644
--- a/src/adaptors/UBExportFullPDF.h
+++ b/src/adaptors/UBExportFullPDF.h
@@ -47,6 +47,7 @@ class UBExportFullPDF : public UBExportAdaptor
virtual QString exportName();
virtual QString exportExtention();
virtual void persist(UBDocumentProxy* pDocument);
+ virtual bool associatedActionactionAvailableFor(const QModelIndex &selectedIndex);
virtual bool persistsDocument(UBDocumentProxy* pDocument, const QString& filename);
diff --git a/src/adaptors/UBExportPDF.cpp b/src/adaptors/UBExportPDF.cpp
index f8d22cdc..78e324af 100644
--- a/src/adaptors/UBExportPDF.cpp
+++ b/src/adaptors/UBExportPDF.cpp
@@ -44,6 +44,7 @@
#include "domain/UBGraphicsPDFItem.h"
#include "document/UBDocumentProxy.h"
+#include "document/UBDocumentController.h"
#include "pdf/GraphicsPDFItem.h"
@@ -65,6 +66,16 @@ void UBExportPDF::persist(UBDocumentProxy* pDocumentProxy)
persistLocally(pDocumentProxy, tr("Export as PDF File"));
}
+bool UBExportPDF::associatedActionactionAvailableFor(const QModelIndex &selectedIndex)
+{
+ const UBDocumentTreeModel *docModel = qobject_cast(selectedIndex.model());
+ if (!selectedIndex.isValid() || docModel->isCatalog(selectedIndex)) {
+ return false;
+ }
+
+ return true;
+}
+
bool UBExportPDF::persistsDocument(UBDocumentProxy* pDocumentProxy, const QString& filename)
{
diff --git a/src/adaptors/UBExportPDF.h b/src/adaptors/UBExportPDF.h
index 4980399a..694319a7 100644
--- a/src/adaptors/UBExportPDF.h
+++ b/src/adaptors/UBExportPDF.h
@@ -46,6 +46,7 @@ class UBExportPDF : public UBExportAdaptor
virtual QString exportName();
virtual QString exportExtention();
virtual void persist(UBDocumentProxy* pDocument);
+ virtual bool associatedActionactionAvailableFor(const QModelIndex &selectedIndex);
virtual bool persistsDocument(UBDocumentProxy* pDocument, const QString& filename);
};
diff --git a/src/adaptors/UBImportCFF.cpp b/src/adaptors/UBImportCFF.cpp
new file mode 100644
index 00000000..611b3168
--- /dev/null
+++ b/src/adaptors/UBImportCFF.cpp
@@ -0,0 +1,294 @@
+/*
+ * 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 .
+ */
+
+
+
+#include
+#include
+
+#include "core/UBApplication.h"
+#include "core/UBPersistenceManager.h"
+#include "core/UBDocumentManager.h"
+#include "core/UBPersistenceManager.h"
+#include "document/UBDocumentProxy.h"
+#include "domain/UBGraphicsPDFItem.h"
+#include "frameworks/UBFileSystemUtils.h"
+#include "pdf/PDFRenderer.h"
+
+#include "UBCFFSubsetAdaptor.h"
+#include "UBImportCFF.h"
+
+#include "globals/UBGlobals.h"
+
+THIRD_PARTY_WARNINGS_DISABLE
+#include "quazip.h"
+#include "quazipfile.h"
+#include "quazipfileinfo.h"
+THIRD_PARTY_WARNINGS_ENABLE
+
+#include "core/memcheck.h"
+
+UBImportCFF::UBImportCFF(QObject *parent)
+ : UBDocumentBasedImportAdaptor(parent)
+{
+ // NOOP
+}
+
+
+UBImportCFF::~UBImportCFF()
+{
+ // NOOP
+}
+
+
+QStringList UBImportCFF::supportedExtentions()
+{
+ return QStringList("iwb");
+}
+
+
+QString UBImportCFF::importFileFilter()
+{
+ QString filter = tr("Common File Format (");
+ QStringList formats = supportedExtentions();
+ bool isFirst = true;
+
+ foreach(QString format, formats)
+ {
+ if(isFirst)
+ isFirst = false;
+ else
+ filter.append(" ");
+
+ filter.append("*."+format);
+ }
+
+ filter.append(")");
+
+ return filter;
+}
+
+bool UBImportCFF::addFileToDocument(UBDocumentProxy* pDocument, const QFile& pFile)
+{
+ QFileInfo fi(pFile);
+ UBApplication::showMessage(tr("Importing file %1...").arg(fi.baseName()), true);
+
+ // first unzip the file to the correct place
+ //TODO create temporary path for iwb file content
+ QString path = QDir::tempPath();
+
+ QString documentRootFolder = expandFileToDir(pFile, path);
+ QString contentFile;
+ if (documentRootFolder.isEmpty()) //if file has failed to unzip it is probably just xml file
+ contentFile = pFile.fileName();
+ else //get path to content xml (according to iwbcff specification)
+ contentFile = documentRootFolder.append("/content.xml");
+
+ if(!contentFile.length()){
+ UBApplication::showMessage(tr("Import of file %1 failed.").arg(fi.baseName()));
+ return false;
+ }
+ else{
+ //TODO convert expanded CFF file content to the destination document
+ //create destination document proxy
+ //fill metadata and save
+ UBDocumentProxy* destDocument = new UBDocumentProxy(UBPersistenceManager::persistenceManager()->generateUniqueDocumentPath());
+ QDir dir;
+ dir.mkdir(destDocument->persistencePath());
+
+ //try to import cff to document
+ if (UBCFFSubsetAdaptor::ConvertCFFFileToUbz(contentFile, destDocument))
+ {
+ UBPersistenceManager::persistenceManager()->addDirectoryContentToDocument(destDocument->persistencePath(), pDocument);
+ UBFileSystemUtils::deleteDir(destDocument->persistencePath());
+ delete destDocument;
+ UBApplication::showMessage(tr("Import successful."));
+ return true;
+ }
+ else
+ {
+ UBFileSystemUtils::deleteDir(destDocument->persistencePath());
+ delete destDocument;
+ UBApplication::showMessage(tr("Import failed."));
+ return false;
+ }
+ }
+}
+
+QString UBImportCFF::expandFileToDir(const QFile& pZipFile, const QString& pDir)
+{
+ QuaZip zip(pZipFile.fileName());
+
+ if(!zip.open(QuaZip::mdUnzip)) {
+ qWarning() << "Import failed. Cause zip.open(): " << zip.getZipError();
+ return "";
+ }
+
+ zip.setFileNameCodec("UTF-8");
+ QuaZipFileInfo info;
+ QuaZipFile file(&zip);
+
+ //create unique cff document root fodler
+ //use current date/time and temp number for folder name
+ QString documentRootFolder;
+ int tmpNumber = 0;
+ QDir rootDir;
+ while (true) {
+ QString tempPath = QString("%1/sank%2.%3")
+ .arg(pDir)
+ .arg(QDateTime::currentDateTime().toString("dd_MM_yyyy_HH-mm"))
+ .arg(tmpNumber);
+ if (!rootDir.exists(tempPath)) {
+ documentRootFolder = tempPath;
+ break;
+ }
+ tmpNumber++;
+ if (tmpNumber == 100000) {
+ qWarning() << "Import failed. Failed to create temporary directory for iwb file";
+ return "";
+ }
+ }
+ if (!rootDir.mkdir(documentRootFolder)) {
+ qWarning() << "Import failed. Couse: failed to create temp folder for cff package";
+ }
+
+ QFile out;
+ char c;
+ for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) {
+ if(!zip.getCurrentFileInfo(&info)) {
+ //TOD UB 4.3 O display error to user or use crash reporter
+ qWarning() << "Import failed. Cause: getCurrentFileInfo(): " << zip.getZipError();
+ return "";
+ }
+// if(!file.open(QIODevice::ReadOnly)) {
+// qWarning() << "Import failed. Cause: file.open(): " << zip.getZipError();
+// return "";
+// }
+ file.open(QIODevice::ReadOnly);
+ if(file.getZipError()!= UNZ_OK) {
+ qWarning() << "Import failed. Cause: file.getFileName(): " << zip.getZipError();
+ return "";
+ }
+
+ 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();
+ return "";
+ }
+ if(!file.atEnd()) {
+ qWarning() << "Import failed. Cause: read all but not EOF";
+ return "";
+ }
+
+ file.close();
+
+ if(file.getZipError()!=UNZ_OK) {
+ qWarning() << "Import failed. Cause: file.close(): " << file.getZipError();
+ return "";
+ }
+ }
+
+ zip.close();
+
+ if(zip.getZipError()!=UNZ_OK) {
+ qWarning() << "Import failed. Cause: zip.close(): " << zip.getZipError();
+ return "";
+ }
+
+ return documentRootFolder;
+}
+
+
+UBDocumentProxy* UBImportCFF::importFile(const QFile& pFile, const QString& pGroup)
+{
+ Q_UNUSED(pGroup); // group is defined in the imported file
+
+ QFileInfo fi(pFile);
+ UBApplication::showMessage(tr("Importing file %1...").arg(fi.baseName()), true);
+
+ // first unzip the file to the correct place
+ //TODO create temporary path for iwb file content
+ QString path = QDir::tempPath();
+
+ QString documentRootFolder = expandFileToDir(pFile, path);
+ QString contentFile;
+ if (documentRootFolder.isEmpty())
+ //if file has failed to umzip it is probably just xml file
+ contentFile = pFile.fileName();
+ else
+ //get path to content xml
+ contentFile = QString("%1/content.xml").arg(documentRootFolder);
+
+ if(!contentFile.length()){
+ UBApplication::showMessage(tr("Import of file %1 failed.").arg(fi.baseName()));
+ return 0;
+ }
+ else{
+ //create destination document proxy
+ //fill metadata and save
+ UBDocumentProxy* destDocument = new UBDocumentProxy(UBPersistenceManager::persistenceManager()->generateUniqueDocumentPath());
+ QDir dir;
+ dir.mkdir(destDocument->persistencePath());
+ if (pGroup.length() > 0)
+ destDocument->setMetaData(UBSettings::documentGroupName, pGroup);
+ if (fi.baseName() > 0)
+ destDocument->setMetaData(UBSettings::documentName, fi.baseName());
+
+ destDocument->setMetaData(UBSettings::documentVersion, UBSettings::currentFileVersion);
+ destDocument->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime()));
+
+ UBDocumentProxy* newDocument = NULL;
+ //try to import cff to document
+ if (UBCFFSubsetAdaptor::ConvertCFFFileToUbz(contentFile, destDocument))
+ {
+ newDocument = UBPersistenceManager::persistenceManager()->createDocumentFromDir(destDocument->persistencePath()
+ ,""
+ ,""
+ ,false
+ ,false
+ ,true);
+
+ UBApplication::showMessage(tr("Import successful."));
+ }
+ else
+ {
+ UBFileSystemUtils::deleteDir(destDocument->persistencePath());
+ UBApplication::showMessage(tr("Import failed."));
+ }
+ delete destDocument;
+
+ if (documentRootFolder.length() != 0)
+ UBFileSystemUtils::deleteDir(documentRootFolder);
+ return newDocument;
+ }
+}
diff --git a/src/adaptors/UBImportCFF.h b/src/adaptors/UBImportCFF.h
new file mode 100644
index 00000000..d06b9d18
--- /dev/null
+++ b/src/adaptors/UBImportCFF.h
@@ -0,0 +1,50 @@
+/*
+ * 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 .
+ */
+
+
+
+#ifndef UBIMPORTCFF_H
+#define UBIMPORTCFF_H
+
+#include
+#include "UBImportAdaptor.h"
+
+class UBDocumentProxy;
+
+class UBImportCFF : public UBDocumentBasedImportAdaptor
+{
+ Q_OBJECT;
+
+ public:
+ UBImportCFF(QObject *parent = 0);
+ virtual ~UBImportCFF();
+
+ virtual QStringList supportedExtentions();
+ virtual QString importFileFilter();
+
+ virtual bool addFileToDocument(UBDocumentProxy* pDocument, const QFile& pFile);
+ virtual UBDocumentProxy* importFile(const QFile& pFile, const QString& pGroup);
+
+ private:
+ QString expandFileToDir(const QFile& pZipFile, const QString& pDir);
+};
+
+#endif // UBIMPORTCFF_H
diff --git a/src/adaptors/UBImportDocumentSetAdaptor.cpp b/src/adaptors/UBImportDocumentSetAdaptor.cpp
new file mode 100644
index 00000000..54888058
--- /dev/null
+++ b/src/adaptors/UBImportDocumentSetAdaptor.cpp
@@ -0,0 +1,205 @@
+/*
+ * 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 .
+ */
+
+
+#include "UBImportDocumentSetAdaptor.h"
+
+#include "document/UBDocumentProxy.h"
+
+#include "frameworks/UBFileSystemUtils.h"
+
+#include "core/UBApplication.h"
+#include "core/UBSettings.h"
+#include "core/UBPersistenceManager.h"
+
+#include "globals/UBGlobals.h"
+
+THIRD_PARTY_WARNINGS_DISABLE
+#include "quazip.h"
+#include "quazipfile.h"
+#include "quazipfileinfo.h"
+THIRD_PARTY_WARNINGS_ENABLE
+
+#include "core/memcheck.h"
+
+UBImportDocumentSetAdaptor::UBImportDocumentSetAdaptor(QObject *parent)
+ :UBImportAdaptor(parent)
+{
+ // NOOP
+}
+
+UBImportDocumentSetAdaptor::~UBImportDocumentSetAdaptor()
+{
+ // NOOP
+}
+
+
+QStringList UBImportDocumentSetAdaptor::supportedExtentions()
+{
+ return QStringList("ubx");
+}
+
+
+QString UBImportDocumentSetAdaptor::importFileFilter()
+{
+ return tr("Open-Sankore (set of documents) (*.ubx)");
+}
+
+QFileInfoList UBImportDocumentSetAdaptor::importData(const QString &zipFile, const QString &destination)
+{
+ //Create tmp directory to extract data, will be deleted after
+ QString tmpDir;
+ int i = 0;
+ QFileInfoList result;
+ do {
+ tmpDir = QDir::tempPath() + "/Sankore_tmpImportUBX_" + QString::number(i++);
+ } while (QFileInfo(tmpDir).exists());
+
+ QDir(QDir::tempPath()).mkdir(tmpDir);
+
+ QFile fZipFile(zipFile);
+
+ if (!extractFileToDir(fZipFile, tmpDir)) {
+ UBFileSystemUtils::deleteDir(tmpDir);
+ return QFileInfoList();
+ }
+
+ QDir tDir(tmpDir);
+
+ foreach(QFileInfo readDir, tDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden , QDir::Name)) {
+ QString newFileName = readDir.fileName();
+ if (QFileInfo(destination + "/" + readDir.fileName()).exists()) {
+ newFileName = QFileInfo(UBPersistenceManager::persistenceManager()->generateUniqueDocumentPath(tmpDir)).fileName();
+ }
+ QString newFilePath = destination + "/" + newFileName;
+ if (UBFileSystemUtils::copy(readDir.absoluteFilePath(), newFilePath)) {
+ result.append(newFilePath);
+ }
+ }
+
+ UBFileSystemUtils::deleteDir(tmpDir);
+
+ return result;
+}
+
+
+bool UBImportDocumentSetAdaptor::extractFileToDir(const QFile& pZipFile, const QString& pDir)
+{
+ QDir rootDir(pDir);
+ QuaZip zip(pZipFile.fileName());
+
+ if(!zip.open(QuaZip::mdUnzip))
+ {
+ qWarning() << "Import failed. Cause zip.open(): " << zip.getZipError();
+ return false;
+ }
+
+ zip.setFileNameCodec("UTF-8");
+ QuaZipFileInfo info;
+ QuaZipFile file(&zip);
+
+ QFile out;
+ char c;
+
+ QString documentRoot = QFileInfo(pDir).absoluteFilePath();
+ for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile())
+ {
+ if(!zip.getCurrentFileInfo(&info))
+ {
+ //TOD UB 4.3 O display error to user or use crash reporter
+ qWarning() << "Import failed. Cause: getCurrentFileInfo(): " << zip.getZipError();
+ return false;
+ }
+
+ if(!file.open(QIODevice::ReadOnly))
+ {
+ qWarning() << "Import failed. Cause: file.open(): " << zip.getZipError();
+ return false;
+ }
+
+ if(file.getZipError()!= UNZ_OK)
+ {
+ qWarning() << "Import failed. Cause: file.getFileName(): " << zip.getZipError();
+ return false;
+ }
+
+ QString actFileName = file.getActualFileName();
+// int ind = actFileName.indexOf("/");
+// if ( ind!= -1) {
+// actFileName.remove(0, ind + 1);
+// }
+ QString newFileName = documentRoot + "/" + actFileName;
+ QFileInfo newFileInfo(newFileName);
+ if (!rootDir.mkpath(newFileInfo.absolutePath()))
+ return false;
+
+ out.setFileName(newFileName);
+ if (!out.open(QIODevice::WriteOnly))
+ return false;
+
+ // Slow like hell (on GNU/Linux at least), but it is not my fault.
+ // Not ZIP/UNZIP package's fault either.
+ // The slowest thing here is out.putChar(c).
+ QByteArray outFileContent = file.readAll();
+ if (out.write(outFileContent) == -1)
+ {
+ qWarning() << "Import failed. Cause: Unable to write file";
+ out.close();
+ return false;
+ }
+
+ while(file.getChar(&c))
+ out.putChar(c);
+
+ out.close();
+
+ if(file.getZipError()!=UNZ_OK)
+ {
+ qWarning() << "Import failed. Cause: " << zip.getZipError();
+ return false;
+ }
+
+ if(!file.atEnd())
+ {
+ qWarning() << "Import failed. Cause: read all but not EOF";
+ return false;
+ }
+
+ file.close();
+
+ if(file.getZipError()!=UNZ_OK)
+ {
+ qWarning() << "Import failed. Cause: file.close(): " << file.getZipError();
+ return false;
+ }
+
+ }
+
+ zip.close();
+
+ if(zip.getZipError()!=UNZ_OK)
+ {
+ qWarning() << "Import failed. Cause: zip.close(): " << zip.getZipError();
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/adaptors/UBImportDocumentSetAdaptor.h b/src/adaptors/UBImportDocumentSetAdaptor.h
new file mode 100644
index 00000000..7e07cfc5
--- /dev/null
+++ b/src/adaptors/UBImportDocumentSetAdaptor.h
@@ -0,0 +1,52 @@
+/*
+ * 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 .
+ */
+
+
+#ifndef UBIMPORTDOCUMENTSETADAPTOR_H
+#define UBIMPORTDOCUMENTSETADAPTOR_H
+
+#include
+#include "UBImportAdaptor.h"
+
+class UBDocumentProxy;
+
+class UBImportDocumentSetAdaptor : public UBImportAdaptor
+{
+ Q_OBJECT
+
+ public:
+ UBImportDocumentSetAdaptor(QObject *parent = 0);
+ virtual ~UBImportDocumentSetAdaptor();
+
+ virtual QStringList supportedExtentions();
+ virtual QString importFileFilter();
+
+ QFileInfoList importData(const QString &zipFile, const QString &destination);
+
+// virtual UBDocumentProxy* importFile(const QFile& pFile, const QString& pGroup);
+// virtual bool addFileToDocument(UBDocumentProxy* pDocument, const QFile& pFile);
+
+ private:
+ bool extractFileToDir(const QFile& pZipFile, const QString& pDir);
+
+};
+
+#endif // UBIMPORTDOCUMENTSETADAPTOR_H
diff --git a/src/adaptors/UBWebPublisher.cpp b/src/adaptors/UBWebPublisher.cpp
new file mode 100644
index 00000000..717dbc65
--- /dev/null
+++ b/src/adaptors/UBWebPublisher.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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 .
+ */
+
+
+
+#include "UBWebPublisher.h"
+
+#include "document/UBDocumentProxy.h"
+#include "document/UBDocumentController.h"
+
+#include "adaptors/publishing/UBDocumentPublisher.h"
+
+#include "core/memcheck.h"
+
+UBWebPublisher::UBWebPublisher(QObject *parent)
+ : UBExportAdaptor(parent)
+{
+ // NOOP
+}
+
+
+UBWebPublisher::~UBWebPublisher()
+{
+ // NOOP
+}
+
+
+QString UBWebPublisher::exportName()
+{
+ return tr("Publish Document on Sankore Web");
+}
+
+
+void UBWebPublisher::persist(UBDocumentProxy* pDocumentProxy)
+{
+ if (!pDocumentProxy)
+ return;
+
+ //UniboardSankoreTransition document;
+ QString documentPath(pDocumentProxy->persistencePath());
+ //document.checkDocumentDirectory(documentPath);
+
+ UBDocumentPublisher* publisher = new UBDocumentPublisher(pDocumentProxy, this); // the publisher will self delete when publication finishes
+ publisher->publish();
+
+}
+
+bool UBWebPublisher::associatedActionactionAvailableFor(const QModelIndex &selectedIndex)
+{
+ const UBDocumentTreeModel *docModel = qobject_cast(selectedIndex.model());
+ if (!selectedIndex.isValid() || docModel->isCatalog(selectedIndex)) {
+ return false;
+ }
+
+ return true;
+}
+
+
diff --git a/src/adaptors/UBWebPublisher.h b/src/adaptors/UBWebPublisher.h
new file mode 100644
index 00000000..d2ac5147
--- /dev/null
+++ b/src/adaptors/UBWebPublisher.h
@@ -0,0 +1,53 @@
+/*
+ * 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 .
+ */
+
+
+
+#ifndef UBWEBPUBLISHER_H_
+#define UBWEBPUBLISHER_H_
+
+#include
+
+#include "UBExportAdaptor.h"
+
+#include "frameworks/UBFileSystemUtils.h"
+#include "ui_webPublishing.h"
+
+class UBDocumentProxy;
+class UBServerXMLHttpRequest;
+
+class UBWebPublisher : public UBExportAdaptor
+{
+ Q_OBJECT
+
+ public:
+ UBWebPublisher(QObject *parent = 0);
+ virtual ~UBWebPublisher();
+
+ virtual QString exportName();
+
+ virtual void persist(UBDocumentProxy* pDocument);
+
+ virtual bool associatedActionactionAvailableFor(const QModelIndex &selectedIndex);
+};
+
+
+#endif /* UBWEBPUBLISHER_H_ */
diff --git a/src/adaptors/adaptors.pri b/src/adaptors/adaptors.pri
index e21ac2ba..ed1d0c60 100644
--- a/src/adaptors/adaptors.pri
+++ b/src/adaptors/adaptors.pri
@@ -12,7 +12,13 @@ HEADERS += src/adaptors/UBExportAdaptor.h\
src/adaptors/UBImportImage.h \
src/adaptors/UBExportWeb.h \
src/adaptors/publishing/UBDocumentPublisher.h \
- src/adaptors/publishing/UBSvgSubsetRasterizer.h
+ src/adaptors/publishing/UBSvgSubsetRasterizer.h \
+ $$PWD/UBExportDocumentSetAdaptor.h \
+ $$PWD/UBImportDocumentSetAdaptor.h \
+ $$PWD/UBExportCFF.h \
+ $$PWD/UBImportCFF.h \
+ $$PWD/UBWebPublisher.h \
+ $$PWD/UBCFFSubsetAdaptor.h
SOURCES += src/adaptors/UBExportAdaptor.cpp\
@@ -28,4 +34,10 @@ SOURCES += src/adaptors/UBExportAdaptor.cpp\
src/adaptors/UBImportImage.cpp \
src/adaptors/UBExportWeb.cpp \
src/adaptors/publishing/UBDocumentPublisher.cpp\
- src/adaptors/publishing/UBSvgSubsetRasterizer.cpp
+ src/adaptors/publishing/UBSvgSubsetRasterizer.cpp \
+ $$PWD/UBExportDocumentSetAdaptor.cpp \
+ $$PWD/UBImportDocumentSetAdaptor.cpp \
+ $$PWD/UBExportCFF.cpp \
+ $$PWD/UBImportCFF.cpp \
+ $$PWD/UBWebPublisher.cpp \
+ $$PWD/UBCFFSubsetAdaptor.cpp
diff --git a/src/adaptors/publishing/UBDocumentPublisher.cpp b/src/adaptors/publishing/UBDocumentPublisher.cpp
index 991486b0..6ada645f 100644
--- a/src/adaptors/publishing/UBDocumentPublisher.cpp
+++ b/src/adaptors/publishing/UBDocumentPublisher.cpp
@@ -1,35 +1,669 @@
/*
- * Copyright (C) 2015-2016 Département de l'Instruction Publique (DIP-SEM)
+ * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour l'Education Numérique en Afrique (GIP ENA)
*
- * Copyright (C) 2013 Open Education Foundation
+ * This file is part of Open-Sankoré.
*
- * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour
- * l'Education Numérique en Afrique (GIP ENA)
- *
- * This file is part of OpenBoard.
- *
- * OpenBoard is free software: you can redistribute it and/or modify
+ * 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).
*
- * OpenBoard is distributed in the hope that it will be useful,
+ * 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
+ * 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 OpenBoard. If not, see .
+ * along with Open-Sankoré. If not, see .
*/
+#include
-#include
#include "UBDocumentPublisher.h"
+#include "frameworks/UBPlatformUtils.h"
+#include "frameworks/UBFileSystemUtils.h"
+#include "frameworks/UBStringUtils.h"
+
+#include "network/UBNetworkAccessManager.h"
+#include "network/UBServerXMLHttpRequest.h"
+
+#include "core/UBDocumentManager.h"
+#include "core/UBApplication.h"
+#include "core/UBPersistenceManager.h"
+#include "core/UBApplicationController.h"
+
+#include "board/UBBoardController.h"
+
+#include "gui/UBMainWindow.h"
+
+#include "document/UBDocumentProxy.h"
+#include "document/UBDocumentContainer.h"
+
+#include "domain/UBGraphicsWidgetItem.h"
+
+#include "globals/UBGlobals.h"
+
+THIRD_PARTY_WARNINGS_DISABLE
+#include "quazip.h"
+#include "quazipfile.h"
+THIRD_PARTY_WARNINGS_ENABLE
+
+#include "adaptors/UBExportFullPDF.h"
+#include "adaptors/UBExportDocument.h"
+#include "adaptors/UBSvgSubsetAdaptor.h"
+
+#include "UBSvgSubsetRasterizer.h"
+
+#include "../../core/UBApplication.h"
+
+#include "core/memcheck.h"
+
+
+UBDocumentPublisher::UBDocumentPublisher(UBDocumentProxy* pDocument, QObject *parent)
+ : QObject(parent)
+ , mSourceDocument(pDocument)
+ , mUsername("")
+ , mPassword("")
+ , bLoginCookieSet(false)
+{
+ init();
+}
+
+
+UBDocumentPublisher::~UBDocumentPublisher()
+{
+}
+
+
+void UBDocumentPublisher::publish()
+{
+ //check that the username and password are stored on preferences
+ UBSettings* settings = UBSettings::settings();
+
+ if(settings->communityUsername().isEmpty() || settings->communityPassword().isEmpty()){
+ UBApplication::showMessage(tr("Credentials has to not been filled out yet."));
+ qDebug() << "trying to connect to community without the required credentials";
+ return;
+ }
+
+ mUsername = settings->communityUsername();
+ mPassword = settings->communityPassword();
+
+ UBPublicationDlg dlg;
+ if(QDialog::Accepted == dlg.exec())
+ {
+ mDocInfos.title = dlg.title();
+ mDocInfos.description = dlg.description();
+
+ buildUbwFile();
+
+ UBApplication::showMessage(tr("Uploading Sankore File on Web."));
+
+ sendUbw(mUsername, mPassword);
+ }
+}
+
+void UBDocumentPublisher::buildUbwFile()
+{
+ QDir d;
+ d.mkpath(UBFileSystemUtils::defaultTempDirPath());
+
+ QString tmpDir = UBFileSystemUtils::createTempDir();
+
+ if (UBFileSystemUtils::copyDir(mSourceDocument->persistencePath(), tmpDir))
+ {
+ QString documentName = mSourceDocument->name();
+ //remove all the directory separators from the document name.
+ //we do not want to interperete them as directory separator
+ documentName = documentName.replace("/",".").replace("\\",".");
+ documentName = documentName.replace(":","-");
+ mPublishingPath = tmpDir;
+ mPublishingSize = mSourceDocument->pageCount();
+
+ rasterizeScenes();
+
+ upgradeDocumentForPublishing();
+
+ UBExportFullPDF pdfExporter;
+ pdfExporter.setVerbose(false);
+ pdfExporter.persistsDocument(mSourceDocument, mPublishingPath + "/" + documentName + ".pdf");
+
+ UBExportDocument ubzExporter;
+ ubzExporter.setVerbose(false);
+ ubzExporter.persistsDocument(mSourceDocument, mPublishingPath + "/" + documentName + ".ubz");
+
+ // remove all useless files
+
+ for (int pageIndex = 0; pageIndex < mPublishingSize; pageIndex++) {
+ QString filename = mPublishingPath + UBFileSystemUtils::digitFileFormat("/page%1.svg",pageIndex);
+
+ QFile::remove(filename);
+ }
+
+ UBFileSystemUtils::deleteDir(mPublishingPath + "/" + UBPersistenceManager::imageDirectory);
+ UBFileSystemUtils::deleteDir(mPublishingPath + "/" + UBPersistenceManager::objectDirectory);
+ UBFileSystemUtils::deleteDir(mPublishingPath + "/" + UBPersistenceManager::videoDirectory);
+ UBFileSystemUtils::deleteDir(mPublishingPath + "/" + UBPersistenceManager::audioDirectory);
+
+ mTmpZipFile = UBFileSystemUtils::defaultTempDirPath() + "/" + UBStringUtils::toCanonicalUuid(QUuid::createUuid()) + ".ubw";
+
+ QuaZip zip(mTmpZipFile);
+ zip.setFileNameCodec("UTF-8");
+ if (!zip.open(QuaZip::mdCreate))
+ {
+ qWarning() << "Export failed. Cause: zip.open(): " << zip.getZipError() << "," << mTmpZipFile;
+ QApplication::restoreOverrideCursor();
+ return;
+ }
+
+ QuaZipFile outFile(&zip);
+
+ if (!UBFileSystemUtils::compressDirInZip(mPublishingPath, "", &outFile, true))
+ {
+ qWarning("Export failed. compressDirInZip failed ...");
+ zip.close();
+ UBApplication::showMessage(tr("Export failed."));
+ QApplication::restoreOverrideCursor();
+ return;
+ }
+
+ if (zip.getZipError() != 0)
+ {
+ qWarning("Export failed. Cause: zip.close(): %d", zip.getZipError());
+ zip.close();
+ UBApplication::showMessage(tr("Export failed."));
+ QApplication::restoreOverrideCursor();
+ return;
+ }
+
+ zip.close();
+
+ }
+ else
+ {
+ UBApplication::showMessage(tr("Export canceled ..."));
+ QApplication::restoreOverrideCursor();
+ }
+}
+
+void UBDocumentPublisher::rasterizeScenes()
+{
+
+ for (int pageIndex = 0; pageIndex < mPublishingSize; pageIndex++)
+ {
+ UBApplication::showMessage(tr("Converting page %1/%2 ...").arg(UBDocumentContainer::pageFromSceneIndex(pageIndex)).arg(mPublishingSize), true);
+
+ UBDocumentProxy publishingDocument(mPublishingPath);
+ UBSvgSubsetRasterizer rasterizer(&publishingDocument, pageIndex);
+
+ QString filename = mPublishingPath + UBFileSystemUtils::digitFileFormat("/page%1.jpg",pageIndex);
+
+ rasterizer.rasterizeToFile(filename);
+
+ }
+}
+
+
+void UBDocumentPublisher::updateGoogleMapApiKey()
+{
+ /*
+ QDir widgestDir(mPublishingPath + "/" + UBPersistenceManager::widgetDirectory);
+
+ QString uniboardWebGoogleMapApiKey = UBSettings::settings()->uniboardWebGoogleMapApiKey->get().toString();
+
+ foreach(QFileInfo dirInfo, widgestDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot))
+ {
+ QString config = UBFileSystemUtils::readTextFile(dirInfo.absoluteFilePath() + "/config.xml").toLower();
+
+ if (config.contains("google") && config.contains("map"))
+ {
+ QDir widgetDir(dirInfo.absoluteFilePath());
+
+ foreach(QFileInfo fileInfo, widgetDir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot))
+ {
+ QFile file(fileInfo.absoluteFilePath());
+
+ if (file.open(QIODevice::ReadWrite))
+ {
+ QTextStream stream(&file);
+ QString content = stream.readAll();
+
+ if (content.contains("ABQIAAAA6vtVqAUu8kZ_eTz7c8kwSBT9UCAhw_xm0LNFHsWmQxTJAdp5lxSY_5r-lZriY_7sACaMnl80JcX6Og"))
+ {
+ content.replace("ABQIAAAA6vtVqAUu8kZ_eTz7c8kwSBT9UCAhw_xm0LNFHsWmQxTJAdp5lxSY_5r-lZriY_7sACaMnl80JcX6Og",
+ uniboardWebGoogleMapApiKey);
+
+ file.resize(0);
+ file.write(content.toUtf8());
+ }
+ file.close();
+ }
+ }
+ }
+ }
+ */
+}
+
+
+void UBDocumentPublisher::upgradeDocumentForPublishing()
+{
+ for (int pageIndex = 0; pageIndex < mPublishingSize; pageIndex++)
+ {
+ UBDocumentProxy publishingDocument(mPublishingPath);
+ UBGraphicsScene *scene = UBSvgSubsetAdaptor::loadScene(&publishingDocument, pageIndex);
+
+ QList widgets;
+
+ foreach(QGraphicsItem* item, scene->items()){
+ UBGraphicsW3CWidgetItem *widgetItem = dynamic_cast(item);
+
+ if(widgetItem){
+ generateWidgetPropertyScript(widgetItem, UBDocumentContainer::pageFromSceneIndex(pageIndex));
+ widgets << widgetItem;
+ }
+ }
+
+ QString filename = mPublishingPath + UBFileSystemUtils::digitFileFormat("/page%1.json",pageIndex);
+
+ QFile jsonFile(filename);
+ if (jsonFile.open(QIODevice::WriteOnly | QIODevice::Truncate))
+ {
+ jsonFile.write("{\n");
+ jsonFile.write(QString(" \"scene\": {\n").toUtf8());
+ jsonFile.write(QString(" \"x\": %1,\n").arg(scene->normalizedSceneRect().x()).toUtf8());
+ jsonFile.write(QString(" \"y\": %1,\n").arg(scene->normalizedSceneRect().y()).toUtf8());
+ jsonFile.write(QString(" \"width\": %1,\n").arg(scene->normalizedSceneRect().width()).toUtf8());
+ jsonFile.write(QString(" \"height\": %1\n").arg(scene->normalizedSceneRect().height()).toUtf8());
+ jsonFile.write(QString(" },\n").toUtf8());
+
+ jsonFile.write(QString(" \"widgets\": [\n").toUtf8());
+
+ bool first = true;
+
+ foreach(UBGraphicsW3CWidgetItem* widget, widgets)
+ {
+ if (!first)
+ jsonFile.write(QString(" ,\n").toUtf8());
+ jsonFile.write(QString(" {\n").toUtf8());
+ jsonFile.write(QString(" \"uuid\": \"%1\",\n").arg(UBStringUtils::toCanonicalUuid(widget->uuid())).toUtf8());
+ jsonFile.write(QString(" \"id\": \"%1\",\n").arg(widget->metadatas().id).toUtf8());
+
+ jsonFile.write(QString(" \"name\": \"%1\",\n").arg(widget->metadatas().name).toUtf8());
+ jsonFile.write(QString(" \"description\": \"%1\",\n").arg(widget->metadatas().description).toUtf8());
+ jsonFile.write(QString(" \"author\": \"%1\",\n").arg(widget->metadatas().author).toUtf8());
+ jsonFile.write(QString(" \"authorEmail\": \"%1\",\n").arg(widget->metadatas().authorEmail).toUtf8());
+ jsonFile.write(QString(" \"authorHref\": \"%1\",\n").arg(widget->metadatas().authorHref).toUtf8());
+ jsonFile.write(QString(" \"version\": \"%1\",\n").arg(widget->metadatas().authorHref).toUtf8());
+
+ jsonFile.write(QString(" \"x\": %1,\n").arg(widget->sceneBoundingRect().x()).toUtf8());
+ jsonFile.write(QString(" \"y\": %1,\n").arg(widget->sceneBoundingRect().y()).toUtf8());
+ jsonFile.write(QString(" \"width\": %1,\n").arg(widget->sceneBoundingRect().width()).toUtf8());
+ jsonFile.write(QString(" \"height\": %1,\n").arg(widget->sceneBoundingRect().height()).toUtf8());
+
+ jsonFile.write(QString(" \"nominalWidth\": %1,\n").arg(widget->boundingRect().width()).toUtf8());
+ jsonFile.write(QString(" \"nominalHeight\": %1,\n").arg(widget->boundingRect().height()).toUtf8());
+
+ QString url = UBPersistenceManager::widgetDirectory + "/" + widget->uuid().toString() + ".wgt";
+ jsonFile.write(QString(" \"src\": \"%1\",\n").arg(url).toUtf8());
+ QString startFile = widget->mainHtmlFileName();
+ jsonFile.write(QString(" \"startFile\": \"%1\",\n").arg(startFile).toUtf8());
+
+ QMap preferences = widget->UBGraphicsWidgetItem::preferences();
+
+ jsonFile.write(QString(" \"preferences\": {\n").toUtf8());
+
+ foreach(QString key, preferences.keys())
+ {
+ QString sep = ",";
+ if (key == preferences.keys().last())
+ sep = "";
+
+ jsonFile.write(QString(" \"%1\": \"%2\"%3\n")
+ .arg(key)
+ .arg(preferences.value(key))
+ .arg(sep)
+ .toUtf8());
+ }
+ jsonFile.write(QString(" },\n").toUtf8());
+
+ jsonFile.write(QString(" \"datastore\": {\n").toUtf8());
+
+ QMap datastoreEntries = widget->datastoreEntries();
+
+ foreach(QString entry, datastoreEntries.keys())
+ {
+ QString sep = ",";
+ if (entry == datastoreEntries.keys().last())
+ sep = "";
+
+ jsonFile.write(QString(" \"%1\": \"%2\"%3\n")
+ .arg(entry)
+ .arg(datastoreEntries.value(entry))
+ .arg(sep)
+ .toUtf8());
+ }
+ jsonFile.write(QString(" }\n").toUtf8());
+
+ jsonFile.write(QString(" }\n").toUtf8());
+
+ first = false;
+ }
+
+ jsonFile.write(" ]\n");
+ jsonFile.write("}\n");
+ }
+ else
+ {
+ qWarning() << "Cannot open file" << filename << "for saving page state";
+ }
+
+ delete scene;
+ }
+
+ updateGoogleMapApiKey();
+}
+
+
+void UBDocumentPublisher::generateWidgetPropertyScript(UBGraphicsW3CWidgetItem *widgetItem, int pageNumber)
+{
+
+ QMap preferences = widgetItem->UBGraphicsWidgetItem::preferences();
+ QMap datastoreEntries = widgetItem->datastoreEntries();
+
+ QString startFileName = widgetItem->mainHtmlFileName();
+
+ if (!startFileName.startsWith("http://"))
+ {
+ QString startFilePath = mPublishingPath + "/" + UBPersistenceManager::widgetDirectory + "/" + widgetItem->uuid().toString() + ".wgt/" + startFileName;
+
+ QFile startFile(startFilePath);
+
+ if (startFile.exists())
+ {
+ if (startFile.open(QIODevice::ReadWrite))
+ {
+ QTextStream stream(&startFile);
+ QStringList lines;
+
+ bool addedJs = false;
+
+ QString line;
+ do
+ {
+ line = stream.readLine();
+ if (!line.isNull())
+ {
+ lines << line;
+
+ if (!addedJs && line.contains("") ) // TODO UB 4.6, this is naive ... the HEAD tag may be on several lines
+ {
+ lines << "";
+ lines << " ";
+ lines << "";
+
+ addedJs = true;
+ }
+ }
+ }
+ while (!line.isNull());
+
+ startFile.resize(0);
+ startFile.write(lines.join("\n").toUtf8()); // TODO UB 4.x detect real html encoding
+
+ startFile.close();
+ }
+ }
+ }
+ else{
+ qWarning() << "Remote Widget start file, cannot inject widget preferences and datastore entries";
+ }
+}
+
+void UBDocumentPublisher::init()
+{
+ mCrlf=0x0d;
+ mCrlf+=0x0a;
+ mDocInfos.title = "";
+ mDocInfos.description = "";
+
+ mpCookieJar = new QNetworkCookieJar();
+ mpNetworkMgr = new QNetworkAccessManager(this);
+
+ connect(mpNetworkMgr, SIGNAL(finished(QNetworkReply*)), this, SLOT(onFinished(QNetworkReply*)));
+}
+
+void UBDocumentPublisher::onFinished(QNetworkReply *reply)
+{
+ QVariant cookieHeader = reply->rawHeader("Set-Cookie");
+ // First we concatenate all the Set-Cookie values (the packet can contains many of them)
+ QStringList qslCookie = cookieHeader.toString().split("\n");
+ QString qsCookieValue = qslCookie.at(0);
+ for (int i = 1; i < qslCookie.size(); i++) {
+ qsCookieValue += "; " +qslCookie.at(i);
+ }
+
+ // Now we isolate every cookie value
+ QStringList qslCookieVals = qsCookieValue.split("; ");
+
+ bool bTransferOk = false;
+
+ for(int j = 0; j < qslCookieVals.size(); j++)
+ {
+ qDebug() << j << qslCookieVals.at(j);
+ if(qslCookieVals.at(j).startsWith("assetStatus"))
+ {
+ QStringList qslAsset = qslCookieVals.at(j).split("=");
+ if(qslAsset.at(1) == "UPLOADED")
+ {
+ bTransferOk = true;
+ break;
+ }
+ }
+ }
+
+ if(bTransferOk)
+ {
+ UBApplication::showMessage(tr("Document uploaded correctly on the web."));
+ }
+ else
+ {
+ UBApplication::showMessage(tr("Failed to upload document on the web."));
+ }
+
+ reply->deleteLater();
+}
+
+void UBDocumentPublisher::sendUbw(QString username, QString password)
+{
+ if (QFile::exists(mTmpZipFile))
+ {
+ QFile f(mTmpZipFile);
+ if (f.open(QIODevice::ReadOnly))
+ {
+ QFileInfo fi(f);
+ QByteArray ba = f.readAll();
+ QString boundary,data, multipartHeader;
+ QByteArray datatoSend;
+
+ boundary = "---WebKitFormBoundaryDKBTgA53MiyWrzLY";
+ multipartHeader = "multipart/form-data; boundary="+boundary;
+
+ data="--"+boundary+mCrlf;
+ data+="Content-Disposition: form-data; name=\"title\"" + mCrlf + mCrlf + mDocInfos.title + mCrlf;
+ data+="--"+boundary+mCrlf;
+ data+="Content-Disposition: form-data; name=\"description\"" + mCrlf + mCrlf + mDocInfos.description.remove("\n") + mCrlf;
+ data+="--"+boundary+mCrlf;
+ data+="Content-Disposition: form-data; name=\"file\"; filename=\""+ fi.fileName() +"\""+mCrlf;
+ data+="Content-Type: application/octet-stream"+mCrlf+mCrlf;
+ datatoSend=data.toLatin1(); // convert data string to byte array for request
+ datatoSend += ba;
+ datatoSend += mCrlf;
+ datatoSend += QString("--%0--%1").arg(boundary).arg(mCrlf);
+
+ QNetworkRequest request(QUrl(QString(DOCPUBLICATION_URL).toLatin1().constData()));
+
+ request.setHeader(QNetworkRequest::ContentTypeHeader, multipartHeader);
+ request.setHeader(QNetworkRequest::ContentLengthHeader,datatoSend.size());
+ QString b64Auth = getBase64Of(QString("%0:%1").arg(username).arg(password));
+ request.setRawHeader("Authorization", QString("Basic %0").arg(b64Auth).toLatin1().constData());
+ request.setRawHeader("Host", "planete.sankore.org");
+ request.setRawHeader("Accept", "*/*");
+ request.setRawHeader("Accept-Language", "en-US,*");
+
+ mpCookieJar->setCookiesFromUrl(mCookies, QUrl(DOCPUBLICATION_URL));
+ mpNetworkMgr->setCookieJar(mpCookieJar);
+
+ // Send the file
+ mpNetworkMgr->post(request,datatoSend);
+ }
+ }
+}
+
+QString UBDocumentPublisher::getBase64Of(QString stringToEncode)
+{
+ return stringToEncode.toLatin1().toBase64();
+}
+
+// ---------------------------------------------------------
UBProxyLoginDlg::UBProxyLoginDlg(QWidget *parent, const char *name):QDialog(parent)
, mpLayout(NULL)
, mpUserLayout(NULL)
diff --git a/src/adaptors/publishing/UBDocumentPublisher.h b/src/adaptors/publishing/UBDocumentPublisher.h
index 7ee2be65..89bf4a35 100644
--- a/src/adaptors/publishing/UBDocumentPublisher.h
+++ b/src/adaptors/publishing/UBDocumentPublisher.h
@@ -1,44 +1,34 @@
/*
- * Copyright (C) 2015-2016 Département de l'Instruction Publique (DIP-SEM)
+ * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour l'Education Numérique en Afrique (GIP ENA)
*
- * Copyright (C) 2013 Open Education Foundation
+ * This file is part of Open-Sankoré.
*
- * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour
- * l'Education Numérique en Afrique (GIP ENA)
- *
- * This file is part of OpenBoard.
- *
- * OpenBoard is free software: you can redistribute it and/or modify
+ * 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).
*
- * OpenBoard is distributed in the hope that it will be useful,
+ * 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
+ * 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 OpenBoard. If not, see .
+ * along with Open-Sankoré. If not, see .
*/
-
-
#ifndef UBDOCUMENTPUBLISHER_H
#define UBDOCUMENTPUBLISHER_H
#include
#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
+
+#include "ui_webPublishing.h"
+
+#define DOCPUBLICATION_URL "http://planete.sankore.org/xwiki/bin/view/CreateResources/UniboardUpload?xpage=plain&outputSyntax=plain"
typedef struct
{
@@ -94,4 +84,58 @@ private:
QTextEdit* mpDescription;
QDialogButtonBox* mpButtons;
};
+
+
+class UBDocumentPublisher : public QObject
+{
+ Q_OBJECT;
+
+public:
+ explicit UBDocumentPublisher(UBDocumentProxy* sourceDocument, QObject *parent = 0);
+ virtual ~UBDocumentPublisher();
+
+ void publish();
+
+signals:
+
+ void loginDone();
+
+protected:
+
+ virtual void updateGoogleMapApiKey();
+ virtual void rasterizeScenes();
+ virtual void upgradeDocumentForPublishing();
+ virtual void generateWidgetPropertyScript(UBGraphicsW3CWidgetItem *widgetItem, int pageNumber);
+
+private slots:
+
+ void onFinished(QNetworkReply* reply);
+
+private:
+
+ UBDocumentProxy *mSourceDocument;
+
+ //UBDocumentProxy *mPublishingDocument;
+ QString mPublishingPath;
+ int mPublishingSize;
+
+
+ void init();
+ void sendUbw(QString username, QString password);
+ QString getBase64Of(QString stringToEncode);
+
+ QHBoxLayout* mpLayout;
+ QNetworkAccessManager* mpNetworkMgr;
+ QNetworkCookieJar* mpCookieJar;
+ QString mUsername;
+ QString mPassword;
+ QString mCrlf;
+ bool bLoginCookieSet;
+
+ void buildUbwFile();
+ QString mTmpZipFile;
+ QList mCookies;
+ sDocumentInfos mDocInfos;
+
+};
#endif // UBDOCUMENTPUBLISHER_H
diff --git a/src/adaptors/publishing/UBSvgSubsetRasterizer.cpp b/src/adaptors/publishing/UBSvgSubsetRasterizer.cpp
index b0ca3d4e..458eb1c9 100644
--- a/src/adaptors/publishing/UBSvgSubsetRasterizer.cpp
+++ b/src/adaptors/publishing/UBSvgSubsetRasterizer.cpp
@@ -1,32 +1,26 @@
/*
- * Copyright (C) 2015-2016 Département de l'Instruction Publique (DIP-SEM)
+ * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour l'Education Numérique en Afrique (GIP ENA)
*
- * Copyright (C) 2013 Open Education Foundation
+ * This file is part of Open-Sankoré.
*
- * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour
- * l'Education Numérique en Afrique (GIP ENA)
- *
- * This file is part of OpenBoard.
- *
- * OpenBoard is free software: you can redistribute it and/or modify
+ * 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).
*
- * OpenBoard is distributed in the hope that it will be useful,
+ * 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
+ * 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 OpenBoard. If not, see .
+ * along with Open-Sankoré. If not, see .
*/
-
#include "UBSvgSubsetRasterizer.h"
#include "domain/UBGraphicsScene.h"
diff --git a/src/adaptors/publishing/UBSvgSubsetRasterizer.h b/src/adaptors/publishing/UBSvgSubsetRasterizer.h
index dcbe1e50..fcc40cff 100644
--- a/src/adaptors/publishing/UBSvgSubsetRasterizer.h
+++ b/src/adaptors/publishing/UBSvgSubsetRasterizer.h
@@ -1,32 +1,26 @@
/*
- * Copyright (C) 2015-2016 Département de l'Instruction Publique (DIP-SEM)
+ * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour l'Education Numérique en Afrique (GIP ENA)
*
- * Copyright (C) 2013 Open Education Foundation
+ * This file is part of Open-Sankoré.
*
- * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour
- * l'Education Numérique en Afrique (GIP ENA)
- *
- * This file is part of OpenBoard.
- *
- * OpenBoard is free software: you can redistribute it and/or modify
+ * 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).
*
- * OpenBoard is distributed in the hope that it will be useful,
+ * 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
+ * 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 OpenBoard. If not, see .
+ * along with Open-Sankoré. If not, see .
*/
-
#ifndef UBSVGSUBSETRASTERIZER_H_
#define UBSVGSUBSETRASTERIZER_H_
diff --git a/src/board/UBBoardController.cpp b/src/board/UBBoardController.cpp
index e9ba86c1..a93a5c07 100644
--- a/src/board/UBBoardController.cpp
+++ b/src/board/UBBoardController.cpp
@@ -854,7 +854,6 @@ void UBBoardController::blackout()
UBApplication::applicationController->blackout();
}
-
void UBBoardController::showKeyboard(bool show)
{
if(show)
@@ -1993,7 +1992,7 @@ void UBBoardController::persistCurrentScene(bool isAnAutomaticBackup, bool force
&& (mActiveSceneIndex >= 0) && mActiveSceneIndex != mMovingSceneIndex
&& (mActiveScene->isModified()))
{
- UBPersistenceManager::persistenceManager()->persistDocumentScene(selectedDocument(), mActiveScene, mActiveSceneIndex, isAnAutomaticBackup,forceImmediateSave);
+ UBPersistenceManager::persistenceManager()->persistDocumentScene(selectedDocument(), mActiveScene, mActiveSceneIndex);
updatePage(mActiveSceneIndex);
}
}
diff --git a/src/board/UBBoardController.h b/src/board/UBBoardController.h
index cc674ccc..513385f1 100644
--- a/src/board/UBBoardController.h
+++ b/src/board/UBBoardController.h
@@ -253,6 +253,8 @@ class UBBoardController : public UBDocumentContainer
void saveData(SaveFlags fls = sf_none);
+ //void regenerateThumbnails();
+
signals:
void newPageAdded();
void activeSceneChanged();
diff --git a/src/core/UBApplicationController.cpp b/src/core/UBApplicationController.cpp
index f3a6e199..fe9c8280 100644
--- a/src/core/UBApplicationController.cpp
+++ b/src/core/UBApplicationController.cpp
@@ -635,6 +635,7 @@ void UBApplicationController::mirroringEnabled(bool enabled)
}
+
void UBApplicationController::closing()
{
if (mMirror)
@@ -642,12 +643,18 @@ void UBApplicationController::closing()
if (mUninoteController)
{
+ mUninoteController->hideWindow();
mUninoteController->close();
}
+ /*
+
if (UBApplication::documentController)
UBApplication::documentController->closing();
+ */
+
+ UBPersistenceManager::persistenceManager()->closing(); // ALTI/AOU - 20140616 : to update the file "documents/folders.xml"
}
diff --git a/src/core/UBDocumentManager.cpp b/src/core/UBDocumentManager.cpp
index 6e95158c..114ec9b4 100644
--- a/src/core/UBDocumentManager.cpp
+++ b/src/core/UBDocumentManager.cpp
@@ -1,32 +1,26 @@
/*
- * Copyright (C) 2015-2016 Département de l'Instruction Publique (DIP-SEM)
+ * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour l'Education Numérique en Afrique (GIP ENA)
*
- * Copyright (C) 2013 Open Education Foundation
+ * This file is part of Open-Sankoré.
*
- * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour
- * l'Education Numérique en Afrique (GIP ENA)
- *
- * This file is part of OpenBoard.
- *
- * OpenBoard is free software: you can redistribute it and/or modify
+ * 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).
*
- * OpenBoard is distributed in the hope that it will be useful,
+ * 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
+ * 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 OpenBoard. If not, see .
+ * along with Open-Sankoré. If not, see .
*/
-
#include "UBDocumentManager.h"
#include "frameworks/UBStringUtils.h"
@@ -34,9 +28,14 @@
#include "adaptors/UBExportFullPDF.h"
#include "adaptors/UBExportDocument.h"
#include "adaptors/UBExportWeb.h"
+#include "adaptors/UBExportCFF.h"
+#include "adaptors/UBExportDocumentSetAdaptor.h"
+#include "adaptors/UBWebPublisher.h"
#include "adaptors/UBImportDocument.h"
#include "adaptors/UBImportPDF.h"
#include "adaptors/UBImportImage.h"
+#include "adaptors/UBImportCFF.h"
+#include "adaptors/UBImportDocumentSetAdaptor.h"
#include "domain/UBGraphicsScene.h"
#include "domain/UBGraphicsSvgItem.h"
@@ -50,6 +49,8 @@
#include "UBSettings.h"
#include "UBPersistenceManager.h"
+#include "../adaptors/UBExportWeb.h"
+
#include "core/memcheck.h"
UBDocumentManager* UBDocumentManager::sDocumentManager = 0;
@@ -73,17 +74,30 @@ UBDocumentManager::UBDocumentManager(QObject *parent)
QString dummyObjects = tr("objects");
QString dummyWidgets = tr("widgets");
+ UBExportCFF* cffExporter = new UBExportCFF(this);
UBExportFullPDF* exportFullPdf = new UBExportFullPDF(this);
UBExportDocument* exportDocument = new UBExportDocument(this);
+ UBWebPublisher* webPublished = new UBWebPublisher(this);
+ UBExportDocumentSetAdaptor *exportDocumentSet = new UBExportDocumentSetAdaptor(this);
mExportAdaptors.append(exportDocument);
+ mExportAdaptors.append(exportDocumentSet);
+ mExportAdaptors.append(webPublished);
mExportAdaptors.append(exportFullPdf);
+ mExportAdaptors.append(cffExporter);
+
+// UBExportWeb* exportWeb = new UBExportWeb(this);
+// mExportAdaptors.append(exportWeb);
UBImportDocument* documentImport = new UBImportDocument(this);
mImportAdaptors.append(documentImport);
+ UBImportDocumentSetAdaptor *documentSetImport = new UBImportDocumentSetAdaptor(this);
+ mImportAdaptors.append(documentSetImport);
UBImportPDF* pdfImport = new UBImportPDF(this);
mImportAdaptors.append(pdfImport);
UBImportImage* imageImport = new UBImportImage(this);
mImportAdaptors.append(imageImport);
+ UBImportCFF* cffImport = new UBImportCFF(this);
+ mImportAdaptors.append(cffImport);
}
@@ -93,38 +107,60 @@ UBDocumentManager::~UBDocumentManager()
}
-QStringList UBDocumentManager::importFileExtensions()
+QStringList UBDocumentManager::importFileExtensions(bool notUbx)
{
QStringList result;
foreach (UBImportAdaptor *importAdaptor, mImportAdaptors)
{
- result << importAdaptor->supportedExtentions();
+ //issue 1629 - NNE - 20131213 : add test to remove ubx extention if necessary
+ if(!(notUbx && importAdaptor->supportedExtentions().at(0) == "ubx")){
+ result << importAdaptor->supportedExtentions();
+ }
}
return result;
}
-QString UBDocumentManager::importFileFilter()
+QString UBDocumentManager::importFileFilter(bool notUbx)
{
QString result;
- result += tr("All supported files (*.%1)").arg(importFileExtensions().join(" *."));
+ result += tr("All supported files (*.%1)").arg(importFileExtensions(notUbx).join(" *."));
foreach (UBImportAdaptor *importAdaptor, mImportAdaptors)
{
if (importAdaptor->importFileFilter().length() > 0)
{
- if (result.length())
- {
- result += ";;";
+ //issue 1629 - NNE - 20131213 : Add a test on ubx before put in the list
+ if(!(notUbx && importAdaptor->supportedExtentions().at(0) == "ubx")){
+ if (result.length())
+ {
+ result += ";;";
+ }
+
+ result += importAdaptor->importFileFilter();
}
- result += importAdaptor->importFileFilter();
}
}
qDebug() << "import file filter" << result;
return result;
}
+QFileInfoList UBDocumentManager::importUbx(const QString &Incomingfile, const QString &destination)
+{
+ UBImportDocumentSetAdaptor *docSetAdaptor;
+ foreach (UBImportAdaptor *curAdaptor, mImportAdaptors) {
+ docSetAdaptor = qobject_cast(curAdaptor);
+ if (docSetAdaptor) {
+ break;
+ }
+ }
+ if (!docSetAdaptor) {
+ return QFileInfoList();
+ }
+
+ return docSetAdaptor->importData(Incomingfile, destination);
+}
UBDocumentProxy* UBDocumentManager::importFile(const QFile& pFile, const QString& pGroup)
{
@@ -150,7 +186,12 @@ UBDocumentProxy* UBDocumentManager::importFile(const QFile& pFile, const QString
// Document import procedure.....
QString documentName = QFileInfo(pFile.fileName()).completeBaseName();
- document = UBPersistenceManager::persistenceManager()->createDocument(pGroup, documentName,false);
+ document = UBPersistenceManager::persistenceManager()->createDocument(pGroup
+ ,documentName
+ , false // Issue 1630 - CFA - 201410503 - suppression de la page vide ajoutee à l'import des pdfs
+ , QString()
+ , 0
+ , true);
QUuid uuid = QUuid::createUuid();
QString filepath = pFile.fileName();
@@ -159,7 +200,6 @@ UBDocumentProxy* UBDocumentManager::importFile(const QFile& pFile, const QString
bool b = UBPersistenceManager::persistenceManager()->addFileToDocument(document, pFile.fileName(), importAdaptor->folderToCopy() , uuid, filepath);
if (!b)
{
- UBPersistenceManager::persistenceManager()->deleteDocument(document);
UBApplication::setDisabled(false);
return NULL;
}
@@ -169,8 +209,9 @@ UBDocumentProxy* UBDocumentManager::importFile(const QFile& pFile, const QString
int nPage = 0;
foreach(UBGraphicsItem* page, pages)
{
+
UBApplication::showMessage(tr("Inserting page %1 of %2").arg(++nPage).arg(pages.size()), true);
-#ifdef Q_OS_OSX
+#ifdef Q_WS_MACX
//Workaround for issue 912
QApplication::processEvents();
#endif
@@ -211,9 +252,11 @@ int UBDocumentManager::addFilesToDocument(UBDocumentProxy* document, QStringList
if (adaptor->isDocumentBased())
{
- UBDocumentBasedImportAdaptor* importAdaptor = (UBDocumentBasedImportAdaptor*)adaptor;
+ //issue 1629 - NNE - 20131212 : Resolve a segfault, but for .ubx, actually
+ //the file will be not imported...
+ UBDocumentBasedImportAdaptor* importAdaptor = dynamic_cast(adaptor);
- if (importAdaptor->addFileToDocument(document, file))
+ if (importAdaptor && importAdaptor->addFileToDocument(document, file))
nImportedDocuments++;
}
else
@@ -240,7 +283,7 @@ int UBDocumentManager::addFilesToDocument(UBDocumentProxy* document, QStringList
UBGraphicsScene* scene = UBPersistenceManager::persistenceManager()->createDocumentSceneAt(document, pageIndex);
importAdaptor->placeImportedItemToScene(scene, page);
UBPersistenceManager::persistenceManager()->persistDocumentScene(document, scene, pageIndex);
- UBApplication::boardController->addEmptyThumbPage();
+ UBApplication::boardController->insertThumbPage(pageIndex);
}
UBPersistenceManager::persistenceManager()->persistDocumentMetadata(document);
diff --git a/src/core/UBDocumentManager.h b/src/core/UBDocumentManager.h
index dd598e04..43f506f6 100644
--- a/src/core/UBDocumentManager.h
+++ b/src/core/UBDocumentManager.h
@@ -45,9 +45,12 @@ class UBDocumentManager : public QObject
static UBDocumentManager* documentManager();
virtual ~UBDocumentManager();
- QString importFileFilter();
- QStringList importFileExtensions();
+ QString importFileFilter(bool notUbx = false);
+
+ QStringList importFileExtensions(bool notUbx = false);
+
+ QFileInfoList importUbx(const QString &Incomingfile, const QString &destination);
UBDocumentProxy* importFile(const QFile& pFile, const QString& pGroup);
int addFilesToDocument(UBDocumentProxy* pDocument, QStringList fileNames);
diff --git a/src/core/UBForeignObjectsHandler.cpp b/src/core/UBForeignObjectsHandler.cpp
new file mode 100644
index 00000000..71620a23
--- /dev/null
+++ b/src/core/UBForeignObjectsHandler.cpp
@@ -0,0 +1,628 @@
+/*
+* 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 .
+*/
+
+#include "UBForeignObjectsHandler.h"
+
+#include
+#include
+#include "UBSettings.h"
+
+const QString tVideo = "video";
+const QString tAudio = "audio";
+const QString tImage = "image";
+const QString tForeignObject = "foreignObject";
+const QString tTeacherGuide = "teacherGuide";
+const QString tMedia = "media";
+const QString tGroups = "groups";
+
+const QString aHref = "xlink:href";
+const QString aType = "ub:type";
+const QString aReqExt = "requiredExtensions";
+const QString aSrc = "ub:src";
+const QString aMediaType = "mediaType";
+const QString aRelativePath = "relativePath";
+const QString aActionMedia = "ub:actionFirstParameter";
+
+const QString vText = "text";
+const QString vReqExt = "http://ns.adobe.com/pdf/1.3/";
+
+const QString wgtSuff = ".wgt";
+const QString thumbSuff = ".png";
+
+const QString scanDirs = "audios,images,videos,teacherGuideObjects,widgets";
+const QStringList trashFilter = QStringList() << "*.swf";
+
+static QString strIdFrom(const QString &filePath)
+{
+ if ((filePath).isEmpty()) {
+ return QString();
+ }
+
+ QRegExp rx("\\{.(?!.*\\{).*\\}");
+ if (rx.indexIn(filePath) == -1) {
+ return QString();
+ }
+
+ return rx.cap();
+}
+
+static bool rm_r(const QString &rmPath)
+{
+ QFileInfo fi(rmPath);
+ if (!fi.exists()) {
+ qDebug() << rmPath << "does not exist";
+ return false;
+ } else if (fi.isFile()) {
+ if (!QFile::remove(rmPath)) {
+ qDebug() << "can't remove file" << rmPath;
+ return false;
+ }
+ return true;
+ } else if (fi.isDir()) {
+ QFileInfoList fList = QDir(rmPath).entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot);
+ foreach (QFileInfo sub, fList) {
+ rm_r(sub.absoluteFilePath());
+ }
+ if (!QDir().rmdir(rmPath)) {
+ qDebug() << "can't remove dir" << rmPath;
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+static bool cp_rf(const QString &what, const QString &where)
+{
+ QFileInfo whatFi(what);
+ QFileInfo whereFi = QFileInfo(where);
+
+ if (!whatFi.exists()) {
+ qDebug() << what << "does not exist" << Q_FUNC_INFO;
+ return false;
+ } else if (whatFi.isFile()) {
+ QString whereDir = where.section("/", 0, -2, QString::SectionSkipEmpty | QString::SectionIncludeLeadingSep);
+ QString newFilePath = where;
+ if (!whereFi.exists()) {
+ QDir().mkpath(whereDir);
+ } else if (whereFi.isDir()) {
+ newFilePath = whereDir + "/" + whatFi.fileName();
+ }
+ if (QFile::exists(newFilePath)) {
+ QFile::remove(newFilePath);
+ }
+ if (!QFile::copy(what, newFilePath)) {
+ qDebug() << "can't copy" << what << "to" << where << Q_FUNC_INFO;
+ return false;
+ }
+ return true;
+ } else if (whatFi.isDir()) {
+
+ if (whereFi.isFile() && whereFi.fileName().toLower() == whatFi.fileName().toLower()) {
+ qDebug() << "can't copy dir" << what << "to file" << where << Q_FUNC_INFO;
+ return false;
+ } else if (whereFi.isDir()) {
+ rm_r(where);
+ }
+
+ QDir().mkpath(where);
+
+ QFileInfoList fList = QDir(what).entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot);
+ foreach (QFileInfo sub, fList) {
+ if (!cp_rf(sub.absoluteFilePath(), where + "/" + sub.fileName()))
+ return false;
+ }
+ return true;
+ }
+ return true;
+}
+
+static QString thumbFileNameFrom(const QString &filePath)
+{
+ if (filePath.isEmpty()) {
+ return QString();
+ }
+
+ QString thumbPath = filePath;
+ thumbPath.replace(QRegExp("[\\{\\}]"), "").replace(wgtSuff, thumbSuff);
+
+ return thumbPath;
+}
+
+
+QString svgPageName(int pageIndex)
+{
+ return QString("page%1.svg").arg(pageIndex, 3, 10, QLatin1Char('0'));
+}
+
+static QDomDocument createDomFromSvg(const QString &svgUrl)
+{
+ Q_ASSERT(QFile::exists(svgUrl));
+ QString mFoldersXmlStorageName = svgUrl;
+
+ if (QFileInfo(mFoldersXmlStorageName).exists()) {
+ QDomDocument xmlDom;
+ QFile inFile(mFoldersXmlStorageName);
+ if (inFile.open(QIODevice::ReadOnly)) {
+ QString domString(inFile.readAll());
+
+ int errorLine = 0; int errorColumn = 0;
+ QString errorStr;
+
+ if (xmlDom.setContent(domString, &errorStr, &errorLine, &errorColumn)) {
+ return xmlDom;
+ } else {
+ qDebug() << "Error reading content of " << mFoldersXmlStorageName << endl
+ << "Error:" << inFile.errorString()
+ << "Line:" << errorLine
+ << "Column:" << errorColumn;
+ }
+ inFile.close();
+ } else {
+ qDebug() << "Error reading" << mFoldersXmlStorageName << endl
+ << "Error:" << inFile.errorString();
+ }
+ }
+
+ return QDomDocument();
+}
+
+class Cleaner
+{
+public:
+ void cure(const QUrl &dir)
+ {
+ mCurrentDir = dir.toLocalFile();
+ cleanTrash();
+
+ // Gathering information from svg files
+ QFileInfoList svgInfos = QDir(mCurrentDir).entryInfoList(QStringList() << "*.svg", QDir::NoDotAndDotDot | QDir::Files);
+ foreach (QFileInfo svgInfo, svgInfos) {
+ cureIdsFromSvgDom(createDomFromSvg(svgInfo.absoluteFilePath()));
+ }
+
+ fitIdsFromFileSystem();
+ QVector deleteCandidates;
+ findRedundandElements(deleteCandidates);
+
+ foreach (QString key, deleteCandidates) {
+ QString delPath = mPresentIdsMap.value(key);
+ if (delPath.isNull()) {
+ continue;
+ } else if (delPath.endsWith(wgtSuff)) { //remove corresponding thumb
+ QString thumbPath = thumbFileNameFrom(delPath);
+
+ //N/C - NNE - 20140417
+ if (QFile::exists(thumbPath)) {
+ rm_r(thumbPath);
+ }
+ }
+ rm_r(delPath);
+ // Clear parent dir if empty
+ QDir dir(delPath);
+ dir.cdUp();
+ if (dir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot).isEmpty()) {
+ dir.rmdir(dir.absolutePath());
+ }
+ }
+
+ qDebug() << "Ok on cure";
+ }
+
+private:
+ void cleanTrash()
+ {
+ QFileInfoList ifs = QDir(mCurrentDir).entryInfoList(trashFilter, QDir::NoDotAndDotDot | QDir::Files);
+ foreach (QFileInfo ifo, ifs) {
+ rm_r(ifo.absoluteFilePath());
+ }
+ }
+
+ void cureIdsFromSvgDom(const QDomDocument &dom)
+ {
+ Q_ASSERT(!dom.isNull());
+
+ QDomElement nextElement = dom.documentElement().firstChildElement();
+ while (!nextElement.isNull()) {
+ QString nextTag = nextElement.tagName();
+ qDebug() << "Tag name of the next parsed element is" << nextTag;
+ if (nextTag == tGroups)
+ {
+ nextElement = nextElement.firstChildElement("group");
+ }
+
+ invokeFromText(nextTag, nextElement);
+ nextElement = nextElement.nextSiblingElement();
+ }
+ }
+
+ void fitIdsFromFileSystem()
+ {
+ QString absPrefix = mCurrentDir + "/";
+ QStringList dirsList = scanDirs.split(",", QString::SkipEmptyParts);
+ foreach (QString dirName, dirsList) {
+ QString absPath = absPrefix + dirName;
+ if (!QFile::exists(absPath)) {
+ continue;
+ }
+ fitIdsFromDir(absPath);
+ }
+
+ }
+
+ void fitIdsFromDir(const QString &scanDir)
+ {
+ QFileInfoList fileList = QDir(scanDir).entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
+ foreach (QFileInfo nInfo, fileList) {
+ QString uid = strIdFrom(nInfo.fileName());
+ if (uid.isNull()) {
+ continue;
+ }
+ mPresentIdsMap.insert(uid, nInfo.absoluteFilePath());
+ }
+ }
+
+ void findRedundandElements(QVector &v)
+ {
+ // Taking information from the physical file system
+ QStringList domIds = mDomIdsMap.keys();
+ QStringList presentIds = mPresentIdsMap.keys();
+ v.resize(qMax(domIds.count(), presentIds.count()));
+ QVector::iterator it_diff;
+
+ it_diff=std::set_symmetric_difference(domIds.begin(), domIds.end()
+ , presentIds.begin(), presentIds.end()
+ , v.begin());
+ v.resize(it_diff - v.begin());
+ }
+
+ void invokeFromText(const QString &what, const QDomElement &element)
+ {
+ if (what == tVideo
+ || what == tAudio
+ || what == tImage) {
+ mediaToContainer(element);
+ } else if (what == tForeignObject) {
+ foreingObjectToContainer(element);
+
+ //N/C - NNE - 20140317
+ cleanObjectFolder(element);
+
+ //N/C - NNE - 20140520
+ //foreign object may referer resource which are not present in the svg
+ addResourceIdToSvg(element);
+ } else if (what == tTeacherGuide) {
+ teacherGuideToContainer(element);
+ }
+
+ pullActionFromElement(element);
+ }
+
+ // N/C - NNE - 20140317 : When export, reduce the size of the ubz file
+ void cleanObjectFolder(const QDomElement &element)
+ {
+ //QDomElement preference = element.firstChildElement("ub:preference");
+
+ //N/C - NNE - 20141021
+ QDomNodeList childrenNode = element.elementsByTagName("ub:preference");
+
+ QVector objectsIdUsed;
+
+ for(int i = 0; i < childrenNode.size(); i++){
+ QDomElement preference = childrenNode.at(i).toElement();
+
+ if(!preference.isNull()){
+ QString value = preference.attribute("value");
+
+ int findPos = value.indexOf("objects/");
+ int endPos;
+
+ //find all objects used
+ while(findPos != -1){
+ endPos = value.indexOf("\"", findPos);
+ objectsIdUsed << value.mid(findPos, endPos - findPos);
+ findPos = value.indexOf("objects/", endPos);
+ }
+ }
+ }
+ //N/C - NNE - 20141021 : END
+
+
+ QString path = element.attribute(aSrc);
+ QString objectsFolderPath = mCurrentDir + "/" + path + "/objects/";
+
+ QDir dir(objectsFolderPath);
+ dir.setFilter(QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot);
+
+ //then check all files in the objects directory
+ //delete the file not used (not in te objectIdUsed variable)
+ QFileInfoList list = dir.entryInfoList();
+ for (int i = 0; i < list.size(); i++) {
+ QFileInfo fileInfo = list.at(i);
+
+ if(!objectsIdUsed.contains("objects/"+fileInfo.fileName())){
+ QFile(fileInfo.filePath()).remove();
+ }
+
+ }
+ }
+ // N/C - NNE - 20140317 : END
+
+ //N/C - NNE - 20140520
+ void addResourceIdToSvg(const QDomElement& element)
+ {
+ QDomElement textContent = element.firstChildElement("itemTextContent");
+
+ QString value = textContent.text();
+
+ int findPos = value.indexOf("images/");
+ int endPos;
+
+ //find all objects used
+ while(findPos != -1){
+ endPos = value.indexOf("\"", findPos);
+
+ QString path = value.mid(findPos, endPos - findPos);
+
+ QString uuid = path.split("/").at(1).split(".").at(0);
+
+ mDomIdsMap.insert(uuid, path);
+
+ findPos = value.indexOf("images/", endPos);
+ }
+ }
+ //N/C - NNE - 20140520 : END
+
+ void pullActionFromElement(const QDomElement &element)
+ {
+ if (!element.hasAttribute(aActionMedia)) {
+ return;
+ }
+
+ QString path = element.attribute(aActionMedia);
+ if (path.isNull()) {
+ return;
+ }
+
+ QString uid = strIdFrom(path);
+ if (uid.isNull()) {
+ return;
+ }
+
+ mDomIdsMap.insert(uid, path);
+ }
+
+ void teacherGuideToContainer(const QDomElement &element)
+ {
+ QDomElement nMediaElement = element.firstChildElement(tMedia);
+ while (!nMediaElement.isNull()) {
+
+ QString path = nMediaElement.attribute(aRelativePath);
+ if (path.isNull()) {
+ continue;
+ }
+
+ QString uid = strIdFrom(path);
+ if (uid.isNull()) {
+ return;
+ }
+ mDomIdsMap.insert(uid, path);
+
+ nMediaElement = nMediaElement.nextSiblingElement(tMedia);
+ }
+ }
+
+ void mediaToContainer(const QDomElement &element)
+ {
+ QString path = element.attribute(aHref);
+ if (path.isNull()) {
+ return;
+ }
+ QString uid = strIdFrom(path);
+ if (uid.isNull()) {
+ return;
+ }
+ mDomIdsMap.insert(uid, path);
+ }
+
+ void foreingObjectToContainer(const QDomElement &element)
+ {
+ QString type = element.attribute(aType);
+ if (type == vText) { // We don't have to care of the text object
+ return;
+ }
+
+ QString path = element.attribute(aSrc);
+ if (path.isNull()) {
+ return;
+ }
+
+ QString uid = strIdFrom(path);
+ if (uid.isNull()) {
+ return;
+ }
+
+ mDomIdsMap.insert(uid, path);
+ }
+
+private:
+ QString mCurrentDir;
+ QDomDocument mSvgData;
+ QMap mDomIdsMap;
+ QMap mPresentIdsMap;
+};
+
+class PageCopier
+{
+public:
+ void copyPage (const QUrl &fromDir, int fromIndex, const QUrl &toDir, int toIndex)
+ {
+ mFromDir = fromDir.toLocalFile();
+ mToDir = toDir.toLocalFile();
+ mFromIndex = fromIndex;
+ mToIndex = toIndex;
+
+ QString svgFrom = mFromDir + "/" + svgPageName(fromIndex);
+ QString svgTo = toDir.toLocalFile() + "/" + svgPageName(toIndex);
+ QDomDocument dd = createDomFromSvg(svgFrom);
+ QFile fl(svgTo);
+ if (!fl.open(QIODevice::WriteOnly)) {
+ qDebug() << Q_FUNC_INFO << "can't open" << fl.fileName() << "for writing";
+ return;
+ }
+ cureIdsFromSvgDom(dd);
+
+ QTextStream str(&fl);
+ dd.save(str, 0);
+ fl.close();
+ qDebug() << Q_FUNC_INFO;
+ }
+
+private:
+ void cureIdsFromSvgDom(const QDomDocument &dom)
+ {
+ Q_ASSERT(!dom.isNull());
+
+ QDomElement nextElement = dom.documentElement().firstChildElement();
+ while (!nextElement.isNull( )) {
+ qDebug() << "Tag name of the next parsed element is" << nextElement.tagName();
+ QString nextTag = nextElement.tagName();
+ cureFromText(nextTag, nextElement);
+ nextElement = nextElement.nextSiblingElement();
+ }
+ }
+
+ void cureFromText(const QString &tagName, QDomElement element)
+ {
+ if (tagName == tVideo
+ || tagName == tAudio
+ || tagName == tImage) {
+ QString newRelative = cureNCopy(element.attribute(aHref));
+ element.setAttribute(aHref, newRelative);
+ if (element.hasAttribute(aActionMedia)) {
+ QString newActionPath = cureNCopy(element.attribute(aActionMedia));
+ element.setAttribute(aActionMedia, newActionPath);
+ }
+ } else if (tagName == tForeignObject) {
+ //Pdf object is a special case. Detect if it ends with #reference
+ QString reqExt = element.attribute(aReqExt);
+ if (reqExt == vReqExt) { //pdf reference
+ QString ref = element.attribute(aHref);
+ if (ref.isEmpty()) {
+ return;
+ }
+ ref.replace(QRegExp("^(.*pdf\\#page\\=).*$"), QString("\\1%1").arg(mToIndex));
+ return;
+ }
+
+ QString type = element.attribute(aType);
+ if (type == vText) { // We don't have to care of the text object
+ if (element.hasAttribute(aActionMedia)) {
+ QString newRelative = cureNCopy(element.attribute(aActionMedia));
+ element.setAttribute(aActionMedia, newRelative);
+ }
+ return;
+ }
+ QString newRelative = cureNCopy(element.attribute(aSrc));
+ element.setAttribute(aSrc, newRelative);
+ } else if (tagName == tTeacherGuide) {
+ QDomElement nMediaElement = element.firstChildElement(tMedia);
+ while (!nMediaElement.isNull()) {
+ QString newRelative = cureNCopy(nMediaElement.attribute(aRelativePath));
+ nMediaElement.setAttribute(aRelativePath, newRelative);
+ nMediaElement = nMediaElement.nextSiblingElement(tMedia);
+ }
+ }
+ }
+
+ QString cureNCopy(const QString &relativePath)
+ {
+ QString relative = relativePath;
+ QUuid newUuid = QUuid::createUuid();
+ QString newPath = relative.replace(QRegExp("\\{.*\\}"), newUuid.toString());
+ cp_rf(mFromDir + "/" + relativePath, mToDir + "/" + newPath);
+
+ return newPath;
+ }
+
+private:
+ QString mFromDir;
+ QString mToDir;
+ int mFromIndex;
+ int mToIndex;
+};
+
+class UBForeighnObjectsHandlerPrivate {
+ UBForeighnObjectsHandlerPrivate(UBForeighnObjectsHandler *pq)
+ : q(pq)
+ {
+ }
+
+public:
+ void cure(const QUrl &dir)
+ {
+ Cleaner *cleaner = new Cleaner;
+ cleaner->cure(dir);
+ delete cleaner;
+ cleaner = 0;
+ }
+
+ void copyPage (const QUrl &fromDir, int fromIndex, const QUrl &toDir, int toIndex)
+ {
+ PageCopier *copier = new PageCopier;
+ copier->copyPage(fromDir, fromIndex, toDir, toIndex);
+ delete copier;
+ copier = 0;
+ }
+
+private:
+ UBForeighnObjectsHandler *q;
+ friend class UBForeighnObjectsHandler;
+};
+
+UBForeighnObjectsHandler::UBForeighnObjectsHandler()
+ : d(new UBForeighnObjectsHandlerPrivate(this))
+{
+
+}
+
+UBForeighnObjectsHandler::~UBForeighnObjectsHandler()
+{
+ delete d;
+}
+
+void UBForeighnObjectsHandler::cure(const QList &dirs)
+{
+ foreach (QUrl dir, dirs) {
+ cure(dir);
+ }
+}
+
+void UBForeighnObjectsHandler::cure(const QUrl &dir)
+{
+ d->cure(dir);
+}
+
+void UBForeighnObjectsHandler::copyPage(const QUrl &fromDir, int fromIndex, const QUrl &toDir, int toIndex)
+{
+ d->copyPage(fromDir, fromIndex, toDir, toIndex);
+}
+
diff --git a/src/core/UBForeignObjectsHandler.h b/src/core/UBForeignObjectsHandler.h
new file mode 100644
index 00000000..18726964
--- /dev/null
+++ b/src/core/UBForeignObjectsHandler.h
@@ -0,0 +1,49 @@
+/*
+* 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 .
+*/
+
+#ifndef UBFOREIGHNOBJECTSHANDLER_H
+#define UBFOREIGHNOBJECTSHANDLER_H
+
+#include
+#include
+#include
+
+class UBForeighnObjectsHandlerPrivate;
+
+class UBForeighnObjectsHandler
+{
+public:
+ UBForeighnObjectsHandler();
+ ~UBForeighnObjectsHandler();
+
+ void cure(const QList &dirs);
+ void cure(const QUrl &dir);
+
+ void copyPage(const QUrl &fromDir, int fromIndex,
+ const QUrl &toDir, int toIndex);
+
+private:
+ UBForeighnObjectsHandlerPrivate *d;
+
+ friend class UBForeighnObjectsHandlerPrivate;
+};
+
+#endif // UBFOREIGHNOBJECTSHANDLER_H
diff --git a/src/core/UBPersistenceManager.cpp b/src/core/UBPersistenceManager.cpp
index 4f3f9704..0b05343f 100644
--- a/src/core/UBPersistenceManager.cpp
+++ b/src/core/UBPersistenceManager.cpp
@@ -1,36 +1,34 @@
/*
- * Copyright (C) 2015-2016 Département de l'Instruction Publique (DIP-SEM)
+ * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour l'Education Numérique en Afrique (GIP ENA)
*
- * Copyright (C) 2013 Open Education Foundation
+ * This file is part of Open-Sankoré.
*
- * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour
- * l'Education Numérique en Afrique (GIP ENA)
- *
- * This file is part of OpenBoard.
- *
- * OpenBoard is free software: you can redistribute it and/or modify
+ * 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).
*
- * OpenBoard is distributed in the hope that it will be useful,
+ * 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
+ * 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 OpenBoard. If not, see .
+ * along with Open-Sankoré. If not, see .
*/
-
#include "UBPersistenceManager.h"
#include "gui/UBMainWindow.h"
#include
+#include
+#include
+#include
+#include
#include "frameworks/UBPlatformUtils.h"
#include "frameworks/UBFileSystemUtils.h"
@@ -38,6 +36,7 @@
#include "core/UBApplication.h"
#include "core/UBSettings.h"
#include "core/UBSetting.h"
+#include "core/UBForeignObjectsHandler.h"
#include "document/UBDocumentProxy.h"
@@ -46,14 +45,11 @@
#include "adaptors/UBThumbnailAdaptor.h"
#include "adaptors/UBMetadataDcSubsetAdaptor.h"
-#include "domain/UBGraphicsMediaItem.h"
-#include "domain/UBGraphicsWidgetItem.h"
-#include "domain/UBGraphicsPixmapItem.h"
-#include "domain/UBGraphicsSvgItem.h"
-
#include "board/UBBoardController.h"
#include "board/UBBoardPaletteManager.h"
+#include "document/UBDocumentController.h"
+
#include "core/memcheck.h"
const QString UBPersistenceManager::imageDirectory = "images"; // added to UBPersistenceManager::mAllDirectories
@@ -61,56 +57,39 @@ const QString UBPersistenceManager::objectDirectory = "objects"; // added to UBP
const QString UBPersistenceManager::widgetDirectory = "widgets"; // added to UBPersistenceManager::mAllDirectories
const QString UBPersistenceManager::videoDirectory = "videos"; // added to UBPersistenceManager::mAllDirectories
const QString UBPersistenceManager::audioDirectory = "audios"; // added to
+const QString UBPersistenceManager::fileDirectory = "files"; // Issue 1683 (Evolution) - AOU - 20131206
+
+const QString UBPersistenceManager::myDocumentsName = "MyDocuments";
+const QString UBPersistenceManager::modelsName = "Models";
+const QString UBPersistenceManager::untitledDocumentsName = "UntitledDocuments";
+const QString UBPersistenceManager::fFolders = "folders.xml";
+const QString UBPersistenceManager::tFolder = "folder";
+const QString UBPersistenceManager::aName = "name";
UBPersistenceManager * UBPersistenceManager::sSingleton = 0;
UBPersistenceManager::UBPersistenceManager(QObject *pParent)
: QObject(pParent)
, mHasPurgedDocuments(false)
- , mIsApplicationClosing(false)
- , mIsWorkerFinished(false)
{
+ xmlFolderStructureFilename = "model";
+
mDocumentSubDirectories << imageDirectory;
mDocumentSubDirectories << objectDirectory;
mDocumentSubDirectories << widgetDirectory;
mDocumentSubDirectories << videoDirectory;
mDocumentSubDirectories << audioDirectory;
+ mDocumentSubDirectories << fileDirectory; // Issue 1683 (Evolution) - AOU - 20131206
- documentProxies = allDocumentProxies();
-
- mThread = new QThread;
- mWorker = new UBPersistenceWorker();
- mWorker->moveToThread(mThread);
- connect(mWorker, SIGNAL(error(QString)),
- this, SLOT(errorString(QString)));
-
- connect(mThread, SIGNAL(started()),
- mWorker, SLOT(process()));
-
- connect(mWorker, SIGNAL(finished()),
- mThread, SLOT(quit()));
-
- connect(mWorker, SIGNAL(finished()),
- this, SLOT(onWorkerFinished()));
-
- connect(mWorker, SIGNAL(finished()),
- mWorker, SLOT(deleteLater()));
-
- connect(mThread, SIGNAL(finished()),
- mThread, SLOT(deleteLater()));
-
- connect(mWorker, SIGNAL(sceneLoaded(QByteArray,UBDocumentProxy*,int)),
- this, SLOT(onSceneLoaded(QByteArray,UBDocumentProxy*,int)));
-
- connect(mWorker, SIGNAL(scenePersisted(UBGraphicsScene*)),
- this, SLOT(onScenePersisted(UBGraphicsScene*)));
+ mDocumentRepositoryPath = UBSettings::userDocumentDirectory();
+ mFoldersXmlStorageName = mDocumentRepositoryPath + "/" + fFolders;
- connect(mWorker, SIGNAL(metadataPersisted(UBDocumentProxy*)),
- this, SLOT(onMetadataPersisted(UBDocumentProxy*)));
+ mDocumentTreeStructureModel = new UBDocumentTreeModel(this);
+ createDocumentProxiesStructure();
- mThread->start();
+ emit proxyListChanged();
}
UBPersistenceManager* UBPersistenceManager::persistenceManager()
@@ -130,105 +109,191 @@ void UBPersistenceManager::destroy()
sSingleton = NULL;
}
-void UBPersistenceManager::onScenePersisted(UBGraphicsScene* scene)
+UBPersistenceManager::~UBPersistenceManager()
{
- if (!mIsApplicationClosing) {
- delete scene;
- scene = NULL;
- }
}
-void UBPersistenceManager::onMetadataPersisted(UBDocumentProxy* proxy)
+void UBPersistenceManager::createDocumentProxiesStructure(bool interactive)
{
- delete proxy;
-}
+ mDocumentRepositoryPath = UBSettings::userDocumentDirectory();
-void UBPersistenceManager::onWorkerFinished()
-{
- mIsWorkerFinished = true;
+ QDir rootDir(mDocumentRepositoryPath);
+ rootDir.mkpath(rootDir.path());
+
+ QFileInfoList contentList = rootDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Time | QDir::Reversed);
+ createDocumentProxiesStructure(contentList, interactive);
+
+ if (QFileInfo(mFoldersXmlStorageName).exists()) {
+ QDomDocument xmlDom;
+ QFile inFile(mFoldersXmlStorageName);
+ if (inFile.open(QIODevice::ReadOnly)) {
+ QString domString(inFile.readAll());
+
+ int errorLine = 0; int errorColumn = 0;
+ QString errorStr;
+
+ if (xmlDom.setContent(domString, &errorStr, &errorLine, &errorColumn)) {
+ loadFolderTreeFromXml("", xmlDom.firstChildElement());
+ } else {
+ qDebug() << "Error reading content of " << mFoldersXmlStorageName << endl
+ << "Error:" << inFile.errorString()
+ << "Line:" << errorLine
+ << "Column:" << errorColumn;
+ }
+ inFile.close();
+ } else {
+ qDebug() << "Error reading" << mFoldersXmlStorageName << endl
+ << "Error:" << inFile.errorString();
+ }
+ }
}
-UBPersistenceManager::~UBPersistenceManager()
+void UBPersistenceManager::createDocumentProxiesStructure(const QFileInfoList &contentInfo, bool interactive)
{
- mIsApplicationClosing = true;
-
- if(mWorker)
- mWorker->applicationWillClose();
+ foreach(QFileInfo path, contentInfo)
+ {
+ QString fullPath = path.absoluteFilePath();
- QTime time;
- time.start();
- qDebug() << "start waiting";
+ QDir dir(fullPath);
- while(!mIsWorkerFinished)
- QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
- qDebug() << "stop waiting after " << time.elapsed() << " ms";
+ if (dir.entryList(QDir::Files | QDir::NoDotAndDotDot).size() > 0)
+ {
+ QMap metadatas = UBMetadataDcSubsetAdaptor::load(fullPath);
+ QString docGroupName = metadatas.value(UBSettings::documentGroupName, QString()).toString();
+ QString docName = metadatas.value(UBSettings::documentName, QString()).toString();
- foreach(QPointer proxyGuard, documentProxies)
- {
- if (!proxyGuard.isNull())
- delete proxyGuard.data();
- }
+ if (docName.isEmpty()) {
+ qDebug() << "Group name and document name are empty in UBPersistenceManager::createDocumentProxiesStructure()";
+ continue;
+ }
- // to be sure that all the scenes are stored on disk
-}
+ QModelIndex parentIndex = mDocumentTreeStructureModel->goTo(docGroupName);
+ if (!parentIndex.isValid()) {
+ return;
+ }
-void UBPersistenceManager::errorString(QString error)
-{
- qDebug() << "peristence thread return the error " << error;
-}
+ UBDocumentProxy* docProxy = new UBDocumentProxy(fullPath); // managed in UBDocumentTreeNode
+ foreach(QString key, metadatas.keys()) {
+ docProxy->setMetaData(key, metadatas.value(key));
+ }
-void UBPersistenceManager::onSceneLoaded(QByteArray scene, UBDocumentProxy* proxy, int sceneIndex)
-{
- Q_UNUSED(scene);
- qDebug() << "scene loaded " << sceneIndex;
- QTime time;
- time.start();
- mSceneCache.insert(proxy, sceneIndex, loadDocumentScene(proxy, sceneIndex, false));
- qDebug() << "millisecond for sceneCache " << time.elapsed();
+ docProxy->setPageCount(sceneCount(docProxy));
+ bool addDoc = false;
+ if (!interactive) {
+ addDoc = true;
+ } else if (processInteractiveReplacementDialog(docProxy) == QDialog::Accepted) {
+ addDoc = true;
+ }
+ if (addDoc) {
+ mDocumentTreeStructureModel->addDocument(docProxy, parentIndex);
+ }
+ }
+ }
}
-QList > UBPersistenceManager::allDocumentProxies()
+QDialog::DialogCode UBPersistenceManager::processInteractiveReplacementDialog(UBDocumentProxy *pProxy)
{
- mDocumentRepositoryPath = UBSettings::userDocumentDirectory();
-
- QDir rootDir(mDocumentRepositoryPath);
- rootDir.mkpath(rootDir.path());
+ //TODO claudio remove this hack necessary on double click on ubz file
+ Qt::CursorShape saveShape;
+ if(UBApplication::overrideCursor()){
+ saveShape = UBApplication::overrideCursor()->shape();
+ UBApplication::overrideCursor()->setShape(Qt::ArrowCursor);
+ }
+ else
+ saveShape = Qt::ArrowCursor;
+ QDialog::DialogCode result = QDialog::Rejected;
- QStringList dirList = rootDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Time | QDir::Reversed);
+ if (UBApplication::documentController
+ && UBApplication::documentController->mainWidget()) {
+ QString docGroupName = pProxy->metaData(UBSettings::documentGroupName).toString();
+ QModelIndex parentIndex = mDocumentTreeStructureModel->goTo(docGroupName);
+ if (!parentIndex.isValid()) {
+ UBApplication::overrideCursor()->setShape(saveShape);
+ return QDialog::Rejected;
+ }
- foreach(QString path, dirList)
- {
- shiftPagesToStartWithTheZeroOne(rootDir.path() + "/" + path);
+ QStringList docList = mDocumentTreeStructureModel->nodeNameList(parentIndex);
+ QString docName = pProxy->metaData(UBSettings::documentName).toString();
+
+ if (docList.contains(docName)) {
+ UBDocumentReplaceDialog *replaceDialog = new UBDocumentReplaceDialog(docName
+ , docList
+ , /*UBApplication::documentController->mainWidget()*/0
+ , Qt::Widget);
+ if (replaceDialog->exec() == QDialog::Accepted) {
+ result = QDialog::Accepted;
+ QString resultName = replaceDialog->lineEditText();
+ int i = docList.indexOf(resultName);
+ if (i != -1) { //replace
+ QModelIndex replaceIndex = mDocumentTreeStructureModel->index(i, 0, parentIndex);
+ UBDocumentProxy *replaceProxy = mDocumentTreeStructureModel->proxyData(replaceIndex);
+ if (replaceProxy) {
+ deleteDocument(replaceProxy);
+ }
+ if (replaceIndex.isValid()) {
+ mDocumentTreeStructureModel->removeRow(i, parentIndex);
+ }
+ }
+ pProxy->setMetaData(UBSettings::documentName, resultName);
+ }
+ replaceDialog->setParent(0);
+ delete replaceDialog;
+ } else {
+ result = QDialog::Accepted;
+ }
}
+ //TODO claudio the if is an hack
+ if(UBApplication::overrideCursor())
+ UBApplication::overrideCursor()->setShape(saveShape);
-// QFileSystemWatcher* watcher = new QFileSystemWatcher(this);
-// watcher->addPath(mDocumentRepositoryPath);
-
-// connect(watcher, SIGNAL(directoryChanged(const QString&)), this, SLOT(documentRepositoryChanged(const QString&)));
-
- QList > proxies;
+ return result;
+}
- foreach(QString path, dirList)
- {
- QString fullPath = rootDir.path() + "/" + path;
+QString UBPersistenceManager::adjustDocumentVirtualPath(const QString &str)
+{
+ QStringList pathList = str.split("/", QString::SkipEmptyParts);
- QDir dir(fullPath);
+ if (pathList.isEmpty()) {
+ pathList.append(myDocumentsName);
+ pathList.append(untitledDocumentsName);
+ }
- if (dir.entryList(QDir::Files | QDir::NoDotAndDotDot).size() > 0)
- {
- UBDocumentProxy* proxy = new UBDocumentProxy(fullPath); // deleted in UBPersistenceManager::destructor
+ if (pathList.first() != myDocumentsName
+ && pathList.first() != UBSettings::trashedDocumentGroupNamePrefix
+ && pathList.first() != modelsName) {
+ pathList.prepend(myDocumentsName);
+ }
- proxy->setPageCount(sceneCount(proxy));
+ return pathList.join("/");
+}
- proxies << QPointer(proxy);
+void UBPersistenceManager::closing()
+{
+ QDir rootDir(mDocumentRepositoryPath);
+ rootDir.mkpath(rootDir.path());
- }
+ QFile outFile(mFoldersXmlStorageName);
+ if (outFile.open(QIODevice::WriteOnly)) {
+ QXmlStreamWriter writer(&outFile);
+ writer.setAutoFormatting(true);
+ writer.writeStartDocument();
+ writer.writeStartElement("content");
+ saveFoldersTreeToXml(writer, QModelIndex());
+ writer.writeEndElement();
+ writer.writeEndDocument();
+
+ outFile.close();
+ } else {
+ qDebug() << "failed to open document" << mFoldersXmlStorageName << "for writing" << endl
+ << "Error string:" << outFile.errorString();
}
-
- return proxies;
}
+bool UBPersistenceManager::isSceneInCached(UBDocumentProxy *proxy, int index) const
+{
+ return mSceneCache.contains(proxy, index);
+}
QStringList UBPersistenceManager::allShapes()
{
@@ -324,11 +389,22 @@ QStringList UBPersistenceManager::allWidgets(const QDir& dir)
}
-UBDocumentProxy* UBPersistenceManager::createDocument(const QString& pGroupName, const QString& pName, bool withEmptyPage)
+UBDocumentProxy* UBPersistenceManager::createDocument(const QString& pGroupName
+ , const QString& pName
+ , bool withEmptyPage
+ , QString directory
+ , int pageCount
+ , bool promptDialogIfExists)
{
- checkIfDocumentRepositoryExists();
-
- UBDocumentProxy *doc = new UBDocumentProxy(); // deleted in UBPersistenceManager::destructor
+ UBDocumentProxy *doc;
+ if(directory.length() != 0 ){
+ doc = new UBDocumentProxy(directory); // deleted in UBPersistenceManager::destructor
+ doc->setPageCount(pageCount);
+ }
+ else{
+ checkIfDocumentRepositoryExists();
+ doc = new UBDocumentProxy();
+ }
if (pGroupName.length() > 0)
{
@@ -341,30 +417,63 @@ UBDocumentProxy* UBPersistenceManager::createDocument(const QString& pGroupName,
}
doc->setMetaData(UBSettings::documentVersion, UBSettings::currentFileVersion);
- QString currentDate = UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime());
+ QString currentDate = UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime());
doc->setMetaData(UBSettings::documentUpdatedAt,currentDate);
doc->setMetaData(UBSettings::documentDate,currentDate);
- if (withEmptyPage)
+ if (withEmptyPage) {
createDocumentSceneAt(doc, 0);
- else
- generatePathIfNeeded(doc);
+ }
+ else{
+ this->generatePathIfNeeded(doc);
+ QDir dir(doc->persistencePath());
+ if (!dir.mkpath(doc->persistencePath()))
+ {
+ return 0; // if we can't create the path, abort function.
+ }
+ }
- documentProxies.insert(0, QPointer(doc));
+ bool addDoc = false;
+ if (!promptDialogIfExists) {
+ addDoc = true;
+ } else if (processInteractiveReplacementDialog(doc) == QDialog::Accepted) {
+ addDoc = true;
+ }
+ if (addDoc) {
+ mDocumentTreeStructureModel->addDocument(doc);
+ emit proxyListChanged();
+ } else {
+ deleteDocument(doc);
+ doc = 0;
+ }
- emit documentCreated(doc);
+ return doc;
+}
- mDocumentCreatedDuringSession << doc;
+UBDocumentProxy* UBPersistenceManager::createNewDocument(const QString& pGroupName
+ , const QString& pName
+ , bool withEmptyPage
+ , QString directory
+ , int pageCount
+ , bool promptDialogIfExists)
+{
+ UBDocumentProxy *resultDoc = createDocument(pGroupName, pName, withEmptyPage, directory, pageCount, promptDialogIfExists);
+ if (resultDoc) {
+ mDocumentTreeStructureModel->markDocumentAsNew(resultDoc);
+ }
- return doc;
+ return resultDoc;
}
-UBDocumentProxy* UBPersistenceManager::createDocumentFromDir(const QString& pDocumentDirectory, const QString& pGroupName, const QString& pName)
+UBDocumentProxy* UBPersistenceManager::createDocumentFromDir(const QString& pDocumentDirectory
+ , const QString& pGroupName
+ , const QString& pName
+ , bool withEmptyPage
+ , bool addTitlePage
+ , bool promptDialogIfExists)
{
checkIfDocumentRepositoryExists();
- UBPersistenceManager::persistenceManager()->shiftPagesToStartWithTheZeroOne(pDocumentDirectory);
-
UBDocumentProxy* doc = new UBDocumentProxy(pDocumentDirectory); // deleted in UBPersistenceManager::destructor
if (pGroupName.length() > 0)
@@ -377,6 +486,16 @@ UBDocumentProxy* UBPersistenceManager::createDocumentFromDir(const QString& pDoc
doc->setMetaData(UBSettings::documentName, pName);
}
+ QMap metadatas = UBMetadataDcSubsetAdaptor::load(pDocumentDirectory);
+
+ if(withEmptyPage) createDocumentSceneAt(doc, 0);
+ if(addTitlePage) persistDocumentScene(doc, mSceneCache.createScene(doc, 0, false), 0);
+
+ foreach(QString key, metadatas.keys())
+ {
+ doc->setMetaData(key, metadatas.value(key));
+ }
+
doc->setUuid(QUuid::createUuid());
doc->setPageCount(sceneCount(doc));
@@ -387,10 +506,21 @@ UBDocumentProxy* UBPersistenceManager::createDocumentFromDir(const QString& pDoc
UBSvgSubsetAdaptor::setSceneUuid(doc, i, QUuid::createUuid());
}
- documentProxies << QPointer(doc);
-
-
- emit documentCreated(doc);
+ //work around the
+ bool addDoc = false;
+ if (!promptDialogIfExists) {
+ addDoc = true;
+ } else if (processInteractiveReplacementDialog(doc) == QDialog::Accepted) {
+ addDoc = true;
+ }
+ if (addDoc) {
+ mDocumentTreeStructureModel->addDocument(doc);
+ emit proxyListChanged();
+ emit documentCreated(doc);
+ } else {
+ deleteDocument(doc);
+ doc = 0;
+ }
return doc;
}
@@ -402,18 +532,14 @@ void UBPersistenceManager::deleteDocument(UBDocumentProxy* pDocumentProxy)
emit documentWillBeDeleted(pDocumentProxy);
+ Q_ASSERT(QFileInfo(pDocumentProxy->persistencePath()).exists());
UBFileSystemUtils::deleteDir(pDocumentProxy->persistencePath());
- documentProxies.removeAll(QPointer(pDocumentProxy));
- mDocumentCreatedDuringSession.removeAll(pDocumentProxy);
-
mSceneCache.removeAllScenes(pDocumentProxy);
pDocumentProxy->deleteLater();
-
}
-
UBDocumentProxy* UBPersistenceManager::duplicateDocument(UBDocumentProxy* pDocumentProxy)
{
checkIfDocumentRepositoryExists();
@@ -433,7 +559,7 @@ UBDocumentProxy* UBPersistenceManager::duplicateDocument(UBDocumentProxy* pDocum
foreach(QString key, pDocumentProxy->metaDatas().keys())
{
copy->setMetaData(key, pDocumentProxy->metaDatas().value(key));
- }
+ }
copy->setMetaData(UBSettings::documentName,
pDocumentProxy->metaData(UBSettings::documentName).toString() + " " + tr("(copy)"));
@@ -444,7 +570,7 @@ UBDocumentProxy* UBPersistenceManager::duplicateDocument(UBDocumentProxy* pDocum
copy->setPageCount(sceneCount(copy));
- documentProxies << QPointer(copy);
+ emit proxyListChanged();
emit documentCreated(copy);
@@ -478,18 +604,15 @@ void UBPersistenceManager::deleteDocumentScenes(UBDocumentProxy* proxy, const QL
foreach(int index, compactedIndexes)
{
- // trig the reload of the thumbnails
emit documentSceneWillBeDeleted(proxy, index);
}
- QString sourceGroupName = proxy->metaData(UBSettings::documentGroupName).toString();
QString sourceName = proxy->metaData(UBSettings::documentName).toString();
- UBDocumentProxy *trashDocProxy = createDocument(UBSettings::trashedDocumentGroupNamePrefix + sourceGroupName, sourceName, false);
- generatePathIfNeeded(trashDocProxy);
+ UBDocumentProxy *trashDocProxy = createDocument(UBSettings::trashedDocumentGroupNamePrefix/* + sourceGroupName*/, sourceName, false);
foreach(int index, compactedIndexes)
{
- UBGraphicsScene *scene = loadDocumentScene(proxy, index, false);
+ UBGraphicsScene *scene = loadDocumentScene(proxy, index);
if (scene)
{
//scene is about to move into new document
@@ -502,10 +625,9 @@ void UBPersistenceManager::deleteDocumentScenes(UBDocumentProxy* proxy, const QL
QDir d = fi.dir();
d.mkpath(d.absolutePath());
- QFile::rename(source, target);
+ QFile::copy(source, target);
}
- UBApplication::showMessage(tr("Moving page to trash folder..."));
insertDocumentSceneAt(trashDocProxy, scene, trashDocProxy->pageCount());
}
}
@@ -552,8 +674,6 @@ void UBPersistenceManager::deleteDocumentScenes(UBDocumentProxy* proxy, const QL
}
-
-
void UBPersistenceManager::duplicateDocumentScene(UBDocumentProxy* proxy, int index)
{
checkIfDocumentRepositoryExists();
@@ -570,81 +690,45 @@ void UBPersistenceManager::duplicateDocumentScene(UBDocumentProxy* proxy, int in
copyPage(proxy, index , index + 1);
+ proxy->incPageCount();
- //TODO: write a proper way to handle object on disk
- UBGraphicsScene *scene = loadDocumentScene(proxy, index + 1);
-
- foreach(QGraphicsItem* item, scene->items())
- {
- UBGraphicsMediaItem *mediaItem = qgraphicsitem_cast (item);
-
- if (mediaItem){
- QString source = mediaItem->mediaFileUrl().toLocalFile();
- QString destination = source;
- QUuid newUuid = QUuid::createUuid();
- QString fileName = QFileInfo(source).completeBaseName();
- destination = destination.replace(fileName,newUuid.toString());
- QFile::copy(source,destination);
- mediaItem->setMediaFileUrl(QUrl::fromLocalFile(destination));
- continue;
- }
-
- UBGraphicsWidgetItem* widget = qgraphicsitem_cast(item);
- if(widget){
- QUuid newUUid = QUuid::createUuid();
- QString newUUidString = newUUid.toString().remove("{").remove("}");
- QString actualUuidString = widget->uuid().toString().remove("{").remove("}");
-
- QString widgetSourcePath = proxy->persistencePath() + "/" + UBPersistenceManager::widgetDirectory + "/{" + actualUuidString + "}.wgt";
- QString screenshotSourcePath = proxy->persistencePath() + "/" + UBPersistenceManager::widgetDirectory + "/" + actualUuidString + ".png";
-
- QString widgetDestinationPath = widgetSourcePath;
- widgetDestinationPath = widgetDestinationPath.replace(actualUuidString,newUUidString);
- QString screenshotDestinationPath = screenshotSourcePath;
- screenshotDestinationPath = screenshotDestinationPath.replace(actualUuidString,newUUidString);
-
- UBFileSystemUtils::copyDir(widgetSourcePath,widgetDestinationPath);
- QFile::copy(screenshotSourcePath,screenshotDestinationPath);
+ emit documentSceneCreated(proxy, index + 1);
+}
- widget->setUuid(newUUid);
+void UBPersistenceManager::copyDocumentScene(UBDocumentProxy *from, int fromIndex, UBDocumentProxy *to, int toIndex)
+{
+ if (from == to && toIndex <= fromIndex) {
+ qDebug() << "operation is not supported" << Q_FUNC_INFO;
+ return;
+ }
- widget->widgetUrl(QUrl::fromLocalFile(widgetDestinationPath));
+ checkIfDocumentRepositoryExists();
- continue;
- }
+ for (int i = to->pageCount(); i > toIndex; i--) {
+ renamePage(to, i - 1, i);
+ mSceneCache.moveScene(to, i - 1, i);
+ }
- UBGraphicsPixmapItem* pixmapItem = qgraphicsitem_cast(item);
- if(pixmapItem){
- QString source = proxy->persistencePath() + "/" + UBPersistenceManager::imageDirectory + "/" + pixmapItem->uuid().toString() + ".png";
- QString destination = source;
- QUuid newUuid = QUuid::createUuid();
- QString fileName = QFileInfo(source).completeBaseName();
- destination = destination.replace(fileName,newUuid.toString());
- QFile::copy(source,destination);
- pixmapItem->setUuid(newUuid);
- continue;
- }
+ UBForeighnObjectsHandler hl;
+ hl.copyPage(QUrl::fromLocalFile(from->persistencePath()), fromIndex,
+ QUrl::fromLocalFile(to->persistencePath()), toIndex);
- UBGraphicsSvgItem* svgItem = qgraphicsitem_cast(item);
- if(svgItem){
- QString source = proxy->persistencePath() + "/" + UBPersistenceManager::imageDirectory + "/" + svgItem->uuid().toString() + ".svg";
- QString destination = source;
- QUuid newUuid = QUuid::createUuid();
- QString fileName = QFileInfo(source).completeBaseName();
- destination = destination.replace(fileName,newUuid.toString());
- QFile::copy(source,destination);
- svgItem->setUuid(newUuid);
- continue;
- }
+ to->incPageCount();
- }
- scene->setModified(true);
+ QString thumbTmp(from->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", fromIndex));
+ QString thumbTo(to->persistencePath() + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", toIndex));
- persistDocumentScene(proxy,scene, index + 1);
+ QFile::remove(thumbTo);
+ QFile::copy(thumbTmp, thumbTo);
- proxy->incPageCount();
+ Q_ASSERT(QFileInfo(thumbTmp).exists());
+ Q_ASSERT(QFileInfo(thumbTo).exists());
+ const QPixmap *pix = new QPixmap(thumbTmp);
+ UBDocumentController *ctrl = UBApplication::documentController;
+ ctrl->addPixmapAt(pix, toIndex);
+ ctrl->TreeViewSelectionChanged(ctrl->firstSelectedTreeIndex(), QModelIndex());
- emit documentSceneCreated(proxy, index + 1);
+// emit documentSceneCreated(to, toIndex + 1);
}
@@ -659,10 +743,6 @@ UBGraphicsScene* UBPersistenceManager::createDocumentSceneAt(UBDocumentProxy* pr
UBGraphicsScene *newScene = mSceneCache.createScene(proxy, index, useUndoRedoStack);
- newScene->setBackground(UBSettings::settings()->isDarkBackground(),
- UBSettings::settings()->UBSettings::pageBackground());
-
- newScene->setBackgroundGridSize(UBSettings::settings()->crossSize);
persistDocumentScene(proxy, newScene, index);
proxy->incPageCount();
@@ -673,7 +753,7 @@ UBGraphicsScene* UBPersistenceManager::createDocumentSceneAt(UBDocumentProxy* pr
}
-void UBPersistenceManager::insertDocumentSceneAt(UBDocumentProxy* proxy, UBGraphicsScene* scene, int index)
+void UBPersistenceManager::insertDocumentSceneAt(UBDocumentProxy* proxy, UBGraphicsScene* scene, int index, bool persist)
{
scene->setDocument(proxy);
@@ -688,7 +768,9 @@ void UBPersistenceManager::insertDocumentSceneAt(UBDocumentProxy* proxy, UBGraph
mSceneCache.insert(proxy, index, scene);
- persistDocumentScene(proxy, scene, index);
+ if (persist) {
+ persistDocumentScene(proxy, scene, index);
+ }
proxy->incPageCount();
@@ -735,73 +817,63 @@ void UBPersistenceManager::moveSceneToIndex(UBDocumentProxy* proxy, int source,
}
-UBGraphicsScene* UBPersistenceManager::loadDocumentScene(UBDocumentProxy* proxy, int sceneIndex, bool cacheNeighboringScenes)
+UBGraphicsScene* UBPersistenceManager::loadDocumentScene(UBDocumentProxy* proxy, int sceneIndex)
{
- UBGraphicsScene* scene = NULL;
-
if (mSceneCache.contains(proxy, sceneIndex))
- scene = mSceneCache.value(proxy, sceneIndex);
+ return mSceneCache.value(proxy, sceneIndex);
else {
- scene = UBSvgSubsetAdaptor::loadScene(proxy, sceneIndex);
+ UBGraphicsScene* scene = UBSvgSubsetAdaptor::loadScene(proxy, sceneIndex);
+ if(!scene){
+ createDocumentSceneAt(proxy,0);
+ scene = UBSvgSubsetAdaptor::loadScene(proxy, 0);
+ }
if (scene)
mSceneCache.insert(proxy, sceneIndex, scene);
- }
- if (cacheNeighboringScenes) {
- if(sceneIndex + 1 < proxy->pageCount() && !mSceneCache.contains(proxy, sceneIndex + 1))
- mWorker->readScene(proxy,sceneIndex+1);
- if(sceneIndex - 1 >= 0 && !mSceneCache.contains(proxy, sceneIndex - 1))
- mWorker->readScene(proxy,sceneIndex-1);
+ return scene;
}
+}
- return scene;
+void UBPersistenceManager::reassignDocProxy(UBDocumentProxy *newDocument, UBDocumentProxy *oldDocument)
+{
+ return mSceneCache.reassignDocProxy(newDocument, oldDocument);
}
-void UBPersistenceManager::persistDocumentScene(UBDocumentProxy* pDocumentProxy, UBGraphicsScene* pScene, const int pSceneIndex, bool isAnAutomaticBackup, bool forceImmediateSaving)
+void UBPersistenceManager::persistDocumentScene(UBDocumentProxy* pDocumentProxy, UBGraphicsScene* pScene, const int pSceneIndex)
{
checkIfDocumentRepositoryExists();
- if(!isAnAutomaticBackup)
- pScene->deselectAllItems();
+ pScene->deselectAllItems();
generatePathIfNeeded(pDocumentProxy);
QDir dir(pDocumentProxy->persistencePath());
dir.mkpath(pDocumentProxy->persistencePath());
- mSceneCache.insert(pDocumentProxy, pSceneIndex, pScene);
+ if (pDocumentProxy->isModified())
+ UBMetadataDcSubsetAdaptor::persist(pDocumentProxy);
if (pScene->isModified())
{
- //qDebug() << "Persisting scene";
- if (pDocumentProxy->isModified())
- persistDocumentMetadata(pDocumentProxy, forceImmediateSaving);
+ UBSvgSubsetAdaptor::persistScene(pDocumentProxy, pScene, pSceneIndex);
UBThumbnailAdaptor::persistScene(pDocumentProxy, pScene, pSceneIndex);
- if(forceImmediateSaving)
- UBSvgSubsetAdaptor::persistScene(pDocumentProxy,pScene,pSceneIndex);
- else {
- UBGraphicsScene* copiedScene = pScene->sceneDeepCopy();
- mWorker->saveScene(pDocumentProxy, copiedScene, pSceneIndex);
- pScene->setModified(false);
- }
+ pScene->setModified(false);
}
+
+ mSceneCache.insert(pDocumentProxy, pSceneIndex, pScene);
}
-void UBPersistenceManager::persistDocumentMetadata(UBDocumentProxy* pDocumentProxy, bool forceImmediateSaving)
+UBDocumentProxy* UBPersistenceManager::persistDocumentMetadata(UBDocumentProxy* pDocumentProxy)
{
- if (forceImmediateSaving) {
- UBMetadataDcSubsetAdaptor::persist(pDocumentProxy);
- emit documentMetadataChanged(pDocumentProxy);
- }
+ UBMetadataDcSubsetAdaptor::persist(pDocumentProxy);
- else {
- UBDocumentProxy* copy = pDocumentProxy->deepCopy();
- mWorker->saveMetadata(copy);
- }
+ emit documentMetadataChanged(pDocumentProxy);
+
+ return pDocumentProxy;
}
@@ -830,8 +902,10 @@ void UBPersistenceManager::copyPage(UBDocumentProxy* pDocumentProxy, const int s
int UBPersistenceManager::sceneCount(const UBDocumentProxy* proxy)
{
const QString pPath = proxy->persistencePath();
+
int pageIndex = 0;
bool moreToProcess = true;
+ bool addedMissingZeroPage = false;
while (moreToProcess)
{
@@ -840,9 +914,19 @@ int UBPersistenceManager::sceneCount(const UBDocumentProxy* proxy)
QFile file(fileName);
if (file.exists())
+ {
pageIndex++;
+ }
else
+ {
moreToProcess = false;
+ }
+ }
+
+ if(pageIndex == 1 && addedMissingZeroPage){
+ // increment is done only to check if there are other pages than the missing zero page
+ // This situation means -> no pages on the document
+ return 0;
}
return pageIndex;
@@ -859,7 +943,7 @@ QString UBPersistenceManager::generateUniqueDocumentPath(const QString& baseFold
QDateTime now = QDateTime::currentDateTime();
QString dirName = now.toString("yyyy-MM-dd hh-mm-ss.zzz");
- return baseFolder + QString("/OpenBoard Document %1").arg(dirName);
+ return baseFolder + QString("/Sankore Document %1").arg(dirName);
}
QString UBPersistenceManager::generateUniqueDocumentPath()
@@ -912,24 +996,8 @@ bool UBPersistenceManager::addDirectoryContentToDocument(const QString& document
pDocument->setPageCount(sceneCount(pDocument));
- return false;
-}
-
-
-UBDocumentProxy* UBPersistenceManager::documentByUuid(const QUuid& pUuid)
-{
- for(int i = 0 ; i < documentProxies.length(); i++)
- {
- UBDocumentProxy* proxy = documentProxies.at(i);
-
- if (proxy && proxy->uuid() == pUuid)
- {
- return proxy;
- }
- }
-
- return 0;
-
+ //issue NC - NNE - 20131213 : At this point, all is well done.
+ return true;
}
@@ -941,35 +1009,14 @@ bool UBPersistenceManager::isEmpty(UBDocumentProxy* pDocumentProxy)
if (pDocumentProxy->pageCount() > 1)
return false;
- UBGraphicsScene *theSoleScene = mSceneCache.value(pDocumentProxy, 0) ? mSceneCache.value(pDocumentProxy, 0) : UBSvgSubsetAdaptor::loadScene(pDocumentProxy, 0);
+ UBGraphicsScene *theSoleScene = UBSvgSubsetAdaptor::loadScene(pDocumentProxy, 0);
bool empty = false;
if (theSoleScene)
{
empty = theSoleScene->isEmpty();
- if(empty){
- mSceneCache.removeScene(pDocumentProxy,0);
- theSoleScene = NULL;
- }
- else{
- //the scene can contain Delegate buttons and the selection frame
- // but this doesn't means that there is something useful on the frame
- bool usefulItemFound = false;
- foreach(QGraphicsItem* eachItem, theSoleScene->getFastAccessItems()){
- if(eachItem->type() > QGraphicsItem::UserType
- && eachItem->type() != UBGraphicsItemType::DelegateButtonType
- && eachItem->type() != UBGraphicsItemType::SelectionFrameType){
- usefulItemFound = true;
- break;
- }
- }
- if(!usefulItemFound){
- mSceneCache.removeScene(pDocumentProxy,0);
- theSoleScene = NULL;
- empty = true;
- }
- }
+ delete theSoleScene;
}
else
{
@@ -982,24 +1029,19 @@ bool UBPersistenceManager::isEmpty(UBDocumentProxy* pDocumentProxy)
void UBPersistenceManager::purgeEmptyDocuments()
{
- if(!mHasPurgedDocuments) // hack to workaround the fact that app closing is called twice :-(
- {
- QList toBeDeleted;
-
- foreach(UBDocumentProxy* docProxy, mDocumentCreatedDuringSession)
- {
- if (isEmpty(docProxy))
- {
- toBeDeleted << docProxy;
- }
- }
+ QList toBeDeleted;
- foreach(UBDocumentProxy* docProxy, toBeDeleted)
+ foreach(UBDocumentProxy* docProxy, mDocumentTreeStructureModel->newDocuments())
+ {
+ if (isEmpty(docProxy))
{
- deleteDocument(docProxy);
+ toBeDeleted << docProxy;
}
+ }
- mHasPurgedDocuments = true;
+ foreach(UBDocumentProxy* docProxy, toBeDeleted)
+ {
+ deleteDocument(docProxy);
}
}
@@ -1018,13 +1060,16 @@ bool UBPersistenceManager::addFileToDocument(UBDocumentProxy* pDocumentProxy,
if (data == NULL && !fi.exists())
return false;
+ qDebug() << fi.suffix();
+
QString fileName = subdir + "/" + objectUuid.toString() + "." + fi.suffix();
+
destinationPath = pDocumentProxy->persistencePath() + "/" + fileName;
if (!QFile::exists(destinationPath))
{
QDir dir;
- dir.mkpath(pDocumentProxy->persistencePath() + "/" + subdir);
+ dir.mkdir(pDocumentProxy->persistencePath() + "/" + subdir);
if (!QFile::exists(pDocumentProxy->persistencePath() + "/" + subdir))
return false;
@@ -1100,25 +1145,88 @@ void UBPersistenceManager::checkIfDocumentRepositoryExists()
QString humanPath = QDir::cleanPath(mDocumentRepositoryPath);
humanPath = QDir::toNativeSeparators(humanPath);
- UBApplication::mainWindow->warning(tr("Document Repository Loss"),qApp->applicationName() + tr("has lost access to the document repository '%1'. Unfortunately the application must shut down to avoid data corruption. Latest changes may be lost as well.").arg(humanPath));
+ UBApplication::mainWindow->warning(tr("Document Repository Loss"),tr("Sankore has lost access to the document repository '%1'. Unfortunately the application must shut down to avoid data corruption. Latest changes may be lost as well.").arg(humanPath));
UBApplication::quit();
}
}
-void UBPersistenceManager::shiftPagesToStartWithTheZeroOne(QString persistencePath)
+void UBPersistenceManager::saveFoldersTreeToXml(QXmlStreamWriter &writer, const QModelIndex &parentIndex)
{
- if(!QFile(persistencePath + "/page000.svg").exists() && QFile(persistencePath + "/page001.svg").exists()){
- int i = 1;
+ for (int i = 0; i < mDocumentTreeStructureModel->rowCount(parentIndex); i++)
+ {
+ QModelIndex currentIndex = mDocumentTreeStructureModel->index(i, 0, parentIndex);
+ if (mDocumentTreeStructureModel->isCatalog(currentIndex))
+ {
+ writer.writeStartElement(tFolder);
+ writer.writeAttribute(aName, mDocumentTreeStructureModel->nodeFromIndex(currentIndex)->nodeName());
+ saveFoldersTreeToXml(writer, currentIndex);
+ writer.writeEndElement();
+ }
+ }
+}
- while(QFile(persistencePath + UBFileSystemUtils::digitFileFormat("/page%1.svg",i)).exists()){
- QFile svg(persistencePath + UBFileSystemUtils::digitFileFormat("/page%1.svg", i));
- svg.rename(persistencePath + UBFileSystemUtils::digitFileFormat("/page%1.svg", i-1));
+void UBPersistenceManager::loadFolderTreeFromXml(const QString &path, const QDomElement &element)
+{
- QFile thumb(persistencePath + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", i));
- thumb.rename(persistencePath + UBFileSystemUtils::digitFileFormat("/page%1.thumbnail.jpg", i-1));
+ QDomElement iterElement = element.firstChildElement();
+ while(!iterElement.isNull())
+ {
+ QString leafPath;
+ if (tFolder == iterElement.tagName())
+ {
+ leafPath = iterElement.attribute(aName);
- i+=1;
+ if (!leafPath.isEmpty())
+ {
+ mDocumentTreeStructureModel->goTo(path + "/" + leafPath);
+ if (!iterElement.firstChildElement().isNull())
+ loadFolderTreeFromXml(path + "/" + leafPath, iterElement);
+ }
}
+ iterElement = iterElement.nextSiblingElement();
}
}
+
+bool UBPersistenceManager::mayHaveVideo(UBDocumentProxy* pDocumentProxy)
+{
+ QDir videoDir(pDocumentProxy->persistencePath() + "/" + UBPersistenceManager::videoDirectory);
+
+ return videoDir.exists() && videoDir.entryInfoList().length() > 0;
+}
+
+bool UBPersistenceManager::mayHaveAudio(UBDocumentProxy* pDocumentProxy)
+{
+ QDir audioDir(pDocumentProxy->persistencePath() + "/" + UBPersistenceManager::audioDirectory);
+
+ return audioDir.exists() && audioDir.entryInfoList().length() > 0;
+}
+
+bool UBPersistenceManager::mayHavePDF(UBDocumentProxy* pDocumentProxy)
+{
+ QDir objectDir(pDocumentProxy->persistencePath() + "/" + UBPersistenceManager::objectDirectory);
+
+ QStringList filters;
+ filters << "*.pdf";
+
+ return objectDir.exists() && objectDir.entryInfoList(filters).length() > 0;
+}
+
+
+bool UBPersistenceManager::mayHaveSVGImages(UBDocumentProxy* pDocumentProxy)
+{
+ QDir imageDir(pDocumentProxy->persistencePath() + "/" + UBPersistenceManager::imageDirectory);
+
+ QStringList filters;
+ filters << "*.svg";
+
+ return imageDir.exists() && imageDir.entryInfoList(filters).length() > 0;
+}
+
+
+bool UBPersistenceManager::mayHaveWidget(UBDocumentProxy* pDocumentProxy)
+{
+ QDir widgetDir(pDocumentProxy->persistencePath() + "/" + UBPersistenceManager::widgetDirectory);
+
+ return widgetDir.exists() && widgetDir.entryInfoList(QDir::Dirs).length() > 0;
+}
diff --git a/src/core/UBPersistenceManager.h b/src/core/UBPersistenceManager.h
index 19d10f66..58b789a4 100644
--- a/src/core/UBPersistenceManager.h
+++ b/src/core/UBPersistenceManager.h
@@ -1,32 +1,26 @@
/*
- * Copyright (C) 2015-2016 Département de l'Instruction Publique (DIP-SEM)
+ * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour l'Education Numérique en Afrique (GIP ENA)
*
- * Copyright (C) 2013 Open Education Foundation
+ * This file is part of Open-Sankoré.
*
- * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour
- * l'Education Numérique en Afrique (GIP ENA)
- *
- * This file is part of OpenBoard.
- *
- * OpenBoard is free software: you can redistribute it and/or modify
+ * 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).
*
- * OpenBoard is distributed in the hope that it will be useful,
+ * 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
+ * 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 OpenBoard. If not, see .
+ * along with Open-Sankoré. If not, see .
*/
-
#ifndef UBPERSISTENCEMANAGER_H_
#define UBPERSISTENCEMANAGER_H_
@@ -34,11 +28,13 @@
#include "UBSceneCache.h"
-#include "UBPersistenceWorker.h"
-
+class QDomNode;
+class QDomElement;
class UBDocument;
class UBDocumentProxy;
class UBGraphicsScene;
+class UBDocumentTreeNode;
+class UBDocumentTreeModel;
class UBPersistenceManager : public QObject
{
@@ -57,16 +53,40 @@ class UBPersistenceManager : public QObject
static const QString videoDirectory;
static const QString audioDirectory;
static const QString widgetDirectory;
- static const QString teacherGuideDirectory;
- static void shiftPagesToStartWithTheZeroOne(QString persistencePath);
+ static const QString fileDirectory; // Issue 1683 (Evolution) - AOU - 20131206
+
+ static const QString myDocumentsName;
+ static const QString modelsName;
+ static const QString untitledDocumentsName;
+ static const QString fFolders;
+ static const QString tFolder;
+ static const QString aName;
static UBPersistenceManager* persistenceManager();
static void destroy();
- virtual UBDocumentProxy* createDocument(const QString& pGroupName = "", const QString& pName = "", bool withEmptyPage = true);
- virtual UBDocumentProxy* createDocumentFromDir(const QString& pDocumentDirectory, const QString& pGroupName = "", const QString& pName = "");
-
- virtual void persistDocumentMetadata(UBDocumentProxy* pDocumentProxy, bool forceImmediateSaving = false);
+ virtual UBDocumentProxy* createDocument(const QString& pGroupName = ""
+ , const QString& pName = ""
+ , bool withEmptyPage = true
+ , QString directory =QString()
+ , int pageCount = 0
+ , bool promptDialogIfExists = false);
+
+ virtual UBDocumentProxy *createNewDocument(const QString& pGroupName = ""
+ , const QString& pName = ""
+ , bool withEmptyPage = true
+ , QString directory =QString()
+ , int pageCount = 0
+ , bool promptDialogIfExists = false);
+
+ virtual UBDocumentProxy* createDocumentFromDir(const QString& pDocumentDirectory
+ , const QString& pGroupName = ""
+ , const QString& pName = ""
+ , bool withEmptyPage = false
+ , bool addTitlePage = false
+ , bool promptDialogIfExists = false);
+
+ virtual UBDocumentProxy* persistDocumentMetadata(UBDocumentProxy* pDocumentProxy);
virtual UBDocumentProxy* duplicateDocument(UBDocumentProxy* pDocumentProxy);
@@ -76,19 +96,24 @@ class UBPersistenceManager : public QObject
virtual void duplicateDocumentScene(UBDocumentProxy* pDocumentProxy, int index);
+ virtual void copyDocumentScene(UBDocumentProxy *from, int fromIndex, UBDocumentProxy *to, int toIndex);
+
virtual void persistDocumentScene(UBDocumentProxy* pDocumentProxy,
- UBGraphicsScene* pScene, const int pSceneIndex, bool isAnAutomaticBackup = false, bool forceImmediateSaving = false);
+ UBGraphicsScene* pScene, const int pSceneIndex);
virtual UBGraphicsScene* createDocumentSceneAt(UBDocumentProxy* pDocumentProxy, int index, bool useUndoRedoStack = true);
- virtual void insertDocumentSceneAt(UBDocumentProxy* pDocumentProxy, UBGraphicsScene* scene, int index);
+ virtual void insertDocumentSceneAt(UBDocumentProxy* pDocumentProxy, UBGraphicsScene* scene, int index, bool persist = true);
virtual void moveSceneToIndex(UBDocumentProxy* pDocumentProxy, int source, int target);
- virtual UBGraphicsScene* loadDocumentScene(UBDocumentProxy* pDocumentProxy, int sceneIndex, bool cacheNeighboringScenes = true);
+ virtual UBGraphicsScene* loadDocumentScene(UBDocumentProxy* pDocumentProxy, int sceneIndex);
UBGraphicsScene *getDocumentScene(UBDocumentProxy* pDocumentProxy, int sceneIndex) {return mSceneCache.value(pDocumentProxy, sceneIndex);}
+ void reassignDocProxy(UBDocumentProxy *newDocument, UBDocumentProxy *oldDocument);
- QList > documentProxies;
+// QList > documentProxies;
+ UBDocumentTreeNode *mDocumentTreeStructure;
+ UBDocumentTreeModel *mDocumentTreeStructureModel;
virtual QStringList allShapes();
virtual QStringList allGips();
@@ -101,7 +126,9 @@ class UBPersistenceManager : public QObject
bool addDirectoryContentToDocument(const QString& documentRootFolder, UBDocumentProxy* pDocument);
- virtual UBDocumentProxy* documentByUuid(const QUuid& pUuid);
+ void createDocumentProxiesStructure(bool interactive = false);
+ void createDocumentProxiesStructure(const QFileInfoList &contentInfo, bool interactive = false);
+ QDialog::DialogCode processInteractiveReplacementDialog(UBDocumentProxy *pProxy);
QStringList documentSubDirectories()
{
@@ -114,7 +141,21 @@ class UBPersistenceManager : public QObject
bool addGraphicsWidgetToDocument(UBDocumentProxy *mDocumentProxy, QString path, QUuid objectUuid, QString& destinationPath);
bool addFileToDocument(UBDocumentProxy* pDocumentProxy, QString path, const QString& subdir, QUuid objectUuid, QString& destinationPath, QByteArray* data = NULL);
+ bool mayHaveVideo(UBDocumentProxy* pDocumentProxy);
+ bool mayHaveAudio(UBDocumentProxy* pDocumentProxy);
+ bool mayHavePDF(UBDocumentProxy* pDocumentProxy);
+ bool mayHaveSVGImages(UBDocumentProxy* pDocumentProxy);
+ bool mayHaveWidget(UBDocumentProxy* pDocumentProxy);
+
+ QString adjustDocumentVirtualPath(const QString &str);
+
+ void closing();
+ bool isSceneInCached(UBDocumentProxy *proxy, int index) const;
+
signals:
+
+ void proxyListChanged();
+
void documentCreated(UBDocumentProxy* pDocumentProxy);
void documentMetadataChanged(UBDocumentProxy* pDocumentProxy);
void documentWillBeDeleted(UBDocumentProxy* pDocumentProxy);
@@ -122,50 +163,31 @@ class UBPersistenceManager : public QObject
void documentSceneCreated(UBDocumentProxy* pDocumentProxy, int pIndex);
void documentSceneWillBeDeleted(UBDocumentProxy* pDocumentProxy, int pIndex);
- private:
-
+private:
int sceneCount(const UBDocumentProxy* pDocumentProxy);
-
static QStringList getSceneFileNames(const QString& folder);
-
- QList > allDocumentProxies();
-
void renamePage(UBDocumentProxy* pDocumentProxy,
- const int sourceIndex, const int targetIndex);
-
+ const int sourceIndex, const int targetIndex);
void copyPage(UBDocumentProxy* pDocumentProxy,
- const int sourceIndex, const int targetIndex);
-
+ const int sourceIndex, const int targetIndex);
void generatePathIfNeeded(UBDocumentProxy* pDocumentProxy);
-
void checkIfDocumentRepositoryExists();
- UBSceneCache mSceneCache;
+ void saveFoldersTreeToXml(QXmlStreamWriter &writer, const QModelIndex &parentIndex);
+ void loadFolderTreeFromXml(const QString &path, const QDomElement &element);
- QStringList mDocumentSubDirectories;
+ QString xmlFolderStructureFilename;
+ UBSceneCache mSceneCache;
+ QStringList mDocumentSubDirectories;
QMutex mDeletedListMutex;
-
bool mHasPurgedDocuments;
-
- QList mDocumentCreatedDuringSession;
-
QString mDocumentRepositoryPath;
-
- UBPersistenceWorker* mWorker;
-
- QThread* mThread;
- bool mIsWorkerFinished;
-
- bool mIsApplicationClosing;
+ QString mFoldersXmlStorageName;
private slots:
void documentRepositoryChanged(const QString& path);
- void errorString(QString error);
- void onSceneLoaded(QByteArray,UBDocumentProxy*,int);
- void onWorkerFinished();
- void onScenePersisted(UBGraphicsScene* scene);
- void onMetadataPersisted(UBDocumentProxy* proxy);
+
};
diff --git a/src/core/UBSceneCache.cpp b/src/core/UBSceneCache.cpp
index 756acef4..8c4b0063 100644
--- a/src/core/UBSceneCache.cpp
+++ b/src/core/UBSceneCache.cpp
@@ -190,6 +190,33 @@ void UBSceneCache::moveScene(UBDocumentProxy* proxy, int sourceIndex, int target
}
+void UBSceneCache::reassignDocProxy(UBDocumentProxy *newDocument, UBDocumentProxy *oldDocument)
+{
+ if (!newDocument || !oldDocument) {
+ return;
+ }
+ if (newDocument->pageCount() != oldDocument->pageCount()) {
+ return;
+ }
+ if (!QFileInfo(oldDocument->persistencePath()).exists()) {
+ return;
+ }
+ for (int i = 0; i < oldDocument->pageCount(); i++) {
+
+ UBSceneCacheID sourceKey(oldDocument, i);
+ UBGraphicsScene *currentScene = value(sourceKey);
+ if (currentScene) {
+ currentScene->setDocument(newDocument);
+ }
+ mCachedKeyFIFO.removeAll(sourceKey);
+ int count = QHash::remove(sourceKey);
+ mCachedSceneCount -= count;
+
+ insert(newDocument, i, currentScene);
+ }
+
+}
+
void UBSceneCache::shiftUpScenes(UBDocumentProxy* proxy, int startIncIndex, int endIncIndex)
{
diff --git a/src/core/UBSceneCache.h b/src/core/UBSceneCache.h
index ea80320e..1d71fb84 100644
--- a/src/core/UBSceneCache.h
+++ b/src/core/UBSceneCache.h
@@ -98,6 +98,8 @@ class UBSceneCache : public QHash
void moveScene(UBDocumentProxy* proxy, int sourceIndex, int targetIndex);
+ void reassignDocProxy(UBDocumentProxy *newDocument, UBDocumentProxy *oldDocument);
+
void shiftUpScenes(UBDocumentProxy* proxy, int startIncIndex, int endIncIndex);
diff --git a/src/core/core.pri b/src/core/core.pri
index a60978ad..3ad1846b 100644
--- a/src/core/core.pri
+++ b/src/core/core.pri
@@ -15,7 +15,8 @@ HEADERS += src/core/UB.h \
src/core/UBDownloadThread.h \
src/core/UBOpenSankoreImporter.h \
src/core/UBTextTools.h \
- src/core/UBPersistenceWorker.h
+ src/core/UBPersistenceWorker.h \
+ $$PWD/UBForeignObjectsHandler.h
SOURCES += src/core/main.cpp \
src/core/UBApplication.cpp \
@@ -33,4 +34,5 @@ SOURCES += src/core/main.cpp \
src/core/UBDownloadThread.cpp \
src/core/UBOpenSankoreImporter.cpp \
src/core/UBTextTools.cpp \
- src/core/UBPersistenceWorker.cpp
+ src/core/UBPersistenceWorker.cpp \
+ $$PWD/UBForeignObjectsHandler.cpp
diff --git a/src/customWidgets/UBActionableWidget.cpp b/src/customWidgets/UBActionableWidget.cpp
new file mode 100644
index 00000000..ba334aca
--- /dev/null
+++ b/src/customWidgets/UBActionableWidget.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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 .
+ */
+
+
+
+#include
+#include
+
+#include "UBActionableWidget.h"
+
+#include "core/memcheck.h"
+
+UBActionableWidget::UBActionableWidget(QWidget *parent, const char *name):QWidget(parent)
+ , mShowActions(false)
+{
+ setObjectName(name);
+ mActions.clear();
+ mCloseButtons.setIcon(QIcon(QPixmap(":images/close.svg")));
+ mCloseButtons.setGeometry(0, 0, 2*ACTIONSIZE, ACTIONSIZE);
+ mCloseButtons.setVisible(false);
+ connect(&mCloseButtons, SIGNAL(clicked()), this, SLOT(onCloseClicked()));
+}
+
+UBActionableWidget::~UBActionableWidget()
+{
+
+}
+
+void UBActionableWidget::addAction(eAction act)
+{
+ if(!mActions.contains(act)){
+ mActions << act;
+ }
+}
+
+void UBActionableWidget::removeAction(eAction act)
+{
+ if(mActions.contains(act)){
+ mActions.remove(mActions.indexOf(act));
+ }
+}
+
+void UBActionableWidget::removeAllActions()
+{
+ mActions.clear();
+}
+
+void UBActionableWidget::setActionsVisible(bool bVisible)
+{
+ if(!mActions.empty() && mActions.contains(eAction_Close)){
+ mCloseButtons.setVisible(bVisible);
+ }
+}
+
+void UBActionableWidget::onCloseClicked()
+{
+ emit close(this);
+}
+
+void UBActionableWidget::setActionsParent(QWidget *parent)
+{
+ if(mActions.contains(eAction_Close)){
+ mCloseButtons.setParent(parent);
+ }
+}
+
+void UBActionableWidget::unsetActionsParent()
+{
+ if(mActions.contains(eAction_Close)){
+ mCloseButtons.setParent(this);
+ }
+}
diff --git a/src/customWidgets/UBActionableWidget.h b/src/customWidgets/UBActionableWidget.h
new file mode 100644
index 00000000..cdc8e767
--- /dev/null
+++ b/src/customWidgets/UBActionableWidget.h
@@ -0,0 +1,68 @@
+/*
+ * 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 .
+ */
+
+
+
+#ifndef UBACTIONABLEWIDGET_H
+#define UBACTIONABLEWIDGET_H
+
+#include
+#include
+#include
+#include
+
+#define ACTIONSIZE 16
+
+typedef enum{
+ eAction_Close,
+ eAction_MoveUp,
+ eAction_MoveDown
+}eAction;
+
+class UBActionableWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ UBActionableWidget(QWidget* parent=0, const char* name="UBActionableWidget");
+ ~UBActionableWidget();
+ void addAction(eAction act);
+ void removeAction(eAction act);
+ void removeAllActions();
+ void setActionsVisible(bool bVisible);
+
+signals:
+ void close(QWidget* w);
+
+protected:
+ void setActionsParent(QWidget* parent);
+ void unsetActionsParent();
+ QVector mActions;
+ QPushButton mCloseButtons;
+
+private slots:
+ void onCloseClicked();
+
+private:
+ bool mShowActions;
+
+};
+
+#endif // UBACTIONABLEWIDGET_H
diff --git a/src/customWidgets/UBGraphicsItemAction.cpp b/src/customWidgets/UBGraphicsItemAction.cpp
new file mode 100644
index 00000000..1d6a7a09
--- /dev/null
+++ b/src/customWidgets/UBGraphicsItemAction.cpp
@@ -0,0 +1,212 @@
+/*
+ * 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 .
+ */
+
+
+
+#include "UBGraphicsItemAction.h"
+#include "core/UBApplication.h"
+#include "core/UBPersistenceManager.h"
+#include "board/UBBoardController.h"
+#include "web/UBWebController.h"
+#include "document/UBDocumentController.h"
+#include "document/UBDocumentProxy.h"
+#include "document/UBDocumentContainer.h"
+
+#include "board/UBBoardController.h"
+
+
+UBGraphicsItemAction::UBGraphicsItemAction(eUBGraphicsItemLinkType linkType, QObject *parent) :
+ QObject(parent)
+{
+ mLinkType = linkType;
+}
+
+ void UBGraphicsItemAction::actionRemoved()
+ {
+ //NOOP
+ }
+
+
+UBGraphicsItemPlayAudioAction::UBGraphicsItemPlayAudioAction(QString audioFile, bool onImport, QObject *parent) :
+ UBGraphicsItemAction(eLinkToAudio,parent)
+ , mMediaObject(0)
+ , mIsLoading(true)
+{
+ Q_ASSERT(audioFile.length() > 0);
+
+ if(onImport){
+ QString extension = QFileInfo(audioFile).completeSuffix();
+ QString destDir = UBApplication::boardController->selectedDocument()->persistencePath() + "/" + UBPersistenceManager::audioDirectory;
+ QString destFile = destDir + "/" + QUuid::createUuid().toString() + "." + extension;
+ if(!QDir(destDir).exists())
+ QDir(UBApplication::boardController->selectedDocument()->persistencePath()).mkdir(destDir);
+ //explanation : the audioFile could be relative. The method copy will return false so a second try is done adding
+ // the document file path
+ if(!QFile(audioFile).copy(destFile))
+ QFile(UBApplication::boardController->selectedDocument()->persistencePath() + "/" + audioFile).copy(destFile);
+ mAudioPath = destFile;
+ mFullPath = destFile;
+ }
+ else
+ {
+ //On import don't recreate the file
+ mAudioPath = audioFile;
+ mFullPath = mAudioPath;
+ }
+
+ mAudioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this);
+ mMediaObject = new Phonon::MediaObject(this);
+ Phonon::createPath(mMediaObject, mAudioOutput);
+ mMediaObject->setCurrentSource(Phonon::MediaSource(mAudioPath));
+}
+
+
+UBGraphicsItemPlayAudioAction::UBGraphicsItemPlayAudioAction() :
+ UBGraphicsItemAction(eLinkToAudio,NULL)
+ , mMediaObject(0)
+ , mIsLoading(true)
+{
+}
+
+
+void UBGraphicsItemPlayAudioAction::setPath(QString audioPath)
+{
+ Q_ASSERT(audioPath.length() > 0);
+ mAudioPath = audioPath;
+ mFullPath = mAudioPath;
+ mAudioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this);
+ mMediaObject = new Phonon::MediaObject(this);
+ Phonon::createPath(mMediaObject, mAudioOutput);
+ mMediaObject->setCurrentSource(Phonon::MediaSource(mAudioPath));
+}
+
+QString UBGraphicsItemPlayAudioAction::fullPath()
+{
+ return mFullPath;
+}
+
+UBGraphicsItemPlayAudioAction::~UBGraphicsItemPlayAudioAction()
+{
+ if(!mMediaObject && mMediaObject->state() == Phonon::PlayingState)
+ mMediaObject->stop();
+}
+
+void UBGraphicsItemPlayAudioAction::onSourceHide()
+{
+ if(mMediaObject && mMediaObject->state() == Phonon::PlayingState){
+ mMediaObject->stop();
+ }
+}
+
+void UBGraphicsItemPlayAudioAction::play()
+{
+ if(mMediaObject->state() == Phonon::PlayingState){
+ mMediaObject->stop();
+ }
+ mMediaObject->seek(0);
+ mMediaObject->play();
+}
+
+
+QStringList UBGraphicsItemPlayAudioAction::save()
+{
+ //Another hack
+ if(UBApplication::documentController && UBApplication::documentController->selectedDocument()){
+ QString documentPath = UBApplication::documentController->selectedDocument()->persistencePath() + "/";
+ return QStringList() << QString("%1").arg(eLinkToAudio) << mAudioPath.replace(documentPath,"");
+ }
+ else{
+ int index = mAudioPath.indexOf("/audios/");
+ QString relativePath = mAudioPath.remove(0,index + 1);
+ return QStringList() << QString("%1").arg(eLinkToAudio) << relativePath;
+ }
+}
+
+void UBGraphicsItemPlayAudioAction::actionRemoved()
+{
+ QFile(mAudioPath).remove();
+}
+
+
+UBGraphicsItemMoveToPageAction::UBGraphicsItemMoveToPageAction(eUBGraphicsItemMovePageAction actionType, int page, QObject* parent) :
+ UBGraphicsItemAction(eLinkToPage,parent)
+{
+ mActionType = actionType;
+ mPage = page;
+}
+
+void UBGraphicsItemMoveToPageAction::play()
+{
+ UBBoardController* boardController = UBApplication::boardController;
+
+ switch (mActionType) {
+ case eMoveToFirstPage:
+ boardController->firstScene();
+ break;
+ case eMoveToLastPage:
+ boardController->lastScene();
+ break;
+ case eMoveToPreviousPage:
+ boardController->previousScene();
+ break;
+ case eMoveToNextPage:
+ boardController->nextScene();
+ break;
+ case eMoveToPage:
+ if(mPage >= 0 && mPage < boardController->pageCount())
+ boardController->setActiveDocumentScene(mPage);
+ else
+ qWarning() << "scene number " << mPage << "ins't accessible anymore";
+ break;
+ default:
+ break;
+ }
+}
+
+QStringList UBGraphicsItemMoveToPageAction::save()
+{
+ return QStringList() << QString("%1").arg(eLinkToPage) << QString("%1").arg(mActionType) << QString("%1").arg(mPage);
+}
+
+
+UBGraphicsItemLinkToWebPageAction::UBGraphicsItemLinkToWebPageAction(QString url, QObject *parent) :
+ UBGraphicsItemAction(eLinkToWebUrl,parent)
+{
+ if (url.length() > 0)
+ {
+ if(!url.startsWith("http://"))
+ url = "http://" + url;
+ mUrl = url;
+ }
+ else
+ mUrl = QString();
+}
+
+void UBGraphicsItemLinkToWebPageAction::play()
+{
+ if (mUrl.length() > 0)
+ UBApplication::webController->loadUrl(QUrl(mUrl));
+}
+
+QStringList UBGraphicsItemLinkToWebPageAction::save()
+{
+ return QStringList() << QString("%1").arg(eLinkToWebUrl) << mUrl;
+}
diff --git a/src/customWidgets/UBGraphicsItemAction.h b/src/customWidgets/UBGraphicsItemAction.h
new file mode 100644
index 00000000..f88a42c8
--- /dev/null
+++ b/src/customWidgets/UBGraphicsItemAction.h
@@ -0,0 +1,124 @@
+/*
+ * 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 .
+ */
+
+
+
+#ifndef UBGRAPHICSITEMSACTIONS_H
+#define UBGRAPHICSITEMSACTIONS_H
+
+#include
+#include
+
+
+enum eUBGraphicsItemMovePageAction {
+ eMoveToFirstPage = 0,
+ eMoveToLastPage,
+ eMoveToPreviousPage,
+ eMoveToNextPage,
+ eMoveToPage
+} ;
+
+enum eUBGraphicsItemLinkType
+{
+ eLinkToAudio = 0,
+ eLinkToPage,
+ eLinkToWebUrl
+};
+
+class UBGraphicsItemAction : public QObject
+{
+ Q_OBJECT
+public:
+ UBGraphicsItemAction(eUBGraphicsItemLinkType linkType,QObject* parent = 0);
+ virtual void play() = 0;
+ virtual QStringList save() = 0;
+ virtual void actionRemoved();
+ virtual QString path() {return "";}
+ eUBGraphicsItemLinkType linkType() { return mLinkType;}
+
+signals:
+
+public slots:
+private:
+ eUBGraphicsItemLinkType mLinkType;
+
+};
+
+
+class UBGraphicsItemPlayAudioAction : public UBGraphicsItemAction
+{
+ Q_OBJECT
+
+public:
+ UBGraphicsItemPlayAudioAction(QString audioFile, bool onImport = true, QObject* parent = 0);
+ UBGraphicsItemPlayAudioAction();
+ ~UBGraphicsItemPlayAudioAction();
+ void play();
+ QStringList save();
+ void actionRemoved();
+ QString path() {return mAudioPath;}
+ void setPath(QString audioPath);
+ QString fullPath();
+
+public slots:
+ void onSourceHide();
+
+private:
+ QString mAudioPath;
+ Phonon::MediaObject *mMediaObject;
+ Phonon::AudioOutput *mAudioOutput;
+ bool mIsLoading;
+ QString mFullPath;
+};
+
+
+class UBGraphicsItemMoveToPageAction : public UBGraphicsItemAction
+{
+ Q_OBJECT
+
+public:
+ UBGraphicsItemMoveToPageAction(eUBGraphicsItemMovePageAction actionType, int page = 0, QObject* parent = 0);
+ void play();
+ QStringList save();
+ int page(){return mPage;}
+ eUBGraphicsItemMovePageAction actionType(){return mActionType;}
+
+private:
+ eUBGraphicsItemMovePageAction mActionType;
+ int mPage;
+
+};
+
+class UBGraphicsItemLinkToWebPageAction : public UBGraphicsItemAction
+{
+ Q_OBJECT
+
+public:
+ UBGraphicsItemLinkToWebPageAction(QString url, QObject* parent = 0);
+ void play();
+ QStringList save();
+ QString url(){return mUrl;}
+
+private:
+ QString mUrl;
+};
+
+#endif // UBGRAPHICSITEMSACTIONS_H
diff --git a/src/customWidgets/UBMediaWidget.cpp b/src/customWidgets/UBMediaWidget.cpp
new file mode 100644
index 00000000..48aecdb0
--- /dev/null
+++ b/src/customWidgets/UBMediaWidget.cpp
@@ -0,0 +1,368 @@
+/*
+ * 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 .
+ */
+
+
+
+#include "core/UBApplication.h"
+#include "globals/UBGlobals.h"
+#include "UBMediaWidget.h"
+
+#include "core/memcheck.h"
+
+/**
+ * \brief Constructor
+ * @param type as the media type
+ * @param parent as the parent widget
+ * @param name as the object name
+ */
+UBMediaWidget::UBMediaWidget(eMediaType type, QWidget *parent, const char *name):UBActionableWidget(parent, name)
+ , mpMediaObject(NULL)
+ , mpVideoWidget(NULL)
+ , mpAudioOutput(NULL)
+ , mpLayout(NULL)
+ , mpSeekerLayout(NULL)
+ , mpPlayStopButton(NULL)
+ , mpPauseButton(NULL)
+ , mpSlider(NULL)
+ , mAutoUpdate(false)
+ , mGeneratingThumbnail(false)
+ , mBorder(5)
+ , mpMediaContainer(NULL)
+ , mMediaLayout(NULL)
+ , mpCover(NULL)
+{
+ SET_STYLE_SHEET();
+
+ addAction(eAction_Close);
+ mType = type;
+ mpLayout = new QVBoxLayout(this);
+ setLayout(mpLayout);
+
+ mpPlayStopButton = new UBMediaButton(this);
+ mpPlayStopButton->setPixmap(QPixmap(":images/play.svg"));
+ mpPauseButton = new UBMediaButton(this);
+ mpPauseButton->setPixmap(QPixmap(":images/pause.svg"));
+ mpPauseButton->setEnabled(false);
+ mpSlider = new QSlider(this);
+ mpSlider->setOrientation(Qt::Horizontal);
+ mpSlider->setMinimum(0);
+ mpSlider->setMaximum(0);
+
+ mpSeekerLayout = new QHBoxLayout();
+ mpSeekerLayout->addWidget(mpPlayStopButton, 0);
+ mpSeekerLayout->addWidget(mpPauseButton, 0);
+ mpSeekerLayout->addWidget(mpSlider, 1);
+ mpSeekerLayout->setContentsMargins(0, 0, 0, 0);
+
+ connect(mpPlayStopButton, SIGNAL(clicked()), this, SLOT(onPlayStopClicked()));
+ connect(mpPauseButton, SIGNAL(clicked()), this, SLOT(onPauseClicked()));
+ connect(mpSlider, SIGNAL(valueChanged(int)), this, SLOT(onSliderChanged(int)));
+}
+
+/**
+ * \brief Destructor
+ */
+UBMediaWidget::~UBMediaWidget()
+{
+ unsetActionsParent();
+ DELETEPTR(mpMediaObject);
+ DELETEPTR(mpSlider);
+ DELETEPTR(mpPauseButton);
+ DELETEPTR(mpPlayStopButton);
+ DELETEPTR(mpAudioOutput);
+ DELETEPTR(mpVideoWidget);
+ DELETEPTR(mpCover);
+ DELETEPTR(mpMediaContainer);
+ DELETEPTR(mpSeekerLayout);
+ DELETEPTR(mpLayout);
+}
+
+/**
+ * \brief Set the media file
+ * @param filePath as the media file path
+ */
+void UBMediaWidget::setFile(const QString &filePath)
+{
+ Q_ASSERT("" != filePath);
+ mFilePath = filePath;
+ mpMediaObject = new Phonon::MediaObject(this);
+ mpMediaObject->setTickInterval(TICK_INTERVAL);
+ connect(mpMediaObject, SIGNAL(stateChanged(Phonon::State,Phonon::State)), this, SLOT(onStateChanged(Phonon::State,Phonon::State)));
+ connect(mpMediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(onTotalTimeChanged(qint64)));
+ connect(mpMediaObject, SIGNAL(tick(qint64)), this, SLOT(onTick(qint64)));
+ mpMediaObject->setCurrentSource(Phonon::MediaSource(filePath));
+ createMediaPlayer();
+}
+
+/**
+ * \brief Get the media type
+ * @returns the media type
+ */
+eMediaType UBMediaWidget::mediaType()
+{
+ return mType;
+}
+
+void UBMediaWidget::showEvent(QShowEvent* event)
+{
+ if(mType == eMediaType_Audio){
+ return;
+ }else{
+ if(!mpVideoWidget){
+ mpVideoWidget = new Phonon::VideoWidget(this);
+ mMediaLayout->addStretch(1);
+ mMediaLayout->addWidget(mpVideoWidget);
+ mMediaLayout->addStretch(1);
+ Phonon::createPath(mpMediaObject, mpVideoWidget);
+ adaptSizeToVideo();
+ mpMediaObject->play();
+ mpMediaObject->stop();
+ }
+ QWidget::showEvent(event);
+ }
+}
+
+void UBMediaWidget::hideEvent(QHideEvent* event)
+{
+ if(mpMediaObject->state() == Phonon::PlayingState)
+ mpMediaObject->stop();
+ UBActionableWidget::hideEvent(event);
+}
+
+/**
+ * \brief Create the media player
+ */
+void UBMediaWidget::createMediaPlayer()
+{
+ mpMediaContainer = new QWidget();
+ mpMediaContainer->setObjectName("UBMediaVideoContainer");
+ mMediaLayout = new QHBoxLayout();
+ mpMediaContainer->setLayout(mMediaLayout);
+
+ if(eMediaType_Video == mType){
+ mMediaLayout->setContentsMargins(10, 10, 10, 10);
+ if(isVisible()){
+ mpVideoWidget = new Phonon::VideoWidget(this);
+ mMediaLayout->addStretch(1);
+ mMediaLayout->addWidget(mpVideoWidget);
+ mMediaLayout->addStretch(1);
+ Phonon::createPath(mpMediaObject, mpVideoWidget);
+ adaptSizeToVideo();
+ }
+ mpAudioOutput = new Phonon::AudioOutput(Phonon::VideoCategory, this);
+ Phonon::createPath(mpMediaObject, mpAudioOutput);
+ }else if(eMediaType_Audio == mType){
+ mMediaLayout->setContentsMargins(10, 10, 10, 10);
+ mpCover = new QLabel(mpMediaContainer);
+ //mpMediaContainer->setStyleSheet(QString("background: none;"));
+ setAudioCover(":images/libpalette/soundIcon.svg");
+ mpCover->setScaledContents(true);
+ mMediaLayout->addStretch(1);
+ mMediaLayout->addWidget(mpCover);
+ mMediaLayout->addStretch(1);
+ mpAudioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this);
+ Phonon::createPath(mpMediaObject, mpAudioOutput);
+ }
+ mpLayout->addWidget(mpMediaContainer, 1);
+ mpLayout->addLayout(mpSeekerLayout, 0);
+ setActionsParent(mpMediaContainer);
+}
+
+/**
+ * \brief Adapt the widget size to the video in order to keep the good aspect ratio
+ */
+void UBMediaWidget::adaptSizeToVideo()
+{
+ if(NULL != mpMediaContainer){
+ int origW = mpMediaContainer->width();
+ int origH = mpMediaContainer->height();
+ int newW = width();
+ float scaleFactor = (float)origW/(float)newW;
+ int newH = origH/scaleFactor;
+ resize(newW, height() + newH);
+ }
+}
+
+/**
+ * \brief Handle the media state change notification
+ * @param newState as the new state
+ * @param oldState as the old state
+ */
+void UBMediaWidget::onStateChanged(Phonon::State newState, Phonon::State oldState)
+{
+ if(!mGeneratingThumbnail){
+ if(Phonon::LoadingState == oldState && Phonon::StoppedState == newState){
+ if(eMediaType_Video == mType){
+ // We do that here to generate the thumbnail of the video
+ mGeneratingThumbnail = true;
+ mpMediaObject->play();
+ mpMediaObject->pause();
+ mGeneratingThumbnail = false;
+ }
+ }else if(Phonon::PlayingState == oldState && Phonon::PausedState == newState){
+ mpPlayStopButton->setPixmap(QPixmap(":images/play.svg"));
+ mpPauseButton->setEnabled(false);
+ }else if((Phonon::PausedState == oldState && Phonon::PlayingState == newState) ||
+ (Phonon::StoppedState == oldState && Phonon::PlayingState == newState)){
+ mpPlayStopButton->setPixmap(QPixmap(":images/stop.svg"));
+ mpPauseButton->setEnabled(true);
+ }else if(Phonon::PlayingState == oldState && Phonon::StoppedState == newState){
+ mpPlayStopButton->setPixmap(QPixmap(":images/play.svg"));
+ mpPauseButton->setEnabled(false);
+ mpSlider->setValue(0);
+ }
+
+ }
+ // if(mType == eMediaType_Video)
+ // updateView(newState);
+}
+
+/**
+ * \brief Handles the total time change notification
+ * @param total as the new total time
+ */
+void UBMediaWidget::onTotalTimeChanged(qint64 total)
+{
+ mpSlider->setMaximum(total);
+}
+
+/**
+ * \brief Handles the tick notification
+ * @param currentTime as the current time
+ */
+void UBMediaWidget::onTick(qint64 currentTime)
+{
+ mAutoUpdate = true;
+ mpSlider->setValue((int)currentTime);
+ mAutoUpdate = false;
+}
+
+/**
+ * \brief Handles the seeker value change notification
+ * @param value as the new seeker value
+ */
+void UBMediaWidget::onSliderChanged(int value)
+{
+ if(!mAutoUpdate){
+ mpMediaObject->seek(value);
+ }
+}
+
+/**
+ * \brief Toggle Play-Stop
+ */
+void UBMediaWidget::onPlayStopClicked()
+{
+ switch(mpMediaObject->state()){
+ case Phonon::PlayingState:
+ mpMediaObject->stop();
+ break;
+
+ case Phonon::StoppedState:
+ case Phonon::PausedState:
+ mpMediaObject->play();
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * \brief Pause the media
+ */
+void UBMediaWidget::onPauseClicked()
+{
+ mpMediaObject->pause();
+}
+
+/**
+ * Get the border
+ * @returns the actual border
+ */
+int UBMediaWidget::border()
+{
+ return mBorder;
+}
+
+/**
+ * \brief Handles the resize event
+ * @param ev as the resize event
+ */
+void UBMediaWidget::resizeEvent(QResizeEvent* ev)
+{
+ Q_UNUSED(ev);
+}
+
+/**
+ * \brief Set the audio cover
+ * @param coverPath as the cover image file path
+ */
+void UBMediaWidget::setAudioCover(const QString &coverPath)
+{
+ if(NULL != mpCover){
+ mpCover->setPixmap(QPixmap(coverPath));
+ }
+}
+
+// -----------------------------------------------------------------------------------------------------------
+/**
+ * \brief Constructor
+ * @param parent as the parent widget
+ * @param name as the object name
+ */
+UBMediaButton::UBMediaButton(QWidget *parent, const char *name):QLabel(parent)
+ , mPressed(false)
+{
+ setObjectName(name);
+ resize(UBMEDIABUTTON_SIZE, UBMEDIABUTTON_SIZE);
+ setStyleSheet(QString("padding:0px 0px 0px 0px; margin:0px 0px 0px 0px;"));
+}
+
+/**
+ * \brief Destructor
+ */
+UBMediaButton::~UBMediaButton()
+{
+
+}
+
+/**
+ * \brief Handles the mouse press notification
+ * @param ev as the mouse press event
+ */
+void UBMediaButton::mousePressEvent(QMouseEvent* ev)
+{
+ Q_UNUSED(ev);
+ mPressed = true;
+}
+
+/**
+ * \brief Handles the mouse release notification
+ * @param ev as the mouse release event
+ */
+void UBMediaButton::mouseReleaseEvent(QMouseEvent* ev)
+{
+ Q_UNUSED(ev);
+ if(mPressed){
+ mPressed = false;
+ emit clicked();
+ }
+}
diff --git a/src/customWidgets/UBMediaWidget.h b/src/customWidgets/UBMediaWidget.h
new file mode 100644
index 00000000..1a6f0db6
--- /dev/null
+++ b/src/customWidgets/UBMediaWidget.h
@@ -0,0 +1,133 @@
+/*
+ * 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 .
+ */
+
+
+
+#ifndef UBMEDIAWIDGET_H
+#define UBMEDIAWIDGET_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "UBActionableWidget.h"
+
+#define UBMEDIABUTTON_SIZE 32
+#define TICK_INTERVAL 1000
+
+/**
+ * \brief The media type
+ */
+typedef enum{
+ eMediaType_Video,
+ eMediaType_Audio
+}eMediaType;
+
+class UBMediaButton : public QLabel
+{
+ Q_OBJECT
+public:
+ UBMediaButton(QWidget* parent=0, const char* name="UBMediaButton");
+ ~UBMediaButton();
+
+signals:
+ void clicked();
+
+protected:
+ void mousePressEvent(QMouseEvent* ev);
+ void mouseReleaseEvent(QMouseEvent* ev);
+
+private:
+ /** And indicator of the press event in progress */
+ bool mPressed;
+};
+
+class UBMediaWidget : public UBActionableWidget
+{
+ Q_OBJECT
+public:
+ UBMediaWidget(eMediaType type = eMediaType_Video, QWidget* parent=0, const char* name="UBMediaWidget");
+ ~UBMediaWidget();
+ void setFile(const QString& filePath);
+ eMediaType mediaType();
+ int border();
+ void setAudioCover(const QString& coverPath);
+ void setUrl(const QString& url){mUrl = url;}
+ QString url(){return mUrl;}
+
+protected:
+ void resizeEvent(QResizeEvent* ev);
+ void showEvent(QShowEvent* event);
+ void hideEvent(QHideEvent* event);
+ /** The current media file path */
+ QString mFilePath;
+
+private slots:
+ void onPlayStopClicked();
+ void onPauseClicked();
+ void onStateChanged(Phonon::State newState, Phonon::State oldState);
+ void onTotalTimeChanged(qint64 total);
+ void onTick(qint64 currentTime);
+ void onSliderChanged(int value);
+
+private:
+ void createMediaPlayer();
+ void adaptSizeToVideo();
+
+ /** The current media type */
+ eMediaType mType;
+ /** The media object */
+ Phonon::MediaObject* mpMediaObject;
+ /** The video renderer */
+ Phonon::VideoWidget* mpVideoWidget;
+ /** The audio renderer */
+ Phonon::AudioOutput* mpAudioOutput;
+ /** The principal layout of this widget */
+ QVBoxLayout* mpLayout;
+ /** The seeker layout */
+ QHBoxLayout* mpSeekerLayout;
+ /** The play-stop button */
+ UBMediaButton* mpPlayStopButton;
+ /** The pause button */
+ UBMediaButton* mpPauseButton;
+ /** The seeker slider */
+ QSlider* mpSlider;
+ /** An indicator of the seeker auto update in progress */
+ bool mAutoUpdate;
+ /** An indicator of the thumbnail generation in progress */
+ bool mGeneratingThumbnail;
+ /** The border */
+ int mBorder;
+ /** A widget that will contain the media */
+ QWidget* mpMediaContainer;
+ /** The media layout */
+ QHBoxLayout* mMediaLayout;
+ /** The audio cover */
+ QLabel* mpCover;
+ /** The media url */
+ QString mUrl;
+};
+
+#endif // UBMEDIAWIDGET_H
diff --git a/src/customWidgets/customWidgets.pri b/src/customWidgets/customWidgets.pri
new file mode 100644
index 00000000..553f6705
--- /dev/null
+++ b/src/customWidgets/customWidgets.pri
@@ -0,0 +1,10 @@
+
+HEADERS += \
+ src/customWidgets/UBMediaWidget.h \
+ src/customWidgets/UBActionableWidget.h \
+ src/customWidgets/UBGraphicsItemAction.h
+
+SOURCES += \
+ src/customWidgets/UBMediaWidget.cpp \
+ src/customWidgets/UBActionableWidget.cpp \
+ src/customWidgets/UBGraphicsItemAction.cpp
diff --git a/src/document/UBDocumentContainer.cpp b/src/document/UBDocumentContainer.cpp
index 7af9e433..5420bc10 100644
--- a/src/document/UBDocumentContainer.cpp
+++ b/src/document/UBDocumentContainer.cpp
@@ -102,6 +102,14 @@ void UBDocumentContainer::addPage(int index)
emit addThumbnailRequired(this, index);
}
+
+void UBDocumentContainer::addPixmapAt(const QPixmap *pix, int index)
+{
+ mDocumentThumbs.insert(index, pix);
+ emit documentThumbnailsUpdated(this);
+}
+
+
void UBDocumentContainer::clearThumbPage()
{
qDeleteAll(mDocumentThumbs);
diff --git a/src/document/UBDocumentContainer.h b/src/document/UBDocumentContainer.h
index 428a2b30..7993c202 100644
--- a/src/document/UBDocumentContainer.h
+++ b/src/document/UBDocumentContainer.h
@@ -42,6 +42,7 @@ class UBDocumentContainer : public QObject
virtual ~UBDocumentContainer();
void setDocument(UBDocumentProxy* document, bool forceReload = false);
+ void pureSetDocument(UBDocumentProxy *document) {mCurrentDocument = document;}
UBDocumentProxy* selectedDocument(){return mCurrentDocument;}
int pageCount(){return mCurrentDocument->pageCount();}
@@ -56,8 +57,10 @@ class UBDocumentContainer : public QObject
void clearThumbPage();
void initThumbPage();
void addPage(int index);
+ void addPixmapAt(const QPixmap *pix, int index);
void updatePage(int index);
void addEmptyThumbPage();
+ void reloadThumbnails();
void insertThumbPage(int index);
@@ -69,7 +72,6 @@ class UBDocumentContainer : public QObject
protected:
void deleteThumbPage(int index);
void updateThumbPage(int index);
- void reloadThumbnails();
signals:
void documentSet(UBDocumentProxy* document);
diff --git a/src/document/UBDocumentController.cpp b/src/document/UBDocumentController.cpp
index 47eeee22..82b0dc37 100644
--- a/src/document/UBDocumentController.cpp
+++ b/src/document/UBDocumentController.cpp
@@ -1,32 +1,25 @@
/*
- * Copyright (C) 2015-2016 Département de l'Instruction Publique (DIP-SEM)
+ * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour l'Education Numérique en Afrique (GIP ENA)
*
- * Copyright (C) 2013 Open Education Foundation
+ * This file is part of Open-Sankoré.
*
- * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour
- * l'Education Numérique en Afrique (GIP ENA)
- *
- * This file is part of OpenBoard.
- *
- * OpenBoard is free software: you can redistribute it and/or modify
+ * 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).
*
- * OpenBoard is distributed in the hope that it will be useful,
+ * 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
+ * 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 OpenBoard. If not, see .
+ * along with Open-Sankoré. If not, see .
*/
-
-
#include "UBDocumentController.h"
#include
@@ -42,6 +35,8 @@
#include "core/UBApplicationController.h"
#include "core/UBSettings.h"
#include "core/UBSetting.h"
+#include "core/UBMimeData.h"
+#include "core/UBForeignObjectsHandler.h"
#include "adaptors/UBExportPDF.h"
#include "adaptors/UBThumbnailAdaptor.h"
@@ -70,371 +65,2086 @@
#include "core/memcheck.h"
-UBDocumentController::UBDocumentController(UBMainWindow* mainWindow)
- : UBDocumentContainer(mainWindow->centralWidget())
- , mSelectionType(None)
- , mParentWidget(mainWindow->centralWidget())
- , mBoardController(UBApplication::boardController)
- , mDocumentUI(0)
- , mMainWindow(mainWindow)
- , mDocumentWidget(0)
- , mIsClosing(false)
- , mToolsPalette(0)
- , mToolsPalettePositionned(false)
- , mTrashTi(0)
- , mDocumentTrashGroupName(tr("Trash"))
- , mDefaultDocumentGroupName(tr("Untitled Documents"))
+static bool lessThan(UBDocumentTreeNode *lValue, UBDocumentTreeNode *rValue)
{
- setupViews();
- setupToolbar();
- this->selectDocument(UBApplication::boardController->selectedDocument());
- connect(this, SIGNAL(exportDone()), mMainWindow, SLOT(onExportDone()));
- connect(this, SIGNAL(documentThumbnailsUpdated(UBDocumentContainer*)), this, SLOT(refreshDocumentThumbnailsView(UBDocumentContainer*)));
+ if (lValue->nodeType() == UBDocumentTreeNode::Catalog) {
+ if (rValue->nodeType() == UBDocumentTreeNode::Catalog) {
+ return lValue->nodeName() < rValue->nodeName();
+ } else {
+ return true;
+ }
+ } else {
+ if (rValue->nodeType() == UBDocumentTreeNode::Catalog) {
+ return false;
+ } else {
+ Q_ASSERT(lValue->proxyData());
+ Q_ASSERT(rValue->proxyData());
+
+ //N/C - NNE - 20140402 : Default order set to alphabetical order
+ //return lValue->nodeName() < rValue->nodeName();
+
+ QDateTime lTime = lValue->proxyData()->documentDate();
+ QDateTime rTime = rValue->proxyData()->documentDate();
+
+ return lTime > rTime;
+ }
+ }
+
+ return false;
}
-UBDocumentController::~UBDocumentController()
+UBDocumentReplaceDialog::UBDocumentReplaceDialog(const QString &pIncommingName, const QStringList &pFileList, QWidget *parent, Qt::WindowFlags pFlags)
+ : QDialog(parent, pFlags)
+ , mFileNameList(pFileList)
+ , mIncommingName(pIncommingName)
+ , acceptText(tr("Accept"))
+ , replaceText(tr("Replace"))
+ , cancelText(tr("Cancel"))
+ , mLabelText(0)
{
- if (mDocumentUI)
- delete mDocumentUI;
-}
+ this->setStyleSheet("background:white;");
+ QVBoxLayout *mainLayout = new QVBoxLayout(this);
-void UBDocumentController::createNewDocument()
-{
- UBDocumentGroupTreeItem* group = selectedDocumentGroupTreeItem();
+ QVBoxLayout *labelLayout = new QVBoxLayout();
- if (group)
- {
- UBDocumentProxy *document = UBPersistenceManager::persistenceManager()->createDocument(group->groupName());
+ mLabelText = new QLabel(labelTextWithName(pIncommingName), this);
+ mLineEdit = new QLineEdit(this);
+ mLineEdit->setText(pIncommingName);
+ mLineEdit->selectedText();
- selectDocument(document);
- }
-}
+ mValidator = new QRegExpValidator(QRegExp("[^\\/\\:\\?\\*\\|\\<\\>\\\"]{1,}"), this);
+// mLineEdit->setValidator(mValidator);
+ labelLayout->addWidget(mLabelText);
+ labelLayout->addWidget(mLineEdit);
+ QHBoxLayout *buttonLayout = new QHBoxLayout();
-UBDocumentProxyTreeItem* UBDocumentController::findDocument(UBDocumentProxy* proxy)
-{
- QTreeWidgetItemIterator it(mDocumentUI->documentTreeWidget);
+ acceptButton = new QPushButton(acceptText, this);
+ QPushButton *cancelButton = new QPushButton(cancelText, this);
+ buttonLayout->addWidget(acceptButton);
+ buttonLayout->addWidget(cancelButton);
- while (*it)
- {
- UBDocumentProxyTreeItem *treeItem = dynamic_cast((*it));
+ mainLayout->addLayout(labelLayout);
+ mainLayout->addLayout(buttonLayout);
- if (treeItem && treeItem->proxy() == proxy)
- return treeItem;
+ acceptButton->setEnabled(false);
- ++it;
- }
+ connect(acceptButton, SIGNAL(clicked()), this, SLOT(accept()));
+ connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
+ connect(mLineEdit, SIGNAL(textEdited(QString)), this, SLOT(reactOnTextChanged(QString)));
- return 0;
+ reactOnTextChanged(mIncommingName);
}
-
-void UBDocumentController::selectDocument(UBDocumentProxy* proxy, bool setAsCurrentDocument)
+void UBDocumentReplaceDialog::setRegexp(const QRegExp pRegExp)
{
- if (proxy==NULL)
- {
- setDocument(NULL);
- return;
- }
+ mValidator->setRegExp(pRegExp);
+}
+bool UBDocumentReplaceDialog::validString(const QString &pStr)
+{
+ Q_UNUSED(pStr);
+ return mLineEdit->hasAcceptableInput();
+}
- QTreeWidgetItemIterator it(mDocumentUI->documentTreeWidget);
+void UBDocumentReplaceDialog::setFileNameAndList(const QString &fileName, const QStringList &pLst)
+{
+ mFileNameList = pLst;
+ mIncommingName = fileName;
+ mLabelText->setText(labelTextWithName(fileName));
+ mLineEdit->setText(fileName);
+ mLineEdit->selectAll();
+ mLineEdit->selectedText();
+}
- mDocumentUI->documentTreeWidget->clearSelection();
- mDocumentUI->documentTreeWidget->setCurrentItem(0);
+QString UBDocumentReplaceDialog::labelTextWithName(const QString &documentName) const
+{
+ return tr("The name %1 is allready used.\nKeeping this name will replace the document.\nProviding a new name will create a new document.")
+ .arg(documentName);
+}
- UBDocumentProxyTreeItem* selected = 0;
+void UBDocumentReplaceDialog::accept()
+{
+ QDialog::accept();
+}
+void UBDocumentReplaceDialog::reject()
+{
+ mLineEdit->clear();
+ emit closeDialog();
- while (*it)
- {
- UBDocumentProxyTreeItem* pi = dynamic_cast((*it));
+ QDialog::reject();
+}
- if (pi)
- {
- if (setAsCurrentDocument)
- pi->setIcon(0, QIcon(""));
+void UBDocumentReplaceDialog::reactOnTextChanged(const QString &pStr)
+{
+// if !mFileNameList.contains(pStr.trimmed(), Qt::CaseSensitive)
- pi->setSelected(false);
+ if (!validString(pStr)) {
+ acceptButton->setEnabled(false);
+ mLineEdit->setStyleSheet("background:#FFB3C8;");
+ acceptButton->setEnabled(false);
- if (pi->proxy() == proxy)
- {
- selected = pi;
- }
- }
+ } else if (mFileNameList.contains(pStr.trimmed(), Qt::CaseSensitive)) {
+ acceptButton->setEnabled(true);
+ mLineEdit->setStyleSheet("background:#FFB3C8;");
+ acceptButton->setText(replaceText);
- ++it;
+ } else {
+ acceptButton->setEnabled(true);
+ mLineEdit->setStyleSheet("background:white;");
+ acceptButton->setText(acceptText);
}
+}
- if (selected)
- {
- setDocument(proxy);
- emit documentThumbnailsUpdated(this);
+UBDocumentTreeNode::UBDocumentTreeNode(Type pType, const QString &pName, const QString &pDisplayName, UBDocumentProxy *pProxy ) :
+ mType(pType)
+ , mName(pName)
+ , mDisplayName(pDisplayName)
+ , mProxy(pProxy)
+{
+ if (pDisplayName.isEmpty()) {
+ mDisplayName = mName;
+ }
+ mParent = 0;
+}
- selected->setSelected(true);
+void UBDocumentTreeNode::addChild(UBDocumentTreeNode *pChild)
+{
+ if (pChild) {
+ mChildren += pChild;
+ pChild->mParent = this;
+ }
+}
- selected->parent()->setExpanded(true);
- selected->setText(0, proxy->name());
+void UBDocumentTreeNode::insertChild(int pIndex, UBDocumentTreeNode *pChild)
+{
+ if (pChild) {
+ mChildren.insert(pIndex, pChild);
+ pChild->mParent = this;
+ }
+}
- if (setAsCurrentDocument)
- {
- selected->setIcon(0, QIcon(":/images/currentDocument.png"));
- if (proxy != mBoardController->selectedDocument())
- mBoardController->setActiveDocumentScene(proxy);
- }
+void UBDocumentTreeNode::moveChild(UBDocumentTreeNode *child, int index, UBDocumentTreeNode *newParent)
+{
+ int childIndex = mChildren.indexOf(child);
+ if (childIndex == -1) {
+ return;
+ }
- mDocumentUI->documentTreeWidget->setCurrentItem(selected);
+ newParent->insertChild(index, child);
+ mChildren.removeAt(childIndex);
+}
- mDocumentUI->documentTreeWidget->scrollToItem(selected);
+void UBDocumentTreeNode::removeChild(int index)
+{
+ if (index < 0 || index > mChildren.count() - 1) {
+ return;
+ }
- mSelectionType = Document;
+ UBDocumentTreeNode *curChild = mChildren[index];
+ while (curChild->mChildren.count()) {
+ curChild->removeChild(0);
}
+
+ mChildren.removeAt(index);
+ delete curChild;
}
-void UBDocumentController::createNewDocumentGroup()
+UBDocumentTreeNode *UBDocumentTreeNode::clone()
{
- UBDocumentGroupTreeItem* docGroupItem = new UBDocumentGroupTreeItem(0); // deleted by the tree widget
- int i = 1;
- QString newFolderName = tr("New Folder");
- while (allGroupNames().contains(newFolderName))
- {
- newFolderName = tr("New Folder") + " " + QVariant(i++).toString();
+ return new UBDocumentTreeNode(this->mType
+ , this->mName
+ , this->mDisplayName
+ , this->mProxy ? new UBDocumentProxy(*this->mProxy)
+ : 0);
+}
+QString UBDocumentTreeNode::dirPathInHierarchy()
+{
+ QString result;
+ UBDocumentTreeNode *curNode = this;
+ //protect the 2nd level items
+ while (curNode->parentNode() && !curNode->isTopLevel()) {
+ result.prepend(curNode->parentNode()->nodeName() + "/");
+ curNode = curNode->parentNode();
}
- docGroupItem->setGroupName(newFolderName);
- int trashIndex = mDocumentUI->documentTreeWidget->indexOfTopLevelItem(mTrashTi);
+ if (result.endsWith("/")) {
+ result.truncate(result.count() - 1);
+ }
- mDocumentUI->documentTreeWidget->insertTopLevelItem(trashIndex, docGroupItem);
- mDocumentUI->documentTreeWidget->setCurrentItem(docGroupItem);
- mDocumentUI->documentTreeWidget->expandItem(docGroupItem);
+ return result;
}
-
-UBDocumentProxy* UBDocumentController::selectedDocumentProxy()
+UBDocumentTreeNode::~UBDocumentTreeNode()
{
- UBDocumentProxyTreeItem* proxyItem = selectedDocumentProxyTreeItem();
- return proxyItem ? proxyItem->proxy() : 0;
+ foreach (UBDocumentTreeNode *curChildren, mChildren) {
+ delete(curChildren);
+ curChildren = 0;
+ }
+ if (mProxy)
+ delete mProxy;
}
-
-UBDocumentProxyTreeItem* UBDocumentController::selectedDocumentProxyTreeItem()
+//issue 1629 - NNE - 20131105
+bool UBDocumentTreeNode::findNode(UBDocumentTreeNode *node)
{
- if (mDocumentUI && mDocumentUI->documentTreeWidget)
- {
- QList selectedItems = mDocumentUI->documentTreeWidget->selectedItems();
+ UBDocumentTreeNode *parent = node->parentNode();
- foreach (QTreeWidgetItem * item, selectedItems)
- {
- UBDocumentProxyTreeItem* proxyItem = dynamic_cast(item);
+ bool hasFound = false;
- if (proxyItem)
- {
- return proxyItem;
- }
+ while(parent){
+ if(parent == this){
+ hasFound = true;
+ break;
}
+
+ parent = parent->parentNode();
}
- return 0;
+ return hasFound;
}
-
-UBDocumentGroupTreeItem* UBDocumentController::selectedDocumentGroupTreeItem()
+UBDocumentTreeNode *UBDocumentTreeNode::nextSibling()
{
- QList selectedItems = mDocumentUI->documentTreeWidget->selectedItems();
+ UBDocumentTreeNode *parent = this->parentNode();
+ UBDocumentTreeNode *nextSibling = NULL;
- foreach (QTreeWidgetItem * item, selectedItems)
- {
- UBDocumentGroupTreeItem* groupItem = dynamic_cast(item);
+ int myIndex = parent->children().indexOf(this);
+ int indexOfNextSibling = myIndex + 1;
- if (groupItem)
- {
- return groupItem;
- }
- else
- {
- UBDocumentGroupTreeItem* parent = dynamic_cast(item->parent());
- if (parent)
- {
- return parent;
- }
- }
+ if(indexOfNextSibling < parent->children().size()){
+ nextSibling = parent->children().at(indexOfNextSibling);
}
- return 0;
+ return nextSibling;
}
-
-void UBDocumentController::itemSelectionChanged()
+UBDocumentTreeNode *UBDocumentTreeNode::previousSibling()
{
- updateCurrentSelection();
+ UBDocumentTreeNode *parent = this->parentNode();
+ UBDocumentTreeNode *previousSibling = NULL;
- emit documentThumbnailsUpdated(this);
+ int myIndex = parent->children().indexOf(this);
+ int indexOfPreviousSibling = myIndex - 1;
- if (multipleSelection())
- mSelectionType = Multiple;
- else if (selectedDocumentProxy())
- mSelectionType = Document;
- else if (selectedDocumentGroupTreeItem())
- mSelectionType = Folder;
- else
- mSelectionType = None;
+ if(indexOfPreviousSibling >= 0){
+ previousSibling = parent->children().at(indexOfPreviousSibling);
+ }
- selectionChanged();
+ return previousSibling;
}
+//issue 1629 - NNE - 20131105 : END
-void UBDocumentController::setupViews()
+UBDocumentTreeModel::UBDocumentTreeModel(QObject *parent) :
+ QAbstractItemModel(parent)
+ , mRootNode(0)
{
+ UBDocumentTreeNode *rootNode = new UBDocumentTreeNode(UBDocumentTreeNode::Catalog, "root");
- if (!mDocumentWidget)
- {
- mDocumentWidget = new QWidget(mMainWindow->centralWidget());
- mMainWindow->addDocumentsWidget(mDocumentWidget);
+ QString trashName = UBSettings::trashedDocumentGroupNamePrefix;
- mDocumentUI = new Ui::documents();
+ UBDocumentTreeNode *myDocsNode = new UBDocumentTreeNode(UBDocumentTreeNode::Catalog, UBPersistenceManager::myDocumentsName, tr("My documents"));
+ rootNode->addChild(myDocsNode);
+ UBDocumentTreeNode *modelsNode = new UBDocumentTreeNode(UBDocumentTreeNode::Catalog, UBPersistenceManager::modelsName, tr("Models"));
+ rootNode->addChild(modelsNode);
+ UBDocumentTreeNode *trashNode = new UBDocumentTreeNode(UBDocumentTreeNode::Catalog, trashName, tr("Trash"));
+ rootNode->addChild(trashNode);
+ UBDocumentTreeNode *untitledDocumentsNode = new UBDocumentTreeNode(UBDocumentTreeNode::Catalog, UBPersistenceManager::untitledDocumentsName, tr("Untitled documents"));
+ myDocsNode->addChild(untitledDocumentsNode);
- mDocumentUI->setupUi(mDocumentWidget);
+ setRootNode(rootNode);
- int thumbWidth = UBSettings::settings()->documentThumbnailWidth->get().toInt();
+ mRoot = index(0, 0, QModelIndex());
+ mMyDocuments = index(0, 0, QModelIndex());
+ mModels = index(1, 0, QModelIndex());
+ mTrash = index(2, 0, QModelIndex());
+ mUntitledDocuments = index(0, 0, mMyDocuments);
+ mAscendingOrder = true;
+}
- mDocumentUI->documentZoomSlider->setValue(thumbWidth);
- mDocumentUI->thumbnailWidget->setThumbnailWidth(thumbWidth);
+QModelIndex UBDocumentTreeModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (!mRootNode || row < 0 || column < 0) {
+ return QModelIndex();
+ }
- connect(mDocumentUI->documentZoomSlider, SIGNAL(valueChanged(int)), this,
- SLOT(documentZoomSliderValueChanged(int)));
+ UBDocumentTreeNode *nodeParent = nodeFromIndex(parent);
+ if (!nodeParent || row > nodeParent->children().count() - 1) {
+ return QModelIndex();
+ }
- connect(mMainWindow->actionOpen, SIGNAL(triggered()), this, SLOT(openSelectedItem()));
- connect(mMainWindow->actionNewFolder, SIGNAL(triggered()), this, SLOT(createNewDocumentGroup()));
- connect(mMainWindow->actionNewDocument, SIGNAL(triggered()), this, SLOT(createNewDocument()));
+ UBDocumentTreeNode *requiredNode = nodeParent->children().at(row);
+ if(!requiredNode) {
+ return QModelIndex();
+ }
- connect(mMainWindow->actionImport, SIGNAL(triggered(bool)), this, SLOT(importFile()));
+ QModelIndex resIndex = createIndex(row, column, requiredNode);
- QMenu* addMenu = new QMenu(mDocumentWidget);
- mAddFolderOfImagesAction = addMenu->addAction(tr("Add Folder of Images"));
- mAddImagesAction = addMenu->addAction(tr("Add Images"));
- mAddFileToDocumentAction = addMenu->addAction(tr("Add Pages from File"));
+ return resIndex;
+}
- connect(mAddFolderOfImagesAction, SIGNAL(triggered(bool)), this, SLOT(addFolderOfImages()));
- connect(mAddFileToDocumentAction, SIGNAL(triggered(bool)), this, SLOT(addFileToDocument()));
- connect(mAddImagesAction, SIGNAL(triggered(bool)), this, SLOT(addImages()));
+QModelIndex UBDocumentTreeModel::parent(const QModelIndex &child) const
+{
+ UBDocumentTreeNode *nodeChild = nodeFromIndex(child);
+ if (!nodeChild) {
+ return QModelIndex();
+ }
- foreach (QWidget* menuWidget, mMainWindow->actionDocumentAdd->associatedWidgets())
- {
- QToolButton *tb = qobject_cast(menuWidget);
+ UBDocumentTreeNode *nodeParent = nodeChild->parentNode();
+ if (!nodeParent) {
+ return QModelIndex();
+ }
- if (tb && !tb->menu())
- {
- tb->setObjectName("ubButtonMenu");
- tb->setPopupMode(QToolButton::InstantPopup);
+ UBDocumentTreeNode *nodePreParent = nodeParent->parentNode();
+ if (!nodePreParent) {
+ return QModelIndex();
+ }
- QMenu* menu = new QMenu(mDocumentWidget);
+ int row = nodePreParent->children().indexOf(nodeParent);
- menu->addAction(mAddFolderOfImagesAction);
- menu->addAction(mAddImagesAction);
- menu->addAction(mAddFileToDocumentAction);
+ QModelIndex resIndex = createIndex(row, 0, nodeParent);
- tb->setMenu(menu);
- }
- }
+ return resIndex;
+}
- QMenu* exportMenu = new QMenu(mDocumentWidget);
+int UBDocumentTreeModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.column() > 0) {
+ return 0;
+ }
- UBDocumentManager *documentManager = UBDocumentManager::documentManager();
- for (int i = 0; i < documentManager->supportedExportAdaptors().length(); i++)
- {
- UBExportAdaptor* adaptor = documentManager->supportedExportAdaptors()[i];
- QAction *currentExportAction = exportMenu->addAction(adaptor->exportName());
- currentExportAction->setData(i);
- connect(currentExportAction, SIGNAL(triggered (bool)), this, SLOT(exportDocument()));
- exportMenu->addAction(currentExportAction);
- }
+ UBDocumentTreeNode *nodeParent = nodeFromIndex(parent);
+ if (!nodeParent) {
+ return 0;
+ }
- foreach (QWidget* menuWidget, mMainWindow->actionExport->associatedWidgets())
- {
- QToolButton *tb = qobject_cast(menuWidget);
+ return nodeParent->children().count();
+}
- if (tb && !tb->menu())
- {
- tb->setObjectName("ubButtonMenu");
- tb->setPopupMode(QToolButton::InstantPopup);
+int UBDocumentTreeModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent)
- tb->setMenu(exportMenu);
- }
- }
+ //N/C - NNE - 20140403
+ return 3;
+}
-#ifdef Q_OS_OSX
- mMainWindow->actionDelete->setShortcut(QKeySequence(Qt::Key_Backspace));
-#else
- mMainWindow->actionDelete->setShortcut(QKeySequence(Qt::Key_Delete));
-#endif
+QVariant UBDocumentTreeModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid()) {
+ return QVariant();
+ }
- connect(mMainWindow->actionDelete, SIGNAL(triggered()), this, SLOT(deleteSelectedItem()));
- connect(mMainWindow->actionDuplicate, SIGNAL(triggered()), this, SLOT(duplicateSelectedItem()));
- connect(mMainWindow->actionRename, SIGNAL(triggered()), this, SLOT(renameSelectedItem()));
- connect(mMainWindow->actionAddToWorkingDocument, SIGNAL(triggered()), this, SLOT(addToDocument()));
+ UBDocumentTreeNode *dataNode = nodeFromIndex(index);
- loadDocumentProxies();
+ if (!dataNode)
+ return QVariant();
- mDocumentUI->documentTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
- mDocumentUI->documentTreeWidget->setDragEnabled(true);
- mDocumentUI->documentTreeWidget->viewport()->setAcceptDrops(true);
- mDocumentUI->documentTreeWidget->setDropIndicatorShown(true);
- mDocumentUI->documentTreeWidget->setIndentation(18); // 1.5 * /resources/style/treeview-branch-closed.png width
- mDocumentUI->documentTreeWidget->setDragDropMode(QAbstractItemView::InternalMove);
- connect(mDocumentUI->documentTreeWidget, SIGNAL(itemSelectionChanged()), this, SLOT(itemSelectionChanged()));
- connect(mDocumentUI->documentTreeWidget, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(itemChanged(QTreeWidgetItem *, int)));
+ if(role == Qt::DisplayRole){
+ if(index.column() == 0){
+ return dataNode->displayName();
+ }else{
+ UBDocumentProxy *proxy = proxyForIndex(index);
- connect(mDocumentUI->thumbnailWidget, SIGNAL(sceneDropped(UBDocumentProxy*, int, int)), this, SLOT(moveSceneToIndex ( UBDocumentProxy*, int, int)));
- connect(mDocumentUI->thumbnailWidget, SIGNAL(resized()), this, SLOT(thumbnailViewResized()));
- connect(mDocumentUI->thumbnailWidget, SIGNAL(mouseDoubleClick(QGraphicsItem*, int)), this, SLOT(pageDoubleClicked(QGraphicsItem*, int)));
- connect(mDocumentUI->thumbnailWidget, SIGNAL(mouseClick(QGraphicsItem*, int)), this, SLOT(pageClicked(QGraphicsItem*, int)));
+ QString displayText = "";
- connect(mDocumentUI->thumbnailWidget->scene(), SIGNAL(selectionChanged()), this, SLOT(pageSelectionChanged()));
+ if(proxy){
+ QDateTime d;
- connect(UBPersistenceManager::persistenceManager(), SIGNAL(documentCreated(UBDocumentProxy*)), this, SLOT(addDocumentInTree(UBDocumentProxy*)));
+ if(index.column() == 1){
+ d = proxy->metaData(UBSettings::documentDate).toDateTime();
+ }else if(index.column() == 2){
+ d = proxy->metaData(UBSettings::documentUpdatedAt).toDateTime();
+ }
- connect(UBPersistenceManager::persistenceManager(), SIGNAL(documentMetadataChanged(UBDocumentProxy*)), this, SLOT(updateDocumentInTree(UBDocumentProxy*)));
+ displayText = d.toString("dd/MM/yyyy hh:mm");
+ }
- connect(UBPersistenceManager::persistenceManager(), SIGNAL(documentSceneCreated(UBDocumentProxy*, int)), this, SLOT(documentSceneChanged(UBDocumentProxy*, int)));
+ return displayText;
- connect(UBPersistenceManager::persistenceManager(), SIGNAL(documentSceneWillBeDeleted(UBDocumentProxy*, int)), this, SLOT(documentSceneChanged(UBDocumentProxy*, int)));
+ }
+ }
- mDocumentUI->thumbnailWidget->setBackgroundBrush(UBSettings::documentViewLightColor);
+ if(role == UBDocumentTreeModel::CreationDate){
+ return findNodeDate(dataNode, UBSettings::documentDate);
+ }
- #ifdef Q_OS_OSX
- mMessageWindow = new UBMessageWindow(NULL);
- #else
- mMessageWindow = new UBMessageWindow(mDocumentUI->thumbnailWidget);
- #endif
+ if(role == UBDocumentTreeModel::UpdateDate){
+ return findNodeDate(dataNode, UBSettings::documentUpdatedAt);
+ }
- mMessageWindow->hide();
+ if(role == Qt::BackgroundRole){
+ if (isConstant(index) || dataNode->nodeType() == UBDocumentTreeNode::Catalog) {
+ return QBrush(0xD9DFEB);
+ }
+ if (mHighLighted.isValid() && index == mHighLighted) {
+ return QBrush(0x6682B5);
+ }
}
-}
+ if(role == Qt::UserRole +1){
+ return QVariant::fromValue(dataNode);
+ }
-QWidget* UBDocumentController::controlView()
-{
- return mDocumentWidget;
-}
+ if (index.column() == 0) {
+ switch (role) {
+ case (Qt::DecorationRole) :
+ if (mCurrentNode && mCurrentNode == dataNode) {
+ return QIcon(":images/currentDocument.png");
+ } else {
+ if (index == trashIndex()) {
+ return QIcon(":images/trash.png");
+ } else if (isConstant(index)) {
+ return QIcon(":images/libpalette/ApplicationsCategory.svg");
+ }
+ switch (static_cast(dataNode->nodeType())) {
+ case UBDocumentTreeNode::Catalog :
+ return QIcon(":images/folder.png");
+ case UBDocumentTreeNode::Document :
+ return QIcon(":images/toolbar/board.png");
+ }
+ }
+ break;
+ case (Qt::FontRole) :
+ if (isConstant(index)) {
+ QFont font;
+ font.setBold(true);
+ return font;
+ }
+ break;
+ case (Qt::ForegroundRole) :
+ if (isConstant(index)) {
+ return QColor(Qt::darkGray);
+ }
+ break;
+ }
+ }
+ return QVariant();
+}
-void UBDocumentController::setupToolbar()
+bool UBDocumentTreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
- UBApplication::app()->insertSpaceToToolbarBeforeAction(mMainWindow->documentToolBar, mMainWindow->actionBoard);
- connect(mMainWindow->actionDocumentTools, SIGNAL(triggered()), this, SLOT(toggleDocumentToolsPalette()));
+ switch (role) {
+ case Qt::EditRole:
+ if (!index.isValid() || value.toString().isEmpty()) {
+ return false;
+ }
+ setNewName(index, value.toString());
+ return true;
+ }
+ return QAbstractItemModel::setData(index, value, role);
}
-void UBDocumentController::setupPalettes()
+Qt::ItemFlags UBDocumentTreeModel::flags (const QModelIndex &index) const
{
+ Qt::ItemFlags resultFlags = QAbstractItemModel::flags(index);
+ UBDocumentTreeNode *indexNode = nodeFromIndex(index);
- mToolsPalette = new UBDocumentToolsPalette(controlView());
-
- mToolsPalette->hide();
+ if ( index.isValid() ) {
+ if (!indexNode->isRoot() && !isConstant(index)) {
+ if (!inTrash(index)) {
+ resultFlags |= Qt::ItemIsEditable;
+ }
+ resultFlags |= Qt::ItemIsDragEnabled;
+ }
+ if (indexNode->nodeType() == UBDocumentTreeNode::Catalog) {
+ resultFlags |= Qt::ItemIsDropEnabled;
+ }
+ }
- bool showToolsPalette = !mToolsPalette->isEmpty();
- mMainWindow->actionDocumentTools->setVisible(showToolsPalette);
+ return resultFlags;
+}
+
+//N/C - NNE -20140407
+QDateTime UBDocumentTreeModel::findNodeDate(UBDocumentTreeNode *node, QString type) const
+{
+ if(type == UBSettings::documentDate){
+ return findCatalogCreationDate(node);
+ }else if(type == UBSettings::documentUpdatedAt){
+ return findCatalogUpdatedDate(node);
+ }
+
+ return QDateTime();
+}
+
+QDateTime UBDocumentTreeModel::findCatalogUpdatedDate(UBDocumentTreeNode *node) const
+{
+ UBDocumentProxy *proxy = node->proxyData();
+
+ if(proxy){
+ return proxy->metaData(UBSettings::documentUpdatedAt).toDateTime();
+ }else if(node->children().size() > 0){
+ QDateTime d = findCatalogUpdatedDate(node->children().at(0));
+
+ for(int i = 1; i < node->children().size(); i++){
+ QDateTime dChild = findCatalogUpdatedDate(node->children().at(i));
+
+ if(dChild != QDateTime()){
+ if(mAscendingOrder){
+ d = qMin(d, dChild);
+ }else{
+ d = qMax(d, dChild);
+ }
+ }
+
+ }
+
+ return d;
+ }
+
+ return QDateTime();
+}
+
+QDateTime UBDocumentTreeModel::findCatalogCreationDate(UBDocumentTreeNode *node) const
+{
+ UBDocumentProxy *proxy = node->proxyData();
+
+ if(proxy){
+ return proxy->metaData(UBSettings::documentDate).toDateTime();
+ }else if(node->children().size() > 0){
+ QDateTime d = findCatalogCreationDate(node->children().at(0));
+
+ for(int i = 1; i < node->children().size(); i++){
+ QDateTime dChild = findCatalogCreationDate(node->children().at(i));
+
+ if(dChild != QDateTime()){
+ if(mAscendingOrder){
+ d = qMin(d, dChild);
+ }else{
+ d = qMax(d, dChild);
+ }
+ }
+
+ }
+
+ return d;
+ }
+
+ return QDateTime();
+}
+//N/C - NNE -20140407 : END
+
+QStringList UBDocumentTreeModel::mimeTypes() const
+{
+ QStringList types;
+ types << "text/uri-list" << "image/png" << "image/tiff" << "image/gif" << "image/jpeg";
+ return types;
+}
+
+QMimeData *UBDocumentTreeModel::mimeData (const QModelIndexList &indexes) const
+{
+ UBDocumentTreeMimeData *mimeData = new UBDocumentTreeMimeData();
+ QList indexList;
+ QList urlList;
+
+ foreach (QModelIndex index, indexes) {
+ if (index.isValid()) {
+ indexList.append(index);
+ urlList.append(QUrl());
+ }
+ }
+
+ mimeData->setUrls(urlList);
+ mimeData->setIndexes(indexList);
+
+ return mimeData;
+}
+
+bool UBDocumentTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
+{
+ if (action == Qt::IgnoreAction) {
+ return false;
+ }
+
+ if (data->hasFormat(UBApplication::mimeTypeUniboardPage)) {
+ UBDocumentTreeNode *curNode = nodeFromIndex(index(row - 1, column, parent));
+ UBDocumentProxy *targetDocProxy = curNode->proxyData();
+ const UBMimeData *ubMime = qobject_cast (data);
+ if (!targetDocProxy || !ubMime || !ubMime->items().count()) {
+ qDebug() << "an error ocured while parsing " << UBApplication::mimeTypeUniboardPage;
+ return false;
+ }
+
+// int count = 0;
+ int total = ubMime->items().size();
+
+ QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+
+ foreach (UBMimeDataItem sourceItem, ubMime->items())
+ {
+ UBDocumentProxy *fromProxy = sourceItem.documentProxy();
+ int fromIndex = sourceItem.sceneIndex();
+ int toIndex = targetDocProxy->pageCount();
+
+ UBPersistenceManager::persistenceManager()->copyDocumentScene(fromProxy, fromIndex,
+ targetDocProxy, toIndex);
+ }
+
+ QApplication::restoreOverrideCursor();
+
+ UBApplication::applicationController->showMessage(tr("%1 pages copied", "", total).arg(total), false);
+
+ return true;
+ }
+
+ const UBDocumentTreeMimeData *mimeData = qobject_cast(data);
+ if (!mimeData) {
+ qDebug() << "Incorrect mimeData, only internal one supported";
+ return false;
+ }
+
+ if (!parent.isValid()) {
+ return false;
+ }
+
+ UBDocumentTreeNode *newParentNode = nodeFromIndex(parent);
+
+ if (!newParentNode) {
+ qDebug() << "incorrect incoming parent node;";
+ return false;
+ }
+
+ QList incomingIndexes = mimeData->indexes();
+
+ foreach (QModelIndex curIndex, incomingIndexes) {
+#ifdef Q_WS_MAC
+ if (inModel(curIndex)) {
+ return true;
+ }
+#endif
+
+ //Issue N/C - NNE - 20140528 : use just the index on the first column
+ if(curIndex.column() == 0){
+ QModelIndex clonedTopLevel = copyIndexToNewParent(curIndex, parent, action == Qt::MoveAction ? aReference : aContentCopy);
+ if (nodeFromIndex(curIndex) == mCurrentNode && action == Qt::MoveAction) {
+ emit currentIndexMoved(clonedTopLevel, curIndex);
+ }
+ }
+ }
+
+ Q_UNUSED(action)
+ Q_UNUSED(row)
+ Q_UNUSED(column)
+ Q_UNUSED(parent)
+
+ return true;
+}
+
+bool UBDocumentTreeModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+ if (row < 0 || row + count > rowCount(parent))
+ return false;
+
+ beginRemoveRows( parent, row, row + count - 1);
+
+ UBDocumentTreeNode *parentNode = nodeFromIndex(parent);
+ for (int i = row; i < row + count; i++) {
+ UBDocumentTreeNode *curChildNode = parentNode->children().at(i);
+ QModelIndex curChildIndex = parent.child(i, 0);
+ if (curChildNode) {
+ if (rowCount(curChildIndex)) {
+ while (rowCount(curChildIndex)) {
+ removeRows(0, 1, curChildIndex);
+ }
+ }
+ }
+ mNewDocuments.removeAll(curChildNode->proxyData());
+ parentNode->removeChild(i);
+
+ }
+
+ endRemoveRows();
+ return true;
+}
+
+QModelIndex UBDocumentTreeModel::indexForNode(UBDocumentTreeNode *pNode) const
+{
+ if (pNode == 0) {
+ return QModelIndex();
+ }
+
+ return pIndexForNode(QModelIndex(), pNode);
+}
+
+QPersistentModelIndex UBDocumentTreeModel::persistentIndexForNode(UBDocumentTreeNode *pNode)
+{
+ return QPersistentModelIndex(indexForNode(pNode));
+}
+
+UBDocumentTreeNode *UBDocumentTreeModel::findProxy(UBDocumentProxy *pSearch, UBDocumentTreeNode *pParent) const
+{
+ foreach (UBDocumentTreeNode *curNode, pParent->children())
+ {
+ if (UBDocumentTreeNode::Catalog != curNode->nodeType())
+ {
+ if (curNode->proxyData()->theSameDocument(pSearch))
+ return curNode;
+ }
+ else if (curNode->children().count())
+ {
+ UBDocumentTreeNode *recursiveDescendResult = findProxy(pSearch, curNode);
+ if (recursiveDescendResult)
+ return findProxy(pSearch, curNode);
+ }
+ }
+
+ return 0;
+}
+
+QModelIndex UBDocumentTreeModel::pIndexForNode(const QModelIndex &parent, UBDocumentTreeNode *pNode) const
+{
+ for (int i = 0; i < rowCount(parent); i++) {
+ QModelIndex curIndex = index(i, 0, parent);
+ if (curIndex.internalPointer() == pNode) {
+ return curIndex;
+ } else if (rowCount(curIndex) > 0) {
+ QModelIndex recursiveDescendIndex = pIndexForNode(curIndex, pNode);
+ if (recursiveDescendIndex.isValid()) {
+ return recursiveDescendIndex;
+ }
+ }
+ }
+ return QModelIndex();
+}
+
+//N/C - NNE - 20140411
+void UBDocumentTreeModel::copyIndexToNewParent(const QModelIndexList &list, const QModelIndex &newParent, eCopyMode pMode)
+{
+ for(int i = 0; i < list.size(); i++){
+ if(list.at(i).column() == 0){
+ copyIndexToNewParent(list.at(i), newParent, pMode);
+ }
+ }
+}
+//N/C - NNE - 20140411 : END
+
+QPersistentModelIndex UBDocumentTreeModel::copyIndexToNewParent(const QModelIndex &source, const QModelIndex &newParent, eCopyMode pMode)
+{
+ UBDocumentTreeNode *nodeParent = nodeFromIndex(newParent);
+ UBDocumentTreeNode *nodeSource = nodeFromIndex(source);
+
+ if (!nodeParent || !nodeSource) {
+ return QModelIndex();
+ }
+
+ //beginInsertRows(newParent, rowCount(newParent), rowCount(newParent));
+
+ UBDocumentTreeNode *clonedNodeSource = 0;
+ switch (static_cast(pMode)) {
+ case aReference:
+ clonedNodeSource = nodeSource->clone();
+ if (mNewDocuments.contains(nodeSource->proxyData())) { //update references for session documents
+ mNewDocuments << clonedNodeSource->proxyData();
+
+ UBPersistenceManager::persistenceManager()->reassignDocProxy(clonedNodeSource->proxyData(), nodeSource->proxyData());
+ }
+ break;
+
+ case aContentCopy:
+ UBDocumentProxy* duplicatedProxy = 0;
+ if (nodeSource->nodeType() == UBDocumentTreeNode::Document && nodeSource->proxyData()) {
+ duplicatedProxy = UBPersistenceManager::persistenceManager()->duplicateDocument(nodeSource->proxyData());
+ duplicatedProxy->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime()));
+ UBMetadataDcSubsetAdaptor::persist(duplicatedProxy);
+ }
+ clonedNodeSource = new UBDocumentTreeNode(nodeSource->nodeType()
+ , nodeSource->nodeName()
+ , nodeSource->displayName()
+ , duplicatedProxy);
+ break;
+ }
+
+ // Determine whether to provide a name with postfix if the name in current level already exists
+ QString newName = clonedNodeSource->nodeName();
+ if ((source.parent() != newParent
+ || pMode != aReference)
+ && (newParent != trashIndex() || !inTrash(newParent))) {
+ newName = adjustNameForParentIndex(newName, newParent);
+ clonedNodeSource->setNodeName(newName);
+ }
+
+ if (clonedNodeSource->proxyData()) {
+ clonedNodeSource->proxyData()->setMetaData(UBSettings::documentGroupName, virtualPathForIndex(newParent));
+ clonedNodeSource->proxyData()->setMetaData(UBSettings::documentName, newName);
+ UBPersistenceManager::persistenceManager()->persistDocumentMetadata(clonedNodeSource->proxyData());
+ }
+
+ addNode(clonedNodeSource, newParent);
+ //endInsertRows();
+
+ QPersistentModelIndex newParentIndex = createIndex(rowCount(newParent), 0, clonedNodeSource);
+
+ if (rowCount(source)) {
+ for (int i = 0; i < rowCount(source); i++) {
+ QModelIndex curNewParentIndexChild = source.child(i, 0);
+ copyIndexToNewParent(curNewParentIndexChild, newParentIndex, pMode);
+ }
+ }
+
+ return newParentIndex;
+}
+
+//N/C - NNE - 20140409
+void UBDocumentTreeModel::moveIndexes(const QModelIndexList &source, const QModelIndex &destination)
+{
+ //Issue N/C - NNE - 20140528
+ QModelIndex destinationParent = destination;
+ while(!isCatalog(destinationParent)){
+ destinationParent = destinationParent.parent();
+ }
+
+ UBDocumentTreeNode *newParentNode = nodeFromIndex(destinationParent);
+
+ bool hasOneInsertion = false;
+
+ for(int i = 0; i < source.size(); i++){
+ UBDocumentTreeNode *sourceNode = nodeFromIndex(source.at(i));
+ QModelIndex s = source.at(i);
+
+ if(newParentNode == sourceNode->parentNode() || sourceNode->findNode(newParentNode))
+ continue;
+
+ if(s.internalId() != destinationParent.internalId()){
+ int sourceIndex = source.at(i).row();
+ int destIndex = positionForParent(sourceNode, newParentNode);
+
+ beginMoveRows(s.parent(), sourceIndex, sourceIndex, destinationParent, destIndex);
+ fixNodeName(s, destinationParent);
+ sourceNode->parentNode()->moveChild(sourceNode, destIndex, newParentNode);
+ updateIndexNameBindings(sourceNode);
+
+ hasOneInsertion = true;
+ }
+ }
+
+ if(hasOneInsertion)
+ endMoveRows();
+}
+
+//N/C - NNE - 20140409
+
+void UBDocumentTreeModel::moveIndex(const QModelIndex &what, const QModelIndex &destination)
+{
+ QModelIndexList list;
+ list.push_back(what);
+ moveIndexes(list, destination);
+}
+
+void UBDocumentTreeModel::setCurrentDocument(UBDocumentProxy *pDocument)
+{
+ UBDocumentTreeNode *testCurNode = findProxy(pDocument, mRootNode);
+
+ if (testCurNode) {
+ setCurrentNode(testCurNode);
+ }
+}
+
+QModelIndex UBDocumentTreeModel::indexForProxy(UBDocumentProxy *pSearch) const
+{
+ UBDocumentTreeNode *proxy = findProxy(pSearch, mRootNode);
+ if (!proxy) {
+ return QModelIndex();
+ }
+
+ return indexForNode(proxy);
+}
+
+void UBDocumentTreeModel::setRootNode(UBDocumentTreeNode *pRoot)
+{
+ mRootNode = pRoot;
+ //reset();
+}
+
+UBDocumentProxy *UBDocumentTreeModel::proxyForIndex(const QModelIndex &pIndex) const
+{
+ UBDocumentTreeNode *node = nodeFromIndex(pIndex);
+ if (!node) {
+ return 0;
+ }
+
+ return node->proxyData();
+}
+
+QString UBDocumentTreeModel::virtualDirForIndex(const QModelIndex &pIndex) const
+{
+ QString result;
+ UBDocumentTreeNode *curNode = nodeFromIndex(pIndex);
+ //protect the 2nd level items
+ while (curNode->parentNode() && !curNode->isTopLevel()) {
+ result.prepend(curNode->parentNode()->nodeName() + "/");
+ curNode = curNode->parentNode();
+ }
+
+ if (result.endsWith("/")) {
+ result.truncate(result.count() - 1);
+ }
+
+ return result;
+}
+
+QString UBDocumentTreeModel::virtualPathForIndex(const QModelIndex &pIndex) const
+{
+ UBDocumentTreeNode *curNode = nodeFromIndex(pIndex);
+ Q_ASSERT(curNode);
+
+ return virtualDirForIndex(pIndex) + "/" + curNode->nodeName();
+}
+
+QStringList UBDocumentTreeModel::nodeNameList(const QModelIndex &pIndex) const
+{
+ QStringList result;
+
+ UBDocumentTreeNode *catalog = nodeFromIndex(pIndex);
+ if (catalog->nodeType() != UBDocumentTreeNode::Catalog) {
+ return QStringList();
+ }
+
+ foreach (UBDocumentTreeNode *curNode, catalog->children()) {
+ result << curNode->nodeName();
+ }
+
+ return result;
+}
+
+bool UBDocumentTreeModel::newNodeAllowed(const QModelIndex &pSelectedIndex) const
+{
+ if (!pSelectedIndex.isValid()) {
+ return false;
+ }
+
+ if (inTrash(pSelectedIndex) || pSelectedIndex == trashIndex()) {
+ return false;
+ }
+
+ return true;
+}
+
+QModelIndex UBDocumentTreeModel::goTo(const QString &dir)
+{
+ QStringList pathList = dir.split("/", QString::SkipEmptyParts);
+
+ if (pathList.isEmpty()) {
+ return untitledDocumentsIndex();
+ }
+
+ if (pathList.first() != UBPersistenceManager::myDocumentsName
+ && pathList.first() != UBSettings::trashedDocumentGroupNamePrefix
+ && pathList.first() != UBPersistenceManager::modelsName) {
+ pathList.prepend(UBPersistenceManager::myDocumentsName);
+ }
+
+ QModelIndex parentIndex;
+
+ bool searchingNode = true;
+ while (!pathList.isEmpty())
+ {
+ QString curLevelName = pathList.takeFirst();
+ if (searchingNode) {
+ searchingNode = false;
+ for (int i = 0; i < rowCount(parentIndex); ++i) {
+ QModelIndex curChildIndex = index(i, 0, parentIndex);
+ if (nodeFromIndex(curChildIndex)->nodeName() == curLevelName) {
+ searchingNode = true;
+ parentIndex = curChildIndex;
+ break;
+ }
+ }
+ }
+
+ if (!searchingNode) {
+ UBDocumentTreeNode *newChild = new UBDocumentTreeNode(UBDocumentTreeNode::Catalog, curLevelName);
+ parentIndex = addNode(newChild, parentIndex);
+ }
+ }
+
+ return parentIndex;
+}
+
+bool UBDocumentTreeModel::inTrash(const QModelIndex &index) const
+{
+ return isDescendantOf(index, trashIndex());
+}
+
+bool UBDocumentTreeModel::inModel(const QModelIndex &index) const
+{
+ return isDescendantOf(index, modelsIndex());
+}
+
+bool UBDocumentTreeModel::inUntitledDocuments(const QModelIndex &index) const
+{
+ return isDescendantOf(index, untitledDocumentsIndex());
+}
+
+//N/C - NNE - 20140408
+bool UBDocumentTreeModel::inMyDocuments(const QModelIndex &index) const
+{
+ return isDescendantOf(index, myDocumentsIndex());
+}
+//N/C - NNE - 20140408 : END
+
+void UBDocumentTreeModel::addDocument(UBDocumentProxy *pProxyData, const QModelIndex &pParent)
+{
+ if (!pProxyData) {
+ return;
+ }
+ QString docName = pProxyData->metaData(UBSettings::documentName).toString();
+ QString docGroupName = pProxyData->metaData(UBSettings::documentGroupName).toString();
+
+ if (docName.isEmpty()) {
+ return;
+ }
+
+ QModelIndex lParent = pParent;
+ UBDocumentTreeNode *freeNode = new UBDocumentTreeNode(UBDocumentTreeNode::Document
+ , docName
+ , QString()
+ , pProxyData);
+ if (!pParent.isValid()) {
+ lParent = goTo(docGroupName);
+ }
+
+ addNode(freeNode, lParent);
+}
+
+void UBDocumentTreeModel::addNewDocument(UBDocumentProxy *pProxyData, const QModelIndex &pParent)
+{
+ addDocument(pProxyData, pParent);
+ mNewDocuments << pProxyData;
+}
+
+void UBDocumentTreeModel::addCatalog(const QString &pName, const QModelIndex &pParent)
+{
+ if (pName.isEmpty() || !pParent.isValid()) {
+ return;
+ }
+
+ UBDocumentTreeNode *catalogNode = new UBDocumentTreeNode(UBDocumentTreeNode::Catalog, pName);
+ addNode(catalogNode, pParent);
+}
+
+void UBDocumentTreeModel::setNewName(const QModelIndex &index, const QString &newName)
+{
+ if (!index.isValid()) {
+ return;
+ }
+
+ UBDocumentTreeNode *indexNode = nodeFromIndex(index);
+
+ QString magicSeparator = "+!##s";
+ if (isCatalog(index)) {
+ QString fullNewName = newName;
+ if (!newName.contains(magicSeparator)) {
+ indexNode->setNodeName(newName);
+ QString virtualDir = virtualDirForIndex(index);
+ fullNewName.prepend(virtualDir.isEmpty() ? "" : virtualDir + magicSeparator);
+ }
+ for (int i = 0; i < rowCount(index); i++) {
+ QModelIndex subIndex = this->index(i, 0, index);
+ setNewName(subIndex, fullNewName + magicSeparator + subIndex.data().toString());
+ }
+
+ } else if (isDocument(index)) {
+ Q_ASSERT(indexNode->proxyData());
+
+ int prefixIndex = newName.lastIndexOf(magicSeparator);
+ if (prefixIndex != -1) {
+ QString newDocumentGroupName = newName.left(prefixIndex).replace(magicSeparator, "/");
+ indexNode->proxyData()->setMetaData(UBSettings::documentGroupName, newDocumentGroupName);
+ } else {
+ indexNode->setNodeName(newName);
+ indexNode->proxyData()->setMetaData(UBSettings::documentName, newName);
+ }
+
+ UBPersistenceManager::persistenceManager()->persistDocumentMetadata(indexNode->proxyData());
+ }
+}
+
+QString UBDocumentTreeModel::adjustNameForParentIndex(const QString &pName, const QModelIndex &pIndex)
+{
+ int i = 0;
+ QString newName = pName;
+ QStringList siblingNames = nodeNameList(pIndex);
+ while (siblingNames.contains(newName)) {
+ newName = pName + " " + QVariant(++i).toString();
+ }
+
+ return newName;
+}
+
+void UBDocumentTreeModel::fixNodeName(const QModelIndex &source, const QModelIndex &dest)
+{
+ // Determine whether to provide a name with postfix if the name in current level allready exists
+ UBDocumentTreeNode *srcNode = nodeFromIndex(source);
+ Q_ASSERT(srcNode);
+
+ QString newName = srcNode->nodeName();
+ if (source.parent() != dest
+ && (dest != trashIndex()
+ || !inTrash(dest))) {
+ newName = adjustNameForParentIndex(newName, dest);
+ srcNode->setNodeName(newName);
+ nodeFromIndex(source)->setNodeName(newName);
+ }
+}
+
+void UBDocumentTreeModel::updateIndexNameBindings(UBDocumentTreeNode *nd)
+{
+ Q_ASSERT(nd);
+
+ if (nd->nodeType() == UBDocumentTreeNode::Catalog) {
+ foreach (UBDocumentTreeNode *lnd, nd->children()) {
+ updateIndexNameBindings(lnd);
+ }
+ } else if (nd->proxyData()) {
+ nd->proxyData()->setMetaData(UBSettings::documentGroupName, virtualPathForIndex(indexForNode(nd->parentNode())));
+ nd->proxyData()->setMetaData(UBSettings::documentName, nd->nodeName());
+ UBPersistenceManager::persistenceManager()->persistDocumentMetadata(nd->proxyData());
+ }
+}
+
+bool UBDocumentTreeModel::isDescendantOf(const QModelIndex &pPossibleDescendant, const QModelIndex &pPossibleAncestor) const
+{
+ if (!pPossibleDescendant.isValid()) {
+ return false;
+ }
+
+ QModelIndex ancestor = pPossibleDescendant;
+ while (ancestor.parent().isValid()) {
+ ancestor = ancestor.parent();
+ if (ancestor == pPossibleAncestor) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+QModelIndex UBDocumentTreeModel::addNode(UBDocumentTreeNode *pFreeNode, const QModelIndex &pParent, eAddItemMode pMode)
+{
+ UBDocumentTreeNode *tstParent = nodeFromIndex(pParent);
+
+ if (!pParent.isValid() || tstParent->nodeType() != UBDocumentTreeNode::Catalog) {
+ return QModelIndex();
+ }
+ int newIndex = pMode == aDetectPosition ? positionForParent(pFreeNode, tstParent): tstParent->children().size();
+ beginInsertRows(pParent, newIndex, newIndex);
+ tstParent->insertChild(newIndex, pFreeNode);
+ endInsertRows();
+
+ return createIndex(newIndex, 0, pFreeNode);
+}
+
+int UBDocumentTreeModel::positionForParent(UBDocumentTreeNode *pFreeNode, UBDocumentTreeNode *pParentNode)
+{
+ Q_ASSERT(pFreeNode);
+ Q_ASSERT(pParentNode);
+ Q_ASSERT(pParentNode->nodeType() == UBDocumentTreeNode::Catalog);
+
+ int c = -1;
+ int childCount = pParentNode->children().count();
+ while (c <= childCount) {
+ if (++c == childCount || lessThan(pFreeNode, pParentNode->children().at(c))) {
+ break;
+ }
+ }
+ return c == -1 ? childCount : c;
+}
+
+UBDocumentTreeNode *UBDocumentTreeModel::nodeFromIndex(const QModelIndex &pIndex) const
+{
+ if (pIndex.isValid()) {
+ return static_cast(pIndex.internalPointer());
+ } else {
+ return mRootNode;
+ }
+}
+
+bool UBDocumentTreeModel::nodeLessThan(const UBDocumentTreeNode *firstIndex, const UBDocumentTreeNode *secondIndex)
+{
+ return firstIndex->nodeName() < secondIndex->nodeName();
+}
+
+UBDocumentTreeModel::~UBDocumentTreeModel()
+{
+ delete mRootNode;
+}
+
+UBDocumentTreeView::UBDocumentTreeView(QWidget *parent) : QTreeView(parent)
+{
+ setObjectName("UBDocumentTreeView");
+ setRootIsDecorated(true);
+}
+
+void UBDocumentTreeView::setSelectedAndExpanded(const QModelIndex &pIndex, bool pExpand)
+{
+ if (!pIndex.isValid()) {
+ return;
+ }
+
+ QModelIndex indexCurrentDoc = pIndex;
+ clearSelection();
+
+ UBSortFilterProxyModel *proxy = dynamic_cast(model());
+
+ QItemSelectionModel::SelectionFlags sel = pExpand
+ ? QItemSelectionModel::Select
+ : QItemSelectionModel::Deselect;
+
+ selectionModel()->select(proxy->mapFromSource(indexCurrentDoc), QItemSelectionModel::Rows | sel);
+
+ setCurrentIndex(pExpand
+ ? indexCurrentDoc
+ : QModelIndex());
+
+ while (indexCurrentDoc.parent().isValid()) {
+ setExpanded(indexCurrentDoc.parent(), pExpand);
+ indexCurrentDoc = indexCurrentDoc.parent();
+ }
+
+ scrollTo(proxy->mapFromSource(pIndex), QAbstractItemView::PositionAtCenter);
+}
+
+void UBDocumentTreeView::onModelIndexChanged(const QModelIndex &pNewIndex, const QModelIndex &pOldIndex)
+{
+ Q_UNUSED(pOldIndex)
+
+ //N/C - NNE - 20140407
+ QModelIndex indexSource = mapIndexToSource(pNewIndex);
+
+ setSelectedAndExpanded(indexSource, true);
+}
+
+void UBDocumentTreeView::hSliderRangeChanged(int min, int max)
+{
+ Q_UNUSED(min);
+ Q_UNUSED(max);
+
+ QScrollBar *hScroller = horizontalScrollBar();
+ if (hScroller)
+ {
+ hScroller->triggerAction(QAbstractSlider::SliderToMaximum);
+ }
+}
+
+void UBDocumentTreeView::dragEnterEvent(QDragEnterEvent *event)
+{
+ QTreeView::dragEnterEvent(event);
+ event->accept();
+ event->acceptProposedAction();
+}
+
+void UBDocumentTreeView::dragLeaveEvent(QDragLeaveEvent *event)
+{
+ Q_UNUSED(event);
+
+ UBDocumentTreeModel *docModel = 0;
+
+ UBSortFilterProxyModel *proxy = dynamic_cast(model());
+
+ if(proxy){
+ docModel = dynamic_cast(proxy->sourceModel());
+ }else{
+ docModel = dynamic_cast(model());
+ }
+
+ docModel->setHighLighted(QModelIndex());
+ update();
+}
+
+void UBDocumentTreeView::dragMoveEvent(QDragMoveEvent *event)
+{
+ bool acceptIt = isAcceptable(selectedIndexes().first(), indexAt(event->pos()));
+
+ if (event->mimeData()->hasFormat(UBApplication::mimeTypeUniboardPage)) {
+ UBSortFilterProxyModel *proxy = dynamic_cast(model());
+
+ UBDocumentTreeModel *docModel = 0;
+
+ if(proxy){
+ docModel = dynamic_cast(proxy->sourceModel());
+ }else{
+ docModel = dynamic_cast(model());
+ }
+
+ QModelIndex targetIndex = mapIndexToSource(indexAt(event->pos()));
+
+ if (!docModel || !docModel->isDocument(targetIndex) || docModel->inTrash(targetIndex)) {
+ event->ignore();
+ event->setDropAction(Qt::IgnoreAction);
+ docModel->setHighLighted(QModelIndex());
+ acceptIt = false;
+ } else {
+ docModel->setHighLighted(targetIndex);
+ acceptIt = true;
+ }
+ updateIndexEnvirons(indexAt(event->pos()));
+ }
+ QTreeView::dragMoveEvent(event);
+
+ event->setAccepted(acceptIt);
+}
+
+void UBDocumentTreeView::dropEvent(QDropEvent *event)
+{
+ event->ignore();
+ event->setDropAction(Qt::IgnoreAction);
+ UBDocumentTreeModel *docModel = 0;
+
+ //N/C - NNE - 20140408
+ UBSortFilterProxyModel *proxy = dynamic_cast(model());
+ if(proxy){
+ docModel = dynamic_cast(proxy->sourceModel());
+ }
+
+ QModelIndex targetIndex = mapIndexToSource(indexAt(event->pos()));
+ QModelIndexList dropIndex = mapIndexesToSource(selectedIndexes());
+
+ //clear the selection right after
+ selectionModel()->clearSelection();
+
+ bool isUBPage = event->mimeData()->hasFormat(UBApplication::mimeTypeUniboardPage);
+
+ bool inModel = docModel->inModel(targetIndex) || targetIndex == docModel->modelsIndex();
+
+ //just check the first index, because the selection is exclusive between
+ //myDocuments, Model and Tash
+ bool isSourceAModel = docModel->inModel(dropIndex.first());
+
+ //issue 1629 - NNE - 20131212
+ bool targetIsInTrash = docModel->inTrash(targetIndex) || docModel->trashIndex() == targetIndex;
+
+ if (isUBPage) {
+ UBDocumentProxy *targetDocProxy = docModel->proxyData(targetIndex);
+ const UBMimeData *ubMime = qobject_cast (event->mimeData());
+ if (!targetDocProxy || !ubMime || !ubMime->items().count()) {
+ qDebug() << "an error ocured while parsing " << UBApplication::mimeTypeUniboardPage;
+ QTreeView::dropEvent(event);
+ return;
+ }
+
+ int total = ubMime->items().size();
+ QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+
+ foreach (UBMimeDataItem sourceItem, ubMime->items())
+ {
+ UBDocumentProxy *fromProxy = sourceItem.documentProxy();
+ int fromIndex = sourceItem.sceneIndex();
+ int toIndex = targetDocProxy->pageCount();
+
+ UBPersistenceManager::persistenceManager()->copyDocumentScene(fromProxy, fromIndex,
+ targetDocProxy, toIndex);
+ }
+
+ QApplication::restoreOverrideCursor();
+ UBApplication::applicationController->showMessage(tr("%1 pages copied", "", total).arg(total), false);
+
+ docModel->setHighLighted(QModelIndex());
+ }
+ else if(isSourceAModel){
+ QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+
+ if(targetIsInTrash){
+ //issue 1629 - NNE - 20131212 : If the source is a model and we want to delete it
+ UBApplication::documentController->moveIndexesToTrash(dropIndex, docModel);
+ }else{
+ UBDocumentTreeNode* node = docModel->nodeFromIndex(targetIndex);
+ QModelIndex targetParentIndex;
+ if(node->nodeType() == UBDocumentTreeNode::Catalog)
+ targetParentIndex = docModel->indexForNode(node);
+ else
+ targetParentIndex = docModel->indexForNode(node->parentNode());
+
+ docModel->copyIndexToNewParent(dropIndex, targetParentIndex,UBDocumentTreeModel::aContentCopy);
+ docModel->setHighLighted(QModelIndex());
+ }
+
+ QApplication::restoreOverrideCursor();
+ }
+ else if(!inModel){
+ //issue 1632 - NNE - 20131212
+ if(targetIsInTrash){
+ UBApplication::documentController->moveIndexesToTrash(dropIndex, docModel);
+ }else{
+ docModel->moveIndexes(dropIndex, targetIndex);
+ }
+
+ expand(proxy->mapFromSource(targetIndex));
+
+ //issue 1632 - NNE - 20131212 : END
+ }else if(inModel){
+ event->setDropAction(Qt::CopyAction);
+ }
+
+ QTreeView::dropEvent(event);
+}
+
+void UBDocumentTreeView::paintEvent(QPaintEvent *event)
+{
+ QTreeView::paintEvent(event);
+}
+
+void UBDocumentTreeView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
+{
+ QTreeView::rowsAboutToBeRemoved(parent, start, end);
+}
+
+bool UBDocumentTreeView::isAcceptable(const QModelIndex &dragIndex, const QModelIndex &atIndex)
+{
+ QModelIndex dragIndexSource = mapIndexToSource(dragIndex);
+ QModelIndex atIndexSource = mapIndexToSource(atIndex);
+
+ if (!dragIndexSource.isValid()) {
+ return false;
+ }
+
+ if (fullModel() && fullModel()->inModel(dragIndexSource)) {
+ if (atIndexSource == fullModel()->modelsIndex() || fullModel()->inModel(atIndexSource)) {
+ return false; //do not accept drop from model to itself
+ }
+ }
+
+ return true;
+}
+
+Qt::DropAction UBDocumentTreeView::acceptableAction(const QModelIndex &dragIndex, const QModelIndex &atIndex)
+{
+ if (fullModel()->inModel(dragIndex)) {
+ if (atIndex == fullModel()->trashIndex() || fullModel()->inTrash(atIndex)) {
+ return Qt::MoveAction; //do not accept drop from model to trash, only "delete" command accepted
+ }
+ return Qt::CopyAction;
+ } else {
+ return Qt::MoveAction;
+ }
+
+ return Qt::IgnoreAction;
+}
+
+void UBDocumentTreeView::updateIndexEnvirons(const QModelIndex &index)
+{
+ QRect updateRect = visualRect(index);
+ const int multipler = 3;
+ updateRect.adjust(0, -updateRect.height() * multipler, 0, updateRect.height() * multipler);
+ update(updateRect);
+}
+
+//N/C - NNE - 20140404
+QModelIndex UBDocumentTreeView::mapIndexToSource(const QModelIndex &index)
+{
+ UBSortFilterProxyModel *proxy = dynamic_cast(model());
+
+ if(proxy){
+ return proxy->mapToSource(index);
+ }
+
+ return index;
+}
+
+QModelIndexList UBDocumentTreeView::mapIndexesToSource(const QModelIndexList &indexes)
+{
+ UBSortFilterProxyModel *proxy = dynamic_cast(model());
+
+ if(proxy){
+ QModelIndexList list;
+
+ for(int i = 0; i < indexes.size(); i++){
+ list.push_back(proxy->mapToSource(indexes.at(i)));
+ }
+
+ return list;
+ }
+
+ return indexes;
+}
+//N/C - NNE - 20140404 : END
+
+UBDocumentTreeItemDelegate::UBDocumentTreeItemDelegate(QObject *parent)
+ : QStyledItemDelegate(parent)
+{
+
+}
+
+void UBDocumentTreeItemDelegate::commitAndCloseEditor()
+{
+ QLineEdit *lineEditor = qobject_cast(sender());
+ if (lineEditor) {
+ emit commitData(lineEditor);
+ emit closeEditor(lineEditor);
+ }
+}
+
+void UBDocumentTreeItemDelegate::processChangedText(const QString &str) const
+{
+ QLineEdit *editor = qobject_cast(sender());
+ if (!editor) {
+ return;
+ }
+
+ if (!validateString(str)) {
+ editor->setStyleSheet("background-color: #FFB3C8;");
+ } else {
+ editor->setStyleSheet("background-color: #FFFFFF;");
+ }
+}
+
+bool UBDocumentTreeItemDelegate::validateString(const QString &str) const
+{
+ return QRegExp("[^\\/\\:\\?\\*\\|\\<\\>\\\"]{1,}").exactMatch(str)
+ && !mExistingFileNames.contains(str);
+
+}
+
+QWidget *UBDocumentTreeItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+ Q_UNUSED(option);
+
+ //N/C - NNE - 20140407 : Add the test for the index column.
+ if(index.column() == 0){
+ mExistingFileNames.clear();
+ const UBDocumentTreeModel *indexModel = qobject_cast(index.model());
+ if (indexModel) {
+ mExistingFileNames = indexModel->nodeNameList(index.parent());
+ mExistingFileNames.removeOne(index.data().toString());
+ }
+
+ QLineEdit *nameEditor = new QLineEdit(parent);
+ connect(nameEditor, SIGNAL(editingFinished()), this, SLOT(commitAndCloseEditor()));
+ connect(nameEditor, SIGNAL(textChanged(QString)), this, SLOT(processChangedText(QString)));
+ return nameEditor;
+ }
+
+ //N/C - NNe - 20140407 : the other column are not editable.
+ return 0;
+}
+
+void UBDocumentTreeItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
+{
+ if (index.column() == 0) {
+ QLineEdit *lineEditor = qobject_cast(editor);
+ lineEditor->setText(index.data().toString());
+ lineEditor->selectAll();
+ }
+}
+
+void UBDocumentTreeItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
+{
+ QLineEdit *lineEditor = qobject_cast(editor);
+ if (validateString(lineEditor->text())) {
+ model->setData(index, lineEditor->text());
+ }
+}
+
+void UBDocumentTreeItemDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex &index) const
+{
+ QStyledItemDelegate::paint(painter, option, index);
+}
+
+UBDocumentController::UBDocumentController(UBMainWindow* mainWindow)
+ : UBDocumentContainer(mainWindow->centralWidget())
+ , mSelectionType(None)
+ , mParentWidget(mainWindow->centralWidget())
+ , mBoardController(UBApplication::boardController)
+ , mDocumentUI(0)
+ , mMainWindow(mainWindow)
+ , mDocumentWidget(0)
+ , mIsClosing(false)
+ , mToolsPalette(0)
+ , mToolsPalettePositionned(false)
+ , mTrashTi(0)
+ , mDocumentTrashGroupName(tr("Trash"))
+ , mDefaultDocumentGroupName(tr("Untitled Documents"))
+ , mCurrentTreeDocument(0)
+ , mCurrentIndexMoved(false)
+{
+
+ setupViews();
+ setupToolbar();
+ connect(this, SIGNAL(exportDone()), mMainWindow, SLOT(onExportDone()));
+ connect(this, SIGNAL(documentThumbnailsUpdated(UBDocumentContainer*)), this, SLOT(refreshDocumentThumbnailsView(UBDocumentContainer*)));
+
+ mUserHasChangedSortOrder = false;
+}
+
+UBDocumentController::~UBDocumentController()
+{
+ if (mDocumentUI)
+ delete mDocumentUI;
+}
+
+void UBDocumentController::createNewDocument()
+{
+ UBPersistenceManager *pManager = UBPersistenceManager::persistenceManager();
+ UBDocumentTreeModel *docModel = pManager->mDocumentTreeStructureModel;
+ QModelIndex selectedIndex = firstSelectedTreeIndex();
+ if (selectedIndex.isValid()) {
+ QString groupName = docModel->isCatalog(selectedIndex)
+ ? docModel->virtualPathForIndex(selectedIndex)
+ : docModel->virtualDirForIndex(selectedIndex);
+
+ UBDocumentProxy *document = pManager->createDocument(groupName);
+ selectDocument(document);
+
+ if (document)
+ pManager->mDocumentTreeStructureModel->markDocumentAsNew(document);
+ }
+}
+
+void UBDocumentController::selectDocument(UBDocumentProxy* proxy, bool setAsCurrentDocument, const bool onImport)
+{
+ if (proxy==NULL)
+ {
+ setDocument(NULL);
+ return;
+ }
+
+ if (setAsCurrentDocument) {
+ UBPersistenceManager::persistenceManager()->mDocumentTreeStructureModel->setCurrentDocument(proxy);
+ QModelIndex indexCurrentDoc = UBPersistenceManager::persistenceManager()->mDocumentTreeStructureModel->indexForProxy(proxy);
+ mDocumentUI->documentTreeView->setSelectedAndExpanded(indexCurrentDoc, true);
+
+ if (proxy != mBoardController->selectedDocument()) // only if wanted Document is different from document actually on Board, // ALTI/AOU - 20140217
+ {
+ //issue 1629 - NNE - 20131105 : When set a current document, change in the board controller
+ mBoardController->setActiveDocumentScene(proxy, 0, false);
+ }
+ }
+
+ mSelectionType = Document;
+ setDocument(proxy);
+}
+
+void UBDocumentController::createNewDocumentGroup()
+{
+ UBPersistenceManager *pManager = UBPersistenceManager::persistenceManager();
+ UBDocumentTreeModel *docModel = pManager->mDocumentTreeStructureModel;
+ QModelIndex selectedIndex = firstSelectedTreeIndex();
+ if (!selectedIndex.isValid()) {
+ return;
+ }
+ QModelIndex parentIndex = docModel->isCatalog(selectedIndex)
+ ? selectedIndex
+ : selectedIndex.parent();
+
+ QString newFolderName = docModel->adjustNameForParentIndex(tr("New Folder"), parentIndex);
+
+ docModel->addCatalog(newFolderName, parentIndex);
+}
+
+
+UBDocumentProxy* UBDocumentController::selectedDocumentProxy()
+{
+ return UBPersistenceManager::persistenceManager()->mDocumentTreeStructureModel->proxyForIndex(firstSelectedTreeIndex());
+}
+
+QList UBDocumentController::selectedProxies()
+{
+ QList result;
+
+ foreach (QModelIndex curIndex, mapIndexesToSource(mDocumentUI->documentTreeView->selectionModel()->selectedIndexes())) {
+ result << UBPersistenceManager::persistenceManager()->mDocumentTreeStructureModel->proxyForIndex(curIndex);
+ }
+
+ return result;
+}
+
+QModelIndexList UBDocumentController::selectedTreeIndexes()
+{
+ return mapIndexesToSource(mDocumentUI->documentTreeView->selectionModel()->selectedRows(0));
+}
+
+UBDocumentProxy* UBDocumentController::firstSelectedTreeProxy()
+{
+ return selectedProxies().count() ? selectedProxies().first() : 0;
+}
+
+void UBDocumentController::TreeViewSelectionChanged(const QModelIndex ¤t, const QModelIndex &previous)
+{
+ Q_UNUSED(previous)
+
+ UBDocumentTreeModel *docModel = UBPersistenceManager::persistenceManager()->mDocumentTreeStructureModel;
+
+ QModelIndex current_index = mapIndexToSource(current);
+
+ //N/C - NNE - 20140414
+ //if the selection contains more than one object, don't show the thumbnail.
+ //We have just to pass a null proxy to disable the display of thumbnail
+ UBDocumentProxy *currentDocumentProxy = 0;
+
+ if(current_index.isValid() && mDocumentUI->documentTreeView->selectionModel()->selectedRows(0).size() == 1){
+ currentDocumentProxy = docModel->proxyData(current_index);
+ setDocument(currentDocumentProxy, false);
+ }
+ //N/C - NNE - 20140414 : END
+
+
+ if (mCurrentIndexMoved) {
+ if (docModel->isDocument(current_index)) {
+ docModel->setCurrentDocument(currentDocumentProxy);
+ } else if (docModel->isCatalog(current_index)) {
+ docModel->setCurrentDocument(0);
+ }
+ mCurrentIndexMoved = false;
+ }
+
+ itemSelectionChanged(docModel->isCatalog(current_index) ? Folder : Document);
+}
+
+//N/C - NNE - 20140402 : workaround for using a proxy model
+QModelIndex UBDocumentController::mapIndexToSource(const QModelIndex &index)
+{
+ UBSortFilterProxyModel *proxy = dynamic_cast(mDocumentUI->documentTreeView->model());
+
+ if(proxy){
+ return proxy->mapToSource(index);
+ }
+
+ return index;
+}
+
+QModelIndexList UBDocumentController::mapIndexesToSource(const QModelIndexList &indexes)
+{
+ UBSortFilterProxyModel *proxy = dynamic_cast(mDocumentUI->documentTreeView->model());
+
+ if(proxy){
+ QModelIndexList list;
+
+ for(int i = 0; i < indexes.size(); i++){
+ list.push_back(proxy->mapToSource(indexes.at(i)));
+ }
+
+ return list;
+ }
+
+ return indexes;
+}
+
+//N/C - NNE - 20140402 : END
+
+void UBDocumentController::TreeViewSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
+{
+ Q_UNUSED(deselected)
+
+ int nbIndexes = selected.indexes().count();
+
+ if (nbIndexes) {
+ //N/C - NNE - 20140408
+
+ QModelIndexList list = mDocumentUI->documentTreeView->selectionModel()->selectedRows();
+
+ //if multi-selection
+ if(list.count() > 1){
+ //check if the selection is in the same top-level folder
+ QModelIndex sourceIndex1 = mapIndexToSource(list.at(list.count()-1));
+ QModelIndex sourceIndex2 = mapIndexToSource(list.at(list.count()-2));
+
+ UBDocumentTreeModel *model = UBPersistenceManager::persistenceManager()->mDocumentTreeStructureModel;
+
+ bool sameFolder = (model->inModel(sourceIndex1) && model->inModel(sourceIndex2));
+
+ sameFolder |= (model->inTrash(sourceIndex1) && model->inTrash(sourceIndex2));
+
+ sameFolder |= (model->inMyDocuments(sourceIndex1) && model->inMyDocuments(sourceIndex2));
+
+ if(!sameFolder){
+ mDocumentUI->documentTreeView->clearSelection();
+ mDocumentUI->documentTreeView->selectionModel()->select(list.at(list.count()-1), QItemSelectionModel::Select | QItemSelectionModel::Rows);
+ }
+ }
+ //N/C - NNE - 20140408 : END
+
+ //if the parent has been already select, don't select its children
+ QModelIndex newSelectedRow = selected.indexes().first();
+ QModelIndex parent = newSelectedRow.parent();
+ bool isParentIsSelected = false;
+ while(parent.isValid()){
+ isParentIsSelected |= (list.indexOf(parent) != -1);
+
+ if(isParentIsSelected)
+ break;
+
+ parent = parent.parent();
+ }
+
+ if(!isParentIsSelected)
+ TreeViewSelectionChanged(newSelectedRow, QModelIndex());
+ else
+ mDocumentUI->documentTreeView->selectionModel()->select(newSelectedRow, QItemSelectionModel::Deselect | QItemSelectionModel::Rows);
+
+ //if he newSelectedRow have children deselect them
+ /*
+ UBDocumentTreeModel *model = UBPersistenceManager::persistenceManager()->mDocumentTreeStructureModel;
+
+ if(model->rowCount(newSelectedRow) > 0){
+ QModelIndexList children;
+ QModelIndex parent = newSelectedRow;
+
+ //init children list
+ for(int i = 0; i < model->rowCount(parent); i++){
+ children.push_back(parent.child(i, 0));
+ }
+
+ for(int i = 0; i < children.size(); i++){
+ //deselect the element
+ mDocumentUI->documentTreeView->selectionModel()->select(children.at(0), QItemSelectionModel::Deselect);
+
+ //add its children if any
+ for(int k = 0; k < model->rowCount(children.at(i)); k++){
+ children.push_back(children.at(i).child(k, 0));
+ }
+ }
+ }
+ */
+ }
+
+}
+
+void UBDocumentController::itemSelectionChanged(LastSelectedElementType newSelection)
+{
+ mSelectionType = newSelection;
+ updateActions();
+}
+
+
+void UBDocumentController::setupViews()
+{
+
+ if (!mDocumentWidget)
+ {
+ mDocumentWidget = new QWidget(mMainWindow->centralWidget());
+ mMainWindow->addDocumentsWidget(mDocumentWidget);
+
+ mDocumentUI = new Ui::documents();
+
+ mDocumentUI->setupUi(mDocumentWidget);
+
+ int thumbWidth = UBSettings::settings()->documentThumbnailWidth->get().toInt();
+
+ mDocumentUI->documentZoomSlider->setValue(thumbWidth);
+ mDocumentUI->thumbnailWidget->setThumbnailWidth(thumbWidth);
+
+ connect(mDocumentUI->documentZoomSlider, SIGNAL(valueChanged(int)), this,
+ SLOT(documentZoomSliderValueChanged(int)));
+
+ connect(mMainWindow->actionOpen, SIGNAL(triggered()), this, SLOT(openSelectedItem()));
+ connect(mMainWindow->actionNewFolder, SIGNAL(triggered()), this, SLOT(createNewDocumentGroup()));
+ connect(mMainWindow->actionNewDocument, SIGNAL(triggered()), this, SLOT(createNewDocument()));
+
+ connect(mMainWindow->actionImport, SIGNAL(triggered(bool)), this, SLOT(importFile()));
+
+ QMenu* addMenu = new QMenu(mDocumentWidget);
+ mAddFolderOfImagesAction = addMenu->addAction(tr("Add Folder of Images"));
+ mAddImagesAction = addMenu->addAction(tr("Add Images"));
+ mAddFileToDocumentAction = addMenu->addAction(tr("Add Pages from File"));
+
+ connect(mAddFolderOfImagesAction, SIGNAL(triggered(bool)), this, SLOT(addFolderOfImages()));
+ connect(mAddFileToDocumentAction, SIGNAL(triggered(bool)), this, SLOT(addFileToDocument()));
+ connect(mAddImagesAction, SIGNAL(triggered(bool)), this, SLOT(addImages()));
+
+ foreach (QWidget* menuWidget, mMainWindow->actionDocumentAdd->associatedWidgets())
+ {
+ QToolButton *tb = qobject_cast(menuWidget);
+
+ if (tb && !tb->menu())
+ {
+ tb->setObjectName("ubButtonMenu");
+ tb->setPopupMode(QToolButton::InstantPopup);
+
+ QMenu* menu = new QMenu(mDocumentWidget);
+
+ menu->addAction(mAddFolderOfImagesAction);
+ menu->addAction(mAddImagesAction);
+ menu->addAction(mAddFileToDocumentAction);
+
+ tb->setMenu(menu);
+ }
+ }
+
+ QMenu* exportMenu = new QMenu(mDocumentWidget);
+
+ UBDocumentManager *documentManager = UBDocumentManager::documentManager();
+ for (int i = 0; i < documentManager->supportedExportAdaptors().length(); i++)
+ {
+ UBExportAdaptor* adaptor = documentManager->supportedExportAdaptors()[i];
+ QAction *currentExportAction = exportMenu->addAction(adaptor->exportName());
+ currentExportAction->setData(i);
+ connect(currentExportAction, SIGNAL(triggered (bool)), this, SLOT(exportDocument()));
+ exportMenu->addAction(currentExportAction);
+ adaptor->setAssociatedAction(currentExportAction);
+ }
+
+ foreach (QWidget* menuWidget, mMainWindow->actionExport->associatedWidgets())
+ {
+ QToolButton *tb = qobject_cast(menuWidget);
+
+ if (tb && !tb->menu())
+ {
+ tb->setObjectName("ubButtonMenu");
+ tb->setPopupMode(QToolButton::InstantPopup);
+
+ tb->setMenu(exportMenu);
+ }
+ }
+
+#ifdef Q_WS_MAC
+ mMainWindow->actionDelete->setShortcut(QKeySequence(Qt::Key_Backspace));
+#endif
+
+ connect(mMainWindow->actionDelete, SIGNAL(triggered()), this, SLOT(deleteSelectedItem()));
+ connect(mMainWindow->actionDuplicate, SIGNAL(triggered()), this, SLOT(duplicateSelectedItem()));
+ connect(mMainWindow->actionRename, SIGNAL(triggered()), this, SLOT(renameSelectedItem()));
+ connect(mMainWindow->actionAddToWorkingDocument, SIGNAL(triggered()), this, SLOT(addToDocument()));
+
+ UBDocumentTreeModel *model = UBPersistenceManager::persistenceManager()->mDocumentTreeStructureModel;
+
+ mSortFilterProxyModel = new UBSortFilterProxyModel();
+
+ mSortFilterProxyModel->setSourceModel(model);
+
+ sortDocuments(UBDocumentController::Alphabetical, UBDocumentController::ASC);
+
+ mDocumentUI->documentTreeView->setModel(mSortFilterProxyModel);
+
+ mDocumentUI->documentTreeView->setItemDelegate(new UBDocumentTreeItemDelegate(this));
+ mDocumentUI->documentTreeView->setDragEnabled(true);
+ mDocumentUI->documentTreeView->setAcceptDrops(true);
+ mDocumentUI->documentTreeView->viewport()->setAcceptDrops(true);
+ mDocumentUI->documentTreeView->setDropIndicatorShown(true);
+ mDocumentUI->documentTreeView->header()->setStretchLastSection(false);
+ mDocumentUI->documentTreeView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
+ mDocumentUI->documentTreeView->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
+ mDocumentUI->documentTreeView->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
+
+ mDocumentUI->documentTreeView->hideColumn(1);
+ mDocumentUI->documentTreeView->hideColumn(2);
+
+ mDocumentUI->sortOrder->hide();
+
+ connect(mDocumentUI->sortKind, SIGNAL(activated(int)), this, SLOT(onSortKindChanged(int)));
+ connect(mDocumentUI->sortOrder, SIGNAL(activated(int)), this, SLOT(onSortOrderChanged(int)));
+
+ connect(mDocumentUI->collapseAll, SIGNAL(clicked()), this, SLOT(collapseAll()));
+
+ connect(mDocumentUI->expandAll, SIGNAL(clicked()), this, SLOT(expandAll()));
+
+ connect(mDocumentUI->documentTreeView->itemDelegate(), SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint) ), mDocumentUI->documentTreeView, SLOT(adjustSize()));
+ connect(mDocumentUI->documentTreeView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(TreeViewSelectionChanged(QItemSelection,QItemSelection)));
+ connect(UBPersistenceManager::persistenceManager()->mDocumentTreeStructureModel, SIGNAL(indexChanged(QModelIndex,QModelIndex))
+ ,mDocumentUI->documentTreeView, SLOT(onModelIndexChanged(QModelIndex,QModelIndex)));
+ connect(UBPersistenceManager::persistenceManager()->mDocumentTreeStructureModel, SIGNAL(currentIndexMoved(QModelIndex,QModelIndex))
+ ,this, SLOT(currentIndexMoved(QModelIndex,QModelIndex)));
+
+ connect(mDocumentUI->thumbnailWidget, SIGNAL(sceneDropped(UBDocumentProxy*, int, int)), this, SLOT(moveSceneToIndex ( UBDocumentProxy*, int, int)));
+ connect(mDocumentUI->thumbnailWidget, SIGNAL(resized()), this, SLOT(thumbnailViewResized()));
+ connect(mDocumentUI->thumbnailWidget, SIGNAL(mouseDoubleClick(QGraphicsItem*,int)), this, SLOT(thumbnailPageDoubleClicked(QGraphicsItem*,int)));
+ connect(mDocumentUI->thumbnailWidget, SIGNAL(mouseClick(QGraphicsItem*, int)), this, SLOT(pageClicked(QGraphicsItem*, int)));
+
+ connect(mDocumentUI->thumbnailWidget->scene(), SIGNAL(selectionChanged()), this, SLOT(pageSelectionChanged()));
+
+ connect(UBPersistenceManager::persistenceManager(), SIGNAL(documentSceneCreated(UBDocumentProxy*, int)), this, SLOT(documentSceneChanged(UBDocumentProxy*, int)));
+ connect(UBPersistenceManager::persistenceManager(), SIGNAL(documentSceneWillBeDeleted(UBDocumentProxy*, int)), this, SLOT(documentSceneChanged(UBDocumentProxy*, int)));
+
+ mDocumentUI->thumbnailWidget->setBackgroundBrush(UBSettings::documentViewLightColor);
+
+ #ifdef Q_WS_MACX
+ mMessageWindow = new UBMessageWindow(NULL);
+ #else
+ mMessageWindow = new UBMessageWindow(mDocumentUI->thumbnailWidget);
+ #endif
+
+ mMessageWindow->setCustomPosition(true);
+ mMessageWindow->hide();
+ }
+}
+
+//N/C - NNE - 20140403
+void UBDocumentController::sortDocuments(int kind, int order)
+{
+ Qt::SortOrder sortOrder = Qt::AscendingOrder;
+
+ //if the user hasn't change the sort
+ //set order to its default value according to
+ //the kind of sort
+ if(!mUserHasChangedSortOrder){
+ if(kind == UBDocumentController::CreationDate || kind == UBDocumentController::UpdateDate){
+ sortOrder = Qt::DescendingOrder;
+ mDocumentUI->sortOrder->setCurrentIndex(1);
+ }else{
+ mDocumentUI->sortOrder->setCurrentIndex(0);
+ }
+ }else if(order == UBDocumentController::DESC){
+ sortOrder = Qt::DescendingOrder;
+ }
+
+ if(kind == UBDocumentController::CreationDate){
+ mSortFilterProxyModel->setSortRole(UBDocumentTreeModel::CreationDate);
+ mSortFilterProxyModel->sort(1, sortOrder);
+
+ mDocumentUI->documentTreeView->showColumn(1);
+ mDocumentUI->documentTreeView->hideColumn(2);
+ }else if(kind == UBDocumentController::UpdateDate){
+ mSortFilterProxyModel->setSortRole(UBDocumentTreeModel::UpdateDate);
+ mSortFilterProxyModel->sort(2, sortOrder);
+
+ mDocumentUI->documentTreeView->hideColumn(1);
+ mDocumentUI->documentTreeView->showColumn(2);
+ }else{
+ mSortFilterProxyModel->setSortRole(Qt::DisplayRole);
+ mSortFilterProxyModel->sort(0, sortOrder);
+
+ //alphabetical order or nothing
+ mDocumentUI->documentTreeView->hideColumn(1);
+ mDocumentUI->documentTreeView->hideColumn(2);
+ }
+}
+
+void UBDocumentController::onSortOrderChanged(int index)
+{
+ int kindIndex = mDocumentUI->sortKind->currentIndex();
+
+ mUserHasChangedSortOrder = true;
+
+ sortDocuments(kindIndex, index);
+}
+
+void UBDocumentController::onSortKindChanged(int index)
+{
+ int orderIndex = mDocumentUI->sortOrder->currentIndex();
+
+ if(index == -1 || index == 0)
+ mDocumentUI->sortOrder->hide();
+ else
+ mDocumentUI->sortOrder->show();
+
+ sortDocuments(index, orderIndex);
+}
+//N/C - NNE - 20140403 : END
+
+QWidget* UBDocumentController::controlView()
+{
+ return mDocumentWidget;
+}
+
+
+void UBDocumentController::setupToolbar()
+{
+ UBApplication::app()->insertSpaceToToolbarBeforeAction(mMainWindow->documentToolBar, mMainWindow->actionBoard);
+ connect(mMainWindow->actionDocumentTools, SIGNAL(triggered()), this, SLOT(toggleDocumentToolsPalette()));
+}
+
+void UBDocumentController::setupPalettes()
+{
+
+ mToolsPalette = new UBDocumentToolsPalette(controlView());
+
+ mToolsPalette->hide();
+
+ bool showToolsPalette = !mToolsPalette->isEmpty();
+ mMainWindow->actionDocumentTools->setVisible(showToolsPalette);
if (showToolsPalette)
{
@@ -442,12 +2152,11 @@ void UBDocumentController::setupPalettes()
}
}
-
void UBDocumentController::show()
{
selectDocument(mBoardController->selectedDocument());
- selectionChanged();
+ updateActions();
if(!mToolsPalette)
setupPalettes();
@@ -476,6 +2185,7 @@ void UBDocumentController::openSelectedItem()
if (proxy && isOKToOpenDocument(proxy))
{
+ mBoardController->setActiveDocumentScene(proxy, thumb->sceneIndex());
UBApplication::applicationController->showBoard();
}
}
@@ -522,568 +2232,353 @@ void UBDocumentController::duplicateSelectedItem()
duplicatePages(selectedSceneIndexes);
emit documentThumbnailsUpdated(this);
selectedDocument()->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime()));
- mDocumentUI->thumbnailWidget->selectItemAt(selectedSceneIndexes.last() + selectedSceneIndexes.size());
+ UBMetadataDcSubsetAdaptor::persist(selectedDocument());
+ int selectedThumbnail = selectedSceneIndexes.last() + selectedSceneIndexes.size();
+ mDocumentUI->thumbnailWidget->selectItemAt(selectedThumbnail);
+ int sceneCount = selectedSceneIndexes.count();
+ showMessage(tr("duplicated %1 page","duplicated %1 pages",sceneCount).arg(sceneCount), false);
+
+ mBoardController->setActiveDocumentScene(selectedThumbnail);
+ mBoardController->reloadThumbnails();
}
}
else
{
- UBDocumentProxy* source = selectedDocumentProxy();
- UBDocumentGroupTreeItem* group = selectedDocumentGroupTreeItem();
-
- if (source && group)
- {
- QString docName = source->metaData(UBSettings::documentName).toString();
-
- showMessage(tr("Duplicating Document %1").arg(docName), true);
+ UBDocumentTreeModel *docModel = UBPersistenceManager::persistenceManager()->mDocumentTreeStructureModel;
+ QModelIndex selectedIndex = firstSelectedTreeIndex();
- UBDocumentProxy* duplicatedDoc = UBPersistenceManager::persistenceManager()->duplicateDocument(source);
- duplicatedDoc->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime()));
-
- selectDocument(duplicatedDoc, false);
-
- showMessage(tr("Document %1 copied").arg(docName), false);
- }
- }
-}
+ Q_ASSERT(!docModel->isConstant(selectedIndex) && !docModel->inTrash(selectedIndex));
-/**
- * @brief Set the first document in the list as current document
- *
- * If there are no documents, a new one is created.
- */
-void UBDocumentController::selectFirstDocumentInList()
-{
- // Loop through all folders until we find one that is not the trash and not empty,
- // and select the first document in that folder
+ showMessage(tr("Duplicating Document %1").arg(""), true);
- for (int i(0); i < mDocumentUI->documentTreeWidget->topLevelItemCount(); ++i) {
- QTreeWidgetItem* item = mDocumentUI->documentTreeWidget->topLevelItem(i);
- UBDocumentGroupTreeItem* groupItem = dynamic_cast(item);
+ docModel->copyIndexToNewParent(selectedIndex, selectedIndex.parent(), UBDocumentTreeModel::aContentCopy);
- if (!groupItem->isTrashFolder() && groupItem->childCount() > 0) {
- selectDocument(((UBDocumentProxyTreeItem*)groupItem->child(0))->proxy(), true);
- groupItem->child(0)->setSelected(true);
- return;
- }
+ showMessage(tr("Document %1 copied").arg(""), false);
}
-
- // No document found => create a new one
- UBDocumentGroupTreeItem* topFolder = dynamic_cast(mDocumentUI->documentTreeWidget->topLevelItem(0));
-
- UBDocumentProxy* document = UBPersistenceManager::persistenceManager()->createDocument(topFolder->groupName());
- selectDocument(document, true);
}
-/**
- * @brief Find the current document, and select it in the list
- *
- * If selectNewCurrentDocument is true, the first document in the list is selected and set as
- * current document.
- */
-void UBDocumentController::selectATreeItemOnMultipleTrashing(bool selectNewCurrentDocument)
+void UBDocumentController::deleteSelectedItem()
{
- mCurrentSelection.clear();
-
- if (selectNewCurrentDocument) {
- selectFirstDocumentInList();
- return;
- }
+ UBDocumentTreeModel *docModel = UBPersistenceManager::persistenceManager()->mDocumentTreeStructureModel;
- // Find the currently selected document, and select its corresponding tree item
- // If it isn't found, then the first document in the list is selected and set as current document
+ QModelIndexList indexes = selectedTreeIndexes();
- for (int i(0); i < mDocumentUI->documentTreeWidget->topLevelItemCount(); i++) {
- QTreeWidgetItem* item = mDocumentUI->documentTreeWidget->topLevelItem(i);
- UBDocumentGroupTreeItem* groupItem = dynamic_cast(item);
+ //we iterate in backward because if we iterate in normal order,
+ //indexes are invalid after the first deletion
+ for(int i = indexes.size()-1; i >= 0; i--){
+ QModelIndex currentIndex = indexes.at(i);
+ DeletionType deletionForSelection = deletionTypeForSelection(mSelectionType, currentIndex, docModel);
- if (!groupItem->isTrashFolder()) {
- for (int j(0); j < groupItem->childCount(); j++) {
- if (((UBDocumentProxyTreeItem*)groupItem->child(j))->proxy() == mBoardController->selectedDocument()) {
- ((UBDocumentProxyTreeItem*)groupItem->child(j))->setSelected(true);
- return;
- }
- }
+ //N/C - NNE - 20140408 : if parent is selected, continue, because it will be deleted when the parent will be deleted
+ if(mDocumentUI->documentTreeView->selectionModel()->isSelected(currentIndex.parent())){
+ continue;
}
- }
-
- selectFirstDocumentInList();
-}
-
-void UBDocumentController::selectADocumentOnTrashingSelectedOne(UBDocumentGroupTreeItem* groupTi,UBDocumentProxyTreeItem *proxyTi)
-{
- int index = proxyTi->parent()->indexOfChild(proxyTi);
- index --;
+ //N/C - NNE - 20140408 : END
- // Select the previous document in the current folder, if there is one
- if (index >= 0)
- {
- if (proxyTi->proxy() == mBoardController->selectedDocument())
- {
- selectDocument(((UBDocumentProxyTreeItem*)proxyTi->parent()->child(index))->proxy(), true);
- }
- else
- proxyTi->parent()->child(index)->setSelected(true);
- }
- // If the deleted document is at the top of its folder, try to select the second top-most one
- else if (proxyTi->parent()->childCount() > 1)
- {
- if (proxyTi->proxy() == mBoardController->selectedDocument())
+ switch (deletionForSelection) {
+ case DeletePage:
{
- selectDocument(((UBDocumentProxyTreeItem*)proxyTi->parent()->child(1))->proxy(), true);
+ deletePages(mDocumentUI->thumbnailWidget->selectedItems());
+ break;
}
- else
- proxyTi->parent()->child(1)->setSelected(true);
- }
- // Otherwise, go through the other folders
- else
- {
- if (proxyTi->proxy() == mBoardController->selectedDocument())
+ case MoveToTrash:
{
- bool documentFound = false;
- for (int i = 0; i < mDocumentUI->documentTreeWidget->topLevelItemCount(); i++)
- {
- QTreeWidgetItem* item = mDocumentUI->documentTreeWidget->topLevelItem(i);
- UBDocumentGroupTreeItem* groupItem = dynamic_cast(item);
- if (!groupItem->isTrashFolder())
- {
- for(int j=0; jchildCount(); j++)
- {
- if (((UBDocumentProxyTreeItem*)groupItem->child(j))->proxy() != mBoardController->selectedDocument())
- {
- selectDocument(((UBDocumentProxyTreeItem*)groupItem->child(0))->proxy(), true);
- documentFound = true;
- break;
- }
- }
- }
- if (documentFound)
- break;
- }
- if (!documentFound)
- {
- UBDocumentProxy *document = UBPersistenceManager::persistenceManager()->createDocument(groupTi->groupName());
- selectDocument(document, true);
- }
- }
- else
- proxyTi->parent()->setSelected(true);
- }
-}
-
-void UBDocumentController::moveDocumentToTrash(UBDocumentGroupTreeItem* groupTi, UBDocumentProxyTreeItem *proxyTi, bool selectNewDocument)
-{
- qDebug() << "moving doc to trash. selection type: " << mSelectionType;
-
- if (selectNewDocument)
- selectADocumentOnTrashingSelectedOne(groupTi,proxyTi);
-
- QString oldGroupName = proxyTi->proxy()->metaData(UBSettings::documentGroupName).toString();
- proxyTi->proxy()->setMetaData(UBSettings::documentGroupName, UBSettings::trashedDocumentGroupNamePrefix + oldGroupName);
- UBPersistenceManager::persistenceManager()->persistDocumentMetadata(proxyTi->proxy());
+ moveToTrash(currentIndex, docModel);
- proxyTi->parent()->removeChild(proxyTi);
- mTrashTi->addChild(proxyTi);
- proxyTi->setFlags(proxyTi->flags() ^ Qt::ItemIsEditable);
-}
-
-void UBDocumentController::moveFolderToTrash(UBDocumentGroupTreeItem* groupTi)
-{
- bool changeCurrentDocument = false;
- for (int i = 0; i < groupTi->childCount(); i++)
- {
- UBDocumentProxyTreeItem* proxyTi = dynamic_cast(groupTi->child(i));
- if (proxyTi && proxyTi->proxy() && proxyTi->proxy() == mBoardController->selectedDocument())
- {
- changeCurrentDocument = true;
break;
}
- }
-
- QList toBeDeleted;
-
-
- for (int i = 0; i < groupTi->childCount(); i++)
- {
- UBDocumentProxyTreeItem* proxyTi = dynamic_cast(groupTi->child(i));
- if (proxyTi && proxyTi->proxy())
- toBeDeleted << proxyTi;
- }
-
- for (int i = 0; i < toBeDeleted.count(); i++)
- {
- UBDocumentProxyTreeItem* proxyTi = toBeDeleted.at(i);
-
- showMessage(QString("Deleting %1").arg(proxyTi->proxy()->metaData(UBSettings::documentName).toString()));
- // Move document to trash
- QString oldGroupName = proxyTi->proxy()->metaData(UBSettings::documentGroupName).toString();
- proxyTi->proxy()->setMetaData(UBSettings::documentGroupName, UBSettings::trashedDocumentGroupNamePrefix + oldGroupName);
- UBPersistenceManager::persistenceManager()->persistDocumentMetadata(proxyTi->proxy());
-
- groupTi->removeChild(proxyTi);
- mTrashTi->addChild(proxyTi);
- proxyTi->setFlags(proxyTi->flags() ^ Qt::ItemIsEditable);
-
- showMessage(QString("%1 deleted").arg(groupTi->groupName()));
- }
-
- // dont remove default group
- if (!groupTi->isDefaultFolder())
- {
- int index = mDocumentUI->documentTreeWidget->indexOfTopLevelItem(groupTi);
-
- if (index >= 0)
+ case CompleteDelete:
{
- mDocumentUI->documentTreeWidget->takeTopLevelItem(index);
+ deleteIndexAndAssociatedData(currentIndex);
+ break;
}
- }
-
- if (changeCurrentDocument)
- {
- bool documentFound = false;
- for (int i = 0; i < mDocumentUI->documentTreeWidget->topLevelItemCount(); i++)
+ case EmptyFolder:
{
- QTreeWidgetItem* item = mDocumentUI->documentTreeWidget->topLevelItem(i);
- UBDocumentGroupTreeItem* groupItem = dynamic_cast(item);
- if (!groupItem->isTrashFolder() && groupItem != groupTi)
- {
- for(int j=0; jchildCount(); j++)
- {
- if (((UBDocumentProxyTreeItem*)groupItem->child(j))->proxy() != mBoardController->selectedDocument())
- {
- selectDocument(((UBDocumentProxyTreeItem*)groupItem->child(0))->proxy(), true);
- documentFound = true;
+ if (currentIndex == docModel->myDocumentsIndex()) { //Emptying "My documents". Keeping Untitled Documents
+ int startInd = 0;
+ while (docModel->rowCount(currentIndex)) {
+ QModelIndex testSubINdecurrentIndex = docModel->index(startInd, 0, currentIndex);
+ if (testSubINdecurrentIndex == docModel->untitledDocumentsIndex()) {
+ emptyFolder(testSubINdecurrentIndex, MoveToTrash);
+ startInd++;
+ continue;
+ }
+ if (!testSubINdecurrentIndex.isValid()) {
break;
}
+ docModel->moveIndex(testSubINdecurrentIndex, docModel->trashIndex());
}
+ //issue 1629 - NNE - 20131105
+ //Here, we are sure that the current scene has been deleted
+ createNewDocumentInUntitledFolder();
+ } else {
+ //issue 1629 - NNE - 20131105
+ //Check if we will delete the current scene
+ UBDocumentTreeNode *currentNode = docModel->nodeFromIndex(currentIndex);
+ bool deleteCurrentScene = currentNode->findNode(docModel->nodeFromIndex(docModel->currentIndex()));
+
+ emptyFolder(currentIndex, MoveToTrash); //Empty constant folder
+
+ if(deleteCurrentScene) createNewDocumentInUntitledFolder();
}
- if (documentFound)
- break;
+
+ break;
}
- if (!documentFound)
+ case EmptyTrash:
{
- UBDocumentProxy *document = UBPersistenceManager::persistenceManager()->createDocument( mDefaultDocumentGroupName );
- selectDocument(document, true);
+ emptyFolder(currentIndex, CompleteDelete); // Empty trash folder
+ break;
+ }
}
}
- reloadThumbnails();
}
-/**
- * @brief Empty the trash folder, deleting all contents permanently.
- * @param showConfirmationDialog If set to true, prompts confirmation from the user
- */
-void UBDocumentController::emptyTrash(bool showConfirmationDialog)
+//N/C - NNE - 20140410
+void UBDocumentController::moveIndexesToTrash(const QModelIndexList &list, UBDocumentTreeModel *docModel)
{
- if (showConfirmationDialog &&
- !UBApplication::mainWindow->yesNoQuestion(tr("Empty Trash"), tr("Are you sure you want to empty trash?")))
- return;
+ QModelIndex currentScene = docModel->indexForNode(docModel->currentNode());
- QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
- QList toBeDeleted;
+ //check if the current scene is selected
+ QItemSelectionModel *selectionModel = mDocumentUI->documentTreeView->selectionModel();
+ bool deleteCurrentScene = selectionModel->isSelected(mSortFilterProxyModel->mapFromSource(currentScene));
+
+ //check if the current scene is in the hierarchy
+ if(!deleteCurrentScene){
+ for(int i = 0; i < list.size(); i++){
+ deleteCurrentScene = docModel->isDescendantOf(currentScene, list.at(i));
- for (int i(0); i < mTrashTi->childCount(); ++i) {
- UBDocumentProxyTreeItem* proxyTi = dynamic_cast(mTrashTi->child(i));
- if (proxyTi && proxyTi->proxy()){
- if(proxyTi->proxy() == mBoardController->selectedDocument()){
- selectADocumentOnTrashingSelectedOne(dynamic_cast(mDocumentUI->documentTreeWidget),proxyTi);
+ if(deleteCurrentScene){
+ break;
}
- toBeDeleted << proxyTi;
}
+
}
- showMessage(tr("Emptying trash"));
+ QModelIndex proxyMapCurentScene = mSortFilterProxyModel->mapFromSource(currentScene);
- for (int i(0); i < toBeDeleted.count(); ++i) {
- UBDocumentProxyTreeItem* proxyTi = toBeDeleted.at(i);
+ if(deleteCurrentScene){
+ QModelIndex sibling = findPreviousSiblingNotSelected(proxyMapCurentScene, selectionModel);
- proxyTi->parent()->removeChild(proxyTi);
- UBPersistenceManager::persistenceManager()->deleteDocument(proxyTi->proxy());
- }
+ if(sibling.isValid()){
+ QModelIndex sourceSibling = mSortFilterProxyModel->mapToSource(sibling);
- showMessage(tr("Emptied trash"));
+ UBDocumentProxy *proxy = docModel->proxyForIndex(sourceSibling);
- QApplication::restoreOverrideCursor();
- mMainWindow->actionDelete->setEnabled(false);
-}
+ docModel->setCurrentDocument(proxy);
-/**
- * @brief Delete an item (document or folder) from the document list
- * @param item The document or folder to delete
- * @param showConfirmationDialog If set to true, the user will be asked for confirmation
- * @param selectNewDocument If set to true, a new document will be selected immediately
- *
- * If the item passed as parameter is a document that is in the trash, then it is deleted
- * permanently. If the trash folder is passed, then all its contents are deleted.
- * Finally, if a folder is passed, all its contents are moved to trash.
- */
-void UBDocumentController::deleteTreeItem(QTreeWidgetItem * item, bool showConfirmationDialog, bool selectNewDocument)
-{
- UBDocumentProxyTreeItem * document = dynamic_cast(item);
- UBDocumentGroupTreeItem * folder = dynamic_cast(item);
+ selectionModel->select(sibling, QItemSelectionModel::ClearAndSelect);
- if (document) {
- if (showConfirmationDialog &&
- !UBApplication::mainWindow->yesNoQuestion(tr("Remove Document"),
- tr("Are you sure you want to remove the document '%1'?").arg(document->proxy()->metaData(UBSettings::documentName).toString())))
- return;
+ deleteCurrentScene = false;
+ }else{
+ sibling = findNextSiblingNotSelected(proxyMapCurentScene, selectionModel);
- if (!document->isInTrash())
- moveDocumentToTrash(dynamic_cast(document->parent()), document, selectNewDocument);
+ if(sibling.isValid()){
+ QModelIndex sourceSibling = mSortFilterProxyModel->mapToSource(sibling);
- else {
- document->parent()->removeChild(document);
- UBPersistenceManager::persistenceManager()->deleteDocument(document->proxy());
+ UBDocumentProxy *proxy = docModel->proxyForIndex(sourceSibling);
- if (selectNewDocument) {
- if (mTrashTi->childCount()==0)
- selectATreeItemOnMultipleTrashing(false);
- else
- selectDocument(((UBDocumentProxyTreeItem*)mTrashTi->child(0))->proxy(), false);
- }
+ docModel->setCurrentDocument(proxy);
- reloadThumbnails();
+ selectionModel->select(sibling, QItemSelectionModel::ClearAndSelect);
+
+ deleteCurrentScene = false;
+ }
}
- }
- else if (folder) {
- if (folder == mTrashTi)
- emptyTrash(showConfirmationDialog);
+ }
- else {
- if (showConfirmationDialog &&
- !UBApplication::mainWindow->yesNoQuestion(tr("Remove Folder"),
- tr("Are you sure you want to remove the folder '%1' and all its content?").arg(folder->groupName())))
- return;
+ docModel->moveIndexes(list, docModel->trashIndex());
- QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
- moveFolderToTrash(folder);
- QApplication::restoreOverrideCursor();
- }
+ if(deleteCurrentScene){
+ createNewDocumentInUntitledFolder();
}
-}
+ selectionModel->clearSelection();
+}
+//N/C - NNE - 20140410 : END
-void UBDocumentController::deleteSelectedItem()
+QModelIndex UBDocumentController::findPreviousSiblingNotSelected(const QModelIndex &index, QItemSelectionModel *selectionModel)
{
- if (mSelectionType == Page) {
- QList selectedItems = mDocumentUI->thumbnailWidget->selectedItems();
- deletePages(selectedItems);
- }
-
- else if (mSelectionType == Multiple) {
- if (!UBApplication::mainWindow->yesNoQuestion(tr("Remove multiple documents"),
- tr("Are you sure you want to remove all selected documents?")))
- return;
+ QModelIndex sibling = index.sibling(index.row() - 1, 0);
- QList foldersToDelete;
+ if(sibling.isValid()){
+ //if sibling is not selected and it is a document
+ //else keep searching
+ if(!parentIsSelected(sibling, selectionModel)
+ && !selectionModel->isSelected(sibling)
+ && !sibling.model()->hasChildren(sibling)){
+ return sibling;
+ }else{
+ return findPreviousSiblingNotSelected(sibling, selectionModel);
+ }
+ }else{
+ //if the parent exist keep searching, else stop the search
+ QModelIndex parent = index.model()->parent(index);
+
+ if(parent.isValid()){
+ return findPreviousSiblingNotSelected(parent, selectionModel);
+ }else{
+ return QModelIndex();
+ }
+ }
+}
- bool currentDocumentDeleted = false;
+QModelIndex UBDocumentController::findNextSiblingNotSelected(const QModelIndex &index, QItemSelectionModel *selectionModel)
+{
+ QModelIndex sibling = index.sibling(index.row() + 1, 0);
- foreach (QTreeWidgetItem * item, mCurrentSelection) {
- LastSelectedElementType type = itemType(item);
- if (type == Document) {
- deleteTreeItem(item, false, false);
+ if(sibling.isValid()){
+ //if sibling is not selected and it is a document and its parent are not selected
+ //else keep searching
+ if(!parentIsSelected(sibling, selectionModel)
+ && !selectionModel->isSelected(sibling)
+ && !sibling.model()->hasChildren(sibling)){
+ QModelIndex model = mSortFilterProxyModel->mapToSource(index);
- UBDocumentProxyTreeItem* proxyItem = dynamic_cast(item);
- if (proxyItem && proxyItem->proxy() && (proxyItem->proxy() == mBoardController->selectedDocument()))
- currentDocumentDeleted = true;
+ if(UBPersistenceManager::persistenceManager()->mDocumentTreeStructureModel->isCatalog(model)){
+ return QModelIndex();
+ }else{
+ return sibling;
}
-
- else if (type == Folder)
- // Delete folders later, to avoid deleting a document twice
- foldersToDelete << item;
+ }else{
+ return findNextSiblingNotSelected(sibling, selectionModel);
}
-
- foreach (QTreeWidgetItem * item, foldersToDelete) {
- deleteTreeItem(item, false, false);
+ }else{
+ //if the parent exist keep searching, else stop the search
+ QModelIndex parent = index.parent();
+
+ if(parent.isValid()){
+ return findNextSiblingNotSelected(parent, selectionModel);
+ }else{
+ return QModelIndex();
}
-
- selectATreeItemOnMultipleTrashing(currentDocumentDeleted);
- }
-
- else if (mSelectionType == Document || mSelectionType == Folder) {
- QTreeWidgetItem * item = mCurrentSelection.first();
- if (item)
- deleteTreeItem(item, true, true);
}
}
-
-void UBDocumentController::exportDocument()
+bool UBDocumentController::parentIsSelected(const QModelIndex& child, QItemSelectionModel *selectionModel)
{
- QAction *currentExportAction = qobject_cast(sender());
- QVariant actionData = currentExportAction->data();
- UBExportAdaptor* selectedExportAdaptor = UBDocumentManager::documentManager()->supportedExportAdaptors()[actionData.toInt()];
+ QModelIndex parent = child.parent();
- UBDocumentProxy* proxy = selectedDocumentProxy();
+ while(parent.isValid()){
+ if(selectionModel->isSelected(parent)){
+ return true;
+ }
- if (proxy)
- {
- selectedExportAdaptor->persist(proxy);
- emit exportDone();
- }
- else
- {
- showMessage(tr("No document selected!"));
+ parent = parent.parent();
}
-}
+ return false;
+}
-void UBDocumentController::documentZoomSliderValueChanged (int value)
+//issue 1629 - NNE - 20131212
+void UBDocumentController::moveToTrash(QModelIndex &index, UBDocumentTreeModel* docModel)
{
- mDocumentUI->thumbnailWidget->setThumbnailWidth(value);
-
- UBSettings::settings()->documentThumbnailWidth->set(value);
+ QModelIndexList list;
+ list.push_back(index);
+ moveIndexesToTrash(list, docModel);
}
+//issue 1629 - NNE - 20131212 : END
-
-void UBDocumentController::loadDocumentProxies()
+void UBDocumentController::emptyFolder(const QModelIndex &index, DeletionType pDeletionType)
{
- QList > proxies = UBPersistenceManager::persistenceManager()->documentProxies;
-
- QStringList emptyGroupNames = UBSettings::settings()->value("Document/EmptyGroupNames", QStringList()).toStringList();
- mDocumentUI->documentTreeWidget->clear();
-
- QMap groupNamesMap;
-
- UBDocumentGroupTreeItem* emptyGroupNameTi = 0;
-
- mTrashTi = new UBDocumentGroupTreeItem(0, false); // deleted by the tree widget
- mTrashTi->setGroupName(mDocumentTrashGroupName);
- mTrashTi->setIcon(0, QIcon(":/images/trash.png"));
-
- foreach (QPointer proxy, proxies)
- {
- if (proxy)
- {
- QString docGroup = proxy->metaData(UBSettings::documentGroupName).toString();
-
+ // Issue NC - CFA - 20131029 : ajout d'une popup de confirmation pour la suppression definitive
+ if(pDeletionType == CompleteDelete && !UBApplication::mainWindow->yesNoQuestion(tr("Empty the trash"),tr("You're about to empty the trash.") +"\n\n" + tr("Are you sure ?")))
+ return;
- bool isEmptyGroupName = false;
- bool isInTrash = false;
+ QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
- if (docGroup.isEmpty()) // #see https://trac.assembla.com/uniboard/ticket/426
- {
- docGroup = mDefaultDocumentGroupName;
- isEmptyGroupName = true;
- }
- else if (docGroup.startsWith(UBSettings::trashedDocumentGroupNamePrefix))
- {
- isInTrash = true;
+ UBDocumentTreeModel *docModel = UBPersistenceManager::persistenceManager()->mDocumentTreeStructureModel;
+ if (!docModel->isCatalog(index)) {
+ return;
}
- QString docName = proxy->metaData(UBSettings::documentName).toString();
+ while (docModel->rowCount(index)) {
+ QModelIndex subIndex = docModel->index(0, 0, index);
+ switch (pDeletionType) {
+ case MoveToTrash :
+ docModel->moveIndex(subIndex, docModel->trashIndex());
+ break;
- if (emptyGroupNames.contains(docGroup))
- emptyGroupNames.removeAll(docGroup);
+ case CompleteDelete :
+ deleteIndexAndAssociatedData(subIndex);
+ break;
+ default:
+ break;
+ }
- if (!groupNamesMap.contains(docGroup) && !isInTrash)
- {
- UBDocumentGroupTreeItem* docGroupItem = new UBDocumentGroupTreeItem(0, !isEmptyGroupName); // deleted by the tree widget
- groupNamesMap.insert(docGroup, docGroupItem);
- docGroupItem->setGroupName(docGroup);
+ }
- if (isEmptyGroupName)
- emptyGroupNameTi = docGroupItem;
+ QApplication::restoreOverrideCursor();
+ // Fin issue NC - CFA - 20131029
}
- UBDocumentGroupTreeItem* docGroupItem;
- if (isInTrash)
- docGroupItem = mTrashTi;
- else
- docGroupItem = groupNamesMap.value(docGroup);
+void UBDocumentController::deleteIndexAndAssociatedData(const QModelIndex &pIndex)
+{
+ UBDocumentTreeModel *docModel = UBPersistenceManager::persistenceManager()->mDocumentTreeStructureModel;
+ while (docModel->rowCount(pIndex)) {
+ QModelIndex subIndex = docModel->index(0, 0, pIndex);
+ deleteIndexAndAssociatedData(subIndex);
+ }
- QTreeWidgetItem* docItem = new UBDocumentProxyTreeItem(docGroupItem, proxy, !isInTrash);
- docItem->setText(0, docName);
+ //N/C - NNE - 20140408
+ if(pIndex.column() == 0){
+ if (docModel->isDocument(pIndex)) {
+ UBDocumentProxy *proxyData = docModel->proxyData(pIndex);
- if (mBoardController->selectedDocument() == proxy)
-{
- mDocumentUI->documentTreeWidget->expandItem(docGroupItem);
- mDocumentUI->documentTreeWidget->setCurrentItem(docGroupItem);
+ if (proxyData) {
+ UBPersistenceManager::persistenceManager()->deleteDocument(proxyData);
}
}
}
- foreach (const QString emptyGroupName, emptyGroupNames)
- {
- UBDocumentGroupTreeItem* docGroupItem = new UBDocumentGroupTreeItem(0); // deleted by the tree widget
- groupNamesMap.insert(emptyGroupName, docGroupItem);
- docGroupItem->setGroupName(emptyGroupName);
+ docModel->removeRow(pIndex.row(), pIndex.parent());
}
- QList groupNamesList = groupNamesMap.keys();
- qSort(groupNamesList);
- foreach (const QString groupName, groupNamesList)
+void UBDocumentController::exportDocument()
{
- UBDocumentGroupTreeItem* ti = groupNamesMap.value(groupName);
+ QAction *currentExportAction = qobject_cast(sender());
+ QVariant actionData = currentExportAction->data();
+ UBExportAdaptor* selectedExportAdaptor = UBDocumentManager::documentManager()->supportedExportAdaptors()[actionData.toInt()];
- if (ti != emptyGroupNameTi)
- mDocumentUI->documentTreeWidget->addTopLevelItem(ti);
- }
- if (emptyGroupNameTi)
- mDocumentUI->documentTreeWidget->addTopLevelItem(emptyGroupNameTi);
+ UBDocumentProxy* proxy = firstSelectedTreeProxy();
+
+ selectedExportAdaptor->persist(proxy);
+ emit exportDone();
- mDocumentUI->documentTreeWidget->addTopLevelItem(mTrashTi);
}
-void UBDocumentController::itemChanged(QTreeWidgetItem * item, int column)
+void UBDocumentController::exportDocumentSet()
{
- UBDocumentProxyTreeItem* proxyItem = dynamic_cast(item);
-
- disconnect(UBPersistenceManager::persistenceManager(), SIGNAL(documentMetadataChanged(UBDocumentProxy*))
- , this, SLOT(updateDocumentInTree(UBDocumentProxy*)));
- if (proxyItem) {
- if (proxyItem->proxy()->metaData(UBSettings::documentName).toString() != item->text(column)) {
- // The item was renamed, we should persist it immediately
- proxyItem->proxy()->setMetaData(UBSettings::documentName, item->text(column));
- UBPersistenceManager::persistenceManager()->persistDocumentMetadata(proxyItem->proxy());
- }
- }
- else
- {
- // it is a group
- UBDocumentGroupTreeItem* editedGroup = dynamic_cast(item);
- if (editedGroup)
- {
- for (int i = 0; i < item->childCount(); i++)
- {
- UBDocumentProxyTreeItem* childItem = dynamic_cast(item->child(i));
+}
- if (childItem)
- {
- if (0 != (item->flags() & Qt::ItemIsEditable))
- {
- childItem->proxy()->setMetaData(UBSettings::documentGroupName, item->text(column));
- UBPersistenceManager::persistenceManager()->persistDocumentMetadata(childItem->proxy());
- }
- }
- }
- }
- }
+void UBDocumentController::documentZoomSliderValueChanged (int value)
+{
+ mDocumentUI->thumbnailWidget->setThumbnailWidth(value);
- connect(UBPersistenceManager::persistenceManager(), SIGNAL(documentMetadataChanged(UBDocumentProxy*)),
- this, SLOT(updateDocumentInTree(UBDocumentProxy*)));
+ UBSettings::settings()->documentThumbnailWidth->set(value);
}
-
void UBDocumentController::importFile()
{
- UBDocumentGroupTreeItem* group = selectedDocumentGroupTreeItem();
UBDocumentManager *docManager = UBDocumentManager::documentManager();
- if (group)
- {
- QString defaultPath = UBSettings::settings()->lastImportFilePath->get().toString();
- if(defaultPath.isDetached())
- defaultPath = UBSettings::settings()->userDocumentDirectory();
- QString filePath = QFileDialog::getOpenFileName(mParentWidget, tr("Open Supported File"), defaultPath, docManager->importFileFilter());
+ QString defaultPath = UBSettings::settings()->lastImportFilePath->get().toString();
+ if(defaultPath.isDetached())
+ defaultPath = UBSettings::settings()->userDocumentDirectory();
+ QString filePath = QFileDialog::getOpenFileName(mParentWidget, tr("Open Supported File"),
+ defaultPath, docManager->importFileFilter());
- QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
- QApplication::processEvents();
- QFileInfo fileInfo(filePath);
+ QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+ QApplication::processEvents();
+ QFileInfo fileInfo(filePath);
+
+ if (fileInfo.suffix().toLower() == "ubx") {
+ UBPersistenceManager::persistenceManager()->createDocumentProxiesStructure(docManager->importUbx(filePath, UBSettings::userDocumentDirectory()), true);
+
+ } else {
UBSettings::settings()->lastImportFilePath->set(QVariant(fileInfo.absolutePath()));
if (filePath.length() > 0)
@@ -1092,27 +2587,26 @@ void UBDocumentController::importFile()
QApplication::processEvents();
QFile selectedFile(filePath);
- QString groupName = group->groupName();
+ QString groupName = UBPersistenceManager::myDocumentsName;
- if (groupName == mDefaultDocumentGroupName || fileInfo.suffix() == "ubz")
- groupName = "";
+ groupName = "";
showMessage(tr("Importing file %1...").arg(fileInfo.baseName()), true);
createdDocument = docManager->importFile(selectedFile, groupName);
- if (createdDocument)
- {
- selectDocument(createdDocument, false);
- }
- else
- {
+
+ if (createdDocument) {
+ selectDocument(createdDocument, true, true);
+
+ } else {
showMessage(tr("Failed to import file ... "));
}
}
-
- QApplication::restoreOverrideCursor();
}
+
+ QApplication::restoreOverrideCursor();
+
}
void UBDocumentController::addFolderOfImages()
@@ -1144,6 +2638,7 @@ void UBDocumentController::addFolderOfImages()
else
{
document->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime()));
+ UBMetadataDcSubsetAdaptor::persist(document);
reloadThumbnails();
}
}
@@ -1166,304 +2661,127 @@ void UBDocumentController::addFileToDocument()
bool UBDocumentController::addFileToDocument(UBDocumentProxy* document)
{
QString defaultPath = UBSettings::settings()->lastImportFilePath->get().toString();
- QString filePath = QFileDialog::getOpenFileName(mParentWidget, tr("Open Supported File"), defaultPath, UBDocumentManager::documentManager()->importFileFilter());
+ QString filePath = QFileDialog::getOpenFileName(mParentWidget, tr("Open Supported File"), defaultPath, UBDocumentManager::documentManager()->importFileFilter(true));
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
QApplication::processEvents();
- QFileInfo fileInfo(filePath);
- UBSettings::settings()->lastImportFilePath->set(QVariant(fileInfo.absolutePath()));
-
- bool success = false;
-
- if (filePath.length() > 0)
- {
- QApplication::processEvents(); // NOTE: We performed this just a few lines before. Is it really necessary to do it again here??
-
- showMessage(tr("Importing file %1...").arg(fileInfo.baseName()), true);
-
- QStringList fileNames;
- fileNames << filePath;
- success = UBDocumentManager::documentManager()->addFilesToDocument(document, fileNames);
-
- if (success)
- {
- document->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime()));
- }
- else
- {
- showMessage(tr("Failed to import file ... "));
- }
- }
-
- QApplication::restoreOverrideCursor();
-
- return success;
-}
-
-
-void UBDocumentController::moveSceneToIndex(UBDocumentProxy* proxy, int source, int target)
-{
- if (UBDocumentContainer::movePageToIndex(source, target))
- {
- proxy->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime()));
-
- mDocumentUI->thumbnailWidget->hightlightItem(target);
- }
-}
-
-
-void UBDocumentController::thumbnailViewResized()
-{
- int maxWidth = qMin(UBSettings::maxThumbnailWidth, mDocumentUI->thumbnailWidget->width());
-
- mDocumentUI->documentZoomSlider->setMaximum(maxWidth);
-}
-
-
-void UBDocumentController::pageSelectionChanged()
-{
- if (mIsClosing)
- return;
-
- bool pageSelected = mDocumentUI->thumbnailWidget->selectedItems().count() > 0;
-
- if (pageSelected)
- mSelectionType = Page;
- else
- mSelectionType = None;
-
- selectionChanged();
-}
-
-bool UBDocumentController::isCurrentSelectionInTrash()
-{
- bool selectionIsInTrash = false;
- foreach (QTreeWidgetItem* item, mCurrentSelection) {
- // Find the first valid element; no need to check all of them
- UBDocumentProxyTreeItem * document = dynamic_cast(item);
- if (document) {
- selectionIsInTrash = document->isInTrash();
- break;
- }
- }
-
- return selectionIsInTrash;
-}
-
-/**
- * @brief Set the currently selected items, after checking the selection is valid
- *
- * This method compares the current selection with the previous one, and deselects
- * the "incorrectly" selected items if necessary. For example, it shouldn't be possible
- * to select items both in the trash and out; and the Trash folder shouldn't be
- * included in multiple selections.
- */
-void UBDocumentController::updateCurrentSelection()
-{
- QList newSelection = mDocumentUI->documentTreeWidget->selectedItems();
-
- // If the selection is of size 1 or 0, we don't need to do any checking, we just accept it.
- if (newSelection.size() <= 1) {
- mCurrentSelection = newSelection;
- return;
- }
-
- // We don't allow the Trash folder in multiple selections
- // If it is currently selected, we deselect all the newly selected items
- if (mCurrentSelection.size() == 1) {
- UBDocumentGroupTreeItem* folder = dynamic_cast(mCurrentSelection.first());
-
- if (folder && folder->isTrashFolder()) {
- foreach (QTreeWidgetItem* item, newSelection) {
- if (item != folder)
- item->setSelected(false);
- }
-
- return;
- }
- }
-
- // Find the elements of the new selection that aren't in the old one
- QSet newItems = newSelection.toSet().subtract(mCurrentSelection.toSet());
-
- bool selectionIsInTrash = isCurrentSelectionInTrash();
-
- foreach (QTreeWidgetItem* item, newItems) {
- bool addToSelection = true;
- UBDocumentProxyTreeItem * document = dynamic_cast(item);
- if (document) {
- // No mix between trashed and non-trashed items
- if (document->isInTrash() != selectionIsInTrash)
- addToSelection = false;
- }
-
- UBDocumentGroupTreeItem * folder = dynamic_cast(item);
- if (folder) {
- // Trash folder is not allowed in multiple selections
- if (folder->isTrashFolder())
- addToSelection = false;
-
- // Don't add a folder when trash items are selected
- if (selectionIsInTrash)
- addToSelection = false;
- }
- if (!folder && !document)
- addToSelection = false;
-
- if (addToSelection) {
- if (!mCurrentSelection.contains(item)) {
- // the .subtract() above doesn't seem to work all the time...
- mCurrentSelection.append(item);
- }
- }
- else
- item->setSelected(false);
- }
-}
-
-void UBDocumentController::selectionChanged()
-{
- if (mIsClosing)
- return;
-
- int pageCount = -1;
-
- UBDocumentProxyTreeItem* proxyTi = selectedDocumentProxyTreeItem();
-
- if (proxyTi && proxyTi->proxy())
- pageCount = proxyTi->proxy()->pageCount();
-
- bool pageSelected = (mSelectionType == Page);
- bool groupSelected = (mSelectionType == Folder);
- bool docSelected = (mSelectionType == Document);
- bool multipleSelected = (mSelectionType == Multiple);
- bool selectedItemsAreInTrash = isCurrentSelectionInTrash();
-
-
- bool trashSelected = false; // set to true if selected items are in trash or if trash folder is selected
- if (groupSelected && selectedDocumentGroupTreeItem())
- trashSelected = selectedDocumentGroupTreeItem()->isTrashFolder();
-
- if ((docSelected || pageSelected) && proxyTi)
- trashSelected = dynamic_cast(proxyTi->parent())->isTrashFolder();
-
- if (multipleSelected)
- trashSelected = selectedItemsAreInTrash;
-
- bool defaultGroupSelected = false;
- if (groupSelected && selectedDocumentGroupTreeItem())
- defaultGroupSelected = selectedDocumentGroupTreeItem()->isDefaultFolder();
-
- mMainWindow->actionNewDocument->setEnabled((groupSelected || docSelected || pageSelected) && !trashSelected);
- mMainWindow->actionExport->setEnabled((docSelected || pageSelected) && !trashSelected);
- bool firstSceneSelected = false;
- if(docSelected)
- mMainWindow->actionDuplicate->setEnabled(!trashSelected);
- else if(pageSelected){
- QList selection = mDocumentUI->thumbnailWidget->selectedItems();
- if(pageCount == 1)
- mMainWindow->actionDuplicate->setEnabled(!trashSelected);
- else{
- for(int i = 0; i < selection.count() && !firstSceneSelected; i += 1){
- if(dynamic_cast(selection.at(i))->sceneIndex() == 0){
- mMainWindow->actionDuplicate->setEnabled(!trashSelected);
- firstSceneSelected = true;
- }
- }
- if(!firstSceneSelected)
- mMainWindow->actionDuplicate->setEnabled(!trashSelected);
- }
- }
- else
- mMainWindow->actionDuplicate->setEnabled(false);
-
- mMainWindow->actionOpen->setEnabled((docSelected || pageSelected) && !trashSelected);
- mMainWindow->actionRename->setEnabled((groupSelected || docSelected) && !trashSelected && !defaultGroupSelected);
-
- mMainWindow->actionAddToWorkingDocument->setEnabled(pageSelected
- && !(selectedDocumentProxy() == mBoardController->selectedDocument()) && !trashSelected);
+ QFileInfo fileInfo(filePath);
+ UBSettings::settings()->lastImportFilePath->set(QVariant(fileInfo.absolutePath()));
- bool deleteEnabled = false;
- if (trashSelected)
- {
- if (docSelected || multipleSelected)
- deleteEnabled = true;
- else if (groupSelected && selectedDocumentGroupTreeItem())
- {
- if (selectedDocumentGroupTreeItem()->childCount() > 0)
- deleteEnabled = true;
- }
- }
- else
- {
- deleteEnabled = groupSelected || docSelected || pageSelected || multipleSelected; // TODO: clean up. this is weirdly done
- }
+ bool success = false;
- if (pageSelected && (pageCount == mDocumentUI->thumbnailWidget->selectedItems().count()))
+ if (filePath.length() > 0)
{
- deleteEnabled = false;
- }
+ QApplication::processEvents(); // NOTE: We performed this just a few lines before. Is it really necessary to do it again here??
+ QFile selectedFile(filePath);
- if(pageSelected && pageCount == 1)
- deleteEnabled = false;
+ showMessage(tr("Importing file %1...").arg(fileInfo.baseName()), true);
- mMainWindow->actionDelete->setEnabled(deleteEnabled);
+ QStringList fileNames;
+ fileNames << filePath;
+ success = UBDocumentManager::documentManager()->addFilesToDocument(document, fileNames);
- if (trashSelected)
- {
- if (docSelected || multipleSelected) // TODO: clean this up. have only "selectedItemsAreInTrash"
+ if (success)
{
- mMainWindow->actionDelete->setIcon(QIcon(":/images/toolbar/deleteDocument.png"));
- mMainWindow->actionDelete->setText(tr("Delete"));
+ document->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime()));
+ UBMetadataDcSubsetAdaptor::persist(document);
}
else
{
- mMainWindow->actionDelete->setIcon(QIcon(":/images/trash.png"));
- mMainWindow->actionDelete->setText(tr("Empty"));
+ showMessage(tr("Failed to import file ... "));
}
}
- else
+
+ QApplication::restoreOverrideCursor();
+
+ return success;
+}
+
+
+void UBDocumentController::moveSceneToIndex(UBDocumentProxy* proxy, int source, int target)
+{
+ if (UBDocumentContainer::movePageToIndex(source, target))
{
- mMainWindow->actionDelete->setIcon(QIcon(":/images/trash.png"));
- mMainWindow->actionDelete->setText(tr("Trash"));
+ proxy->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime()));
+ UBMetadataDcSubsetAdaptor::persist(proxy);
+
+ mDocumentUI->thumbnailWidget->hightlightItem(target);
+
+ mBoardController->setActiveDocumentScene(target);
+ mBoardController->reloadThumbnails();
}
+}
+
- mMainWindow->actionDocumentAdd->setEnabled((docSelected || pageSelected) && !trashSelected && !multipleSelected);
- mMainWindow->actionImport->setEnabled(!trashSelected && !multipleSelected);
+void UBDocumentController::thumbnailViewResized()
+{
+ int maxWidth = qMin(UBSettings::maxThumbnailWidth, mDocumentUI->thumbnailWidget->width());
+ mDocumentUI->documentZoomSlider->setMaximum(maxWidth);
}
+void UBDocumentController::pageSelectionChanged()
+{
+ if (mIsClosing)
+ return;
+
+ bool pageSelected = mDocumentUI->thumbnailWidget->selectedItems().count() > 0;
+
+ if (pageSelected)
+ itemSelectionChanged(Page);
+ else
+ itemSelectionChanged(None);
+
+ updateActions();
+}
+
void UBDocumentController::documentSceneChanged(UBDocumentProxy* proxy, int pSceneIndex)
{
Q_UNUSED(pSceneIndex);
if (proxy == selectedDocumentProxy())
{
- emit documentThumbnailsUpdated(this);
+ reloadThumbnails();
+ }
+
+ QModelIndexList sel = mDocumentUI->documentTreeView->selectionModel()->selectedRows(0);
+
+ QModelIndex selection;
+ if(sel.count() > 0){
+ selection = sel.first();
}
-}
+ TreeViewSelectionChanged(selection, QModelIndex());
+}
-void UBDocumentController::pageDoubleClicked(QGraphicsItem* item, int index)
+void UBDocumentController::thumbnailPageDoubleClicked(QGraphicsItem* item, int index)
{
- Q_UNUSED(item);
- Q_UNUSED(index);
+ UBDocumentTreeModel *docModel = UBPersistenceManager::persistenceManager()->mDocumentTreeStructureModel;
+ QModelIndex selectedIndex = firstSelectedTreeIndex();
+
+ if (selectedIndex.isValid()) {
+ if (docModel->inModel(selectedIndex)) {
+ UBApplication::showMessage(tr("The model documents are not editable. Copy it to \"My documents\" to be able to work with"));
+ return;
+ } else if (docModel->inTrash(selectedIndex)) {
+ return;
+ }
+ }
- bool pageSelected = (mSelectionType == Page);
- bool groupSelected = (mSelectionType == Folder);
- bool docSelected = (mSelectionType == Document);
+ QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+ UBSceneThumbnailPixmap* thumb = qgraphicsitem_cast (item);
- bool trashSelected = false;
- if (groupSelected && selectedDocumentGroupTreeItem())
- trashSelected = selectedDocumentGroupTreeItem()->isTrashFolder();
- UBDocumentProxyTreeItem* proxyTi = selectedDocumentProxyTreeItem();
- if ((docSelected || pageSelected) && proxyTi)
- trashSelected = dynamic_cast(proxyTi->parent())->isTrashFolder();
- if (trashSelected) return;
+ if (thumb) {
+ UBDocumentProxy* proxy = thumb->proxy();
+ if (proxy && isOKToOpenDocument(proxy)) {
+ mBoardController->setActiveDocumentScene(proxy, index);
+ UBApplication::applicationController->showBoard();
+ }
+ }
- openSelectedItem();
+ QApplication::restoreOverrideCursor();
}
@@ -1476,32 +2794,6 @@ void UBDocumentController::pageClicked(QGraphicsItem* item, int index)
}
-void UBDocumentController::closing()
-{
- mIsClosing = true;
-
- QStringList emptyGroups;
-
- for (int i = 0; i < mDocumentUI->documentTreeWidget->topLevelItemCount(); i++)
- {
- QTreeWidgetItem* item = mDocumentUI->documentTreeWidget->topLevelItem(i);
-
- if (item->childCount() == 0)
- {
- UBDocumentGroupTreeItem* groupItem = dynamic_cast(item);
- if (groupItem)
- {
- QString groupName = groupItem->groupName();
- if (!emptyGroups.contains(groupName) && groupName != mDocumentTrashGroupName)
- emptyGroups << groupName;
- }
- }
- }
-
- UBSettings::settings()->setValue("Document/EmptyGroupNames", emptyGroups);
-
-}
-
void UBDocumentController::addToDocument()
{
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
@@ -1527,102 +2819,33 @@ void UBDocumentController::addToDocument()
for (int i = 0; i < pageInfoList.length(); i++)
{
- mBoardController->addScene(pageInfoList.at(i).first, pageInfoList.at(i).second, true);
+ mBoardController->addScene(pageInfoList.at(i).first, pageInfoList.at(i).second, false);
}
int newActiveSceneIndex = selectedItems.count() == mBoardController->selectedDocument()->pageCount() ? 0 : oldActiveSceneIndex + 1;
mDocumentUI->thumbnailWidget->selectItemAt(newActiveSceneIndex, false);
selectDocument(mBoardController->selectedDocument());
mBoardController->selectedDocument()->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime()));
+ UBMetadataDcSubsetAdaptor::persist(mBoardController->selectedDocument());
+ mBoardController->reloadThumbnails();
+ //UBApplication::boardController->documentNavigator()->generateThumbnails(this);
UBApplication::applicationController->showBoard();
- }
-
- QApplication::restoreOverrideCursor();
-}
-
-void UBDocumentController::addDocumentInTree(UBDocumentProxy* pDocument)
-{
- QString documentName = pDocument->name();
- QString documentGroup = pDocument->groupName();
-
- if (documentGroup.isEmpty())
- {
- documentGroup = mDefaultDocumentGroupName;
-
- }
- UBDocumentGroupTreeItem* group = 0;
-
- if (documentGroup.startsWith(UBSettings::trashedDocumentGroupNamePrefix))
- {
- group = mTrashTi;
- }
- else
- {
- for (int i = 0; i < mDocumentUI->documentTreeWidget->topLevelItemCount(); i++)
- {
- QTreeWidgetItem* item = mDocumentUI->documentTreeWidget->topLevelItem(i);
- UBDocumentGroupTreeItem* groupItem = dynamic_cast(item);
- if (groupItem->groupName() == documentGroup)
- {
- group = groupItem;
- break;
- }
- }
- }
-
- if (group == 0)
- {
- group = new UBDocumentGroupTreeItem(0); // deleted by the tree widget
- group->setGroupName(documentGroup);
- mDocumentUI->documentTreeWidget->addTopLevelItem(group);
- }
-
- UBDocumentProxyTreeItem *ti = new UBDocumentProxyTreeItem(group, pDocument, !group->isTrashFolder());
- ti->setText(0, documentName);
- mDocumentUI->documentTreeWidget->editItem(ti,0);
-}
-
-
-void UBDocumentController::updateDocumentInTree(UBDocumentProxy* pDocument)
-{
- QTreeWidgetItemIterator it(mDocumentUI->documentTreeWidget);
- while (*it)
- {
- UBDocumentProxyTreeItem* pi = dynamic_cast((*it));
-
- if (pi && pi->proxy() == pDocument)
- {
- pi->setText(0, pDocument->name());
- break;
- }
- ++it;
- }
-}
-
-QStringList UBDocumentController::allGroupNames()
-{
- QStringList result;
-
- for (int i = 0; i < mDocumentUI->documentTreeWidget->topLevelItemCount(); i++)
- {
- QTreeWidgetItem* item = mDocumentUI->documentTreeWidget->topLevelItem(i);
- UBDocumentGroupTreeItem* groupItem = dynamic_cast(item);
- result << groupItem->groupName();
+ mBoardController->setActiveDocumentScene(newActiveSceneIndex);
}
- return result;
+ QApplication::restoreOverrideCursor();
}
-
void UBDocumentController::renameSelectedItem()
{
- if (mDocumentUI->documentTreeWidget->selectedItems().count() > 0)
- mDocumentUI->documentTreeWidget->editItem(mDocumentUI->documentTreeWidget->selectedItems().at(0));
+ QModelIndex selectedIndex = firstSelectedTreeIndex();
+ if (selectedIndex.isValid()) {
+ mDocumentUI->documentTreeView->edit(selectedIndex);
+ }
}
-
bool UBDocumentController::isOKToOpenDocument(UBDocumentProxy* proxy)
{
//check version
@@ -1630,14 +2853,14 @@ bool UBDocumentController::isOKToOpenDocument(UBDocumentProxy* proxy)
if (docVersion.isEmpty() || docVersion.startsWith("4.1") || docVersion.startsWith("4.2")
|| docVersion.startsWith("4.3") || docVersion.startsWith("4.4") || docVersion.startsWith("4.5")
- || docVersion.startsWith("4.6") || docVersion.startsWith("4.8")) // TODO UB 4.7 update if necessary
+ || docVersion.startsWith("4.6") || docVersion.startsWith("4.7")) // TODO UB 4.8 update if necessary
{
return true;
}
else
{
if (UBApplication::mainWindow->yesNoQuestion(tr("Open Document"),
- tr("The document '%1' has been generated with a newer version of OpenBoard (%2). By opening it, you may lose some information. Do you want to proceed?")
+ tr("The document '%1' has been generated with a newer version of Sankore (%2). By opening it, you may lose some information. Do you want to proceed?")
.arg(proxy->metaData(UBSettings::documentName).toString())
.arg(docVersion)))
{
@@ -1659,7 +2882,7 @@ void UBDocumentController::showMessage(const QString& message, bool showSpinning
QRect newSize = mDocumentUI->thumbnailWidget->geometry();
- #ifdef Q_OS_OSX
+ #ifdef Q_WS_MACX
QPoint point(newSize.left() + margin, newSize.bottom() - mMessageWindow->height() - margin);
mMessageWindow->move(mDocumentUI->thumbnailWidget->mapToGlobal(point));
#else
@@ -1714,13 +2937,13 @@ void UBDocumentController::addImages()
else
{
document->setMetaData(UBSettings::documentUpdatedAt, UBStringUtils::toUtcIsoDateTime(QDateTime::currentDateTime()));
+ UBMetadataDcSubsetAdaptor::persist(document);
reloadThumbnails();
}
}
}
}
-
void UBDocumentController::toggleDocumentToolsPalette()
{
if (!mToolsPalette->isVisible() && !mToolsPalettePositionned)
@@ -1761,6 +2984,7 @@ void UBDocumentController::paste()
void UBDocumentController::focusChanged(QWidget *old, QWidget *current)
{
Q_UNUSED(old);
+ UBDocumentTreeModel *treeModel = UBPersistenceManager::persistenceManager()->mDocumentTreeStructureModel;
if (current == mDocumentUI->thumbnailWidget)
{
@@ -1769,13 +2993,11 @@ void UBDocumentController::focusChanged(QWidget *old, QWidget *current)
else
mSelectionType = None;
}
- else if (current == mDocumentUI->documentTreeWidget)
+ else if (current == mDocumentUI->documentTreeView)
{
- if (multipleSelection())
- mSelectionType = Multiple;
- else if (selectedDocumentProxy())
+ if (treeModel->isDocument(firstSelectedTreeIndex()))
mSelectionType = Document;
- else if (selectedDocumentGroupTreeItem())
+ else if (treeModel->isCatalog(firstSelectedTreeIndex()))
mSelectionType = Folder;
else
mSelectionType = None;
@@ -1790,14 +3012,158 @@ void UBDocumentController::focusChanged(QWidget *old, QWidget *current)
else
{
if (old != mDocumentUI->thumbnailWidget &&
- old != mDocumentUI->documentTreeWidget &&
+ old != mDocumentUI->documentTreeView &&
old != mDocumentUI->documentZoomSlider)
{
mSelectionType = None;
}
}
+}
+
+void UBDocumentController::updateActions()
+{
+ if (mIsClosing)
+ return;
+
+ UBDocumentTreeModel *docModel = UBPersistenceManager::persistenceManager()->mDocumentTreeStructureModel;
+
+ //N/C - NNE - 20140408
+ QModelIndexList list = mDocumentUI->documentTreeView->selectionModel()->selectedRows(0);
+
+ //if in multi selection, juste activate the actionDelete
+ if(list.count() > 1){
+ mMainWindow->actionNewDocument->setEnabled(false);
+ mMainWindow->actionNewFolder->setEnabled(false);
+ mMainWindow->actionExport->setEnabled(false);
+ mMainWindow->actionDuplicate->setEnabled(false);
+ mMainWindow->actionOpen->setEnabled(false);
+ mMainWindow->actionRename->setEnabled(false);
+
+ mMainWindow->actionAddToWorkingDocument->setEnabled(false);
+ mMainWindow->actionDocumentAdd->setEnabled(false);
+ mMainWindow->actionImport->setEnabled(false);
+ mMainWindow->actionDelete->setEnabled(true);
+
+ return;
+ }
+ //N/C - NNE - 20140408 : END
+
+ QModelIndex selectedIndex = firstSelectedTreeIndex();
+ UBDocumentProxy *selectedProxy = docModel->proxyData(selectedIndex);
+ int pageCount = -1;
+ if (selectedProxy) {
+ pageCount = selectedProxy->pageCount();
+ }
+
+ bool pageSelected = false;
+ bool groupSelected = false;
+ bool docSelected = false;
+
+ if (mSelectionType == Page) {
+ pageSelected = true;
+ } else {
+ if (docModel->isDocument(firstSelectedTreeIndex())) {
+ docSelected = true;
+ } else if (docModel->isCatalog(firstSelectedTreeIndex())) {
+ groupSelected = true;
+ }
+ }
+
+ bool trashSelected = docModel->inTrash(selectedIndex) || selectedIndex == docModel->trashIndex() ? true : false;
+ bool modelSelected = docModel->inModel(selectedIndex) || selectedIndex == docModel->modelsIndex() ? true : false;
+
+ mMainWindow->actionNewDocument->setEnabled(docModel->newNodeAllowed(selectedIndex) && !modelSelected);
+ mMainWindow->actionNewFolder->setEnabled(docModel->newNodeAllowed(selectedIndex));
+ mMainWindow->actionExport->setEnabled((docSelected || pageSelected || groupSelected) && !trashSelected);
+ updateExportSubActions(selectedIndex);
+
+ bool firstSceneSelected = false;
+
+ if (docSelected) {
+ mMainWindow->actionDuplicate->setEnabled(!trashSelected && !modelSelected);
+
+ } else if (pageSelected) {
+ QList selection = mDocumentUI->thumbnailWidget->selectedItems();
+ if(pageCount == 1) {
+ mMainWindow->actionDuplicate->setEnabled(!trashSelected && pageCanBeDuplicated(UBDocumentContainer::pageFromSceneIndex(0)));
+
+ } else {
+ for (int i = 0; i < selection.count() && !firstSceneSelected; i += 1) {
+ if (qgraphicsitem_cast(selection.at(i))->sceneIndex() == 0) {
+ mMainWindow->actionDuplicate->setEnabled(!trashSelected && pageCanBeDuplicated(UBDocumentContainer::pageFromSceneIndex(0)));
+ firstSceneSelected = true;
+ break;
+ }
+ }
+ if (!firstSceneSelected) {
+ mMainWindow->actionDuplicate->setEnabled(!trashSelected);
+ }
+ }
+
+ } else {
+ mMainWindow->actionDuplicate->setEnabled(false);
+ }
+
+ mMainWindow->actionOpen->setEnabled((docSelected || pageSelected) && !trashSelected && !modelSelected);
+ mMainWindow->actionRename->setEnabled(docModel->isOkToRename(selectedIndex));
+
+ mMainWindow->actionAddToWorkingDocument->setEnabled(pageSelected
+ && !(selectedProxy == mBoardController->selectedDocument()) && !trashSelected);
+
+ DeletionType deletionForSelection = deletionTypeForSelection(mSelectionType, selectedIndex, docModel);
+ mMainWindow->actionDelete->setEnabled(deletionForSelection != NoDeletion);
+
+ switch (static_cast(deletionForSelection)) {
+ case MoveToTrash :
+ case DeletePage :
+ mMainWindow->actionDelete->setIcon(QIcon(":/images/trash.png"));
+ mMainWindow->actionDelete->setText(tr("Trash"));
+ break;
+ case CompleteDelete :
+ mMainWindow->actionDelete->setIcon(QIcon(":/images/toolbar/deleteDocument.png"));
+ mMainWindow->actionDelete->setText(tr("Delete"));
+ break;
+ case EmptyFolder :
+ mMainWindow->actionDelete->setIcon(QIcon(":/images/trash.png"));
+ mMainWindow->actionDelete->setText(tr("Empty"));
+ break;
+ case EmptyTrash :
+ mMainWindow->actionDelete->setIcon(QIcon(":/images/toolbar/deleteDocument.png"));
+ mMainWindow->actionDelete->setText(tr("Empty"));
+ break;
+ }
+
+ mMainWindow->actionDocumentAdd->setEnabled((docSelected || pageSelected) && !trashSelected && !modelSelected);
+ mMainWindow->actionImport->setEnabled(!trashSelected);
+
+}
+
+void UBDocumentController::updateExportSubActions(const QModelIndex &selectedIndex)
+{
+ UBDocumentManager *documentManager = UBDocumentManager::documentManager();
+ for (int i = 0; i < documentManager->supportedExportAdaptors().length(); i++)
+ {
+ UBExportAdaptor* adaptor = documentManager->supportedExportAdaptors()[i];
+ if (adaptor->associatedAction()) {
+ adaptor->associatedAction()->setEnabled(adaptor->associatedActionactionAvailableFor(selectedIndex));
+ }
+ }
+}
+
+void UBDocumentController::currentIndexMoved(const QModelIndex &newIndex, const QModelIndex &PreviousIndex)
+{
+ Q_UNUSED(newIndex);
+ Q_UNUSED(PreviousIndex);
- selectionChanged();
+ UBDocumentTreeModel *docModel = UBPersistenceManager::persistenceManager()->mDocumentTreeStructureModel;
+ UBDocumentProxy *newProxy = docModel->proxyData(newIndex);
+ if (newProxy) {
+ UBDocumentProxy *cp = new UBDocumentProxy(*newProxy); // we cannot use newProxy because it will be destroyed later
+ pureSetDocument(cp);
+ mBoardController->pureSetDocument(cp);
+ mBoardController->pureSetDocument(newProxy);
+ }
+ mCurrentIndexMoved = true;
}
void UBDocumentController::deletePages(QList