diff --git a/platform/src/gui/GraphShape/BasicShape/CNewElfShape.cpp b/platform/src/gui/GraphShape/BasicShape/CNewElfShape.cpp new file mode 100644 index 00000000..f72d7185 --- /dev/null +++ b/platform/src/gui/GraphShape/BasicShape/CNewElfShape.cpp @@ -0,0 +1,492 @@ +#include "CNewElfShape.h" +#include "CShapeAdaptor.h" +#include "../hmi/CGraphScene.h" +#include "CLinkLine.h" +#include "CTextShape.h" +#include "CIconShape.h" + +CNewElfShape::CNewElfShape(char type, QGraphicsItem *parent) + : CGroupShape(type, parent) +{ +} + +CNewElfShape::~CNewElfShape() +{ + +} + +void CNewElfShape::clear() +{ + QList::iterator it = m_mergeList.begin(); + for (; it != m_mergeList.end(); it++) + { + getScene()->removeItem(*it); + } + m_mergeList.clear(); + m_tempInstMap.clear(); + m_txtReplaceMap.clear(); + m_pIconInfo = NULL; +} + +int CNewElfShape::read(CGStream &stream, char flag) +{ + Q_UNUSED(flag) + CShape::read(stream); + + if (stream.GetMode() == CGStream::xmlfile) + { + CXMLStream &xmls = stream.m_XMLStream; + xmls.GetValue("icon_name", m_pokeFile); + QRectF rect; + xmls.GetValue("rect", rect); + m_initWidth = rect.width(); + m_initHeight = rect.height(); + float wFactor = 1.; + float hFactor = 1.; + xmls.GetValue("WFactor", wFactor); + xmls.GetValue("HFactor", hFactor); + int replace_nums = 0; + xmls.GetValue("replace_nums", replace_nums); + QString replace; + for(int n=0; n> tmp; + m_pokeFile = QString::fromStdString(tmp); + + int x = 0; + int y = 0; + stream >> x; + stream >> y; + stream >> m_initWidth; + stream >> m_initHeight; + setPos(x, y); + double wFactor = 1.; + double hFactor = 1.; + stream >> wFactor; + stream >> hFactor; + int replace_nums; + stream >> replace_nums; + std::string replace_txt; + for(int n=0; n> replace_txt; + QStringList tmp = QString::fromStdString(replace_txt).split(":"); + if(tmp.size() == 2) + { + m_txtReplaceMap[QString(tmp[0]).toInt()] = tmp[1]; + } + } + setIconInfo(m_pokeFile, true); + setWFactor(wFactor); + setHFactor(hFactor); + setObjOpacity(opacity()); + } + + return 1; +} + +int CNewElfShape::write(CGStream &stream, char flag) +{ + Q_UNUSED(flag) + CShape::write(stream); + int count = 0; + if (stream.GetMode() == CGStream::xmlfile) + { + CXMLStream &xmls = stream.m_XMLStream; + QRect tmprect(pos().x(), pos().y(), m_initWidth, m_initHeight); + tmprect.normalized(); + xmls.PutValue("rect", tmprect); + xmls.PutValue("icon_name", m_pokeFile); + xmls.PutValue("WFactor", getWFactor()); + xmls.PutValue("HFactor", getHFactor()); + xmls.PutValue("replace_nums", m_txtReplaceMap.size()); + QMap::iterator iter = m_txtReplaceMap.begin(); + for(int n=0; iter != m_txtReplaceMap.end(); iter++,n++) + { + xmls.PutValue(QString("replace%1").arg(n), + QString("%1:%2").arg(QString::number(iter.key())).arg(iter.value())); + } + return 1; + } + + stream << m_pokeFile.toStdString(); + count += sizeof(int) + m_pokeFile.size(); + stream << (int)pos().x(); + count += sizeof(int); + stream << (int)pos().y(); + count += sizeof(int); + stream << m_initWidth; + count += sizeof(int); + stream << m_initHeight; + count += sizeof(int); + stream << getWFactor(); + count += sizeof(double); + stream << getHFactor(); + count += sizeof(double); + stream << m_txtReplaceMap.size(); + count += sizeof(int); + QString replace_txt; + QMap::iterator iter = m_txtReplaceMap.begin(); + for(int n=0; iter != m_txtReplaceMap.end(); iter++,n++) + { + replace_txt = QString("%1:%2").arg(QString::number(iter.key())).arg(iter.value()); + stream << replace_txt.toStdString(); + count += sizeof(int) + replace_txt.size(); + } + + return count; +} + +qreal CNewElfShape::getWFactor() const +{ + if(m_initWidth <= 0) + return 1.0; + return m_width / m_initWidth; +} + +qreal CNewElfShape::getHFactor() const +{ + if(m_initHeight <= 0) + return 1.0; + return m_height / m_initHeight; +} + +void CNewElfShape::setWFactor(float value) +{ + if(value <= 0) + return; + + prepareGeometryChange(); + m_width = m_initWidth * value; + QList::iterator it = m_mergeList.begin(); + for (; it != m_mergeList.end(); it++) + { + (*it)->zoomWidth(value); + } +} + +void CNewElfShape::setHFactor(float value) +{ + if(value <= 0) + return; + + prepareGeometryChange(); + m_height = m_initHeight * value; + QList::iterator it = m_mergeList.begin(); + for (; it != m_mergeList.end(); it++) + { + (*it)->zoomHeight(value); + } +} + +bool CNewElfShape::setIconInfo(QString &name, bool addToScene) +{ + m_pokeFile = name; + m_pIconInfo = IconInfoControlInstance()->getIconInfoPtr(28, name); + if (m_pIconInfo != NULL) + { + m_initWidth = m_pIconInfo->m_iconWidth; + m_initHeight = m_pIconInfo->m_iconHeight; + m_width = m_initWidth; + m_height = m_initHeight; + } + else + { + m_pIconInfo = IconInfoControlInstance()->getUnknowIconInfoPtr(); + m_initWidth = m_pIconInfo->m_iconWidth; + m_initHeight = m_pIconInfo->m_iconHeight; + m_width = m_initWidth; + m_height = m_initHeight; + } + + QList *objlist = m_pIconInfo->getObjListPtr(); + QList::iterator it = objlist->begin(); + + CShape *obj; + CShape *cloneObj = NULL; + for (; it != objlist->end(); it++) + { + obj = *it; + cloneObj = obj->clone(); + cloneObj->setObjId(obj->getObjId()); + cloneObj->setPos(obj->pos()+pos()); + cloneObj->m_prePos = cloneObj->pos(); + addObj(cloneObj); + if(addToScene){ + getScene()->addItem(cloneObj); + } + } + return true; +} + +void CNewElfShape::addObj(CShape *obj) +{ + if(obj == NULL) + { + return; + } + m_mergeList.push_back(obj); + obj->setParentObj(this); + obj->setFlag(QGraphicsItem::ItemIsMovable, false); + obj->setFlag(QGraphicsItem::ItemIsSelectable, false); + obj->setScene(getScene()); + + if(obj->getObjType() == OBJTYPE_RELATIVE) + { + CLinkLine *link = dynamic_cast(obj); + link->setStartDevId(getInstObjId(link->getStartDevId())); + link->setEndDevId(getInstObjId(link->getEndDevId())); + } + else if(obj->getObjType() == OBJTYPE_STRING || obj->getObjType() == OBJTYPE_POKE || obj->getObjType() == OBJTYPE_DBDATA) + { + obj->setFlag(QGraphicsItem::ItemIsSelectable, true); + QMap::iterator iter = m_txtReplaceMap.find(obj->getObjId()); + if(iter != m_txtReplaceMap.end()) + { + CTextShape *text = dynamic_cast(obj); + text->setString(iter.value()); + } + } + + replaceDynamic(obj); + addObjIdMap(obj->getObjId(), getScene()->getElfObjID()); + obj->setObjId(getScene()->getElfObjID()); + getScene()->increaseElfObjID(); +} + +void CNewElfShape::setPropertyValue(const QString &name, QVariant value) +{ + CShape::setPropertyValue(name, value); + + if (name == "纵向缩放比例") + { + if(value.toDouble() < 0.1) + { + return; + } + setHFactor(value.toDouble()); + } + else if (name == "横向缩放比例") + { + if(value.toDouble() < 0.1) + { + return; + } + setWFactor(value.toDouble()); + } + else if(name == QObject::tr("调用图形")) + { + QString v = value.toString().replace("QFile--", "").replace("\\", "/"); + if(v.contains(".elx")) + { + QString name; + CBaseInstance()->getPathName(CBase::PATH_TYPE_ELF, name); + QDir dir(name); + m_pokeFile = dir.relativeFilePath(v).remove(-4, 4); + } + else + { + m_pokeFile = v; + } + clear(); + setIconInfo(m_pokeFile, true); + } +} + +void CNewElfShape::getPropertyList(std::list > &propertyList) +{ + updateMergeRectList(); + + QString str = m_pokeFile; + str = str.section('/', -1); + str = "QFile--" + str; + + propertyList.push_back(std::pair(QObject::tr("对象名称"), m_nameString)); + propertyList.push_back(std::pair(QObject::tr("位置"), QVariant(pos().toPoint()))); + propertyList.push_back(std::pair(QObject::tr("横向缩放比例"), getWFactor())); + propertyList.push_back(std::pair(QObject::tr("纵向缩放比例"), getHFactor())); + propertyList.push_back(std::pair(QObject::tr("是否显示"), getInitVisible())); +// propertyList.push_back(std::pair(QObject::tr("轴Z坐标"), zValue())); + propertyList.push_back(std::pair(QObject::tr("透明度"), opacity())); + propertyList.push_back(std::pair(QObject::tr("调用图形"), str)); +} + +void CNewElfShape::updateGeometry(qreal x, qreal y, qreal width, qreal height) +{ + prepareGeometryChange(); + + setPos(x, y); + + m_width = width; + m_height = height; + setWFactor(m_width / m_initWidth); + setHFactor(m_height / m_initHeight); +} + +void CNewElfShape::addObjIdMap(const long &temp, const long &inst) +{ + m_tempInstMap[temp] = inst; +} + +long CNewElfShape::getTempObjId(long nInstObjId) +{ + QMap::iterator iter = m_tempInstMap.begin(); + for(; iter != m_tempInstMap.end(); ++iter) + { + if(iter.value() == nInstObjId) + { + return iter.key(); + } + } + return -1; +} + +long CNewElfShape::getInstObjId(long nTempObjId) +{ + QMap::iterator iter = m_tempInstMap.find(nTempObjId); + if(iter == m_tempInstMap.end()) + { + return -1; + } + return iter.value(); +} + +void CNewElfShape::addReplaceTxt(long nInstObjId, const QString &text) +{ + m_txtReplaceMap[getTempObjId(nInstObjId)] = text; +} + +void CNewElfShape::replaceDynamic(CShape *obj) +{ + int group,num; + QString cTag,pTag; + CDynamic *cDy,*pDy; + obj->getDynamicPtrInfo(group, num); + for(int n=0; n < group; ++n) + { + cDy = obj->getDynamicPtr(n, num); + if(cDy) + { + pDy = getDynamicPtr(n,num); + if(!pDy) + { + break; + } + cTag = cDy->getTagName(); //< "station1.PSCADA.digital.station1.G01_dlq.Pos.value" + pTag = pDy->getTagName(); //< "PSCADA.station1.G02" + QStringList cList = cTag.split("."); + QStringList pList = pTag.split("."); + if(cList.size() != 7 || pList.size() != 3) + { + continue; + } + cList[0] = pList[1]; + cList[1] = pList[0]; + cList[3] = pList[1]; + cList[4] = QString(cList[4]).replace(QString(cList[4]).section("_", 0, 0), pList[2]); + cDy->setTagName(cList.join(".")); + } + } +} + +void CNewElfShape::paint(QPainter *painter, const QStyleOptionGraphicsItem *style, QWidget *w) +{ + Q_UNUSED(style) + Q_UNUSED(w) + painter->save(); + auto objP = QRectF(m_startX, m_startY, m_width, m_height); + subDraw(painter, objP, Qt::darkBlue, Qt::DotLine, 0, Qt::NoBrush, 1); + drawHandles(painter); + painter->restore(); +} + +void CNewElfShape::mouseMoveEvent(QGraphicsSceneMouseEvent *e) +{ + if(parentItem()) + { + return QGraphicsItem::mouseMoveEvent(e); + } + if ((e -> buttons() & Qt::LeftButton) && (m_selPoint > -1) && scene()) + { + QPointF mousePoint = (e -> pos()); + + prepareGeometryChange(); + m_pos2 = pos() - mapToScene(mousePoint); + switch (m_selPoint) + { + case 3: +// m_width = mousePoint.x(); + break; + case 6: +// m_width = mousePoint.x(); +// m_height = mousePoint.y(); + break; + case 5: +// m_height = mousePoint.y(); + break; + default: + break; + } + + if(m_width <= 4) + { + m_width = 4; + } + if(m_height <= 4) + { + m_height = 4; + } + setWFactor(m_width / m_initWidth); + setHFactor(m_height / m_initHeight); + } + else + { + QGraphicsItem::mouseMoveEvent(e); + } +} + +QVariant CNewElfShape::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) +{ + switch (change) + { + case ItemSelectedChange: + { + QList::iterator it = m_mergeList.begin(); + for (; it != m_mergeList.end(); it++) + { + (*it)->setFlag(QGraphicsItem::ItemIsSelectable, !value.toBool()); + if(!dynamic_cast(*it)) + { + (*it)->setFlag(QGraphicsItem::ItemIsSelectable, false); + } + } + if(value.toInt() == 1) + { + setZaxisTop(); + } + else + { + setZaxisBottom(); + } + } + default: + break; + }; + return CShape::itemChange(change,value); +} diff --git a/platform/src/gui/GraphShape/DynamicShape/CDyLinkLine.cpp b/platform/src/gui/GraphShape/DynamicShape/CDyLinkLine.cpp new file mode 100644 index 00000000..1e455675 --- /dev/null +++ b/platform/src/gui/GraphShape/DynamicShape/CDyLinkLine.cpp @@ -0,0 +1,236 @@ +#include "CDyLinkLine.h" +#include "CLinkLine.h" +#include "../hmi/CGraphScene.h" + +CDyLinkLine::CDyLinkLine(char type, QGraphicsItem *parent) : CLineShape(type, parent) +{ + m_objType = type; + m_arrowType = ArrowType::End; + m_IslandState = 254; + + setFlag(QGraphicsItem::ItemIsMovable, true); + setFlag(QGraphicsItem::ItemIsSelectable, true); + + m_hoverPin = -1; + m_selPin = -1; + m_pinList << QPointF(m_startX, m_startY); + m_pinStatus << 0; + m_nodeNoVec << 0; +} + +int CDyLinkLine::read(CGStream &stream, char flag) +{ + CLineShape::read(stream, flag); + m_pinList.clear(); + m_pinStatus.clear(); + m_pinList << QPointF(m_startX, m_startY) << QPointF(m_endX, m_endY); + m_pinStatus << 0 << 0; + return 1; +} + +CShape *CDyLinkLine::clone(char flag) +{ + CDyLinkLine *pObj = new CDyLinkLine(m_objType, NULL); + pObj->copy((CShape *)this, flag); + return (CShape *)pObj; +} + +int CDyLinkLine::copy(CShape *src, char flag) +{ + Q_UNUSED(flag) + if (src == NULL) + { + return -1; + } + CLineShape::copy(src, flag); + m_pinList = ((CDyLinkLine*)src)->m_pinList; + m_pinStatus = ((CDyLinkLine*)src)->m_pinStatus; + return 0; +} + +bool CDyLinkLine::IsPscadaLinkObj() +{ + return true; +} + +QPointF CDyLinkLine::getScenePin(qreal pin) +{ + QPointF pinPoint; + if (pin >=0 && pin < m_pinList.count()) + { + pinPoint = mapToScene(m_pinList.at(pin)); + } + + return pinPoint; +} + +bool CDyLinkLine::getSelectScenePin(QPointF &pin) +{ + if (m_selPin == -1) + { + return false; + } + else + { + pin = mapToScene(m_pinList.at(m_selPin)); + } + + return true; +} + +qreal CDyLinkLine::getSelectPin() +{ + return m_selPin; +} + +int CDyLinkLine::getPinStatus(int pin) +{ + int status = -1; + if (pin >= 0 && pin < 3) + { + status = m_pinStatus[pin]; + } + + return status; +} + +void CDyLinkLine::setPinSelected(int pin) +{ + m_selPin = pin; +} + +void CDyLinkLine::setPinHovered(int pin) +{ + m_hoverPin = pin; +} + +void CDyLinkLine::setEndPoint(const QPointF &point) +{ + CLineShape::setEndPoint(point); + + if(m_pinList.size() > 1) + { + m_pinList.removeLast(); + m_pinStatus.removeLast(); + } + m_pinList << QPointF(m_endX, m_endY); + m_pinStatus << 0; +} + +bool CDyLinkLine::getIslandState(int &state) +{ + if (m_IslandState == 254) + { + return false; + } + else + { + state = m_IslandState; + return true; + } +} + +void CDyLinkLine::setIslandState(int state) +{ + m_IslandState= state; +} + +QVariant CDyLinkLine::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) +{ + switch (change) + { + case ItemPositionHasChanged: + foreach (CLinkLine *edge, m_edgeList) + edge->adjust(); + break; + default: + break; + }; + + return QGraphicsItem::itemChange(change,value); +} + +void CDyLinkLine::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + unsigned char envFlag = getScene()->getEnvTypeFlag(); + if(envFlag == AppMode::ExplorerMode) + { + CDynamic *pdyn = getDynamicPtr(0); + if (pdyn) + { + int qcolor = 0; + getIslandState(qcolor); + if(!qcolor) + { + int c = CBaseInstance()->getOffColor(); + pdyn->setDyLineColor(c); + pdyn->setDyFillColor(c); + } + else + { + pdyn->setDyLineColor(getLineColor()); + pdyn->setDyFillColor(getFillColor()); + } + } + } + else + { + QPointF hander(3, 3); + QPointF pin; + + for (int i = 0; i < m_pinList.count(); i++) + { + pin = m_pinList.at(i); + if (i == m_hoverPin) + { + painter->setBrush(QBrush(Qt::red)); + } + + painter->setPen(QPen(Qt::black)); + painter->drawEllipse(QRectF(pin - hander, pin + hander)); + } + } + + CLineShape::paint(painter, option, widget); +} + +void CDyLinkLine::mousePressEvent(QGraphicsSceneMouseEvent *e) +{ + m_selPin = m_hoverPin; + CLineShape::mousePressEvent(e); +} + +void CDyLinkLine::hoverMoveEvent(QGraphicsSceneHoverEvent *e) +{ + CLineShape::hoverMoveEvent(e); + + QPointF hoverPoint = e->pos(); + + { + for (m_hoverPin = 0; m_hoverPin < m_pinList.count(); m_hoverPin++) + { + if (hasClickedOn(hoverPoint, m_pinList.at(m_hoverPin))) + { + break; + } + } + + if (m_hoverPin == m_pinList.count()) + { + m_hoverPin = -1; + } + + update(); + } +} + +void CDyLinkLine::hoverLeaveEvent(QGraphicsSceneHoverEvent *e) +{ + if (m_hoverPin > -1) + { + m_hoverPin = -1; + update(); + } + + CLineShape::hoverLeaveEvent(e); +} diff --git a/platform/src/gui/GraphShape/include/CDyLinkLine.h b/platform/src/gui/GraphShape/include/CDyLinkLine.h new file mode 100644 index 00000000..fb87b24d --- /dev/null +++ b/platform/src/gui/GraphShape/include/CDyLinkLine.h @@ -0,0 +1,47 @@ +#ifndef CDYLINKLINE_H +#define CDYLINKLINE_H + +#include "CLineShape.h" + +class DLL_CLASS CDyLinkLine : public CLineShape +{ + Q_OBJECT +public: + CDyLinkLine(char type, QGraphicsItem *parent = NULL); + + int read(CGStream &stream, char flag); + CShape *clone(char flag = RW_PART_ALL); + int copy(CShape *src, char flag = RW_PART_ALL); + + bool IsPscadaLinkObj(); + + QPointF getScenePin(qreal pin); + bool getSelectScenePin(QPointF &pin); + qreal getSelectPin(); + int getPinStatus(int pin); + void setPinSelected(int pin); + void setPinHovered(int pin); + + void setEndPoint(const QPointF &point); + + bool getIslandState(int &state); + void setIslandState(int state); + +protected: + QVariant itemChange(GraphicsItemChange change, const QVariant &value); + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + void mousePressEvent(QGraphicsSceneMouseEvent *e); + void hoverMoveEvent(QGraphicsSceneHoverEvent *e); + void hoverLeaveEvent(QGraphicsSceneHoverEvent *e); + +public: + void getObjName(QString &name) + { + name = QObject::tr("自由连接线"); + } + +private: + int m_IslandState; +}; + +#endif // CDYLINKLINE_H diff --git a/platform/src/gui/GraphShape/include/CNewElfShape.h b/platform/src/gui/GraphShape/include/CNewElfShape.h new file mode 100644 index 00000000..cd63a76f --- /dev/null +++ b/platform/src/gui/GraphShape/include/CNewElfShape.h @@ -0,0 +1,60 @@ +#ifndef CNEWELFSHAPE_H +#define CNEWELFSHAPE_H + +#include "CGroupShape.h" +#include "../IconInfo/CIconInfo.h" +#include "../IconInfo/CIconInfoControl.h" + +class DLL_CLASS CNewElfShape : public CGroupShape +{ + Q_OBJECT +public: + CNewElfShape(char type, QGraphicsItem *parent = NULL); + virtual ~CNewElfShape(); + + void getObjName(QString &name) + { + name = m_pokeFile; + } + QString getPokeFile() + { + return m_pokeFile; + } + + void clear(); + + int read(CGStream &stream, char flag); + int write(CGStream &stream, char flag); + + qreal getWFactor() const; + qreal getHFactor() const; + void setWFactor(float value); + void setHFactor(float value); + bool setIconInfo(QString &name, bool addToScene = false); + void addObj(CShape *obj); + + void setPropertyValue(const QString &name, QVariant value); + void getPropertyList(std::list< std::pair > &propertyList); + void updateGeometry(qreal x, qreal y, qreal width, qreal height); + + void addObjIdMap(const long &temp, const long &inst); + long getTempObjId(long nInstObjId); + long getInstObjId(long nTempObjId); + void addReplaceTxt(long nInstObjId, const QString &text); + void replaceDynamic(CShape *obj); + +protected: + void paint(QPainter *painter, const QStyleOptionGraphicsItem *style, QWidget *w); + void mouseMoveEvent(QGraphicsSceneMouseEvent *e); + QVariant itemChange(GraphicsItemChange change, const QVariant &value); + +public: + CIconInfo *m_pIconInfo; + QMap m_tempInstMap; //< 模板obj_id - 实例obj_id + QMap m_txtReplaceMap; //< 模板obj_id - 文本 + QString m_pokeFile; + qreal m_initWidth; + qreal m_initHeight; +}; + +#endif // CNEWELFSHAPE_H diff --git a/platform/src/gui/GraphTool/AutoCreateElement/AutoCreateElement.pro b/platform/src/gui/GraphTool/AutoCreateElement/AutoCreateElement.pro new file mode 100644 index 00000000..3c8f6135 --- /dev/null +++ b/platform/src/gui/GraphTool/AutoCreateElement/AutoCreateElement.pro @@ -0,0 +1,50 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2024-12-17T17:51:45 +# +#------------------------------------------------- + +QT += core gui widgets sql xml script +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = AutoCreateElement +TEMPLATE = lib + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which has been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +INCLUDEPATH += $$PWD +INCLUDEPATH += ../../PropertyEditor + +SOURCES += \ + CAutoCreate.cpp + +HEADERS += \ + CAutoCreate.h \ + AutoCreateExport.h \ + CAutoListModel.h + +DEFINES += DLL_OUT_AUTOCREATE + +LIBS += -lGraphPub -lGraphShape +LIBS += -llog4cplus -ldb_base_api -ldb_api_ex -lpub_logger_api -lpub_utility_api -ldb_sysinfo_api -lpub_widget +LIBS += -lPropertyEditor -lToolBoxTree + +COMMON_PRI=$$PWD/../../../common.pri +exists($$COMMON_PRI) { + include($$COMMON_PRI) +}else { + error("FATAL error: can not find common.pri") +} + +FORMS += \ + CAutoCreate.ui + diff --git a/platform/src/gui/GraphTool/AutoCreateElement/AutoCreateExport.h b/platform/src/gui/GraphTool/AutoCreateElement/AutoCreateExport.h new file mode 100644 index 00000000..b598d91c --- /dev/null +++ b/platform/src/gui/GraphTool/AutoCreateElement/AutoCreateExport.h @@ -0,0 +1,26 @@ +#ifndef AUTOCREATEEXPORT_H +#define AUTOCREATEEXPORT_H + +#ifndef G_DECL_EXPORT_AUTOCREATE +# ifdef WIN32 +# define G_DECL_EXPORT_AUTOCREATE __declspec(dllexport) +# else +# define G_DECL_EXPORT_AUTOCREATE __attribute__((visibility("default"))) +# endif +#endif + +#ifndef G_DECL_IMPORT_AUTOCREATE +# ifdef WIN32 +# define G_DECL_IMPORT_AUTOCREATE __declspec(dllimport) +# else +# define G_DECL_IMPORT_AUTOCREATE +# endif +#endif + +#ifdef DLL_OUT_AUTOCREATE +# define DLL_CLASS_AUTOCREATE G_DECL_EXPORT_AUTOCREATE +#else +# define DLL_CLASS_AUTOCREATE G_DECL_IMPORT_AUTOCREATE +#endif + +#endif // AUTOCREATEEXPORT_H diff --git a/platform/src/gui/GraphTool/AutoCreateElement/CAutoCreate.cpp b/platform/src/gui/GraphTool/AutoCreateElement/CAutoCreate.cpp new file mode 100644 index 00000000..b4efdbe4 --- /dev/null +++ b/platform/src/gui/GraphTool/AutoCreateElement/CAutoCreate.cpp @@ -0,0 +1,854 @@ +#include "CAutoCreate.h" +#include "ui_CAutoCreate.h" +#include "dbms/db_sysinfo_api/CDbSysInfo.h" +#include "pub_logger_api/logger.h" +#include "pub_utility_api/FileUtil.h" +#include "pub_utility_api/I18N.h" +#include "pub_utility_api/FileStyle.h" +#include "pub_widget/PubWidgetInit.h" +#include "../ToolBoxTree/CBoxListView.h" +#include "../../include/CXMLStream.h" +#include "../../include/CShape.h" +#include "../GraphShape/include/CIconShape.h" +#include "../GraphShape/include/CDrawObjFactory.h" +#include "../GraphShape/include/CLinkLine.h" +#include "../GraphShape/include/CNewElfShape.h" + +#include +#include +#include +#include + +CAutoCreate::CAutoCreate(QWidget *parent, Qt::WindowFlags f) : + CustomUiDialog(parent), + ui(new Ui::CAutoCreate), + m_pReadDb(Q_NULLPTR), + m_devGroupModel(Q_NULLPTR), + m_devPointModel(Q_NULLPTR), + m_devPointSelModel(Q_NULLPTR), + m_pPropertyBox(Q_NULLPTR), + m_pToolBox(Q_NULLPTR), + m_pCurrentObj(Q_NULLPTR), + m_pGroupRadio(Q_NULLPTR) +{ + ui->setupUi(this); + setWindowTitle(tr("批量生成图元")); + initial(); + if(!parent) + { + setWindowFlag(Qt::WindowStaysOnTopHint); + setAttribute(Qt::WA_DeleteOnClose); + } + + CustomUiDialog::setAutoLayout(true); +} + +CAutoCreate::~CAutoCreate() +{ + if(m_pReadDb != NULL) + { + m_pReadDb->close(); + delete m_pReadDb; + } + m_pReadDb = NULL; + + if( m_pCurrentObj ) + { + delete m_pCurrentObj; + } + m_pCurrentObj = NULL; + + delete ui; +} + +void CAutoCreate::initial() +{ + initDBConnect(); + initVar(); + loadSheet(); + initUi(); + initConn(); + if ( m_pReadDb->isOpen()) + { + QSqlQuery query; + //查询所有专业名称 + m_pReadDb->execute(QString("select tag_name, description from sys_model_sub_system_info where sub_system_id > %1").arg(CN_AppId_COMAPP), query); + if(query.isActive()) + { + while(query.next()) + { + QString strSubSystemName = query.value(0).toString(); + QString strSubSystemDesc = query.value(1).toString(); + ui->Profession->addItem(strSubSystemDesc, strSubSystemName); + } + } + + //查询所有位置名称 + m_pReadDb->execute("select tag_name, description from sys_model_location_info", query); + if(query.isActive()) + { + while(query.next()) + { + QString strLocationName = query.value(0).toString(); + QString strLocationDesc = query.value(1).toString(); + ui->Location->addItem(strLocationDesc, strLocationName); + } + } + } + ui->Profession->adjustSize(); + ui->Location->adjustSize(); +} + +void CAutoCreate::initDBConnect() +{ + m_pReadDb = new CDbApi(DB_CONN_MODEL_READ); + m_pReadDb->open(); + if(m_pReadDb->isOpen()) + { + LOGINFO("initialize autoCreateElements database success!"); + } + else + { + LOGERROR("initialize autoCreateElements database failed!"); + } +} + +void CAutoCreate::initUi() +{ + ui->Device_TableView->setModel(m_devGroupModel); + + ui->select_listView->setModel(m_devPointSelModel); + ui->select_listView->setDragEnabled(true); + ui->select_listView->setDropIndicatorShown(true); + ui->select_listView->setDragDropMode(QAbstractItemView::InternalMove); + ui->select_listView->setDefaultDropAction(Qt::MoveAction); + + ui->TagNameView->setModel(m_devPointModel); + ui->TagNameView->setSelectionMode(QAbstractItemView::ExtendedSelection); + + + ui->TagTypeComboBox->addItem(tr("数字量"), "digital"); + ui->TagTypeComboBox->addItem(tr("模拟量"), "analog"); + ui->TagTypeComboBox->addItem(tr("混合量"), "mix"); + ui->TagTypeComboBox->addItem(tr("累积量"), "accuml"); + ui->TagTypeComboBox->addItem(tr("常量"), "const"); + ui->TagTypeComboBox->setCurrentIndex(0); + + QCompleter *completer = new QCompleter(ui->DeviceGroupComboBox->model()); //补全器 + completer->setFilterMode(Qt::MatchContains); + ui->DeviceGroupComboBox->setEditable(true); + ui->DeviceGroupComboBox->setCompleter(completer); + ui->DeviceGroupComboBox->setInsertPolicy(QComboBox::NoInsert); + + + m_pGroupRadio = new QButtonGroup(this); + m_pGroupRadio->addButton(ui->radio_column , 0); + m_pGroupRadio->addButton(ui->radio_row , 1); + ui->radio_column->setChecked(true); + + QPushButton * pDeviceFilter = new QPushButton(this); + pDeviceFilter->setObjectName("filterBtn"); + pDeviceFilter->setCursor(QCursor(Qt::ArrowCursor)); + QHBoxLayout * pDeviceLayout = new QHBoxLayout(); + pDeviceLayout->setContentsMargins(1, 1, 1, 1); + pDeviceLayout->addStretch(); + pDeviceLayout->addWidget(pDeviceFilter); + ui->DeviceFilter->setLayout(pDeviceLayout); + + QPushButton * pPointFilter = new QPushButton(this); + pPointFilter->setObjectName("filterBtn"); + pPointFilter->setCursor(QCursor(Qt::ArrowCursor)); + QHBoxLayout * pPointLayout = new QHBoxLayout(); + pPointLayout->setContentsMargins(1, 1, 1, 1); + pPointLayout->addStretch(); + pPointLayout->addWidget(pPointFilter); + ui->DeviceFilter_point->setLayout(pPointLayout); + + connect(pDeviceFilter, SIGNAL(clicked()), this, SLOT(slot_devGroupFilter())); + connect(pPointFilter, SIGNAL(clicked()), this, SLOT(slot_devPointFilter())); + + //加载图元 + loadToolBox(); +} + +void CAutoCreate::initVar() +{ + m_devGroupModel = new QStandardItemModel(this); + m_devPointModel = new QStandardItemModel(this); + m_devPointSelModel = new CAutoListModel(this); + m_devPointModel->setColumnCount(2); + m_devPointSelModel->setColumnCount(2); + m_pPropertyBox = ui->widget; + m_pToolBox = ui->treeWidget; +} + +void CAutoCreate::initConn() +{ + connect(ui->Location, SIGNAL(currentIndexChanged(QString)), this, SLOT(slot_currentLocationChanged(QString))); + connect(ui->Profession, SIGNAL(currentIndexChanged(QString)), this, SLOT(slot_currentProfessionChanged(QString))); + connect(ui->DeviceGroupComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(slot_currentDevGroupChanged(QString))); + connect(ui->TagTypeComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(slot_currentDevGroupChanged(QString))); + connect(ui->Device_TableView, SIGNAL(clicked(QModelIndex)), this, SLOT(slot_currentSelectDeviceChanged(QModelIndex))); + connect(ui->DeviceFilter , SIGNAL(textEdited(QString)) , this , SLOT(slot_devGroupFilter())); + connect(ui->DeviceFilter_point , SIGNAL(textEdited(QString)) , this , SLOT(slot_devPointFilter())); + connect(ui->TagNameView , &QListView::doubleClicked , this , &CAutoCreate::slot_tagNameListViewDoubleClicked ); + connect(ui->select_listView , &QListView::doubleClicked , this , &CAutoCreate::slot_selectListViewDoubleClicked ); + connect(ui->btn_delAll , &QPushButton::clicked , this , &CAutoCreate::slot_deleAllBtnClicked); + connect(ui->btn_delSelect , &QPushButton::clicked , this , &CAutoCreate::slot_deleSelectBtnClicked); + connect(ui->btn_addAll , &QPushButton::clicked , this , &CAutoCreate::slot_addAllBtnClicked); + connect(ui->btn_addSelect , &QPushButton::clicked , this , &CAutoCreate::slot_addSelectBtnClicked); + connect(m_devPointSelModel , &QStandardItemModel::rowsInserted , this , &CAutoCreate::slot_updateLabel); + connect(m_devPointSelModel , &QStandardItemModel::rowsRemoved , this , &CAutoCreate::slot_updateLabel); + connect(ui->btn_confirm , &QPushButton::clicked , this , &CAutoCreate::slot_btnConfirmCreate); + connect(ui->btn_cancel , &QPushButton::clicked , this , &CAutoCreate::reject); + connect(m_pPropertyBox, SIGNAL(propertyValueChanged(QString, QVariant, bool)), + this, SLOT(updateCurrentProperty(QString, QVariant, bool))); + +} + +void CAutoCreate::loadSheet() +{ + QString qss = QString(); + std::string strFullPath = iot_public::CFileStyle::getPathOfStyleFile("public.qss","zh","light"); + + QFile qssfile1(QString::fromStdString(strFullPath)); + qssfile1.open(QFile::ReadOnly); + if (qssfile1.isOpen()) + { + qss += QLatin1String(qssfile1.readAll()); + qssfile1.close(); + } + + strFullPath = iot_public::CFileStyle::getPathOfStyleFile("AutoCreate.qss","zh","light") ; + QFile qssfile(QString::fromStdString(strFullPath)) ; + qssfile.open(QFile::ReadOnly); + if (qssfile.isOpen()) + { + qss += QLatin1String(qssfile.readAll()); + qssfile.close(); + } + + if (!qss.isEmpty()) + { + qApp->setStyleSheet(qss); + } + iot_public::installTranslator(iot_public::getCurLanguage()); +} + +void CAutoCreate::updatePointList() +{ + m_devPointModel->clear(); + QString professionDescription = ui->Profession->currentText(); + QString locationDescription = ui->Location->currentText(); + professionDescription = professionDescription.replace("'", "''"); + locationDescription = locationDescription.replace("'", "''"); + if( professionDescription.isEmpty() || locationDescription.isEmpty() || !ui->Device_TableView->currentIndex().isValid()) + { + return; + } + QString strDeviceName = m_devGroupModel->item(ui->Device_TableView->currentIndex().row())->data().toString().split(",").first(); + QString typeValue = ui->TagTypeComboBox->currentData().toString(); + //获取当前设备 点位 + if(m_pReadDb->isOpen()) + { + QSqlQuery query; + QString queryStr = QString( + "SELECT l.tag_name AS location_tag_name," + "s.tag_name AS sub_system_tag_name," + "'%1' AS table_name," + "t.tag_name AS point_tag_name,t.description " + "FROM %1 t " + "JOIN sys_model_sub_system_info s ON t.sub_system = s.sub_system_id " + "JOIN sys_model_location_info l ON t.location_id = l.location_id " + "WHERE t.sub_system = (" + "SELECT sub_system_id " + "FROM sys_model_sub_system_info " + "WHERE description = '%2' " + "AND sub_system_id > %3" + ") " + "AND t.location_id = (" + "SELECT location_id " + "FROM sys_model_location_info " + "WHERE description = '%4'" + ") " + "AND t.device = '%5'" + "ORDER BY t.seq_no ASC" + ).arg(typeValue).arg(professionDescription).arg(CN_AppId_COMAPP).arg(locationDescription).arg(strDeviceName); + if( m_pReadDb->execute(queryStr, query) ) + { + if(query.isActive()) + { + while(query.next()) + { + QString tagInfo = QString("%1.%2.%3.%4").arg(query.value(0).toString()).arg(query.value(1).toString()).arg(query.value(2).toString()).arg(query.value(3).toString()); + QString desc = query.value(4).toString(); + m_devPointModel->appendRow({new QStandardItem(desc) , new QStandardItem(tagInfo)}); + } + + } + }else + { + LOGERROR("AutoCreate: updatePointList sql failed! sqlStr: %s" , queryStr.toStdString().c_str()); + } + } + + if( m_devPointModel->index(0,0).isValid() ) + { + ui->TagNameView->setCurrentIndex(m_devPointModel->index(0,0)); + } + +} + +void CAutoCreate::loadToolBox() +{ + loadIconTrans(); + for (int j = 0; j < DrawObjDatabase::numWidgetGroups(); j++) + { + QString grp = DrawObjDatabase::widgetGroup(j); + + //目前只开放基本图元以及电气图元 + if ( (grp != tr("基本图元") && grp != tr("电气图元")) || !DrawObjDatabase::isGroupVisible(grp)) + { + continue; + } + + QTreeWidgetItem *tb2 = new QTreeWidgetItem(m_pToolBox); + tb2->setText(0, s_iconTransMap[grp]); + tb2->setData(0, Qt::UserRole + 3, grp); + + CBoxListView * listView = m_pToolBox->addListView(tb2, true); + connect(listView, &CBoxListView::itemPressed, this, &CAutoCreate::slot_updataProPerty); + + for (int i = 0; i < DrawObjDatabase::count(); ++i) + { + if (DrawObjDatabase::group(i) != grp) + { + continue; + } + + DrawObjDatabaseRecord * record = DrawObjDatabase::at(i); + if(record) + { + record->name = s_iconTransMap[record->name]; + DrawObjDatabase::iconSet(i); + listView->addWidget(record); + } + } + m_pToolBox->adjustSubListSize(tb2); + } +} + +void CAutoCreate::loadIconTrans() +{ + if(!s_iconTransMap.isEmpty()) + return; + + CXMLStream xmls; + QString toolTrans; + CBaseInstance()->getPathName(CBase::PATH_TYPE_ICONTRANS, toolTrans); + + for(int j = 0; j < DrawObjDatabase::numWidgetGroups(); j++) + { + QString grp = DrawObjDatabase::widgetGroup(j); + s_iconTransMap[grp] = grp; + for(int i = 0; i < DrawObjDatabase::count(); ++i) + { + QString atext = DrawObjDatabase::className(i); + s_iconTransMap[atext] = atext; + } + } + + int ret = xmls.OPEN(toolTrans.toLocal8Bit().data(), 100, 1); + if(ret == -1) + { + return; + } + + QDomElement contextItem, transItem; + contextItem = xmls.GetChild("context"); + QDomNode transNode = contextItem.firstChild(); + QString source, trans; + while(!transNode.isNull()) + { + transItem = transNode.toElement(); + source = transItem.attribute("source"); + trans = transItem.attribute("trans"); + s_iconTransMap[source] = trans.isEmpty() ? source : trans; + transNode = transNode.nextSibling(); + } + + xmls.CLOSE(); +} + +void CAutoCreate::getAllSelectPointInfo(QList > &listInfo) +{ + listInfo.clear(); + int rowCount = m_devPointSelModel->rowCount(); + for (int row = 0; row < rowCount; ++row) + { + QStandardItem *descItem = m_devPointSelModel->item(row, 0); + QStandardItem *valueItem = m_devPointSelModel->item(row, 1); + + if (descItem && valueItem) + { + QString desc = descItem->text(); + QString value = valueItem->text(); + listInfo.append(qMakePair(desc, value)); + } + } +} + +void CAutoCreate::updateCurrentProperty(const QString &name, const QVariant &value, bool sub) +{ + Q_UNUSED(sub) + if( m_pCurrentObj == NULL) + { + return; + } + m_pCurrentObj->setPropertyValue(name, value); + m_pCurrentObj->update(); +} + +void CAutoCreate::slot_btnConfirmCreate() +{ + int count = ui->spinBox_num->value(); + int lineSpace = ui->spinBox_index->value(); + int checkId = m_pGroupRadio->checkedId(); + QList> allData; + getAllSelectPointInfo(allData); + if( m_pCurrentObj && count > 0 ) + { + CShape * tmp = m_pCurrentObj->clone(RW_PART_SHAPE | RW_PART_LINK); + emit signal_createBatchObj(tmp , allData ,count , checkId ,lineSpace); + } +} + +void CAutoCreate::slot_currentLocationChanged(const QString &text) +{ + Q_UNUSED(text); + slot_currentProfessionChanged(text); +} + +void CAutoCreate::slot_currentDevGroupChanged(const QString &text) +{ + Q_UNUSED(text) + m_devGroupModel->clear(); + + QString dev_grp = ui->DeviceGroupComboBox->currentData().toString(); + QString professionDescription = ui->Profession->currentText(); + QString locationDescription = ui->Location->currentText(); + if( dev_grp.isEmpty() || professionDescription.isEmpty() || locationDescription.isEmpty()) + { + updatePointList(); + return; + } + dev_grp = dev_grp.replace("'", "''"); + professionDescription = professionDescription.replace("'", "''"); + locationDescription = locationDescription.replace("'", "''"); + + if(m_pReadDb->isOpen()) + { + QSqlQuery query; + QString queryStr = QString( + "SELECT description, tag_name, dev_type " + "FROM dev_info " + "WHERE sub_system = (" + "SELECT sub_system_id " + "FROM sys_model_sub_system_info " + "WHERE description = '%1' " + "AND sub_system_id > %2" + ") " + "AND location_id = (" + "SELECT location_id " + "FROM sys_model_location_info " + "WHERE description = '%3'" + ") " + "AND group_tag_name = '%4'" + ).arg(professionDescription).arg(CN_AppId_COMAPP).arg(locationDescription).arg(dev_grp); + + if( m_pReadDb->execute(queryStr, query) ) + { + if(query.isActive()) + { + while(query.next()) + { + QStandardItem *item = new QStandardItem(); + item->setText(query.value(0).toString()); + item->setData(query.value(1).toString() + "," + query.value(2).toString()); + m_devGroupModel->appendRow(item); + } + } + + }else + { + LOGERROR("AutoCreate slot_currentDevGroupChanged sql failed! sqlstr: %s" , queryStr.toStdString().c_str()); + } + } + if( m_devGroupModel->index(0,0).isValid() ) + { + ui->Device_TableView->setCurrentIndex(m_devGroupModel->index(0,0)); + emit ui->Device_TableView->clicked(m_devGroupModel->index(0,0)); + } + updatePointList(); +} + +void CAutoCreate::slot_currentTypeChanged(const QString &text) +{ + Q_UNUSED(text) + updatePointList(); +} + +void CAutoCreate::slot_currentSelectDeviceChanged(const QModelIndex &index) +{ + Q_UNUSED(index) + //updateTableType(); + updatePointList(); +} + +void CAutoCreate::slot_devGroupFilter() +{ + QString filterName = ui->DeviceFilter->text(); + int nRowCount = m_devGroupModel->rowCount(); + for (int nIndex = 0; nIndex < nRowCount; nIndex++) + { + if (filterName.isEmpty() || m_devGroupModel->item(nIndex)->text().contains(filterName,Qt::CaseInsensitive)) + { + ui->Device_TableView->setRowHidden(nIndex,false); + } + else + { + ui->Device_TableView->setRowHidden(nIndex,true); + } + } +} + +void CAutoCreate::slot_devPointFilter() +{ + QString filterName = ui->DeviceFilter_point->text(); + int nRowCount = m_devPointModel->rowCount(); + for (int nIndex = 0; nIndex < nRowCount; nIndex++) + { + if (filterName.isEmpty() || m_devPointModel->item(nIndex , 0)->text().contains(filterName,Qt::CaseInsensitive)) + { + ui->TagNameView->setRowHidden(nIndex,false); + } + else + { + ui->TagNameView->setRowHidden(nIndex,true); + } + } +} + +void CAutoCreate::slot_tagNameListViewDoubleClicked(const QModelIndex &index) +{ + if( index.isValid() ) + { + QStandardItem *item1 = m_devPointModel->itemFromIndex(m_devPointModel->index(index.row(), 0)); + QStandardItem *item2 = m_devPointModel->itemFromIndex(m_devPointModel->index(index.row(), 1)); + + if (item1 && item2) + { + QList newRow; + + QStandardItem *tmp = new QStandardItem(item1->text()); + QStandardItem *tmp2 = new QStandardItem(item2->text()+ QString(".value")); + tmp->setFlags(tmp->flags() | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled); + tmp2->setFlags(tmp2->flags() | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled); + newRow.append(tmp); + newRow.append(tmp2); + m_devPointSelModel->appendRow(newRow); + } + } +} + +void CAutoCreate::slot_selectListViewDoubleClicked(const QModelIndex &index) +{ + if (index.isValid()) + { + QStandardItem *item = m_devPointSelModel->itemFromIndex(index); + if (item) { + m_devPointSelModel->removeRow(item->row()); + } + } +} + +void CAutoCreate::slot_deleSelectBtnClicked() +{ + QItemSelectionModel *selectionModel = ui->select_listView->selectionModel(); + QModelIndexList list = selectionModel->selectedIndexes(); + for( const QModelIndex &index : list) + { + if( index.isValid() ) + { + m_devPointSelModel->removeRow(index.row()); + } + } + slot_updateLabel(); +} + +void CAutoCreate::slot_deleAllBtnClicked() +{ + m_devPointSelModel->clear(); + slot_updateLabel(); +} + +void CAutoCreate::slot_addAllBtnClicked() +{ + int rowCount = m_devPointModel->rowCount(); + for (int row = 0; row < rowCount; ++row) { + QStandardItem *item = m_devPointModel->item(row , 0); + QStandardItem *item2 = m_devPointModel->item(row , 1); + if (item && item2) { + QList newRow; + + newRow.append(new QStandardItem(item->text())); + newRow.append(new QStandardItem(item2->text()+ QString(".value"))); + m_devPointSelModel->appendRow(newRow); + } + } +} + +void CAutoCreate::slot_addSelectBtnClicked() +{ + QItemSelectionModel *tmp = ui->TagNameView->selectionModel(); + QModelIndexList list = tmp->selectedIndexes(); + for( const QModelIndex &index : list) + { + slot_tagNameListViewDoubleClicked(index); + } +} + +void CAutoCreate::slot_updateLabel() +{ + ui->label_selectCount->setText(QString::number(m_devPointSelModel->rowCount())); + ui->spinBox_num->setValue(m_devPointSelModel->rowCount()); +} + +void CAutoCreate::constructLink(CGroupShape *obj, QVector &subIdx) +{ + if(!obj) return; + + qDebug() << "subIdx:" << subIdx; + + QList *sublist = obj->getMergeListPtr(); + if(sublist) + { + CShape *tmp = NULL; + QList::iterator it = sublist->begin(); + for(; it != sublist->end(); it++) + { + tmp = (*it); + qDebug() << "tmp:" << tmp->getObjId(); + if(tmp->getObjType() == OBJTYPE_RELATIVE) + { + CLinkLine *link = dynamic_cast(tmp); + CShape *startDev = NULL; + CShape *endDev = NULL; + + qDebug() << "link:" << link->getStartDevId(); + + if(link->getStartDevId() > 0 && link->getEndDevId() > 0) + { + int idxs = subIdx.indexOf(link->getStartDevId()); + int idxe = subIdx.indexOf(link->getEndDevId()); + + qDebug() << idxs << " " << idxe; + if(idxs != idxe && idxs >= 0 && idxe >= 0) + { + startDev = sublist->at(idxs); + endDev = sublist->at(idxe); + } + } + + if(startDev && endDev) + { + link->initLink(startDev, endDev, link->getStartDevPin(), link->getEndDevPin()); + link->adjust(true); + link->setFlag(QGraphicsItem::ItemIsMovable, false); + } + } + } + } +} + + +CShape* CAutoCreate::shapeTwin(CShape *obj) +{ + if(!obj) return NULL; + + CGStream bofs; + bofs.Init(CGStream::buffer); + obj->copyToClipboard(bofs); + bofs.GoStart(); + + CShape *twin = NULL; + QList retlist; + CDrawObjFactory *fac; + getDrawObjFactory(&fac); + fac->createDrawObj(obj->getObjType(), &twin); +// twin->setScene(this); +// twin->setParentWidget((QWidget *)views().front()->viewport(), getEnvTypeFlag()); + twin->pasteFromClipboard(bofs, &retlist, RW_PART_SHAPE | RW_PART_LINK); + twin = retlist.first(); + fac->release(); + return twin; +} + +void CAutoCreate::slot_updataProPerty(const DrawObjDatabaseRecord *record) +{ + std::list< std::pair > propertylist; + std::list< std::pair >::iterator iter; + QMap propertymap; + QString propertyname; + QVariant propertyvalue; + QString splitname; + QMap > myproperty; + QMap propertyOrderMap; + + if( NULL == record) + { + return; + } + + if( m_pCurrentObj ) + { + delete m_pCurrentObj; + } + m_pCurrentObj = NULL; + + int objType = record->toolType; + QString typeN = record->typeSub; + QString mark = record->mark; + QString strategy = record->strategy; + QString name = record->name; + //创建一个临时图元 + CDrawObjFactory *fac; + getDrawObjFactory(&fac); + fac->createDrawObj(objType, &m_pCurrentObj, typeN); + fac->release(); + + if(NULL == m_pCurrentObj) + { + return; + } + + if (objType == OBJTYPE_ICON + 20 && !name.isEmpty()) + { + (dynamic_cast(m_pCurrentObj))->setIconInfo(objType - 100, name); + } + else if (objType == OBJTYPE_ICON + 25 && !name.isEmpty()) + { + CIconInfo * iconInfo = IconInfoControlInstance()->getIconInfoPtr(objType - 100, name); + if (iconInfo == NULL) + { + iconInfo = IconInfoControlInstance()->getUnknowIconInfoPtr(); + } + QList *objlist = iconInfo->getObjListPtr(); + if(!objlist->isEmpty()) + { + delete m_pCurrentObj; + m_pCurrentObj = NULL; + + QVector subIdx; + CShape *tmp = objlist->first(); + if(tmp->getObjType() != OBJTYPE_MERGE) + { + return; + } + foreach (CShape *obj, dynamic_cast(tmp)->m_mergeList) + { + subIdx.push_back(obj->getObjId()); + } + + constructLink(dynamic_cast(tmp), subIdx); + + m_pCurrentObj = shapeTwin(tmp); + }else if (objType == OBJTYPE_ELF && !name.isEmpty() && name != "精灵图元") + { + CNewElfShape * tmp = dynamic_cast(m_pCurrentObj); + tmp->setIconInfo(name, false); + } + } + + m_pCurrentObj->m_dyStrategy = strategy; + m_pCurrentObj->m_mark = mark; + //获取属性 + m_pCurrentObj->getPropertyList(propertylist); + m_pCurrentObj->getObjName(splitname); + if(m_pCurrentObj->IsIconObj()) + { + splitname = s_iconTransMap[splitname]; + } + + QStringList propertyOrder; + for (iter = propertylist.begin(); iter != propertylist.end(); iter ++) + { + propertyname = (*iter).first; + propertyvalue = (*iter).second; + //跳过对象名称和位置 + if( propertyname == tr("对象名称") || propertyname == tr("位置")) + { + continue; + } + propertyOrder.append(propertyname); + propertymap.insert(propertyname, propertyvalue); + } + + propertyOrderMap.insert(splitname, propertyOrder); + myproperty.insert(splitname, propertymap); + m_pPropertyBox->CreatePropertySheet(propertyOrderMap, myproperty); +} + +void CAutoCreate::slot_currentProfessionChanged(const QString &text) +{ + Q_UNUSED(text); + ui->DeviceGroupComboBox->clear(); + + QString professionDescription = ui->Profession->currentText(); + QString locationDescription = ui->Location->currentText(); + professionDescription = professionDescription.replace("'", "''"); + locationDescription = locationDescription.replace("'", "''"); + + if(m_pReadDb->isOpen()) + { + QSqlQuery query; + //查询该专业、车站下所有设备组 + QString queryStr = QString( + "SELECT description, tag_name " + "FROM dev_group " + "WHERE sub_system = (" + "SELECT sub_system_id " + "FROM sys_model_sub_system_info " + "WHERE description = '%1' " + "AND sub_system_id > %2" + ") " + "AND location_id = (" + "SELECT location_id " + "FROM sys_model_location_info " + "WHERE description = '%3'" + ") " + "ORDER BY dev_group_no ASC" + ).arg(professionDescription).arg(CN_AppId_COMAPP).arg(locationDescription); + if( m_pReadDb->execute(queryStr, query) ) + { + if(query.isActive()) + { + while(query.next()) + { + ui->DeviceGroupComboBox->addItem(query.value(0).toString(), query.value(1).toString()); + } + } + }else + { + LOGERROR("AutoCreate: slot_currentProfessionChanged sql failed! sqlStr: %s" , queryStr.toStdString().c_str()); + } + + } + if( ui->DeviceGroupComboBox->count() > 0 ) + { + ui->DeviceGroupComboBox->setCurrentIndex(0); + }else + { + ui->DeviceGroupComboBox->setCurrentIndex(-1); + } +} diff --git a/platform/src/gui/GraphTool/AutoCreateElement/CAutoCreate.h b/platform/src/gui/GraphTool/AutoCreateElement/CAutoCreate.h new file mode 100644 index 00000000..660dea3b --- /dev/null +++ b/platform/src/gui/GraphTool/AutoCreateElement/CAutoCreate.h @@ -0,0 +1,86 @@ +#ifndef CAUTOCREATE_H +#define CAUTOCREATE_H + +#include "db_api_ex/CDbApi.h" +#include "AutoCreateExport.h" +#include "pub_widget/CustomDialog.h" +#include "../../include/propertyeditor.h" +#include "../ToolBoxTree/CBoxTreeWidget.h" +#include "../ToolBoxTree/CDrawObjDatabase.h" +#include "../../include/CShape.h" +#include "../GraphShape/include/CGroupShape.h" +#include "CAutoListModel.h" + + +#include +#include + +namespace Ui { +class CAutoCreate; +} + +using namespace iot_dbms; + +class DLL_CLASS_AUTOCREATE CAutoCreate : public CustomUiDialog +{ + Q_OBJECT +public: + explicit CAutoCreate(QWidget *parent = 0, Qt::WindowFlags f = Qt::WindowFlags()); + ~CAutoCreate(); + +private: + void initial(); //初始化 + void initDBConnect(); //初始化数据库连接 + void initUi(); //界面初始化 + void initConn(); //连接初始化 + void initVar(); //变量初始化 + void loadSheet(); + + void updatePointList(); //更新点位数据 + void loadToolBox(); //加载图元 + void loadIconTrans(); //加载翻译 + void getAllSelectPointInfo(QList> &listInfo); //获取选中的点位信息 + void constructLink(CGroupShape *obj, QVector &subIdx); + CShape *shapeTwin(CShape *obj); + +private slots: + void slot_currentProfessionChanged(const QString &text); + void slot_currentLocationChanged(const QString &text); + void slot_currentDevGroupChanged(const QString &text); + void slot_currentTypeChanged(const QString &text); + void slot_currentSelectDeviceChanged(const QModelIndex &index); + void slot_devGroupFilter(); + void slot_devPointFilter(); + void slot_tagNameListViewDoubleClicked(const QModelIndex &index); + void slot_selectListViewDoubleClicked(const QModelIndex &index); + void slot_deleSelectBtnClicked(); + void slot_deleAllBtnClicked(); + void slot_addAllBtnClicked(); + void slot_addSelectBtnClicked(); + void slot_updateLabel(); + void slot_updataProPerty(const DrawObjDatabaseRecord *record); + + void updateCurrentProperty(const QString &name, const QVariant &value, bool sub); + + void slot_btnConfirmCreate(); + +signals: + void signal_createBatchObj(CShape *obj , QList> listInfo, int count , int rowOrCol , int lineSpace); + +private: + Ui::CAutoCreate *ui; + CDbApi * m_pReadDb; + QStandardItemModel *m_devGroupModel; + QStandardItemModel *m_devPointModel; + CAutoListModel *m_devPointSelModel; + PropertyEditor *m_pPropertyBox; + CBoxTreeWidget *m_pToolBox; + DrawObjDatabaseRecord *m_pSelectRecord; //当前所选择的图元 + QButtonGroup *m_pGroupRadio; + +public: + QMap s_iconTransMap; + CShape *m_pCurrentObj; //当前选中的对象 +}; + +#endif // CAUTOCREATE_H diff --git a/platform/src/gui/GraphTool/AutoCreateElement/CAutoCreate.ui b/platform/src/gui/GraphTool/AutoCreateElement/CAutoCreate.ui new file mode 100644 index 00000000..0d7233c9 --- /dev/null +++ b/platform/src/gui/GraphTool/AutoCreateElement/CAutoCreate.ui @@ -0,0 +1,686 @@ + + + CAutoCreate + + + + 0 + 0 + 950 + 733 + + + + Form + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 75 + 0 + + + + 确定 + + + + + + + + 0 + 0 + + + + + 75 + 0 + + + + 取消 + + + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 1 + + + + + + + + Qt::Horizontal + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + 10 + + + + + + + 数量: + + + + + + + 按列排 + + + + + + + 按行排 + + + + + + + 行列距: + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 0 + 5 + + + + + + + + + + + + + + + + + + 0 + 0 + + + + + 520 + 640 + + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + + + + 0 + 0 + + + + + 500 + 330 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 3 + + + 6 + + + 3 + + + 6 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 点类型: + + + + + + + QComboBox QAbstractItemView::item{min-height: 23px;} + + + + + + + + 160 + 16777215 + + + + + + + + + + 0 + + + + + + + + + + + + QFrame::Raised + + + QAbstractItemView::NoEditTriggers + + + + + + + Qt::Horizontal + + + + + + + + + + + + 添加全部 + + + + + + + 添加 + + + + + + + 删除 + + + + + + + 删除全部 + + + + + + + + + + + + + + + + 0 + 50 + + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::Sunken + + + 1 + + + Qt::Horizontal + + + + + + + 3 + + + 6 + + + 3 + + + 6 + + + 2 + + + 4 + + + + + 设备组: + + + + + + + + 160 + 16777215 + + + + + + + + + + 0 + + + + + + + + + + + + + + + QFrame::Raised + + + QAbstractItemView::NoEditTriggers + + + + + + + + + + + 0 + 60 + + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + 6 + + + 3 + + + 6 + + + 3 + + + 4 + + + + + + 0 + 0 + + + + + 0 + 25 + + + + QComboBox QAbstractItemView::item{min-height: 23px;} + + + QComboBox::AdjustToMinimumContentsLength + + + 12 + + + + + + + + 0 + 0 + + + + + 100 + 25 + + + + QComboBox QAbstractItemView::item{min-height: 23px;} + + + QComboBox::AdjustToMinimumContentsLength + + + 12 + + + + + + + 位置: + + + + + + + 专业: + + + + + + + + + + + + 已选择测点数: + + + + + + + 0 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Horizontal + + + + + + + + + + + PropertyEditor + QWidget +
../../include/propertyeditor.h
+ 1 +
+ + CBoxTreeWidget + QTreeWidget +
../ToolBoxTree/CBoxTreeWidget.h
+
+
+ + +
diff --git a/platform/src/gui/GraphTool/AutoCreateElement/CAutoListModel.h b/platform/src/gui/GraphTool/AutoCreateElement/CAutoListModel.h new file mode 100644 index 00000000..50aa4962 --- /dev/null +++ b/platform/src/gui/GraphTool/AutoCreateElement/CAutoListModel.h @@ -0,0 +1,68 @@ +#ifndef CAUTOLISTMODEL_H +#define CAUTOLISTMODEL_H + +#include +#include "AutoCreateExport.h" +#include +#include +#include + +class DLL_CLASS_AUTOCREATE CAutoListModel: public QStandardItemModel +{ + Q_OBJECT + +public: + using QStandardItemModel::QStandardItemModel; + + Qt::DropActions supportedDropActions() const override { + return Qt::MoveAction; + } + + bool dropMimeData(const QMimeData *data, Qt::DropAction action, + int row, int column, const QModelIndex &parent) override { + + Q_UNUSED(column) + if (action == Qt::IgnoreAction) + return true; + + row = parent.row(); + + if (!data->hasFormat("application/x-qabstractitemmodeldatalist")) + return false; + + + QByteArray encoded = data->data("application/x-qabstractitemmodeldatalist"); + QDataStream stream(&encoded, QIODevice::ReadOnly); + int sourceRow = -1; + while (!stream.atEnd()) { + int r, c; + QMap roles; + stream >> r >> c >> roles; + if (sourceRow == -1) + sourceRow = r; + } + + if (row == -1) + row = rowCount(); + + if (sourceRow == row) + return false; + + + if (sourceRow >= 0 && sourceRow < rowCount()) { + QList items = takeRow(sourceRow); + if( row >= rowCount()) + { + appendRow(items); + }else + { + insertRow(row, items); + } + return true; + } + + return false; + } +}; + +#endif // CAUTOLISTMODEL_H diff --git a/platform/src/gui/GraphTool/AutoCreateElement/CAutoListView.cpp b/platform/src/gui/GraphTool/AutoCreateElement/CAutoListView.cpp new file mode 100644 index 00000000..651787c6 --- /dev/null +++ b/platform/src/gui/GraphTool/AutoCreateElement/CAutoListView.cpp @@ -0,0 +1,181 @@ +#include "CAutoListView.h" + +#include +#include +CAutoListView::CAutoListView(QWidget *parent) + :QListView(parent) +{ +// setSelectionMode(QAbstractItemView::ExtendedSelection); +// setDragEnabled(true); +// setAcceptDrops(true); +// setDropIndicatorShown(true); +// setDefaultDropAction(Qt::MoveAction); +} + +void CAutoListView::mousePressEvent(QMouseEvent *event) +{ + if(event->buttons() & Qt::LeftButton){ + startPos = event->pos(); + } + QListView::mousePressEvent(event); +} + +void CAutoListView::mouseReleaseEvent(QMouseEvent *event) +{ + QListView::mouseReleaseEvent(event); + if((event->pos() - startPos).manhattanLength() > 5) return; + + QModelIndex index = indexAt(event->pos()); + setCurrentIndex(index); //鼠标relesse时才选中 +} + +void CAutoListView::mouseMoveEvent(QMouseEvent *event) +{ + QListView::mouseMoveEvent(event); + if(event->buttons() & Qt::LeftButton){ + if((event->pos() - startPos).manhattanLength() < QApplication::startDragDistance()) return; + + QModelIndex theDragIndex = indexAt(startPos); + theDragRow = theDragIndex.row(); + + setCurrentIndex(theDragIndex); //拖拽即选中 + + QStandardItemModel *listModel = qobject_cast(model()); + QStandardItem *theDragItem = static_cast(listModel->item(theDragRow)); + +//[1]把拖拽数据放在QMimeData容器中 + QString text = theDragItem->text(); + QByteArray itemData; + QDataStream dataStream(&itemData, QIODevice::WriteOnly); + dataStream << text; + + QMimeData *mimeData = new QMimeData; + mimeData->setData(myMimeType(), itemData); +//[1] + + // 创建 QDrag 对象并设置拖拽数据和预览图 + QPixmap pixmap = QPixmap(100, 50); // 创建一个固定大小的预览图 + pixmap.fill(Qt::transparent); // 透明背景 + QPainter painter(&pixmap); + painter.setPen(Qt::black); + painter.setFont(QFont("Arial", 10)); + painter.drawText(pixmap.rect(), Qt::AlignCenter, text); // 在图像上绘制文本 + + QDrag *drag = new QDrag(this); + drag->setMimeData(mimeData); + drag->setPixmap(pixmap); + drag->setHotSpot(QPoint(pixmap.width() / 2, pixmap.height() / 2)); // 设置热点位置为图像中心 + + //删除的行需要根据theInsertRow和theDragRow的大小关系来判断(这个也是我根据实际情况测试发现的) + if(drag->exec(Qt::MoveAction) == Qt::MoveAction){ + int theRemoveRow = -1; + if(theInsertRow < theDragRow) theRemoveRow = theDragRow + 1; + else theRemoveRow = theDragRow; + model()->removeRow(theRemoveRow); + } + } +} + +void CAutoListView::dragEnterEvent(QDragEnterEvent *event) +{ + CAutoListView *source = qobject_cast(event->source()); + if (source && source == this) { + //IsDraging(标志位)判断是否正在拖拽 + IsDraging = true; + event->setDropAction(Qt::MoveAction); + event->accept(); + } +} + +void CAutoListView::dragLeaveEvent(QDragLeaveEvent *event) +{ + oldHighlightedRow = theHighlightedRow; + theHighlightedRow = -2; + + //之前QListWidget用的是update(QRect),这里用的是update(QModelIndex),当然这里也可以使用update(QRect),只是想换一种方法而已 + update(model()->index(oldHighlightedRow, 0)); //UpRow + update(model()->index(oldHighlightedRow + 1, 0)); //DownRow + + IsDraging = false; //IsDraging(标志位)判断是否正在拖拽 + + theInsertRow = -1; + event->accept(); +} + +void CAutoListView::dragMoveEvent(QDragMoveEvent *event) +{ + CAutoListView *source = qobject_cast(event->source()); + if (source && source == this) { + + oldHighlightedRow = theHighlightedRow; + theHighlightedRow = indexAt(event->pos() - QPoint(0, offset())).row(); + + //offset() = 19 = 40 / 2 - 1,其中40是行高 + if(event->pos().y() >= offset()){ + + if(oldHighlightedRow != theHighlightedRow){ + //刷新旧区域使dropIndicator消失 + update(model()->index(oldHighlightedRow, 0)); + update(model()->index(oldHighlightedRow + 1, 0)); + + //刷新新区域使dropIndicator显示 + update(model()->index(theHighlightedRow, 0)); + update(model()->index(theHighlightedRow + 1, 0)); + }else{ + update(model()->index(theHighlightedRow, 0)); + update(model()->index(theHighlightedRow + 1, 0)); + } + + theInsertRow = theHighlightedRow + 1; + }else{ + theHighlightedRow = -1; + update(model()->index(0, 0)); + update(model()->index(1, 0)); + theInsertRow = 0; + } + + event->setDropAction(Qt::MoveAction); + event->accept(); + } +} + +void CAutoListView::dropEvent(QDropEvent *event) +{ + CAutoListView *source = qobject_cast(event->source()); + if (source && source == this){ + + IsDraging = false; //IsDraging(标志位)判断是否正在拖拽 + + oldHighlightedRow = theHighlightedRow; + theHighlightedRow = -2; + + //刷新旧区域使dropIndicator消失 + update(model()->index(oldHighlightedRow, 0)); + update(model()->index(oldHighlightedRow + 1, 0)); + + + if(theInsertRow == theDragRow || theInsertRow == theDragRow + 1) return; + + //这里我像QListWidget那样调用父类dropEvent(event)发现不起作用(原因尚不明),没办法,只能删除旧行,插入新行 + //if(theSelectedRow == theDragRow){ + //QListView::dropEvent(event); + //return; + //} + + QString text; + QIcon icon, icon_hover; + QByteArray itemData = event->mimeData()->data(myMimeType()); + QDataStream dataStream(&itemData, QIODevice::ReadOnly); + dataStream >> text; + + model()->insertRow(theInsertRow); + + QStandardItemModel *listModel = qobject_cast(model()); + listModel->setItem(theInsertRow, 0, new QStandardItem(text)); + + setCurrentIndex(model()->index(theInsertRow, 0)); //插入行保持选中状态 + + event->setDropAction(Qt::MoveAction); + event->accept(); + } +} diff --git a/platform/src/gui/GraphTool/AutoCreateElement/CAutoListView.h b/platform/src/gui/GraphTool/AutoCreateElement/CAutoListView.h new file mode 100644 index 00000000..b53cd7bf --- /dev/null +++ b/platform/src/gui/GraphTool/AutoCreateElement/CAutoListView.h @@ -0,0 +1,93 @@ +#ifndef CAUTOLISTVIEW_H +#define CAUTOLISTVIEW_H + +#include +#include +#include "Export.h" +#include "CAutoCreate.h" + +class DLL_CLASS CAutoListView : public QListView +{ + Q_OBJECT +public: + CAutoListView(QWidget *parent = Q_NULLPTR); + bool isDraging() const {return IsDraging;} + int offset() const {return 19;} + int highlightedRow() const {return theHighlightedRow;} + int dragRow() const {return theDragRow;} + static QString myMimeType() { return QStringLiteral("TestListView/text-icon-icon_hover"); } + + protected: + void mousePressEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void dragEnterEvent(QDragEnterEvent *event) override; + void dragLeaveEvent(QDragLeaveEvent *event) override; + void dragMoveEvent(QDragMoveEvent *event) override; + void dropEvent(QDropEvent *event) override; +//protected: +// void dragEnterEvent(QDragEnterEvent *event) override { +// CAutoListView *source = qobject_cast(event->source()); +// if (source && source == this) { +// //IsDraging(标志位)判断是否正在拖拽 +// //IsDraging = true; +// event->setDropAction(Qt::MoveAction); +// event->accept(); +// } +// } + +// void dragMoveEvent(QDragMoveEvent *event) override { +// event->setDropAction(Qt::MoveAction); +// event->accept(); + +// } + +// void dropEvent(QDropEvent *event) override { +// CAutoListView *source = qobject_cast(event->source()); +// if (source && source == this) { +// // 设置拖放操作类型 +// event->setDropAction(Qt::MoveAction); + +// // 调用父类的 dropEvent 处理 +// QListView::dropEvent(event); + +// // 获取当前模型 +// QAbstractItemModel *model = this->model(); + +// // 获取拖动到的索引 +// QModelIndex dropIndex = indexAt(event->pos()); +// if (!dropIndex.isValid()) return; + +// // 获取所选项索引 +// QModelIndexList selectedIndexes = selectionModel()->selectedIndexes(); +// if (selectedIndexes.isEmpty()) return; + +// // 排序索引列表,确保从上到下的顺序 +// std::sort(selectedIndexes.begin(), selectedIndexes.end(), [](const QModelIndex &a, const QModelIndex &b) { +// return a.row() < b.row(); +// }); + +// // 遍历所选项,逐个删除它们 +// for (const QModelIndex &index : selectedIndexes) { +// model->removeRow(index.row()); +// } + +// // 将删除的项插入到目标位置 +// for (const QModelIndex &index : selectedIndexes) { +// // 插入项,插入的位置为拖动的目标索引 +// model->insertRow(dropIndex.row()); +// model->setData(model->index(dropIndex.row(), 0), model->data(index)); +// } +// } +// } + + private: + QPoint startPos; + bool IsDraging = false; + int theHighlightedRow = -2; + int oldHighlightedRow = -2; + int theDragRow = -1; + int theInsertRow = -1; +}; + +#endif // CAUTOLISTVIEW_H diff --git a/platform/src/gui/GraphTool/QssEditor/icos/Thumbs.db b/platform/src/gui/GraphTool/QssEditor/icos/Thumbs.db new file mode 100644 index 00000000..c83c82e8 Binary files /dev/null and b/platform/src/gui/GraphTool/QssEditor/icos/Thumbs.db differ diff --git a/platform/src/gui/GraphTool/ToolBoxTree/CBoxDelegate.cpp b/platform/src/gui/GraphTool/ToolBoxTree/CBoxDelegate.cpp new file mode 100644 index 00000000..7f3b6e69 --- /dev/null +++ b/platform/src/gui/GraphTool/ToolBoxTree/CBoxDelegate.cpp @@ -0,0 +1,76 @@ +#include "CBoxDelegate.h" +#include "CBoxListView.h" +#include "CBoxTreeWidget.h" + +CListDelegate::CListDelegate(QObject *parent) + : m_pView(dynamic_cast(parent)) +{ + +} + +QSize CListDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + if(m_pView) + { + if(m_pView->model()->data(index, Qt::DisplayRole) != QVariant()) + { + return QSize(m_pView->getMaxTextWidth(), QStyledItemDelegate::sizeHint(option, index).height()); + } + } + return QStyledItemDelegate::sizeHint(option, index); +} + +CTreeDelegate::CTreeDelegate(QObject *parent) + : m_pView(dynamic_cast(parent)) +{ + +} + +void CTreeDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + QStyledItemDelegate::paint(painter, option, index); + bool bExpanded = m_pView->isExpanded(index); + bExpanded ? drawRightArrow(painter, option) : drawDownArrow(painter, option); +} + +void CTreeDelegate::drawDownArrow(QPainter *painter, const QStyleOptionViewItem &option) const +{ + painter->save(); + + QPen pen; + pen.setColor(QColor(0,0,0)); + pen.setWidthF(1.5); + painter->setPen(pen); + + QStyleOptionViewItem viewOption(option); + qreal x = viewOption.rect.left() + viewOption.rect.width() - 15; + qreal y = viewOption.rect.top() + viewOption.rect.height() / 2 + 2; + QPointF p1(x - 5, y - 5); + QPointF p2(x, y); + QPointF p3(x + 5, y - 5); + + painter->drawLine(p1, p2); + painter->drawLine(p2, p3); + painter->restore(); +} + +void CTreeDelegate::drawRightArrow(QPainter *painter, const QStyleOptionViewItem &option) const +{ + painter->save(); + + QPen pen; + pen.setColor(QColor(0,0,0)); + pen.setWidthF(1.5); + painter->setPen(pen); + + QStyleOptionViewItem viewOption(option); + qreal x = viewOption.rect.left() + viewOption.rect.width() - 10; + qreal y = viewOption.rect.top() + viewOption.rect.height() / 2; + QPointF p1(x - 5, y - 5); + QPointF p2(x, y); + QPointF p3(x - 5, y + 5); + + painter->drawLine(p1, p2); + painter->drawLine(p2, p3); + painter->restore(); +} diff --git a/platform/src/gui/GraphTool/ToolBoxTree/CBoxDelegate.h b/platform/src/gui/GraphTool/ToolBoxTree/CBoxDelegate.h new file mode 100644 index 00000000..9037af35 --- /dev/null +++ b/platform/src/gui/GraphTool/ToolBoxTree/CBoxDelegate.h @@ -0,0 +1,38 @@ +#ifndef CBOXDELEGATE_H +#define CBOXDELEGATE_H + +#include +#include "Export.h" + +class CBoxListView; +class DLL_CLASS CListDelegate : public QStyledItemDelegate +{ +public: + CListDelegate(QObject *parent = Q_NULLPTR); + + QSize sizeHint(const QStyleOptionViewItem &option, + const QModelIndex &index) const override; + +private: + CBoxListView * m_pView; +}; + +class QTreeWidget; +class CTreeDelegate : public QStyledItemDelegate +{ +public: + CTreeDelegate(QObject *parent = Q_NULLPTR); + + void paint(QPainter *painter, + const QStyleOptionViewItem &option, const QModelIndex &index) const override; + + void drawDownArrow(QPainter *painter, + const QStyleOptionViewItem &option) const; + void drawRightArrow(QPainter *painter, + const QStyleOptionViewItem &option) const; + +private: + QTreeWidget * m_pView; +}; + +#endif // CBOXDELEGATE_H diff --git a/platform/src/gui/GraphTool/ToolBoxTree/CBoxListModel.cpp b/platform/src/gui/GraphTool/ToolBoxTree/CBoxListModel.cpp new file mode 100644 index 00000000..d2ade8cb --- /dev/null +++ b/platform/src/gui/GraphTool/ToolBoxTree/CBoxListModel.cpp @@ -0,0 +1,102 @@ +#include "CBoxListModel.h" + +CBoxListModel::CBoxListModel(QObject *parent) + : QAbstractListModel(parent) +{ + +} + +CBoxListModel::~CBoxListModel() +{ + m_items.clear(); +} + +bool CBoxListModel::isExist(const QString &name) +{ + for(int nIndex(0); nIndex < m_items.size(); ++nIndex) + { + if(m_items[nIndex]->name == name) + { + return true; + } + } + return false; +} + +DrawObjDatabaseRecord *CBoxListModel::record(const QModelIndex &index) const +{ + const int row = index.row(); + if (row < 0 || row >= m_items.size()) + return Q_NULLPTR; + + return m_items.at(row); +} + +QVariant CBoxListModel::data(const QModelIndex &index, int role) const +{ + const int row = index.row(); + if (row < 0 || row >= m_items.size()) + return QVariant(); + + const DrawObjDatabaseRecord *item = m_items.at(row); + switch (role) { + case Qt::DisplayRole: + { + if(item->icon && !item->icon->isNull()) + { + return QVariant(); + } + return QVariant(item->name); + } + case Qt::DecorationRole: + return QVariant(*(item->icon)); + case Qt::WhatsThisRole: + return QVariant(item->toolType); + case Qt::ToolTipRole: + return QVariant(item->name); + case Qt::UserRole: + return QVariant(item->typeSub); + case Qt::UserRole + 1: + return QVariant(item->mark); + case Qt::UserRole + 2: + return QVariant(item->strategy); + case Qt::UserRole + 3: + return QVariant(item->name); + } + return QVariant(); +} + +int CBoxListModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + return m_items.size(); +} + +Qt::ItemFlags CBoxListModel::flags(const QModelIndex &index) const +{ + Q_UNUSED(index) + return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled; +} + +bool CBoxListModel::removeRows(int row, int count, const QModelIndex &parent) +{ + if (row < 0 || count < 1) + return false; + const int size = m_items.size(); + const int last = row + count - 1; + if (row >= size || last >= size) + return false; + beginRemoveRows(parent, row, last); + for (int r = last; r >= row; r--) + m_items.removeAt(r); + endRemoveRows(); + return true; +} + +void CBoxListModel::addWidget(DrawObjDatabaseRecord *record) +{ + const int row = m_items.size(); + beginInsertRows(QModelIndex(), row, row); + m_items.push_back(record); + endInsertRows(); +} diff --git a/platform/src/gui/GraphTool/ToolBoxTree/CBoxListModel.h b/platform/src/gui/GraphTool/ToolBoxTree/CBoxListModel.h new file mode 100644 index 00000000..f1e794e4 --- /dev/null +++ b/platform/src/gui/GraphTool/ToolBoxTree/CBoxListModel.h @@ -0,0 +1,28 @@ +#ifndef CBOXLISTMODEL_H +#define CBOXLISTMODEL_H + +#include "Export.h" +#include "QAbstractListModel" +#include "CDrawObjDatabase.h" + +class DLL_CLASS CBoxListModel : public QAbstractListModel +{ + Q_OBJECT +public: + CBoxListModel(QObject *parent = Q_NULLPTR); + ~CBoxListModel(); + + bool isExist(const QString &name); + DrawObjDatabaseRecord* record(const QModelIndex &index) const; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + Qt::ItemFlags flags (const QModelIndex & index ) const override; + bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override; + void addWidget(DrawObjDatabaseRecord *record); + +private: + QList m_items; +}; + +#endif // CBOXLISTMODEL_H diff --git a/platform/src/gui/GraphTool/ToolBoxTree/CBoxListView.cpp b/platform/src/gui/GraphTool/ToolBoxTree/CBoxListView.cpp new file mode 100644 index 00000000..80853dae --- /dev/null +++ b/platform/src/gui/GraphTool/ToolBoxTree/CBoxListView.cpp @@ -0,0 +1,122 @@ +#include "CBoxListView.h" +#include "CBoxListModel.h" +#include "CBoxDelegate.h" + +CBoxListView::CBoxListView(QWidget *parent) + : QListView(parent), + m_pModel(new CBoxListModel(this)), + m_nMaxTextWidth(0) +{ + setFocusPolicy(Qt::NoFocus); + setFrameShape(QFrame::NoFrame); + setIconSize(QSize(30, 30)); + setSpacing(1); + setTextElideMode(Qt::ElideMiddle); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setResizeMode(QListView::Adjust); + setDragEnabled(true); + setDragDropMode(QAbstractItemView::DragOnly); + QFont font = qApp->font(); + font.setPointSize(font.pointSize() + 1); + setFont(font); + //setUniformItemSizes(true); + setModel(m_pModel); + setItemDelegate(new CListDelegate(this)); + + connect(this, &CBoxListView::pressed, this, &CBoxListView::slotItemPressed); +} + +bool CBoxListView::isExist(const QString &name) +{ + return m_pModel->isExist(name); +} + +DrawObjDatabaseRecord *CBoxListView::selectedRecord() +{ + QModelIndex curIndex = currentIndex(); + if( !curIndex.isValid() ) + { + return NULL; + } + return m_pModel->record(curIndex); +} + +void CBoxListView::addWidget(DrawObjDatabaseRecord *record) +{ + if(record->icon && record->icon->isNull()){ + setMaxTextWidth(record->name); + } + m_pModel->addWidget(record); +} + +void CBoxListView::removeSelectedWidget() +{ + QModelIndex curIndex = currentIndex(); + if( !curIndex.isValid() ) + { + return; + } + m_pModel->removeRows(curIndex.row(), 1); +} + +int CBoxListView::getMaxTextWidth() +{ + return m_nMaxTextWidth; +} + +void CBoxListView::setMaxTextWidth(const QString &text) +{ + QFontMetrics font = this->fontMetrics(); + int width = font.boundingRect(text+"AA").width(); + if(width > m_nMaxTextWidth) + { + m_nMaxTextWidth = width; + } +} + +bool CBoxListView::filter(const QString &text) +{ + bool isHidden = true; + DrawObjDatabaseRecord * record; + for(int nIndex(0); nIndexrowCount(); ++nIndex) + { + record = m_pModel->record(m_pModel->index(nIndex, 0)); + if(text.isEmpty() || (record && record->name.contains(text))) + { + setRowHidden(nIndex, false); + isHidden = false; + } + else + { + setRowHidden(nIndex, true); + } + } + return isHidden; +} + +void CBoxListView::dragMoveEvent(QDragMoveEvent *e) +{ + e->setAccepted(false); +} + +void CBoxListView::startDrag(Qt::DropActions supportedActions) +{ + Q_UNUSED(supportedActions) + QDrag *drag = new QDrag(this); + QMimeData *mimeData = new QMimeData(); + mimeData->setText("toolBox"); + drag->setMimeData(mimeData); + drag->exec(Qt::CopyAction); +} + +void CBoxListView::slotItemPressed(const QModelIndex &index) +{ + emit itemSelected(); + CBoxListModel * model = dynamic_cast(this->model()); + DrawObjDatabaseRecord * record = model->record(index); + if(record) + { + emit itemPressed(record); + } +} diff --git a/platform/src/gui/GraphTool/ToolBoxTree/CBoxListView.h b/platform/src/gui/GraphTool/ToolBoxTree/CBoxListView.h new file mode 100644 index 00000000..c2168ade --- /dev/null +++ b/platform/src/gui/GraphTool/ToolBoxTree/CBoxListView.h @@ -0,0 +1,44 @@ +#ifndef CBOXLISTVIEW_H +#define CBOXLISTVIEW_H + + +#include "Export.h" +#include +#include "CDrawObjDatabase.h" + +class CBoxListModel; +class DLL_CLASS CBoxListView : public QListView +{ + Q_OBJECT +public: + CBoxListView(QWidget *parent = Q_NULLPTR); + + using QListView::contentsSize; + + bool isExist(const QString &name); + + DrawObjDatabaseRecord * selectedRecord(); + void addWidget(DrawObjDatabaseRecord *record); + void removeSelectedWidget(); + + int getMaxTextWidth(); + void setMaxTextWidth(const QString &text); + + bool filter(const QString &text); +signals: + void itemSelected(); + void itemPressed(const DrawObjDatabaseRecord *record); + +protected: + void dragMoveEvent(QDragMoveEvent *e); + void startDrag(Qt::DropActions supportedActions); + +private slots: + void slotItemPressed(const QModelIndex &index); + +private: + CBoxListModel * m_pModel; + int m_nMaxTextWidth; +}; + +#endif // CBOXLISTVIEW_H diff --git a/platform/src/gui/GraphTool/ToolBoxTree/CBoxTreeWidget.cpp b/platform/src/gui/GraphTool/ToolBoxTree/CBoxTreeWidget.cpp new file mode 100644 index 00000000..b3d238ff --- /dev/null +++ b/platform/src/gui/GraphTool/ToolBoxTree/CBoxTreeWidget.cpp @@ -0,0 +1,190 @@ +#include +#include +#include +#include +#include "CBoxTreeWidget.h" +#include "CBoxListView.h" +#include "CBoxDelegate.h" + +CBoxTreeWidget::CBoxTreeWidget(QWidget *parent) + : QTreeWidget(parent) +{ + setFocusPolicy(Qt::NoFocus); + setRootIsDecorated(false); + setIndentation(0); + setColumnCount(1); + setTextElideMode(Qt::ElideMiddle); + setVerticalScrollMode(QTreeView::ScrollPerPixel); + setStyleSheet("QTreeView::item{height:26px;}"); + QFont font = qApp->font(); + font.setPointSize(font.pointSize() + 1); + setFont(font); + QPalette palette = this->palette(); + palette.setColor(QPalette::Shadow, Qt::blue); + setIconSize(QSize(30, 30)); + setPalette(palette); + setAutoFillBackground(true); + + setItemDelegate(new CTreeDelegate(this)); + initHeaderView(); +} + +bool CBoxTreeWidget::isExist(const QString &name) +{ + for(int nIndex = 0; nIndex < topLevelItemCount(); ++nIndex) + { + QTreeWidgetItem * item = topLevelItem(nIndex); + if(item->childCount() <= 0) + { + continue; + } + CBoxListView *listView = static_cast(itemWidget(item->child(0), 0)); + if(listView == NULL) + { + continue; + } + if(listView->isExist(name)) + { + return true; + } + } + return false; +} + +QString CBoxTreeWidget::currentName() +{ + QTreeWidgetItem * item = currentItem(); + if(item) + { + CBoxListView *listWidget = static_cast(itemWidget(item, 0)); + if(listWidget) + { + return listWidget->model()->data(listWidget->currentIndex(), Qt::UserRole + 3).toString(); + } + else + { + return item->data(0, Qt::UserRole + 3).toString(); + } + } + return QString(); +} + +CBoxListView *CBoxTreeWidget::addListView(QTreeWidgetItem *parent, bool iconMode) +{ + QTreeWidgetItem *embed_item = new QTreeWidgetItem(parent); + CBoxListView *listView = new CBoxListView(this); + listView->setViewMode(iconMode ? QListView::IconMode : QListView::ListMode); + connect(listView, &CBoxListView::itemSelected, this, &CBoxTreeWidget::slotItemWidgetSelected); + setItemWidget(embed_item, 0, listView); + m_itemWidgetMap[listView] = embed_item; + return listView; +} + +CBoxListView *CBoxTreeWidget::getListView(QTreeWidgetItem *parent) +{ + if(parent == NULL) + { + return NULL; + } + QMap::const_iterator iter = m_itemWidgetMap.constBegin(); + for( ; iter != m_itemWidgetMap.constEnd(); ++iter) + { + if(iter.value() == parent) + { + return dynamic_cast(iter.key()); + } + } + return NULL; +} + +void CBoxTreeWidget::adjustSubListSize(QTreeWidgetItem *cat_item) +{ + QTreeWidgetItem *embedItem = cat_item->child(0); + if (embedItem == 0) + return; + + CBoxListView *listWidget = static_cast(itemWidget(embedItem, 0)); + listWidget->setFixedWidth(header()->width()); + listWidget->doItemsLayout(); + const int height = qMax(listWidget->contentsSize().height() ,1); + listWidget->setFixedHeight(height); + embedItem->setSizeHint(0, QSize(-1, height - 1)); +} + +void CBoxTreeWidget::resizeEvent(QResizeEvent *e) +{ + QTreeWidget::resizeEvent(e); + if (const int numTopLevels = topLevelItemCount()) { + for (int i = numTopLevels - 1; i >= 0; --i) + adjustSubListSize(topLevelItem(i)); + } +} + +void CBoxTreeWidget::mousePressEvent(QMouseEvent *event) +{ + if(event->button() == Qt::LeftButton) + { + QTreeWidgetItem * item = itemAt(event->pos()); + if(item){ + item->isExpanded() ? collapseItem(item) : expandItem(item); + } + } + return QTreeWidget::mousePressEvent(event); +} + +void CBoxTreeWidget::filter(const QString &text) +{ + for(int nIndex(0); nIndex < topLevelItemCount(); ++nIndex) + { + QTreeWidgetItem * top = topLevelItem(nIndex); + if(!top->child(0)) + { + top->setHidden(true); + continue; + } + CBoxListView *listWidget = static_cast(itemWidget(top->child(0), 0)); + if(listWidget) + { + top->setHidden(listWidget->filter(text)); + } + else + { + top->setHidden(true); + } + adjustSubListSize(top); + } + text.isEmpty() ? collapseAll() : expandAll(); +} + +void CBoxTreeWidget::slotItemWidgetSelected() +{ + QWidget * widget = dynamic_cast(sender()); + QMap::const_iterator iter = m_itemWidgetMap.find(widget); + if(iter != m_itemWidgetMap.constEnd()) + { + clearSelection(); + setCurrentItem(iter.value()); + iter.value()->parent()->setSelected(true); + } +} + +void CBoxTreeWidget::initHeaderView() +{ + QHBoxLayout * hLayout = new QHBoxLayout; + QLineEdit * edit = new QLineEdit(this); + edit->setFrame(false); + edit->setPlaceholderText(tr("搜索...")); + edit->setFixedHeight(21); + hLayout->setContentsMargins(3,0,0,0); + hLayout->addWidget(edit); + QVBoxLayout * vLayout = new QVBoxLayout; + vLayout->addLayout(hLayout); + QFrame * line = new QFrame(this); + line->setFrameShape(QFrame::HLine); + line->setFrameShadow(QFrame::Sunken); + vLayout->addWidget(line); + vLayout->setMargin(1); + vLayout->setSpacing(1); + header()->setLayout(vLayout); + connect(edit, SIGNAL(textChanged(QString)), this, SLOT(filter(QString))); +} diff --git a/platform/src/gui/GraphTool/ToolBoxTree/CBoxTreeWidget.h b/platform/src/gui/GraphTool/ToolBoxTree/CBoxTreeWidget.h new file mode 100644 index 00000000..54746e94 --- /dev/null +++ b/platform/src/gui/GraphTool/ToolBoxTree/CBoxTreeWidget.h @@ -0,0 +1,36 @@ +#ifndef CBOXTREEWIDGET_H +#define CBOXTREEWIDGET_H + +#include "Export.h" +#include "QTreeWidget" + +class CBoxListView; +class DLL_CLASS CBoxTreeWidget : public QTreeWidget +{ + Q_OBJECT +public: + CBoxTreeWidget(QWidget *parent = Q_NULLPTR); + + bool isExist(const QString &name); + QString currentName(); + + CBoxListView *addListView(QTreeWidgetItem *parent, bool iconMode); + CBoxListView *getListView(QTreeWidgetItem *parent); + void adjustSubListSize(QTreeWidgetItem *cat_item); + +protected: + void resizeEvent(QResizeEvent *e); + void mousePressEvent(QMouseEvent *event); + +private slots: + void filter(const QString &text); + +private: + void slotItemWidgetSelected(); + void initHeaderView(); + +private: + QMap m_itemWidgetMap; +}; + +#endif // CBOXTREEWIDGET_H diff --git a/platform/src/gui/GraphTool/ToolBoxTree/CDrawObjDatabase.cpp b/platform/src/gui/GraphTool/ToolBoxTree/CDrawObjDatabase.cpp new file mode 100644 index 00000000..838637d2 --- /dev/null +++ b/platform/src/gui/GraphTool/ToolBoxTree/CDrawObjDatabase.cpp @@ -0,0 +1,422 @@ +#include +#include + +#include "../../include/CXMLStream.h" +#include "../../include/CStream.h" +#include "CDrawObjDatabase.h" +#include "../../include/public/pub_utility_api/FileUtil.h" + +const int dbsize = 500; +const int dbcustom = 200; +const int dbdictsize = 211; + +static DrawObjDatabaseRecord *db[dbsize]; +static QHash className2Id; +static int dbcount = 0; +static int dbcustomcount = 200; +static QStringList *wGroups; +static QStringList *invisibleGroups; +static bool was_in_setup = false; + +DrawObjDatabaseRecord::DrawObjDatabaseRecord() +{ + toolType = 0; + icon = 0; + nameCounter = 0; + isCommon = false; +} + +DrawObjDatabaseRecord::~DrawObjDatabaseRecord() +{ + delete icon; + icon = NULL; +} + +DrawObjDatabase::DrawObjDatabase() +{ +} + +void DrawObjDatabase::setupDataBase(int id) +{ + was_in_setup = true; + + // Q_UNUSED(id) + if (dbcount && (id != -2)) + { + return; + } + if (id == -2) + { + dbcount = 0; + } + wGroups = new QStringList; + invisibleGroups = new QStringList; + invisibleGroups->append("Forms"); + invisibleGroups->append("Temp"); + + DrawObjDatabaseRecord *r = 0; + QString iconbuf; + + QDomElement rootItem, groupItem, bodyItem, objItem; + QDomNode groupNode, objNode; + QString sysPath, fileName; + + CBaseInstance()->getPathName(CBase::PATH_TYPE_SYS, sysPath); + fileName = sysPath + "toolbox.xml"; + + CGStream iofs; + iofs.SetMode(CGStream::xmlfile); + + CXMLStream &xmls = iofs.m_XMLStream; + int ret = xmls.OPEN(fileName.toLocal8Bit().data(), std::ios::in, 1); + if (ret < 0) + { + //qDebug("open fileName %s error", fileName.c_str()); + return; + } + QString name, stragey, mark; + QString groupName, iconSetName, subType, tipSetName; + int type, isCommon; + rootItem = xmls.GetChild("graph"); + bodyItem = xmls.GetChild("body"); + //groupItem = xmls.GetChild("group",&bodyItem); + groupNode = bodyItem.firstChild(); + while (!groupNode.isNull()) + { + groupItem = groupNode.toElement(); + groupName = groupItem.tagName(); + objNode = groupNode.firstChild(); + + if(objNode.isNull()) + { + widgetGroup(groupName); + } + else + { + while (!objNode.isNull()) + { + objItem = objNode.toElement(); + name = objItem.tagName(); + stragey = objItem.attribute("strategy"); + mark = objItem.attribute("mark"); + type = objItem.attribute("type").toInt(); + subType = objItem.attribute("sub_type"); + iconSetName = objItem.attribute("icon"); + CBaseInstance()->getFilePathName(CBase::PATH_TYPE_ICONSET, iconSetName, iconbuf); + isCommon = objItem.attribute("common").toInt(); + objNode = objNode.nextSibling(); + + r = new DrawObjDatabaseRecord; + + if (type > 100) + { + tipSetName = name + ".png"; + } + else + { + r->toolTip.clear(); + } + + r->iconSet = iconbuf; + r->name = name; + r->group = widgetGroup(groupName); + r->toolType = type; + r->typeSub = subType; + r->isCommon = isCommon; + r->strategy = stragey; + r->mark = mark; + append(r); + } + } + groupNode = groupNode.nextSibling(); + } + + xmls.CLOSE(); +} + +int DrawObjDatabase::count() +{ + setupDataBase(-1); + return dbcount; +} + +int DrawObjDatabase::startCustom() +{ + setupDataBase(-1); + return dbcustom; +} + +QIcon DrawObjDatabase::iconSet(int id) +{ + setupDataBase(id); + DrawObjDatabaseRecord *r = at(id); + if (!r) + { + return QIcon(); + } + if (!r->icon) + { + if (r->iconSet.isEmpty()) + { + return QIcon(); + } + QPixmap pix = QPixmap(QObject::tr(r->iconSet.toLocal8Bit().data())); + // QSize size = pix.size(); + // pix = pix.scaled(size*5); + // size = pix.size(); + if (pix.isNull()) + { + pix = QPixmap(QObject::tr(r->iconSet.toLocal8Bit().data())); + } + + r->icon = new QIcon(pix); + } + + return *r->icon; +} + +QString DrawObjDatabase::className(int id) +{ + setupDataBase(id); + DrawObjDatabaseRecord *r = at(id); + if (!r) + { + return QString(); + } + return r->name; +} + +int DrawObjDatabase::curToolType(int id) +{ + setupDataBase(id); + DrawObjDatabaseRecord *r = at(id); + if (!r) + { + return 0; + } + return r->toolType; +} + +QString DrawObjDatabase::curToolTypeN(int id) +{ + setupDataBase(id); + DrawObjDatabaseRecord *r = at(id); + if (!r) + { + return 0; + } + return r->typeSub; +} + +QString DrawObjDatabase::mark(int id) +{ + setupDataBase(id); + DrawObjDatabaseRecord *r = at(id); + if (!r) + { + return 0; + } + return r->mark; +} + +QString DrawObjDatabase::strategy(int id) +{ + setupDataBase(id); + DrawObjDatabaseRecord *r = at(id); + if (!r) + { + return 0; + } + return r->strategy; +} + +QString DrawObjDatabase::group(int id) +{ + setupDataBase(id); + DrawObjDatabaseRecord *r = at(id); + if (!r) + { + return QString(); + } + return r->group; +} + +QString DrawObjDatabase::toolTip(int id) +{ + setupDataBase(id); + DrawObjDatabaseRecord *r = at(id); + if (!r) + { + return QString(); + } + return r->toolTip; +} + +QString DrawObjDatabase::whatsThis(int id) +{ + setupDataBase(id); + DrawObjDatabaseRecord *r = at(id); + if (!r) + { + return QString(); + } + return r->whatsThis; +} + +QString DrawObjDatabase::includeFile(int id) +{ + setupDataBase(id); + DrawObjDatabaseRecord *r = at(id); + if (!r) + { + return QString(); + } + if (r->includeFile.isNull()) + { + return r->name.toLower() + ".h"; + } + return r->includeFile; +} + +bool DrawObjDatabase::isCommon(int id) +{ + setupDataBase(id); + DrawObjDatabaseRecord *r = at(id); + if (!r) + { + return false; + } + return r->isCommon; +} + +int DrawObjDatabase::idFromClassName(const QString &name) +{ + setupDataBase(-1); + if (name.isEmpty()) + { + return 0; + } + QHash::iterator it = className2Id.find(name); + if (it != className2Id.end()) + { + return it.value(); + } + + if (name == "FormWindow") + { + return idFromClassName("QLayoutWidget"); + } + + return -1; +} + +bool DrawObjDatabase::hasWidget(const QString &name) +{ + return className2Id.find(name) != className2Id.end(); +} + +DrawObjDatabaseRecord *DrawObjDatabase::at(int index) +{ + if (index < 0) + { + return 0; + } + if (index >= dbcustom && index < dbcustomcount) + { + return db[index]; + } + if (index < dbcount) + { + return db[index]; + } + return 0; +} + +void DrawObjDatabase::insert(int index, DrawObjDatabaseRecord *r) +{ + if (index < 0 || index >= dbsize) + { + return; + } + db[index] = r; + className2Id.insert(r->name, index); + if (index < dbcustom) + { + dbcount = qMax(dbcount, index); + } +} + +void DrawObjDatabase::append(DrawObjDatabaseRecord *r) +{ + if (!was_in_setup) + { + setupDataBase(-1); + } + insert(dbcount++, r); +} + +QString DrawObjDatabase::widgetGroup(const QString &g) +{ + if (!wGroups->contains(g)) + { + wGroups->append(g); + } + return g; +} + +bool DrawObjDatabase::isGroupEmpty(const QString &grp) +{ + DrawObjDatabaseRecord *r = 0; + for (int i = 0; i < dbcount; ++i) + { + if (!(r = db[ i ])) + { + continue; + } + + if (r->group == grp) + { + return false; + } + + } + return true; +} + +QString DrawObjDatabase::widgetGroup(int i) +{ + setupDataBase(-1); + if (i >= 0 && i < (int)wGroups->count()) + { + return wGroups->at(i); + } + return QString(); +} + +int DrawObjDatabase::numWidgetGroups() +{ + setupDataBase(-1); + return wGroups->count(); +} + +bool DrawObjDatabase::isGroupVisible(const QString &g) +{ + setupDataBase(-1); + //return invisibleGroups->find(g) == -1; + return !invisibleGroups->contains(g); +} + +int DrawObjDatabase::addCustomWidget(DrawObjDatabaseRecord *r) +{ + insert(dbcustomcount++, r); + return dbcustomcount - 1; +} + +bool DrawObjDatabase::isCustomWidget(int id) +{ + if (id >= dbcustom && id < dbcustomcount) + { + return true; + } + return false; +} diff --git a/platform/src/gui/GraphTool/ToolBoxTree/CDrawObjDatabase.h b/platform/src/gui/GraphTool/ToolBoxTree/CDrawObjDatabase.h new file mode 100644 index 00000000..0d37256a --- /dev/null +++ b/platform/src/gui/GraphTool/ToolBoxTree/CDrawObjDatabase.h @@ -0,0 +1,60 @@ + +#ifndef CDROWOBJDATABASE_H +#define CDROWOBJDATABASE_H + +#include +#include +#include "Export.h" +#include "../../include/CBase.h" + + +struct DLL_CLASS DrawObjDatabaseRecord +{ + DrawObjDatabaseRecord(); + ~DrawObjDatabaseRecord(); + + QString iconSet, name, group, typeSub, toolTip, whatsThis, includeFile; + QString strategy; + QString mark; + + uint isCommon : 1; + QIcon *icon; + int nameCounter; + int toolType; +}; + +class DLL_CLASS DrawObjDatabase +{ + +public: + DrawObjDatabase(); + static void setupDataBase(int id); + static int count(); + static int startCustom(); + static QIcon iconSet(int id); + static QString className(int id); + static int curToolType(int id); + static QString curToolTypeN(int id); + static QString group(int id); + static QString mark(int id); + static QString strategy(int id); + static QString toolTip(int id); + static QString whatsThis(int id); + static QString includeFile(int id); + static bool isCommon(int id); + static int idFromClassName(const QString &name); + static DrawObjDatabaseRecord *at(int inde); + static void insert(int index, DrawObjDatabaseRecord *r); + static void append(DrawObjDatabaseRecord *r); + static QString widgetGroup(const QString &g); + static QString widgetGroup(int i); + static int numWidgetGroups(); + static bool isGroupVisible(const QString &g); + static bool isGroupEmpty(const QString &grp); + static int addCustomWidget(DrawObjDatabaseRecord *r); + static bool isCustomWidget(int id); + static bool isCustomPluginWidget(int id); + static bool hasWidget(const QString &name); +}; + +#endif diff --git a/platform/src/gui/GraphTool/ToolBoxTree/ToolBoxTree.pro b/platform/src/gui/GraphTool/ToolBoxTree/ToolBoxTree.pro new file mode 100644 index 00000000..e9e42091 --- /dev/null +++ b/platform/src/gui/GraphTool/ToolBoxTree/ToolBoxTree.pro @@ -0,0 +1,36 @@ +# 原文件本来存放在hmi项目下,当时由于批量生成需要复用到hmi的工具箱树结构,就直接将其提了出来单独做成了dll + +QT += core gui widgets sql xml + +TARGET = ToolBoxTree +TEMPLATE = lib + +INCLUDEPATH += $$PWD + + +HEADERS += \ + CBoxDelegate.h \ + CBoxListModel.h \ + CBoxListView.h \ + CBoxTreeWidget.h \ + CDrawObjDatabase.h + +SOURCES += \ + CBoxDelegate.cpp \ + CBoxListModel.cpp \ + CBoxListView.cpp \ + CBoxTreeWidget.cpp \ + CDrawObjDatabase.cpp + +DEFINES += DLL_OUT + +LIBS += -lpub_widget +LIBS += -lGraphPub -lGraphShape +LIBS += -llog4cplus -lpub_logger_api -lpub_utility_api -ldb_base_api -ldb_api_ex -lprotobuf -lpub_sysinfo_api + +COMMON_PRI=$$PWD/../../../common.pri +exists($$COMMON_PRI) { + include($$COMMON_PRI) +}else { + error("FATAL error: can not find common.pri") +} diff --git a/platform/src/gui/hmi/dialog/graphTree/CGraphFileTree.cpp b/platform/src/gui/hmi/dialog/graphTree/CGraphFileTree.cpp new file mode 100644 index 00000000..631466d9 --- /dev/null +++ b/platform/src/gui/hmi/dialog/graphTree/CGraphFileTree.cpp @@ -0,0 +1,175 @@ +#include +#include +#include +#include +#include +#include +#include "../../include/CBase.h" +#include "CGraphFileTree.h" + +CGraphFileTree::CGraphFileTree(QWidget *parent) + : QTreeWidget(parent) +{ + initStyle(); + + m_strBasePath = CBaseInstance()->getSysHome() + QDir::separator() + QString("data") + QDir::separator() + QString("pic"); + QHBoxLayout * hLayout = new QHBoxLayout; + QLineEdit * edit = new QLineEdit(this); + edit->setFrame(false); + edit->setPlaceholderText(tr("搜索...")); + edit->setFixedHeight(21); + hLayout->setContentsMargins(3,0,0,0); + hLayout->addWidget(edit); + QVBoxLayout * vLayout = new QVBoxLayout; + vLayout->addLayout(hLayout); + QFrame * line = new QFrame(this); + line->setFrameShape(QFrame::HLine); + line->setFrameShadow(QFrame::Sunken); + vLayout->addWidget(line); + vLayout->setMargin(1); + vLayout->setSpacing(1); + header()->setLayout(vLayout); + connect(edit, SIGNAL(textChanged(QString)), this, SLOT(filter(QString))); + + reload(); +} + +void CGraphFileTree::reload(const QString &path) +{ + if(m_strBasePath != path) + { + m_strBasePath = path; + reload(); + } +} + +void CGraphFileTree::mousePressEvent(QMouseEvent *event) +{ + QTreeWidgetItem * pItem = static_cast(indexAt(event->pos()).internalPointer()); + if(pItem) + { + if(pItem->type() == FileType) + { + emit sigFileClicked(pItem->data(0, Qt::UserRole).toString()); + } + } + return QTreeWidget::mousePressEvent(event); +} + +void CGraphFileTree::contextMenuEvent(QContextMenuEvent *event) +{ + QMenu menu; + menu.addAction(tr("刷新"), this, SLOT(reload())); + menu.exec(event->globalPos()); +} + +void CGraphFileTree::reload() +{ + clear(); + buildTree(NULL, m_strBasePath); +} + +void CGraphFileTree::filter(const QString &text) +{ + for(int nIndex(0); nIndextext(0); + if(text.isEmpty() || temp.contains(text)) + { + setChildShow(item); + isHidden = false; + } + else + { + if(item->childCount() > 0) + { + for(int nIndex(0); nIndexchildCount(); ++nIndex) + { + if(!filter(item->child(nIndex), text)) + { + isHidden = false; + } + } + } + else + { + isHidden = true; + } + } + + setItemHidden(item, isHidden); + return isHidden; +} + +void CGraphFileTree::setChildShow(QTreeWidgetItem *item) +{ + int childCount = item->childCount(); + for(int nIndex(0); nIndex < childCount; ++nIndex) + { + setItemHidden(item->child(nIndex), false); + setChildShow(item->child(nIndex)); + } +} + +void CGraphFileTree::initStyle() +{ + QFont font = qApp->font(); + font.setPointSize(font.pointSize() + 1); + setFont(font); + QPalette palette = this->palette(); + palette.setColor(QPalette::Shadow, Qt::blue); + setIconSize(QSize(30, 30)); + setPalette(palette); + setAutoFillBackground(true); + setStyleSheet("QTreeView::item{height:26px;}"); +} + +void CGraphFileTree::buildTree(QTreeWidgetItem * parent, QString basePath) +{ + QDir dir(basePath); + + QFileInfoList folderList = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); + foreach (QFileInfo folder, folderList) { + QTreeWidgetItem * item = new QTreeWidgetItem(FolderType); + item->setText(0, folder.baseName()); + if(parent == NULL) + { + addTopLevelItem(item); + } + else + { + parent->addChild(item); + } + buildTree(item, folder.absoluteFilePath()); + } + + QFileInfoList fileList = dir.entryInfoList(QDir::Files | QDir::NoSymLinks); + foreach (QFileInfo file, fileList) { + QTreeWidgetItem * item = new QTreeWidgetItem(FileType); + item->setText(0, file.baseName() + "." + file.suffix()); + item->setData(0, Qt::UserRole, file.filePath()); + if(parent == NULL) + { + addTopLevelItem(item); + } + else + { + parent->addChild(item); + } + } +} diff --git a/platform/src/gui/hmi/dialog/graphTree/CGraphFileTree.h b/platform/src/gui/hmi/dialog/graphTree/CGraphFileTree.h new file mode 100644 index 00000000..17d6839a --- /dev/null +++ b/platform/src/gui/hmi/dialog/graphTree/CGraphFileTree.h @@ -0,0 +1,35 @@ +#ifndef CGRAPHFILETREE_H +#define CGRAPHFILETREE_H + +#include + +class CGraphFileTree : public QTreeWidget +{ + Q_OBJECT + enum NodeType{ FolderType = QTreeWidgetItem::UserType + 1, FileType }; +public: + CGraphFileTree(QWidget *parent = Q_NULLPTR); + void reload(const QString& path); + +signals: + void sigFileClicked(const QString& path); + +protected: + void mousePressEvent(QMouseEvent *event); + void contextMenuEvent(QContextMenuEvent *event); + +private slots: + void reload(); + void filter(const QString &text); + +private: + void initStyle(); + void buildTree(QTreeWidgetItem *parent, QString basePath); + bool filter(QTreeWidgetItem *item, const QString &text); + void setChildShow(QTreeWidgetItem *item); + +private: + QString m_strBasePath; +}; + +#endif // CGRAPHFILETREE_H diff --git a/platform/src/gui/hmi/dialog/hmiConfigDialog/CComboxDelegate.cpp b/platform/src/gui/hmi/dialog/hmiConfigDialog/CComboxDelegate.cpp new file mode 100644 index 00000000..98ac13d9 --- /dev/null +++ b/platform/src/gui/hmi/dialog/hmiConfigDialog/CComboxDelegate.cpp @@ -0,0 +1,39 @@ +#include "CComboxDelegate.h" +#include +#include +#include + +CComboxDelegate::CComboxDelegate(QObject *parent) + : QStyledItemDelegate(parent) +{ + +} + +QWidget *CComboxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + Q_UNUSED(option) + Q_UNUSED(index) + QComboBox * box = new QComboBox(parent); + QDesktopWidget *dw = QApplication::desktop(); + int count = dw->screenCount(); + for(int n = 0; n < count; n++) + { + box->addItem(QString::number(n)); + } + return box; +} + +void CComboxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const +{ + QComboBox * box = static_cast(editor); + box->setCurrentIndex(box->findText(index.data(Qt::DisplayRole).toString())); +} + +void CComboxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const +{ + QComboBox * box = static_cast(editor); + if(model->data(index, Qt::DisplayRole) != box->currentText()) + { + model->setData(index, box->currentText(), Qt::DisplayRole); + } +} diff --git a/platform/src/gui/hmi/dialog/hmiConfigDialog/CComboxDelegate.h b/platform/src/gui/hmi/dialog/hmiConfigDialog/CComboxDelegate.h new file mode 100644 index 00000000..5c09c43b --- /dev/null +++ b/platform/src/gui/hmi/dialog/hmiConfigDialog/CComboxDelegate.h @@ -0,0 +1,21 @@ +#ifndef CCOMBOXDELEGATE_H +#define CCOMBOXDELEGATE_H + +#include +#include + +class CComboxDelegate : public QStyledItemDelegate +{ + Q_OBJECT +public: + CComboxDelegate(QObject *parent = Q_NULLPTR); + + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, + const QModelIndex &index) const override; + + void setEditorData(QWidget *editor, const QModelIndex &index) const override; + void setModelData(QWidget *editor, QAbstractItemModel *model, + const QModelIndex &index) const override; +}; + +#endif // CCOMBOXDELEGATE_H diff --git a/platform/src/gui/hmi/dialog/toolBoxTree/CBoxDelegate.cpp b/platform/src/gui/hmi/dialog/toolBoxTree/CBoxDelegate.cpp new file mode 100644 index 00000000..7f3b6e69 --- /dev/null +++ b/platform/src/gui/hmi/dialog/toolBoxTree/CBoxDelegate.cpp @@ -0,0 +1,76 @@ +#include "CBoxDelegate.h" +#include "CBoxListView.h" +#include "CBoxTreeWidget.h" + +CListDelegate::CListDelegate(QObject *parent) + : m_pView(dynamic_cast(parent)) +{ + +} + +QSize CListDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + if(m_pView) + { + if(m_pView->model()->data(index, Qt::DisplayRole) != QVariant()) + { + return QSize(m_pView->getMaxTextWidth(), QStyledItemDelegate::sizeHint(option, index).height()); + } + } + return QStyledItemDelegate::sizeHint(option, index); +} + +CTreeDelegate::CTreeDelegate(QObject *parent) + : m_pView(dynamic_cast(parent)) +{ + +} + +void CTreeDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + QStyledItemDelegate::paint(painter, option, index); + bool bExpanded = m_pView->isExpanded(index); + bExpanded ? drawRightArrow(painter, option) : drawDownArrow(painter, option); +} + +void CTreeDelegate::drawDownArrow(QPainter *painter, const QStyleOptionViewItem &option) const +{ + painter->save(); + + QPen pen; + pen.setColor(QColor(0,0,0)); + pen.setWidthF(1.5); + painter->setPen(pen); + + QStyleOptionViewItem viewOption(option); + qreal x = viewOption.rect.left() + viewOption.rect.width() - 15; + qreal y = viewOption.rect.top() + viewOption.rect.height() / 2 + 2; + QPointF p1(x - 5, y - 5); + QPointF p2(x, y); + QPointF p3(x + 5, y - 5); + + painter->drawLine(p1, p2); + painter->drawLine(p2, p3); + painter->restore(); +} + +void CTreeDelegate::drawRightArrow(QPainter *painter, const QStyleOptionViewItem &option) const +{ + painter->save(); + + QPen pen; + pen.setColor(QColor(0,0,0)); + pen.setWidthF(1.5); + painter->setPen(pen); + + QStyleOptionViewItem viewOption(option); + qreal x = viewOption.rect.left() + viewOption.rect.width() - 10; + qreal y = viewOption.rect.top() + viewOption.rect.height() / 2; + QPointF p1(x - 5, y - 5); + QPointF p2(x, y); + QPointF p3(x - 5, y + 5); + + painter->drawLine(p1, p2); + painter->drawLine(p2, p3); + painter->restore(); +} diff --git a/platform/src/gui/hmi/dialog/toolBoxTree/CBoxDelegate.h b/platform/src/gui/hmi/dialog/toolBoxTree/CBoxDelegate.h new file mode 100644 index 00000000..342f95ad --- /dev/null +++ b/platform/src/gui/hmi/dialog/toolBoxTree/CBoxDelegate.h @@ -0,0 +1,37 @@ +#ifndef CBOXDELEGATE_H +#define CBOXDELEGATE_H + +#include + +class CBoxListView; +class CListDelegate : public QStyledItemDelegate +{ +public: + CListDelegate(QObject *parent = Q_NULLPTR); + + QSize sizeHint(const QStyleOptionViewItem &option, + const QModelIndex &index) const override; + +private: + CBoxListView * m_pView; +}; + +class QTreeWidget; +class CTreeDelegate : public QStyledItemDelegate +{ +public: + CTreeDelegate(QObject *parent = Q_NULLPTR); + + void paint(QPainter *painter, + const QStyleOptionViewItem &option, const QModelIndex &index) const override; + + void drawDownArrow(QPainter *painter, + const QStyleOptionViewItem &option) const; + void drawRightArrow(QPainter *painter, + const QStyleOptionViewItem &option) const; + +private: + QTreeWidget * m_pView; +}; + +#endif // CBOXDELEGATE_H diff --git a/platform/src/gui/hmi/dialog/toolBoxTree/CBoxListModel.cpp b/platform/src/gui/hmi/dialog/toolBoxTree/CBoxListModel.cpp new file mode 100644 index 00000000..d2ade8cb --- /dev/null +++ b/platform/src/gui/hmi/dialog/toolBoxTree/CBoxListModel.cpp @@ -0,0 +1,102 @@ +#include "CBoxListModel.h" + +CBoxListModel::CBoxListModel(QObject *parent) + : QAbstractListModel(parent) +{ + +} + +CBoxListModel::~CBoxListModel() +{ + m_items.clear(); +} + +bool CBoxListModel::isExist(const QString &name) +{ + for(int nIndex(0); nIndex < m_items.size(); ++nIndex) + { + if(m_items[nIndex]->name == name) + { + return true; + } + } + return false; +} + +DrawObjDatabaseRecord *CBoxListModel::record(const QModelIndex &index) const +{ + const int row = index.row(); + if (row < 0 || row >= m_items.size()) + return Q_NULLPTR; + + return m_items.at(row); +} + +QVariant CBoxListModel::data(const QModelIndex &index, int role) const +{ + const int row = index.row(); + if (row < 0 || row >= m_items.size()) + return QVariant(); + + const DrawObjDatabaseRecord *item = m_items.at(row); + switch (role) { + case Qt::DisplayRole: + { + if(item->icon && !item->icon->isNull()) + { + return QVariant(); + } + return QVariant(item->name); + } + case Qt::DecorationRole: + return QVariant(*(item->icon)); + case Qt::WhatsThisRole: + return QVariant(item->toolType); + case Qt::ToolTipRole: + return QVariant(item->name); + case Qt::UserRole: + return QVariant(item->typeSub); + case Qt::UserRole + 1: + return QVariant(item->mark); + case Qt::UserRole + 2: + return QVariant(item->strategy); + case Qt::UserRole + 3: + return QVariant(item->name); + } + return QVariant(); +} + +int CBoxListModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + return m_items.size(); +} + +Qt::ItemFlags CBoxListModel::flags(const QModelIndex &index) const +{ + Q_UNUSED(index) + return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled; +} + +bool CBoxListModel::removeRows(int row, int count, const QModelIndex &parent) +{ + if (row < 0 || count < 1) + return false; + const int size = m_items.size(); + const int last = row + count - 1; + if (row >= size || last >= size) + return false; + beginRemoveRows(parent, row, last); + for (int r = last; r >= row; r--) + m_items.removeAt(r); + endRemoveRows(); + return true; +} + +void CBoxListModel::addWidget(DrawObjDatabaseRecord *record) +{ + const int row = m_items.size(); + beginInsertRows(QModelIndex(), row, row); + m_items.push_back(record); + endInsertRows(); +} diff --git a/platform/src/gui/hmi/dialog/toolBoxTree/CBoxListModel.h b/platform/src/gui/hmi/dialog/toolBoxTree/CBoxListModel.h new file mode 100644 index 00000000..f3b620d7 --- /dev/null +++ b/platform/src/gui/hmi/dialog/toolBoxTree/CBoxListModel.h @@ -0,0 +1,27 @@ +#ifndef CBOXLISTMODEL_H +#define CBOXLISTMODEL_H + +#include "QAbstractListModel" +#include "CDrawObjDatabase.h" + +class CBoxListModel : public QAbstractListModel +{ + Q_OBJECT +public: + CBoxListModel(QObject *parent = Q_NULLPTR); + ~CBoxListModel(); + + bool isExist(const QString &name); + DrawObjDatabaseRecord* record(const QModelIndex &index) const; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + Qt::ItemFlags flags (const QModelIndex & index ) const override; + bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override; + void addWidget(DrawObjDatabaseRecord *record); + +private: + QList m_items; +}; + +#endif // CBOXLISTMODEL_H diff --git a/platform/src/gui/hmi/dialog/toolBoxTree/CBoxListView.cpp b/platform/src/gui/hmi/dialog/toolBoxTree/CBoxListView.cpp new file mode 100644 index 00000000..80853dae --- /dev/null +++ b/platform/src/gui/hmi/dialog/toolBoxTree/CBoxListView.cpp @@ -0,0 +1,122 @@ +#include "CBoxListView.h" +#include "CBoxListModel.h" +#include "CBoxDelegate.h" + +CBoxListView::CBoxListView(QWidget *parent) + : QListView(parent), + m_pModel(new CBoxListModel(this)), + m_nMaxTextWidth(0) +{ + setFocusPolicy(Qt::NoFocus); + setFrameShape(QFrame::NoFrame); + setIconSize(QSize(30, 30)); + setSpacing(1); + setTextElideMode(Qt::ElideMiddle); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setResizeMode(QListView::Adjust); + setDragEnabled(true); + setDragDropMode(QAbstractItemView::DragOnly); + QFont font = qApp->font(); + font.setPointSize(font.pointSize() + 1); + setFont(font); + //setUniformItemSizes(true); + setModel(m_pModel); + setItemDelegate(new CListDelegate(this)); + + connect(this, &CBoxListView::pressed, this, &CBoxListView::slotItemPressed); +} + +bool CBoxListView::isExist(const QString &name) +{ + return m_pModel->isExist(name); +} + +DrawObjDatabaseRecord *CBoxListView::selectedRecord() +{ + QModelIndex curIndex = currentIndex(); + if( !curIndex.isValid() ) + { + return NULL; + } + return m_pModel->record(curIndex); +} + +void CBoxListView::addWidget(DrawObjDatabaseRecord *record) +{ + if(record->icon && record->icon->isNull()){ + setMaxTextWidth(record->name); + } + m_pModel->addWidget(record); +} + +void CBoxListView::removeSelectedWidget() +{ + QModelIndex curIndex = currentIndex(); + if( !curIndex.isValid() ) + { + return; + } + m_pModel->removeRows(curIndex.row(), 1); +} + +int CBoxListView::getMaxTextWidth() +{ + return m_nMaxTextWidth; +} + +void CBoxListView::setMaxTextWidth(const QString &text) +{ + QFontMetrics font = this->fontMetrics(); + int width = font.boundingRect(text+"AA").width(); + if(width > m_nMaxTextWidth) + { + m_nMaxTextWidth = width; + } +} + +bool CBoxListView::filter(const QString &text) +{ + bool isHidden = true; + DrawObjDatabaseRecord * record; + for(int nIndex(0); nIndexrowCount(); ++nIndex) + { + record = m_pModel->record(m_pModel->index(nIndex, 0)); + if(text.isEmpty() || (record && record->name.contains(text))) + { + setRowHidden(nIndex, false); + isHidden = false; + } + else + { + setRowHidden(nIndex, true); + } + } + return isHidden; +} + +void CBoxListView::dragMoveEvent(QDragMoveEvent *e) +{ + e->setAccepted(false); +} + +void CBoxListView::startDrag(Qt::DropActions supportedActions) +{ + Q_UNUSED(supportedActions) + QDrag *drag = new QDrag(this); + QMimeData *mimeData = new QMimeData(); + mimeData->setText("toolBox"); + drag->setMimeData(mimeData); + drag->exec(Qt::CopyAction); +} + +void CBoxListView::slotItemPressed(const QModelIndex &index) +{ + emit itemSelected(); + CBoxListModel * model = dynamic_cast(this->model()); + DrawObjDatabaseRecord * record = model->record(index); + if(record) + { + emit itemPressed(record); + } +} diff --git a/platform/src/gui/hmi/dialog/toolBoxTree/CBoxListView.h b/platform/src/gui/hmi/dialog/toolBoxTree/CBoxListView.h new file mode 100644 index 00000000..378b1361 --- /dev/null +++ b/platform/src/gui/hmi/dialog/toolBoxTree/CBoxListView.h @@ -0,0 +1,42 @@ +#ifndef CBOXLISTVIEW_H +#define CBOXLISTVIEW_H + +#include +#include "CDrawObjDatabase.h" + +class CBoxListModel; +class CBoxListView : public QListView +{ + Q_OBJECT +public: + CBoxListView(QWidget *parent = Q_NULLPTR); + + using QListView::contentsSize; + + bool isExist(const QString &name); + + DrawObjDatabaseRecord * selectedRecord(); + void addWidget(DrawObjDatabaseRecord *record); + void removeSelectedWidget(); + + int getMaxTextWidth(); + void setMaxTextWidth(const QString &text); + + bool filter(const QString &text); +signals: + void itemSelected(); + void itemPressed(const DrawObjDatabaseRecord *record); + +protected: + void dragMoveEvent(QDragMoveEvent *e); + void startDrag(Qt::DropActions supportedActions); + +private slots: + void slotItemPressed(const QModelIndex &index); + +private: + CBoxListModel * m_pModel; + int m_nMaxTextWidth; +}; + +#endif // CBOXLISTVIEW_H diff --git a/platform/src/gui/hmi/dialog/toolBoxTree/CBoxTreeWidget.cpp b/platform/src/gui/hmi/dialog/toolBoxTree/CBoxTreeWidget.cpp new file mode 100644 index 00000000..b3d238ff --- /dev/null +++ b/platform/src/gui/hmi/dialog/toolBoxTree/CBoxTreeWidget.cpp @@ -0,0 +1,190 @@ +#include +#include +#include +#include +#include "CBoxTreeWidget.h" +#include "CBoxListView.h" +#include "CBoxDelegate.h" + +CBoxTreeWidget::CBoxTreeWidget(QWidget *parent) + : QTreeWidget(parent) +{ + setFocusPolicy(Qt::NoFocus); + setRootIsDecorated(false); + setIndentation(0); + setColumnCount(1); + setTextElideMode(Qt::ElideMiddle); + setVerticalScrollMode(QTreeView::ScrollPerPixel); + setStyleSheet("QTreeView::item{height:26px;}"); + QFont font = qApp->font(); + font.setPointSize(font.pointSize() + 1); + setFont(font); + QPalette palette = this->palette(); + palette.setColor(QPalette::Shadow, Qt::blue); + setIconSize(QSize(30, 30)); + setPalette(palette); + setAutoFillBackground(true); + + setItemDelegate(new CTreeDelegate(this)); + initHeaderView(); +} + +bool CBoxTreeWidget::isExist(const QString &name) +{ + for(int nIndex = 0; nIndex < topLevelItemCount(); ++nIndex) + { + QTreeWidgetItem * item = topLevelItem(nIndex); + if(item->childCount() <= 0) + { + continue; + } + CBoxListView *listView = static_cast(itemWidget(item->child(0), 0)); + if(listView == NULL) + { + continue; + } + if(listView->isExist(name)) + { + return true; + } + } + return false; +} + +QString CBoxTreeWidget::currentName() +{ + QTreeWidgetItem * item = currentItem(); + if(item) + { + CBoxListView *listWidget = static_cast(itemWidget(item, 0)); + if(listWidget) + { + return listWidget->model()->data(listWidget->currentIndex(), Qt::UserRole + 3).toString(); + } + else + { + return item->data(0, Qt::UserRole + 3).toString(); + } + } + return QString(); +} + +CBoxListView *CBoxTreeWidget::addListView(QTreeWidgetItem *parent, bool iconMode) +{ + QTreeWidgetItem *embed_item = new QTreeWidgetItem(parent); + CBoxListView *listView = new CBoxListView(this); + listView->setViewMode(iconMode ? QListView::IconMode : QListView::ListMode); + connect(listView, &CBoxListView::itemSelected, this, &CBoxTreeWidget::slotItemWidgetSelected); + setItemWidget(embed_item, 0, listView); + m_itemWidgetMap[listView] = embed_item; + return listView; +} + +CBoxListView *CBoxTreeWidget::getListView(QTreeWidgetItem *parent) +{ + if(parent == NULL) + { + return NULL; + } + QMap::const_iterator iter = m_itemWidgetMap.constBegin(); + for( ; iter != m_itemWidgetMap.constEnd(); ++iter) + { + if(iter.value() == parent) + { + return dynamic_cast(iter.key()); + } + } + return NULL; +} + +void CBoxTreeWidget::adjustSubListSize(QTreeWidgetItem *cat_item) +{ + QTreeWidgetItem *embedItem = cat_item->child(0); + if (embedItem == 0) + return; + + CBoxListView *listWidget = static_cast(itemWidget(embedItem, 0)); + listWidget->setFixedWidth(header()->width()); + listWidget->doItemsLayout(); + const int height = qMax(listWidget->contentsSize().height() ,1); + listWidget->setFixedHeight(height); + embedItem->setSizeHint(0, QSize(-1, height - 1)); +} + +void CBoxTreeWidget::resizeEvent(QResizeEvent *e) +{ + QTreeWidget::resizeEvent(e); + if (const int numTopLevels = topLevelItemCount()) { + for (int i = numTopLevels - 1; i >= 0; --i) + adjustSubListSize(topLevelItem(i)); + } +} + +void CBoxTreeWidget::mousePressEvent(QMouseEvent *event) +{ + if(event->button() == Qt::LeftButton) + { + QTreeWidgetItem * item = itemAt(event->pos()); + if(item){ + item->isExpanded() ? collapseItem(item) : expandItem(item); + } + } + return QTreeWidget::mousePressEvent(event); +} + +void CBoxTreeWidget::filter(const QString &text) +{ + for(int nIndex(0); nIndex < topLevelItemCount(); ++nIndex) + { + QTreeWidgetItem * top = topLevelItem(nIndex); + if(!top->child(0)) + { + top->setHidden(true); + continue; + } + CBoxListView *listWidget = static_cast(itemWidget(top->child(0), 0)); + if(listWidget) + { + top->setHidden(listWidget->filter(text)); + } + else + { + top->setHidden(true); + } + adjustSubListSize(top); + } + text.isEmpty() ? collapseAll() : expandAll(); +} + +void CBoxTreeWidget::slotItemWidgetSelected() +{ + QWidget * widget = dynamic_cast(sender()); + QMap::const_iterator iter = m_itemWidgetMap.find(widget); + if(iter != m_itemWidgetMap.constEnd()) + { + clearSelection(); + setCurrentItem(iter.value()); + iter.value()->parent()->setSelected(true); + } +} + +void CBoxTreeWidget::initHeaderView() +{ + QHBoxLayout * hLayout = new QHBoxLayout; + QLineEdit * edit = new QLineEdit(this); + edit->setFrame(false); + edit->setPlaceholderText(tr("搜索...")); + edit->setFixedHeight(21); + hLayout->setContentsMargins(3,0,0,0); + hLayout->addWidget(edit); + QVBoxLayout * vLayout = new QVBoxLayout; + vLayout->addLayout(hLayout); + QFrame * line = new QFrame(this); + line->setFrameShape(QFrame::HLine); + line->setFrameShadow(QFrame::Sunken); + vLayout->addWidget(line); + vLayout->setMargin(1); + vLayout->setSpacing(1); + header()->setLayout(vLayout); + connect(edit, SIGNAL(textChanged(QString)), this, SLOT(filter(QString))); +} diff --git a/platform/src/gui/hmi/dialog/toolBoxTree/CBoxTreeWidget.h b/platform/src/gui/hmi/dialog/toolBoxTree/CBoxTreeWidget.h new file mode 100644 index 00000000..d6f80629 --- /dev/null +++ b/platform/src/gui/hmi/dialog/toolBoxTree/CBoxTreeWidget.h @@ -0,0 +1,35 @@ +#ifndef CBOXTREEWIDGET_H +#define CBOXTREEWIDGET_H + +#include "QTreeWidget" + +class CBoxListView; +class CBoxTreeWidget : public QTreeWidget +{ + Q_OBJECT +public: + CBoxTreeWidget(QWidget *parent = Q_NULLPTR); + + bool isExist(const QString &name); + QString currentName(); + + CBoxListView *addListView(QTreeWidgetItem *parent, bool iconMode); + CBoxListView *getListView(QTreeWidgetItem *parent); + void adjustSubListSize(QTreeWidgetItem *cat_item); + +protected: + void resizeEvent(QResizeEvent *e); + void mousePressEvent(QMouseEvent *event); + +private slots: + void filter(const QString &text); + +private: + void slotItemWidgetSelected(); + void initHeaderView(); + +private: + QMap m_itemWidgetMap; +}; + +#endif // CBOXTREEWIDGET_H diff --git a/platform/src/gui/platform_fr.ts b/platform/src/gui/platform_fr.ts new file mode 100644 index 00000000..fa0a269c --- /dev/null +++ b/platform/src/gui/platform_fr.ts @@ -0,0 +1,5348 @@ + + + + + AddBtnForm + + + Form + + + + + CAddBtnForm + + + 添加图片 + + + + + 添加边框 + + + + + 添加渐变 + + + + + 添加颜色 + + + + + 添加字体 + + + + + 添加副控制 + + + + + 添加状态 + + + + + 背景图片 + + + + + 边框图片 + + + + + 图片 + + + + + 颜色 + + + + + 背景颜色 + + + + + 间隔背景颜色 + + + + + 边框颜色 + + + + + 上边框颜色 + + + + + 右边框颜色 + + + + + 下边框颜色 + + + + + 左边框颜色 + + + + + 网格颜色 + + + + + 选中颜色 + + + + + 选中背景颜色 + + + + + add-line + + + + + add-page + + + + + branch + + + + + chunk + + + + + close-button + + + + + corner + + + + + down-arrow + + + + + down-button + + + + + drop-down + + + + + float-button + + + + + groove + + + + + indicator + + + + + handle + + + + + icon + + + + + item + + + + + left-arrow + + + + + left-corner + + + + + menu-arrow + + + + + menu-button + + + + + menu-indicator + + + + + right-arrow + + + + + pane + + + + + right-corner + + + + + scroller + + + + + section + + + + + separator + + + + + sub-line + + + + + sub-page + + + + + tab + + + + + tab-bar + + + + + tear + + + + + tearoff + + + + + text + + + + + title + + + + + up-arrow + + + + + up-button + + + + + active + + + + + adjoins-item + + + + + alternate + + + + + bottom + + + + + checked + + + + + closable + + + + + closed + + + + + default + + + + + disabled + + + + + editable + + + + + edit-focus + + + + + enabled + + + + + exclusive + + + + + first + + + + + flat + + + + + floatable + + + + + focus + + + + + has-children + + + + + has-siblings + + + + + horizontal + + + + + hover + + + + + indeterminate + + + + + last + + + + + left + + + + + maximized + + + + + middle + + + + + minimized + + + + + movable + + + + + no-frame + + + + + non-exclusive + + + + + off + + + + + on + + + + + only-one + + + + + open + + + + + next-selected + + + + + pressed + + + + + previous-selected + + + + + read-only + + + + + right + + + + + selected + + + + + top + + + + + unchecked + + + + + vertical + + + + + window + + + + + 无边框 + + + + + 点状边框 + + + + + 虚线边框 + + + + + 实线边框 + + + + + 双线边框 + + + + + 边框圆角 + + + + + 左上边框圆角 + + + + + 右上边框圆角 + + + + + 左下边框圆角 + + + + + 右下边框圆角 + + + + + 选择文件 + + + + + 渐变配置 + 选择渐变 + + + + + 选择颜色 + + + + + CAnimationConfigDialog + + + + 动画配置 + + + + + 取消 + + + + + 确定 + + + + + 旋转动画 + + + + + + + 动画过渡间隔: + + + + + + + ms + + + + + + + 关联测点: + + + + + + ° + + + + + + + 最小值 + + + + + 旋转偏移角度 + + + + + + + 最大值 + + + + + + + 测点值 + + + + + + + + + + None + + + + + + + 动画值配置: + + + + + 位移动画 + + + + + 水平偏移像素 + + + + + 垂直偏移像素 + + + + + + + + px + + + + + 缩放动画 + + + + + 水平缩放比例 + + + + + 垂直缩放比例 + + + + + + + + % + + + + + CBindCheckModel + + + 检查结果 + + + + + 对象名称 + + + + + 点描述 + + + + + 点标签 + + + + + 正常 + + + + + 无对象名称 + + + + + 对象名称重复 + + + + + 联库错误 + + + + + 未联库 + + + + + CBindCheckWidget + + + 检查 + + + + + 正常项 + + + + + 异常项 + + + + + 未联库 + + + + + CBoxTreeWidget + + + 搜索... + + + + + CChartShape + + + 饼图 + + + + + 棒图 + + + + + 折线图 + + + + + 实时图 + + + + + CColorConfigWidget + + + 颜色选择 + + + + + CConfigDialog + + + 页面配置 + + + + + 基础配置 + + + + + 分辨率: + + + + + * + + + + + 像素 + + + + + 失电颜色: + + + + + 背景: + + + + + 首页: + + + + + 单屏显示 + + + + + 多屏配置 + + + + + 屏幕个数: + + + + + 确定 + + + + + 取消 + + + + + CDataBindModel + + + 标签名称 + + + + + CDataBindView + + + 提示 + + + + + 当前测点已经存在! + + + + + 警告 + + + + + 当前未选中任何行! + + + + + 删除 + + + + + 清空 + + + + + 新建 + + + + + CDesignerScene + + + + + + 提示 + + + + + 组合图元不可镜像! + + + + + 精灵图元不可镜像! + + + + + 控件图元不可镜像! + + + + + 图表图元不可镜像! + + + + + CDesignerView + + + 编辑图元 + + + + + 文本替换 + + + + + 动画配置 + + + + + 文本编辑 + + + + + 数据源配置 + + + + + 添加到精灵图元 + + + + + 检索器 + + + + + + 视图 + + + + + + 显示网格 + + + + + + 网格间距 + + + + + + 网格颜色 + + + + + CDesignerWnd + + + 设计窗口 + + + + + 图形已被修改! +保存所作的改动? + + + + + 保存 + + + + + 不保存 + + + + + + + 取消 + + + + + 新建 + + + + + 提醒 + + + + + 请选择新建类型? + + + + + 新建图形 + + + + + 新建图元 + + + + + + 精灵图元 + + + + + + 打开 + + + + + + 打开文件 + + + + + pic (*.glx *.ilx *.elx) + + + + + + + + + + + + + + + + 提示 + + + + + 找不到文件: + + + + + + + 保存文件 + + + + + 另存文件 + + + + + + + 图元名称首字母不能为数字! + + + + + + + 图元名称只支持中文、字母、数字和下划线 + + + + + 非法的命名 + + + + + 执行上传拓扑? + + + + + 确认 + + + + + + + + + + + + + + + + + + + + 警告 + + + + + 未设置所属专业.位置 + + + + + 无效的位置信息 + + + + + + 操作dev_topo_info失败 + + + + + + + 操作dev_topo_ver失败 + + + + + 上传拓扑成功! + + + + + 关闭 + + + + + Ctrl+N + + + + + Ctrl+O + + + + + Ctrl+S + + + + + F11 + + + + + F5 + + + + + 重新联库 + + + + + Ctrl+F + + + + + 检索器 + + + + + F2 + + + + + 清空联库 + + + + + 图层管理 + + + + + Delete + + + + + + Ctrl+C + + + + + 全选 + + + + + Ctrl+A + + + + + Ctrl+X + + + + + Ctrl+V + + + + + Ctrl+k + + + + + Ctrl+b + + + + + 添加图元 + + + + + 移除图元 + + + + + 编辑图元 + + + + + 增加图库 + + + + + 删除图库 + + + + + + 位置: + + + + + 栅格 + + + + + 捕捉 + + + + + 正交 + + + + + 属性编辑 + + + + + 联库信息 + + + + + 模型检查 + + + + + + 图层 + + + + + + + + + + + - + + + + + 图层显示 + + + + + 窗口 + + + + + 状态 + + + + + + 图层数量已达到最大值,不允许继续添加图层! + + + + + 图层%1 + + + + + 状态%1 + + + + + %1 - %2[*] + + + + + 当前图元名称已存在,不允许重复添加! + + + + + 请输入新建图库的名称 + + + + + + + + + 错误 + + + + + 图库名称不能为空! + + + + + 图库名称首字母不能为数字! + + + + + 图库名称首字母不能为空格! + + + + + 图库名称只支持中文、字母、数字和下划线 + + + + + 该图库名称已存在! + + + + + 图元状态数量已达到最大值,不允许继续添加图元状态! + + + + + 精灵图元编辑模式下不允许添加图层! + + + + + 图层数量至少为1,不允许继续删除图层! + + + + + 图元状态数量至少为1,不允许继续删除图元状态! + + + + + 精灵图元编辑模式下不允许删除图层! + + + + + 非图表图元暂不支持关联统计量! + + + + + CExplorerWnd + + + + + + + + 打开文件 + + + + + + + 提示 + + + + + 加密狗运行异常! + + + + + 加密狗检测正常! + + + + + 确认退出系统? + + + + + 确认 + + + + + 取消 + + + + + 编辑图形 + + + + + Ctrl+d + + + + + 加密狗状态 + + + + + Ctrl+R + + + + + 退出 + + + + + Ctrl+E + + + + + 导航图 + + + + + %1 - %2 + + + + + 导出图形 + + + + + 图形文件(*.png) + + + + + CFindReplace + + + 联库替换 + + + + + 已替换:%1个 + + + + + CFlowLine + + + + 潮流颜色 + + + + + + 潮流长度 + + + + + CGTableWidget + + + 导出xlsx文件为 + + + + + CGlobalConfigDialog + + + 全局变量 + + + + + + + + + + + - + + + + + 确定 + + + + + 取消 + + + + + 全局变量配置 + + + + + 描述 + + + + + 名称 + + + + + 类型 + + + + + 值 + + + + + 提示 + + + + + 保存失败! + + + + + 数值型 + + + + + 布尔型 + + + + + 字符串 + + + + + CGradientDialog + + + 填充配置 + + + + + CGraphApp + + + + + 提示 + + + + + 系统未启动! + + + + + 加密狗检测异常! + + + + + 加密狗运行异常! + + + + + CGraphDataAcess + + + 用户不具有指定权限 + + + + + 无用户登录信息 + + + + + 输入名称不存在 + + + + + 输入名称不唯一 + + + + + 不允许在该节点登录 + + + + + 密码错误 + + + + + 用户已失效 + + + + + 用户已锁定 + + + + + 用户不属于所选用户组 + + + + + 未知错误,系统可能未正常启动 + + + + + 未知错误 + + + + + 内存出错 + + + + + CGraphFileTree + + + 搜索... + + + + + 刷新 + + + + + CGraphView + + + + + 图幅 + + + + + + 标题 + + + + + + 背景色 + + + + + + 背景图片 + + + + + + 是否缩放 + + + + + + 是否拓扑 + + + + + + 自适应显示 + + + + + + 窗口标识 + + + + + + 发布类型 + + + + + + 图层显示 + + + + + + 窗口关闭按钮 + + + + + + 专业.位置 + + + + + + 模态 + + + + + CGridShape + + + 网格线颜色 + + + + + 网格填充颜色 + + + + + 交替填充颜色 + + + + + CHmiConfig + + + 页面配置 + + + + + 屏幕首页面 + + + + + 屏幕号 + + + + + 提示 + + + + + 保存失败! + + + + + CLayerDlg + + + 图层工具 + + + + + CLineEditWithBt + + + + 选择文件 + + + + + CPenDialog + + + Pen + + + + + 线宽: + + + + + 线型: + + + + + 预览 + + + + + 画笔配置 + + + + + + NoPen + + + + + + SolidLine + + + + + + DashLine + + + + + + DotLine + + + + + + DashDotLine + + + + + + DashDotDotLine + + + + + CPreviewForm + + + + + + + + + + + + + + + + + + + + + + + + + + 新建项目 + + + + + CQssEditor + + + 样式编辑器 + + + + + CRetriever + + + + 检索器 + + + + + + + + 专业: + + + + + + + + 位置: + + + + + + 设备组: + + + + + 表名: + + + + + 统计量模板: + + + + + 统计量 + + + + + 设备检索 + + + + + 多点关联 + + + + + 检索方式: + + + + + 表检索 + + + + + 设备组检索 + + + + + 点类型: + + + + + 值: + + + + + 点名: + + + + + 列名: + + + + + + 数字量 + + + + + + 模拟量 + + + + + + 混合量 + + + + + + 累积量 + + + + + + 常量 + + + + + + 通用 + + + + + + 其他 + + + + + 值 + + + + + 状态 + + + + + 时间 + + + + + CScreenShot + + + 保存图像 + + + + + 图形文件 (*.png) + + + + + CSearchDialog + + + 查找和替换 + + + + + CShape + + + 画笔 + + + + + 画刷 + + + + + %1 + + + + + + CShapeConfigDialog + + + 数据绑定 + + + + + 策略配置 + + + + + 着色策略配置 + + + + + 标签名称 + + + + + 文本内容 + + + + + + 确认 + + + + + + 取消 + + + + + + 清空 + + + + + 语法检查 + + + + + 函数代码 + + + + + 函数名称 + + + + + 新建 + + + + + 删除 + + + + + 复制 + + + + + 修改 + + + + + 添加行 + + + + + 删除行 + + + + + 函数编辑 + + + + + 策略名称: + + + + + 策略描述: + + + + + + + + + 提示 + + + + + 策略名称不能为空! + + + + + 策略描述不能为空! + + + + + 非法的命名 + + + + + 策略名称已经存在, 不能重复创建! + + + + + 策略名称不能以数字开头! + + + + + Error + + + + + Information + + + + + 语法正确, 脚本有效。 + + + + + 警告 + + + + + 当前未选中行! + + + + + CSpinBoxGroup + + + + 错误 + + + + + 的最小值不能超过最大值! + + + + + 的最大值不能小于最小值! + + + + + CStrategyConfigDelegate + + + 颜色选择 + + + + + CStrategyConfigModel + + + 合成值 + + + + + 线色 + + + + + 填充色 + + + + + 闪烁线色前景色 + + + + + 闪烁线色背景色 + + + + + 闪烁填充前景色 + + + + + 闪烁填充背景色 + + + + + 图元平面 + + + + + 是否闪烁 + + + + + 闪烁频率 + + + + + 是否显示 + + + + + 警告 + + + + + 当前合成值已经存在! + + + + + CTagSourceCfgDialog + + + + 数据源配置 + + + + + 取消 + + + + + 确定 + + + + + CTextReplacer + + + Dialog + + + + + 查找: + + + + + 替换为: + + + + + 替换 + + + + + 大小写匹配 + + + + + 文本替换 + + + + + CWebPublish + + + web发布 + + + + + + + 提示 + + + + + 只能在服务器上进行Web发布! + + + + + 发布成功! + + + + + 发布失败! + + + + + FilepathWidget + + + ... + + + + + + + 打开文件 + + + + + FindReplaceDlg + + + 联库替换 + 连库替换 + + + + + 连设备组 + + + + + 连位置 + + + + + 连设备 + + + + + 替换前: + + + + + 替换 + + + + + 替换后: + + + + + 关闭 + + + + + 整站连接 + + + + + 区分大小写 + + + + + FindWidget + + + Form + + + + + Find : + + + + + Find Next + + + + + Find Prev + + + + + Replace : + + + + + Replace + + + + + Replace All + + + + + Case Sensitive + + + + + Whole Words + + + + + GradientDialog + + + Dialog + + + + + Gradient + + + + + Fill Type: + + + + + Start Color + + + + + End Color + + + + + Preview + + + + + MainWindow + + + web发布 + + + + + 基础配置 + + + + + 下一步 + + + + + 首页配置 + + + + + 背景图片配置 + + + + + 权限验证 + + + + + 发布内容 + + + + + 画面/图元 + + + + + 图片 + + + + + 风格 + + + + + 发布 + + + + + 上一步 + + + + + PreviewForm + + + Form + + + + + QObject + + + + + 横向缩放比例 + + + + + + + 纵向缩放比例 + + + + + + 属性 + + + + + 值 + + + + + + 起始角度 + + + + + + 弧线角度 + + + + + 贝塞尔曲线 + + + + + 光字牌 + + + + + + 显示类型 + + + + + + + + + + + + + + + + + + + 宽高 + + + + + 数据长度 + + + + + + 小数点位数 + + + + + + 正负号显示 + + + + + + + + + + + 文本内容 + + + + + + + 水平居左 + + + + + + + 水平居中 + + + + + + + 水平居右 + + + + + + + 垂直居上 + + + + + + + 垂直居中 + + + + + + + 垂直居下 + + + + + + + 无边框 + + + + + + + 凸出边框 + + + + + + + 凹陷边框 + + + + + + + 平行边框 + + + + + 浮点型 + + + + + 整型 + + + + + 字符串 + + + + + 数字量文本 + + + + + 正常显示 + + + + + 显示负号 + + + + + 显示左右箭头 + + + + + 显示上下箭头 + + + + + + + + + + + + + + + + + 对象名称 + + + + + + + + + + + + + + + + + + + + 位置 + + + + + + + + + + + 旋转角度 + + + + + + + + + + 中心点旋转 + + + + + + + + + 字体 + + + + + + + + + + 字体颜色 + + + + + + + + + + + 背景颜色 + + + + + + + + 水平对齐方式 + + + + + + + + 垂直对齐方式 + + + + + + + + + + + + + + 是否显示 + + + + + + + + 边框样式 + + + + + + + + 边框颜色 + + + + + + + + 边框深度 + + + + + + + + + + + + + + + + + + 轴Z坐标 + + + + + + + + + + + + 着色策略 + + + + + + + + + + + + + + + + + + + + 透明度 + + + + + + x轴半径 + + + + + + y轴半径 + + + + + + + + 半径 + + + + + 网格线颜色 + + + + + 网格填充颜色 + + + + + 交替填充颜色 + + + + + + 交替填充 + + + + + + 行数量 + + + + + + 列数量 + + + + + + 设备组 + + + + + + 自适应模式 + + + + + 屏幕宽高比 + + + + + 图元宽高比 + + + + + + + + 起点箭头 + + + + + + + + 终点箭头 + + + + + 起点 + + + + + 终点 + + + + + 起点箭头外观 + + + + + 起点箭头大小 + + + + + 终点箭头外观 + + + + + 终点箭头大小 + + + + + + + + 调用图形 + + + + + + + + + 位图 + + + + + + 热键类型 + + + + + + + + + 图层显示 + + + + + + 水平方向 + + + + + + 竖直方向 + + + + + + 切换画面 + + + + + + 弹出画面 + + + + + + 程序调用 + + + + + + + 文字方向 + + + + + 箭头外观 + + + + + + 水平填充百分比 + + + + + + 垂直填充百分比 + + + + + + 矩形圆角 + + + + + + + 画笔 + + + + + + 画刷 + + + + + 脚本 + + + + + + 时间格式 + + + + + + 内容 + + + + + + 插件名 + + + + + + Tip提示信息 + + + + + + 图标 + + + + + + 图标宽高 + + + + + view_mode + + + + + + 调用资源 + + + + + + 动作类型 + + + + + + 组号 + + + + + + 选中 + + + + + + 类型 + + + + + 切换图层 + + + + + 切换导航 + + + + + 上一页 + + + + + 下一页 + + + + + 显示文本 + + + + + 显示密码 + + + + + 文本输入 + + + + + + 按钮 + + + + + 组合框 + + + + + 复选框 + + + + + 单选按钮 + + + + + 标签 + + + + + 列表框 + + + + + 数字输入 + + + + + 日期 + + + + + + 时间 + + + + + 树形 + + + + + 表格 + + + + + 插件 + + + + + 文本框 + + + + + 菜单 + + + + + + 图表标题 + + + + + + 标题颜色 + + + + + + 标题字体 + + + + + + 显示图例 + + + + + + 图例文字颜色 + + + + + + 图例文字字体 + + + + + + 显示背景 + + + + + + 轮廓颜色 + + + + + + 图例位置 + + + + + + + + 图表模式 + + + + + + 是否统计图表 + + + + + + 时间滚动 + + + + + + 项提示文本颜色 + + + + + + 项提示文本字体 + + + + + + + 项数量 + + + + + + 组数量 + + + + + + 棒描述 + + + + + + 棒颜色 + + + + + + 饼描述 + + + + + + 饼颜色 + + + + + + + 曲线数量 + + + + + + 曲线线宽 + + + + + + + + Y轴线颜色 + + + + + + + + Y轴标题 + + + + + + + + Y轴标题颜色 + + + + + + + + Y轴标题字体 + + + + + + + + Y轴最小值 + + + + + + + + Y轴最大值 + + + + + + + + Y轴刻度数 + + + + + + + + Y轴文字颜色 + + + + + + + + Y轴文字字体 + + + + + + + + 显示Y轴网格线 + + + + + + + + Y轴网格线 + + + + + + X轴格式 + + + + + + X轴跨度 + + + + + + + X轴刻度数 + + + + + + + + X轴线颜色 + + + + + + + + X轴文字颜色 + + + + + + + + X轴文字字体 + + + + + + + + X轴网格线 + + + + + + + + 显示X轴网格线 + + + + + + 刷新间隔 + + + + + + + 曲线描述 + + + + + + + 曲线颜色 + + + + + + 参考线数量 + + + + + + 参考线1 + + + + + + 参考线2 + + + + + + 参考线3 + + + + + + 自定义 + + + + + + + 日 + + + + + 月 + + + + + 年 + + + + + 左侧 + + + + + 顶部 + + + + + 右侧 + + + + + 底部 + + + + + + 潮流外观 + + + + + + 矩形 + + + + + 箭头 + + + + + 圆形 + + + + + 圆流 + + + + + + 显示端号 + + + + + + 方向性 + + + + + 圆弧 + + + + + 母线 + + + + + 多态文本 + + + + + 线端 + + + + + 自由连接线 + + + + + 带电区域 + + + + + 椭圆 + + + + + 圆 + + + + + 潮流线 + + + + + 网格 + + + + + 组合 + + + + + 直线 + + + + + 连接线 + + + + + 折线 + + + + + 端子 + + + + + 热键 + + + + + 多边形 + + + + + 告警提示 + + + + + 文本 + + + + + + + + + 提示 + + + + + 组合图元不可镜像! + + + + + 精灵图元不可镜像! + + + + + 控件图元不可镜像! + + + + + 图表图元不可镜像! + + + + + 存在重复设备:%1 + + + + + 图层0 + + + + + + 状态%1 + + + + + 组态页面 + + + + + 静态页面 + + + + + QPushButton::图层工具 + + + + + 文字编辑 + + + + + 确定 + + + + + 取消 + + + + + + 关系库 + + + + + + 时序库 + + + + + + 实时库 + + + + + 测点 + + + + + 数据源 + + + + + 查询语句 + + + + + 警告 + + + + + HMI正在运行 + + + + + QSMessageBox + + + 是 + + + + + 否 + + + + + QssEditor + + + 样式编辑器 + + + + + Ctrl+S + + + + + Ctrl+F + + + + + QtBoolEdit + + + + + True + + + + + + False + + + + + QtBoolPropertyManager + + + True + + + + + False + + + + + QtCharEdit + + + Clear Char + + + + + QtColorEditWidget + + + ... + + + + + QtColorPropertyManager + + + Red + + + + + Green + + + + + Blue + + + + + Alpha + + + + + QtCursorDatabase + + + Arrow + + + + + Up Arrow + + + + + Cross + + + + + Wait + + + + + IBeam + + + + + Size Vertical + + + + + Size Horizontal + + + + + Size Backslash + + + + + Size Slash + + + + + Size All + + + + + Blank + + + + + Split Vertical + + + + + Split Horizontal + + + + + Pointing Hand + + + + + Forbidden + + + + + Open Hand + + + + + Closed Hand + + + + + What's This + + + + + Busy + + + + + QtFontEditWidget + + + ... + + + + + 选择字体 + + + + + QtFontPropertyManager + + + Family + + + + + Point Size + + + + + Bold + + + + + Italic + + + + + Underline + + + + + Strikeout + + + + + Kerning + + + + + QtGradientDialog + + + + 编辑渐变 + + + + + 确认 + + + + + 取消 + + + + + QtGradientEditor + + + Form + + + + + Gradient Editor + + + + + This area shows a preview of the gradient being edited. It also allows you to edit parameters specific to the gradient's type such as start and final point, radius, etc. by drag & drop. + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + Gradient Stops Editor + + + + + This area allows you to edit gradient stops. Double click on the existing stop handle to duplicate it. Double click outside of the existing stop handles to create a new stop. Drag & drop the handle to reposition it. Use right mouse button to popup context menu with extra actions. + + + + + Zoom + + + + + + Reset Zoom + + + + + Position + + + + + + + Hue + + + + + H + + + + + + Saturation + + + + + S + + + + + Sat + + + + + + Value + + + + + V + + + + + Val + + + + + + + Alpha + + + + + A + + + + + Type + + + + + Spread + + + + + Color + + + + + Current stop's color + + + + + Show HSV specification + + + + + HSV + + + + + Show RGB specification + + + + + RGB + + + + + Current stop's position + + + + + % + + + + + Zoom In + + + + + Zoom Out + + + + + Toggle details extension + + + + + > + + + + + Linear Type + + + + + + + + + + ... + + + + + Radial Type + + + + + Conical Type + + + + + Pad Spread + + + + + Repeat Spread + + + + + Reflect Spread + + + + + Start X + + + + + Start Y + + + + + Final X + + + + + Final Y + + + + + + Central X + + + + + + Central Y + + + + + Focal X + + + + + Focal Y + + + + + Radius + + + + + Angle + + + + + Linear + + + + + Radial + + + + + Conical + + + + + Pad + + + + + Repeat + + + + + Reflect + + + + + QtGradientStopsWidget + + + New Stop + + + + + Delete + + + + + Flip All + + + + + Select All + + + + + Zoom In + + + + + Zoom Out + + + + + Reset Zoom + + + + + QtGradientViewDialogN + + + Dialog + + + + + 确认 + + + + + 取消 + + + + + Select Gradient + + + + + QtKeySequenceEdit + + + Clear Shortcut + + + + + QtLocalePropertyManager + + + %1, %2 + + + + + Language + + + + + Country + + + + + QtPointFPropertyManager + + + (%1, %2) + + + + + X + + + + + Y + + + + + QtPointPropertyManager + + + (%1, %2) + + + + + X + + + + + Y + + + + + QtPropertyBrowserUtils + + + [%1, %2, %3] (%4) + + + + + [%1, %2] + + + + + QtRectFPropertyManager + + + [(%1, %2), %3 x %4] + + + + + X + + + + + Y + + + + + Width + + + + + Height + + + + + QtRectPropertyManager + + + [(%1, %2), %3 x %4] + + + + + X + + + + + Y + + + + + Width + + + + + Height + + + + + QtSizeFPropertyManager + + + %1 x %2 + + + + + Width + + + + + Height + + + + + QtSizePolicyPropertyManager + + + + <Invalid> + + + + + [%1, %2, %3, %4] + + + + + Horizontal Policy + + + + + Vertical Policy + + + + + Horizontal Stretch + + + + + Vertical Stretch + + + + + QtSizePropertyManager + + + %1 x %2 + + + + + Width + + + + + Height + + + + + ScriptForm + + + 脚本编辑器 + + + + + Copy + + + + + Cut + + + + + Paste + + + + + Undo + + + + + Redo + + + + + ZoomIn + + + + + ZoomOut + + + + + Find && Replace + + + + + Script Syntax Check + + + + + F7 + + + + + + Warning + + + + + The program is incomplete. + + + + + Information + + + + + The program is correct. + + + + + Line: %1, Column: %2 + + + + + SearchDialog + + + 查找和替换 + + + + + 查找目标 + + + + + 下一个 + + + + + 替换为 + + + + + 全部替换 + + + + + qdesigner_internal::QtGradientStopsController + + + H + + + + + S + + + + + V + + + + + + Hue + + + + + Sat + + + + + Val + + + + + Saturation + + + + + Value + + + + + R + + + + + G + + + + + B + + + + + Red + + + + + Green + + + + + Blue + + + + + qtgradientviewn + + + Form + + + + + + 新建 + + + + + + 编辑 + + + + + + 重命名 + + + + + + + 移除 + + + + + 渐变 + + + + + 确认移除选中渐变? + + + + diff --git a/platform/src/include/application/app_fbd/fbd_common/FbdDiagOptCmdApi.h b/platform/src/include/application/app_fbd/fbd_common/FbdDiagOptCmdApi.h new file mode 100644 index 00000000..2f152e5f --- /dev/null +++ b/platform/src/include/application/app_fbd/fbd_common/FbdDiagOptCmdApi.h @@ -0,0 +1,148 @@ +/******************************************************************************** +* @file FbdDiagOptCmdApi.h +* @brief 功能块图(Diagram)控制接口 +* @author caodingfa +* @version 1.0 +* @date 2024/10/23 +**********************************************************************************/ + +#pragma once + +#include "FbdCommonExport.h" +#include "operate_server_api/JsonOptCommand.h" +#include "net_msg_bus_api/CMbCommunicator.h" + +namespace iot_app +{ +namespace app_fbd +{ +typedef boost::shared_ptr SOptCtrlReplyPtr; + +//< 功能块图(Diagram)控制接口,内部有锁,线程安全 +class CFbdDiagOptCmdApi +{ +public: + + virtual ~CFbdDiagOptCmdApi() = default; + + /******************************************************************************** + * @brief 取消字符串类型全局变量 + * @param strVarName 变量名 + * @return 成功返回iotSuccess,失败返回错误码 + **********************************************************************************/ + //virtual int unregGlobalStringVar(const std::string &strVarName) = 0; + + /********************************************************************************* + * @brief addSub添加订阅,支持通配。 + * @param[in] nAppID 应用ID,0通配所有应用。 + * @param[in] nChannelID 通道ID,0通配所有通道。 + * @return + * @retval 成功,返回true。 + * 失败,返回false。传入参数非法。 + **********************************************************************************/ + + + /********************************************************************************* + * @brief 获取通信器名称 + * @return 失败返回空字符串 + **********************************************************************************/ + virtual std::string getMbCommName() = 0; + + /********************************************************************************* + * @brief 订阅命令处理反馈通道,内部订阅了所有专业的CH_OPT_TO_HMI_OPTCMD_UP通道 + * @param[in] strInstName 实例名,用来实现引用计数的,所有图元取消订阅时销毁通信器。 + * @return + * @retval 成功,返回true。 + * 失败,返回false。 + **********************************************************************************/ + virtual bool subOptCtrlReplyTopic(const std::string &strInstName) = 0; + + /********************************************************************************* + * @brief 取消订阅命令处理反馈通道,所有图元取消订阅时销毁通信器 + * @param[in] strInstName 实例名,用来实现引用计数的,所有图元取消订阅时。 + * @return + * @retval 成功,返回true。 + * 失败,返回false。 + **********************************************************************************/ + virtual bool unsubOptCtrlReplyTopic(const std::string &strInstName) = 0; + + /********************************************************************************* + * @brief 获取指定图元的反馈消息 + * @param[in] strInstName 实例名,用来实现引用计数的,所有图元取消订阅时。 + * @return + * @retval 成功返回消息,无消息返回空。 + **********************************************************************************/ + virtual SOptCtrlReplyPtr getOptCtrlReply(const std::string &strInstName) = 0; + //消息中strHostName要求赋值为本节点名,strInstName要与subOptCtrlReplyTopic中一致 + + /********************************************************************************* + * @brief sendMsgToDomain发送消息给指定域的所有订阅者。 + * @details 指定域内的所有订阅了该消息主题(应用ID、通道ID)的通讯器将会收到该消息。 + * 非阻塞。 + * + * @param[in] msgSend 需要发送的消息,在发送前应先设置好内容,isValid()需为true。 + * 为减少内存复制,调用本函数后,msgSend的内容将被取走, + * msgSend的所有内容、属性将为空。 + * @param[in] nDomainID 目标域ID,默认-1为本域。 + * + * @return 本消息总线保证消息原子性,而非发送数据流,所以返回值为bool,而非发送字节数。 + * @retval 成功返回true,代表消息总线库已经接收消息发送请求,但并不代表已经成功送出。 + * 失败返回false,有可能是传入参数不正确,msgSend无效(isValid()为false), + * 或者是发送队列已满(比如与服务连接中断)。 + **********************************************************************************/ + virtual bool sendOptCtrReqToDomain(iot_net::CMbMessage &msgSend, const int nDomainID) = 0; + /********************************************************************************* + * @brief pushOptCtrlMessageCache + * @details 消息压入控制消息缓冲区异步发送 + * 非阻塞。 + * + * @param[in] msgSend 需要发送的控制消息 + * @param[in] diagName 消息所属的图表名。 + * @param[in] nAppId 控制点所属应用id。 + * @return + **********************************************************************************/ + virtual bool pushOptCtrlMessageCache(SOptCtrlRequest msgSend,const std::string diagName,const int nAppId) = 0; + /********************************************************************************* + * @brief trigerSendMessage + * @details 触发消息发送 + * 非阻塞。 + * + * @param[in] 图表名 + * @return + **********************************************************************************/ + virtual bool trigerSendMessage(const std::vector vecDiagName) = 0; + /********************************************************************************* + * @brief removeGroup + * @details 工作线程析构时调用 + * + * + * @param[in] 图表名 + * @return + **********************************************************************************/ + virtual bool removeGroup(const std::vector vecDiagName) = 0; + + /****************************************************************************** + * @brief sendMsgToDomain发送消息给指定域的所有订阅者,使用单例中的只发布不接收消息的通讯器 + * @details 指定域内的所有订阅了该消息主题(应用ID、通道ID)的通讯器将会收到该消息。 + * 非阻塞。 + * + * @param[in] msgSend 需要发送的消息,在发送前应先设置好内容,isValid()需为true。 + * 为减少内存复制,调用本函数后,msgSend的内容将被取走, + * msgSend的所有内容、属性将为空。 + * @param[in] nDomainID 目标域ID,默认-1为本域。 + * + * @return 本消息总线保证消息原子性,而非发送数据流,所以返回值为bool,而非发送字节数。 + * @retval 成功返回true,代表消息总线库已经接收消息发送请求,但并不代表已经成功送出。 + * 失败返回false,有可能是传入参数不正确,msgSend无效(isValid()为false), + * 或者是发送队列已满(比如与服务连接中断)。 + **********************************************************************************/ + virtual bool sendMsgToDomainByPublishCommunicator(iot_net::CMbMessage &msgSend, const int nDomainID )=0; +}; + +typedef boost::shared_ptr CFbdDiagOptCmdApiPtr; + +//< 获取单例对象,内部有锁,线程安全 +FBD_COMMON_API CFbdDiagOptCmdApiPtr getFbdDiagOptCmdApi(); + +} //< namespace app_fbd +} //< namespace iot_app diff --git a/platform/src/include/public/pub_excel/excellib.h b/platform/src/include/public/pub_excel/excellib.h new file mode 100644 index 00000000..fa6d4470 --- /dev/null +++ b/platform/src/include/public/pub_excel/excellib.h @@ -0,0 +1,13 @@ +#ifndef EXCELLIB_H +#define EXCELLIB_H + +#include "excellib_global.h" + +class EXCELLIBSHARED_EXPORT ExcelLib +{ + +public: + ExcelLib(); +}; + +#endif // EXCELLIB_H diff --git a/platform/src/include/public/pub_excel/excellib_global.h b/platform/src/include/public/pub_excel/excellib_global.h new file mode 100644 index 00000000..7f15a261 --- /dev/null +++ b/platform/src/include/public/pub_excel/excellib_global.h @@ -0,0 +1,12 @@ +#ifndef EXCELLIB_GLOBAL_H +#define EXCELLIB_GLOBAL_H + +#include + +#if defined(EXCELLIB_LIBRARY) +# define EXCELLIBSHARED_EXPORT Q_DECL_EXPORT +#else +# define EXCELLIBSHARED_EXPORT Q_DECL_IMPORT +#endif + +#endif // EXCELLIB_GLOBAL_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxabstractooxmlfile.cpp b/platform/src/include/public/pub_excel/xlsx/xlsxabstractooxmlfile.cpp new file mode 100644 index 00000000..36d15a02 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxabstractooxmlfile.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ + +#include "xlsxabstractooxmlfile.h" +#include "xlsxabstractooxmlfile_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE_XLSX + +AbstractOOXmlFilePrivate::AbstractOOXmlFilePrivate(AbstractOOXmlFile *q, AbstractOOXmlFile::CreateFlag flag=AbstractOOXmlFile::F_NewFromScratch) + :relationships(new Relationships), flag(flag), q_ptr(q) +{ + +} + +AbstractOOXmlFilePrivate::~AbstractOOXmlFilePrivate() +{ + +} + +/*! + * \internal + * + * \class AbstractOOXmlFile + * + * Base class of all the ooxml part file. + */ + +AbstractOOXmlFile::AbstractOOXmlFile(CreateFlag flag) + :d_ptr(new AbstractOOXmlFilePrivate(this, flag)) +{ +} + +AbstractOOXmlFile::AbstractOOXmlFile(AbstractOOXmlFilePrivate *d) + :d_ptr(d) +{ + +} + +AbstractOOXmlFile::~AbstractOOXmlFile() +{ + if (d_ptr->relationships) + delete d_ptr->relationships; + delete d_ptr; +} + +QByteArray AbstractOOXmlFile::saveToXmlData() const +{ + QByteArray data; + QBuffer buffer(&data); + buffer.open(QIODevice::WriteOnly); + saveToXmlFile(&buffer); + + return data; +} + +bool AbstractOOXmlFile::loadFromXmlData(const QByteArray &data) +{ + QBuffer buffer; + buffer.setData(data); + buffer.open(QIODevice::ReadOnly); + + return loadFromXmlFile(&buffer); +} + +/*! + * \internal + */ +void AbstractOOXmlFile::setFilePath(const QString path) +{ + Q_D(AbstractOOXmlFile); + d->filePathInPackage = path; +} + +/*! + * \internal + */ +QString AbstractOOXmlFile::filePath() const +{ + Q_D(const AbstractOOXmlFile); + return d->filePathInPackage; +} + + +/*! + * \internal + */ +Relationships *AbstractOOXmlFile::relationships() const +{ + Q_D(const AbstractOOXmlFile); + return d->relationships; +} + + +QT_END_NAMESPACE_XLSX diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxabstractooxmlfile.h b/platform/src/include/public/pub_excel/xlsx/xlsxabstractooxmlfile.h new file mode 100644 index 00000000..a5a791c2 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxabstractooxmlfile.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ + +#ifndef QXLSX_XLSXABSTRACTOOXMLFILE_H +#define QXLSX_XLSXABSTRACTOOXMLFILE_H + +#include "xlsxglobal.h" + +class QIODevice; +class QByteArray; + +QT_BEGIN_NAMESPACE_XLSX +class Relationships; +class AbstractOOXmlFilePrivate; + +class Q_XLSX_EXPORT AbstractOOXmlFile +{ + Q_DECLARE_PRIVATE(AbstractOOXmlFile) +public: + enum CreateFlag + { + F_NewFromScratch, + F_LoadFromExists + }; + + virtual ~AbstractOOXmlFile(); + + virtual void saveToXmlFile(QIODevice *device) const = 0; + virtual bool loadFromXmlFile(QIODevice *device) = 0; + + virtual QByteArray saveToXmlData() const; + virtual bool loadFromXmlData(const QByteArray &data); + + Relationships *relationships() const; + + void setFilePath(const QString path); + QString filePath() const; + +protected: + AbstractOOXmlFile(CreateFlag flag); + AbstractOOXmlFile(AbstractOOXmlFilePrivate *d); + + AbstractOOXmlFilePrivate *d_ptr; +}; + +QT_END_NAMESPACE_XLSX + +#endif // QXLSX_XLSXABSTRACTOOXMLFILE_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxabstractooxmlfile_p.h b/platform/src/include/public/pub_excel/xlsx/xlsxabstractooxmlfile_p.h new file mode 100644 index 00000000..a1a2e609 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxabstractooxmlfile_p.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ + +#ifndef XLSXOOXMLFILE_P_H +#define XLSXOOXMLFILE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Xlsx API. It exists for the convenience +// of the Qt Xlsx. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "xlsxabstractooxmlfile.h" +#include "xlsxrelationships_p.h" + +#include + +QT_BEGIN_NAMESPACE_XLSX + +class XLSX_AUTOTEST_EXPORT AbstractOOXmlFilePrivate +{ + Q_DECLARE_PUBLIC(AbstractOOXmlFile) + +public: + AbstractOOXmlFilePrivate(AbstractOOXmlFile *q, AbstractOOXmlFile::CreateFlag flag); + virtual ~AbstractOOXmlFilePrivate(); + + QString filePathInPackage;//such as "xl/worksheets/sheet1.xml" + //used when load the .xlsx file + Relationships *relationships; + AbstractOOXmlFile::CreateFlag flag; + AbstractOOXmlFile *q_ptr; +}; + +QT_END_NAMESPACE_XLSX + +#endif // XLSXOOXMLFILE_P_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxabstractsheet.cpp b/platform/src/include/public/pub_excel/xlsx/xlsxabstractsheet.cpp new file mode 100644 index 00000000..2cf6eeeb --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxabstractsheet.cpp @@ -0,0 +1,206 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#include "xlsxabstractsheet.h" +#include "xlsxabstractsheet_p.h" +#include "xlsxworkbook.h" + +QT_BEGIN_NAMESPACE_XLSX + +AbstractSheetPrivate::AbstractSheetPrivate(AbstractSheet *p, AbstractSheet::CreateFlag flag) + : AbstractOOXmlFilePrivate(p, flag) +{ + type = AbstractSheet::ST_WorkSheet; + sheetState = AbstractSheet::SS_Visible; +} + +AbstractSheetPrivate::~AbstractSheetPrivate() +{ +} + +/*! + \class AbstractSheet + \inmodule QtXlsx + \brief Base class for worksheet, chartsheet, etc. +*/ + +/*! + \enum AbstractSheet::SheetType + + \value ST_WorkSheet + \value ST_ChartSheet + \omitvalue ST_DialogSheet + \omitvalue ST_MacroSheet +*/ + +/*! + \enum AbstractSheet::SheetState + + \value SS_Visible + \value SS_Hidden + \value SS_VeryHidden User cann't make a veryHidden sheet visible in normal way. +*/ + +/*! + \fn AbstractSheet::copy(const QString &distName, int distId) const + + Copies the current sheet to a sheet called \a distName with \a distId. + Returns the new sheet. + */ + +/*! + * \internal + */ +AbstractSheet::AbstractSheet(const QString &name, int id, Workbook *workbook, AbstractSheetPrivate *d) : + AbstractOOXmlFile(d) +{ + d_func()->name = name; + d_func()->id = id; + d_func()->workbook = workbook; +} + + +/*! + * Returns the name of the sheet. + */ +QString AbstractSheet::sheetName() const +{ + Q_D(const AbstractSheet); + return d->name; +} + +/*! + * \internal + */ +void AbstractSheet::setSheetName(const QString &sheetName) +{ + Q_D(AbstractSheet); + d->name = sheetName; +} + +/*! + * Returns the type of the sheet. + */ +AbstractSheet::SheetType AbstractSheet::sheetType() const +{ + Q_D(const AbstractSheet); + return d->type; +} + +/*! + * \internal + */ +void AbstractSheet::setSheetType(SheetType type) +{ + Q_D(AbstractSheet); + d->type = type; +} + +/*! + * Returns the state of the sheet. + * + * \sa isHidden(), isVisible(), setSheetState() + */ +AbstractSheet::SheetState AbstractSheet::sheetState() const +{ + Q_D(const AbstractSheet); + return d->sheetState; +} + +/*! + * Set the state of the sheet to \a state. + */ +void AbstractSheet::setSheetState(SheetState state) +{ + Q_D(AbstractSheet); + d->sheetState = state; +} + +/*! + * Returns true if the sheet is not visible, otherwise false will be returned. + * + * \sa sheetState(), setHidden() + */ +bool AbstractSheet::isHidden() const +{ + Q_D(const AbstractSheet); + return d->sheetState != SS_Visible; +} + +/*! + * Returns true if the sheet is visible. + */ +bool AbstractSheet::isVisible() const +{ + return !isHidden(); +} + +/*! + * Make the sheet hiden or visible based on \a hidden. + */ +void AbstractSheet::setHidden(bool hidden) +{ + Q_D(AbstractSheet); + if (hidden == isHidden()) + return; + + d->sheetState = hidden ? SS_Hidden : SS_Visible; +} + +/*! + * Convenience function, equivalent to setHidden(! \a visible). + */ +void AbstractSheet::setVisible(bool visible) +{ + setHidden(!visible); +} + +/*! + * \internal + */ +int AbstractSheet::sheetId() const +{ + Q_D(const AbstractSheet); + return d->id; +} + +/*! + * \internal + */ +Drawing *AbstractSheet::drawing() const +{ + Q_D(const AbstractSheet); + return d->drawing.data(); +} + +/*! + * Return the workbook + */ +Workbook *AbstractSheet::workbook() const +{ + Q_D(const AbstractSheet); + return d->workbook; +} + +QT_END_NAMESPACE_XLSX diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxabstractsheet.h b/platform/src/include/public/pub_excel/xlsx/xlsxabstractsheet.h new file mode 100644 index 00000000..7aa416dc --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxabstractsheet.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#ifndef XLSXABSTRACTSHEET_H +#define XLSXABSTRACTSHEET_H + +#include "xlsxabstractooxmlfile.h" +#include +#include + +QT_BEGIN_NAMESPACE_XLSX +class Workbook; +class Drawing; +class AbstractSheetPrivate; +class Q_XLSX_EXPORT AbstractSheet : public AbstractOOXmlFile +{ + Q_DECLARE_PRIVATE(AbstractSheet) +public: + enum SheetType { + ST_WorkSheet, + ST_ChartSheet, + ST_DialogSheet, + ST_MacroSheet + }; + + enum SheetState { + SS_Visible, + SS_Hidden, + SS_VeryHidden + }; + + QString sheetName() const; + SheetType sheetType() const; + SheetState sheetState() const; + void setSheetState(SheetState ss); + bool isHidden() const; + bool isVisible() const; + void setHidden(bool hidden); + void setVisible(bool visible); + + Workbook *workbook() const; + +protected: + friend class Workbook; + AbstractSheet(const QString &sheetName, int sheetId, Workbook *book, AbstractSheetPrivate *d); + virtual AbstractSheet *copy(const QString &distName, int distId) const = 0; + void setSheetName(const QString &sheetName); + void setSheetType(SheetType type); + int sheetId() const; + + Drawing *drawing() const; +}; + +QT_END_NAMESPACE_XLSX +#endif // XLSXABSTRACTSHEET_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxabstractsheet_p.h b/platform/src/include/public/pub_excel/xlsx/xlsxabstractsheet_p.h new file mode 100644 index 00000000..7d0f3446 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxabstractsheet_p.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#ifndef XLSXABSTRACTSHEET_P_H +#define XLSXABSTRACTSHEET_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Xlsx API. It exists for the convenience +// of the Qt Xlsx. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "xlsxglobal.h" +#include "xlsxabstractsheet.h" +#include "xlsxabstractooxmlfile_p.h" + +#include + +namespace QXlsx { + +class XLSX_AUTOTEST_EXPORT AbstractSheetPrivate : public AbstractOOXmlFilePrivate +{ + Q_DECLARE_PUBLIC(AbstractSheet) +public: + AbstractSheetPrivate(AbstractSheet *p, AbstractSheet::CreateFlag flag); + ~AbstractSheetPrivate(); + + Workbook *workbook; + QSharedPointer drawing; + + QString name; + int id; + AbstractSheet::SheetState sheetState; + AbstractSheet::SheetType type; +}; + +} +#endif // XLSXABSTRACTSHEET_P_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxcell.cpp b/platform/src/include/public/pub_excel/xlsx/xlsxcell.cpp new file mode 100644 index 00000000..fcaf7a6b --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxcell.cpp @@ -0,0 +1,178 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#include "xlsxcell.h" +#include "xlsxcell_p.h" +#include "xlsxformat.h" +#include "xlsxformat_p.h" +#include "xlsxutility_p.h" +#include "xlsxworksheet.h" +#include "xlsxworkbook.h" +#include + +QT_BEGIN_NAMESPACE_XLSX + +CellPrivate::CellPrivate(Cell *p) : + q_ptr(p) +{ + +} + +CellPrivate::CellPrivate(const CellPrivate * const cp) + : value(cp->value), formula(cp->formula), cellType(cp->cellType) + , format(cp->format), richString(cp->richString), parent(cp->parent) +{ + +} + +/*! + \class Cell + \inmodule QtXlsx + \brief The Cell class provides a API that is used to handle the worksheet cell. + +*/ + +/*! + \enum Cell::CellType + \value BooleanType Boolean type + \value NumberType Number type, can be blank or used with forumula + \value ErrorType Error type + \value SharedStringType Shared string type + \value StringType String type, can be used with forumula + \value InlineStringType Inline string type + */ + +/*! + * \internal + * Created by Worksheet only. + */ +Cell::Cell(const QVariant &data, CellType type, const Format &format, Worksheet *parent) : + d_ptr(new CellPrivate(this)) +{ + d_ptr->value = data; + d_ptr->cellType = type; + d_ptr->format = format; + d_ptr->parent = parent; +} + +/*! + * \internal + */ +Cell::Cell(const Cell * const cell): + d_ptr(new CellPrivate(cell->d_ptr)) +{ + d_ptr->q_ptr = this; +} + +/*! + * Destroys the Cell and cleans up. + */ +Cell::~Cell() +{ + delete d_ptr; +} + +/*! + * Return the dataType of this Cell + */ +Cell::CellType Cell::cellType() const +{ + Q_D(const Cell); + return d->cellType; +} + +/*! + * Return the data content of this Cell + */ +QVariant Cell::value() const +{ + Q_D(const Cell); + return d->value; +} + +/*! + * Return the style used by this Cell. If no style used, 0 will be returned. + */ +Format Cell::format() const +{ + Q_D(const Cell); + return d->format; +} + +/*! + * Returns true if the cell has one formula. + */ +bool Cell::hasFormula() const +{ + Q_D(const Cell); + return d->formula.isValid(); +} + +/*! + * Return the formula contents if the dataType is Formula + */ +CellFormula Cell::formula() const +{ + Q_D(const Cell); + return d->formula; +} + +/*! + * Returns whether the value is probably a dateTime or not + */ +bool Cell::isDateTime() const +{ + Q_D(const Cell); + if (d->cellType == NumberType && d->value.toDouble() >=0 + && d->format.isValid() && d->format.isDateTimeFormat()) { + return true; + } + return false; +} + +/*! + * Return the data time value. + */ +QDateTime Cell::dateTime() const +{ + Q_D(const Cell); + if (!isDateTime()) + return QDateTime(); + return datetimeFromNumber(d->value.toDouble(), d->parent->workbook()->isDate1904()); +} + +/*! + * Returns whether the cell is probably a rich string or not + */ +bool Cell::isRichString() const +{ + Q_D(const Cell); + if (d->cellType != SharedStringType && d->cellType != InlineStringType + && d->cellType != StringType) + return false; + + return d->richString.isRichString(); +} + +QT_END_NAMESPACE_XLSX diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxcell.h b/platform/src/include/public/pub_excel/xlsx/xlsxcell.h new file mode 100644 index 00000000..7aec8ced --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxcell.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#ifndef QXLSX_XLSXCELL_H +#define QXLSX_XLSXCELL_H + +#include "xlsxglobal.h" +#include "xlsxformat.h" +#include + +QT_BEGIN_NAMESPACE_XLSX + +class Worksheet; +class Format; +class CellFormula; +class CellPrivate; +class WorksheetPrivate; + +class Q_XLSX_EXPORT Cell +{ + Q_DECLARE_PRIVATE(Cell) +public: + enum CellType { + BooleanType, //t="b" + NumberType, //t="n" (default) + ErrorType, //t="e" + SharedStringType, //t="s" + StringType, //t="str" + InlineStringType //t="inlineStr" + }; + + CellType cellType() const; + QVariant value() const; + Format format() const; + + bool hasFormula() const; + CellFormula formula() const; + + bool isDateTime() const; + QDateTime dateTime() const; + + bool isRichString() const; + + ~Cell(); +private: + friend class Worksheet; + friend class WorksheetPrivate; + + Cell(const QVariant &data=QVariant(), CellType type=NumberType, const Format &format=Format(), Worksheet *parent=0); + Cell(const Cell * const cell); + CellPrivate * const d_ptr; +}; + +QT_END_NAMESPACE_XLSX + +#endif // QXLSX_XLSXCELL_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxcell_p.h b/platform/src/include/public/pub_excel/xlsx/xlsxcell_p.h new file mode 100644 index 00000000..b537ff24 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxcell_p.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#ifndef XLSXCELL_P_H +#define XLSXCELL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Xlsx API. It exists for the convenience +// of the Qt Xlsx. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "xlsxglobal.h" +#include "xlsxcell.h" +#include "xlsxcellrange.h" +#include "xlsxrichstring.h" +#include "xlsxcellformula.h" +#include +#include + +QT_BEGIN_NAMESPACE_XLSX + +class CellPrivate +{ + Q_DECLARE_PUBLIC(Cell) +public: + CellPrivate(Cell *p); + CellPrivate(const CellPrivate * const cp); + + QVariant value; + CellFormula formula; + Cell::CellType cellType; + Format format; + + RichString richString; + + Worksheet *parent; + Cell *q_ptr; +}; + +QT_END_NAMESPACE_XLSX + +#endif // XLSXCELL_P_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxcellformula.cpp b/platform/src/include/public/pub_excel/xlsx/xlsxcellformula.cpp new file mode 100644 index 00000000..858d3479 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxcellformula.cpp @@ -0,0 +1,259 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#include "xlsxcellformula.h" +#include "xlsxcellformula_p.h" +#include "xlsxutility_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE_XLSX + +CellFormulaPrivate::CellFormulaPrivate(const QString &formula_, const CellRange &ref_, CellFormula::FormulaType type_) + :formula(formula_), type(type_), reference(ref_), ca(false), si(0) +{ + //Remove the formula '=' sign if exists + if (formula.startsWith(QLatin1String("="))) + formula.remove(0,1); + else if (formula.startsWith(QLatin1String("{=")) && formula.endsWith(QLatin1String("}"))) + formula = formula.mid(2, formula.length()-3); +} + +CellFormulaPrivate::CellFormulaPrivate(const CellFormulaPrivate &other) + : QSharedData(other) + , formula(other.formula), type(other.type), reference(other.reference) + , ca(other.ca), si(other.si) +{ + +} + +CellFormulaPrivate::~CellFormulaPrivate() +{ + +} + +/*! + \class CellFormula + \inmodule QtXlsx + \brief The CellFormula class provides a API that is used to handle the cell formula. + +*/ + +/*! + \enum CellFormula::FormulaType + \value NormalType + \value ArrayType + \value DataTableType + \value SharedType +*/ + +/*! + * Creates a new formula. + */ +CellFormula::CellFormula() +{ + //The d pointer is initialized with a null pointer +} + +/*! + * Creates a new formula with the given \a formula and \a type. + */ +CellFormula::CellFormula(const char *formula, FormulaType type) + :d(new CellFormulaPrivate(QString::fromLatin1(formula), CellRange(), type)) +{ + +} + +/*! + * Creates a new formula with the given \a formula and \a type. + */ +CellFormula::CellFormula(const QString &formula, FormulaType type) + :d(new CellFormulaPrivate(formula, CellRange(), type)) +{ + +} + +/*! + * Creates a new formula with the given \a formula, \a ref and \a type. + */ +CellFormula::CellFormula(const QString &formula, const CellRange &ref, FormulaType type) + :d(new CellFormulaPrivate(formula, ref, type)) +{ + +} + +/*! + Creates a new formula with the same attributes as the \a other formula. + */ +CellFormula::CellFormula(const CellFormula &other) + :d(other.d) +{ +} + +/*! + Assigns the \a other formula to this formula, and returns a + reference to this formula. + */ +CellFormula &CellFormula::operator =(const CellFormula &other) +{ + d = other.d; + return *this; +} + +/*! + * Destroys this formula. + */ +CellFormula::~CellFormula() +{ + +} + +/*! + * Returns the type of the formula. + */ +CellFormula::FormulaType CellFormula::formulaType() const +{ + return d ? d->type : NormalType; +} + +/*! + * Returns the contents of the formula. + */ +QString CellFormula::formulaText() const +{ + return d ? d->formula : QString(); +} + +/*! + * Returns the reference cells of the formula. For normal formula, + * this will return an invalid CellRange object. + */ +CellRange CellFormula::reference() const +{ + return d ? d->reference : CellRange(); +} + +/*! + * Returns whether the formula is valid. + */ +bool CellFormula::isValid() const +{ + return d; +} + +/*! + * Returns the shared index for shared formula. + */ +int CellFormula::sharedIndex() const +{ + return d && d->type == SharedType ? d->si : -1; +} + +/*! + * \internal + */ +bool CellFormula::saveToXml(QXmlStreamWriter &writer) const +{ + writer.writeStartElement(QStringLiteral("f")); + QString t; + switch (d->type) { + case CellFormula::ArrayType: + t = QStringLiteral("array"); + break; + case CellFormula::SharedType: + t = QStringLiteral("shared"); + break; + default: + break; + } + if (!t.isEmpty()) + writer.writeAttribute(QStringLiteral("t"), t); + if (d->reference.isValid()) + writer.writeAttribute(QStringLiteral("ref"), d->reference.toString()); + if (d->ca) + writer.writeAttribute(QStringLiteral("ca"), QStringLiteral("1")); + if (d->type == CellFormula::SharedType) + writer.writeAttribute(QStringLiteral("si"), QString::number(d->si)); + + if (!d->formula.isEmpty()) + writer.writeCharacters(d->formula); + + writer.writeEndElement(); //f + + return true; +} + +/*! + * \internal + */ +bool CellFormula::loadFromXml(QXmlStreamReader &reader) +{ + Q_ASSERT(reader.name() == QLatin1String("f")); + if (!d) + d = new CellFormulaPrivate(QString(), CellRange(), NormalType); + + QXmlStreamAttributes attributes = reader.attributes(); + QString typeString = attributes.value(QLatin1String("t")).toString(); + if (typeString == QLatin1String("array")) + d->type = ArrayType; + else if (typeString == QLatin1String("shared")) + d->type = SharedType; + else + d->type = NormalType; + + if (attributes.hasAttribute(QLatin1String("ref"))) { + QString refString = attributes.value(QLatin1String("ref")).toString(); + d->reference = CellRange(refString); + } + + QString ca = attributes.value(QLatin1String("si")).toString(); + d->ca = parseXsdBoolean(ca, false); + + if (attributes.hasAttribute(QLatin1String("si"))) + d->si = attributes.value(QLatin1String("si")).toString().toInt(); + + d->formula = reader.readElementText(); + return true; +} + +/*! + * \internal + */ +bool CellFormula::operator ==(const CellFormula &formula) const +{ + return d->formula == formula.d->formula && d->type == formula.d->type + && d->si ==formula.d->si; +} + +/*! + * \internal + */ +bool CellFormula::operator !=(const CellFormula &formula) const +{ + return d->formula != formula.d->formula || d->type != formula.d->type + || d->si !=formula.d->si; +} + +QT_END_NAMESPACE_XLSX diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxcellformula.h b/platform/src/include/public/pub_excel/xlsx/xlsxcellformula.h new file mode 100644 index 00000000..0d4679b5 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxcellformula.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#ifndef QXLSX_XLSXCELLFORMULA_H +#define QXLSX_XLSXCELLFORMULA_H + +#include "xlsxglobal.h" +#include + +class QXmlStreamWriter; +class QXmlStreamReader; + +QT_BEGIN_NAMESPACE_XLSX + +class CellFormulaPrivate; +class CellRange; +class Worksheet; +class WorksheetPrivate; + +class Q_XLSX_EXPORT CellFormula +{ +public: + enum FormulaType { + NormalType, + ArrayType, + DataTableType, + SharedType + }; + + CellFormula(); + CellFormula(const char *formula, FormulaType type=NormalType); + CellFormula(const QString &formula, FormulaType type=NormalType); + CellFormula(const QString &formula, const CellRange &ref, FormulaType type); + CellFormula(const CellFormula &other); + ~CellFormula(); + CellFormula &operator =(const CellFormula &other); + bool isValid() const; + + FormulaType formulaType() const; + QString formulaText() const; + CellRange reference() const; + int sharedIndex() const; + + bool operator == (const CellFormula &formula) const; + bool operator != (const CellFormula &formula) const; + + bool saveToXml(QXmlStreamWriter &writer) const; + bool loadFromXml(QXmlStreamReader &reader); +private: + friend class Worksheet; + friend class WorksheetPrivate; + QExplicitlySharedDataPointer d; +}; + +QT_END_NAMESPACE_XLSX + +#endif // QXLSX_XLSXCELLFORMULA_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxcellformula_p.h b/platform/src/include/public/pub_excel/xlsx/xlsxcellformula_p.h new file mode 100644 index 00000000..6aeddc92 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxcellformula_p.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#ifndef XLSXCELLFORMULA_P_H +#define XLSXCELLFORMULA_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Xlsx API. It exists for the convenience +// of the Qt Xlsx. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "xlsxglobal.h" +#include "xlsxcellformula.h" +#include "xlsxcellrange.h" + +#include +#include + +QT_BEGIN_NAMESPACE_XLSX + +class CellFormulaPrivate : public QSharedData +{ +public: + CellFormulaPrivate(const QString &formula, const CellRange &reference, CellFormula::FormulaType type); + CellFormulaPrivate(const CellFormulaPrivate &other); + ~CellFormulaPrivate(); + + QString formula; //formula contents + CellFormula::FormulaType type; + CellRange reference; + bool ca; //Calculate Cell + int si; //Shared group index +}; + +QT_END_NAMESPACE_XLSX + +#endif // XLSXCELLFORMULA_P_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxcellrange.cpp b/platform/src/include/public/pub_excel/xlsx/xlsxcellrange.cpp new file mode 100644 index 00000000..6251ab7a --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxcellrange.cpp @@ -0,0 +1,147 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#include "xlsxcellrange.h" +#include "xlsxcellreference.h" +#include +#include +#include + +QT_BEGIN_NAMESPACE_XLSX + +/*! + \class CellRange + \brief For a range "A1:B2" or single cell "A1" + \inmodule QtXlsx + + The CellRange class stores the top left and bottom + right rows and columns of a range in a worksheet. +*/ + +/*! + Constructs an range, i.e. a range + whose rowCount() and columnCount() are 0. +*/ +CellRange::CellRange() + : top(-1), left(-1), bottom(-2), right(-2) +{ +} + +/*! + Constructs the range from the given \a top, \a + left, \a bottom and \a right rows and columns. + + \sa topRow(), leftColumn(), bottomRow(), rightColumn() +*/ +CellRange::CellRange(int top, int left, int bottom, int right) + : top(top), left(left), bottom(bottom), right(right) +{ +} + +CellRange::CellRange(const CellReference &topLeft, const CellReference &bottomRight) + : top(topLeft.row()), left(topLeft.column()) + , bottom(bottomRight.row()), right(bottomRight.column()) +{ +} + +/*! + \overload + Constructs the range form the given \a range string. +*/ +CellRange::CellRange(const QString &range) +{ + init(range); +} + +/*! + \overload + Constructs the range form the given \a range string. +*/ +CellRange::CellRange(const char *range) +{ + init(QString::fromLatin1(range)); +} + +void CellRange::init(const QString &range) +{ + QStringList rs = range.split(QLatin1Char(':')); + if (rs.size() == 2) { + CellReference start(rs[0]); + CellReference end(rs[1]); + top = start.row(); + left = start.column(); + bottom = end.row(); + right = end.column(); + } else { + CellReference p(rs[0]); + top = p.row(); + left = p.column(); + bottom = p.row(); + right = p.column(); + } +} + +/*! + Constructs a the range by copying the given \a + other range. +*/ +CellRange::CellRange(const CellRange &other) + : top(other.top), left(other.left), bottom(other.bottom), right(other.right) +{ +} + +/*! + Destroys the range. +*/ +CellRange::~CellRange() +{ +} + +/*! + Convert the range to string notation, such as "A1:B5". +*/ +QString CellRange::toString(bool row_abs, bool col_abs) const +{ + if (!isValid()) + return QString(); + + if (left == right && top == bottom) { + //Single cell + return CellReference(top, left).toString(row_abs, col_abs); + } + + QString cell_1 = CellReference(top, left).toString(row_abs, col_abs); + QString cell_2 = CellReference(bottom, right).toString(row_abs, col_abs); + return cell_1 + QLatin1String(":") + cell_2; +} + +/*! + * Returns true if the Range is valid. + */ +bool CellRange::isValid() const +{ + return left <= right && top <= bottom; +} + +QT_END_NAMESPACE_XLSX diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxcellrange.h b/platform/src/include/public/pub_excel/xlsx/xlsxcellrange.h new file mode 100644 index 00000000..5a510b05 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxcellrange.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#ifndef QXLSX_XLSXCELLRANGE_H +#define QXLSX_XLSXCELLRANGE_H +#include "xlsxglobal.h" +#include "xlsxcellreference.h" + +QT_BEGIN_NAMESPACE_XLSX + +class Q_XLSX_EXPORT CellRange +{ +public: + CellRange(); + CellRange(int firstRow, int firstColumn, int lastRow, int lastColumn); + CellRange(const CellReference &topLeft, const CellReference &bottomRight); + CellRange(const QString &range); + CellRange(const char *range); + CellRange(const CellRange &other); + ~CellRange(); + + QString toString(bool row_abs=false, bool col_abs=false) const; + bool isValid() const; + inline void setFirstRow(int row) { top = row; } + inline void setLastRow(int row) { bottom = row; } + inline void setFirstColumn(int col) { left = col; } + inline void setLastColumn(int col) { right = col; } + inline int firstRow() const { return top; } + inline int lastRow() const { return bottom; } + inline int firstColumn() const { return left; } + inline int lastColumn() const { return right; } + inline int rowCount() const { return bottom - top + 1; } + inline int columnCount() const { return right - left + 1; } + inline CellReference topLeft() const { return CellReference(top, left); } + inline CellReference topRight() const { return CellReference(top, right); } + inline CellReference bottomLeft() const { return CellReference(bottom, left); } + inline CellReference bottomRight() const { return CellReference(bottom, right); } + + inline bool operator ==(const CellRange &other) const + { + return top==other.top && bottom==other.bottom + && left == other.left && right == other.right; + } + inline bool operator !=(const CellRange &other) const + { + return top!=other.top || bottom!=other.bottom + || left != other.left || right != other.right; + } +private: + void init(const QString &range); + int top, left, bottom, right; +}; + +QT_END_NAMESPACE_XLSX + +Q_DECLARE_TYPEINFO(QXlsx::CellRange, Q_MOVABLE_TYPE); + +#endif // QXLSX_XLSXCELLRANGE_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxcellreference.cpp b/platform/src/include/public/pub_excel/xlsx/xlsxcellreference.cpp new file mode 100644 index 00000000..e7cf5da9 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxcellreference.cpp @@ -0,0 +1,174 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#include "xlsxcellreference.h" +#include +#include +#include + +QT_BEGIN_NAMESPACE_XLSX + +namespace { + +int intPow(int x, int p) +{ + if (p == 0) return 1; + if (p == 1) return x; + + int tmp = intPow(x, p/2); + if (p%2 == 0) return tmp * tmp; + else return x * tmp * tmp; +} + +QString col_to_name(int col_num) +{ + static QMap col_cache; + + if (!col_cache.contains(col_num)) { + QString col_str; + int remainder; + while (col_num) { + remainder = col_num % 26; + if (remainder == 0) + remainder = 26; + col_str.prepend(QChar('A'+remainder-1)); + col_num = (col_num - 1) / 26; + } + col_cache.insert(col_num, col_str); + } + + return col_cache[col_num]; +} + +int col_from_name(const QString &col_str) +{ + int col = 0; + int expn = 0; + for (int i=col_str.size()-1; i>-1; --i) { + col += (col_str[i].unicode() - 'A' + 1) * intPow(26, expn); + expn++; + } + + return col; +} +} //namespace + +/*! + \class CellReference + \brief For one single cell such as "A1" + \inmodule QtXlsx + + The CellReference class stores the cell location in a worksheet. +*/ + +/*! + Constructs an invalid Cell Reference +*/ +CellReference::CellReference() + : _row(-1), _column(-1) +{ +} + +/*! + Constructs the Reference from the given \a row, and \a column. +*/ +CellReference::CellReference(int row, int column) + : _row(row), _column(column) +{ +} + +/*! + \overload + Constructs the Reference form the given \a cell string. +*/ +CellReference::CellReference(const QString &cell) +{ + init(cell); +} + +/*! + \overload + Constructs the Reference form the given \a cell string. +*/ +CellReference::CellReference(const char *cell) +{ + init(QString::fromLatin1(cell)); +} + +void CellReference::init(const QString &cell_str) +{ + static QRegularExpression re(QStringLiteral("^\\$?([A-Z]{1,3})\\$?(\\d+)$")); + QRegularExpressionMatch match = re.match(cell_str); + if (match.hasMatch()) { + const QString col_str = match.captured(1); + const QString row_str = match.captured(2); + _row = row_str.toInt(); + _column = col_from_name(col_str); + } +} + +/*! + Constructs a Reference by copying the given \a + other Reference. +*/ +CellReference::CellReference(const CellReference &other) + : _row(other._row), _column(other._column) +{ +} + +/*! + Destroys the Reference. +*/ +CellReference::~CellReference() +{ +} + +/*! + Convert the Reference to string notation, such as "A1" or "$A$1". + If current object is invalid, an empty string will be returned. +*/ +QString CellReference::toString(bool row_abs, bool col_abs) const +{ + if (!isValid()) + return QString(); + + QString cell_str; + if (col_abs) + cell_str.append(QLatin1Char('$')); + cell_str.append(col_to_name(_column)); + if (row_abs) + cell_str.append(QLatin1Char('$')); + cell_str.append(QString::number(_row)); + return cell_str; +} + +/*! + * Returns true if the Reference is valid. + */ +bool CellReference::isValid() const +{ + return _row > 0 && _column > 0; +} + +QT_END_NAMESPACE_XLSX diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxcellreference.h b/platform/src/include/public/pub_excel/xlsx/xlsxcellreference.h new file mode 100644 index 00000000..6a917c2f --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxcellreference.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#ifndef QXLSX_XLSXCELLREFERENCE_H +#define QXLSX_XLSXCELLREFERENCE_H +#include "xlsxglobal.h" + +QT_BEGIN_NAMESPACE_XLSX + +class Q_XLSX_EXPORT CellReference +{ +public: + CellReference(); + CellReference(int row, int column); + CellReference(const QString &cell); + CellReference(const char *cell); + CellReference(const CellReference &other); + ~CellReference(); + + QString toString(bool row_abs=false, bool col_abs=false) const; + static CellReference fromString(const QString &cell); + bool isValid() const; + inline void setRow(int row) { _row = row; } + inline void setColumn(int col) { _column = col; } + inline int row() const { return _row; } + inline int column() const { return _column; } + + inline bool operator ==(const CellReference &other) const + { + return _row==other._row && _column==other._column; + } + inline bool operator !=(const CellReference &other) const + { + return _row!=other._row || _column!=other._column; + } +private: + void init(const QString &cell); + int _row, _column; +}; + +QT_END_NAMESPACE_XLSX + +Q_DECLARE_TYPEINFO(QXlsx::CellReference, Q_MOVABLE_TYPE); + +#endif // QXLSX_XLSXCELLREFERENCE_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxchart.cpp b/platform/src/include/public/pub_excel/xlsx/xlsxchart.cpp new file mode 100644 index 00000000..a69f5c25 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxchart.cpp @@ -0,0 +1,645 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ + +#include "xlsxchart_p.h" +#include "xlsxworksheet.h" +#include "xlsxcellrange.h" +#include "xlsxutility_p.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE_XLSX + +ChartPrivate::ChartPrivate(Chart *q, Chart::CreateFlag flag) + :AbstractOOXmlFilePrivate(q, flag), chartType(static_cast(0)) +{ + +} + +ChartPrivate::~ChartPrivate() +{ + +} + +/*! + * \class Chart + * \inmodule QtXlsx + * \brief Main class for the charts. + */ + +/*! + \enum Chart::ChartType + + \value CT_Area + \value CT_Area3D, + \value CT_Line, + \value CT_Line3D, + \value CT_Scatter, + \value CT_Pie, + \value CT_Pie3D, + \value CT_Doughnut, + \value CT_Bar, + \value CT_Bar3D, + + \omitvalue CT_Stock, + \omitvalue CT_Radar, + \omitvalue CT_OfPie, + \omitvalue CT_Surface, + \omitvalue CT_Surface3D, + \omitvalue CT_Bubble +*/ + +/*! + * \internal + */ +Chart::Chart(AbstractSheet *parent, CreateFlag flag) + :AbstractOOXmlFile(new ChartPrivate(this, flag)) +{ + d_func()->sheet = parent; +} + +/*! + * Destroys the chart. + */ +Chart::~Chart() +{ +} + +/*! + * Add the data series which is in the range \a range of the \a sheet. + */ +void Chart::addSeries(const CellRange &range, AbstractSheet *sheet) +{ + Q_D(Chart); + if (!range.isValid()) + return; + if (sheet && sheet->sheetType() != AbstractSheet::ST_WorkSheet) + return; + if (!sheet && d->sheet->sheetType() != AbstractSheet::ST_WorkSheet) + return; + + QString sheetName = sheet ? sheet->sheetName() : d->sheet->sheetName(); + //In case sheetName contains space or ' + sheetName = escapeSheetName(sheetName); + + if (range.columnCount() == 1 || range.rowCount() == 1) { + QSharedPointer series = QSharedPointer(new XlsxSeries); + series->numberDataSource_numRef = sheetName + QLatin1String("!") + range.toString(true, true); + d->seriesList.append(series); + } else if (range.columnCount() < range.rowCount()) { + //Column based series + int firstDataColumn = range.firstColumn(); + QString axDataSouruce_numRef; + if (d->chartType == CT_Scatter || d->chartType == CT_Bubble) { + firstDataColumn += 1; + CellRange subRange(range.firstRow(), range.firstColumn(), range.lastRow(), range.firstColumn()); + axDataSouruce_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true); + } + + for (int col=firstDataColumn; col<=range.lastColumn(); ++col) { + CellRange subRange(range.firstRow(), col, range.lastRow(), col); + QSharedPointer series = QSharedPointer(new XlsxSeries); + series->axDataSource_numRef = axDataSouruce_numRef; + series->numberDataSource_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true); + d->seriesList.append(series); + } + + } else { + //Row based series + int firstDataRow = range.firstRow(); + QString axDataSouruce_numRef; + if (d->chartType == CT_Scatter || d->chartType == CT_Bubble) { + firstDataRow += 1; + CellRange subRange(range.firstRow(), range.firstColumn(), range.firstRow(), range.lastColumn()); + axDataSouruce_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true); + } + + for (int row=firstDataRow; row<=range.lastRow(); ++row) { + CellRange subRange(row, range.firstColumn(), row, range.lastColumn()); + QSharedPointer series = QSharedPointer(new XlsxSeries); + series->axDataSource_numRef = axDataSouruce_numRef; + series->numberDataSource_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true); + d->seriesList.append(series); + } + } +} + +/*! + * Set the type of the chart to \a type + */ +void Chart::setChartType(ChartType type) +{ + Q_D(Chart); + d->chartType = type; +} + +/*! + * \internal + * + */ +void Chart::setChartStyle(int id) +{ + Q_UNUSED(id) + //!Todo +} + +/*! + * \internal + */ +void Chart::saveToXmlFile(QIODevice *device) const +{ + Q_D(const Chart); + + QXmlStreamWriter writer(device); + + writer.writeStartDocument(QStringLiteral("1.0"), true); + writer.writeStartElement(QStringLiteral("c:chartSpace")); + writer.writeAttribute(QStringLiteral("xmlns:c"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/chart")); + writer.writeAttribute(QStringLiteral("xmlns:a"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/main")); + writer.writeAttribute(QStringLiteral("xmlns:r"), QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships")); + + d->saveXmlChart(writer); + + writer.writeEndElement();//c:chartSpace + writer.writeEndDocument(); +} + +/*! + * \internal + */ +bool Chart::loadFromXmlFile(QIODevice *device) +{ + Q_D(Chart); + + QXmlStreamReader reader(device); + while (!reader.atEnd()) { + reader.readNextStartElement(); + if (reader.tokenType() == QXmlStreamReader::StartElement) { + if (reader.name() == QLatin1String("chart")) { + if (!d->loadXmlChart(reader)) + return false; + } + } + } + return true; +} + +bool ChartPrivate::loadXmlChart(QXmlStreamReader &reader) +{ + Q_ASSERT(reader.name() == QLatin1String("chart")); + + while (!reader.atEnd()) { + reader.readNextStartElement(); + if (reader.tokenType() == QXmlStreamReader::StartElement) { + if (reader.name() == QLatin1String("plotArea")) { + if (!loadXmlPlotArea(reader)) + return false; + } else if (reader.name() == QLatin1String("legend")) { + //!Todo + } + } else if (reader.tokenType() == QXmlStreamReader::EndElement && + reader.name() == QLatin1String("chart")) { + break; + } + } + return true; +} + +bool ChartPrivate::loadXmlPlotArea(QXmlStreamReader &reader) +{ + Q_ASSERT(reader.name() == QLatin1String("plotArea")); + + while (!reader.atEnd()) { + reader.readNextStartElement(); + if (reader.tokenType() == QXmlStreamReader::StartElement) { + if (reader.name() == QLatin1String("layout")) { + //!ToDo + } else if (reader.name().endsWith(QLatin1String("Chart"))) { + //For pieChart, barChart, ... + loadXmlXxxChart(reader); + } else if (reader.name().endsWith(QLatin1String("Ax"))) { + //For valAx, catAx, serAx, dateAx + loadXmlAxis(reader); + } + + } else if (reader.tokenType() == QXmlStreamReader::EndElement && + reader.name() == QLatin1String("plotArea")) { + break; + } + } + return true; +} + +bool ChartPrivate::loadXmlXxxChart(QXmlStreamReader &reader) +{ + QStringRef name = reader.name(); + if (name == QLatin1String("pieChart")) chartType = Chart::CT_Pie; + else if (name == QLatin1String("pie3DChart")) chartType = Chart::CT_Pie3D; + else if (name == QLatin1String("barChart")) chartType = Chart::CT_Bar; + else if (name == QLatin1String("bar3DChart")) chartType = Chart::CT_Bar3D; + else if (name == QLatin1String("lineChart")) chartType = Chart::CT_Line; + else if (name == QLatin1String("line3DChart")) chartType = Chart::CT_Line3D; + else if (name == QLatin1String("scatterChart")) chartType = Chart::CT_Scatter; + else if (name == QLatin1String("areaChart")) chartType = Chart::CT_Area; + else if (name == QLatin1String("area3DChart")) chartType = Chart::CT_Area3D; + else if (name == QLatin1String("doughnutChart")) chartType = Chart::CT_Doughnut; + else qDebug()<<"Cann't load chart: "< series = QSharedPointer(new XlsxSeries); + seriesList.append(series); + + while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement + && reader.name() == QLatin1String("ser"))) { + if (reader.readNextStartElement()) { + QStringRef name = reader.name(); + if (name == QLatin1String("cat") || name == QLatin1String("xVal")) { + while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement + && reader.name() == name)) { + if (reader.readNextStartElement()) { + if (reader.name() == QLatin1String("numRef")) + series->axDataSource_numRef = loadXmlNumRef(reader); + } + } + } else if (name == QLatin1String("val") || name == QLatin1String("yVal")) { + while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement + && reader.name() == name)) { + if (reader.readNextStartElement()) { + if (reader.name() == QLatin1String("numRef")) + series->numberDataSource_numRef = loadXmlNumRef(reader); + } + } + } else if (name == QLatin1String("extLst")) { + while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement + && reader.name() == name)) { + reader.readNextStartElement(); + } + } + } + } + + return true; +} + + +QString ChartPrivate::loadXmlNumRef(QXmlStreamReader &reader) +{ + Q_ASSERT(reader.name() == QLatin1String("numRef")); + + while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement + && reader.name() == QLatin1String("numRef"))) { + if (reader.readNextStartElement()) { + if (reader.name() == QLatin1String("f")) + return reader.readElementText(); + } + } + + return QString(); +} + +void ChartPrivate::saveXmlChart(QXmlStreamWriter &writer) const +{ + writer.writeStartElement(QStringLiteral("c:chart")); + writer.writeStartElement(QStringLiteral("c:plotArea")); + switch (chartType) { + case Chart::CT_Pie: + case Chart::CT_Pie3D: + saveXmlPieChart(writer); + break; + case Chart::CT_Bar: + case Chart::CT_Bar3D: + saveXmlBarChart(writer); + break; + case Chart::CT_Line: + case Chart::CT_Line3D: + saveXmlLineChart(writer); + break; + case Chart::CT_Scatter: + saveXmlScatterChart(writer); + break; + case Chart::CT_Area: + case Chart::CT_Area3D: + saveXmlAreaChart(writer); + break; + case Chart::CT_Doughnut: + saveXmlDoughnutChart(writer); + break; + default: + break; + } + saveXmlAxes(writer); + writer.writeEndElement(); //plotArea + +// saveXmlLegend(writer); + + writer.writeEndElement(); //chart +} + +void ChartPrivate::saveXmlPieChart(QXmlStreamWriter &writer) const +{ + QString name = chartType==Chart::CT_Pie ? QStringLiteral("c:pieChart") : QStringLiteral("c:pie3DChart"); + + writer.writeStartElement(name); + + //Do the same behavior as Excel, Pie prefer varyColors + writer.writeEmptyElement(QStringLiteral("c:varyColors")); + writer.writeAttribute(QStringLiteral("val"), QStringLiteral("1")); + + for (int i=0; i(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Cat, XlsxAxis::Bottom, 0, 1))); + const_cast(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::Left, 1, 0))); + } + + //Note: Bar3D have 2~3 axes + Q_ASSERT(axisList.size()==2 || (axisList.size()==3 && chartType==Chart::CT_Bar3D)); + + for (int i=0; iaxisId)); + } + + writer.writeEndElement(); //barChart, bar3DChart +} + +void ChartPrivate::saveXmlLineChart(QXmlStreamWriter &writer) const +{ + QString name = chartType==Chart::CT_Line ? QStringLiteral("c:lineChart") : QStringLiteral("c:line3DChart"); + + writer.writeStartElement(name); + + writer.writeEmptyElement(QStringLiteral("grouping")); + + for (int i=0; i(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Cat, XlsxAxis::Bottom, 0, 1))); + const_cast(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::Left, 1, 0))); + if (chartType==Chart::CT_Line3D) + const_cast(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Ser, XlsxAxis::Bottom, 2, 0))); + } + + Q_ASSERT((axisList.size()==2||chartType==Chart::CT_Line)|| (axisList.size()==3 && chartType==Chart::CT_Line3D)); + + for (int i=0; iaxisId)); + } + + writer.writeEndElement(); //lineChart, line3DChart +} + +void ChartPrivate::saveXmlScatterChart(QXmlStreamWriter &writer) const +{ + const QString name = QStringLiteral("c:scatterChart"); + + writer.writeStartElement(name); + + writer.writeEmptyElement(QStringLiteral("c:scatterStyle")); + + for (int i=0; i(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::Bottom, 0, 1))); + const_cast(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::Left, 1, 0))); + } + + Q_ASSERT(axisList.size()==2); + + for (int i=0; iaxisId)); + } + + writer.writeEndElement(); //c:scatterChart +} + +void ChartPrivate::saveXmlAreaChart(QXmlStreamWriter &writer) const +{ + QString name = chartType==Chart::CT_Area ? QStringLiteral("c:areaChart") : QStringLiteral("c:area3DChart"); + + writer.writeStartElement(name); + + writer.writeEmptyElement(QStringLiteral("grouping")); + + for (int i=0; i(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Cat, XlsxAxis::Bottom, 0, 1))); + const_cast(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::Left, 1, 0))); + } + + //Note: Area3D have 2~3 axes + Q_ASSERT(axisList.size()==2 || (axisList.size()==3 && chartType==Chart::CT_Area3D)); + + for (int i=0; iaxisId)); + } + + writer.writeEndElement(); //lineChart, line3DChart +} + +void ChartPrivate::saveXmlDoughnutChart(QXmlStreamWriter &writer) const +{ + QString name = QStringLiteral("c:doughnutChart"); + + writer.writeStartElement(name); + + writer.writeEmptyElement(QStringLiteral("c:varyColors")); + writer.writeAttribute(QStringLiteral("val"), QStringLiteral("1")); + + for (int i=0; iaxDataSource_numRef.isEmpty()) { + if (chartType == Chart::CT_Scatter || chartType == Chart::CT_Bubble) + writer.writeStartElement(QStringLiteral("c:xVal")); + else + writer.writeStartElement(QStringLiteral("c:cat")); + writer.writeStartElement(QStringLiteral("c:numRef")); + writer.writeTextElement(QStringLiteral("c:f"), ser->axDataSource_numRef); + writer.writeEndElement();//c:numRef + writer.writeEndElement();//c:cat or c:xVal + } + + if (!ser->numberDataSource_numRef.isEmpty()) { + if (chartType == Chart::CT_Scatter || chartType == Chart::CT_Bubble) + writer.writeStartElement(QStringLiteral("c:yVal")); + else + writer.writeStartElement(QStringLiteral("c:val")); + writer.writeStartElement(QStringLiteral("c:numRef")); + writer.writeTextElement(QStringLiteral("c:f"), ser->numberDataSource_numRef); + writer.writeEndElement();//c:numRef + writer.writeEndElement();//c:val or c:yVal + } + + writer.writeEndElement();//c:ser +} + +bool ChartPrivate::loadXmlAxis(QXmlStreamReader &reader) +{ + Q_ASSERT(reader.name().endsWith(QLatin1String("Ax"))); + QString name = reader.name().toString(); + + XlsxAxis *axis = new XlsxAxis; + if (name == QLatin1String("valAx")) + axis->type = XlsxAxis::T_Val; + else if (name == QLatin1String("catAx")) + axis->type = XlsxAxis::T_Cat; + else if (name == QLatin1String("serAx")) + axis->type = XlsxAxis::T_Ser; + else + axis->type = XlsxAxis::T_Date; + + axisList.append(QSharedPointer(axis)); + + while (!reader.atEnd()) { + reader.readNextStartElement(); + if (reader.tokenType() == QXmlStreamReader::StartElement) { + if (reader.name() == QLatin1String("axPos")) { + QXmlStreamAttributes attrs = reader.attributes(); + QStringRef pos = attrs.value(QLatin1String("val")); + if (pos==QLatin1String("l")) + axis->axisPos = XlsxAxis::Left; + else if (pos==QLatin1String("r")) + axis->axisPos = XlsxAxis::Right; + else if (pos==QLatin1String("b")) + axis->axisPos = XlsxAxis::Bottom; + else + axis->axisPos = XlsxAxis::Top; + } else if (reader.name() == QLatin1String("axId")) { + axis->axisId = reader.attributes().value(QLatin1String("val")).toString().toInt(); + } else if (reader.name() == QLatin1String("crossAx")) { + axis->crossAx = reader.attributes().value(QLatin1String("val")).toString().toInt(); + } + } else if (reader.tokenType() == QXmlStreamReader::EndElement + && reader.name() == name) { + break; + } + } + + return true; +} + +void ChartPrivate::saveXmlAxes(QXmlStreamWriter &writer) const +{ + for (int i=0; itype) { + case XlsxAxis::T_Cat: name = QStringLiteral("c:catAx"); break; + case XlsxAxis::T_Val: name = QStringLiteral("c:valAx"); break; + case XlsxAxis::T_Ser: name = QStringLiteral("c:serAx"); break; + case XlsxAxis::T_Date: name = QStringLiteral("c:dateAx"); break; + default: break; + } + + QString pos; + switch (axis->axisPos) { + case XlsxAxis::Top: pos = QStringLiteral("t"); break; + case XlsxAxis::Bottom: pos = QStringLiteral("b"); break; + case XlsxAxis::Left: pos = QStringLiteral("l"); break; + case XlsxAxis::Right: pos = QStringLiteral("r"); break; + default: break; + } + + writer.writeStartElement(name); + writer.writeEmptyElement(QStringLiteral("c:axId")); + writer.writeAttribute(QStringLiteral("val"), QString::number(axis->axisId)); + + writer.writeStartElement(QStringLiteral("c:scaling")); + writer.writeEmptyElement(QStringLiteral("c:orientation")); + writer.writeAttribute(QStringLiteral("val"), QStringLiteral("minMax")); + writer.writeEndElement();//c:scaling + + writer.writeEmptyElement(QStringLiteral("c:axPos")); + writer.writeAttribute(QStringLiteral("val"), pos); + + writer.writeEmptyElement(QStringLiteral("c:crossAx")); + writer.writeAttribute(QStringLiteral("val"), QString::number(axis->crossAx)); + + writer.writeEndElement();//name + } +} + +QT_END_NAMESPACE_XLSX diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxchart.h b/platform/src/include/public/pub_excel/xlsx/xlsxchart.h new file mode 100644 index 00000000..fcd8e2d8 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxchart.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ + +#ifndef QXLSX_CHART_H +#define QXLSX_CHART_H + +#include "xlsxabstractooxmlfile.h" + +#include + +class QXmlStreamReader; +class QXmlStreamWriter; + +QT_BEGIN_NAMESPACE_XLSX + +class AbstractSheet; +class Worksheet; +class ChartPrivate; +class CellRange; +class DrawingAnchor; + +class Q_XLSX_EXPORT Chart : public AbstractOOXmlFile +{ + Q_DECLARE_PRIVATE(Chart) + +public: + enum ChartType { + CT_Area = 1, //Zero is internally used for unknown types + CT_Area3D, + CT_Line, + CT_Line3D, + CT_Stock, + CT_Radar, + CT_Scatter, + CT_Pie, + CT_Pie3D, + CT_Doughnut, + CT_Bar, + CT_Bar3D, + CT_OfPie, + CT_Surface, + CT_Surface3D, + CT_Bubble + }; + + ~Chart(); + + void addSeries(const CellRange &range, AbstractSheet *sheet=0); + void setChartType(ChartType type); + void setChartStyle(int id); + + void saveToXmlFile(QIODevice *device) const; + bool loadFromXmlFile(QIODevice *device); + +private: + friend class AbstractSheet; + friend class Worksheet; + friend class Chartsheet; + friend class DrawingAnchor; + + Chart(AbstractSheet *parent, CreateFlag flag); +}; + +QT_END_NAMESPACE_XLSX + +#endif // QXLSX_CHART_H + diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxchart_p.h b/platform/src/include/public/pub_excel/xlsx/xlsxchart_p.h new file mode 100644 index 00000000..4fcd0fb9 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxchart_p.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ + +#ifndef QXLSX_CHART_P_H +#define QXLSX_CHART_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Xlsx API. It exists for the convenience +// of the Qt Xlsx. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "xlsxabstractooxmlfile_p.h" +#include "xlsxchart.h" + +#include + +class QXmlStreamReader; +class QXmlStreamWriter; + +namespace QXlsx { + +class XlsxSeries +{ +public: + //At present, we care about number cell ranges only! + QString numberDataSource_numRef; //yval, val + QString axDataSource_numRef; //xval, cat +}; + +class XlsxAxis +{ +public: + enum Type + { + T_Cat, + T_Val, + T_Date, + T_Ser + }; + + enum Pos + { + Left, + Right, + Top, + Bottom + }; + + XlsxAxis(){} + + XlsxAxis(Type t, Pos p, int id, int crossId) + :type(t), axisPos(p), axisId(id), crossAx(crossId) + { + } + + Type type; + Pos axisPos; //l,r,b,t + int axisId; + int crossAx; +}; + +class ChartPrivate : public AbstractOOXmlFilePrivate +{ + Q_DECLARE_PUBLIC(Chart) + +public: + ChartPrivate(Chart *q, Chart::CreateFlag flag); + ~ChartPrivate(); + + bool loadXmlChart(QXmlStreamReader &reader); + bool loadXmlPlotArea(QXmlStreamReader &reader); + bool loadXmlXxxChart(QXmlStreamReader &reader); + bool loadXmlSer(QXmlStreamReader &reader); + QString loadXmlNumRef(QXmlStreamReader &reader); + bool loadXmlAxis(QXmlStreamReader &reader); + + void saveXmlChart(QXmlStreamWriter &writer) const; + void saveXmlPieChart(QXmlStreamWriter &writer) const; + void saveXmlBarChart(QXmlStreamWriter &writer) const; + void saveXmlLineChart(QXmlStreamWriter &writer) const; + void saveXmlScatterChart(QXmlStreamWriter &writer) const; + void saveXmlAreaChart(QXmlStreamWriter &writer) const; + void saveXmlDoughnutChart(QXmlStreamWriter &writer) const; + void saveXmlSer(QXmlStreamWriter &writer, XlsxSeries *ser, int id) const; + void saveXmlAxes(QXmlStreamWriter &writer) const; + + Chart::ChartType chartType; + + QList > seriesList; + QList > axisList; + + AbstractSheet *sheet; +}; + +} // namespace QXlsx + +#endif // QXLSX_CHART_P_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxchartsheet.cpp b/platform/src/include/public/pub_excel/xlsx/xlsxchartsheet.cpp new file mode 100644 index 00000000..5cf477c9 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxchartsheet.cpp @@ -0,0 +1,159 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#include "xlsxchartsheet.h" +#include "xlsxchartsheet_p.h" +#include "xlsxworkbook.h" +#include "xlsxutility_p.h" +#include "xlsxdrawing_p.h" +#include "xlsxdrawinganchor_p.h" +#include "xlsxchart.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE_XLSX + +ChartsheetPrivate::ChartsheetPrivate(Chartsheet *p, Chartsheet::CreateFlag flag) + : AbstractSheetPrivate(p, flag), chart(0) +{ + +} + +ChartsheetPrivate::~ChartsheetPrivate() +{ +} + +/*! + \class Chartsheet + \inmodule QtXlsx + \brief Represent one chartsheet in the workbook. +*/ + +/*! + * \internal + */ +Chartsheet::Chartsheet(const QString &name, int id, Workbook *workbook, CreateFlag flag) + :AbstractSheet(name, id, workbook, new ChartsheetPrivate(this, flag)) +{ + setSheetType(ST_ChartSheet); + + if (flag == Chartsheet::F_NewFromScratch) { + d_func()->drawing = QSharedPointer(new Drawing(this, flag)); + + DrawingAbsoluteAnchor *anchor = new DrawingAbsoluteAnchor(drawing(), DrawingAnchor::Picture); + + anchor->pos = QPoint(0, 0); + anchor->ext = QSize(9293679, 6068786); + + QSharedPointer chart = QSharedPointer(new Chart(this, flag)); + chart->setChartType(Chart::CT_Bar); + anchor->setObjectGraphicFrame(chart); + + d_func()->chart = chart.data(); + } +} + +/*! + * \internal + * + * Make a copy of this sheet. + */ + +Chartsheet *Chartsheet::copy(const QString &distName, int distId) const +{ + //:Todo + Q_UNUSED(distName) + Q_UNUSED(distId) + return 0; +} + +/*! + * Destroys this workssheet. + */ +Chartsheet::~Chartsheet() +{ +} + +/*! + * Returns the chart object of the sheet. + */ +Chart *Chartsheet::chart() +{ + Q_D(Chartsheet); + + return d->chart; +} + +void Chartsheet::saveToXmlFile(QIODevice *device) const +{ + Q_D(const Chartsheet); + d->relationships->clear(); + + QXmlStreamWriter writer(device); + + writer.writeStartDocument(QStringLiteral("1.0"), true); + writer.writeDefaultNamespace(QStringLiteral("http://schemas.openxmlformats.org/spreadsheetml/2006/main")); + writer.writeNamespace(QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships"), QStringLiteral("r")); + writer.writeStartElement(QStringLiteral("chartsheet")); + + writer.writeStartElement(QStringLiteral("sheetViews")); + writer.writeEmptyElement(QStringLiteral("sheetView")); + writer.writeAttribute(QStringLiteral("workbookViewId"), QString::number(0)); + writer.writeAttribute(QStringLiteral("zoomToFit"), QStringLiteral("1")); + writer.writeEndElement(); //sheetViews + + int idx = d->workbook->drawings().indexOf(d->drawing.data()); + d->relationships->addWorksheetRelationship(QStringLiteral("/drawing"), QStringLiteral("../drawings/drawing%1.xml").arg(idx+1)); + + writer.writeEmptyElement(QStringLiteral("drawing")); + writer.writeAttribute(QStringLiteral("r:id"), QStringLiteral("rId%1").arg(d->relationships->count())); + + writer.writeEndElement();//chartsheet + writer.writeEndDocument(); +} + +bool Chartsheet::loadFromXmlFile(QIODevice *device) +{ + Q_D(Chartsheet); + + QXmlStreamReader reader(device); + while (!reader.atEnd()) { + reader.readNextStartElement(); + if (reader.tokenType() == QXmlStreamReader::StartElement) { + if (reader.name() == QLatin1String("drawing")) { + QString rId = reader.attributes().value(QStringLiteral("r:id")).toString(); + QString name = d->relationships->getRelationshipById(rId).target; + QString path = QDir::cleanPath(splitPath(filePath())[0] + QLatin1String("/") + name); + d->drawing = QSharedPointer(new Drawing(this, F_LoadFromExists)); + d->drawing->setFilePath(path); + } + } + } + + return true; +} + +QT_END_NAMESPACE_XLSX diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxchartsheet.h b/platform/src/include/public/pub_excel/xlsx/xlsxchartsheet.h new file mode 100644 index 00000000..6c5ee981 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxchartsheet.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#ifndef XLSXCHARTSHEET_H +#define XLSXCHARTSHEET_H + +#include "xlsxabstractsheet.h" +#include +#include + +QT_BEGIN_NAMESPACE_XLSX +class Workbook; +class DocumentPrivate; +class ChartsheetPrivate; +class Chart; +class Q_XLSX_EXPORT Chartsheet : public AbstractSheet +{ + Q_DECLARE_PRIVATE(Chartsheet) +public: + + ~Chartsheet(); + Chart *chart(); + +private: + friend class DocumentPrivate; + friend class Workbook; + Chartsheet(const QString &sheetName, int sheetId, Workbook *book, CreateFlag flag); + Chartsheet *copy(const QString &distName, int distId) const; + + void saveToXmlFile(QIODevice *device) const; + bool loadFromXmlFile(QIODevice *device); +}; + +QT_END_NAMESPACE_XLSX +#endif // XLSXCHARTSHEET_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxchartsheet_p.h b/platform/src/include/public/pub_excel/xlsx/xlsxchartsheet_p.h new file mode 100644 index 00000000..817da88b --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxchartsheet_p.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#ifndef XLSXCHARTSHEET_P_H +#define XLSXCHARTSHEET_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Xlsx API. It exists for the convenience +// of the Qt Xlsx. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "xlsxglobal.h" +#include "xlsxchartsheet.h" +#include "xlsxabstractsheet_p.h" + +namespace QXlsx { + +class XLSX_AUTOTEST_EXPORT ChartsheetPrivate : public AbstractSheetPrivate +{ + Q_DECLARE_PUBLIC(Chartsheet) +public: + ChartsheetPrivate(Chartsheet *p, Chartsheet::CreateFlag flag); + ~ChartsheetPrivate(); + + Chart *chart; +}; + +} +#endif // XLSXCHARTSHEET_P_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxcolor.cpp b/platform/src/include/public/pub_excel/xlsx/xlsxcolor.cpp new file mode 100644 index 00000000..b1ed4639 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxcolor.cpp @@ -0,0 +1,198 @@ +#include "xlsxcolor_p.h" +#include "xlsxstyles_p.h" +#include "xlsxutility_p.h" + +#include +#include +#include +#include + +namespace QXlsx { + + +XlsxColor::XlsxColor(const QColor &color) +{ + if (color.isValid()) + val.setValue(color); +} + +XlsxColor::XlsxColor(const QString &theme, const QString &tint) + :val(QStringList()<() && val.value().isValid()) + return true; + return false; +} + +bool XlsxColor::isIndexedColor() const +{ + return val.userType() == QMetaType::Int; +} + +bool XlsxColor::isThemeColor() const +{ + return val.userType() == QMetaType::QStringList; +} + +bool XlsxColor::isInvalid() const +{ + return !val.isValid(); +} + +QColor XlsxColor::rgbColor() const +{ + if (isRgbColor()) + return val.value(); + return QColor(); +} + +int XlsxColor::indexedColor() const +{ + if (isIndexedColor()) + return val.toInt(); + return -1; +} + +QStringList XlsxColor::themeColor() const +{ + if (isThemeColor()) + return val.toStringList(); + return QStringList(); +} + +bool XlsxColor::saveToXml(QXmlStreamWriter &writer, const QString &node) const +{ + if (!node.isEmpty()) + writer.writeEmptyElement(node); //color, bgColor, fgColor + else + writer.writeEmptyElement(QStringLiteral("color")); + + if (val.userType() == qMetaTypeId()) { + writer.writeAttribute(QStringLiteral("rgb"), XlsxColor::toARGBString(val.value())); + } else if (val.userType() == QMetaType::QStringList) { + QStringList themes = val.toStringList(); + writer.writeAttribute(QStringLiteral("theme"), themes[0]); + if (!themes[1].isEmpty()) + writer.writeAttribute(QStringLiteral("tint"), themes[1]); + } else if (val.userType() == QMetaType::Int) { + writer.writeAttribute(QStringLiteral("indexed"), val.toString()); + } else { + writer.writeAttribute(QStringLiteral("auto"), QStringLiteral("1")); + } + + return true; +} + +bool XlsxColor::loadFromXml(QXmlStreamReader &reader) +{ + QXmlStreamAttributes attributes = reader.attributes(); + + if (attributes.hasAttribute(QLatin1String("rgb"))) { + QString colorString = attributes.value(QLatin1String("rgb")).toString(); + val.setValue(fromARGBString(colorString)); + } else if (attributes.hasAttribute(QLatin1String("indexed"))) { + int index = attributes.value(QLatin1String("indexed")).toString().toInt(); + val.setValue(index); + } else if (attributes.hasAttribute(QLatin1String("theme"))) { + QString theme = attributes.value(QLatin1String("theme")).toString(); + QString tint = attributes.value(QLatin1String("tint")).toString(); + val.setValue(QStringList()<(), this); +} + + +QColor XlsxColor::fromARGBString(const QString &c) +{ + Q_ASSERT(c.length() == 8); + QColor color; + color.setAlpha(c.mid(0, 2).toInt(0, 16)); + color.setRed(c.mid(2, 2).toInt(0, 16)); + color.setGreen(c.mid(4, 2).toInt(0, 16)); + color.setBlue(c.mid(6, 2).toInt(0, 16)); + return color; +} + +QString XlsxColor::toARGBString(const QColor &c) +{ + QString color; + color.sprintf("%02X%02X%02X%02X", c.alpha(), c.red(), c.green(), c.blue()); + return color; +} + +#if !defined(QT_NO_DATASTREAM) +QDataStream &operator<<(QDataStream &s, const XlsxColor &color) +{ + if (color.isInvalid()) + s<<0; + else if (color.isRgbColor()) + s<<1<>(QDataStream &s, XlsxColor &color) +{ + int marker(4); + s>>marker; + if (marker == 0) { + color = XlsxColor(); + } else if (marker == 1) { + QColor c; + s>>c; + color = XlsxColor(c); + } else if (marker == 2) { + int indexed; + s>>indexed; + color = XlsxColor(indexed); + } else if (marker == 3) { + QStringList list; + s>>list; + color = XlsxColor(list[0], list[1]); + } + + return s; +} + +#endif + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug dbg, const XlsxColor &c) +{ + if (c.isInvalid()) + dbg.nospace() << "XlsxColor(invalid)"; + else if (c.isRgbColor()) + dbg.nospace() << c.rgbColor(); + else if (c.isIndexedColor()) + dbg.nospace() << "XlsxColor(indexed," << c.indexedColor() << ")"; + else if (c.isThemeColor()) + dbg.nospace() << "XlsxColor(theme," << c.themeColor().join(QLatin1Char(':')) << ")"; + + return dbg.space(); +} + +#endif + +} // namespace QXlsx diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxcolor_p.h b/platform/src/include/public/pub_excel/xlsx/xlsxcolor_p.h new file mode 100644 index 00000000..eff1b0ba --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxcolor_p.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ + +#ifndef QXLSX_XLSXCOLOR_P_H +#define QXLSX_XLSXCOLOR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Xlsx API. It exists for the convenience +// of the Qt Xlsx. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "xlsxglobal.h" +#include +#include + +class QXmlStreamWriter; +class QXmlStreamReader; + +namespace QXlsx { + +class Styles; + +class Q_XLSX_EXPORT XlsxColor +{ +public: + explicit XlsxColor(const QColor &color = QColor()); + explicit XlsxColor(const QString &theme, const QString &tint=QString()); + explicit XlsxColor (int index); + + bool isThemeColor() const; + bool isIndexedColor() const; + bool isRgbColor() const; + bool isInvalid() const; + + QColor rgbColor() const; + int indexedColor() const; + QStringList themeColor() const; + + operator QVariant() const; + + static QColor fromARGBString(const QString &c); + static QString toARGBString(const QColor &c); + + bool saveToXml(QXmlStreamWriter &writer, const QString &node=QString()) const; + bool loadFromXml(QXmlStreamReader &reader); + +private: + QVariant val; +}; + +#if !defined(QT_NO_DATASTREAM) +Q_XLSX_EXPORT QDataStream &operator<<(QDataStream &, const XlsxColor &); +Q_XLSX_EXPORT QDataStream &operator>>(QDataStream &, XlsxColor &); +#endif + +#ifndef QT_NO_DEBUG_STREAM +Q_XLSX_EXPORT QDebug operator<<(QDebug dbg, const XlsxColor &c); +#endif + +} // namespace QXlsx + +Q_DECLARE_METATYPE(QXlsx::XlsxColor) + +#endif // QXLSX_XLSXCOLOR_P_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxconditionalformatting.cpp b/platform/src/include/public/pub_excel/xlsx/xlsxconditionalformatting.cpp new file mode 100644 index 00000000..03561fe6 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxconditionalformatting.cpp @@ -0,0 +1,735 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ + +#include "xlsxconditionalformatting.h" +#include "xlsxconditionalformatting_p.h" +#include "xlsxworksheet.h" +#include "xlsxcellrange.h" +#include "xlsxstyles_p.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE_XLSX + +ConditionalFormattingPrivate::ConditionalFormattingPrivate() +{ + +} + +ConditionalFormattingPrivate::ConditionalFormattingPrivate(const ConditionalFormattingPrivate &other) + :QSharedData(other) +{ + +} + +ConditionalFormattingPrivate::~ConditionalFormattingPrivate() +{ + +} + +void ConditionalFormattingPrivate::writeCfVo(QXmlStreamWriter &writer, const XlsxCfVoData &cfvo) const +{ + writer.writeEmptyElement(QStringLiteral("cfvo")); + QString type; + switch(cfvo.type) { + case ConditionalFormatting::VOT_Formula: type=QStringLiteral("formula"); break; + case ConditionalFormatting::VOT_Max: type=QStringLiteral("max"); break; + case ConditionalFormatting::VOT_Min: type=QStringLiteral("min"); break; + case ConditionalFormatting::VOT_Num: type=QStringLiteral("num"); break; + case ConditionalFormatting::VOT_Percent: type=QStringLiteral("percent"); break; + case ConditionalFormatting::VOT_Percentile: type=QStringLiteral("percentile"); break; + default: break; + } + writer.writeAttribute(QStringLiteral("type"), type); + writer.writeAttribute(QStringLiteral("val"), cfvo.value); + if (!cfvo.gte) + writer.writeAttribute(QStringLiteral("gte"), QStringLiteral("0")); +} + +/*! + * \class ConditionalFormatting + * \brief Conditional formatting for single cell or ranges + * \inmodule QtXlsx + * + * The conditional formatting can be applied to a single cell or ranges of cells. + */ + + +/*! + \enum ConditionalFormatting::HighlightRuleType + + \value Highlight_LessThan + \value Highlight_LessThanOrEqual + \value Highlight_Equal + \value Highlight_NotEqual + \value Highlight_GreaterThanOrEqual + \value Highlight_GreaterThan + \value Highlight_Between + \value Highlight_NotBetween + + \value Highlight_ContainsText + \value Highlight_NotContainsText + \value Highlight_BeginsWith + \value Highlight_EndsWith + + \value Highlight_TimePeriod + + \value Highlight_Duplicate + \value Highlight_Unique + + \value Highlight_Blanks + \value Highlight_NoBlanks + \value Highlight_Errors + \value Highlight_NoErrors + + \value Highlight_Top + \value Highlight_TopPercent + \value Highlight_Bottom + \value Highlight_BottomPercent + + \value Highlight_AboveAverage + \value Highlight_AboveOrEqualAverage + \value Highlight_BelowAverage + \value Highlight_BelowOrEqualAverage + \value Highlight_AboveStdDev1 + \value Highlight_AboveStdDev2 + \value Highlight_AboveStdDev3 + \value Highlight_BelowStdDev1 + \value Highlight_BelowStdDev2 + \value Highlight_BelowStdDev3 + + \value Highlight_Expression +*/ + +/*! + \enum ConditionalFormatting::ValueObjectType + + \value VOT_Formula + \value VOT_Max + \value VOT_Min + \value VOT_Num + \value VOT_Percent + \value VOT_Percentile +*/ + +/*! + Construct a conditional formatting object +*/ +ConditionalFormatting::ConditionalFormatting() + :d(new ConditionalFormattingPrivate()) +{ + +} + +/*! + Constructs a copy of \a other. +*/ +ConditionalFormatting::ConditionalFormatting(const ConditionalFormatting &other) + :d(other.d) +{ + +} + +/*! + Assigns \a other to this conditional formatting and returns a reference to + this conditional formatting. + */ +ConditionalFormatting &ConditionalFormatting::operator=(const ConditionalFormatting &other) +{ + this->d = other.d; + return *this; +} + + +/*! + * Destroy the object. + */ +ConditionalFormatting::~ConditionalFormatting() +{ +} + +/*! + * Add a hightlight rule with the given \a type, \a formula1, \a formula2, + * \a format and \a stopIfTrue. + * Return false if failed. + */ +bool ConditionalFormatting::addHighlightCellsRule(HighlightRuleType type, const QString &formula1, const QString &formula2, const Format &format, bool stopIfTrue) +{ + if (format.isEmpty()) + return false; + + bool skipFormula = false; + + QSharedPointer cfRule(new XlsxCfRuleData); + if (type >= Highlight_LessThan && type <= Highlight_NotBetween) { + cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("cellIs"); + QString op; + switch (type) { + case Highlight_Between: op = QStringLiteral("between"); break; + case Highlight_Equal: op = QStringLiteral("equal"); break; + case Highlight_GreaterThan: op = QStringLiteral("greaterThan"); break; + case Highlight_GreaterThanOrEqual: op = QStringLiteral("greaterThanOrEqual"); break; + case Highlight_LessThan: op = QStringLiteral("lessThan"); break; + case Highlight_LessThanOrEqual: op = QStringLiteral("lessThanOrEqual"); break; + case Highlight_NotBetween: op = QStringLiteral("notBetween"); break; + case Highlight_NotEqual: op = QStringLiteral("notEqual"); break; + default: break; + } + cfRule->attrs[XlsxCfRuleData::A_operator] = op; + } else if (type >= Highlight_ContainsText && type <= Highlight_EndsWith) { + if (type == Highlight_ContainsText) { + cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("containsText"); + cfRule->attrs[XlsxCfRuleData::A_operator] = QStringLiteral("containsText"); + cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("NOT(ISERROR(SEARCH(\"%1\",%2)))").arg(formula1); + } else if (type == Highlight_NotContainsText) { + cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("notContainsText"); + cfRule->attrs[XlsxCfRuleData::A_operator] = QStringLiteral("notContains"); + cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("ISERROR(SEARCH(\"%2\",%1))").arg(formula1); + } else if (type == Highlight_BeginsWith) { + cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("beginsWith"); + cfRule->attrs[XlsxCfRuleData::A_operator] = QStringLiteral("beginsWith"); + cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("LEFT(%2,LEN(\"%1\"))=\"%1\"").arg(formula1); + } else { + cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("endsWith"); + cfRule->attrs[XlsxCfRuleData::A_operator] = QStringLiteral("endsWith"); + cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("RIGHT(%2,LEN(\"%1\"))=\"%1\"").arg(formula1); + } + cfRule->attrs[XlsxCfRuleData::A_text] = formula1; + skipFormula = true; + } else if (type == Highlight_TimePeriod) { + cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("timePeriod"); + //:Todo + return false; + } else if (type == Highlight_Duplicate) { + cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("duplicateValues"); + } else if (type == Highlight_Unique) { + cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("uniqueValues"); + } else if (type == Highlight_Errors) { + cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("containsErrors"); + cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("ISERROR(%1)"); + skipFormula = true; + } else if (type == Highlight_NoErrors) { + cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("notContainsErrors"); + cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("NOT(ISERROR(%1))"); + skipFormula = true; + } else if (type == Highlight_Blanks) { + cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("containsBlanks"); + cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("LEN(TRIM(%1))=0"); + skipFormula = true; + } else if (type == Highlight_NoBlanks) { + cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("notContainsBlanks"); + cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("LEN(TRIM(%1))>0"); + skipFormula = true; + } else if (type >= Highlight_Top && type <= Highlight_BottomPercent) { + cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("top10"); + if (type == Highlight_Bottom || type == Highlight_BottomPercent) + cfRule->attrs[XlsxCfRuleData::A_bottom] = QStringLiteral("1"); + if (type == Highlight_TopPercent || type == Highlight_BottomPercent) + cfRule->attrs[XlsxCfRuleData::A_percent] = QStringLiteral("1"); + cfRule->attrs[XlsxCfRuleData::A_rank] = !formula1.isEmpty() ? formula1 : QStringLiteral("10"); + skipFormula = true; + } else if (type >= Highlight_AboveAverage && type <= Highlight_BelowStdDev3) { + cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("aboveAverage"); + if (type >= Highlight_BelowAverage && type <= Highlight_BelowStdDev3) + cfRule->attrs[XlsxCfRuleData::A_aboveAverage] = QStringLiteral("0"); + if (type == Highlight_AboveOrEqualAverage || type == Highlight_BelowOrEqualAverage) + cfRule->attrs[XlsxCfRuleData::A_equalAverage] = QStringLiteral("1"); + if (type == Highlight_AboveStdDev1 || type == Highlight_BelowStdDev1) + cfRule->attrs[XlsxCfRuleData::A_stdDev] = QStringLiteral("1"); + else if (type == Highlight_AboveStdDev2 || type == Highlight_BelowStdDev2) + cfRule->attrs[XlsxCfRuleData::A_stdDev] = QStringLiteral("2"); + else if (type == Highlight_AboveStdDev3 || type == Highlight_BelowStdDev3) + cfRule->attrs[XlsxCfRuleData::A_stdDev] = QStringLiteral("3"); + } else if (type == Highlight_Expression){ + cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("expression"); + } else { + return false; + } + + cfRule->dxfFormat = format; + if (stopIfTrue) + cfRule->attrs[XlsxCfRuleData::A_stopIfTrue] = true; + if (!skipFormula) { + if (!formula1.isEmpty()) + cfRule->attrs[XlsxCfRuleData::A_formula1] = formula1.startsWith(QLatin1String("=")) ? formula1.mid(1) : formula1; + if (!formula2.isEmpty()) + cfRule->attrs[XlsxCfRuleData::A_formula2] = formula2.startsWith(QLatin1String("=")) ? formula2.mid(1) : formula2; + } + d->cfRules.append(cfRule); + return true; +} + +/*! + * \overload + * + * Add a hightlight rule with the given \a type \a format and \a stopIfTrue. + */ +bool ConditionalFormatting::addHighlightCellsRule(HighlightRuleType type, const Format &format, bool stopIfTrue) +{ + if ((type >= Highlight_AboveAverage && type <= Highlight_BelowStdDev3) + || (type >= Highlight_Duplicate && type <= Highlight_NoErrors)) { + return addHighlightCellsRule(type, QString(), QString(), format, stopIfTrue); + } + + return false; +} + +/*! + * \overload + * + * Add a hightlight rule with the given \a type, \a formula, \a format and \a stopIfTrue. + * Return false if failed. + */ +bool ConditionalFormatting::addHighlightCellsRule(HighlightRuleType type, const QString &formula, const Format &format, bool stopIfTrue) +{ + if (type == Highlight_Between || type == Highlight_NotBetween) + return false; + + return addHighlightCellsRule(type, formula, QString(), format, stopIfTrue); +} + +/*! + * Add a dataBar rule with the given \a color, \a type1, \a val1 + * , \a type2, \a val2, \a showData and \a stopIfTrue. + * Return false if failed. + */ +bool ConditionalFormatting::addDataBarRule(const QColor &color, ValueObjectType type1, const QString &val1, ValueObjectType type2, const QString &val2, bool showData, bool stopIfTrue) +{ + QSharedPointer cfRule(new XlsxCfRuleData); + + cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("dataBar"); + cfRule->attrs[XlsxCfRuleData::A_color1] = XlsxColor(color); + if (stopIfTrue) + cfRule->attrs[XlsxCfRuleData::A_stopIfTrue] = true; + if (!showData) + cfRule->attrs[XlsxCfRuleData::A_hideData] = true; + + XlsxCfVoData cfvo1(type1, val1); + XlsxCfVoData cfvo2(type2, val2); + cfRule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(cfvo1); + cfRule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(cfvo2); + + d->cfRules.append(cfRule); + return true; +} + +/*! + * \overload + * Add a dataBar rule with the given \a color, \a showData and \a stopIfTrue. + */ +bool ConditionalFormatting::addDataBarRule(const QColor &color, bool showData, bool stopIfTrue) +{ + return addDataBarRule(color, VOT_Min, QStringLiteral("0"), VOT_Max, QStringLiteral("0"), showData, stopIfTrue); +} + +/*! + * Add a colorScale rule with the given \a minColor, \a maxColor and \a stopIfTrue. + * Return false if failed. + */ +bool ConditionalFormatting::add2ColorScaleRule(const QColor &minColor, const QColor &maxColor, bool stopIfTrue) +{ + ValueObjectType type1 = VOT_Min; + ValueObjectType type2 = VOT_Max; + QString val1 = QStringLiteral("0"); + QString val2 = QStringLiteral("0"); + + QSharedPointer cfRule(new XlsxCfRuleData); + + cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("colorScale"); + cfRule->attrs[XlsxCfRuleData::A_color1] = XlsxColor(minColor); + cfRule->attrs[XlsxCfRuleData::A_color2] = XlsxColor(maxColor); + if (stopIfTrue) + cfRule->attrs[XlsxCfRuleData::A_stopIfTrue] = true; + + XlsxCfVoData cfvo1(type1, val1); + XlsxCfVoData cfvo2(type2, val2); + cfRule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(cfvo1); + cfRule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(cfvo2); + + d->cfRules.append(cfRule); + return true; +} + +/*! + * Add a colorScale rule with the given \a minColor, \a midColor, \a maxColor and \a stopIfTrue. + * Return false if failed. + */ +bool ConditionalFormatting::add3ColorScaleRule(const QColor &minColor, const QColor &midColor, const QColor &maxColor, bool stopIfTrue) +{ + ValueObjectType type1 = VOT_Min; + ValueObjectType type2 = VOT_Percent; + ValueObjectType type3 = VOT_Max; + QString val1 = QStringLiteral("0"); + QString val2 = QStringLiteral("50"); + QString val3 = QStringLiteral("0"); + + QSharedPointer cfRule(new XlsxCfRuleData); + + cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("colorScale"); + cfRule->attrs[XlsxCfRuleData::A_color1] = XlsxColor(minColor); + cfRule->attrs[XlsxCfRuleData::A_color2] = XlsxColor(midColor); + cfRule->attrs[XlsxCfRuleData::A_color3] = XlsxColor(maxColor); + + if (stopIfTrue) + cfRule->attrs[XlsxCfRuleData::A_stopIfTrue] = true; + + XlsxCfVoData cfvo1(type1, val1); + XlsxCfVoData cfvo2(type2, val2); + XlsxCfVoData cfvo3(type3, val3); + cfRule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(cfvo1); + cfRule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(cfvo2); + cfRule->attrs[XlsxCfRuleData::A_cfvo3] = QVariant::fromValue(cfvo3); + + d->cfRules.append(cfRule); + return true; +} + +/*! + Returns the ranges on which the validation will be applied. + */ +QList ConditionalFormatting::ranges() const +{ + return d->ranges; +} + +/*! + Add the \a cell on which the conditional formatting will apply to. + */ +void ConditionalFormatting::addCell(const CellReference &cell) +{ + d->ranges.append(CellRange(cell, cell)); +} + +/*! + \overload + Add the cell(\a row, \a col) on which the conditional formatting will apply to. + */ +void ConditionalFormatting::addCell(int row, int col) +{ + d->ranges.append(CellRange(row, col, row, col)); +} + +/*! + \overload + Add the range(\a firstRow, \a firstCol, \a lastRow, \a lastCol) on + which the conditional formatting will apply to. + */ +void ConditionalFormatting::addRange(int firstRow, int firstCol, int lastRow, int lastCol) +{ + d->ranges.append(CellRange(firstRow, firstCol, lastRow, lastCol)); +} + +/*! + Add the \a range on which the conditional formatting will apply to. + */ +void ConditionalFormatting::addRange(const CellRange &range) +{ + d->ranges.append(range); +} + +bool ConditionalFormattingPrivate::readCfRule(QXmlStreamReader &reader, XlsxCfRuleData *rule, Styles *styles) +{ + Q_ASSERT(reader.name() == QLatin1String("cfRule")); + QXmlStreamAttributes attrs = reader.attributes(); + if (attrs.hasAttribute(QLatin1String("type"))) + rule->attrs[XlsxCfRuleData::A_type] = attrs.value(QLatin1String("type")).toString(); + if (attrs.hasAttribute(QLatin1String("dxfId"))) { + int id = attrs.value(QLatin1String("dxfId")).toString().toInt(); + if (styles) + rule->dxfFormat = styles->dxfFormat(id); + else + rule->dxfFormat.setDxfIndex(id); + } + rule->priority = attrs.value(QLatin1String("priority")).toString().toInt(); + if (attrs.value(QLatin1String("stopIfTrue")) == QLatin1String("1")) { + //default is false + rule->attrs[XlsxCfRuleData::A_stopIfTrue] = QLatin1String("1"); + } + if (attrs.value(QLatin1String("aboveAverage")) == QLatin1String("0")) { + //default is true + rule->attrs[XlsxCfRuleData::A_aboveAverage] = QLatin1String("0"); + } + if (attrs.value(QLatin1String("percent")) == QLatin1String("1")) { + //default is false + rule->attrs[XlsxCfRuleData::A_percent] = QLatin1String("1"); + } + if (attrs.value(QLatin1String("bottom")) == QLatin1String("1")) { + //default is false + rule->attrs[XlsxCfRuleData::A_bottom] = QLatin1String("1"); + } + if (attrs.hasAttribute(QLatin1String("operator"))) + rule->attrs[XlsxCfRuleData::A_operator] = attrs.value(QLatin1String("operator")).toString(); + + if (attrs.hasAttribute(QLatin1String("text"))) + rule->attrs[XlsxCfRuleData::A_text] = attrs.value(QLatin1String("text")).toString(); + + if (attrs.hasAttribute(QLatin1String("timePeriod"))) + rule->attrs[XlsxCfRuleData::A_timePeriod] = attrs.value(QLatin1String("timePeriod")).toString(); + + if (attrs.hasAttribute(QLatin1String("rank"))) + rule->attrs[XlsxCfRuleData::A_rank] = attrs.value(QLatin1String("rank")).toString(); + + if (attrs.hasAttribute(QLatin1String("stdDev"))) + rule->attrs[XlsxCfRuleData::A_stdDev] = attrs.value(QLatin1String("stdDev")).toString(); + + if (attrs.value(QLatin1String("equalAverage")) == QLatin1String("1")) { + //default is false + rule->attrs[XlsxCfRuleData::A_equalAverage] = QLatin1String("1"); + } + + while (!reader.atEnd()) { + reader.readNextStartElement(); + if (reader.tokenType() == QXmlStreamReader::StartElement) { + if (reader.name() == QLatin1String("formula")) { + QString f = reader.readElementText(); + if (!rule->attrs.contains(XlsxCfRuleData::A_formula1)) + rule->attrs[XlsxCfRuleData::A_formula1] = f; + else if (!rule->attrs.contains(XlsxCfRuleData::A_formula2)) + rule->attrs[XlsxCfRuleData::A_formula2] = f; + else if (!rule->attrs.contains(XlsxCfRuleData::A_formula3)) + rule->attrs[XlsxCfRuleData::A_formula3] = f; + } else if (reader.name() == QLatin1String("dataBar")) { + readCfDataBar(reader, rule); + } else if (reader.name() == QLatin1String("colorScale")) { + readCfColorScale(reader, rule); + } + } + if (reader.tokenType() == QXmlStreamReader::EndElement + && reader.name() == QStringLiteral("conditionalFormatting")) { + break; + } + } + return true; +} + +bool ConditionalFormattingPrivate::readCfDataBar(QXmlStreamReader &reader, XlsxCfRuleData *rule) +{ + Q_ASSERT(reader.name() == QLatin1String("dataBar")); + QXmlStreamAttributes attrs = reader.attributes(); + if (attrs.value(QLatin1String("showValue")) == QLatin1String("0")) + rule->attrs[XlsxCfRuleData::A_hideData] = QStringLiteral("1"); + + while (!reader.atEnd()) { + reader.readNextStartElement(); + if (reader.tokenType() == QXmlStreamReader::StartElement) { + if (reader.name() == QLatin1String("cfvo")) { + XlsxCfVoData data; + readCfVo(reader, data); + if (!rule->attrs.contains(XlsxCfRuleData::A_cfvo1)) + rule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(data); + else + rule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(data); + } else if (reader.name() == QLatin1String("color")) { + XlsxColor color; + color.loadFromXml(reader); + rule->attrs[XlsxCfRuleData::A_color1] = color; + } + } + if (reader.tokenType() == QXmlStreamReader::EndElement + && reader.name() == QStringLiteral("dataBar")) { + break; + } + } + + return true; +} + +bool ConditionalFormattingPrivate::readCfColorScale(QXmlStreamReader &reader, XlsxCfRuleData *rule) +{ + Q_ASSERT(reader.name() == QLatin1String("colorScale")); + + while (!reader.atEnd()) { + reader.readNextStartElement(); + if (reader.tokenType() == QXmlStreamReader::StartElement) { + if (reader.name() == QLatin1String("cfvo")) { + XlsxCfVoData data; + readCfVo(reader, data); + if (!rule->attrs.contains(XlsxCfRuleData::A_cfvo1)) + rule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(data); + else if (!rule->attrs.contains(XlsxCfRuleData::A_cfvo2)) + rule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(data); + else + rule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(data); + } else if (reader.name() == QLatin1String("color")) { + XlsxColor color; + color.loadFromXml(reader); + if (!rule->attrs.contains(XlsxCfRuleData::A_color1)) + rule->attrs[XlsxCfRuleData::A_color1] = color; + else if (!rule->attrs.contains(XlsxCfRuleData::A_color2)) + rule->attrs[XlsxCfRuleData::A_color2] = color; + else + rule->attrs[XlsxCfRuleData::A_color3] = color; + } + } + if (reader.tokenType() == QXmlStreamReader::EndElement + && reader.name() == QStringLiteral("colorScale")) { + break; + } + } + + return true; +} + +bool ConditionalFormattingPrivate::readCfVo(QXmlStreamReader &reader, XlsxCfVoData &cfvo) +{ + Q_ASSERT(reader.name() == QStringLiteral("cfvo")); + + QXmlStreamAttributes attrs = reader.attributes(); + + QString type = attrs.value(QLatin1String("type")).toString(); + ConditionalFormatting::ValueObjectType t; + if (type == QLatin1String("formula")) + t = ConditionalFormatting::VOT_Formula; + else if (type == QLatin1String("max")) + t = ConditionalFormatting::VOT_Max; + else if (type == QLatin1String("min")) + t = ConditionalFormatting::VOT_Min; + else if (type == QLatin1String("num")) + t = ConditionalFormatting::VOT_Num; + else if (type == QLatin1String("percent")) + t = ConditionalFormatting::VOT_Percent; + else //if (type == QLatin1String("percentile")) + t = ConditionalFormatting::VOT_Percentile; + + cfvo.type = t; + cfvo.value = attrs.value(QLatin1String("val")).toString(); + if (attrs.value(QLatin1String("gte")) == QLatin1String("0")) { + //default is true + cfvo.gte = false; + } + return true; +} + +bool ConditionalFormatting::loadFromXml(QXmlStreamReader &reader, Styles *styles) +{ + Q_ASSERT(reader.name() == QStringLiteral("conditionalFormatting")); + + d->ranges.clear(); + d->cfRules.clear(); + QXmlStreamAttributes attrs = reader.attributes(); + QString sqref = attrs.value(QLatin1String("sqref")).toString(); + foreach (QString range, sqref.split(QLatin1Char(' '))) + this->addRange(range); + + while (!reader.atEnd()) { + reader.readNextStartElement(); + if (reader.tokenType() == QXmlStreamReader::StartElement) { + if (reader.name() == QLatin1String("cfRule")) { + QSharedPointer cfRule(new XlsxCfRuleData); + d->readCfRule(reader, cfRule.data(), styles); + d->cfRules.append(cfRule); + } + } + if (reader.tokenType() == QXmlStreamReader::EndElement + && reader.name() == QStringLiteral("conditionalFormatting")) { + break; + } + } + + + return true; +} + +bool ConditionalFormatting::saveToXml(QXmlStreamWriter &writer) const +{ + writer.writeStartElement(QStringLiteral("conditionalFormatting")); + QStringList sqref; + foreach (CellRange range, ranges()) + sqref.append(range.toString()); + writer.writeAttribute(QStringLiteral("sqref"), sqref.join(QLatin1Char(' '))); + + for (int i=0; icfRules.size(); ++i) { + const QSharedPointer &rule = d->cfRules[i]; + writer.writeStartElement(QStringLiteral("cfRule")); + writer.writeAttribute(QStringLiteral("type"), rule->attrs[XlsxCfRuleData::A_type].toString()); + if (rule->dxfFormat.dxfIndexValid()) + writer.writeAttribute(QStringLiteral("dxfId"), QString::number(rule->dxfFormat.dxfIndex())); + writer.writeAttribute(QStringLiteral("priority"), QString::number(rule->priority)); + if (rule->attrs.contains(XlsxCfRuleData::A_stopIfTrue)) + writer.writeAttribute(QStringLiteral("stopIfTrue"), rule->attrs[XlsxCfRuleData::A_stopIfTrue].toString()); + if (rule->attrs.contains(XlsxCfRuleData::A_aboveAverage)) + writer.writeAttribute(QStringLiteral("aboveAverage"), rule->attrs[XlsxCfRuleData::A_aboveAverage].toString()); + if (rule->attrs.contains(XlsxCfRuleData::A_percent)) + writer.writeAttribute(QStringLiteral("percent"), rule->attrs[XlsxCfRuleData::A_percent].toString()); + if (rule->attrs.contains(XlsxCfRuleData::A_bottom)) + writer.writeAttribute(QStringLiteral("bottom"), rule->attrs[XlsxCfRuleData::A_bottom].toString()); + if (rule->attrs.contains(XlsxCfRuleData::A_operator)) + writer.writeAttribute(QStringLiteral("operator"), rule->attrs[XlsxCfRuleData::A_operator].toString()); + if (rule->attrs.contains(XlsxCfRuleData::A_text)) + writer.writeAttribute(QStringLiteral("text"), rule->attrs[XlsxCfRuleData::A_text].toString()); + if (rule->attrs.contains(XlsxCfRuleData::A_timePeriod)) + writer.writeAttribute(QStringLiteral("timePeriod"), rule->attrs[XlsxCfRuleData::A_timePeriod].toString()); + if (rule->attrs.contains(XlsxCfRuleData::A_rank)) + writer.writeAttribute(QStringLiteral("rank"), rule->attrs[XlsxCfRuleData::A_rank].toString()); + if (rule->attrs.contains(XlsxCfRuleData::A_stdDev)) + writer.writeAttribute(QStringLiteral("stdDev"), rule->attrs[XlsxCfRuleData::A_stdDev].toString()); + if (rule->attrs.contains(XlsxCfRuleData::A_equalAverage)) + writer.writeAttribute(QStringLiteral("equalAverage"), rule->attrs[XlsxCfRuleData::A_equalAverage].toString()); + + if (rule->attrs[XlsxCfRuleData::A_type] == QLatin1String("dataBar")) { + writer.writeStartElement(QStringLiteral("dataBar")); + if (rule->attrs.contains(XlsxCfRuleData::A_hideData)) + writer.writeAttribute(QStringLiteral("showValue"), QStringLiteral("0")); + d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo1].value()); + d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo2].value()); + rule->attrs[XlsxCfRuleData::A_color1].value().saveToXml(writer); + writer.writeEndElement();//dataBar + } else if (rule->attrs[XlsxCfRuleData::A_type] == QLatin1String("colorScale")) { + writer.writeStartElement(QStringLiteral("colorScale")); + d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo1].value()); + d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo2].value()); + if (rule->attrs.contains(XlsxCfRuleData::A_cfvo3)) + d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo3].value()); + + rule->attrs[XlsxCfRuleData::A_color1].value().saveToXml(writer); + rule->attrs[XlsxCfRuleData::A_color2].value().saveToXml(writer); + if (rule->attrs.contains(XlsxCfRuleData::A_color3)) + rule->attrs[XlsxCfRuleData::A_color3].value().saveToXml(writer); + + writer.writeEndElement();//colorScale + } + + + if (rule->attrs.contains(XlsxCfRuleData::A_formula1_temp)) { + QString startCell = ranges()[0].toString().split(QLatin1Char(':'))[0]; + writer.writeTextElement(QStringLiteral("formula"), rule->attrs[XlsxCfRuleData::A_formula1_temp].toString().arg(startCell)); + } else if (rule->attrs.contains(XlsxCfRuleData::A_formula1)) { + writer.writeTextElement(QStringLiteral("formula"), rule->attrs[XlsxCfRuleData::A_formula1].toString()); + } + if (rule->attrs.contains(XlsxCfRuleData::A_formula2)) + writer.writeTextElement(QStringLiteral("formula"), rule->attrs[XlsxCfRuleData::A_formula2].toString()); + if (rule->attrs.contains(XlsxCfRuleData::A_formula3)) + writer.writeTextElement(QStringLiteral("formula"), rule->attrs[XlsxCfRuleData::A_formula3].toString()); + + writer.writeEndElement(); //cfRule + } + + writer.writeEndElement(); //conditionalFormatting + return true; +} + +QT_END_NAMESPACE_XLSX diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxconditionalformatting.h b/platform/src/include/public/pub_excel/xlsx/xlsxconditionalformatting.h new file mode 100644 index 00000000..45378f73 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxconditionalformatting.h @@ -0,0 +1,135 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#ifndef QXLSX_XLSXCONDITIONALFORMATTING_H +#define QXLSX_XLSXCONDITIONALFORMATTING_H + +#include "xlsxglobal.h" +#include "xlsxcellrange.h" +#include "xlsxcellreference.h" +#include +#include +#include + +class QXmlStreamReader; +class QXmlStreamWriter; +class QColor; +class ConditionalFormattingTest; + +QT_BEGIN_NAMESPACE_XLSX + +class Format; +class Worksheet; +class Styles; + +class ConditionalFormattingPrivate; +class Q_XLSX_EXPORT ConditionalFormatting +{ +public: + enum HighlightRuleType { + Highlight_LessThan, + Highlight_LessThanOrEqual, + Highlight_Equal, + Highlight_NotEqual, + Highlight_GreaterThanOrEqual, + Highlight_GreaterThan, + Highlight_Between, + Highlight_NotBetween, + + Highlight_ContainsText, + Highlight_NotContainsText, + Highlight_BeginsWith, + Highlight_EndsWith, + + Highlight_TimePeriod, + + Highlight_Duplicate, + Highlight_Unique, + Highlight_Blanks, + Highlight_NoBlanks, + Highlight_Errors, + Highlight_NoErrors, + + Highlight_Top, + Highlight_TopPercent, + Highlight_Bottom, + Highlight_BottomPercent, + + Highlight_AboveAverage, + Highlight_AboveOrEqualAverage, + Highlight_AboveStdDev1, + Highlight_AboveStdDev2, + Highlight_AboveStdDev3, + Highlight_BelowAverage, + Highlight_BelowOrEqualAverage, + Highlight_BelowStdDev1, + Highlight_BelowStdDev2, + Highlight_BelowStdDev3, + + Highlight_Expression + }; + + enum ValueObjectType + { + VOT_Formula, + VOT_Max, + VOT_Min, + VOT_Num, + VOT_Percent, + VOT_Percentile + }; + + ConditionalFormatting(); + ConditionalFormatting(const ConditionalFormatting &other); + ~ConditionalFormatting(); + + bool addHighlightCellsRule(HighlightRuleType type, const Format &format, bool stopIfTrue=false); + bool addHighlightCellsRule(HighlightRuleType type, const QString &formula1, const Format &format, bool stopIfTrue=false); + bool addHighlightCellsRule(HighlightRuleType type, const QString &formula1, const QString &formula2, const Format &format, bool stopIfTrue=false); + bool addDataBarRule(const QColor &color, bool showData=true, bool stopIfTrue=false); + bool addDataBarRule(const QColor &color, ValueObjectType type1, const QString &val1, ValueObjectType type2, const QString &val2, bool showData=true, bool stopIfTrue=false); + bool add2ColorScaleRule(const QColor &minColor, const QColor &maxColor, bool stopIfTrue=false); + bool add3ColorScaleRule(const QColor &minColor, const QColor &midColor, const QColor &maxColor, bool stopIfTrue=false); + + QList ranges() const; + + void addCell(const CellReference &cell); + void addCell(int row, int col); + void addRange(int firstRow, int firstCol, int lastRow, int lastCol); + void addRange(const CellRange &range); + + //needed by QSharedDataPointer!! + ConditionalFormatting &operator=(const ConditionalFormatting &other); + +private: + friend class Worksheet; + friend class ::ConditionalFormattingTest; + bool saveToXml(QXmlStreamWriter &writer) const; + bool loadFromXml(QXmlStreamReader &reader, Styles *styles=0); + QSharedDataPointer d; +}; + +QT_END_NAMESPACE_XLSX + +#endif // QXLSX_XLSXCONDITIONALFORMATTING_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxconditionalformatting_p.h b/platform/src/include/public/pub_excel/xlsx/xlsxconditionalformatting_p.h new file mode 100644 index 00000000..ff71e5b4 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxconditionalformatting_p.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ + +#ifndef XLSXCONDITIONALFORMATTING_P_H +#define XLSXCONDITIONALFORMATTING_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Xlsx API. It exists for the convenience +// of the Qt Xlsx. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "xlsxconditionalformatting.h" +#include "xlsxformat.h" +#include "xlsxcolor_p.h" +#include +#include +#include + +QT_BEGIN_NAMESPACE_XLSX + +class XlsxCfVoData +{ +public: + XlsxCfVoData() + :gte(true) + { + } + + XlsxCfVoData(ConditionalFormatting::ValueObjectType type, const QString &value, bool gte=true) + :type(type), value(value), gte(gte) + { + } + + ConditionalFormatting::ValueObjectType type; + QString value; + bool gte; +}; + +class XlsxCfRuleData +{ +public: + enum Attribute { + A_type, + A_dxfId, + //A_priority, + A_stopIfTrue, + A_aboveAverage, + A_percent, + A_bottom, + A_operator, + A_text, + A_timePeriod, + A_rank, + A_stdDev, + A_equalAverage, + + A_dxfFormat, + A_formula1, + A_formula2, + A_formula3, + A_formula1_temp, + + A_color1, + A_color2, + A_color3, + + A_cfvo1, + A_cfvo2, + A_cfvo3, + + A_hideData + }; + + XlsxCfRuleData() + :priority(1) + {} + + int priority; + Format dxfFormat; + QMap attrs; +}; + +class ConditionalFormattingPrivate : public QSharedData +{ +public: + ConditionalFormattingPrivate(); + ConditionalFormattingPrivate(const ConditionalFormattingPrivate &other); + ~ConditionalFormattingPrivate(); + + void writeCfVo(QXmlStreamWriter &writer, const XlsxCfVoData& cfvo) const; + bool readCfVo(QXmlStreamReader &reader, XlsxCfVoData& cfvo); + bool readCfRule(QXmlStreamReader &reader, XlsxCfRuleData *cfRule, Styles *styles); + bool readCfDataBar(QXmlStreamReader &reader, XlsxCfRuleData *cfRule); + bool readCfColorScale(QXmlStreamReader &reader, XlsxCfRuleData *cfRule); + + QList >cfRules; + QList ranges; +}; + +QT_END_NAMESPACE_XLSX + +Q_DECLARE_METATYPE(QXlsx::XlsxCfVoData) +#endif // XLSXCONDITIONALFORMATTING_P_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxcontenttypes.cpp b/platform/src/include/public/pub_excel/xlsx/xlsxcontenttypes.cpp new file mode 100644 index 00000000..8a500ac9 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxcontenttypes.cpp @@ -0,0 +1,205 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#include "xlsxcontenttypes_p.h" +#include +#include +#include +#include +#include +#include + +namespace QXlsx { + +ContentTypes::ContentTypes(CreateFlag flag) + :AbstractOOXmlFile(flag) +{ + m_package_prefix = QStringLiteral("application/vnd.openxmlformats-package."); + m_document_prefix = QStringLiteral("application/vnd.openxmlformats-officedocument."); + + m_defaults.insert(QStringLiteral("rels"), m_package_prefix + QStringLiteral("relationships+xml")); + m_defaults.insert(QStringLiteral("xml"), QStringLiteral("application/xml")); +} + +void ContentTypes::addDefault(const QString &key, const QString &value) +{ + m_defaults.insert(key, value); +} + +void ContentTypes::addOverride(const QString &key, const QString &value) +{ + m_overrides.insert(key, value); +} + +void ContentTypes::addDocPropApp() +{ + addOverride(QStringLiteral("/docProps/app.xml"), m_document_prefix + QStringLiteral("extended-properties+xml")); +} + +void ContentTypes::addDocPropCore() +{ + addOverride(QStringLiteral("/docProps/core.xml"), m_package_prefix + QStringLiteral("core-properties+xml")); +} + +void ContentTypes::addStyles() +{ + addOverride(QStringLiteral("/xl/styles.xml"), m_document_prefix + QStringLiteral("spreadsheetml.styles+xml")); +} + +void ContentTypes::addTheme() +{ + addOverride(QStringLiteral("/xl/theme/theme1.xml"), m_document_prefix + QStringLiteral("theme+xml")); +} + +void ContentTypes::addWorkbook() +{ + addOverride(QStringLiteral("/xl/workbook.xml"), m_document_prefix + QStringLiteral("spreadsheetml.sheet.main+xml")); +} + +void ContentTypes::addWorksheetName(const QString &name) +{ + addOverride(QStringLiteral("/xl/worksheets/%1.xml").arg(name), m_document_prefix + QStringLiteral("spreadsheetml.worksheet+xml")); +} + +void ContentTypes::addChartsheetName(const QString &name) +{ + addOverride(QStringLiteral("/xl/chartsheets/%1.xml").arg(name), m_document_prefix + QStringLiteral("spreadsheetml.chartsheet+xml")); +} + +void ContentTypes::addDrawingName(const QString &name) +{ + addOverride(QStringLiteral("/xl/drawings/%1.xml").arg(name), m_document_prefix + QStringLiteral("drawing+xml")); +} + +void ContentTypes::addChartName(const QString &name) +{ + addOverride(QStringLiteral("/xl/charts/%1.xml").arg(name), m_document_prefix + QStringLiteral("drawingml.chart+xml")); +} + +void ContentTypes::addCommentName(const QString &name) +{ + addOverride(QStringLiteral("/xl/%1.xml").arg(name), m_document_prefix + QStringLiteral("spreadsheetml.comments+xml")); +} + +void ContentTypes::addTableName(const QString &name) +{ + addOverride(QStringLiteral("/xl/tables/%1.xml").arg(name), m_document_prefix + QStringLiteral("spreadsheetml.table+xml")); +} + +void ContentTypes::addExternalLinkName(const QString &name) +{ + addOverride(QStringLiteral("/xl/externalLinks/%1.xml").arg(name), m_document_prefix + QStringLiteral("spreadsheetml.externalLink+xml")); +} + +void ContentTypes::addSharedString() +{ + addOverride(QStringLiteral("/xl/sharedStrings.xml"), m_document_prefix + QStringLiteral("spreadsheetml.sharedStrings+xml")); +} + +void ContentTypes::addVmlName() +{ + addOverride(QStringLiteral("vml"), m_document_prefix + QStringLiteral("vmlDrawing")); +} + +void ContentTypes::addCalcChain() +{ + addOverride(QStringLiteral("/xl/calcChain.xml"), m_document_prefix + QStringLiteral("spreadsheetml.calcChain+xml")); +} + +void ContentTypes::addVbaProject() +{ + //:TODO + addOverride(QStringLiteral("bin"), QStringLiteral("application/vnd.ms-office.vbaProject")); +} + +void ContentTypes::clearOverrides() +{ + m_overrides.clear(); +} + +void ContentTypes::saveToXmlFile(QIODevice *device) const +{ + QXmlStreamWriter writer(device); + + writer.writeStartDocument(QStringLiteral("1.0"), true); + writer.writeStartElement(QStringLiteral("Types")); + writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.openxmlformats.org/package/2006/content-types")); + + { + QMapIterator it(m_defaults); + while (it.hasNext()) { + it.next(); + writer.writeStartElement(QStringLiteral("Default")); + writer.writeAttribute(QStringLiteral("Extension"), it.key()); + writer.writeAttribute(QStringLiteral("ContentType"), it.value()); + writer.writeEndElement();//Default + } + } + + { + QMapIterator it(m_overrides); + while (it.hasNext()) { + it.next(); + writer.writeStartElement(QStringLiteral("Override")); + writer.writeAttribute(QStringLiteral("PartName"), it.key()); + writer.writeAttribute(QStringLiteral("ContentType"), it.value()); + writer.writeEndElement(); //Override + } + } + + writer.writeEndElement();//Types + writer.writeEndDocument(); + +} + +bool ContentTypes::loadFromXmlFile(QIODevice *device) +{ + m_defaults.clear(); + m_overrides.clear(); + + QXmlStreamReader reader(device); + while (!reader.atEnd()) { + QXmlStreamReader::TokenType token = reader.readNext(); + if (token == QXmlStreamReader::StartElement) { + if (reader.name() == QLatin1String("Default")) { + QXmlStreamAttributes attrs = reader.attributes(); + QString extension = attrs.value(QLatin1String("Extension")).toString(); + QString type = attrs.value(QLatin1String("ContentType")).toString(); + m_defaults.insert(extension, type); + } else if (reader.name() == QLatin1String("Override")) { + QXmlStreamAttributes attrs = reader.attributes(); + QString partName = attrs.value(QLatin1String("PartName")).toString(); + QString type = attrs.value(QLatin1String("ContentType")).toString(); + m_overrides.insert(partName, type); + } + } + + if (reader.hasError()) { + qDebug()< +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#ifndef XLSXCONTENTTYPES_H +#define XLSXCONTENTTYPES_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Xlsx API. It exists for the convenience +// of the Qt Xlsx. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "xlsxabstractooxmlfile.h" + +#include +#include +#include + +class QIODevice; + +namespace QXlsx { + +class ContentTypes : public AbstractOOXmlFile +{ +public: + ContentTypes(CreateFlag flag); + + void addDefault(const QString &key, const QString &value); + void addOverride(const QString &key, const QString &value); + + //Convenient funcation for addOverride() + void addDocPropCore(); + void addDocPropApp(); + void addStyles(); + void addTheme(); + void addWorkbook(); + void addWorksheetName(const QString &name); + void addChartsheetName(const QString &name); + void addChartName(const QString &name); + void addDrawingName(const QString &name); + void addCommentName(const QString &name); + void addTableName(const QString &name); + void addExternalLinkName(const QString &name); + void addSharedString(); + void addVmlName(); + void addCalcChain(); + void addVbaProject(); + + void clearOverrides(); + + void saveToXmlFile(QIODevice *device) const; + bool loadFromXmlFile(QIODevice *device); +private: + QMap m_defaults; + QMap m_overrides; + + QString m_package_prefix; + QString m_document_prefix; +}; + +} +#endif // XLSXCONTENTTYPES_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxdatavalidation.cpp b/platform/src/include/public/pub_excel/xlsx/xlsxdatavalidation.cpp new file mode 100644 index 00000000..c538c728 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxdatavalidation.cpp @@ -0,0 +1,552 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ + +#include "xlsxdatavalidation.h" +#include "xlsxdatavalidation_p.h" +#include "xlsxworksheet.h" +#include "xlsxcellrange.h" + +#include +#include + +QT_BEGIN_NAMESPACE_XLSX + +DataValidationPrivate::DataValidationPrivate() + :validationType(DataValidation::None), validationOperator(DataValidation::Between) + , errorStyle(DataValidation::Stop), allowBlank(false), isPromptMessageVisible(true) + , isErrorMessageVisible(true) +{ + +} + +DataValidationPrivate::DataValidationPrivate(DataValidation::ValidationType type, DataValidation::ValidationOperator op, const QString &formula1, const QString &formula2, bool allowBlank) + :validationType(type), validationOperator(op) + , errorStyle(DataValidation::Stop), allowBlank(allowBlank), isPromptMessageVisible(true) + , isErrorMessageVisible(true), formula1(formula1), formula2(formula2) +{ + +} + +DataValidationPrivate::DataValidationPrivate(const DataValidationPrivate &other) + :QSharedData(other) + , validationType(DataValidation::None), validationOperator(DataValidation::Between) + , errorStyle(DataValidation::Stop), allowBlank(false), isPromptMessageVisible(true) + , isErrorMessageVisible(true) +{ + +} + +DataValidationPrivate::~DataValidationPrivate() +{ + +} + +/*! + * \class DataValidation + * \brief Data validation for single cell or a range + * \inmodule QtXlsx + * + * The data validation can be applied to a single cell or a range of cells. + */ + +/*! + * \enum DataValidation::ValidationType + * + * The enum type defines the type of data that you wish to validate. + * + * \value None the type of data is unrestricted. This is the same as not applying a data validation. + * \value Whole restricts the cell to integer values. Means "Whole number"? + * \value Decimal restricts the cell to decimal values. + * \value List restricts the cell to a set of user specified values. + * \value Date restricts the cell to date values. + * \value Time restricts the cell to time values. + * \value TextLength restricts the cell data based on an integer string length. + * \value Custom restricts the cell based on an external Excel formula that returns a true/false value. + */ + +/*! + * \enum DataValidation::ValidationOperator + * + * The enum type defines the criteria by which the data in the + * cell is validated + * + * \value Between + * \value NotBetween + * \value Equal + * \value NotEqual + * \value LessThan + * \value LessThanOrEqual + * \value GreaterThan + * \value GreaterThanOrEqual + */ + +/*! + * \enum DataValidation::ErrorStyle + * + * The enum type defines the type of error dialog that + * is displayed. + * + * \value Stop + * \value Warning + * \value Information + */ + +/*! + * Construct a data validation object with the given \a type, \a op, \a formula1 + * \a formula2, and \a allowBlank. + */ +DataValidation::DataValidation(ValidationType type, ValidationOperator op, const QString &formula1, const QString &formula2, bool allowBlank) + :d(new DataValidationPrivate(type, op, formula1, formula2, allowBlank)) +{ + +} + +/*! + Construct a data validation object +*/ +DataValidation::DataValidation() + :d(new DataValidationPrivate()) +{ + +} + +/*! + Constructs a copy of \a other. +*/ +DataValidation::DataValidation(const DataValidation &other) + :d(other.d) +{ + +} + +/*! + Assigns \a other to this validation and returns a reference to this validation. + */ +DataValidation &DataValidation::operator=(const DataValidation &other) +{ + this->d = other.d; + return *this; +} + + +/*! + * Destroy the object. + */ +DataValidation::~DataValidation() +{ +} + +/*! + Returns the validation type. + */ +DataValidation::ValidationType DataValidation::validationType() const +{ + return d->validationType; +} + +/*! + Returns the validation operator. + */ +DataValidation::ValidationOperator DataValidation::validationOperator() const +{ + return d->validationOperator; +} + +/*! + Returns the validation error style. + */ +DataValidation::ErrorStyle DataValidation::errorStyle() const +{ + return d->errorStyle; +} + +/*! + Returns the formula1. + */ +QString DataValidation::formula1() const +{ + return d->formula1; +} + +/*! + Returns the formula2. + */ +QString DataValidation::formula2() const +{ + return d->formula2; +} + +/*! + Returns whether blank is allowed. + */ +bool DataValidation::allowBlank() const +{ + return d->allowBlank; +} + +/*! + Returns the error message. + */ +QString DataValidation::errorMessage() const +{ + return d->errorMessage; +} + +/*! + Returns the error message title. + */ +QString DataValidation::errorMessageTitle() const +{ + return d->errorMessageTitle; +} + +/*! + Returns the prompt message. + */ +QString DataValidation::promptMessage() const +{ + return d->promptMessage; +} + +/*! + Returns the prompt message title. + */ +QString DataValidation::promptMessageTitle() const +{ + return d->promptMessageTitle; +} + +/*! + Returns the whether prompt message is shown. + */ +bool DataValidation::isPromptMessageVisible() const +{ + return d->isPromptMessageVisible; +} + +/*! + Returns the whether error message is shown. + */ +bool DataValidation::isErrorMessageVisible() const +{ + return d->isErrorMessageVisible; +} + +/*! + Returns the ranges on which the validation will be applied. + */ +QList DataValidation::ranges() const +{ + return d->ranges; +} + +/*! + Sets the validation type to \a type. + */ +void DataValidation::setValidationType(DataValidation::ValidationType type) +{ + d->validationType = type; +} + +/*! + Sets the validation operator to \a op. + */ +void DataValidation::setValidationOperator(DataValidation::ValidationOperator op) +{ + d->validationOperator = op; +} + +/*! + Sets the error style to \a es. + */ +void DataValidation::setErrorStyle(DataValidation::ErrorStyle es) +{ + d->errorStyle = es; +} + +/*! + Sets the formula1 to \a formula. + */ +void DataValidation::setFormula1(const QString &formula) +{ + if (formula.startsWith(QLatin1Char('='))) + d->formula1 = formula.mid(1); + else + d->formula1 = formula; +} + +/*! + Sets the formulas to \a formula. + */ +void DataValidation::setFormula2(const QString &formula) +{ + if (formula.startsWith(QLatin1Char('='))) + d->formula2 = formula.mid(1); + else + d->formula2 = formula; +} + +/*! + Sets the error message to \a error with title \a title. + */ +void DataValidation::setErrorMessage(const QString &error, const QString &title) +{ + d->errorMessage = error; + d->errorMessageTitle = title; +} + +/*! + Sets the prompt message to \a prompt with title \a title. + */ +void DataValidation::setPromptMessage(const QString &prompt, const QString &title) +{ + d->promptMessage = prompt; + d->promptMessageTitle = title; +} + +/*! + Enable/disabe blank allow based on \a enable. + */ +void DataValidation::setAllowBlank(bool enable) +{ + d->allowBlank = enable; +} + +/*! + Enable/disabe prompt message visible based on \a visible. + */ +void DataValidation::setPromptMessageVisible(bool visible) +{ + d->isPromptMessageVisible = visible; +} + +/*! + Enable/disabe error message visible based on \a visible. + */ +void DataValidation::setErrorMessageVisible(bool visible) +{ + d->isErrorMessageVisible = visible; +} + +/*! + Add the \a cell on which the DataValidation will apply to. + */ +void DataValidation::addCell(const CellReference &cell) +{ + d->ranges.append(CellRange(cell, cell)); +} + +/*! + \overload + Add the cell(\a row, \a col) on which the DataValidation will apply to. + */ +void DataValidation::addCell(int row, int col) +{ + d->ranges.append(CellRange(row, col, row, col)); +} + +/*! + \overload + Add the range(\a firstRow, \a firstCol, \a lastRow, \a lastCol) on + which the DataValidation will apply to. + */ +void DataValidation::addRange(int firstRow, int firstCol, int lastRow, int lastCol) +{ + d->ranges.append(CellRange(firstRow, firstCol, lastRow, lastCol)); +} + +/*! + Add the \a range on which the DataValidation will apply to. + */ +void DataValidation::addRange(const CellRange &range) +{ + d->ranges.append(range); +} + +/*! + * \internal + */ +bool DataValidation::saveToXml(QXmlStreamWriter &writer) const +{ + static QMap typeMap; + static QMap opMap; + static QMap esMap; + if (typeMap.isEmpty()) { + typeMap.insert(DataValidation::None, QStringLiteral("none")); + typeMap.insert(DataValidation::Whole, QStringLiteral("whole")); + typeMap.insert(DataValidation::Decimal, QStringLiteral("decimal")); + typeMap.insert(DataValidation::List, QStringLiteral("list")); + typeMap.insert(DataValidation::Date, QStringLiteral("date")); + typeMap.insert(DataValidation::Time, QStringLiteral("time")); + typeMap.insert(DataValidation::TextLength, QStringLiteral("textLength")); + typeMap.insert(DataValidation::Custom, QStringLiteral("custom")); + + opMap.insert(DataValidation::Between, QStringLiteral("between")); + opMap.insert(DataValidation::NotBetween, QStringLiteral("notBetween")); + opMap.insert(DataValidation::Equal, QStringLiteral("equal")); + opMap.insert(DataValidation::NotEqual, QStringLiteral("notEqual")); + opMap.insert(DataValidation::LessThan, QStringLiteral("lessThan")); + opMap.insert(DataValidation::LessThanOrEqual, QStringLiteral("lessThanOrEqual")); + opMap.insert(DataValidation::GreaterThan, QStringLiteral("greaterThan")); + opMap.insert(DataValidation::GreaterThanOrEqual, QStringLiteral("greaterThanOrEqual")); + + esMap.insert(DataValidation::Stop, QStringLiteral("stop")); + esMap.insert(DataValidation::Warning, QStringLiteral("warning")); + esMap.insert(DataValidation::Information, QStringLiteral("information")); + } + + writer.writeStartElement(QStringLiteral("dataValidation")); + if (validationType() != DataValidation::None) + writer.writeAttribute(QStringLiteral("type"), typeMap[validationType()]); + if (errorStyle() != DataValidation::Stop) + writer.writeAttribute(QStringLiteral("errorStyle"), esMap[errorStyle()]); + if (validationOperator() != DataValidation::Between) + writer.writeAttribute(QStringLiteral("operator"), opMap[validationOperator()]); + if (allowBlank()) + writer.writeAttribute(QStringLiteral("allowBlank"), QStringLiteral("1")); + // if (dropDownVisible()) + // writer.writeAttribute(QStringLiteral("showDropDown"), QStringLiteral("1")); + if (isPromptMessageVisible()) + writer.writeAttribute(QStringLiteral("showInputMessage"), QStringLiteral("1")); + if (isErrorMessageVisible()) + writer.writeAttribute(QStringLiteral("showErrorMessage"), QStringLiteral("1")); + if (!errorMessageTitle().isEmpty()) + writer.writeAttribute(QStringLiteral("errorTitle"), errorMessageTitle()); + if (!errorMessage().isEmpty()) + writer.writeAttribute(QStringLiteral("error"), errorMessage()); + if (!promptMessageTitle().isEmpty()) + writer.writeAttribute(QStringLiteral("promptTitle"), promptMessageTitle()); + if (!promptMessage().isEmpty()) + writer.writeAttribute(QStringLiteral("prompt"), promptMessage()); + + QStringList sqref; + foreach (CellRange range, ranges()) + sqref.append(range.toString()); + writer.writeAttribute(QStringLiteral("sqref"), sqref.join(QLatin1Char(' '))); + + if (!formula1().isEmpty()) + writer.writeTextElement(QStringLiteral("formula1"), formula1()); + if (!formula2().isEmpty()) + writer.writeTextElement(QStringLiteral("formula2"), formula2()); + + writer.writeEndElement(); //dataValidation + + return true; +} + +/*! + * \internal + */ +DataValidation DataValidation::loadFromXml(QXmlStreamReader &reader) +{ + Q_ASSERT(reader.name() == QLatin1String("dataValidation")); + + static QMap typeMap; + static QMap opMap; + static QMap esMap; + if (typeMap.isEmpty()) { + typeMap.insert(QStringLiteral("none"), DataValidation::None); + typeMap.insert(QStringLiteral("whole"), DataValidation::Whole); + typeMap.insert(QStringLiteral("decimal"), DataValidation::Decimal); + typeMap.insert(QStringLiteral("list"), DataValidation::List); + typeMap.insert(QStringLiteral("date"), DataValidation::Date); + typeMap.insert(QStringLiteral("time"), DataValidation::Time); + typeMap.insert(QStringLiteral("textLength"), DataValidation::TextLength); + typeMap.insert(QStringLiteral("custom"), DataValidation::Custom); + + opMap.insert(QStringLiteral("between"), DataValidation::Between); + opMap.insert(QStringLiteral("notBetween"), DataValidation::NotBetween); + opMap.insert(QStringLiteral("equal"), DataValidation::Equal); + opMap.insert(QStringLiteral("notEqual"), DataValidation::NotEqual); + opMap.insert(QStringLiteral("lessThan"), DataValidation::LessThan); + opMap.insert(QStringLiteral("lessThanOrEqual"), DataValidation::LessThanOrEqual); + opMap.insert(QStringLiteral("greaterThan"), DataValidation::GreaterThan); + opMap.insert(QStringLiteral("greaterThanOrEqual"), DataValidation::GreaterThanOrEqual); + + esMap.insert(QStringLiteral("stop"), DataValidation::Stop); + esMap.insert(QStringLiteral("warning"), DataValidation::Warning); + esMap.insert(QStringLiteral("information"), DataValidation::Information); + } + + DataValidation validation; + QXmlStreamAttributes attrs = reader.attributes(); + + QString sqref = attrs.value(QLatin1String("sqref")).toString(); + foreach (QString range, sqref.split(QLatin1Char(' '))) + validation.addRange(range); + + if (attrs.hasAttribute(QLatin1String("type"))) { + QString t = attrs.value(QLatin1String("type")).toString(); + validation.setValidationType(typeMap.contains(t) ? typeMap[t] : DataValidation::None); + } + if (attrs.hasAttribute(QLatin1String("errorStyle"))) { + QString es = attrs.value(QLatin1String("errorStyle")).toString(); + validation.setErrorStyle(esMap.contains(es) ? esMap[es] : DataValidation::Stop); + } + if (attrs.hasAttribute(QLatin1String("operator"))) { + QString op = attrs.value(QLatin1String("operator")).toString(); + validation.setValidationOperator(opMap.contains(op) ? opMap[op] : DataValidation::Between); + } + if (attrs.hasAttribute(QLatin1String("allowBlank"))) { + validation.setAllowBlank(true); + } else { + validation.setAllowBlank(false); + } + if (attrs.hasAttribute(QLatin1String("showInputMessage"))) { + validation.setPromptMessageVisible(true); + } else { + validation.setPromptMessageVisible(false); + } + if (attrs.hasAttribute(QLatin1String("showErrorMessage"))) { + validation.setErrorMessageVisible(true); + } else { + validation.setErrorMessageVisible(false); + } + + QString et = attrs.value(QLatin1String("errorTitle")).toString(); + QString e = attrs.value(QLatin1String("error")).toString(); + if (!e.isEmpty() || !et.isEmpty()) + validation.setErrorMessage(e, et); + + QString pt = attrs.value(QLatin1String("promptTitle")).toString(); + QString p = attrs.value(QLatin1String("prompt")).toString(); + if (!p.isEmpty() || !pt.isEmpty()) + validation.setPromptMessage(p, pt); + + //find the end + while(!(reader.name() == QLatin1String("dataValidation") && reader.tokenType() == QXmlStreamReader::EndElement)) { + reader.readNextStartElement(); + if (reader.tokenType() == QXmlStreamReader::StartElement) { + if (reader.name() == QLatin1String("formula1")) { + validation.setFormula1(reader.readElementText()); + } else if (reader.name() == QLatin1String("formula2")) { + validation.setFormula2(reader.readElementText()); + } + } + } + return validation; +} + +QT_END_NAMESPACE_XLSX diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxdatavalidation.h b/platform/src/include/public/pub_excel/xlsx/xlsxdatavalidation.h new file mode 100644 index 00000000..3a190792 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxdatavalidation.h @@ -0,0 +1,123 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#ifndef QXLSX_XLSXDATAVALIDATION_H +#define QXLSX_XLSXDATAVALIDATION_H + +#include "xlsxglobal.h" +#include +#include +#include + +class QXmlStreamReader; +class QXmlStreamWriter; + +QT_BEGIN_NAMESPACE_XLSX + +class Worksheet; +class CellRange; +class CellReference; + +class DataValidationPrivate; +class Q_XLSX_EXPORT DataValidation +{ +public: + enum ValidationType + { + None, + Whole, + Decimal, + List, + Date, + Time, + TextLength, + Custom + }; + + enum ValidationOperator + { + Between, + NotBetween, + Equal, + NotEqual, + LessThan, + LessThanOrEqual, + GreaterThan, + GreaterThanOrEqual + }; + + enum ErrorStyle + { + Stop, + Warning, + Information + }; + + DataValidation(); + DataValidation(ValidationType type, ValidationOperator op=Between, const QString &formula1=QString() + , const QString &formula2=QString(), bool allowBlank=false); + DataValidation(const DataValidation &other); + ~DataValidation(); + + ValidationType validationType() const; + ValidationOperator validationOperator() const; + ErrorStyle errorStyle() const; + QString formula1() const; + QString formula2() const; + bool allowBlank() const; + QString errorMessage() const; + QString errorMessageTitle() const; + QString promptMessage() const; + QString promptMessageTitle() const; + bool isPromptMessageVisible() const; + bool isErrorMessageVisible() const; + QList ranges() const; + + void setValidationType(ValidationType type); + void setValidationOperator(ValidationOperator op); + void setErrorStyle(ErrorStyle es); + void setFormula1(const QString &formula); + void setFormula2(const QString &formula); + void setErrorMessage(const QString &error, const QString &title=QString()); + void setPromptMessage(const QString &prompt, const QString &title=QString()); + void setAllowBlank(bool enable); + void setPromptMessageVisible(bool visible); + void setErrorMessageVisible(bool visible); + + void addCell(const CellReference &cell); + void addCell(int row, int col); + void addRange(int firstRow, int firstCol, int lastRow, int lastCol); + void addRange(const CellRange &range); + + DataValidation &operator=(const DataValidation &other); + + bool saveToXml(QXmlStreamWriter &writer) const; + static DataValidation loadFromXml(QXmlStreamReader &reader); +private: + QSharedDataPointer d; +}; + +QT_END_NAMESPACE_XLSX + +#endif // QXLSX_XLSXDATAVALIDATION_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxdatavalidation_p.h b/platform/src/include/public/pub_excel/xlsx/xlsxdatavalidation_p.h new file mode 100644 index 00000000..236bb3da --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxdatavalidation_p.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ + +#ifndef XLSXDATAVALIDATION_P_H +#define XLSXDATAVALIDATION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Xlsx API. It exists for the convenience +// of the Qt Xlsx. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "xlsxdatavalidation.h" +#include + +QT_BEGIN_NAMESPACE_XLSX + +class Q_XLSX_EXPORT DataValidationPrivate : public QSharedData +{ +public: + DataValidationPrivate(); + DataValidationPrivate(DataValidation::ValidationType type, DataValidation::ValidationOperator op, const QString &formula1, const QString &formula2, bool allowBlank); + DataValidationPrivate(const DataValidationPrivate &other); + ~DataValidationPrivate(); + + DataValidation::ValidationType validationType; + DataValidation::ValidationOperator validationOperator; + DataValidation::ErrorStyle errorStyle; + bool allowBlank; + bool isPromptMessageVisible; + bool isErrorMessageVisible; + QString formula1; + QString formula2; + QString errorMessage; + QString errorMessageTitle; + QString promptMessage; + QString promptMessageTitle; + QList ranges; +}; + +QT_END_NAMESPACE_XLSX +#endif // XLSXDATAVALIDATION_P_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxdocpropsapp.cpp b/platform/src/include/public/pub_excel/xlsx/xlsxdocpropsapp.cpp new file mode 100644 index 00000000..49ad9b29 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxdocpropsapp.cpp @@ -0,0 +1,157 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#include "xlsxdocpropsapp_p.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace QXlsx { + +DocPropsApp::DocPropsApp(CreateFlag flag) + :AbstractOOXmlFile(flag) +{ +} + +void DocPropsApp::addPartTitle(const QString &title) +{ + m_titlesOfPartsList.append(title); +} + +void DocPropsApp::addHeadingPair(const QString &name, int value) +{ + m_headingPairsList.append(qMakePair(name, value)); +} + +bool DocPropsApp::setProperty(const QString &name, const QString &value) +{ + static QStringList validKeys; + if (validKeys.isEmpty()) { + validKeys << QStringLiteral("manager") << QStringLiteral("company"); + } + + if (!validKeys.contains(name)) + return false; + + if (value.isEmpty()) + m_properties.remove(name); + else + m_properties[name] = value; + + return true; +} + +QString DocPropsApp::property(const QString &name) const +{ + if (m_properties.contains(name)) + return m_properties[name]; + + return QString(); +} + +QStringList DocPropsApp::propertyNames() const +{ + return m_properties.keys(); +} + +void DocPropsApp::saveToXmlFile(QIODevice *device) const +{ + QXmlStreamWriter writer(device); + QString vt = QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"); + + writer.writeStartDocument(QStringLiteral("1.0"), true); + writer.writeStartElement(QStringLiteral("Properties")); + writer.writeDefaultNamespace(QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/extended-properties")); + writer.writeNamespace(vt, QStringLiteral("vt")); + writer.writeTextElement(QStringLiteral("Application"), QStringLiteral("Microsoft Excel")); + writer.writeTextElement(QStringLiteral("DocSecurity"), QStringLiteral("0")); + writer.writeTextElement(QStringLiteral("ScaleCrop"), QStringLiteral("false")); + + writer.writeStartElement(QStringLiteral("HeadingPairs")); + writer.writeStartElement(vt, QStringLiteral("vector")); + writer.writeAttribute(QStringLiteral("size"), QString::number(m_headingPairsList.size()*2)); + writer.writeAttribute(QStringLiteral("baseType"), QStringLiteral("variant")); + typedef QPair PairType; //Make foreach happy + foreach (PairType pair, m_headingPairsList) { + writer.writeStartElement(vt, QStringLiteral("variant")); + writer.writeTextElement(vt, QStringLiteral("lpstr"), pair.first); + writer.writeEndElement(); //vt:variant + writer.writeStartElement(vt, QStringLiteral("variant")); + writer.writeTextElement(vt, QStringLiteral("i4"), QString::number(pair.second)); + writer.writeEndElement(); //vt:variant + } + writer.writeEndElement();//vt:vector + writer.writeEndElement();//HeadingPairs + + writer.writeStartElement(QStringLiteral("TitlesOfParts")); + writer.writeStartElement(vt, QStringLiteral("vector")); + writer.writeAttribute(QStringLiteral("size"), QString::number(m_titlesOfPartsList.size())); + writer.writeAttribute(QStringLiteral("baseType"), QStringLiteral("lpstr")); + foreach (QString title, m_titlesOfPartsList) + writer.writeTextElement(vt, QStringLiteral("lpstr"), title); + writer.writeEndElement();//vt:vector + writer.writeEndElement();//TitlesOfParts + + if (m_properties.contains(QStringLiteral("manager"))) + writer.writeTextElement(QStringLiteral("Manager"), m_properties[QStringLiteral("manager")]); + //Not like "manager", "company" always exists for Excel generated file. + writer.writeTextElement(QStringLiteral("Company"), m_properties.contains(QStringLiteral("company")) ? m_properties[QStringLiteral("company")]: QString()); + writer.writeTextElement(QStringLiteral("LinksUpToDate"), QStringLiteral("false")); + writer.writeTextElement(QStringLiteral("SharedDoc"), QStringLiteral("false")); + writer.writeTextElement(QStringLiteral("HyperlinksChanged"), QStringLiteral("false")); + writer.writeTextElement(QStringLiteral("AppVersion"), QStringLiteral("12.0000")); + + writer.writeEndElement(); //Properties + writer.writeEndDocument(); +} + +bool DocPropsApp::loadFromXmlFile(QIODevice *device) +{ + QXmlStreamReader reader(device); + while (!reader.atEnd()) { + QXmlStreamReader::TokenType token = reader.readNext(); + if (token == QXmlStreamReader::StartElement) { + if (reader.name() == QLatin1String("Properties")) + continue; + + if (reader.name() == QStringLiteral("Manager")) { + setProperty(QStringLiteral("manager"), reader.readElementText()); + } else if (reader.name() == QStringLiteral("Company")) { + setProperty(QStringLiteral("company"), reader.readElementText()); + } + } + + if (reader.hasError()) { + qDebug("Error when read doc props app file."); + } + } + return true; +} + +} //namespace diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxdocpropsapp_p.h b/platform/src/include/public/pub_excel/xlsx/xlsxdocpropsapp_p.h new file mode 100644 index 00000000..433731ea --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxdocpropsapp_p.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#ifndef XLSXDOCPROPSAPP_H +#define XLSXDOCPROPSAPP_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Xlsx API. It exists for the convenience +// of the Qt Xlsx. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "xlsxglobal.h" +#include "xlsxabstractooxmlfile.h" +#include +#include +#include +#include + +class QIODevice; + +namespace QXlsx { + +class XLSX_AUTOTEST_EXPORT DocPropsApp : public AbstractOOXmlFile +{ +public: + DocPropsApp(CreateFlag flag); + + void addPartTitle(const QString &title); + void addHeadingPair(const QString &name, int value); + + bool setProperty(const QString &name, const QString &value); + QString property(const QString &name) const; + QStringList propertyNames() const; + + void saveToXmlFile(QIODevice *device) const; + bool loadFromXmlFile(QIODevice *device); + +private: + QStringList m_titlesOfPartsList; + QList > m_headingPairsList; + QMap m_properties; +}; + +} +#endif // XLSXDOCPROPSAPP_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxdocpropscore.cpp b/platform/src/include/public/pub_excel/xlsx/xlsxdocpropscore.cpp new file mode 100644 index 00000000..7e955f8d --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxdocpropscore.cpp @@ -0,0 +1,168 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#include "xlsxdocpropscore_p.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace QXlsx { + +DocPropsCore::DocPropsCore(CreateFlag flag) + :AbstractOOXmlFile(flag) +{ +} + +bool DocPropsCore::setProperty(const QString &name, const QString &value) +{ + static QStringList validKeys; + if (validKeys.isEmpty()) { + validKeys << QStringLiteral("title") << QStringLiteral("subject") + << QStringLiteral("keywords") << QStringLiteral("description") + << QStringLiteral("category") << QStringLiteral("status") + << QStringLiteral("created") << QStringLiteral("creator"); + } + + if (!validKeys.contains(name)) + return false; + + if (value.isEmpty()) + m_properties.remove(name); + else + m_properties[name] = value; + + return true; +} + +QString DocPropsCore::property(const QString &name) const +{ + if (m_properties.contains(name)) + return m_properties[name]; + + return QString(); +} + +QStringList DocPropsCore::propertyNames() const +{ + return m_properties.keys(); +} + +void DocPropsCore::saveToXmlFile(QIODevice *device) const +{ + QXmlStreamWriter writer(device); + const QString cp = QStringLiteral("http://schemas.openxmlformats.org/package/2006/metadata/core-properties"); + const QString dc = QStringLiteral("http://purl.org/dc/elements/1.1/"); + const QString dcterms = QStringLiteral("http://purl.org/dc/terms/"); + const QString dcmitype = QStringLiteral("http://purl.org/dc/dcmitype/"); + const QString xsi = QStringLiteral("http://www.w3.org/2001/XMLSchema-instance"); + writer.writeStartDocument(QStringLiteral("1.0"), true); + writer.writeStartElement(QStringLiteral("cp:coreProperties")); + writer.writeNamespace(cp, QStringLiteral("cp")); + writer.writeNamespace(dc, QStringLiteral("dc")); + writer.writeNamespace(dcterms, QStringLiteral("dcterms")); + writer.writeNamespace(dcmitype, QStringLiteral("dcmitype")); + writer.writeNamespace(xsi, QStringLiteral("xsi")); + + if (m_properties.contains(QStringLiteral("title"))) + writer.writeTextElement(dc, QStringLiteral("title"), m_properties[QStringLiteral("title")]); + + if (m_properties.contains(QStringLiteral("subject"))) + writer.writeTextElement(dc, QStringLiteral("subject"), m_properties[QStringLiteral("subject")]); + + writer.writeTextElement(dc, QStringLiteral("creator"), m_properties.contains(QStringLiteral("creator")) ? m_properties[QStringLiteral("creator")] : QStringLiteral("Qt Xlsx Library")); + + if (m_properties.contains(QStringLiteral("keywords"))) + writer.writeTextElement(cp, QStringLiteral("keywords"), m_properties[QStringLiteral("keywords")]); + + if (m_properties.contains(QStringLiteral("description"))) + writer.writeTextElement(dc, QStringLiteral("description"), m_properties[QStringLiteral("description")]); + + writer.writeTextElement(cp, QStringLiteral("lastModifiedBy"), m_properties.contains(QStringLiteral("creator")) ? m_properties[QStringLiteral("creator")] : QStringLiteral("Qt Xlsx Library")); + + writer.writeStartElement(dcterms, QStringLiteral("created")); + writer.writeAttribute(xsi, QStringLiteral("type"), QStringLiteral("dcterms:W3CDTF")); + writer.writeCharacters(m_properties.contains(QStringLiteral("created")) ? m_properties[QStringLiteral("created")] : QDateTime::currentDateTime().toString(Qt::ISODate)); + writer.writeEndElement();//dcterms:created + + writer.writeStartElement(dcterms, QStringLiteral("modified")); + writer.writeAttribute(xsi, QStringLiteral("type"), QStringLiteral("dcterms:W3CDTF")); + writer.writeCharacters(QDateTime::currentDateTime().toString(Qt::ISODate)); + writer.writeEndElement();//dcterms:created + + if (m_properties.contains(QStringLiteral("category"))) + writer.writeTextElement(cp, QStringLiteral("category"), m_properties[QStringLiteral("category")]); + + if (m_properties.contains(QStringLiteral("status"))) + writer.writeTextElement(cp, QStringLiteral("contentStatus"), m_properties[QStringLiteral("status")]); + + writer.writeEndElement(); //cp:coreProperties + writer.writeEndDocument(); +} + +bool DocPropsCore::loadFromXmlFile(QIODevice *device) +{ + QXmlStreamReader reader(device); + + const QString cp = QStringLiteral("http://schemas.openxmlformats.org/package/2006/metadata/core-properties"); + const QString dc = QStringLiteral("http://purl.org/dc/elements/1.1/"); + const QString dcterms = QStringLiteral("http://purl.org/dc/terms/"); + + while (!reader.atEnd()) { + QXmlStreamReader::TokenType token = reader.readNext(); + if (token == QXmlStreamReader::StartElement) { + const QStringRef nsUri = reader.namespaceUri(); + const QStringRef name = reader.name(); + if (name == QStringLiteral("subject") && nsUri == dc) { + setProperty(QStringLiteral("subject"), reader.readElementText()); + } else if (name == QStringLiteral("title") && nsUri == dc) { + setProperty(QStringLiteral("title"), reader.readElementText()); + } else if (name == QStringLiteral("creator") && nsUri == dc) { + setProperty(QStringLiteral("creator"), reader.readElementText()); + } else if (name == QStringLiteral("description") && nsUri == dc) { + setProperty(QStringLiteral("description"), reader.readElementText()); + } else if (name == QStringLiteral("keywords") && nsUri == cp) { + setProperty(QStringLiteral("keywords"), reader.readElementText()); + } else if (name == QStringLiteral("created") && nsUri == dcterms) { + setProperty(QStringLiteral("created"), reader.readElementText()); + } else if (name == QStringLiteral("category") && nsUri == cp) { + setProperty(QStringLiteral("category"), reader.readElementText()); + } else if (name == QStringLiteral("contentStatus") && nsUri == cp) { + setProperty(QStringLiteral("status"), reader.readElementText()); + } + } + + if (reader.hasError()) { + qDebug()<<"Error when read doc props core file."< +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#ifndef XLSXDOCPROPSCORE_H +#define XLSXDOCPROPSCORE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Xlsx API. It exists for the convenience +// of the Qt Xlsx. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "xlsxglobal.h" +#include "xlsxabstractooxmlfile.h" +#include +#include + +class QIODevice; + +namespace QXlsx { + +class XLSX_AUTOTEST_EXPORT DocPropsCore : public AbstractOOXmlFile +{ +public: + explicit DocPropsCore(CreateFlag flag); + + bool setProperty(const QString &name, const QString &value); + QString property(const QString &name) const; + QStringList propertyNames() const; + + void saveToXmlFile(QIODevice *device) const; + bool loadFromXmlFile(QIODevice *device); + +private: + QMap m_properties; +}; + +} +#endif // XLSXDOCPROPSCORE_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxdocument.cpp b/platform/src/include/public/pub_excel/xlsx/xlsxdocument.cpp new file mode 100644 index 00000000..314e789e --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxdocument.cpp @@ -0,0 +1,1046 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ + +#include "xlsxdocument.h" +#include "xlsxdocument_p.h" +#include "xlsxworkbook.h" +#include "xlsxworksheet.h" +#include "xlsxcontenttypes_p.h" +#include "xlsxrelationships_p.h" +#include "xlsxstyles_p.h" +#include "xlsxtheme_p.h" +#include "xlsxdocpropsapp_p.h" +#include "xlsxdocpropscore_p.h" +#include "xlsxsharedstrings_p.h" +#include "xlsxutility_p.h" +#include "xlsxworkbook_p.h" +#include "xlsxdrawing_p.h" +#include "xlsxmediafile_p.h" +#include "xlsxchart.h" +#include "xlsxzipreader_p.h" +#include "xlsxzipwriter_p.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE_XLSX + +/* + From Wikipedia: The Open Packaging Conventions (OPC) is a + container-file technology initially created by Microsoft to store + a combination of XML and non-XML files that together form a single + entity such as an Open XML Paper Specification (OpenXPS) + document. http://en.wikipedia.org/wiki/Open_Packaging_Conventions. + + At its simplest an Excel XLSX file contains the following elements: + + ____ [Content_Types].xml + | + |____ docProps + | |____ app.xml + | |____ core.xml + | + |____ xl + | |____ workbook.xml + | |____ worksheets + | | |____ sheet1.xml + | | + | |____ styles.xml + | | + | |____ theme + | | |____ theme1.xml + | | + | |_____rels + | |____ workbook.xml.rels + | + |_____rels + |____ .rels + + The Packager class coordinates the classes that represent the + elements of the package and writes them into the XLSX file. +*/ + +DocumentPrivate::DocumentPrivate(Document *p) : + q_ptr(p), defaultPackageName(QStringLiteral("Book1.xlsx")) +{ +} + +void DocumentPrivate::init() +{ + if (contentTypes.isNull()) + contentTypes = QSharedPointer(new ContentTypes(ContentTypes::F_NewFromScratch)); + + if (workbook.isNull()) + workbook = QSharedPointer(new Workbook(Workbook::F_NewFromScratch)); +} + +bool DocumentPrivate::loadPackage(QIODevice *device) +{ + Q_Q(Document); + ZipReader zipReader(device); + QStringList filePaths = zipReader.filePaths(); + + //Load the Content_Types file + if (!filePaths.contains(QLatin1String("[Content_Types].xml"))) + return false; + contentTypes = QSharedPointer(new ContentTypes(ContentTypes::F_LoadFromExists)); + contentTypes->loadFromXmlData(zipReader.fileData(QStringLiteral("[Content_Types].xml"))); + + //Load root rels file + if (!filePaths.contains(QLatin1String("_rels/.rels"))) + return false; + Relationships rootRels; + rootRels.loadFromXmlData(zipReader.fileData(QStringLiteral("_rels/.rels"))); + + //load core property + QList rels_core = rootRels.packageRelationships(QStringLiteral("/metadata/core-properties")); + if (!rels_core.isEmpty()) { + //Get the core property file name if it exists. + //In normal case, this should be "docProps/core.xml" + QString docPropsCore_Name = rels_core[0].target; + + DocPropsCore props(DocPropsCore::F_LoadFromExists); + props.loadFromXmlData(zipReader.fileData(docPropsCore_Name)); + foreach (QString name, props.propertyNames()) + q->setDocumentProperty(name, props.property(name)); + } + + //load app property + QList rels_app = rootRels.documentRelationships(QStringLiteral("/extended-properties")); + if (!rels_app.isEmpty()) { + //Get the app property file name if it exists. + //In normal case, this should be "docProps/app.xml" + QString docPropsApp_Name = rels_app[0].target; + + DocPropsApp props(DocPropsApp::F_LoadFromExists); + props.loadFromXmlData(zipReader.fileData(docPropsApp_Name)); + foreach (QString name, props.propertyNames()) + q->setDocumentProperty(name, props.property(name)); + } + + //load workbook now, Get the workbook file path from the root rels file + //In normal case, this should be "xl/workbook.xml" + workbook = QSharedPointer(new Workbook(Workbook::F_LoadFromExists)); + QList rels_xl = rootRels.documentRelationships(QStringLiteral("/officeDocument")); + if (rels_xl.isEmpty()) + return false; + QString xlworkbook_Path = rels_xl[0].target; + QString xlworkbook_Dir = splitPath(xlworkbook_Path)[0]; + workbook->relationships()->loadFromXmlData(zipReader.fileData(getRelFilePath(xlworkbook_Path))); + workbook->setFilePath(xlworkbook_Path); + workbook->loadFromXmlData(zipReader.fileData(xlworkbook_Path)); + + //load styles + QList rels_styles = workbook->relationships()->documentRelationships(QStringLiteral("/styles")); + if (!rels_styles.isEmpty()) { + //In normal case this should be styles.xml which in xl + QString name = rels_styles[0].target; + QString path = xlworkbook_Dir + QLatin1String("/") + name; + QSharedPointer styles (new Styles(Styles::F_LoadFromExists)); + styles->loadFromXmlData(zipReader.fileData(path)); + workbook->d_func()->styles = styles; + } + + //load sharedStrings + QList rels_sharedStrings = workbook->relationships()->documentRelationships(QStringLiteral("/sharedStrings")); + if (!rels_sharedStrings.isEmpty()) { + //In normal case this should be sharedStrings.xml which in xl + QString name = rels_sharedStrings[0].target; + QString path = xlworkbook_Dir + QLatin1String("/") + name; + workbook->d_func()->sharedStrings->loadFromXmlData(zipReader.fileData(path)); + } + + //load theme + QList rels_theme = workbook->relationships()->documentRelationships(QStringLiteral("/theme")); + if (!rels_theme.isEmpty()) { + //In normal case this should be theme/theme1.xml which in xl + QString name = rels_theme[0].target; + QString path = xlworkbook_Dir + QLatin1String("/") + name; + workbook->theme()->loadFromXmlData(zipReader.fileData(path)); + } + + //load sheets + for (int i=0; isheetCount(); ++i) { + AbstractSheet *sheet = workbook->sheet(i); + QString rel_path = getRelFilePath(sheet->filePath()); + //If the .rel file exists, load it. + if (zipReader.filePaths().contains(rel_path)) + sheet->relationships()->loadFromXmlData(zipReader.fileData(rel_path)); + sheet->loadFromXmlData(zipReader.fileData(sheet->filePath())); + } + + //load external links + for (int i=0; id_func()->externalLinks.count(); ++i) { + SimpleOOXmlFile *link = workbook->d_func()->externalLinks[i].data(); + QString rel_path = getRelFilePath(link->filePath()); + //If the .rel file exists, load it. + if (zipReader.filePaths().contains(rel_path)) + link->relationships()->loadFromXmlData(zipReader.fileData(rel_path)); + link->loadFromXmlData(zipReader.fileData(link->filePath())); + } + + //load drawings + for (int i=0; idrawings().size(); ++i) { + Drawing *drawing = workbook->drawings()[i]; + QString rel_path = getRelFilePath(drawing->filePath()); + if (zipReader.filePaths().contains(rel_path)) + drawing->relationships()->loadFromXmlData(zipReader.fileData(rel_path)); + drawing->loadFromXmlData(zipReader.fileData(drawing->filePath())); + } + + //load charts + QList > chartFileToLoad = workbook->chartFiles(); + for (int i=0; i cf = chartFileToLoad[i]; + cf->loadFromXmlData(zipReader.fileData(cf->filePath())); + } + + //load media files + QList > mediaFileToLoad = workbook->mediaFiles(); + for (int i=0; i mf = mediaFileToLoad[i]; + const QString path = mf->fileName(); + const QString suffix = path.mid(path.lastIndexOf(QLatin1Char('.'))+1); + mf->set(zipReader.fileData(path), suffix); + } + + return true; +} + +bool DocumentPrivate::savePackage(QIODevice *device) const +{ + Q_Q(const Document); + ZipWriter zipWriter(device); + if (zipWriter.error()) + return false; + + contentTypes->clearOverrides(); + + DocPropsApp docPropsApp(DocPropsApp::F_NewFromScratch); + DocPropsCore docPropsCore(DocPropsCore::F_NewFromScratch); + + // save worksheet xml files + QList > worksheets = workbook->getSheetsByTypes(AbstractSheet::ST_WorkSheet); + if (!worksheets.isEmpty()) + docPropsApp.addHeadingPair(QStringLiteral("Worksheets"), worksheets.size()); + for (int i=0; i sheet = worksheets[i]; + contentTypes->addWorksheetName(QStringLiteral("sheet%1").arg(i+1)); + docPropsApp.addPartTitle(sheet->sheetName()); + + zipWriter.addFile(QStringLiteral("xl/worksheets/sheet%1.xml").arg(i+1), sheet->saveToXmlData()); + Relationships *rel = sheet->relationships(); + if (!rel->isEmpty()) + zipWriter.addFile(QStringLiteral("xl/worksheets/_rels/sheet%1.xml.rels").arg(i+1), rel->saveToXmlData()); + } + + //save chartsheet xml files + QList > chartsheets = workbook->getSheetsByTypes(AbstractSheet::ST_ChartSheet); + if (!chartsheets.isEmpty()) + docPropsApp.addHeadingPair(QStringLiteral("Chartsheets"), chartsheets.size()); + for (int i=0; i sheet = chartsheets[i]; + contentTypes->addWorksheetName(QStringLiteral("sheet%1").arg(i+1)); + docPropsApp.addPartTitle(sheet->sheetName()); + + zipWriter.addFile(QStringLiteral("xl/chartsheets/sheet%1.xml").arg(i+1), sheet->saveToXmlData()); + Relationships *rel = sheet->relationships(); + if (!rel->isEmpty()) + zipWriter.addFile(QStringLiteral("xl/chartsheets/_rels/sheet%1.xml.rels").arg(i+1), rel->saveToXmlData()); + } + + // save external links xml files + for (int i=0; id_func()->externalLinks.count(); ++i) { + SimpleOOXmlFile *link = workbook->d_func()->externalLinks[i].data(); + contentTypes->addExternalLinkName(QStringLiteral("externalLink%1").arg(i+1)); + + zipWriter.addFile(QStringLiteral("xl/externalLinks/externalLink%1.xml").arg(i+1), link->saveToXmlData()); + Relationships *rel = link->relationships(); + if (!rel->isEmpty()) + zipWriter.addFile(QStringLiteral("xl/externalLinks/_rels/externalLink%1.xml.rels").arg(i+1), rel->saveToXmlData()); + } + + // save workbook xml file + contentTypes->addWorkbook(); + zipWriter.addFile(QStringLiteral("xl/workbook.xml"), workbook->saveToXmlData()); + zipWriter.addFile(QStringLiteral("xl/_rels/workbook.xml.rels"), workbook->relationships()->saveToXmlData()); + + // save drawing xml files + for (int i=0; idrawings().size(); ++i) { + contentTypes->addDrawingName(QStringLiteral("drawing%1").arg(i+1)); + + Drawing *drawing = workbook->drawings()[i]; + zipWriter.addFile(QStringLiteral("xl/drawings/drawing%1.xml").arg(i+1), drawing->saveToXmlData()); + if (!drawing->relationships()->isEmpty()) + zipWriter.addFile(QStringLiteral("xl/drawings/_rels/drawing%1.xml.rels").arg(i+1), drawing->relationships()->saveToXmlData()); + } + + // save docProps app/core xml file + foreach (QString name, q->documentPropertyNames()) { + docPropsApp.setProperty(name, q->documentProperty(name)); + docPropsCore.setProperty(name, q->documentProperty(name)); + } + contentTypes->addDocPropApp(); + contentTypes->addDocPropCore(); + zipWriter.addFile(QStringLiteral("docProps/app.xml"), docPropsApp.saveToXmlData()); + zipWriter.addFile(QStringLiteral("docProps/core.xml"), docPropsCore.saveToXmlData()); + + // save sharedStrings xml file + if (!workbook->sharedStrings()->isEmpty()) { + contentTypes->addSharedString(); + zipWriter.addFile(QStringLiteral("xl/sharedStrings.xml"), workbook->sharedStrings()->saveToXmlData()); + } + + // save styles xml file + contentTypes->addStyles(); + zipWriter.addFile(QStringLiteral("xl/styles.xml"), workbook->styles()->saveToXmlData()); + + // save theme xml file + contentTypes->addTheme(); + zipWriter.addFile(QStringLiteral("xl/theme/theme1.xml"), workbook->theme()->saveToXmlData()); + + // save chart xml files + for (int i=0; ichartFiles().size(); ++i) { + contentTypes->addChartName(QStringLiteral("chart%1").arg(i+1)); + QSharedPointer cf = workbook->chartFiles()[i]; + zipWriter.addFile(QStringLiteral("xl/charts/chart%1.xml").arg(i+1), cf->saveToXmlData()); + } + + // save image files + for (int i=0; imediaFiles().size(); ++i) { + QSharedPointer mf = workbook->mediaFiles()[i]; + if (!mf->mimeType().isEmpty()) + contentTypes->addDefault(mf->suffix(), mf->mimeType()); + + zipWriter.addFile(QStringLiteral("xl/media/image%1.%2").arg(i+1).arg(mf->suffix()), mf->contents()); + } + + // save root .rels xml file + Relationships rootrels; + rootrels.addDocumentRelationship(QStringLiteral("/officeDocument"), QStringLiteral("xl/workbook.xml")); + rootrels.addPackageRelationship(QStringLiteral("/metadata/core-properties"), QStringLiteral("docProps/core.xml")); + rootrels.addDocumentRelationship(QStringLiteral("/extended-properties"), QStringLiteral("docProps/app.xml")); + zipWriter.addFile(QStringLiteral("_rels/.rels"), rootrels.saveToXmlData()); + + // save content types xml file + zipWriter.addFile(QStringLiteral("[Content_Types].xml"), contentTypes->saveToXmlData()); + + zipWriter.close(); + return true; +} + + +/*! + \class Document + \inmodule QtXlsx + \brief The Document class provides a API that is used to handle the contents of .xlsx files. + +*/ + +/*! + * Creates a new empty xlsx document. + * The \a parent argument is passed to QObject's constructor. + */ +Document::Document(QObject *parent) : + QObject(parent), d_ptr(new DocumentPrivate(this)) +{ + d_ptr->init(); +} + +/*! + * \overload + * Try to open an existing xlsx document named \a name. + * The \a parent argument is passed to QObject's constructor. + */ +Document::Document(const QString &name, QObject *parent) : + QObject(parent), d_ptr(new DocumentPrivate(this)) +{ + d_ptr->packageName = name; + if (QFile::exists(name)) { + QFile xlsx(name); + if (xlsx.open(QFile::ReadOnly)) + d_ptr->loadPackage(&xlsx); + } + d_ptr->init(); +} + +/*! + * \overload + * Try to open an existing xlsx document from \a device. + * The \a parent argument is passed to QObject's constructor. + */ +Document::Document(QIODevice *device, QObject *parent) : + QObject(parent), d_ptr(new DocumentPrivate(this)) +{ + if (device && device->isReadable()) + d_ptr->loadPackage(device); + d_ptr->init(); +} + +/*! + \overload + + Write \a value to cell \a row_column with the given \a format. + */ +bool Document::write(const CellReference &row_column, const QVariant &value, const Format &format) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->write(row_column, value, format); + return false; +} + +/*! + * Write \a value to cell (\a row, \a col) with the \a format. + * Returns true on success. + */ +bool Document::write(int row, int col, const QVariant &value, const Format &format) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->write(row, col, value, format); + return false; +} + +/*! + \overload + Returns the contents of the cell \a cell. + + \sa cellAt() +*/ +QVariant Document::read(const CellReference &cell) const +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->read(cell); + return QVariant(); +} + +/*! + Returns the contents of the cell (\a row, \a col). + + \sa cellAt() + */ +QVariant Document::read(int row, int col) const +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->read(row, col); + return QVariant(); +} + +/*! + * Insert an \a image to current active worksheet at the position \a row, \a column + * Returns ture if success. + */ +bool Document::insertImage(int row, int column, const QImage &image) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->insertImage(row, column, image); + return false; +} + +/*! + * Creates an chart with the given \a size and insert it to the current + * active worksheet at the position \a row, \a col. + * The chart will be returned. + */ +Chart *Document::insertChart(int row, int col, const QSize &size) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->insertChart(row, col, size); + return 0; +} + +/*! + Merge a \a range of cells. The first cell should contain the data and the others should + be blank. All cells will be applied the same style if a valid \a format is given. + Returns true on success. + + \note All cells except the top-left one will be cleared. + */ +bool Document::mergeCells(const CellRange &range, const Format &format) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->mergeCells(range, format); + return false; +} + +/*! + Unmerge the cells in the \a range. + Returns true on success. +*/ +bool Document::unmergeCells(const CellRange &range) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->unmergeCells(range); + return false; +} + +/*! + Sets width in characters of columns with the given \a range and \a width. + Returns true on success. + */ +bool Document::setColumnWidth(const CellRange &range, double width) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->setColumnWidth(range, width); + return false; +} + +/*! + Sets format property of columns with the gien \a range and \a format. + Returns true on success. + */ +bool Document::setColumnFormat(const CellRange &range, const Format &format) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->setColumnFormat(range, format); + return false; +} + +/*! + Sets hidden property of columns \a range to \a hidden. Columns are 1-indexed. + Hidden columns are not visible. + Returns true on success. + */ +bool Document::setColumnHidden(const CellRange &range, bool hidden) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->setColumnWidth(range, hidden); + return false; +} + +/*! + Sets width in characters \a column to \a width. Columns are 1-indexed. + Returns true on success. + */ +bool Document::setColumnWidth(int column, double width) +{ + return setColumnWidth(column,column,width); +} + +/*! + Sets format property \a column to \a format. Columns are 1-indexed. + Returns true on success. + */ +bool Document::setColumnFormat(int column, const Format &format) +{ + return setColumnFormat(column,column,format); +} + +/*! + Sets hidden property of a \a column. Columns are 1-indexed. + Returns true on success. + */ +bool Document::setColumnHidden(int column, bool hidden) +{ + return setColumnHidden(column,column,hidden); +} + +/*! + Sets width in characters for columns [\a colFirst, \a colLast]. Columns are 1-indexed. + Returns true on success. + */ +bool Document::setColumnWidth(int colFirst, int colLast, double width) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->setColumnWidth(colFirst, colLast, width); + return false; +} + +/*! + Sets format property of columns [\a colFirst, \a colLast] to \a format. + Columns are 1-indexed. + Returns true on success. + */ +bool Document::setColumnFormat(int colFirst, int colLast, const Format &format) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->setColumnFormat(colFirst, colLast, format); + return false; +} + + +/*! + Sets hidden property of columns [\a colFirst, \a colLast] to \a hidden. + Columns are 1-indexed. + Returns true on success. + */ +bool Document::setColumnHidden(int colFirst, int colLast, bool hidden) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->setColumnHidden(colFirst, colLast, hidden); + return false; +} + +/*! + Returns width of the \a column in characters of the normal font. + Columns are 1-indexed. + Returns true on success. + */ +double Document::columnWidth(int column) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->columnWidth(column); + return 0.0; +} + +/*! + Returns formatting of the \a column. Columns are 1-indexed. + */ +Format Document::columnFormat(int column) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->columnFormat(column); + return Format(); +} + +/*! + Returns true if \a column is hidden. Columns are 1-indexed. + */ +bool Document::isColumnHidden(int column) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->isColumnHidden(column); + return false; +} + +/*! + Sets the \a format of the \a row. + Rows are 1-indexed. + + Returns true if success. +*/ +bool Document::setRowFormat(int row, const Format &format) +{ + return setRowFormat(row,row, format); +} + +/*! + Sets the \a format of the rows including and between \a rowFirst and \a rowLast. + Rows are 1-indexed. + + Returns true if success. +*/ +bool Document::setRowFormat(int rowFirst, int rowLast, const Format &format) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->setRowFormat(rowFirst, rowLast, format); + return false; +} + +/*! + Sets the \a hidden property of the row \a row. + Rows are 1-indexed. If hidden is true rows will not be visible. + + Returns true if success. +*/ +bool Document::setRowHidden(int row, bool hidden) +{ + return setRowHidden(row,row,hidden); +} + +/*! + Sets the \a hidden property of the rows including and between \a rowFirst and \a rowLast. + Rows are 1-indexed. If hidden is true rows will not be visible. + + Returns true if success. +*/ +bool Document::setRowHidden(int rowFirst, int rowLast, bool hidden) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->setRowHidden(rowFirst, rowLast, hidden); + return false; +} + +/*! + Sets the \a height of the row \a row. + Row height measured in point size. + Rows are 1-indexed. + + Returns true if success. +*/ +bool Document::setRowHeight(int row, double height) +{ + return setRowHeight(row,row,height); +} + +/*! + Sets the \a height of the rows including and between \a rowFirst and \a rowLast. + Row height measured in point size. + Rows are 1-indexed. + + Returns true if success. +*/ +bool Document::setRowHeight(int rowFirst, int rowLast, double height) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->setRowHeight(rowFirst, rowLast, height); + return false; +} + +/*! + Returns height of \a row in points. +*/ +double Document::rowHeight(int row) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->rowHeight(row); + return 0.0; +} + +/*! + Returns format of \a row. +*/ +Format Document::rowFormat(int row) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->rowFormat(row); + return Format(); +} + +/*! + Returns true if \a row is hidden. +*/ +bool Document::isRowHidden(int row) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->isRowHidden(row); + return false; +} + +/*! + Groups rows from \a rowFirst to \a rowLast with the given \a collapsed. + Returns false if error occurs. + */ +bool Document::groupRows(int rowFirst, int rowLast, bool collapsed) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->groupRows(rowFirst, rowLast, collapsed); + return false; +} + +/*! + Groups columns from \a colFirst to \a colLast with the given \a collapsed. + Returns false if error occurs. + */ +bool Document::groupColumns(int colFirst, int colLast, bool collapsed) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->groupColumns(colFirst, colLast, collapsed); + return false; +} + +/*! + * Add a data \a validation rule for current worksheet. Returns true if successful. + */ +bool Document::addDataValidation(const DataValidation &validation) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->addDataValidation(validation); + return false; +} + +/*! + * Add a conditional formatting \a cf for current worksheet. Returns true if successful. + */ +bool Document::addConditionalFormatting(const ConditionalFormatting &cf) +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->addConditionalFormatting(cf); + return false; +} + +/*! + * \overload + * Returns the cell at the position \a pos. If there is no cell at + * the specified position, the function returns 0. + * + * \sa read() + */ +Cell *Document::cellAt(const CellReference &pos) const +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->cellAt(pos); + return 0; +} + +/*! + * Returns the cell at the given \a row and \a col. If there + * is no cell at the specified position, the function returns 0. + * + * \sa read() + */ +Cell *Document::cellAt(int row, int col) const +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->cellAt(row, col); + return 0; +} + +/*! + * \brief Create a defined name in the workbook with the given \a name, \a formula, \a comment + * and \a scope. + * + * \param name The defined name. + * \param formula The cell or range that the defined name refers to. + * \param scope The name of one worksheet, or empty which means golbal scope. + * \return Return false if the name invalid. + */ +bool Document::defineName(const QString &name, const QString &formula, const QString &comment, const QString &scope) +{ + Q_D(Document); + + return d->workbook->defineName(name, formula, comment, scope); +} + +/*! + Return the range that contains cell data. + */ +CellRange Document::dimension() const +{ + if (Worksheet *sheet = currentWorksheet()) + return sheet->dimension(); + return CellRange(); +} + +/*! + * Returns the value of the document's \a key property. + */ +QString Document::documentProperty(const QString &key) const +{ + Q_D(const Document); + if (d->documentProperties.contains(key)) + return d->documentProperties[key]; + else + return QString(); +} + +/*! + Set the document properties such as Title, Author etc. + + The method can be used to set the document properties of the Excel + file created by Qt Xlsx. These properties are visible when you use the + Office Button -> Prepare -> Properties option in Excel and are also + available to external applications that read or index windows files. + + The \a property \a key that can be set are: + + \list + \li title + \li subject + \li creator + \li manager + \li company + \li category + \li keywords + \li description + \li status + \endlist +*/ +void Document::setDocumentProperty(const QString &key, const QString &property) +{ + Q_D(Document); + d->documentProperties[key] = property; +} + +/*! + * Returns the names of all properties that were addedusing setDocumentProperty(). + */ +QStringList Document::documentPropertyNames() const +{ + Q_D(const Document); + return d->documentProperties.keys(); +} + +/*! + * Return the internal Workbook object. + */ +Workbook *Document::workbook() const +{ + Q_D(const Document); + return d->workbook.data(); +} + +/*! + * Returns the sheet object named \a sheetName. + */ +AbstractSheet *Document::sheet(const QString &sheetName) const +{ + Q_D(const Document); + return d->workbook->sheet(sheetNames().indexOf(sheetName)); +} + +/*! + * Creates and append an sheet with the given \a name and \a type. + * Return true if success. + */ +bool Document::addSheet(const QString &name, AbstractSheet::SheetType type) +{ + Q_D(Document); + return d->workbook->addSheet(name, type); +} + +/*! + * Creates and inserts an document with the given \a name and \a type at the \a index. + * Returns false if the \a name already used. + */ +bool Document::insertSheet(int index, const QString &name, AbstractSheet::SheetType type) +{ + Q_D(Document); + return d->workbook->insertSheet(index, name, type); +} + +/*! + Rename the worksheet from \a oldName to \a newName. + Returns true if the success. + */ +bool Document::renameSheet(const QString &oldName, const QString &newName) +{ + Q_D(Document); + if (oldName == newName) + return false; + return d->workbook->renameSheet(sheetNames().indexOf(oldName), newName); +} + +/*! + Make a copy of the worksheet \a srcName with the new name \a distName. + Returns true if the success. + */ +bool Document::copySheet(const QString &srcName, const QString &distName) +{ + Q_D(Document); + if (srcName == distName) + return false; + return d->workbook->copySheet(sheetNames().indexOf(srcName), distName); +} + +/*! + Move the worksheet \a srcName to the new pos \a distIndex. + Returns true if the success. + */ +bool Document::moveSheet(const QString &srcName, int distIndex) +{ + Q_D(Document); + return d->workbook->moveSheet(sheetNames().indexOf(srcName), distIndex); +} + +/*! + Delete the worksheet \a name. + Returns true if current sheet was deleted successfully. + */ +bool Document::deleteSheet(const QString &name) +{ + Q_D(Document); + return d->workbook->deleteSheet(sheetNames().indexOf(name)); +} + +/*! + * \brief Return pointer of current sheet. + */ +AbstractSheet *Document::currentSheet() const +{ + Q_D(const Document); + + return d->workbook->activeSheet(); +} + +/*! + * \brief Return pointer of current worksheet. + * If the type of sheet is not AbstractSheet::ST_WorkSheet, then 0 will be returned. + */ +Worksheet *Document::currentWorksheet() const +{ + AbstractSheet *st = currentSheet(); + if (st && st->sheetType() == AbstractSheet::ST_WorkSheet) + return static_cast(st); + else + return 0; +} + +/*! + * \brief Set worksheet named \a name to be active sheet. + * Returns true if success. + */ +bool Document::selectSheet(const QString &name) +{ + Q_D(Document); + return d->workbook->setActiveSheet(sheetNames().indexOf(name)); +} + +/*! + * Returns the names of worksheets contained in current document. + */ +QStringList Document::sheetNames() const +{ + Q_D(const Document); + return d->workbook->worksheetNames(); +} + +/*! + * Save current document to the filesystem. If no name specified when + * the document constructed, a default name "book1.xlsx" will be used. + * Returns true if saved successfully. + */ +bool Document::save() const +{ + Q_D(const Document); + QString name = d->packageName.isEmpty() ? d->defaultPackageName : d->packageName; + + return saveAs(name); +} + +/*! + * Saves the document to the file with the given \a name. + * Returns true if saved successfully. + */ +bool Document::saveAs(const QString &name) const +{ + QFile file(name); + if (file.open(QIODevice::WriteOnly)) + return saveAs(&file); + return false; +} + +/*! + * \overload + * This function writes a document to the given \a device. + * + * \warning The \a device will be closed when this function returned. + */ +bool Document::saveAs(QIODevice *device) const +{ + Q_D(const Document); + return d->savePackage(device); +} + +/*! + * Destroys the document and cleans up. + */ +Document::~Document() +{ + delete d_ptr; +} + +QT_END_NAMESPACE_XLSX diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxdocument.h b/platform/src/include/public/pub_excel/xlsx/xlsxdocument.h new file mode 100644 index 00000000..7f1113dd --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxdocument.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ + +#ifndef QXLSX_XLSXDOCUMENT_H +#define QXLSX_XLSXDOCUMENT_H + +#include "xlsxglobal.h" +#include "xlsxformat.h" +#include "xlsxworksheet.h" +#include +#include +class QIODevice; +class QImage; + +QT_BEGIN_NAMESPACE_XLSX + +class Workbook; +class Cell; +class CellRange; +class DataValidation; +class ConditionalFormatting; +class Chart; +class CellReference; + +class DocumentPrivate; +class Q_XLSX_EXPORT Document : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(Document) + +public: + explicit Document(QObject *parent = 0); + Document(const QString &xlsxName, QObject *parent=0); + Document(QIODevice *device, QObject *parent=0); + ~Document(); + + bool write(const CellReference &cell, const QVariant &value, const Format &format=Format()); + bool write(int row, int col, const QVariant &value, const Format &format=Format()); + QVariant read(const CellReference &cell) const; + QVariant read(int row, int col) const; + bool insertImage(int row, int col, const QImage &image); + Chart *insertChart(int row, int col, const QSize &size); + bool mergeCells(const CellRange &range, const Format &format=Format()); + bool unmergeCells(const CellRange &range); + + bool setColumnWidth(const CellRange &range, double width); + bool setColumnFormat(const CellRange &range, const Format &format); + bool setColumnHidden(const CellRange &range, bool hidden); + bool setColumnWidth(int column, double width); + bool setColumnFormat(int column, const Format &format); + bool setColumnHidden(int column, bool hidden); + bool setColumnWidth(int colFirst, int colLast, double width); + bool setColumnFormat(int colFirst, int colLast, const Format &format); + bool setColumnHidden(int colFirst, int colLast, bool hidden); + double columnWidth(int column); + Format columnFormat(int column); + bool isColumnHidden(int column); + + bool setRowHeight(int row, double height); + bool setRowFormat(int row, const Format &format); + bool setRowHidden(int row, bool hidden); + bool setRowHeight(int rowFirst, int rowLast, double height); + bool setRowFormat(int rowFirst, int rowLast, const Format &format); + bool setRowHidden(int rowFirst, int rowLast, bool hidden); + + double rowHeight(int row); + Format rowFormat(int row); + bool isRowHidden(int row); + + bool groupRows(int rowFirst, int rowLast, bool collapsed = true); + bool groupColumns(int colFirst, int colLast, bool collapsed = true); + bool addDataValidation(const DataValidation &validation); + bool addConditionalFormatting(const ConditionalFormatting &cf); + + Cell *cellAt(const CellReference &cell) const; + Cell *cellAt(int row, int col) const; + + bool defineName(const QString &name, const QString &formula, const QString &comment=QString(), const QString &scope=QString()); + + CellRange dimension() const; + + QString documentProperty(const QString &name) const; + void setDocumentProperty(const QString &name, const QString &property); + QStringList documentPropertyNames() const; + + QStringList sheetNames() const; + bool addSheet(const QString &name = QString(), AbstractSheet::SheetType type = AbstractSheet::ST_WorkSheet); + bool insertSheet(int index, const QString &name = QString(), AbstractSheet::SheetType type = AbstractSheet::ST_WorkSheet); + bool selectSheet(const QString &name); + bool renameSheet(const QString &oldName, const QString &newName); + bool copySheet(const QString &srcName, const QString &distName = QString()); + bool moveSheet(const QString &srcName, int distIndex); + bool deleteSheet(const QString &name); + + Workbook *workbook() const; + AbstractSheet *sheet(const QString &sheetName) const; + AbstractSheet *currentSheet() const; + Worksheet *currentWorksheet() const; + + bool save() const; + bool saveAs(const QString &xlsXname) const; + bool saveAs(QIODevice *device) const; + +private: + Q_DISABLE_COPY(Document) + DocumentPrivate * const d_ptr; +}; + +QT_END_NAMESPACE_XLSX + +#endif // QXLSX_XLSXDOCUMENT_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxdocument_p.h b/platform/src/include/public/pub_excel/xlsx/xlsxdocument_p.h new file mode 100644 index 00000000..736a678a --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxdocument_p.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ + +#ifndef XLSXDOCUMENT_P_H +#define XLSXDOCUMENT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Xlsx API. It exists for the convenience +// of the Qt Xlsx. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "xlsxdocument.h" +#include "xlsxworkbook.h" +#include "xlsxcontenttypes_p.h" + +#include + +namespace QXlsx { + +class DocumentPrivate +{ + Q_DECLARE_PUBLIC(Document) +public: + DocumentPrivate(Document *p); + void init(); + + bool loadPackage(QIODevice *device); + bool savePackage(QIODevice *device) const; + + Document *q_ptr; + const QString defaultPackageName; //default name when package name not specified + QString packageName; //name of the .xlsx file + + QMap documentProperties; //core, app and custom properties + QSharedPointer workbook; + QSharedPointer contentTypes; +}; + +} + +#endif // XLSXDOCUMENT_P_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxdrawing.cpp b/platform/src/include/public/pub_excel/xlsx/xlsxdrawing.cpp new file mode 100644 index 00000000..ae7d2d7b --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxdrawing.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ + +#include "xlsxdrawing_p.h" +#include "xlsxdrawinganchor_p.h" +#include "xlsxabstractsheet.h" + +#include +#include +#include + +namespace QXlsx { + +Drawing::Drawing(AbstractSheet *sheet, CreateFlag flag) + :AbstractOOXmlFile(flag), sheet(sheet) +{ + workbook = sheet->workbook(); +} + +Drawing::~Drawing() +{ + qDeleteAll(anchors); +} + +void Drawing::saveToXmlFile(QIODevice *device) const +{ + relationships()->clear(); + + QXmlStreamWriter writer(device); + + writer.writeStartDocument(QStringLiteral("1.0"), true); + writer.writeStartElement(QStringLiteral("xdr:wsDr")); + writer.writeAttribute(QStringLiteral("xmlns:xdr"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing")); + writer.writeAttribute(QStringLiteral("xmlns:a"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/main")); + + foreach (DrawingAnchor *anchor, anchors) + anchor->saveToXml(writer); + + writer.writeEndElement();//xdr:wsDr + writer.writeEndDocument(); +} + +bool Drawing::loadFromXmlFile(QIODevice *device) +{ + QXmlStreamReader reader(device); + while (!reader.atEnd()) { + reader.readNextStartElement(); + if (reader.tokenType() == QXmlStreamReader::StartElement) { + if (reader.name() == QLatin1String("absoluteAnchor")) { + DrawingAbsoluteAnchor * anchor = new DrawingAbsoluteAnchor(this); + anchor->loadFromXml(reader); + } else if (reader.name() == QLatin1String("oneCellAnchor")) { + DrawingOneCellAnchor * anchor = new DrawingOneCellAnchor(this); + anchor->loadFromXml(reader); + } else if (reader.name() == QLatin1String("twoCellAnchor")) { + DrawingTwoCellAnchor * anchor = new DrawingTwoCellAnchor(this); + anchor->loadFromXml(reader); + } + } + } + + return true; +} + +} // namespace QXlsx diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxdrawing_p.h b/platform/src/include/public/pub_excel/xlsx/xlsxdrawing_p.h new file mode 100644 index 00000000..3afad4db --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxdrawing_p.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ + +#ifndef QXLSX_DRAWING_H +#define QXLSX_DRAWING_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Xlsx API. It exists for the convenience +// of the Qt Xlsx. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "xlsxrelationships_p.h" +#include "xlsxabstractooxmlfile.h" + +#include +#include +#include + +class QIODevice; +class QXmlStreamWriter; + +namespace QXlsx { + +class DrawingAnchor; +class Workbook; +class AbstractSheet; +class MediaFile; + +class Drawing : public AbstractOOXmlFile +{ +public: + Drawing(AbstractSheet *sheet, CreateFlag flag); + ~Drawing(); + void saveToXmlFile(QIODevice *device) const; + bool loadFromXmlFile(QIODevice *device); + + AbstractSheet *sheet; + Workbook *workbook; + QList anchors; +}; + +} // namespace QXlsx + +#endif // QXLSX_DRAWING_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxdrawinganchor.cpp b/platform/src/include/public/pub_excel/xlsx/xlsxdrawinganchor.cpp new file mode 100644 index 00000000..be12dc03 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxdrawinganchor.cpp @@ -0,0 +1,529 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ + +#include "xlsxdrawinganchor_p.h" +#include "xlsxdrawing_p.h" +#include "xlsxmediafile_p.h" +#include "xlsxchart.h" +#include "xlsxworkbook.h" +#include "xlsxutility_p.h" + +#include +#include +#include +#include + +namespace QXlsx { + +/* + The vertices that define the position of a graphical object + within the worksheet in pixels. + + +------------+------------+ + | A | B | + +-----+------------+------------+ + | |(x1,y1) | | + | 1 |(A1)._______|______ | + | | | | | + | | | | | + +-----+----| OBJECT |-----+ + | | | | | + | 2 | |______________. | + | | | (B2)| + | | | (x2,y2)| + +---- +------------+------------+ + + Example of an object that covers some of the area from cell A1 to B2. + + Based on the width and height of the object we need to calculate 8 vars: + + col_start, row_start, col_end, row_end, x1, y1, x2, y2. + + We also calculate the absolute x and y position of the top left vertex of + the object. This is required for images. + + The width and height of the cells that the object occupies can be + variable and have to be taken into account. +*/ + +//anchor + +DrawingAnchor::DrawingAnchor(Drawing *drawing, ObjectType objectType) + :m_drawing(drawing), m_objectType(objectType) +{ + m_drawing->anchors.append(this); + m_id = m_drawing->anchors.size();//must be unique in one drawing{x}.xml file. +} + +DrawingAnchor::~DrawingAnchor() +{ + +} + +void DrawingAnchor::setObjectPicture(const QImage &img) +{ + QByteArray ba; + QBuffer buffer(&ba); + buffer.open(QIODevice::WriteOnly); + img.save(&buffer, "PNG"); + + m_pictureFile = QSharedPointer(new MediaFile(ba, QStringLiteral("png"), QStringLiteral("image/png"))); + m_drawing->workbook->addMediaFile(m_pictureFile); + + m_objectType = Picture; +} + +void DrawingAnchor::setObjectGraphicFrame(QSharedPointer chart) +{ + m_chartFile = chart; + m_drawing->workbook->addChartFile(chart); + + m_objectType = GraphicFrame; +} + +QPoint DrawingAnchor::loadXmlPos(QXmlStreamReader &reader) +{ + Q_ASSERT(reader.name() == QLatin1String("pos")); + + QPoint pos; + QXmlStreamAttributes attrs = reader.attributes(); + pos.setX(attrs.value(QLatin1String("x")).toString().toInt()); + pos.setY(attrs.value(QLatin1String("y")).toString().toInt()); + return pos; +} + +QSize DrawingAnchor::loadXmlExt(QXmlStreamReader &reader) +{ + Q_ASSERT(reader.name() == QLatin1String("ext")); + + QSize size; + QXmlStreamAttributes attrs = reader.attributes(); + size.setWidth(attrs.value(QLatin1String("cx")).toString().toInt()); + size.setHeight(attrs.value(QLatin1String("cy")).toString().toInt()); + return size; +} + +XlsxMarker DrawingAnchor::loadXmlMarker(QXmlStreamReader &reader, const QString &node) +{ + Q_ASSERT(reader.name() == node); + + int col = 0; + int colOffset = 0; + int row = 0; + int rowOffset = 0; + while (!reader.atEnd()) { + reader.readNextStartElement(); + if (reader.tokenType() == QXmlStreamReader::StartElement) { + if (reader.name() == QLatin1String("col")) { + col = reader.readElementText().toInt(); + } else if (reader.name() == QLatin1String("colOff")) { + colOffset = reader.readElementText().toInt(); + } else if (reader.name() == QLatin1String("row")) { + row = reader.readElementText().toInt(); + } else if (reader.name() == QLatin1String("rowOff")) { + rowOffset = reader.readElementText().toInt(); + } + } else if (reader.tokenType() == QXmlStreamReader::EndElement + && reader.name() == node) { + break; + } + } + + return XlsxMarker(row, col, rowOffset, colOffset); +} + +void DrawingAnchor::loadXmlObject(QXmlStreamReader &reader) +{ + if (reader.name() == QLatin1String("sp")) { + //Shape + m_objectType = Shape; + loadXmlObjectShape(reader); + } else if (reader.name() == QLatin1String("grpSp")) { + //Group Shape + m_objectType = GroupShape; + loadXmlObjectGroupShape(reader); + } else if (reader.name() == QLatin1String("graphicFrame")) { + //Graphic Frame + m_objectType = GraphicFrame; + loadXmlObjectGraphicFrame(reader); + } else if (reader.name() == QLatin1String("cxnSp")) { + //Connection Shape + m_objectType = ConnectionShape; + loadXmlObjectConnectionShape(reader); + } else if (reader.name() == QLatin1String("pic")) { + //Picture + m_objectType = Picture; + loadXmlObjectPicture(reader); + } +} + +void DrawingAnchor::loadXmlObjectConnectionShape(QXmlStreamReader &reader) +{ + Q_UNUSED(reader) +} + +void DrawingAnchor::loadXmlObjectGraphicFrame(QXmlStreamReader &reader) +{ + Q_ASSERT(reader.name() == QLatin1String("graphicFrame")); + + while (!reader.atEnd()) { + reader.readNextStartElement(); + if (reader.tokenType() == QXmlStreamReader::StartElement) { + if (reader.name() == QLatin1String("chart")) { + QString rId = reader.attributes().value(QLatin1String("r:id")).toString(); + QString name = m_drawing->relationships()->getRelationshipById(rId).target; + QString path = QDir::cleanPath(splitPath(m_drawing->filePath())[0] + QLatin1String("/") + name); + + bool exist = false; + QList > cfs = m_drawing->workbook->chartFiles(); + for (int i=0; ifilePath() == path) { + //already exist + exist = true; + m_chartFile = cfs[i]; + } + } + if (!exist) { + m_chartFile = QSharedPointer (new Chart(m_drawing->sheet, Chart::F_LoadFromExists)); + m_chartFile->setFilePath(path); + m_drawing->workbook->addChartFile(m_chartFile); + } + } + } else if (reader.tokenType() == QXmlStreamReader::EndElement + && reader.name() == QLatin1String("graphicFrame")) { + break; + } + } + + return; +} + +void DrawingAnchor::loadXmlObjectGroupShape(QXmlStreamReader &reader) +{ + Q_UNUSED(reader) +} + +void DrawingAnchor::loadXmlObjectPicture(QXmlStreamReader &reader) +{ + Q_ASSERT(reader.name() == QLatin1String("pic")); + + while (!reader.atEnd()) { + reader.readNextStartElement(); + if (reader.tokenType() == QXmlStreamReader::StartElement) { + if (reader.name() == QLatin1String("blip")) { + QString rId = reader.attributes().value(QLatin1String("r:embed")).toString(); + QString name = m_drawing->relationships()->getRelationshipById(rId).target; + QString path = QDir::cleanPath(splitPath(m_drawing->filePath())[0] + QLatin1String("/") + name); + + bool exist = false; + QList > mfs = m_drawing->workbook->mediaFiles(); + for (int i=0; ifileName() == path) { + //already exist + exist = true; + m_pictureFile = mfs[i]; + } + } + if (!exist) { + m_pictureFile = QSharedPointer (new MediaFile(path)); + m_drawing->workbook->addMediaFile(m_pictureFile, true); + } + } + } else if (reader.tokenType() == QXmlStreamReader::EndElement + && reader.name() == QLatin1String("pic")) { + break; + } + } + + return; +} + +void DrawingAnchor::loadXmlObjectShape(QXmlStreamReader &reader) +{ + Q_UNUSED(reader) +} + +void DrawingAnchor::saveXmlPos(QXmlStreamWriter &writer, const QPoint &pos) const +{ + writer.writeEmptyElement(QStringLiteral("xdr:pos")); + writer.writeAttribute(QStringLiteral("x"), QString::number(pos.x())); + writer.writeAttribute(QStringLiteral("y"), QString::number(pos.y())); +} + +void DrawingAnchor::saveXmlExt(QXmlStreamWriter &writer, const QSize &ext) const +{ + writer.writeStartElement(QStringLiteral("xdr:ext")); + writer.writeAttribute(QStringLiteral("cx"), QString::number(ext.width())); + writer.writeAttribute(QStringLiteral("cy"), QString::number(ext.height())); + writer.writeEndElement(); //xdr:ext +} + +void DrawingAnchor::saveXmlMarker(QXmlStreamWriter &writer, const XlsxMarker &marker, const QString &node) const +{ + writer.writeStartElement(node); //xdr:from or xdr:to + writer.writeTextElement(QStringLiteral("xdr:col"), QString::number(marker.col())); + writer.writeTextElement(QStringLiteral("xdr:colOff"), QString::number(marker.colOff())); + writer.writeTextElement(QStringLiteral("xdr:row"), QString::number(marker.row())); + writer.writeTextElement(QStringLiteral("xdr:rowOff"), QString::number(marker.rowOff())); + writer.writeEndElement(); +} + +void DrawingAnchor::saveXmlObject(QXmlStreamWriter &writer) const +{ + if (m_objectType == Picture) + saveXmlObjectPicture(writer); + else if (m_objectType == ConnectionShape) + saveXmlObjectConnectionShape(writer); + else if (m_objectType == GraphicFrame) + saveXmlObjectGraphicFrame(writer); + else if (m_objectType == GroupShape) + saveXmlObjectGroupShape(writer); + else if (m_objectType == Shape) + saveXmlObjectShape(writer); +} + +void DrawingAnchor::saveXmlObjectConnectionShape(QXmlStreamWriter &writer) const +{ + Q_UNUSED(writer) +} + +void DrawingAnchor::saveXmlObjectGraphicFrame(QXmlStreamWriter &writer) const +{ + writer.writeStartElement(QStringLiteral("xdr:graphicFrame")); + writer.writeAttribute(QStringLiteral("macro"), QString()); + + writer.writeStartElement(QStringLiteral("xdr:nvGraphicFramePr")); + writer.writeEmptyElement(QStringLiteral("xdr:cNvPr")); + writer.writeAttribute(QStringLiteral("id"), QString::number(m_id)); + writer.writeAttribute(QStringLiteral("name"),QStringLiteral("Chart %1").arg(m_id)); + writer.writeEmptyElement(QStringLiteral("xdr:cNvGraphicFramePr")); + writer.writeEndElement();//xdr:nvGraphicFramePr + + writer.writeStartElement(QStringLiteral("xdr:xfrm")); + writer.writeEndElement(); //xdr:xfrm + + writer.writeStartElement(QStringLiteral("a:graphic")); + writer.writeStartElement(QStringLiteral("a:graphicData")); + writer.writeAttribute(QStringLiteral("uri"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/chart")); + + int idx = m_drawing->workbook->chartFiles().indexOf(m_chartFile); + m_drawing->relationships()->addDocumentRelationship(QStringLiteral("/chart"), QStringLiteral("../charts/chart%1.xml").arg(idx+1)); + + writer.writeEmptyElement(QStringLiteral("c:chart")); + writer.writeAttribute(QStringLiteral("xmlns:c"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/chart")); + writer.writeAttribute(QStringLiteral("xmlns:r"), QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships")); + writer.writeAttribute(QStringLiteral("r:id"), QStringLiteral("rId%1").arg(m_drawing->relationships()->count())); + + writer.writeEndElement(); //a:graphicData + writer.writeEndElement(); //a:graphic + writer.writeEndElement(); //xdr:graphicFrame +} + +void DrawingAnchor::saveXmlObjectGroupShape(QXmlStreamWriter &writer) const +{ + Q_UNUSED(writer) +} + +void DrawingAnchor::saveXmlObjectPicture(QXmlStreamWriter &writer) const +{ + Q_ASSERT(m_objectType == Picture && !m_pictureFile.isNull()); + + writer.writeStartElement(QStringLiteral("xdr:pic")); + + writer.writeStartElement(QStringLiteral("xdr:nvPicPr")); + writer.writeEmptyElement(QStringLiteral("xdr:cNvPr")); + writer.writeAttribute(QStringLiteral("id"), QString::number(m_id)); + writer.writeAttribute(QStringLiteral("name"), QStringLiteral("Picture %1").arg(m_id)); + + writer.writeStartElement(QStringLiteral("xdr:cNvPicPr")); + writer.writeEmptyElement(QStringLiteral("a:picLocks")); + writer.writeAttribute(QStringLiteral("noChangeAspect"), QStringLiteral("1")); + writer.writeEndElement(); //xdr:cNvPicPr + + writer.writeEndElement(); //xdr:nvPicPr + + m_drawing->relationships()->addDocumentRelationship(QStringLiteral("/image"), QStringLiteral("../media/image%1.%2") + .arg(m_pictureFile->index()+1) + .arg(m_pictureFile->suffix())); + + writer.writeStartElement(QStringLiteral("xdr:blipFill")); + writer.writeEmptyElement(QStringLiteral("a:blip")); + writer.writeAttribute(QStringLiteral("xmlns:r"), QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships")); + writer.writeAttribute(QStringLiteral("r:embed"), QStringLiteral("rId%1").arg(m_drawing->relationships()->count())); + writer.writeStartElement(QStringLiteral("a:stretch")); + writer.writeEmptyElement(QStringLiteral("a:fillRect")); + writer.writeEndElement(); //a:stretch + writer.writeEndElement();//xdr:blipFill + + writer.writeStartElement(QStringLiteral("xdr:spPr")); + + writer.writeStartElement(QStringLiteral("a:prstGeom")); + writer.writeAttribute(QStringLiteral("prst"), QStringLiteral("rect")); + writer.writeEmptyElement(QStringLiteral("a:avLst")); + writer.writeEndElement(); //a:prstGeom + + writer.writeEndElement(); //xdr:spPr + + writer.writeEndElement(); //xdr:pic +} + +void DrawingAnchor::saveXmlObjectShape(QXmlStreamWriter &writer) const +{ + Q_UNUSED(writer) +} + +//absolute anchor + +DrawingAbsoluteAnchor::DrawingAbsoluteAnchor(Drawing *drawing, ObjectType objectType) + :DrawingAnchor(drawing, objectType) +{ + +} + +bool DrawingAbsoluteAnchor::loadFromXml(QXmlStreamReader &reader) +{ + Q_ASSERT(reader.name() == QLatin1String("absoluteAnchor")); + + while (!reader.atEnd()) { + reader.readNextStartElement(); + if (reader.tokenType() == QXmlStreamReader::StartElement) { + if (reader.name() == QLatin1String("pos")) { + pos = loadXmlPos(reader); + } else if (reader.name() == QLatin1String("ext")) { + ext = loadXmlExt(reader); + } else { + loadXmlObject(reader); + } + } else if (reader.tokenType() == QXmlStreamReader::EndElement + && reader.name() == QLatin1String("absoluteAnchor")) { + break; + } + } + return true; +} + +void DrawingAbsoluteAnchor::saveToXml(QXmlStreamWriter &writer) const +{ + writer.writeStartElement(QStringLiteral("xdr:absoluteAnchor")); + saveXmlPos(writer, pos); + saveXmlExt(writer, ext); + + saveXmlObject(writer); + + writer.writeEmptyElement(QStringLiteral("xdr:clientData")); + writer.writeEndElement(); //xdr:absoluteAnchor +} + +//one cell anchor + +DrawingOneCellAnchor::DrawingOneCellAnchor(Drawing *drawing, ObjectType objectType) + :DrawingAnchor(drawing, objectType) +{ + +} + +bool DrawingOneCellAnchor::loadFromXml(QXmlStreamReader &reader) +{ + Q_ASSERT(reader.name() == QLatin1String("oneCellAnchor")); + while (!reader.atEnd()) { + reader.readNextStartElement(); + if (reader.tokenType() == QXmlStreamReader::StartElement) { + if (reader.name() == QLatin1String("from")) { + from = loadXmlMarker(reader, QLatin1String("from")); + } else if (reader.name() == QLatin1String("ext")) { + ext = loadXmlExt(reader); + } else { + loadXmlObject(reader); + } + } else if (reader.tokenType() == QXmlStreamReader::EndElement + && reader.name() == QLatin1String("oneCellAnchor")) { + break; + } + } + return true; +} + +void DrawingOneCellAnchor::saveToXml(QXmlStreamWriter &writer) const +{ + writer.writeStartElement(QStringLiteral("xdr:oneCellAnchor")); + + saveXmlMarker(writer, from, QStringLiteral("xdr:from")); + saveXmlExt(writer, ext); + + saveXmlObject(writer); + + writer.writeEmptyElement(QStringLiteral("xdr:clientData")); + writer.writeEndElement(); //xdr:oneCellAnchor +} + +/* + Two cell anchor + + This class specifies a two cell anchor placeholder for a group + , a shape, or a drawing element. It moves with + cells and its extents are in EMU units. +*/ +DrawingTwoCellAnchor::DrawingTwoCellAnchor(Drawing *drawing, ObjectType objectType) + :DrawingAnchor(drawing, objectType) +{ + +} + +bool DrawingTwoCellAnchor::loadFromXml(QXmlStreamReader &reader) +{ + Q_ASSERT(reader.name() == QLatin1String("twoCellAnchor")); + while (!reader.atEnd()) { + reader.readNextStartElement(); + if (reader.tokenType() == QXmlStreamReader::StartElement) { + if (reader.name() == QLatin1String("from")) { + from = loadXmlMarker(reader, QLatin1String("from")); + } else if (reader.name() == QLatin1String("to")) { + to = loadXmlMarker(reader, QLatin1String("to")); + } else { + loadXmlObject(reader); + } + } else if (reader.tokenType() == QXmlStreamReader::EndElement + && reader.name() == QLatin1String("twoCellAnchor")) { + break; + } + } + return true; +} + +void DrawingTwoCellAnchor::saveToXml(QXmlStreamWriter &writer) const +{ + writer.writeStartElement(QStringLiteral("xdr:twoCellAnchor")); + writer.writeAttribute(QStringLiteral("editAs"), QStringLiteral("oneCell")); + + saveXmlMarker(writer, from, QStringLiteral("xdr:from")); + saveXmlMarker(writer, to, QStringLiteral("xdr:to")); + + saveXmlObject(writer); + + writer.writeEmptyElement(QStringLiteral("xdr:clientData")); + writer.writeEndElement(); //xdr:twoCellAnchor +} + +} // namespace QXlsx diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxdrawinganchor_p.h b/platform/src/include/public/pub_excel/xlsx/xlsxdrawinganchor_p.h new file mode 100644 index 00000000..2f38a911 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxdrawinganchor_p.h @@ -0,0 +1,151 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ + +#ifndef QXLSX_XLSXDRAWINGANCHOR_P_H +#define QXLSX_XLSXDRAWINGANCHOR_P_H + +#include "xlsxglobal.h" + +#include +#include +#include +#include + +class QXmlStreamReader; +class QXmlStreamWriter; + +namespace QXlsx { + +class Drawing; +class MediaFile; +class Chart; + +//Helper class +struct XlsxMarker +{ + XlsxMarker(){} + XlsxMarker(int row, int column, int rowOffset, int colOffset) + :cell(QPoint(row, column)), offset(rowOffset, colOffset) + { + + } + + int row() const {return cell.x();} + int col() const {return cell.y();} + int rowOff() const {return offset.width();} + int colOff() const {return offset.height();} + + QPoint cell; + QSize offset; +}; + +class DrawingAnchor +{ +public: + enum ObjectType { + GraphicFrame, + Shape, + GroupShape, + ConnectionShape, + Picture, + Unknown + }; + + DrawingAnchor(Drawing *drawing, ObjectType objectType); + virtual ~DrawingAnchor(); + void setObjectPicture(const QImage &img); + void setObjectGraphicFrame(QSharedPointer chart); + + virtual bool loadFromXml(QXmlStreamReader &reader) = 0; + virtual void saveToXml(QXmlStreamWriter &writer) const = 0; + +protected: + QPoint loadXmlPos(QXmlStreamReader &reader); + QSize loadXmlExt(QXmlStreamReader &reader); + XlsxMarker loadXmlMarker(QXmlStreamReader &reader, const QString &node); + void loadXmlObject(QXmlStreamReader &reader); + void loadXmlObjectShape(QXmlStreamReader &reader); + void loadXmlObjectGroupShape(QXmlStreamReader &reader); + void loadXmlObjectGraphicFrame(QXmlStreamReader &reader); + void loadXmlObjectConnectionShape(QXmlStreamReader &reader); + void loadXmlObjectPicture(QXmlStreamReader &reader); + + void saveXmlPos(QXmlStreamWriter &writer, const QPoint &pos) const; + void saveXmlExt(QXmlStreamWriter &writer, const QSize &ext) const; + void saveXmlMarker(QXmlStreamWriter &writer, const XlsxMarker &marker, const QString &node) const; + void saveXmlObject(QXmlStreamWriter &writer) const; + void saveXmlObjectShape(QXmlStreamWriter &writer) const; + void saveXmlObjectGroupShape(QXmlStreamWriter &writer) const; + void saveXmlObjectGraphicFrame(QXmlStreamWriter &writer) const; + void saveXmlObjectConnectionShape(QXmlStreamWriter &writer) const; + void saveXmlObjectPicture(QXmlStreamWriter &writer) const; + + Drawing *m_drawing; + ObjectType m_objectType; + QSharedPointer m_pictureFile; + QSharedPointer m_chartFile; + + int m_id; +}; + +class DrawingAbsoluteAnchor : public DrawingAnchor +{ +public: + DrawingAbsoluteAnchor(Drawing *drawing, ObjectType objectType=Unknown); + + QPoint pos; + QSize ext; + + bool loadFromXml(QXmlStreamReader &reader); + void saveToXml(QXmlStreamWriter &writer) const; +}; + +class DrawingOneCellAnchor : public DrawingAnchor +{ +public: + DrawingOneCellAnchor(Drawing *drawing, ObjectType objectType=Unknown); + + XlsxMarker from; + QSize ext; + + bool loadFromXml(QXmlStreamReader &reader); + void saveToXml(QXmlStreamWriter &writer) const; +}; + +class DrawingTwoCellAnchor : public DrawingAnchor +{ +public: + DrawingTwoCellAnchor(Drawing *drawing, ObjectType objectType=Unknown); + + XlsxMarker from; + XlsxMarker to; + + bool loadFromXml(QXmlStreamReader &reader); + void saveToXml(QXmlStreamWriter &writer) const; +}; + +} // namespace QXlsx + +#endif // QXLSX_XLSXDRAWINGANCHOR_P_H diff --git a/platform/src/include/public/pub_excel/xlsx/xlsxformat.cpp b/platform/src/include/public/pub_excel/xlsx/xlsxformat.cpp new file mode 100644 index 00000000..074184f7 --- /dev/null +++ b/platform/src/include/public/pub_excel/xlsx/xlsxformat.cpp @@ -0,0 +1,1432 @@ +/**************************************************************************** +** Copyright (c) 2013-2014 Debao Zhang +** All right reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +#include "xlsxformat.h" +#include "xlsxformat_p.h" +#include "xlsxcolor_p.h" +#include "xlsxnumformatparser_p.h" +#include +#include + +QT_BEGIN_NAMESPACE_XLSX + +FormatPrivate::FormatPrivate() + : dirty(true) + , font_dirty(true), font_index_valid(false), font_index(0) + , fill_dirty(true), fill_index_valid(false), fill_index(0) + , border_dirty(true), border_index_valid(false), border_index(0) + , xf_index(-1), xf_indexValid(false) + , is_dxf_fomat(false), dxf_index(-1), dxf_indexValid(false) + , theme(0) +{ +} + +FormatPrivate::FormatPrivate(const FormatPrivate &other) + : QSharedData(other) + , dirty(other.dirty), formatKey(other.formatKey) + , font_dirty(other.font_dirty), font_index_valid(other.font_index_valid), font_key(other.font_key), font_index(other.font_index) + , fill_dirty(other.fill_dirty), fill_index_valid(other.fill_index_valid), fill_key(other.fill_key), fill_index(other.fill_index) + , border_dirty(other.border_dirty), border_index_valid(other.border_index_valid), border_key(other.border_key), border_index(other.border_index) + , xf_index(other.xf_index), xf_indexValid(other.xf_indexValid) + , is_dxf_fomat(other.is_dxf_fomat), dxf_index(other.dxf_index), dxf_indexValid(other.dxf_indexValid) + , theme(other.theme) + , properties(other.properties) +{ + +} + +FormatPrivate::~FormatPrivate() +{ + +} + +/*! + * \class Format + * \inmodule QtXlsx + * \brief Providing the methods and properties that are available for formatting cells in Excel. + */ + +/*! + * \enum Format::FontScript + * + * The enum type defines the type of font script. + * + * \value FontScriptNormal normal + * \value FontScriptSuper super script + * \value FontScriptSub sub script + */ + + +/*! + * \enum Format::FontUnderline + * + * The enum type defines the type of font underline. + * + * \value FontUnderlineNone + * \value FontUnderlineSingle + * \value FontUnderlineDouble + * \value FontUnderlineSingleAccounting + * \value FontUnderlineDoubleAccounting + */ + +/*! + * \enum Format::HorizontalAlignment + * + * The enum type defines the type of horizontal alignment. + * + * \value AlignHGeneral + * \value AlignLeft + * \value AlignHCenter + * \value AlignRight + * \value AlignHFill + * \value AlignHJustify + * \value AlignHMerge + * \value AlignHDistributed + */ + +/*! + * \enum Format::VerticalAlignment + * + * The enum type defines the type of vertical alignment. + * + * \value AlignTop, + * \value AlignVCenter, + * \value AlignBottom, + * \value AlignVJustify, + * \value AlignVDistributed + */ + +/*! + * \enum Format::BorderStyle + * + * The enum type defines the type of font underline. + * + * \value BorderNone + * \value BorderThin + * \value BorderMedium + * \value BorderDashed + * \value BorderDotted + * \value BorderThick + * \value BorderDouble + * \value BorderHair + * \value BorderMediumDashed + * \value BorderDashDot + * \value BorderMediumDashDot + * \value BorderDashDotDot + * \value BorderMediumDashDotDot + * \value BorderSlantDashDot +*/ + +/*! + * \enum Format::DiagonalBorderType + * + * The enum type defines the type of diagonal border. + * + * \value DiagonalBorderNone + * \value DiagonalBorderDown + * \value DiagonalBorderUp + * \value DiagnoalBorderBoth + */ + +/*! + * \enum Format::FillPattern + * + * The enum type defines the type of fill. + * + * \value PatternNone + * \value PatternSolid + * \value PatternMediumGray + * \value PatternDarkGray + * \value PatternLightGray + * \value PatternDarkHorizontal + * \value PatternDarkVertical + * \value PatternDarkDown + * \value PatternDarkUp + * \value PatternDarkGrid + * \value PatternDarkTrellis + * \value PatternLightHorizontal + * \value PatternLightVertical + * \value PatternLightDown + * \value PatternLightUp + * \value PatternLightTrellis + * \value PatternGray125 + * \value PatternGray0625 + * \value PatternLightGrid + */ + +/*! + * Creates a new invalid format. + */ +Format::Format() +{ + //The d pointer is initialized with a null pointer +} + +/*! + Creates a new format with the same attributes as the \a other format. + */ +Format::Format(const Format &other) + :d(other.d) +{ + +} + +/*! + Assigns the \a other format to this format, and returns a + reference to this format. + */ +Format &Format::operator =(const Format &other) +{ + d = other.d; + return *this; +} + +/*! + * Destroys this format. + */ +Format::~Format() +{ +} + +/*! + * Returns the number format identifier. + */ +int Format::numberFormatIndex() const +{ + return intProperty(FormatPrivate::P_NumFmt_Id, 0); +} + +/*! + * Set the number format identifier. The \a format + * must be a valid built-in number format identifier + * or the identifier of a custom number format. + */ +void Format::setNumberFormatIndex(int format) +{ + setProperty(FormatPrivate::P_NumFmt_Id, format); + clearProperty(FormatPrivate::P_NumFmt_FormatCode); +} + +/*! + * Returns the number format string. + * \note for built-in number formats, this may + * return an empty string. + */ +QString Format::numberFormat() const +{ + return stringProperty(FormatPrivate::P_NumFmt_FormatCode); +} + +/*! + * Set number \a format. + * http://office.microsoft.com/en-001/excel-help/create-a-custom-number-format-HP010342372.aspx + */ +void Format::setNumberFormat(const QString &format) +{ + if (format.isEmpty()) + return; + setProperty(FormatPrivate::P_NumFmt_FormatCode, format); + clearProperty(FormatPrivate::P_NumFmt_Id); //numFmt id must be re-generated. +} + +/*! + * Returns whether the number format is probably a dateTime or not + */ +bool Format::isDateTimeFormat() const +{ + if (hasProperty(FormatPrivate::P_NumFmt_FormatCode)) { + //Custom numFmt, so + //Gauss from the number string + return NumFormatParser::isDateTime(numberFormat()); + } else if (hasProperty(FormatPrivate::P_NumFmt_Id)){ + //Non-custom numFmt + int idx = numberFormatIndex(); + + //Is built-in date time number id? + if ((idx >= 14 && idx <= 22) || (idx >= 45 && idx <= 47)) + return true; + + if ((idx >= 27 && idx <= 36) || (idx >= 50 && idx <= 58)) //Used in CHS\CHT\JPN\KOR + return true; + } + + return false; +} + +/*! + \internal + Set a custom num \a format with the given \a id. + */ +void Format::setNumberFormat(int id, const QString &format) +{ + setProperty(FormatPrivate::P_NumFmt_Id, id); + setProperty(FormatPrivate::P_NumFmt_FormatCode, format); +} + +/*! + \internal + Called by styles to fix the numFmt + */ +void Format::fixNumberFormat(int id, const QString &format) +{ + setProperty(FormatPrivate::P_NumFmt_Id, id, 0, false); + setProperty(FormatPrivate::P_NumFmt_FormatCode, format, QString(), false); +} + +/*! + \internal + Return true if the format has number format. + */ +bool Format::hasNumFmtData() const +{ + if (!d) + return false; + + if (hasProperty(FormatPrivate::P_NumFmt_Id) + || hasProperty(FormatPrivate::P_NumFmt_FormatCode)) { + return true; + } + return false; +} + +/*! + * Return the size of the font in points. + */ +int Format::fontSize() const +{ + return intProperty(FormatPrivate::P_Font_Size); +} + +/*! + * Set the \a size of the font in points. + */ +void Format::setFontSize(int size) +{ + setProperty(FormatPrivate::P_Font_Size, size, 0); +} + +/*! + * Return whether the font is italic. + */ +bool Format::fontItalic() const +{ + return boolProperty(FormatPrivate::P_Font_Italic); +} + +/*! + * Turn on/off the italic font based on \a italic. + */ +void Format::setFontItalic(bool italic) +{ + setProperty(FormatPrivate::P_Font_Italic, italic, false); +} + +/*! + * Return whether the font is strikeout. + */ +bool Format::fontStrikeOut() const +{ + return boolProperty(FormatPrivate::P_Font_StrikeOut); +} + +/*! + * Turn on/off the strikeOut font based on \a strikeOut. + */ +void Format::setFontStrikeOut(bool strikeOut) +{ + setProperty(FormatPrivate::P_Font_StrikeOut, strikeOut, false); +} + +/*! + * Return the color of the font. + */ +QColor Format::fontColor() const +{ + if (hasProperty(FormatPrivate::P_Font_Color)) + return colorProperty(FormatPrivate::P_Font_Color); + return QColor(); +} + +/*! + * Set the \a color of the font. + */ +void Format::setFontColor(const QColor &color) +{ + setProperty(FormatPrivate::P_Font_Color, XlsxColor(color), XlsxColor()); +} + +/*! + * Return whether the font is bold. + */ +bool Format::fontBold() const +{ + return boolProperty(FormatPrivate::P_Font_Bold); +} + +/*! + * Turn on/off the bold font based on the given \a bold. + */ +void Format::setFontBold(bool bold) +{ + setProperty(FormatPrivate::P_Font_Bold, bold, false); +} + +/*! + * Return the script style of the font. + */ +Format::FontScript Format::fontScript() const +{ + return static_cast(intProperty(FormatPrivate::P_Font_Script)); +} + +/*! + * Set the script style of the font to \a script. + */ +void Format::setFontScript(FontScript script) +{ + setProperty(FormatPrivate::P_Font_Script, script, FontScriptNormal); +} + +/*! + * Return the underline style of the font. + */ +Format::FontUnderline Format::fontUnderline() const +{ + return static_cast(intProperty(FormatPrivate::P_Font_Underline)); +} + +/*! + * Set the underline style of the font to \a underline. + */ +void Format::setFontUnderline(FontUnderline underline) +{ + setProperty(FormatPrivate::P_Font_Underline, underline, FontUnderlineNone); +} + +/*! + * Return whether the font is outline. + */ +bool Format::fontOutline() const +{ + return boolProperty(FormatPrivate::P_Font_Outline); +} + +/*! + * Turn on/off the outline font based on \a outline. + */ +void Format::setFontOutline(bool outline) +{ + setProperty(FormatPrivate::P_Font_Outline, outline, false); +} + +/*! + * Return the name of the font. + */ +QString Format::fontName() const +{ + return stringProperty(FormatPrivate::P_Font_Name, QStringLiteral("Calibri")); +} + +/*! + * Set the name of the font to \a name. + */ +void Format::setFontName(const QString &name) +{ + setProperty(FormatPrivate::P_Font_Name, name, QStringLiteral("Calibri")); +} + +/*! + * Returns a QFont object based on font data contained in the format. + */ +QFont Format::font() const +{ + QFont font; + font.setFamily(fontName()); + if (fontSize() > 0) + font.setPointSize(fontSize()); + font.setBold(fontBold()); + font.setItalic(fontItalic()); + font.setUnderline(fontUnderline()!=FontUnderlineNone); + font.setStrikeOut(fontStrikeOut()); + return font; +} + +/*! + * Set the format properties from the given \a font. + */ +void Format::setFont(const QFont &font) +{ + setFontName(font.family()); + if (font.pointSize() > 0) + setFontSize(font.pointSize()); + setFontBold(font.bold()); + setFontItalic(font.italic()); + setFontUnderline(font.underline() ? FontUnderlineSingle : FontUnderlineNone); + setFontStrikeOut(font.strikeOut()); +} + +/*! + * \internal + * When the format has font data, when need to assign a valid index for it. + * The index value is depend on the order in styles.xml + */ +bool Format::fontIndexValid() const +{ + if (!hasFontData()) + return false; + return d->font_index_valid; +} + +/*! + * \internal + */ +int Format::fontIndex() const +{ + if (fontIndexValid()) + return d->font_index; + + return 0; +} + +/*! + * \internal + */ +void Format::setFontIndex(int index) +{ + d->font_index = index; + d->font_index_valid = true; +} + +/*! + * \internal + */ +QByteArray Format::fontKey() const +{ + if (isEmpty()) + return QByteArray(); + + if (d->font_dirty) { + QByteArray key; + QDataStream stream(&key, QIODevice::WriteOnly); + for (int i=FormatPrivate::P_Font_STARTID; iproperties.contains(i)) + stream << i << d->properties[i]; + }; + + const_cast(this)->d->font_key = key; + const_cast(this)->d->font_dirty = false; + } + + return d->font_key; +} + +/*! + \internal + Return true if the format has font format, otherwise return false. + */ +bool Format::hasFontData() const +{ + if (!d) + return false; + + for (int i=FormatPrivate::P_Font_STARTID; i(intProperty(FormatPrivate::P_Alignment_AlignH, AlignHGeneral)); +} + +/*! + * Set the horizontal alignment with the given \a align. + */ +void Format::setHorizontalAlignment(HorizontalAlignment align) +{ + if (hasProperty(FormatPrivate::P_Alignment_Indent) + &&(align != AlignHGeneral && align != AlignLeft && align != AlignRight && align != AlignHDistributed)) { + clearProperty(FormatPrivate::P_Alignment_Indent); + } + + if (hasProperty(FormatPrivate::P_Alignment_ShinkToFit) + && (align == AlignHFill || align == AlignHJustify || align == AlignHDistributed)) { + clearProperty(FormatPrivate::P_Alignment_ShinkToFit); + } + + setProperty(FormatPrivate::P_Alignment_AlignH, align, AlignHGeneral); +} + +/*! + * Return the vertical alignment. + */ +Format::VerticalAlignment Format::verticalAlignment() const +{ + return static_cast(intProperty(FormatPrivate::P_Alignment_AlignV, AlignBottom)); +} + +/*! + * Set the vertical alignment with the given \a align. + */ +void Format::setVerticalAlignment(VerticalAlignment align) +{ + setProperty(FormatPrivate::P_Alignment_AlignV, align, AlignBottom); +} + +/*! + * Return whether the cell text is wrapped. + */ +bool Format::textWrap() const +{ + return boolProperty(FormatPrivate::P_Alignment_Wrap); +} + +/*! + * Enable the text wrap if \a wrap is true. + */ +void Format::setTextWarp(bool wrap) +{ + if (wrap && hasProperty(FormatPrivate::P_Alignment_ShinkToFit)) + clearProperty(FormatPrivate::P_Alignment_ShinkToFit); + + setProperty(FormatPrivate::P_Alignment_Wrap, wrap, false); +} + +/*! + * Return the text rotation. + */ +int Format::rotation() const +{ + return intProperty(FormatPrivate::P_Alignment_Rotation); +} + +/*! + * Set the text roation with the given \a rotation. Must be in the range [0, 180] or 255. + */ +void Format::setRotation(int rotation) +{ + setProperty(FormatPrivate::P_Alignment_Rotation, rotation, 0); +} + +/*! + * Return the text indentation level. + */ +int Format::indent() const +{ + return intProperty(FormatPrivate::P_Alignment_Indent); +} + +/*! + * Set the text indentation level with the given \a indent. Must be less than or equal to 15. + */ +void Format::setIndent(int indent) +{ + if (indent && hasProperty(FormatPrivate::P_Alignment_AlignH)) { + HorizontalAlignment hl = horizontalAlignment(); + + if (hl != AlignHGeneral && hl != AlignLeft && hl!= AlignRight && hl!= AlignHJustify) { + setHorizontalAlignment(AlignLeft); + } + } + + setProperty(FormatPrivate::P_Alignment_Indent, indent, 0); +} + +/*! + * Return whether the cell is shrink to fit. + */ +bool Format::shrinkToFit() const +{ + return boolProperty(FormatPrivate::P_Alignment_ShinkToFit); +} + +/*! + * Turn on/off shrink to fit base on \a shink. + */ +void Format::setShrinkToFit(bool shink) +{ + if (shink && hasProperty(FormatPrivate::P_Alignment_Wrap)) + clearProperty(FormatPrivate::P_Alignment_Wrap); + + if (shink && hasProperty(FormatPrivate::P_Alignment_AlignH)) { + HorizontalAlignment hl = horizontalAlignment(); + if (hl == AlignHFill || hl == AlignHJustify || hl == AlignHDistributed) + setHorizontalAlignment(AlignLeft); + } + + setProperty(FormatPrivate::P_Alignment_ShinkToFit, shink, false); +} + +/*! + * \internal + */ +bool Format::hasAlignmentData() const +{ + if (!d) + return false; + + for (int i=FormatPrivate::P_Alignment_STARTID; i(intProperty(FormatPrivate::P_Border_LeftStyle)); +} + +/*! + * Sets the left border style to \a style + */ +void Format::setLeftBorderStyle(BorderStyle style) +{ + setProperty(FormatPrivate::P_Border_LeftStyle, style, BorderNone); +} + +/*! + * Returns the left border color + */ +QColor Format::leftBorderColor() const +{ + return colorProperty(FormatPrivate::P_Border_LeftColor); +} + +/*! + Sets the left border color to the given \a color +*/ +void Format::setLeftBorderColor(const QColor &color) +{ + setProperty(FormatPrivate::P_Border_LeftColor, XlsxColor(color), XlsxColor()); +} + +/*! + Returns the right border style. +*/ +Format::BorderStyle Format::rightBorderStyle() const +{ + return static_cast(intProperty(FormatPrivate::P_Border_RightStyle)); +} + +/*! + Sets the right border style to the given \a style. +*/ +void Format::setRightBorderStyle(BorderStyle style) +{ + setProperty(FormatPrivate::P_Border_RightStyle, style, BorderNone); +} + +/*! + Returns the right border color. +*/ +QColor Format::rightBorderColor() const +{ + return colorProperty(FormatPrivate::P_Border_RightColor); +} + +/*! + Sets the right border color to the given \a color +*/ +void Format::setRightBorderColor(const QColor &color) +{ + setProperty(FormatPrivate::P_Border_RightColor, XlsxColor(color), XlsxColor()); +} + +/*! + Returns the top border style. +*/ +Format::BorderStyle Format::topBorderStyle() const +{ + return static_cast(intProperty(FormatPrivate::P_Border_TopStyle)); +} + +/*! + Sets the top border style to the given \a style. +*/ +void Format::setTopBorderStyle(BorderStyle style) +{ + setProperty(FormatPrivate::P_Border_TopStyle, style, BorderNone); +} + +/*! + Returns the top border color. +*/ +QColor Format::topBorderColor() const +{ + return colorProperty(FormatPrivate::P_Border_TopColor); +} + +/*! + Sets the top border color to the given \a color. +*/ +void Format::setTopBorderColor(const QColor &color) +{ + setProperty(FormatPrivate::P_Border_TopColor, XlsxColor(color), XlsxColor()); +} + +/*! + Returns the bottom border style. +*/ +Format::BorderStyle Format::bottomBorderStyle() const +{ + return static_cast(intProperty(FormatPrivate::P_Border_BottomStyle)); +} + +/*! + Sets the bottom border style to the given \a style. +*/ +void Format::setBottomBorderStyle(BorderStyle style) +{ + setProperty(FormatPrivate::P_Border_BottomStyle, style, BorderNone); +} + +/*! + Returns the bottom border color. +*/ +QColor Format::bottomBorderColor() const +{ + return colorProperty(FormatPrivate::P_Border_BottomColor); +} + +/*! + Sets the bottom border color to the given \a color. +*/ +void Format::setBottomBorderColor(const QColor &color) +{ + setProperty(FormatPrivate::P_Border_BottomColor, XlsxColor(color), XlsxColor()); +} + +/*! + Return the diagonla border style. +*/ +Format::BorderStyle Format::diagonalBorderStyle() const +{ + return static_cast(intProperty(FormatPrivate::P_Border_DiagonalStyle)); +} + +/*! + Sets the diagonal border style to the given \a style. +*/ +void Format::setDiagonalBorderStyle(BorderStyle style) +{ + setProperty(FormatPrivate::P_Border_DiagonalStyle, style, BorderNone); +} + +/*! + Returns the diagonal border type. +*/ +Format::DiagonalBorderType Format::diagonalBorderType() const +{ + return static_cast(intProperty(FormatPrivate::P_Border_DiagonalType)); +} + +/*! + Sets the diagonal border type to the given \a style +*/ +void Format::setDiagonalBorderType(DiagonalBorderType style) +{ + setProperty(FormatPrivate::P_Border_DiagonalType, style, DiagonalBorderNone); +} + +/*! + Returns the diagonal border color. +*/ +QColor Format::diagonalBorderColor() const +{ + return colorProperty(FormatPrivate::P_Border_DiagonalColor); +} + +/*! + Sets the diagonal border color to the given \a color +*/ +void Format::setDiagonalBorderColor(const QColor &color) +{ + setProperty(FormatPrivate::P_Border_DiagonalColor, XlsxColor(color), XlsxColor()); +} + +/*! + \internal + Returns whether this format has been set valid border index. +*/ +bool Format::borderIndexValid() const +{ + if (!hasBorderData()) + return false; + return d->border_index_valid; +} + +/*! + \internal + Returns the border index. +*/ +int Format::borderIndex() const +{ + if (borderIndexValid()) + return d->border_index; + return 0; +} + +/*! + * \internal + */ +void Format::setBorderIndex(int index) +{ + d->border_index = index; + d->border_index_valid = true; +} + +/*! \internal + */ +QByteArray Format::borderKey() const +{ + if (isEmpty()) + return QByteArray(); + + if (d->border_dirty) { + QByteArray key; + QDataStream stream(&key, QIODevice::WriteOnly); + for (int i=FormatPrivate::P_Border_STARTID; iproperties.contains(i)) + stream << i << d->properties[i]; + }; + + const_cast(this)->d->border_key = key; + const_cast(this)->d->border_dirty = false; + } + + return d->border_key; +} + +/*! + \internal + Return true if the format has border format, otherwise return false. + */ +bool Format::hasBorderData() const +{ + if (!d) + return false; + + for (int i=FormatPrivate::P_Border_STARTID; i(intProperty(FormatPrivate::P_Fill_Pattern, PatternNone)); +} + +/*! + Sets the fill pattern to the given \a pattern. +*/ +void Format::setFillPattern(FillPattern pattern) +{ + setProperty(FormatPrivate::P_Fill_Pattern, pattern, PatternNone); +} + +/*! + Returns the foreground color of the pattern. +*/ +QColor Format::patternForegroundColor() const +{ + return colorProperty(FormatPrivate::P_Fill_FgColor); +} + +/*! + Sets the foreground color of the pattern with the given \a color. +*/ +void Format::setPatternForegroundColor(const QColor &color) +{ + if (color.isValid() && !hasProperty(FormatPrivate::P_Fill_Pattern)) + setFillPattern(PatternSolid); + setProperty(FormatPrivate::P_Fill_FgColor, XlsxColor(color), XlsxColor()); +} + +/*! + Returns the background color of the pattern. +*/ +QColor Format::patternBackgroundColor() const +{ + return colorProperty(FormatPrivate::P_Fill_BgColor); +} + +/*! + Sets the background color of the pattern with the given \a color. +*/ +void Format::setPatternBackgroundColor(const QColor &color) +{ + if (color.isValid() && !hasProperty(FormatPrivate::P_Fill_Pattern)) + setFillPattern(PatternSolid); + setProperty(FormatPrivate::P_Fill_BgColor, XlsxColor(color), XlsxColor()); +} + +/*! + * \internal + */ +bool Format::fillIndexValid() const +{ + if (!hasFillData()) + return false; + return d->fill_index_valid; +} + +/*! + * \internal + */ +int Format::fillIndex() const +{ + if (fillIndexValid()) + return d->fill_index; + return 0; +} + +/*! + * \internal + */ +void Format::setFillIndex(int index) +{ + d->fill_index = index; + d->fill_index_valid = true; +} + +/*! + * \internal + */ +QByteArray Format::fillKey() const +{ + if (isEmpty()) + return QByteArray(); + + if (d->fill_dirty) { + QByteArray key; + QDataStream stream(&key, QIODevice::WriteOnly); + for (int i=FormatPrivate::P_Fill_STARTID; iproperties.contains(i)) + stream << i << d->properties[i]; + }; + + const_cast(this)->d->fill_key = key; + const_cast(this)->d->fill_dirty = false; + } + + return d->fill_key; +} + +/*! + \internal + Return true if the format has fill format, otherwise return false. + */ +bool Format::hasFillData() const +{ + if (!d) + return false; + + for (int i=FormatPrivate::P_Fill_STARTID; i