1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  */
9 
10 #include <columniterator.hxx>
11 #include <column.hxx>
12 #include <document.hxx>
13 #include <table.hxx>
14 
15 #include <osl/diagnose.h>
16 
ScColumnTextWidthIterator(const ScDocument & rDoc,ScColumn & rCol,SCROW nStartRow,SCROW nEndRow)17 ScColumnTextWidthIterator::ScColumnTextWidthIterator(const ScDocument& rDoc, ScColumn& rCol, SCROW nStartRow, SCROW nEndRow) :
18     mnEnd(static_cast<size_t>(nEndRow)),
19     mnCurPos(0)
20 {
21     miBlockCur = rCol.maCellTextAttrs.begin();
22     miBlockEnd = rCol.maCellTextAttrs.end();
23     init(rDoc, nStartRow, nEndRow);
24 }
25 
ScColumnTextWidthIterator(const ScDocument & rDoc,const ScAddress & rStartPos,SCROW nEndRow)26 ScColumnTextWidthIterator::ScColumnTextWidthIterator(const ScDocument& rDoc, const ScAddress& rStartPos, SCROW nEndRow) :
27     mnEnd(static_cast<size_t>(nEndRow)),
28     mnCurPos(0)
29 {
30     auto & rCellTextAttrs = rDoc.maTabs[rStartPos.Tab()]->aCol[rStartPos.Col()].maCellTextAttrs;
31     miBlockCur = rCellTextAttrs.begin();
32     miBlockEnd = rCellTextAttrs.end();
33     init(rDoc, rStartPos.Row(), nEndRow);
34 }
35 
next()36 void ScColumnTextWidthIterator::next()
37 {
38     ++miDataCur;
39     ++mnCurPos;
40 
41     if (miDataCur != miDataEnd)
42     {
43         // Still in the same block. We're good.
44         checkEndRow();
45         return;
46     }
47 
48     // Move to the next block.
49     for (++miBlockCur; miBlockCur != miBlockEnd; ++miBlockCur)
50     {
51         if (miBlockCur->type != sc::element_type_celltextattr)
52         {
53             // We don't iterator over this block.
54             mnCurPos += miBlockCur->size;
55             continue;
56         }
57 
58         getDataIterators(0);
59         checkEndRow();
60         return;
61     }
62 
63     // Reached the end.
64     assert(miBlockCur == miBlockEnd);
65 }
66 
hasCell() const67 bool ScColumnTextWidthIterator::hasCell() const
68 {
69     return miBlockCur != miBlockEnd;
70 }
71 
getPos() const72 SCROW ScColumnTextWidthIterator::getPos() const
73 {
74     assert(miBlockCur != miBlockEnd && miDataCur != miDataEnd);
75     return static_cast<SCROW>(mnCurPos);
76 }
77 
getValue() const78 sal_uInt16 ScColumnTextWidthIterator::getValue() const
79 {
80     assert(miBlockCur != miBlockEnd && miDataCur != miDataEnd);
81     return miDataCur->mnTextWidth;
82 }
83 
setValue(sal_uInt16 nVal)84 void ScColumnTextWidthIterator::setValue(sal_uInt16 nVal)
85 {
86     assert(miBlockCur != miBlockEnd && miDataCur != miDataEnd);
87     miDataCur->mnTextWidth = nVal;
88 }
89 
init(const ScDocument & rDoc,SCROW nStartRow,SCROW nEndRow)90 void ScColumnTextWidthIterator::init(const ScDocument& rDoc, SCROW nStartRow, SCROW nEndRow)
91 {
92     if (!rDoc.ValidRow(nStartRow) || !rDoc.ValidRow(nEndRow))
93         miBlockCur = miBlockEnd;
94 
95     size_t nStart = static_cast<size_t>(nStartRow);
96 
97     // Locate the start row position.
98     size_t nBlockStart = 0, nBlockEnd = 0;
99     for (; miBlockCur != miBlockEnd; ++miBlockCur, nBlockStart = nBlockEnd)
100     {
101         nBlockEnd = nBlockStart + miBlockCur->size; // non-inclusive end point.
102         if (nBlockStart <= nStart && nStart < nBlockEnd)
103         {
104             // Initial block is found!
105             break;
106         }
107     }
108 
109     if (miBlockCur == miBlockEnd)
110         // Initial block not found for whatever reason... Bail out.
111         return;
112 
113     // Locate the initial row position within this block.
114     if (miBlockCur->type == sc::element_type_celltextattr)
115     {
116         // This block stores text widths for non-empty cells.
117         size_t nOffsetInBlock = nStart - nBlockStart;
118         mnCurPos = nStart;
119         getDataIterators(nOffsetInBlock);
120         checkEndRow();
121         return;
122     }
123 
124     // Current block is not of ushort type.  Skip to the next block.
125     nBlockStart = nBlockEnd;
126     ++miBlockCur;
127 
128     // Look for the first ushort block.
129     for (; miBlockCur != miBlockEnd; ++miBlockCur, nBlockStart = nBlockEnd)
130     {
131         nBlockEnd = nBlockStart + miBlockCur->size; // non-inclusive end point.
132         if (miBlockCur->type != sc::element_type_celltextattr)
133             continue;
134 
135         // Found!
136         mnCurPos = nBlockStart;
137         getDataIterators(0);
138         checkEndRow();
139         return;
140     }
141 
142     // Not found.
143     assert(miBlockCur == miBlockEnd);
144 }
145 
getDataIterators(size_t nOffsetInBlock)146 void ScColumnTextWidthIterator::getDataIterators(size_t nOffsetInBlock)
147 {
148     OSL_ENSURE(miBlockCur != miBlockEnd, "block is at end position");
149 #if 0
150     // Does not compile
151     OSL_ENSURE(miBlockCur->type == sc::celltextattr_block,
152                "wrong block type - unsigned short block expected.");
153 #endif
154     miDataCur = sc::celltextattr_block::begin(*miBlockCur->data);
155     miDataEnd = sc::celltextattr_block::end(*miBlockCur->data);
156 
157     std::advance(miDataCur, nOffsetInBlock);
158 }
159 
checkEndRow()160 void ScColumnTextWidthIterator::checkEndRow()
161 {
162     if (mnCurPos <= mnEnd)
163         // We're still good.
164         return;
165 
166     // We're below the end position. End the iteration.
167     miBlockCur = miBlockEnd;
168 }
169 
170 namespace sc {
171 
ColumnIterator(const CellStoreType & rCells,SCROW nRow1,SCROW nRow2)172 ColumnIterator::ColumnIterator( const CellStoreType& rCells, SCROW nRow1, SCROW nRow2 ) :
173     maPos(rCells.position(nRow1)),
174     maPosEnd(rCells.position(maPos.first, nRow2)),
175     mbComplete(false)
176 {
177 }
178 
~ColumnIterator()179 ColumnIterator::~ColumnIterator() {}
180 
next()181 void ColumnIterator::next()
182 {
183     if ( maPos == maPosEnd)
184         mbComplete = true;
185     else
186         maPos = CellStoreType::next_position(maPos);
187 }
188 
getRow() const189 SCROW ColumnIterator::getRow() const
190 {
191     return CellStoreType::logical_position(maPos);
192 }
193 
hasCell() const194 bool ColumnIterator::hasCell() const
195 {
196     return !mbComplete;
197 }
198 
getType() const199 mdds::mtv::element_t ColumnIterator::getType() const
200 {
201     return maPos.first->type;
202 }
203 
getCell() const204 ScRefCellValue ColumnIterator::getCell() const
205 {
206     return toRefCell(maPos.first, maPos.second);
207 }
208 
209 }
210 
211 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
212