~ubuntu-branches/ubuntu/precise/koffice/precise

« back to all changes in this revision

Viewing changes to kspread/commands/SortManipulator.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2010-09-21 15:36:35 UTC
  • mfrom: (1.4.1 upstream) (60.2.11 maverick)
  • Revision ID: james.westby@ubuntu.com-20100921153635-6tejqkiro2u21ydi
Tags: 1:2.2.2-0ubuntu3
Add kubuntu_03_fix-crash-on-closing-sqlite-connection-2.2.2.diff and
kubuntu_04_support-large-memo-values-for-msaccess-2.2.2.diff as
recommended by upstream http://kexi-
project.org/wiki/wikiview/index.php@Kexi2.2_Patches.html#sqlite_stab
ility

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
using namespace KSpread;
31
31
 
32
32
SortManipulator::SortManipulator()
33
 
    : AbstractDFManipulator()
34
 
    , m_cellStorage( 0 )
35
 
{
36
 
  m_changeformat = false;
37
 
  m_rows = true;
38
 
  m_skipfirst = false;
39
 
  m_cs = false;
40
 
  m_usecustomlist = false;
41
 
 
42
 
  setText( i18n("Sort Data") );
43
 
}
44
 
 
45
 
SortManipulator::~SortManipulator ()
46
 
{
47
 
}
48
 
 
49
 
bool SortManipulator::process (Element* element)
50
 
{
51
 
  // process one element - rectangular range
52
 
 
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
56
 
  // values
57
 
 
58
 
  // sort
59
 
  sort (element);
60
 
 
61
 
  // set values
62
 
  return AbstractDFManipulator::process (element);
 
33
        : AbstractDFManipulator()
 
34
        , m_cellStorage(0)
 
35
{
 
36
    m_changeformat = false;
 
37
    m_rows = true;
 
38
    m_skipfirst = false;
 
39
    m_cs = false;
 
40
    m_usecustomlist = false;
 
41
 
 
42
    setText(i18n("Sort Data"));
 
43
}
 
44
 
 
45
SortManipulator::~SortManipulator()
 
46
{
 
47
}
 
48
 
 
49
bool SortManipulator::process(Element* element)
 
50
{
 
51
    // process one element - rectangular range
 
52
 
 
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
 
56
    // values
 
57
 
 
58
    // sort
 
59
    sort(element);
 
60
 
 
61
    // set values
 
62
    return AbstractDFManipulator::process(element);
63
63
}
64
64
 
65
65
bool SortManipulator::preProcessing()
66
66
{
67
67
    // Only on sorting we need to temporarily store the old data.
68
68
    // On restoring (undo) we return immediately.
69
 
    if ( m_reverse )
 
69
    if (m_reverse)
70
70
        return AbstractDFManipulator::preProcessing();
71
71
 
72
 
    m_cellStorage = new CellStorage( m_sheet->cellStorage()->subStorage( *this ) );
 
72
    m_cellStorage = new CellStorage(m_sheet->cellStorage()->subStorage(*this));
73
73
 
74
74
    Region::Iterator endOfList(cells().end());
75
 
    for (Region::Iterator it = cells().begin(); it != endOfList; ++it)
76
 
    {
 
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)
80
 
            {
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());
83
81
            }
84
82
    }
85
83
 
97
95
    return AbstractDFManipulator::postProcessing();
98
96
}
99
97
 
100
 
void SortManipulator::addSortBy (int v, bool asc)
101
 
{
102
 
  m_sortby.push_back (v);
103
 
  m_sortorder.push_back (asc);
104
 
}
105
 
 
106
 
void SortManipulator::clearSortOrder ()
107
 
{
108
 
  m_sortby.clear ();
109
 
  m_sortorder.clear ();
110
 
}
111
 
 
112
 
Value SortManipulator::newValue (Element *element, int col, int row,
113
 
    bool *parse, Format::Type *)
114
 
{
115
 
  Q_UNUSED(parse);
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];
121
 
  else
122
 
    colidx = sorted[colidx];
123
 
 
124
 
  // have to return stored value, to avoid earlier calls disrupting latter ones
125
 
  return m_cellStorage->value( colidx + range.left(), rowidx + range.top() );
126
 
}
127
 
 
128
 
Style SortManipulator::newFormat (Element *element, int col, int row)
129
 
{
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)
 
99
{
 
100
    m_sortby.push_back(v);
 
101
    m_sortorder.push_back(asc);
 
102
}
 
103
 
 
104
void SortManipulator::clearSortOrder()
 
105
{
 
106
    m_sortby.clear();
 
107
    m_sortorder.clear();
 
108
}
 
109
 
 
110
Value SortManipulator::newValue(Element *element, int col, int row,
 
111
                                bool *parse, Format::Type *)
 
112
{
 
113
    Q_UNUSED(parse);
 
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];
136
119
    else
137
 
      colidx = sorted[colidx];
138
 
  }
139
 
 
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() ) );
142
 
}
143
 
 
144
 
void SortManipulator::sort (Element *element)
145
 
