From b6e425772c6b0dcd024b07291443f19ad83c55c3 Mon Sep 17 00:00:00 2001 From: xris1658 Date: Mon, 17 Feb 2025 18:18:36 +0800 Subject: [PATCH 1/5] Add activeCell and sqref in worksheets --- QXlsx/header/xlsxworksheet.h | 7 ++++++ QXlsx/header/xlsxworksheet_p.h | 3 +++ QXlsx/source/xlsxworksheet.cpp | 46 ++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/QXlsx/header/xlsxworksheet.h b/QXlsx/header/xlsxworksheet.h index ccf48564..7d79fbee 100644 --- a/QXlsx/header/xlsxworksheet.h +++ b/QXlsx/header/xlsxworksheet.h @@ -186,6 +186,13 @@ class QXLSX_EXPORT Worksheet : public AbstractSheet void setWhiteSpaceVisible(bool visible); bool setStartPage(int spagen); // add by liufeijin20181028 + CellReference getActiveCell(); + void setActiveCell(CellReference cell); + void setActiveCell(int row, int col); + CellRange getSqref(); + void setSqref(CellRange sqref); + void setSqref(int top, int left, int bottom, int right); + QVector getFullCells(int *maxRow, int *maxCol) const; private: diff --git a/QXlsx/header/xlsxworksheet_p.h b/QXlsx/header/xlsxworksheet_p.h index ee784da7..74c7f620 100644 --- a/QXlsx/header/xlsxworksheet_p.h +++ b/QXlsx/header/xlsxworksheet_p.h @@ -286,6 +286,9 @@ class WorksheetPrivate : public AbstractSheetPrivate QRegularExpression urlPattern; + CellReference activeCell; + CellRange sqref; + private: static double calculateColWidth(int characters); }; diff --git a/QXlsx/source/xlsxworksheet.cpp b/QXlsx/source/xlsxworksheet.cpp index 9f692f94..50350e74 100644 --- a/QXlsx/source/xlsxworksheet.cpp +++ b/QXlsx/source/xlsxworksheet.cpp @@ -61,6 +61,8 @@ WorksheetPrivate::WorksheetPrivate(Worksheet *p, Worksheet::CreateFlag flag) , showOutlineSymbols(true) , showWhiteSpace(true) , urlPattern(QStringLiteral("^([fh]tt?ps?://)|(mailto:)|(file://)")) + , activeCell(1, 1) + , sqref(1, 1, 1, 1) { } @@ -1324,6 +1326,10 @@ void Worksheet::saveToXmlFile(QIODevice *device) const if (!d->showWhiteSpace) writer.writeAttribute(QStringLiteral("showWhiteSpace"), QStringLiteral("0")); writer.writeAttribute(QStringLiteral("workbookViewId"), QStringLiteral("0")); + writer.writeStartElement(QStringLiteral("selection")); + writer.writeAttribute(QStringLiteral("activeCell"), d->activeCell.toString()); + writer.writeAttribute(QStringLiteral("sqref"), d->sqref.toString()); + writer.writeEndElement(); // selection writer.writeEndElement(); // sheetView writer.writeEndElement(); // sheetViews @@ -1481,6 +1487,46 @@ bool Worksheet::setStartPage(int spagen) } //}} +CellReference Worksheet::getActiveCell() +{ + Q_D(Worksheet); + return d->activeCell; +} + +void Worksheet::setActiveCell(CellReference cell) +{ + Q_D(Worksheet); + d->activeCell = cell; +} + +void Worksheet::setActiveCell(int row, int col) +{ + Q_D(Worksheet); + d->activeCell.setRow(row); + d->activeCell.setColumn(col); +} + +CellRange Worksheet::getSqref() +{ + Q_D(Worksheet); + return d->sqref; +} + +void Worksheet::setSqref(CellRange sqref) +{ + Q_D(Worksheet); + d->sqref = sqref; +} + +void Worksheet::setSqref(int top, int left, int bottom, int right) +{ + Q_D(Worksheet); + d->sqref.setFirstRow(top); + d->sqref.setFirstColumn(left); + d->sqref.setLastRow(bottom); + d->sqref.setLastColumn(right); +} + void WorksheetPrivate::saveXmlSheetData(QXmlStreamWriter &writer) const { calculateSpans(); From 9b6a2d172280907316c93d7f015022cbf639e1f3 Mon Sep 17 00:00:00 2001 From: xris1658 Date: Mon, 17 Feb 2025 18:37:12 +0800 Subject: [PATCH 2/5] Add multi-range support for worksheet sqref --- QXlsx/header/xlsxworksheet.h | 5 ++--- QXlsx/header/xlsxworksheet_p.h | 2 +- QXlsx/source/xlsxworksheet.cpp | 25 ++++++++++++------------- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/QXlsx/header/xlsxworksheet.h b/QXlsx/header/xlsxworksheet.h index 7d79fbee..679073ec 100644 --- a/QXlsx/header/xlsxworksheet.h +++ b/QXlsx/header/xlsxworksheet.h @@ -189,9 +189,8 @@ class QXLSX_EXPORT Worksheet : public AbstractSheet CellReference getActiveCell(); void setActiveCell(CellReference cell); void setActiveCell(int row, int col); - CellRange getSqref(); - void setSqref(CellRange sqref); - void setSqref(int top, int left, int bottom, int right); + QList getSqref(); + void setSqref(const QList& sqref); QVector getFullCells(int *maxRow, int *maxCol) const; diff --git a/QXlsx/header/xlsxworksheet_p.h b/QXlsx/header/xlsxworksheet_p.h index 74c7f620..83d1ed3c 100644 --- a/QXlsx/header/xlsxworksheet_p.h +++ b/QXlsx/header/xlsxworksheet_p.h @@ -287,7 +287,7 @@ class WorksheetPrivate : public AbstractSheetPrivate QRegularExpression urlPattern; CellReference activeCell; - CellRange sqref; + QList sqref; private: static double calculateColWidth(int characters); diff --git a/QXlsx/source/xlsxworksheet.cpp b/QXlsx/source/xlsxworksheet.cpp index 50350e74..5bf9a53c 100644 --- a/QXlsx/source/xlsxworksheet.cpp +++ b/QXlsx/source/xlsxworksheet.cpp @@ -62,7 +62,7 @@ WorksheetPrivate::WorksheetPrivate(Worksheet *p, Worksheet::CreateFlag flag) , showWhiteSpace(true) , urlPattern(QStringLiteral("^([fh]tt?ps?://)|(mailto:)|(file://)")) , activeCell(1, 1) - , sqref(1, 1, 1, 1) + , sqref({CellRange(1, 1, 1, 1)}) { } @@ -1328,7 +1328,15 @@ void Worksheet::saveToXmlFile(QIODevice *device) const writer.writeAttribute(QStringLiteral("workbookViewId"), QStringLiteral("0")); writer.writeStartElement(QStringLiteral("selection")); writer.writeAttribute(QStringLiteral("activeCell"), d->activeCell.toString()); - writer.writeAttribute(QStringLiteral("sqref"), d->sqref.toString()); + QString sqrefString; + for (auto it = d->sqref.begin(); it != d->sqref.end(); ++it) { + if(it != d->sqref.begin()) + { + sqrefString.push_back(u' '); + } + sqrefString.append(it->toString()); + } + writer.writeAttribute(QStringLiteral("sqref"), sqrefString); writer.writeEndElement(); // selection writer.writeEndElement(); // sheetView writer.writeEndElement(); // sheetViews @@ -1506,27 +1514,18 @@ void Worksheet::setActiveCell(int row, int col) d->activeCell.setColumn(col); } -CellRange Worksheet::getSqref() +QList Worksheet::getSqref() { Q_D(Worksheet); return d->sqref; } -void Worksheet::setSqref(CellRange sqref) +void Worksheet::setSqref(const QList& sqref) { Q_D(Worksheet); d->sqref = sqref; } -void Worksheet::setSqref(int top, int left, int bottom, int right) -{ - Q_D(Worksheet); - d->sqref.setFirstRow(top); - d->sqref.setFirstColumn(left); - d->sqref.setLastRow(bottom); - d->sqref.setLastColumn(right); -} - void WorksheetPrivate::saveXmlSheetData(QXmlStreamWriter &writer) const { calculateSpans(); From dfc69409fcc4de66acb29d01a1c0e3d234de6dee Mon Sep 17 00:00:00 2001 From: xris1658 Date: Mon, 17 Feb 2025 18:40:42 +0800 Subject: [PATCH 3/5] Set worksheet sqref to A1:A1 while passing an empty `CellRange` list --- QXlsx/source/xlsxworksheet.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/QXlsx/source/xlsxworksheet.cpp b/QXlsx/source/xlsxworksheet.cpp index 5bf9a53c..dc268ade 100644 --- a/QXlsx/source/xlsxworksheet.cpp +++ b/QXlsx/source/xlsxworksheet.cpp @@ -1524,6 +1524,8 @@ void Worksheet::setSqref(const QList& sqref) { Q_D(Worksheet); d->sqref = sqref; + if(d->sqref.empty()) + d->sqref.emplace_back(1, 1, 1, 1); } void WorksheetPrivate::saveXmlSheetData(QXmlStreamWriter &writer) const From 11204fddd135b23a9a625daad9cb6d87f16d5c66 Mon Sep 17 00:00:00 2001 From: xris1658 Date: Wed, 26 Nov 2025 20:22:03 +0800 Subject: [PATCH 4/5] Use functions available in Qt 5 --- QXlsx/source/xlsxworksheet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/QXlsx/source/xlsxworksheet.cpp b/QXlsx/source/xlsxworksheet.cpp index 1c7ab98a..68ba8c5f 100644 --- a/QXlsx/source/xlsxworksheet.cpp +++ b/QXlsx/source/xlsxworksheet.cpp @@ -1525,7 +1525,7 @@ void Worksheet::setSqref(const QList& sqref) Q_D(Worksheet); d->sqref = sqref; if(d->sqref.empty()) - d->sqref.emplace_back(1, 1, 1, 1); + d->sqref.append(CellRange(1, 1, 1, 1)); } void WorksheetPrivate::saveXmlSheetData(QXmlStreamWriter &writer) const From e4896011e1bada3c79d26a274eb5ec372a7460bb Mon Sep 17 00:00:00 2001 From: xris1658 Date: Sun, 30 Nov 2025 21:22:19 +0800 Subject: [PATCH 5/5] Move activeCell and sqref to selection --- QXlsx/header/xlsxworksheet.h | 13 ++--- QXlsx/header/xlsxworksheet_p.h | 11 +++- QXlsx/source/xlsxworksheet.cpp | 99 +++++++++++++++++++++++++--------- 3 files changed, 89 insertions(+), 34 deletions(-) diff --git a/QXlsx/header/xlsxworksheet.h b/QXlsx/header/xlsxworksheet.h index 679073ec..17a1b8a2 100644 --- a/QXlsx/header/xlsxworksheet.h +++ b/QXlsx/header/xlsxworksheet.h @@ -185,12 +185,13 @@ class QXLSX_EXPORT Worksheet : public AbstractSheet bool isWhiteSpaceVisible() const; void setWhiteSpaceVisible(bool visible); bool setStartPage(int spagen); // add by liufeijin20181028 - - CellReference getActiveCell(); - void setActiveCell(CellReference cell); - void setActiveCell(int row, int col); - QList getSqref(); - void setSqref(const QList& sqref); + CellReference selectionActiveCell() const; + void setSelectionActiveCell(CellReference activeCell); + quint32 selectionActiveCellId() const; + bool selectionActiveCellId(quint32 activeCellId); + QList selectionSqref() const; + void setSelectionSqref(const QList &selectionSqref); + void setSelectionSqref(QList &&selectionSqref); QVector getFullCells(int *maxRow, int *maxCol) const; diff --git a/QXlsx/header/xlsxworksheet_p.h b/QXlsx/header/xlsxworksheet_p.h index 83d1ed3c..50bae28e 100644 --- a/QXlsx/header/xlsxworksheet_p.h +++ b/QXlsx/header/xlsxworksheet_p.h @@ -132,6 +132,14 @@ struct XlsxColumnInfo { bool collapsed; }; +// ECMA-376 Part1 18.3.1.78 +struct XlsxSheetViewSelectionProps { + CellReference activeCell; + quint32 activeCellId; + // TODO: Add pane while adding multiple-`sheetView` support + QList sqref; +}; + class CellTable { public: @@ -286,8 +294,7 @@ class WorksheetPrivate : public AbstractSheetPrivate QRegularExpression urlPattern; - CellReference activeCell; - QList sqref; + XlsxSheetViewSelectionProps selectionProps; private: static double calculateColWidth(int characters); diff --git a/QXlsx/source/xlsxworksheet.cpp b/QXlsx/source/xlsxworksheet.cpp index 68ba8c5f..9d29dc59 100644 --- a/QXlsx/source/xlsxworksheet.cpp +++ b/QXlsx/source/xlsxworksheet.cpp @@ -61,8 +61,6 @@ WorksheetPrivate::WorksheetPrivate(Worksheet *p, Worksheet::CreateFlag flag) , showOutlineSymbols(true) , showWhiteSpace(true) , urlPattern(QStringLiteral("^([fh]tt?ps?://)|(mailto:)|(file://)")) - , activeCell(1, 1) - , sqref({CellRange(1, 1, 1, 1)}) { } @@ -1326,18 +1324,27 @@ void Worksheet::saveToXmlFile(QIODevice *device) const if (!d->showWhiteSpace) writer.writeAttribute(QStringLiteral("showWhiteSpace"), QStringLiteral("0")); writer.writeAttribute(QStringLiteral("workbookViewId"), QStringLiteral("0")); - writer.writeStartElement(QStringLiteral("selection")); - writer.writeAttribute(QStringLiteral("activeCell"), d->activeCell.toString()); - QString sqrefString; - for (auto it = d->sqref.begin(); it != d->sqref.end(); ++it) { - if(it != d->sqref.begin()) - { - sqrefString.push_back(u' '); + if (d->selectionProps.activeCell.isValid() || !d->selectionProps.sqref.isEmpty()) { + writer.writeStartElement(QStringLiteral("selection")); + if (d->selectionProps.activeCell.isValid()) { + writer.writeAttribute(QStringLiteral("activeCell"), + d->selectionProps.activeCell.toString()); } - sqrefString.append(it->toString()); + if (!d->selectionProps.sqref.isEmpty()) { + QString sqrefString; + for (const auto range : d->selectionProps.sqref) { + sqrefString.append(range.toString()); + sqrefString.push_back(QLatin1Char(' ')); + } + sqrefString.truncate(sqrefString.size() - 1); + writer.writeAttribute(QStringLiteral("sqref"), sqrefString); + if (d->selectionProps.sqref.size() > 1) { + writer.writeAttribute(QStringLiteral("activeCellId"), + QString::number(d->selectionProps.activeCellId)); + } + } + writer.writeEndElement(); // selection } - writer.writeAttribute(QStringLiteral("sqref"), sqrefString); - writer.writeEndElement(); // selection writer.writeEndElement(); // sheetView writer.writeEndElement(); // sheetViews @@ -1495,37 +1502,52 @@ bool Worksheet::setStartPage(int spagen) } //}} -CellReference Worksheet::getActiveCell() +CellReference Worksheet::selectionActiveCell() const { - Q_D(Worksheet); - return d->activeCell; + Q_D(const Worksheet); + return d->selectionProps.activeCell; } -void Worksheet::setActiveCell(CellReference cell) +void Worksheet::setSelectionActiveCell(CellReference activeCell) { Q_D(Worksheet); - d->activeCell = cell; + d->selectionProps.activeCell = activeCell; } -void Worksheet::setActiveCell(int row, int col) +quint32 Worksheet::selectionActiveCellId() const +{ + Q_D(const Worksheet); + return d->selectionProps.activeCellId; +} + +bool Worksheet::selectionActiveCellId(quint32 activeCellId) { Q_D(Worksheet); - d->activeCell.setRow(row); - d->activeCell.setColumn(col); + if (activeCellId < d->selectionProps.sqref.size()) { + d->selectionProps.activeCellId = activeCellId; + return true; + } + return false; +} + +QList Worksheet::selectionSqref() const +{ + Q_D(const Worksheet); + return d->selectionProps.sqref; } -QList Worksheet::getSqref() +void Worksheet::setSelectionSqref(const QList &selectionSqref) { Q_D(Worksheet); - return d->sqref; + d->selectionProps.sqref = selectionSqref; + d->selectionProps.activeCellId = 0; } -void Worksheet::setSqref(const QList& sqref) +void Worksheet::setSelectionSqref(QList &&selectionSqref) { Q_D(Worksheet); - d->sqref = sqref; - if(d->sqref.empty()) - d->sqref.append(CellRange(1, 1, 1, 1)); + d->selectionProps.sqref = std::move(selectionSqref); + d->selectionProps.activeCellId = 0; } void WorksheetPrivate::saveXmlSheetData(QXmlStreamWriter &writer) const @@ -2623,6 +2645,31 @@ void WorksheetPrivate::loadXmlSheetViews(QXmlStreamReader &reader) showOutlineSymbols = attrs.value(QLatin1String("showOutlineSymbols")) != QLatin1String("0"); showWhiteSpace = attrs.value(QLatin1String("showWhiteSpace")) != QLatin1String("0"); + reader.readNextStartElement(); + if (reader.tokenType() == QXmlStreamReader::StartElement && + reader.name() == QLatin1String("selection")) { + QXmlStreamAttributes selectionAttr = reader.attributes(); + selectionProps.activeCell = + CellReference(selectionAttr.value(QLatin1String("activeCell")).toString()); + selectionProps.activeCellId = + selectionAttr.value(QLatin1String("activeCellId")).toUInt(); + QStringView sqrefStr = selectionAttr.value(QLatin1String("sqref")); + QList ranges = sqrefStr.split(QLatin1Char(' ')); + for (const auto &range : ranges) { + selectionProps.sqref.append(CellRange(range.toString())); + } + if (selectionProps.activeCellId >= selectionProps.sqref.count()) { + for (auto it = selectionProps.sqref.begin(); it != selectionProps.sqref.end(); + ++it) { + const auto &range = *it; + if (!(range.topLeft() > selectionProps.activeCell) && + !(selectionProps.activeCell > range.bottomRight())) { + selectionProps.activeCellId = it - selectionProps.sqref.begin(); + break; + } + } + } + } } } }