From kde-commits Wed Apr 21 15:48:40 2010 From: Marijn Kruisselbrink Date: Wed, 21 Apr 2010 15:48:40 +0000 To: kde-commits Subject: koffice/filters/kspread/excel Message-Id: <20100421154840.E5E02AC8A3 () svn ! kde ! org> X-MARC-Message: https://marc.info/?l=kde-commits&m=127186474104998 SVN commit 1117238 by mkruisselbrink: don't save builtin named ranges (that aren't really named ranges in the first place) as named ranges, but save autofilter ranges as autofilter ranges. M +32 -3 import/excelimport.cc M +17 -4 sidewinder/excel.cpp M +4 -0 sidewinder/excel.h M +35 -0 sidewinder/formulas.cpp M +6 -2 sidewinder/formulas.h M +15 -6 sidewinder/globalssubstreamhandler.cpp M +23 -0 sidewinder/records.xml M +15 -4 sidewinder/workbook.cpp M +11 -7 sidewinder/workbook.h --- trunk/koffice/filters/kspread/excel/import/excelimport.cc #1117237:1117238 @@ -566,12 +566,12 @@ processSheetForBody(store, sheet, xmlWriter); } - std::map &namedAreas = workbook->namedAreas(); + std::map, UString> &namedAreas = workbook->namedAreas(); if(namedAreas.size() > 0) { xmlWriter->startElement("table:named-expressions"); - for(std::map::iterator it = namedAreas.begin(); it != namedAreas.end(); it++) { + for(std::map, UString>::iterator it = namedAreas.begin(); it != namedAreas.end(); it++) { xmlWriter->startElement("table:named-range"); - xmlWriter->addAttribute("table:name", string((*it).first) ); // e.g. "My Named Range" + xmlWriter->addAttribute("table:name", string((*it).first.second) ); // e.g. "My Named Range" QString range = string((*it).second); if(range.startsWith('[') && range.endsWith(']')) range = range.mid(1, range.length() - 2); @@ -581,6 +581,35 @@ xmlWriter->endElement(); } + bool openedDBRanges = false; + int rangeId = 1; + for (unsigned i = 0; i < workbook->sheetCount(); i++) { + QList filters = workbook->filterRanges(i); + QString sheetName = string(workbook->sheet(i)->name()); + if (filters.size()) { + if (!openedDBRanges) xmlWriter->startElement("table:database-ranges"); + openedDBRanges = true; + + foreach (const QRect& filter, filters) { + QString sRange(sheetName); + sRange.append("."); + sRange.append(columnName(filter.left())); + sRange.append(QString::number(filter.top()+1)); + sRange.append(":"); + sRange.append(sheetName); + sRange.append("."); + sRange.append(columnName(filter.right())); + sRange.append(QString::number(workbook->sheet(i)->maxRow())); + xmlWriter->startElement("table:database-range"); + xmlWriter->addAttribute("table:name", QString("database-%1").arg(rangeId++)); + xmlWriter->addAttribute("table:display-filter-buttons", "true"); + xmlWriter->addAttribute("table:target-range-address", sRange); + xmlWriter->endElement(); // table:database-range + } + } + } + if (openedDBRanges) xmlWriter->endElement(); // table:database-ranges + xmlWriter->endElement(); // office:spreadsheet } --- trunk/koffice/filters/kspread/excel/sidewinder/excel.cpp #1117237:1117238 @@ -965,6 +965,8 @@ public: unsigned optionFlags; UString definedName; + int sheetIndex; // 0 for global + bool builtin; }; @@ -990,6 +992,16 @@ return d->definedName; } +unsigned NameRecord::sheetIndex() const +{ + return d->sheetIndex; +} + +bool NameRecord::isBuiltin() const +{ + return d->builtin; +} + void NameRecord::setData(unsigned size, const unsigned char* data, const unsigned int*) { if (size < 14) { @@ -1003,7 +1015,7 @@ //const bool fOB = d->optionFlags & 0x04; //const bool fProc = d->optionFlags & 0x08; //const bool fCalcExp = d->optionFlags & 0x10; - const bool fBuiltin = d->optionFlags & 0x20; + d->builtin = d->optionFlags & 0x20; // 6 bits fGrp //const bool reserved1 = d->optionFlags & 0x1800; //const bool fPublished = d->optionFlags & 0x3000; @@ -1013,7 +1025,7 @@ const unsigned len = readU8(data + 3); // cch const unsigned cce = readU16(data + 4); // len of rgce // 2 bytes reserved - const unsigned iTab = readU16(data + 8); // if !=0 then its a local name + d->sheetIndex = readU16(data + 8); // if !=0 then its a local name // 4 bytes reserved if (version() == Excel95) { @@ -1023,7 +1035,7 @@ d->definedName = UString(buffer); delete[] buffer; } else if (version() == Excel97) { - if( fBuiltin ) { // field is for a build-in name + if( d->builtin ) { // field is for a build-in name const unsigned opts = readU8(data + 14); const bool fHighByte = opts & 0x01; const unsigned id = fHighByte ? readU16(data + 15) : readU8(data + 15) + 0x0*256; @@ -1041,6 +1053,7 @@ case 0x0A: d->definedName = "Auto_Activate"; break; case 0x0B: d->definedName = "Auto_Deactivate"; break; case 0x0C: d->definedName = "Sheet_Title"; break; + case 0x0D: d->definedName = "_FilterDatabase"; break; default: break; } } else { // must satisfy same restrictions then name field on XLNameUnicodeString @@ -1090,7 +1103,7 @@ m_formula = t; } - std::cout << "NameRecord name=" << d->definedName << " iTab=" << iTab << " fBuiltin=" << fBuiltin << " formula=" << m_formula.id() << " (" << m_formula.idAsString() << ")" << std::endl; + std::cout << "NameRecord name=" << d->definedName << " iTab=" << d->sheetIndex << " fBuiltin=" << d->builtin << " formula=" << m_formula.id() << " (" << m_formula.idAsString() << ")" << std::endl; } void NameRecord::dump(std::ostream& /*out*/) const --- trunk/koffice/filters/kspread/excel/sidewinder/excel.h #1117237:1117238 @@ -620,6 +620,10 @@ void setDefinedName(const UString& name); + unsigned sheetIndex() const; + + bool isBuiltin() const; + virtual void setData(unsigned size, const unsigned char* data, const unsigned int* continuePositions); virtual const char* name() const { --- trunk/koffice/filters/kspread/excel/sidewinder/formulas.cpp #1117237:1117238 @@ -974,6 +974,41 @@ return result; } +std::pair FormulaToken::filterArea3d() const +{ + if (version() != Excel97) { + return std::make_pair(0, QRect()); + } + + unsigned sheetRef = readU16(&d->data[0]); + + // FIXME check data size ! + unsigned char buf[2]; + int row1Ref, row2Ref, col1Ref, col2Ref; + + buf[0] = d->data[2]; + buf[1] = d->data[3]; + row1Ref = readU16(buf); + + buf[0] = d->data[4]; + buf[1] = d->data[5]; + row2Ref = readU16(buf); + + buf[0] = d->data[6]; + buf[1] = d->data[7]; + col1Ref = readU16(buf); + + buf[0] = d->data[8]; + buf[1] = d->data[9]; + col2Ref = readU16(buf); + + col1Ref &= 0x3fff; + col2Ref &= 0x3fff; + + QRect range(col1Ref, row1Ref, col2Ref - col1Ref + 1, row2Ref - row1Ref + 1); + return std::make_pair(sheetRef, range); +} + UString FormulaToken::areaMap(unsigned row, unsigned col) { unsigned char buf[4]; --- trunk/koffice/filters/kspread/excel/sidewinder/formulas.h #1117237:1117238 @@ -26,6 +26,8 @@ #include +#include + namespace Swinder { @@ -129,6 +131,8 @@ UString area(unsigned row, unsigned col, bool relative = false) const; // only when id is Area3d UString area3d(const std::vector& externSheets, unsigned row, unsigned col) const; + // only when id is Area3d, assumes all references to be absolute + std::pair filterArea3d() const; // only when id is MemArea UString areaMap(unsigned row, unsigned col); @@ -144,7 +148,7 @@ std::pair baseFormulaRecord() const; void operator=(const FormulaToken& token); - + private: class Private; Private *d; @@ -167,7 +171,7 @@ FormulaTokens decodeFormula(unsigned size, unsigned pos, const unsigned char* data, unsigned version); UString decodeFormula(unsigned row, unsigned col, bool isShared, const FormulaTokens& tokens); - UString dataTableFormula(unsigned row, unsigned col, const DataTableRecord* record); + UString dataTableFormula(unsigned row, unsigned col, const DataTableRecord* record); virtual const std::vector& externSheets() const { return m_externSheets; } virtual UString nameFromIndex(unsigned /*index*/) const { return UString(); } --- trunk/koffice/filters/kspread/excel/sidewinder/globalssubstreamhandler.cpp #1117237:1117238 @@ -679,12 +679,21 @@ d->nameTable.push_back(record->definedName()); if(record->m_formula.id() != FormulaToken::Unused) { - FormulaTokens tokens; - tokens.push_back(record->m_formula); - UString f = decodeFormula(0, 0, false, tokens); - if(!f.isEmpty()) { - UString n = record->definedName(); - d->workbook->setNamedArea(n, f); + if (record->isBuiltin()) { + if (record->definedName() == "_FilterDatabase") { + if (record->m_formula.id() == FormulaToken::Area3d) { + std::pair area = record->m_formula.filterArea3d(); + d->workbook->addFilterRange(area.first, area.second); + } + } + } else { + FormulaTokens tokens; + tokens.push_back(record->m_formula); + UString f = decodeFormula(0, 0, false, tokens); + if(!f.isEmpty()) { + UString n = record->definedName(); + d->workbook->setNamedArea(record->sheetIndex(), n, f); + } } } } --- trunk/koffice/filters/kspread/excel/sidewinder/records.xml #1117237:1117238 @@ -957,5 +957,28 @@ + + + + + + + + + + + + + + + + + + + + + + + --- trunk/koffice/filters/kspread/excel/sidewinder/workbook.cpp #1117237:1117238 @@ -33,7 +33,8 @@ Store* store; std::vector sheets; QHash properties; - std::map namedAreas; + std::map, UString> namedAreas; + std::map > filterRanges; int activeTab; bool passwordProtected; unsigned long passwd; @@ -109,16 +110,26 @@ d->properties[ type ] = value; } -std::map& Workbook::namedAreas() +std::map, UString>& Workbook::namedAreas() { return d->namedAreas; } -void Workbook::setNamedArea(UString name, UString formula) +void Workbook::setNamedArea(unsigned sheet, UString name, UString formula) { - d->namedAreas[name] = formula; + d->namedAreas[std::make_pair(sheet, name)] = formula; } +QList Workbook::filterRanges(unsigned sheet) const +{ + return d->filterRanges[sheet]; +} + +void Workbook::addFilterRange(unsigned sheet, const QRect& range) +{ + d->filterRanges[sheet].push_back(range); +} + int Workbook::activeTab() const { return d->activeTab; --- trunk/koffice/filters/kspread/excel/sidewinder/workbook.h #1117237:1117238 @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -36,7 +37,7 @@ public: explicit Store() {} virtual ~Store() {} - + virtual bool open(const std::string& filename) = 0; virtual bool write(const char *data, int size) = 0; virtual bool close() = 0; @@ -51,7 +52,7 @@ /** * Constructs a new workbook. - * + * * @a store An optional implementation of the Store class * that is used to write content like images to. */ @@ -66,7 +67,7 @@ * Returns the used KoStore or NULL if not KoStore was set. /*/ Store* store() const; - + /** * Clears the workbook, i.e. makes it as if it is just constructed. */ @@ -114,9 +115,12 @@ QVariant property(PropertyType type, const QVariant &defaultValue = QVariant()) const; void setProperty(PropertyType type, const QVariant &value); - std::map& namedAreas(); - void setNamedArea(UString name, UString formula); - + std::map, UString>& namedAreas(); + void setNamedArea(unsigned sheet, UString name, UString formula); + + QList filterRanges(unsigned sheet) const; + void addFilterRange(unsigned sheet, const QRect& range); + int activeTab() const; void setActiveTab(int tab); @@ -127,7 +131,7 @@ void setPassword(unsigned long hash); void emitProgress(int value); - + signals: void sigProgress(int value);