30
30
using namespace KSpread;
32
32
SortManipulator::SortManipulator()
33
: AbstractDFManipulator()
36
m_changeformat = false;
40
m_usecustomlist = false;
42
setText( i18n("Sort Data") );
45
SortManipulator::~SortManipulator ()
49
bool SortManipulator::process (Element* element)
51
// process one element - rectangular range
53
// here we perform the actual sorting, remember the new ordering and
54
// let AbstractDFManipulator::process do the rest of the work
55
// the new ordering is used in newValue and newFormat to return proper
62
return AbstractDFManipulator::process (element);
33
: AbstractDFManipulator()
36
m_changeformat = false;
40
m_usecustomlist = false;
42
setText(i18n("Sort Data"));
45
SortManipulator::~SortManipulator()
49
bool SortManipulator::process(Element* element)
51
// process one element - rectangular range
53
// here we perform the actual sorting, remember the new ordering and
54
// let AbstractDFManipulator::process do the rest of the work
55
// the new ordering is used in newValue and newFormat to return proper
62
return AbstractDFManipulator::process(element);
65
65
bool SortManipulator::preProcessing()
67
67
// Only on sorting we need to temporarily store the old data.
68
68
// On restoring (undo) we return immediately.
70
70
return AbstractDFManipulator::preProcessing();
72
m_cellStorage = new CellStorage( m_sheet->cellStorage()->subStorage( *this ) );
72
m_cellStorage = new CellStorage(m_sheet->cellStorage()->subStorage(*this));
74
74
Region::Iterator endOfList(cells().end());
75
for (Region::Iterator it = cells().begin(); it != endOfList; ++it)
75
for (Region::Iterator it = cells().begin(); it != endOfList; ++it) {
77
76
QRect range = (*it)->rect();
78
77
for (int col = range.left(); col <= range.right(); ++col)
79
for (int row = range.top(); row <= range.bottom(); ++row)
81
Cell cell = Cell( m_sheet, col, row );
82
m_styles.insert( cell, cell.style() );
78
for (int row = range.top(); row <= range.bottom(); ++row) {
79
Cell cell = Cell(m_sheet, col, row);
80
m_styles.insert(cell, cell.style());
97
95
return AbstractDFManipulator::postProcessing();
100
void SortManipulator::addSortBy (int v, bool asc)
102
m_sortby.push_back (v);
103
m_sortorder.push_back (asc);
106
void SortManipulator::clearSortOrder ()
109
m_sortorder.clear ();
112
Value SortManipulator::newValue (Element *element, int col, int row,
113
bool *parse, Format::Type *)
116
QRect range = element->rect();
117
int colidx = col - range.left();
118
int rowidx = row - range.top();
119
if (m_rows) // sort rows
120
rowidx = sorted[rowidx];
122
colidx = sorted[colidx];
124
// have to return stored value, to avoid earlier calls disrupting latter ones
125
return m_cellStorage->value( colidx + range.left(), rowidx + range.top() );
128
Style SortManipulator::newFormat (Element *element, int col, int row)
130
QRect range = element->rect();
131
int colidx = col - range.left();
132
int rowidx = row - range.top();
133
if (m_changeformat) {
98
void SortManipulator::addSortBy(int v, bool asc)
100
m_sortby.push_back(v);
101
m_sortorder.push_back(asc);
104
void SortManipulator::clearSortOrder()
110
Value SortManipulator::newValue(Element *element, int col, int row,
111
bool *parse, Format::Type *)
114
QRect range = element->rect();
115
int colidx = col - range.left();
116
int rowidx = row - range.top();
134
117
if (m_rows) // sort rows
135
rowidx = sorted[rowidx];
118
rowidx = sorted[rowidx];
137
colidx = sorted[colidx];
140
// have to return stored format, to avoid earlier calls disrupting latter ones
141
return m_styles.value( Cell( m_sheet, colidx + range.left(), rowidx + range.top() ) );
144
void SortManipulator::sort (Element *element)
146
// we'll use insert-sort to sort
147
QRect range = element->rect();
148
int max = m_rows ? range.bottom() : range.right();
149
int min = m_rows ? range.top() : range.left();
150
int count = max - min + 1;
151
// initially, all values are at their original positions
153
for (int i = 0; i < count; ++i) sorted[i] = i;
155
// for each position, find the lowest value and move it there
156
int start = m_skipfirst ? 1 : 0;
157
for (int i = start; i < count - 1; ++i) {
159
for (int j = i+1; j < count; ++j)
160
if (shouldReorder (element, sorted[lowest], sorted[j]))
162
// move lowest to start
164
sorted[i] = sorted[lowest];
165
sorted[lowest] = tmp;
168
// that's all - process will take care of the rest, together with our
169
// newValue/newFormat
172
bool SortManipulator::shouldReorder (Element *element, int first, int second)
174
// we use ValueCalc::natural* to compare
175
// indexes are real indexes, we don't use the sorted array here
177
ValueCalc *calc = m_sheet->map()->calc();
178
ValueConverter *conv = m_sheet->map()->converter();
180
QRect range = element->rect();
181
int firstrow = range.top();
182
int firstcol = range.left();
184
QList<int>::iterator it = m_sortby.begin();
185
QList<bool>::iterator it2 = m_sortorder.begin();
186
for (; it != m_sortby.end(); ++it, ++it2) {
188
int ascending = *it2;
189
// figure out coordinates of the cells
190
int row1 = firstrow + (m_rows ? first : which);
191
int row2 = firstrow + (m_rows ? second : which);
192
int col1 = firstcol + (m_rows ? which : first);
193
int col2 = firstcol + (m_rows ? which : second);
194
Value val1 = Cell( m_sheet, col1, row1 ).value();
195
Value val2 = Cell( m_sheet, col2, row2 ).value();
196
// empty values always go to the end, so if second value is empty and
197
// first one is not, we don't need to reorder
198
if ((!val1.isEmpty()) && val2.isEmpty())
202
if (m_usecustomlist) {
203
QString s1 = conv->asString (val1).asString().toLower();
204
QString s2 = conv->asString (val2).asString().toLower();
205
QStringList::iterator it;
206
int pos1 = -1, pos2 = -1;
208
// Try to locate our two strings in the list. If both are there, assume
209
// ordering as specified by the list.
210
for (it = m_customlist.begin(); it != m_customlist.end(); ++it) {
211
if ((pos1 == -1) && ((*it).toLower() == s1))
213
if ((pos2 == -1) && ((*it).toLower() == s2))
217
if ((pos1 >= 0) && (pos2 >= 0) && (pos1 != pos2))
218
// both are in the list, not the same
219
return (pos1 > pos2);
222
if (calc->naturalGreater (val1, val2, m_cs))
223
// first one greater - must reorder if ascending, don't reorder if not
225
if (calc->naturalLower (val1, val2, m_cs))
226
// first one lower - don't reorder if ascending, reorder if not
228
// equal - don't know yet, continue
231
// no difference found, they're the same - no need to reorder
120
colidx = sorted[colidx];
122
// have to return stored value, to avoid earlier calls disrupting latter ones
123
return m_cellStorage->value(colidx + range.left(), rowidx + range.top());
126
Style SortManipulator::newFormat(Element *element, int col, int row)
128
QRect range = element->rect();
129
int colidx = col - range.left();
130
int rowidx = row - range.top();
131
if (m_changeformat) {
132
if (m_rows) // sort rows
133
rowidx = sorted[rowidx];
135
colidx = sorted[colidx];
138
// have to return stored format, to avoid earlier calls disrupting latter ones
139
return m_styles.value(Cell(m_sheet, colidx + range.left(), rowidx + range.top()));
142
void SortManipulator::sort(Element *element)
144
// we'll use insert-sort to sort
145
QRect range = element->rect();
146
int max = m_rows ? range.bottom() : range.right();
147
int min = m_rows ? range.top() : range.left();
148
int count = max - min + 1;
149
// initially, all values are at their original positions
151
for (int i = 0; i < count; ++i) sorted[i] = i;
153
// for each position, find the lowest value and move it there
154
int start = m_skipfirst ? 1 : 0;
155
for (int i = start; i < count - 1; ++i) {
157
for (int j = i + 1; j < count; ++j)
158
if (shouldReorder(element, sorted[lowest], sorted[j]))
160
// move lowest to start
162
sorted[i] = sorted[lowest];
163
sorted[lowest] = tmp;
166
// that's all - process will take care of the rest, together with our
167
// newValue/newFormat
170
bool SortManipulator::shouldReorder(Element *element, int first, int second)
172
// we use ValueCalc::natural* to compare
173
// indexes are real indexes, we don't use the sorted array here
175
ValueCalc *calc = m_sheet->map()->calc();
176
ValueConverter *conv = m_sheet->map()->converter();
178
QRect range = element->rect();
179
int firstrow = range.top();
180
int firstcol = range.left();
182
QList<int>::iterator it = m_sortby.begin();
183
QList<bool>::iterator it2 = m_sortorder.begin();
184
for (; it != m_sortby.end(); ++it, ++it2) {
186
int ascending = *it2;
187
// figure out coordinates of the cells
188
int row1 = firstrow + (m_rows ? first : which);
189
int row2 = firstrow + (m_rows ? second : which);
190
int col1 = firstcol + (m_rows ? which : first);
191
int col2 = firstcol + (m_rows ? which : second);
192
Value val1 = Cell(m_sheet, col1, row1).value();
193
Value val2 = Cell(m_sheet, col2, row2).value();
194
// empty values always go to the end, so if second value is empty and
195
// first one is not, we don't need to reorder
196
if ((!val1.isEmpty()) && val2.isEmpty())
200
if (m_usecustomlist) {
201
QString s1 = conv->asString(val1).asString().toLower();
202
QString s2 = conv->asString(val2).asString().toLower();
203
QStringList::iterator it;
204
int pos1 = -1, pos2 = -1;
206
// Try to locate our two strings in the list. If both are there, assume
207
// ordering as specified by the list.
208
for (it = m_customlist.begin(); it != m_customlist.end(); ++it) {
209
if ((pos1 == -1) && ((*it).toLower() == s1))
211
if ((pos2 == -1) && ((*it).toLower() == s2))
215
if ((pos1 >= 0) && (pos2 >= 0) && (pos1 != pos2))
216
// both are in the list, not the same
217
return (pos1 > pos2);
220
if (calc->naturalGreater(val1, val2, m_cs))
221
// first one greater - must reorder if ascending, don't reorder if not
223
if (calc->naturalLower(val1, val2, m_cs))
224
// first one lower - don't reorder if ascending, reorder if not
226
// equal - don't know yet, continue
229
// no difference found, they're the same - no need to reorder