diff --git a/examples/xlsx/mergecells/main.cpp b/examples/xlsx/mergecells/main.cpp new file mode 100644 index 0000000..48fd3ef --- /dev/null +++ b/examples/xlsx/mergecells/main.cpp @@ -0,0 +1,28 @@ +#include +#include "xlsxworkbook.h" +#include "xlsxworksheet.h" + +#ifdef Q_OS_MAC +# define DATA_PATH "../../../" +#else +# define DATA_PATH "./" +#endif + +int main(int argc, char** argv) +{ + QGuiApplication(argc, argv); + + QXlsx::Workbook workbook; + QXlsx::Worksheet *sheet = workbook.addWorksheet(); + + sheet->write("B1", "Merge Cells"); + sheet->mergeCells("B1:B5"); + + sheet->write("E2", "Merge Cells 2"); + sheet->mergeCells("E2:G4"); + + workbook.save(DATA_PATH"Test.xlsx"); + + return 0; +} + diff --git a/examples/xlsx/mergecells/mergecells.pro b/examples/xlsx/mergecells/mergecells.pro new file mode 100644 index 0000000..1bfe1d5 --- /dev/null +++ b/examples/xlsx/mergecells/mergecells.pro @@ -0,0 +1,6 @@ +TARGET = mergecells + +#include(../../../src/xlsx/qtxlsx.pri) +QT += xlsx + +SOURCES += main.cpp diff --git a/examples/xlsx/xlsx.pro b/examples/xlsx/xlsx.pro index 50c714b..a558313 100644 --- a/examples/xlsx/xlsx.pro +++ b/examples/xlsx/xlsx.pro @@ -1,5 +1,6 @@ TEMPLATE = subdirs SUBDIRS = hello style \ documentproperty \ - image + image \ + mergecells diff --git a/src/xlsx/xlsxworksheet.cpp b/src/xlsx/xlsxworksheet.cpp index d295058..986b716 100755 --- a/src/xlsx/xlsxworksheet.cpp +++ b/src/xlsx/xlsxworksheet.cpp @@ -484,6 +484,74 @@ int Worksheet::insertImage(int row, int column, const QImage &image, const QPoin return 0; } +int Worksheet::mergeCells(const QString &range) +{ + Q_D(Worksheet); + QStringList cells = range.split(QLatin1Char(':')); + if (cells.size() != 2) + return -1; + QPoint cell1 = xl_cell_to_rowcol(cells[0]); + QPoint cell2 = xl_cell_to_rowcol(cells[1]); + + if (cell1 == QPoint(-1,-1) || cell2 == QPoint(-1, -1)) + return -1; + + return mergeCells(cell1.x(), cell1.y(), cell2.x(), cell2.y()); +} + +int Worksheet::mergeCells(int row_begin, int column_begin, int row_end, int column_end) +{ + Q_D(Worksheet); + + if (row_begin == row_end && column_begin == column_end) + return -1; + + if (d->checkDimensions(row_end, column_end)) + return -1; + + XlsxCellRange range; + range.row_begin = row_begin; + range.row_end = row_end; + range.column_begin = column_begin; + range.column_end = column_end; + + d->merges.append(range); + + return 0; +} + +int Worksheet::unmergeCells(const QString &range) +{ + Q_D(Worksheet); + QStringList cells = range.split(QLatin1Char(':')); + if (cells.size() != 2) + return -1; + QPoint cell1 = xl_cell_to_rowcol(cells[0]); + QPoint cell2 = xl_cell_to_rowcol(cells[1]); + + if (cell1 == QPoint(-1,-1) || cell2 == QPoint(-1, -1)) + return -1; + + return unmergeCells(cell1.x(), cell1.y(), cell2.x(), cell2.y()); +} + +int Worksheet::unmergeCells(int row_begin, int column_begin, int row_end, int column_end) +{ + Q_D(Worksheet); + XlsxCellRange range; + range.row_begin = row_begin; + range.row_end = row_end; + range.column_begin = column_begin; + range.column_end = column_end; + + if (!d->merges.contains(range)) + return -1; + + d->merges.removeOne(range); + + return 0; +} + void Worksheet::saveToXmlFile(QIODevice *device) { Q_D(Worksheet); @@ -555,6 +623,7 @@ void Worksheet::saveToXmlFile(QIODevice *device) } writer.writeEndElement();//sheetData + d->writeMergeCells(writer); d->writeHyperlinks(writer); d->writeDrawings(writer); @@ -662,6 +731,24 @@ void WorksheetPrivate::writeCellData(XmlStreamWriter &writer, int row, int col, writer.writeEndElement(); //c } +void WorksheetPrivate::writeMergeCells(XmlStreamWriter &writer) +{ + if (merges.isEmpty()) + return; + + writer.writeStartElement(QStringLiteral("mergeCells")); + writer.writeAttribute(QStringLiteral("count"), QString::number(merges.size())); + + foreach (XlsxCellRange range, merges) { + QString cell1 = xl_rowcol_to_cell(range.row_begin, range.column_begin); + QString cell2 = xl_rowcol_to_cell(range.row_end, range.column_end); + writer.writeEmptyElement(QStringLiteral("mergeCell")); + writer.writeAttribute(QStringLiteral("ref"), cell1+QLatin1Char(':')+cell2); + } + + writer.writeEndElement(); //mergeCells +} + void WorksheetPrivate::writeHyperlinks(XmlStreamWriter &writer) { if (urlTable.isEmpty()) diff --git a/src/xlsx/xlsxworksheet.h b/src/xlsx/xlsxworksheet.h index 516e9c7..4a254c7 100755 --- a/src/xlsx/xlsxworksheet.h +++ b/src/xlsx/xlsxworksheet.h @@ -62,17 +62,23 @@ public: int insertImage(int row, int column, const QImage &image, const QPointF &offset=QPointF(), double xScale=1, double yScale=1); + int mergeCells(int row_begin, int column_begin, int row_end, int column_end); + int mergeCells(const QString &range); + int unmergeCells(int row_begin, int column_begin, int row_end, int column_end); + int unmergeCells(const QString &range); + 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); void setRightToLeft(bool enable); void setZeroValuesHidden(bool enable); + void saveToXmlFile(QIODevice *device); + ~Worksheet(); private: friend class Package; friend class Workbook; Worksheet(const QString &sheetName, Workbook *parent=0); - ~Worksheet(); virtual bool isChartsheet() const; QString name() const; @@ -80,7 +86,6 @@ private: bool isSelected() const; void setHidden(bool hidden); void setSelected(bool select); - void saveToXmlFile(QIODevice *device); QStringList externUrlList() const; QStringList externDrawingList() const; QList > drawingLinks() const; diff --git a/src/xlsx/xlsxworksheet_p.h b/src/xlsx/xlsxworksheet_p.h index 462c053..80ffa1e 100644 --- a/src/xlsx/xlsxworksheet_p.h +++ b/src/xlsx/xlsxworksheet_p.h @@ -82,6 +82,23 @@ struct XlsxImageData double yScale; }; +struct XlsxCellRange +{ + int row_begin; + int row_end; + int column_begin; + int column_end; + + bool operator ==(const XlsxCellRange &other) const { + return row_begin==other.row_begin && row_end==other.row_end + && column_begin == other.column_begin && column_end==other.column_end; + } + bool operator !=(const XlsxCellRange &other) const { + return row_begin!=other.row_begin || row_end!=other.row_end + || column_begin != other.column_begin || column_end!=other.column_end; + } +}; + /* The vertices that define the position of a graphical object within the worksheet in pixels. @@ -166,6 +183,7 @@ public: void calculateSpans(); void writeSheetData(XmlStreamWriter &writer); void writeCellData(XmlStreamWriter &writer, int row, int col, XlsxCellData *cell); + void writeMergeCells(XmlStreamWriter &writer); void writeHyperlinks(XmlStreamWriter &writer); void writeDrawings(XmlStreamWriter &writer); int rowPixelsSize(int row); @@ -178,6 +196,7 @@ public: QMap > cellTable; QMap > comments; QMap > urlTable; + QList merges; QStringList externUrlList; QStringList externDrawingList; QList imageList; diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 7eee048..9183dcb 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -1,3 +1,4 @@ TEMPLATE=subdirs SUBDIRS=\ - utility + utility \ + mergecell diff --git a/tests/auto/mergecell/mergecell.pro b/tests/auto/mergecell/mergecell.pro new file mode 100644 index 0000000..640aa57 --- /dev/null +++ b/tests/auto/mergecell/mergecell.pro @@ -0,0 +1,18 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2013-09-06T10:52:56 +# +#------------------------------------------------- + +QT += testlib xlsx xlsx-private +CONFIG += testcase +DEFINES += XLSX_TEST + +TARGET = tst_mergecelltest +CONFIG += console +CONFIG -= app_bundle + +TEMPLATE = app + +SOURCES += tst_mergecelltest.cpp +DEFINES += SRCDIR=\\\"$$PWD/\\\" diff --git a/tests/auto/mergecell/tst_mergecelltest.cpp b/tests/auto/mergecell/tst_mergecelltest.cpp new file mode 100644 index 0000000..6833d12 --- /dev/null +++ b/tests/auto/mergecell/tst_mergecelltest.cpp @@ -0,0 +1,71 @@ +#include +#include + +#include "xlsxworksheet.h" +#include "xlsxworkbook.h" + +class MergeCellTest : public QObject +{ + Q_OBJECT + +public: + MergeCellTest(); + +private Q_SLOTS: + void testWithoutMerge(); + void testMerge(); + void testUnMerge(); +}; + +MergeCellTest::MergeCellTest() +{ +} + +void MergeCellTest::testWithoutMerge() +{ + QXlsx::Workbook book; + QXlsx::Worksheet *sheet = book.addWorksheet("Sheet1"); + sheet->write("B1", "Hello"); + + QByteArray xmldata; + QBuffer buffer(&xmldata); + buffer.open(QIODevice::WriteOnly); + sheet->saveToXmlFile(&buffer); + + QVERIFY2(!xmldata.contains("write("B1", "Test Merged Cell"); + sheet->mergeCells("B1:B5"); + + QByteArray xmldata; + QBuffer buffer(&xmldata); + buffer.open(QIODevice::WriteOnly); + sheet->saveToXmlFile(&buffer); + + QVERIFY2(xmldata.contains(""), ""); +} + +void MergeCellTest::testUnMerge() +{ + QXlsx::Workbook book; + QXlsx::Worksheet *sheet = book.addWorksheet("Sheet1"); + sheet->write("B1", "Test Merged Cell"); + sheet->mergeCells("B1:B5"); + sheet->unmergeCells("B1:B5"); + + QByteArray xmldata; + QBuffer buffer(&xmldata); + buffer.open(QIODevice::WriteOnly); + sheet->saveToXmlFile(&buffer); + + QVERIFY2(!xmldata.contains("