{
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
152
 
  sorted.clear ();
153
 
  for (int i = 0; i < count; ++i) sorted[i] = i;
154
 
 
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) {
158
 
    int lowest = i;
159
 
    for (int j = i+1; j < count; ++j)
160
 
      if (shouldReorder (element, sorted[lowest], sorted[j]))
161
 
        lowest = j;
162
 
    // move lowest to start
163
 
    int tmp = sorted[i];
164
 
    sorted[i] = sorted[lowest];
165
 
    sorted[lowest] = tmp;
166
 
  }
167
 
 
168
 
  // that's all - process will take care of the rest, together with our
169
 
  // newValue/newFormat
170
 
}
171
 
 
172
 
bool SortManipulator::shouldReorder (Element *element, int first, int second)
173
 
{
174
 
  // we use ValueCalc::natural* to compare
175
 
  // indexes are real indexes, we don't use the sorted array here
176
 
 
177
 
  ValueCalc *calc = m_sheet->map()->calc();
178
 
  ValueConverter *conv = m_sheet->map()->converter();
179
 
 
180
 
  QRect range = element->rect();
181
 
  int firstrow = range.top();
182
 
  int firstcol = range.left();
183
 
 
184
 
  QList<int>::iterator it = m_sortby.begin();
185
 
  QList<bool>::iterator it2 = m_sortorder.begin();
186
 
  for (; it != m_sortby.end(); ++it, ++it2) {
187
 
    int which = *it;
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())
199
 
      return false;
200
 
 
201
 
    // custom list ?
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;
207
 
      int pos = 0;
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))
212
 
          pos1 = pos;
213
 
        if ((pos2 == -1) && ((*it).toLower() == s2))
214
 
          pos2 = pos;
215
 
        pos++;
216
 
      }
217
 
      if ((pos1 >= 0) && (pos2 >= 0) && (pos1 != pos2))
218
 
        // both are in the list, not the same
219
 
        return (pos1 > pos2);
220
 
    }
221
 
 
222
 
    if (calc->naturalGreater (val1, val2, m_cs))
223
 
      // first one greater - must reorder if ascending, don't reorder if not
224
 
      return ascending;
225
 
    if (calc->naturalLower (val1, val2, m_cs))
226
 
      // first one lower - don't reorder if ascending, reorder if not
227
 
      return !ascending;
228
 
    // equal - don't know yet, continue
229
 
  }
230
 
 
231
 
  // no difference found, they're the same - no need to reorder
232
 
  return false;
 
120
        colidx = sorted[colidx];
 
121
 
 
122
    // have to return stored value, to avoid earlier calls disrupting latter ones
 
123
    return m_cellStorage->value(colidx + range.left(), rowidx + range.top());
 
124
}
 
125
 
 
126
Style SortManipulator::newFormat(Element *element, int col, int row)
 
127
{
 
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];
 
134
        else
 
135
            colidx = sorted[colidx];
 
136
    }
 
137
 
 
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()));
 
140
}
 
141
 
 
142
void SortManipulator::sort(Element *element)
 
143
{
 
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
 
150
    sorted.clear();
 
151
    for (int i = 0; i < count; ++i) sorted[i] = i;
 
152
 
 
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) {
 
156
        int lowest = i;
 
157
        for (int j = i + 1; j < count; ++j)
 
158
            if (shouldReorder(element, sorted[lowest], sorted[j]))
 
159
                lowest = j;
 
160
        // move lowest to start
 
161
        int tmp = sorted[i];
 
162
        sorted[i] = sorted[lowest];
 
163
        sorted[lowest] = tmp;
 
164
    }
 
165
 
 
166
    // that's all - process will take care of the rest, together with our
 
167
    // newValue/newFormat
 
168
}
 
169
 
 
170
bool SortManipulator::shouldReorder(Element *element, int first, int second)
 
171
{
 
172
    // we use ValueCalc::natural* to compare
 
173
    // indexes are real indexes, we don't use the sorted array here
 
174
 
 
175
    ValueCalc *calc = m_sheet->map()->calc();
 
176
    ValueConverter *conv = m_sheet->map()->converter();
 
177
 
 
178
    QRect range = element->rect();
 
179
    int firstrow = range.top();
 
180
    int firstcol = range.left();
 
181
 
 
182
    QList<int>::iterator it = m_sortby.begin();
 
183
    QList<bool>::iterator it2 = m_sortorder.begin();
 
184
    for (; it != m_sortby.end(); ++it, ++it2) {
 
185
        int which = *it;
 
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())
 
197
            return false;
 
198
 
 
199
        // custom list ?
 
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;
 
205
            int pos = 0;
 
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))
 
210
                    pos1 = pos;
 
211
                if ((pos2 == -1) && ((*it).toLower() == s2))
 
212
                    pos2 = pos;
 
213
                pos++;
 
214
            }
 
215
            if ((pos1 >= 0) && (pos2 >= 0) && (pos1 != pos2))
 
216
                // both are in the list, not the same
 
217
                return (pos1 > pos2);
 
218
        }
 
219
 
 
220
        if (calc->naturalGreater(val1, val2, m_cs))
 
221
            // first one greater - must reorder if ascending, don't reorder if not
 
222
            return ascending;
 
223
        if (calc->naturalLower(val1, val2, m_cs))
 
224
            // first one lower - don't reorder if ascending, reorder if not
 
225
            return !ascending;
 
226
        // equal - don't know yet, continue
 
227
    }
 
228
 
 
229
    // no difference found, they're the same - no need to reorder
 
230
    return false;
233
231
}