diff --git a/examples/xlsx/hello/main.cpp b/examples/xlsx/hello/main.cpp index 4436117..b2a677a 100755 --- a/examples/xlsx/hello/main.cpp +++ b/examples/xlsx/hello/main.cpp @@ -16,6 +16,7 @@ int main() sheet->write("B3", 12345); sheet->write("C5", "=44+33"); sheet->write("D7", true); + sheet->write("E1", "http://qt-project.org"); QXlsx::Worksheet *sheet2 = workbook.addWorksheet(); //Rows and columns are zero indexed. diff --git a/src/xlsx/xlsxpackage.cpp b/src/xlsx/xlsxpackage.cpp index da3a624..0e0fb57 100644 --- a/src/xlsx/xlsxpackage.cpp +++ b/src/xlsx/xlsxpackage.cpp @@ -285,6 +285,21 @@ void Package::writeWorkbookRelsFile(ZipWriter &zipWriter) void Package::writeWorksheetRelsFile(ZipWriter &zipWriter) { + int index = 1; + foreach (Worksheet *sheet, m_workbook->worksheets()) { + if (sheet->isChartsheet()) + continue; + Relationships rels; + + foreach (QString link, sheet->externUrlList()) + rels.addWorksheetRelationship(QStringLiteral("/hyperlink"), link, QStringLiteral("External")); + QByteArray data; + QBuffer buffer(&data); + buffer.open(QIODevice::WriteOnly); + rels.saveToXmlFile(&buffer); + zipWriter.addFile(QStringLiteral("xl/worksheets/_rels/sheet%1.xml.rels").arg(index), data); + index += 1; + } } } // namespace QXlsx diff --git a/src/xlsx/xlsxworksheet.cpp b/src/xlsx/xlsxworksheet.cpp index 0763663..c0edc02 100755 --- a/src/xlsx/xlsxworksheet.cpp +++ b/src/xlsx/xlsxworksheet.cpp @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include #include @@ -256,6 +258,12 @@ void Worksheet::setZeroValuesHidden(bool enable) d->show_zeros = !enable; } +QStringList Worksheet::externUrlList() const +{ + Q_D(const Worksheet); + return d->externUrlList; +} + int Worksheet::write(int row, int column, const QVariant &value, Format *format) { Q_D(Worksheet); @@ -279,13 +287,16 @@ int Worksheet::write(int row, int column, const QVariant &value, Format *format) ret = writeNumber(row, column, value.toDouble(), format); } } else if (value.type() == QMetaType::QUrl) { //url - + ret = writeUrl(row, column, value.toUrl(), format); } else if (value.type() == QMetaType::QString) { //string QString token = value.toString(); + QRegularExpression urlPattern(QStringLiteral("^([fh]tt?ps?://)|(mailto:)|((in|ex)ternal:)")); if (token.startsWith(QLatin1String("="))) { ret = writeFormula(row, column, token, format); } else if (token.startsWith(QLatin1String("{")) && token.endsWith(QLatin1String("}"))) { + } else if (token.contains(urlPattern)) { + ret = writeUrl(row, column, QUrl(token)); } else { ret = writeString(row, column, token, format); } @@ -386,6 +397,70 @@ int Worksheet::writeDateTime(int row, int column, const QDateTime &dt, Format *f return 0; } +int Worksheet::writeUrl(int row, int column, const QUrl &url, Format *format, const QString &display, const QString &tip) +{ + Q_D(Worksheet); + if (d->checkDimensions(row, column)) + return -1; + + int link_type = 1; + QString urlString = url.toString(); + QString displayString = display; + if (urlString.startsWith(QLatin1String("internal:"))) { + urlString.replace(QLatin1String("internal:"), QString()); + link_type = 2; + } else if (urlString.startsWith(QLatin1String("external:"))) { + urlString.replace(QLatin1String("external:"), QString()); + link_type = 3; + } + + if (display.isEmpty()) + displayString = urlString; + + //For external links, chagne the directory separator from Unix to Dos + if (link_type == 3) { + urlString.replace(QLatin1Char('/'), QLatin1String("\\")); + displayString.replace(QLatin1Char('/'), QLatin1String("\\")); + } + + displayString.replace(QLatin1String("mailto:"), QString()); + + int error = 0; + if (displayString.size() > d->xls_strmax) { + displayString = displayString.left(d->xls_strmax); + error = -2; + } + + QString locationString = displayString; + if (link_type == 1) { + locationString = QString(); + } else if (link_type == 3) { + // External Workbook links need to be modified into correct format. + // The URL will look something like 'c:\temp\file.xlsx#Sheet!A1'. + // We need the part to the left of the # as the URL and the part to + //the right as the "location" string (if it exists). + if (urlString.contains(QLatin1Char('#'))) { + QStringList list = urlString.split(QLatin1Char('#')); + urlString = list[0]; + locationString = list[1]; + } else { + locationString = QString(); + } + link_type = 1; + } + + + //Write the hyperlink string as normal string. + SharedStrings *sharedStrings = d->workbook->sharedStrings(); + int index = sharedStrings->addSharedString(urlString); + d->cellTable[row][column] = new XlsxCellData(index, XlsxCellData::String, format); + + //Store the hyperlink data in sa separate table + d->urlTable[row][column] = new XlsxUrlData(link_type, urlString, locationString, tip); + + return error; +} + void Worksheet::saveToXmlFile(QIODevice *device) { Q_D(Worksheet); @@ -457,6 +532,8 @@ void Worksheet::saveToXmlFile(QIODevice *device) } writer.writeEndElement();//sheetData + d->writeHyperlinks(writer); + writer.writeEndElement();//worksheet writer.writeEndDocument(); } @@ -561,6 +638,49 @@ void WorksheetPrivate::writeCellData(XmlStreamWriter &writer, int row, int col, writer.writeEndElement(); //c } +void WorksheetPrivate::writeHyperlinks(XmlStreamWriter &writer) +{ + if (urlTable.isEmpty()) + return; + + int rel_count = 0; + externUrlList.clear(); + + writer.writeStartElement(QStringLiteral("hyperlinks")); + QMapIterator > it(urlTable); + while (it.hasNext()) { + it.next(); + int row = it.key(); + QMapIterator it2(it.value()); + while(it2.hasNext()) { + it2.next(); + int col = it2.key(); + XlsxUrlData *data = it2.value(); + QString ref = xl_rowcol_to_cell(row, col); + writer.writeEmptyElement(QStringLiteral("hyperlink")); + writer.writeAttribute(QStringLiteral("ref"), ref); + if (data->linkType == 1) { + rel_count += 1; + externUrlList.append(data->url); + writer.writeAttribute(QStringLiteral("r:id"), QStringLiteral("rId%1").arg(rel_count)); + if (!data->location.isEmpty()) + writer.writeAttribute(QStringLiteral("location"), data->location); +// if (!data->url.isEmpty()) +// writer.writeAttribute(QStringLiteral("display"), data->url); + if (!data->tip.isEmpty()) + writer.writeAttribute(QStringLiteral("tooltip"), data->tip); + } else { + writer.writeAttribute(QStringLiteral("location"), data->url); + if (!data->tip.isEmpty()) + writer.writeAttribute(QStringLiteral("tooltip"), data->tip); + writer.writeAttribute(QStringLiteral("display"), data->location); + } + } + } + + writer.writeEndElement();//hyperlinks +} + /* Sets row height and format. Row height measured in point size. If format equals 0 then format is ignored. diff --git a/src/xlsx/xlsxworksheet.h b/src/xlsx/xlsxworksheet.h index a92523e..6d1cb09 100755 --- a/src/xlsx/xlsxworksheet.h +++ b/src/xlsx/xlsxworksheet.h @@ -32,6 +32,7 @@ #include class QIODevice; class QDateTime; +class QUrl; namespace QXlsx { class Package; @@ -53,6 +54,7 @@ public: int writeBlank(int row, int column, Format *format=0); int writeBool(int row, int column, bool value, Format *format=0); int writeDateTime(int row, int column, const QDateTime& dt, Format *format=0); + int writeUrl(int row, int column, const QUrl &url, Format *format=0, const QString &display=QString(), const QString &tip=QString()); bool setRow(int row, double height, Format* format=0, bool hidden=false); bool setColumn(int colFirst, int colLast, double width, Format* format=0, bool hidden=false); @@ -73,6 +75,7 @@ private: void setHidden(bool hidden); void setSelected(bool select); void saveToXmlFile(QIODevice *device); + QStringList externUrlList() const; WorksheetPrivate * const d_ptr; }; diff --git a/src/xlsx/xlsxworksheet_p.h b/src/xlsx/xlsxworksheet_p.h index d42d21e..874643c 100644 --- a/src/xlsx/xlsxworksheet_p.h +++ b/src/xlsx/xlsxworksheet_p.h @@ -51,6 +51,20 @@ struct XlsxCellData Format *format; }; +struct XlsxUrlData +{ + XlsxUrlData(int linkType=1, const QString &url=QString(), const QString &location=QString(), const QString &tip=QString()) : + linkType(linkType), url(url), location(location), tip(tip) + { + + } + + int linkType; + QString url; + QString location; //location string + QString tip; +}; + struct XlsxRowInfo { XlsxRowInfo(double height, Format *format, bool hidden) : @@ -89,10 +103,13 @@ public: void calculateSpans(); void writeSheetData(XmlStreamWriter &writer); void writeCellData(XmlStreamWriter &writer, int row, int col, XlsxCellData *cell); + void writeHyperlinks(XmlStreamWriter &writer); Workbook *workbook; QMap > cellTable; QMap > comments; + QMap > urlTable; + QStringList externUrlList; QMap rowsInfo; QList colsInfo; QMap colsInfoHelper;//Not owns the XlsxColumnInfo