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

« back to all changes in this revision

Viewing changes to kspread/Util.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:
41
41
 
42
42
//used in Cell::encodeFormula and
43
43
//  dialogs/kspread_dlg_paperlayout.cc
44
 
int KSpread::Util::decodeColumnLabelText( const QString &_col )
 
44
int KSpread::Util::decodeColumnLabelText(const QString &labelText)
45
45
{
46
46
    int col = 0;
47
 
    int offset='a'-'A';
 
47
    const int offset = 'a' -'A';
48
48
    int counterColumn = 0;
49
 
    for ( int i=0; i < _col.length(); i++ )
50
 
    {
51
 
        counterColumn = (int) ::pow(26.0 , static_cast<int>(_col.length() - i - 1));
52
 
        if( _col[i] >= 'A' && _col[i] <= 'Z' )
53
 
            col += counterColumn * ( _col[i].toLatin1() - 'A' + 1);  // okay here (Werner)
54
 
        else if( _col[i] >= 'a' && _col[i] <= 'z' )
55
 
            col += counterColumn * ( _col[i].toLatin1() - 'A' - offset + 1 );
 
49
    const uint totalLength = labelText.length();
 
50
    uint labelTextLength;
 
51
    for (labelTextLength = 0; labelTextLength < totalLength; labelTextLength++) {
 
52
        const char c = labelText[labelTextLength].toLatin1();
 
53
        if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')))
 
54
            break;
 
55
    }
 
56
    if (labelTextLength == 0) {
 
57
        kWarning(36001) << "No column label text found for col:" << labelText;
 
58
        return 0;
 
59
    }
 
60
    for (uint i = 0; i < labelTextLength; i++) {
 
61
        const char c = labelText[i].toLatin1();
 
62
        counterColumn = (int) ::pow(26.0 , static_cast<int>(labelTextLength - i - 1));
 
63
        if (c >= 'A' && c <= 'Z')
 
64
            col += counterColumn * (c - 'A' + 1);  // okay here (Werner)
 
65
        else if (c >= 'a' && c <= 'z')
 
66
            col += counterColumn * (c - 'A' - offset + 1);
 
67
    }
 
68
    return col;
 
69
}
 
70
 
 
71
int KSpread::Util::decodeRowLabelText(const QString &labelText)
 
72
{
 
73
    QRegExp rx("([A-Za-z]+)([0-9]+)");
 
74
    if(rx.exactMatch(labelText))
 
75
        return rx.cap(2).toInt();
 
76
    return 0;
 
77
}
 
78
 
 
79
QString KSpread::Util::encodeColumnLabelText(int column)
 
80
{
 
81
    return Cell::columnName(column);
 
82
}
 
83
 
 
84
QDomElement KSpread::NativeFormat::createElement(const QString & tagName, const QFont & font, QDomDocument & doc)
 
85
{
 
86
    QDomElement e(doc.createElement(tagName));
 
87
 
 
88
    e.setAttribute("family", font.family());
 
89
    e.setAttribute("size", font.pointSize());
 
90
    e.setAttribute("weight", font.weight());
 
91
    if (font.bold())
 
92
        e.setAttribute("bold", "yes");
 
93
    if (font.italic())
 
94
        e.setAttribute("italic", "yes");
 
95
    if (font.underline())
 
96
        e.setAttribute("underline", "yes");
 
97
    if (font.strikeOut())
 
98
        e.setAttribute("strikeout", "yes");
 
99
    //e.setAttribute( "charset", KGlobal::charsets()->name( font ) );
 
100
 
 
101
    return e;
 
102
}
 
103
 
 
104
QDomElement KSpread::NativeFormat::createElement(const QString & tagname, const QPen & pen, QDomDocument & doc)
 
105
{
 
106
    QDomElement e(doc.createElement(tagname));
 
107
    e.setAttribute("color", pen.color().name());
 
108
    e.setAttribute("style", (int)pen.style());
 
109
    e.setAttribute("width", (int)pen.width());
 
110
    return e;
 
111
}
 
112
 
 
113
QFont KSpread::NativeFormat::toFont(KoXmlElement & element)
 
114
{
 
115
    bool ok;
 
116
    int size = element.attribute("size").toInt(&ok);
 
117
    if (!ok)
 
118
        return QFont();
 
119
 
 
120
    QFont f;
 
121
    f.setFamily(element.attribute("family"));
 
122
    if (size > 0)
 
123
        f.setPointSize(size);
 
124
 
 
125
    f.setWeight(element.attribute("weight").toInt(&ok));
 
126
    if (!ok)
 
127
        return QFont();
 
128
 
 
129
    if (element.hasAttribute("italic") && element.attribute("italic") == "yes")
 
130
        f.setItalic(true);
 
131
 
 
132
    if (element.hasAttribute("bold") && element.attribute("bold") == "yes")
 
133
        f.setBold(true);
 
134
 
 
135
    if (element.hasAttribute("underline") && element.attribute("underline") == "yes")
 
136
        f.setUnderline(true);
 
137
 
 
138
    if (element.hasAttribute("strikeout") && element.attribute("strikeout") == "yes")
 
139
        f.setStrikeOut(true);
 
140
 
 
141
    /* Uncomment when charset is added to kspread_dlg_layout
 
142
       + save a document-global charset
 
143
       if ( element.hasAttribute( "charset" ) )
 
144
         KGlobal::charsets()->setQFont( f, element.attribute("charset") );
56
145
        else
57
 
            kDebug(36001) <<"Util::decodeColumnLabelText: Wrong characters in label text for col:'" << _col << '\'';
58
 
    }
59
 
    return col;
60
 
}
61
 
 
62
 
QDomElement KSpread::NativeFormat::createElement( const QString & tagName, const QFont & font, QDomDocument & doc )
63
 
{
64
 
  QDomElement e( doc.createElement( tagName ) );
65
 
 
66
 
  e.setAttribute( "family", font.family() );
67
 
  e.setAttribute( "size", font.pointSize() );
68
 
  e.setAttribute( "weight", font.weight() );
69
 
  if ( font.bold() )
70
 
    e.setAttribute( "bold", "yes" );
71
 
  if ( font.italic() )
72
 
    e.setAttribute( "italic", "yes" );
73
 
  if ( font.underline() )
74
 
    e.setAttribute( "underline", "yes" );
75
 
  if ( font.strikeOut() )
76
 
    e.setAttribute( "strikeout", "yes" );
77
 
  //e.setAttribute( "charset", KGlobal::charsets()->name( font ) );
78
 
 
79
 
  return e;
80
 
}
81
 
 
82
 
QDomElement KSpread::NativeFormat::createElement( const QString & tagname, const QPen & pen, QDomDocument & doc )
83
 
{
84
 
  QDomElement e( doc.createElement( tagname ) );
85
 
  e.setAttribute( "color", pen.color().name() );
86
 
  e.setAttribute( "style", (int)pen.style() );
87
 
  e.setAttribute( "width", (int)pen.width() );
88
 
  return e;
89
 
}
90
 
 
91
 
QFont KSpread::NativeFormat::toFont( KoXmlElement & element )
92
 
{
93
 
  bool ok;
94
 
  int size = element.attribute("size").toInt( &ok );
95
 
  if ( !ok )
96
 
    return QFont();
97
 
 
98
 
  QFont f;
99
 
  f.setFamily( element.attribute( "family" ) );
100
 
  if (size > 0)
101
 
    f.setPointSize( size );
102
 
 
103
 
  f.setWeight( element.attribute("weight").toInt( &ok ) );
104
 
  if ( !ok )
105
 
    return QFont();
106
 
 
107
 
  if ( element.hasAttribute( "italic" ) && element.attribute("italic") == "yes" )
108
 
    f.setItalic( true );
109
 
 
110
 
  if ( element.hasAttribute( "bold" ) && element.attribute("bold") == "yes" )
111
 
    f.setBold( true );
112
 
 
113
 
  if ( element.hasAttribute( "underline" ) && element.attribute("underline") == "yes" )
114
 
    f.setUnderline( true );
115
 
 
116
 
  if ( element.hasAttribute( "strikeout" ) && element.attribute("strikeout") == "yes" )
117
 
    f.setStrikeOut( true );
118
 
 
119
 
  /* Uncomment when charset is added to kspread_dlg_layout
120
 
     + save a document-global charset
121
 
     if ( element.hasAttribute( "charset" ) )
122
 
       KGlobal::charsets()->setQFont( f, element.attribute("charset") );
123
 
      else
124
 
  */
125
 
  // ######## Not needed anymore in 3.0?
126
 
  //KGlobal::charsets()->setQFont( f, KGlobal::locale()->charset() );
127
 
 
128
 
  return f;
129
 
}
130
 
 
131
 
QPen KSpread::NativeFormat::toPen( KoXmlElement & element )
132
 
{
133
 
  bool ok;
134
 
  QPen p;
135
 
 
136
 
  p.setStyle( (Qt::PenStyle)element.attribute("style").toInt( &ok ) );
137
 
  if ( !ok )
138
 
    return QPen();
139
 
 
140
 
  p.setWidth( element.attribute("width").toInt( &ok ) );
141
 
  if ( !ok )
142
 
    return QPen();
143
 
 
144
 
  p.setColor( QColor( element.attribute("color") ) );
145
 
 
146
 
  return p;
147
 
}
148
 
 
149
 
bool util_isPointValid( const QPoint& point )
150
 
{
151
 
    if (    point.x() >= 0
152
 
        &&  point.y() >= 0
153
 
        &&  point.x() <= KS_colMax
154
 
        &&  point.y() <= KS_rowMax
 
146
    */
 
147
    // ######## Not needed anymore in 3.0?
 
148
    //KGlobal::charsets()->setQFont( f, KGlobal::locale()->charset() );
 
149
 
 
150
    return f;
 
151
}
 
152
 
 
153
QPen KSpread::NativeFormat::toPen(KoXmlElement & element)
 
154
{
 
155
    bool ok;
 
156
    QPen p;
 
157
 
 
158
    p.setStyle((Qt::PenStyle)element.attribute("style").toInt(&ok));
 
159
    if (!ok)
 
160
        return QPen();
 
161
 
 
162
    p.setWidth(element.attribute("width").toInt(&ok));
 
163
    if (!ok)
 
164
        return QPen();
 
165
 
 
166
    p.setColor(QColor(element.attribute("color")));
 
167
 
 
168
    return p;
 
169
}
 
170
 
 
171
bool util_isPointValid(const QPoint& point)
 
172
{
 
173
    if (point.x() >= 0
 
174
            &&  point.y() >= 0
 
175
            &&  point.x() <= KS_colMax
 
176
            &&  point.y() <= KS_rowMax
155
177
       )
156
178
        return true;
157
179
    else
158
180
        return false;
159
181
}
160
182
 
161
 
bool util_isRectValid( const QRect& rect )
 
183
bool util_isRectValid(const QRect& rect)
162
184
{
163
 
    if (    util_isPointValid( rect.topLeft() )
164
 
        &&  util_isPointValid( rect.bottomRight() )
 
185
    if (util_isPointValid(rect.topLeft())
 
186
            &&  util_isPointValid(rect.bottomRight())
165
187
       )
166
188
        return true;
167
189
    else
170
192
 
171
193
 
172
194
//not used anywhere
173
 
int KSpread::Util::penCompare( QPen const & pen1, QPen const & pen2 )
 
195
int KSpread::Util::penCompare(QPen const & pen1, QPen const & pen2)
174
196
{
175
 
  if ( pen1.style() == Qt::NoPen && pen2.style() == Qt::NoPen )
 
197
    if (pen1.style() == Qt::NoPen && pen2.style() == Qt::NoPen)
 
198
        return 0;
 
199
 
 
200
    if (pen1.style() == Qt::NoPen)
 
201
        return -1;
 
202
 
 
203
    if (pen2.style() == Qt::NoPen)
 
204
        return 1;
 
205
 
 
206
    if (pen1.width() < pen2.width())
 
207
        return -1;
 
208
 
 
209
    if (pen1.width() > pen2.width())
 
210
        return 1;
 
211
 
 
212
    if (pen1.style() < pen2.style())
 
213
        return -1;
 
214
 
 
215
    if (pen1.style() > pen2.style())
 
216
        return 1;
 
217
 
 
218
    if (pen1.color().name() < pen2.color().name())
 
219
        return -1;
 
220
 
 
221
    if (pen1.color().name() > pen2.color().name())
 
222
        return 1;
 
223
 
176
224
    return 0;
177
 
 
178
 
  if ( pen1.style() == Qt::NoPen )
179
 
    return -1;
180
 
 
181
 
  if ( pen2.style() == Qt::NoPen )
182
 
    return 1;
183
 
 
184
 
  if ( pen1.width() < pen2.width() )
185
 
    return -1;
186
 
 
187
 
  if ( pen1.width() > pen2.width() )
188
 
    return 1;
189
 
 
190
 
  if ( pen1.style() < pen2.style() )
191
 
    return -1;
192
 
 
193
 
  if ( pen1.style() > pen2.style() )
194
 
    return 1;
195
 
 
196
 
  if ( pen1.color().name() < pen2.color().name() )
197
 
    return -1;
198
 
 
199
 
  if ( pen1.color().name() > pen2.color().name() )
200
 
    return 1;
201
 
 
202
 
  return 0;
203
 
}
204
 
 
205
 
 
206
 
QString KSpread::Odf::convertRefToBase( const QString & sheet, const QRect & rect )
207
 
{
208
 
  QPoint bottomRight( rect.bottomRight() );
209
 
 
210
 
  QString s( '$' );
211
 
  s += sheet;
212
 
  s += ".$";
213
 
  s += Cell::columnName( bottomRight.x() );
214
 
  s += '$';
215
 
  s += QString::number( bottomRight.y() );
216
 
 
217
 
  return s;
218
 
}
219
 
 
220
 
QString KSpread::Odf::convertRefToRange( const QString & sheet, const QRect & rect )
221
 
{
222
 
  QPoint topLeft( rect.topLeft() );
223
 
  QPoint bottomRight( rect.bottomRight() );
224
 
 
225
 
  if ( topLeft == bottomRight )
226
 
    return Odf::convertRefToBase( sheet, rect );
227
 
 
228
 
  QString s( '$' );
229
 
  s += sheet;
230
 
  s += ".$";
231
 
  s += /*Util::encodeColumnLabelText*/Cell::columnName( topLeft.x() );
232
 
  s += '$';
233
 
  s += QString::number( topLeft.y() );
234
 
  s += ":.$";
235
 
  s += /*Util::encodeColumnLabelText*/Cell::columnName( bottomRight.x() );
236
 
  s += '$';
237
 
  s += QString::number( bottomRight.y() );
238
 
 
239
 
  return s;
240
 
}
241
 
 
242
 
 // e.g.: Sheet4.A1:Sheet4.E28
243
 
 //used in Sheet::saveOdf
244
 
QString KSpread::Odf::convertRangeToRef( const QString & sheetName, const QRect & _area )
245
 
{
246
 
    return sheetName + '.' + Cell::name( _area.left(), _area.top() ) + ':' + sheetName + '.'+ Cell::name( _area.right(), _area.bottom() );
247
 
}
248
 
 
249
 
QString KSpread::Odf::encodePen( const QPen & pen )
 
225
}
 
226
 
 
227
 
 
228
QString KSpread::Odf::convertRefToBase(const QString & sheet, const QRect & rect)
 
229
{
 
230
    QPoint bottomRight(rect.bottomRight());
 
231
 
 
232
    QString s('$');
 
233
    s += sheet;
 
234
    s += ".$";
 
235
    s += Cell::columnName(bottomRight.x());
 
236
    s += '$';
 
237
    s += QString::number(bottomRight.y());
 
238
 
 
239
    return s;
 
240
}
 
241
 
 
242
QString KSpread::Odf::convertRefToRange(const QString & sheet, const QRect & rect)
 
243
{
 
244
    QPoint topLeft(rect.topLeft());
 
245
    QPoint bottomRight(rect.bottomRight());
 
246
 
 
247
    if (topLeft == bottomRight)
 
248
        return Odf::convertRefToBase(sheet, rect);
 
249
 
 
250
    QString s('$');
 
251
    s += sheet;
 
252
    s += ".$";
 
253
    s += /*Util::encodeColumnLabelText*/Cell::columnName(topLeft.x());
 
254
    s += '$';
 
255
    s += QString::number(topLeft.y());
 
256
    s += ":.$";
 
257
    s += /*Util::encodeColumnLabelText*/Cell::columnName(bottomRight.x());
 
258
    s += '$';
 
259
    s += QString::number(bottomRight.y());
 
260
 
 
261
    return s;
 
262
}
 
263
 
 
264
// e.g.: Sheet4.A1:Sheet4.E28
 
265
//used in Sheet::saveOdf
 
266
QString KSpread::Odf::convertRangeToRef(const QString & sheetName, const QRect & _area)
 
267
{
 
268
    return sheetName + '.' + Cell::name(_area.left(), _area.top()) + ':' + sheetName + '.' + Cell::name(_area.right(), _area.bottom());
 
269
}
 
270
 
 
271
QString KSpread::Odf::encodePen(const QPen & pen)
250
272
{
251
273
//     kDebug()<<"encodePen( const QPen & pen ) :"<<pen;
252
274
    // NOTE Stefan: QPen api docs:
253
275
    //              A line width of zero indicates a cosmetic pen. This means
254
276
    //              that the pen width is always drawn one pixel wide,
255
277
    //              independent of the transformation set on the painter.
256
 
    QString s = QString( "%1pt " ).arg( (pen.width() == 0) ? 1 : pen.width() );
257
 
    switch( pen.style() )
258
 
    {
 
278
    QString s = QString("%1pt ").arg((pen.width() == 0) ? 1 : pen.width());
 
279
    switch (pen.style()) {
259
280
    case Qt::NoPen:
260
281
        return "none";
261
282
    case Qt::SolidLine:
262
 
        s+="solid";
 
283
        s += "solid";
263
284
        break;
264
285
    case Qt::DashLine:
265
 
        s+="dashed";
 
286
        s += "dashed";
266
287
        break;
267
288
    case Qt::DotLine:
268
 
        s+="dotted";
 
289
        s += "dotted";
269
290
        break;
270
291
    case Qt::DashDotLine:
271
 
        s+="dot-dash";
 
292
        s += "dot-dash";
272
293
        break;
273
294
    case Qt::DashDotDotLine:
274
 
        s+="dot-dot-dash";
 
295
        s += "dot-dot-dash";
275
296
        break;
276
297
    default: break;
277
298
    }
278
 
    kDebug()<<" encodePen :"<<s;
279
 
    if ( pen.color().isValid() )
280
 
    {
281
 
        s+=' ';
282
 
        s+=Style::colorName(pen.color());
 
299
    kDebug() << " encodePen :" << s;
 
300
    if (pen.color().isValid()) {
 
301
        s += ' ';
 
302
        s += Style::colorName(pen.color());
283
303
    }
284
304
    return s;
285
305
}
286
306
 
287
 
QPen KSpread::Odf::decodePen( const QString &border )
 
307
QPen KSpread::Odf::decodePen(const QString &border)
288
308
{
289
309
    QPen pen;
290
310
    //string like "0.088cm solid #800000"
291
 
    if (border.isEmpty() || border=="none" || border=="hidden") // in fact no border
292
 
    {
293
 
        pen.setStyle( Qt::NoPen );
 
311
    if (border.isEmpty() || border == "none" || border == "hidden") { // in fact no border
 
312
        pen.setStyle(Qt::NoPen);
294
313
        return pen;
295
314
    }
296
315
    //code from koborder, for the moment kspread doesn't use koborder
299
318
    QByteArray _style = border.section(' ', 1, 1).toLatin1();
300
319
    QString _color = border.section(' ', 2, 2);
301
320
 
302
 
    pen.setWidth( ( int )( KoUnit::parseValue( _width, 1.0 ) ) );
303
 
 
304
 
    if ( _style =="none" )
305
 
        pen.setStyle( Qt::NoPen );
306
 
    else if ( _style =="solid" )
307
 
        pen.setStyle( Qt::SolidLine );
308
 
    else if ( _style =="dashed" )
309
 
        pen.setStyle( Qt::DashLine );
310
 
    else if ( _style =="dotted" )
311
 
        pen.setStyle( Qt::DotLine );
312
 
    else if ( _style =="dot-dash" )
313
 
        pen.setStyle( Qt::DashDotLine );
314
 
    else if ( _style =="dot-dot-dash" )
315
 
        pen.setStyle( Qt::DashDotDotLine );
316
 
    else
317
 
        kDebug()<<" style undefined :"<<_style;
318
 
 
319
 
    if ( _color.isEmpty() )
320
 
        pen.setColor( QColor() );
321
 
    else
322
 
        pen.setColor(  QColor( _color ) );
 
321
    pen.setWidth((int)(KoUnit::parseValue(_width, 1.0)));
 
322
 
 
323
    if (_style == "none")
 
324
        pen.setStyle(Qt::NoPen);
 
325
    else if (_style == "solid")
 
326
        pen.setStyle(Qt::SolidLine);
 
327
    else if (_style == "dashed")
 
328
        pen.setStyle(Qt::DashLine);
 
329
    else if (_style == "dotted")
 
330
        pen.setStyle(Qt::DotLine);
 
331
    else if (_style == "dot-dash")
 
332
        pen.setStyle(Qt::DashDotLine);
 
333
    else if (_style == "dot-dot-dash")
 
334
        pen.setStyle(Qt::DashDotDotLine);
 
335
    else
 
336
        kDebug() << " style undefined :" << _style;
 
337
 
 
338
    if (_color.isEmpty())
 
339
        pen.setColor(QColor());
 
340
    else
 
341
        pen.setColor(QColor(_color));
323
342
 
324
343
    return pen;
325
344
}
326
345
 
327
346
//Return true when it's a reference to cell from sheet.
328
 
bool KSpread::Util::localReferenceAnchor( const QString &_ref )
 
347
bool KSpread::Util::localReferenceAnchor(const QString &_ref)
329
348
{
330
349
    bool isLocalRef = (_ref.indexOf("http://") != 0 &&
331
350
                       _ref.indexOf("https://") != 0 &&
332
351
                       _ref.indexOf("mailto:") != 0 &&
333
352
                       _ref.indexOf("ftp://") != 0  &&
334
 
                       _ref.indexOf("file:") != 0 );
 
353
                       _ref.indexOf("file:") != 0);
335
354
    return isLocalRef;
336
355
}
337
356
 
338
357
 
339
 
QString KSpread::Odf::decodeFormula(const QString& expression, const KLocale* locale)
 
358
QString KSpread::Odf::decodeFormula(const QString& expression, const KLocale* locale, QString namespacePrefix)
340
359
{
341
360
    // parsing state
342
361
    enum { Start, InNumber, InString, InIdentifier, InReference, InSheetName } state = Start;
348
367
    QString reference;
349
368
 
350
369
    int i = 0;
351
 
    if ((!expression.isEmpty()) && (expression[0] == '='))
352
 
    {
353
 
        result='=';
 
370
    if ((!expression.isEmpty()) && (expression[0] == '=')) {
 
371
        result = '=';
354
372
        ++i;
355
373
    }
356
374
 
357
375
    // main loop
358
 
    while ( i < expression.length() )
359
 
    {
360
 
        switch ( state )
361
 
        {
362
 
            case Start:
363
 
            {
364
 
                // check for number
365
 
                if ( expression[i].isDigit() )
366
 
                    state = InNumber;
367
 
 
368
 
                // a string?
369
 
                else if ( expression[i] == '"' )
370
 
                {
371
 
                    state = InString;
372
 
                    result.append( expression[i++] );
 
376
    while (i < expression.length()) {
 
377
        switch (state) {
 
378
        case Start: {
 
379
            // check for number
 
380
            if (expression[i].isDigit())
 
381
                state = InNumber;
 
382
 
 
383
            // a string?
 
384
            else if (expression[i] == '"') {
 
385
                state = InString;
 
386
                result.append(expression[i++]);
 
387
            }
 
388
 
 
389
            // decimal dot ?
 
390
            else if (expression[i] == '.')
 
391
                state = InNumber;
 
392
 
 
393
            // beginning with alphanumeric ?
 
394
            // could be identifier, cell, range, or function...
 
395
            else if (isIdentifier(expression[i]))
 
396
                state = InIdentifier;
 
397
 
 
398
            // [ marks sheet name for 3-d cell, e.g ['Sales Q3'.A4]
 
399
            else if (expression[i].unicode() == '[') {
 
400
                ++i;
 
401
                state = InReference;
 
402
                // NOTE Stefan: As long as KSpread does not support fixed sheets eat the dollar sign.
 
403
                if (expression[i] == '$') ++i;
 
404
            }
 
405
 
 
406
            // look for operator match
 
407
            else {
 
408
                int op;
 
409
                QString s;
 
410
 
 
411
                // check for two-chars operator, such as '<=', '>=', etc
 
412
                s.append(expression[i]);
 
413
                if (i + 1 < expression.length())
 
414
                    s.append(expression[i+1]);
 
415
                op = matchOperator(s);
 
416
 
 
417
                // check for one-char operator, such as '+', ';', etc
 
418
                if (op == Token::InvalidOp) {
 
419
                    s = QString(expression[i]);
 
420
                    op = matchOperator(s);
373
421
                }
374
422
 
375
 
                // beginning with alphanumeric ?
376
 
                // could be identifier, cell, range, or function...
377
 
                else if ( isIdentifier( expression[i] ) )
378
 
                    state = InIdentifier;
379
 
 
380
 
                // [ marks sheet name for 3-d cell, e.g ['Sales Q3'.A4]
381
 
                else if ( expression[i].unicode() == '[' )
382
 
                {
 
423
                // any matched operator ?
 
424
                if (op == Token::Equal)
 
425
                    result.append("==");
 
426
                else
 
427
                    result.append(s);
 
428
                if (op != Token::InvalidOp) {
 
429
                    int len = s.length();
 
430
                    i += len;
 
431
                } else {
383
432
                    ++i;
 
433
                    state = Start;
 
434
                }
 
435
            }
 
436
            break;
 
437
        }
 
438
        case InReference: {
 
439
            if (expression[i] == ']') {
 
440
                result.append(Region::loadOdf(reference));
 
441
                reference.clear();
 
442
                state = Start;
 
443
            } else if (expression[i] == '\'') {
 
444
                reference.append('\'');
 
445
                state = InSheetName;
 
446
            } else
 
447
                reference.append(expression[i]);
 
448
            ++i;
 
449
            break;
 
450
        }
 
451
        case InSheetName: {
 
452
            reference.append(expression[i]);
 
453
            if (expression[i] == '\'') {
 
454
                // an escaped apostrophe?
 
455
                if (i + 1 < expression.count() && expression[i+1] == '\'')
 
456
                    ++i; // eat it
 
457
                else // the end
384
458
                    state = InReference;
385
 
                    // NOTE Stefan: As long as KSpread does not support fixed sheets eat the dollar sign.
386
 
                    if ( expression[i] == '$' ) ++i;
387
 
                }
388
 
 
389
 
                // decimal dot ?
390
 
                else if ( expression[i] == '.' )
391
 
                    state = InNumber;
392
 
 
393
 
                // look for operator match
394
 
                else
395
 
                {
396
 
                    int op;
397
 
                    QString s;
398
 
 
399
 
                    // check for two-chars operator, such as '<=', '>=', etc
400
 
                    s.append( expression[i] );
401
 
                    if (i+1 < expression.length())
402
 
                        s.append( expression[i+1] );
403
 
                    op = matchOperator( s );
404
 
 
405
 
                    // check for one-char operator, such as '+', ';', etc
406
 
                    if ( op == Token::InvalidOp )
407
 
                    {
408
 
                        s = QString( expression[i] );
409
 
                        op = matchOperator( s );
410
 
                    }
411
 
 
412
 
                    // any matched operator ?
413
 
                    if (  op == Token::Equal )
414
 
                        result.append( "==" );
415
 
                    else
416
 
                        result.append( s );
417
 
                    if ( op != Token::InvalidOp )
418
 
                    {
419
 
                        int len = s.length();
420
 
                        i += len;
421
 
                    }
422
 
                    else
423
 
                    {
424
 
                        ++i;
425
 
                        state = Start;
426
 
                    }
427
 
                }
428
 
                break;
429
 
            }
430
 
            case InReference:
431
 
            {
432
 
                if (expression[i] == ']')
433
 
                {
434
 
                    result.append(Region::loadOdf(reference));
435
 
                    reference.clear();
436
 
                    state = Start;
437
 
                }
438
 
                else if (expression[i] == '\'')
439
 
                {
440
 
                    reference.append('\'');
441
 
                    state = InSheetName;
442
 
                }
443
 
                else
444
 
                    reference.append(expression[i]);
445
 
                ++i;
446
 
                break;
447
 
            }
448
 
            case InSheetName:
449
 
            {
450
 
                reference.append(expression[i]);
451
 
                if (expression[i] == '\'')
452
 
                {
453
 
                    // an escaped apostrophe?
454
 
                    if (i+1 < expression.count() && expression[i+1] == '\'')
455
 
                        ++i; // eat it
456
 
                    else // the end
457
 
                        state = InReference;
458
 
                }
459
 
                ++i;
460
 
                break;
461
 
            }
462
 
            case InNumber:
463
 
            {
464
 
                // consume as long as it's digit
465
 
                if ( expression[i].isDigit() )
466
 
                    result.append( expression[i++] );
467
 
                // convert '.' to decimal separator
468
 
                else if ( expression[i] == '.' )
469
 
                {
470
 
                    result.append( decimal );
471
 
                    ++i;
472
 
                }
473
 
                // exponent ?
474
 
                else if ( expression[i].toUpper() == 'E' )
475
 
                {
476
 
                    result.append( 'E' );
477
 
                    ++i;
478
 
                }
479
 
                // we're done with integer number
480
 
                else
481
 
                    state = Start;
482
 
                break;
483
 
            }
484
 
            case InString:
485
 
            {
486
 
                // consume until "
487
 
                if ( expression[i] != '"' )
488
 
                    result.append( expression[i++] );
489
 
                // we're done
490
 
                else
491
 
                {
492
 
                    result.append( expression[i] );
493
 
                    ++i;
494
 
                    state = Start;
495
 
                }
496
 
                break;
497
 
            }
498
 
            case InIdentifier:
499
 
            {
500
 
                // handle problematic functions
501
 
                if ( expression.mid(i ).startsWith( "ERROR.TYPE" ) ) {
502
 
                    // replace it
503
 
                    result.append( "ERRORTYPE" );
504
 
                    i+=10; // number of characters in "ERROR.TYPE"
505
 
                } else if ( expression.mid(i ).startsWith( "LEGACY.NORMSDIST" ) ) {
506
 
                    // replace it
507
 
                    result.append( "LEGACYNORMSDIST" );
508
 
                    i+=16; // number of characters in "LEGACY.NORMSDIST"
509
 
                } else if ( expression.mid(i ).startsWith( "LEGACY.NORMSINV" ) ) {
510
 
                    // replace it
511
 
                    result.append( "LEGACYNORMSINV" );
512
 
                    i+=15; // number of characters in "LEGACY.NORMSINV"
513
 
                }
514
 
 
515
 
 
516
 
                // consume as long as alpha, dollar sign, underscore, or digit
517
 
                if ( isIdentifier( expression[i] )  || expression[i].isDigit() )
518
 
                    result.append( expression[i++] );
519
 
                // we're done
520
 
                else
521
 
                    state = Start;
522
 
                break;
523
 
            }
524
 
            default:
525
 
                break;
 
459
            }
 
460
            ++i;
 
461
            break;
 
462
        }
 
463
        case InNumber: {
 
464
            // consume as long as it's digit
 
465
            if (expression[i].isDigit())
 
466
                result.append(expression[i++]);
 
467
            // convert '.' to decimal separator
 
468
            else if (expression[i] == '.') {
 
469
                result.append(decimal);
 
470
                ++i;
 
471
            }
 
472
            // exponent ?
 
473
            else if (expression[i].toUpper() == 'E') {
 
474
                result.append('E');
 
475
                ++i;
 
476
            }
 
477
            // we're done with integer number
 
478
            else
 
479
                state = Start;
 
480
            break;
 
481
        }
 
482
        case InString: {
 
483
            // consume until "
 
484
            if (expression[i] != '"')
 
485
                result.append(expression[i++]);
 
486
            // we're done
 
487
            else {
 
488
                result.append(expression[i]);
 
489
                ++i;
 
490
                state = Start;
 
491
            }
 
492
            break;
 
493
        }
 
494
        case InIdentifier: {
 
495
            // handle problematic functions
 
496
            if (expression.mid(i).startsWith("ERROR.TYPE")) {
 
497
                // replace it
 
498
                result.append("ERRORTYPE");
 
499
                i += 10; // number of characters in "ERROR.TYPE"
 
500
            } else if (expression.mid(i).startsWith("LEGACY.NORMSDIST")) {
 
501
                // replace it
 
502
                result.append("LEGACYNORMSDIST");
 
503
                i += 16; // number of characters in "LEGACY.NORMSDIST"
 
504
            } else if (expression.mid(i).startsWith("LEGACY.NORMSINV")) {
 
505
                // replace it
 
506
                result.append("LEGACYNORMSINV");
 
507
                i += 15; // number of characters in "LEGACY.NORMSINV"
 
508
            } else if (namespacePrefix == "oooc:" && expression.mid(i).startsWith("TABLE") && !isIdentifier(expression[i+5])) {
 
509
                result.append("MULTIPLE.OPERATIONS");
 
510
                i += 5;
 
511
            }
 
512
 
 
513
 
 
514
            // consume as long as alpha, dollar sign, underscore, or digit
 
515
            if (isIdentifier(expression[i])  || expression[i].isDigit())
 
516
                result.append(expression[i++]);
 
517
            // we're done
 
518
            else
 
519
                state = Start;
 
520
            break;
 
521
        }
 
522
        default:
 
523
            break;
526
524
        }
527
525
    }
528
526
    return result;
529
527
}
530
528
 
531
 
QString KSpread::Odf::encodeFormula( const QString& expr, const KLocale* locale )
 
529
QString KSpread::Odf::encodeFormula(const QString& expr, const KLocale* locale)
532
530
{
533
531
    // use locale settings
534
532
    const QString decimal = locale ? locale->decimalSymbol() : ".";
536
534
    QString result('=');
537
535
 
538
536
    Formula formula;
539
 
    Tokens tokens = formula.scan( expr, locale );
 
537
    Tokens tokens = formula.scan(expr, locale);
540
538
 
541
 
    if ( !tokens.valid() || tokens.count() == 0 )
 
539
    if (!tokens.valid() || tokens.count() == 0)
542
540
        return expr; // no altering on error
543
541
 
544
 
    for ( int i = 0; i < tokens.count(); ++i )
545
 
    {
 
542
    for (int i = 0; i < tokens.count(); ++i) {
546
543
        const QString tokenText = tokens[i].text();
547
544
        const Token::Type type = tokens[i].type();
548
545
 
549
 
        switch ( type )
550
 
        {
 
546
        switch (type) {
551
547
        case Token::Cell:
552
 
        case Token::Range:
553
 
        {
554
 
            result.append( '[' );
 
548
        case Token::Range: {
 
549
            result.append('[');
555
550
            // FIXME Stefan: Hack to get the apostrophes right. Fix and remove!
556
551
            const int pos = tokenText.lastIndexOf('!');
557
552
            if (pos != -1 && tokenText.left(pos).contains(' '))
558
553
                result.append(Region::saveOdf('\'' + tokenText.left(pos) + '\'' + tokenText.mid(pos)));
559
554
            else
560
555
                result.append(Region::saveOdf(tokenText));
561
 
            result.append( ']' );
562
 
            break;
563
 
        }
564
 
        case Token::Float:
565
 
        {
566
 
            QString tmp( tokenText );
567
 
            result.append( tmp.replace( decimal, "." ) );
568
 
            break;
569
 
        }
570
 
        case Token::Operator:
571
 
        {
572
 
            if ( tokens[i].asOperator() == Token::Equal )
573
 
                result.append( '=' );
 
556
            result.append(']');
 
557
            break;
 
558
        }
 
559
        case Token::Float: {
 
560
            QString tmp(tokenText);
 
561
            result.append(tmp.replace(decimal, "."));
 
562
            break;
 
563
        }
 
564
        case Token::Operator: {
 
565
            if (tokens[i].asOperator() == Token::Equal)
 
566
                result.append('=');
574
567
            else
575
 
                result.append( tokenText );
 
568
                result.append(tokenText);
576
569
            break;
577
570
        }
578
 
        case Token::Identifier:
579
 
        {
580
 
            if ( tokenText == "ERRORTYPE" ) {
 
571
        case Token::Identifier: {
 
572
            if (tokenText == "ERRORTYPE") {
581
573
                // need to replace this
582
 
                result.append( "ERROR.TYPE" );
583
 
            } else if ( tokenText == "LEGACYNORMSDIST" ) {
584
 
                result.append( "LEGACY.NORMSDIST" );
585
 
            } else if ( tokenText == "LEGACYNORMSINV" ) {
586
 
                result.append( "LEGACY.NORMSINV" );
 
574
                result.append("ERROR.TYPE");
 
575
            } else if (tokenText == "LEGACYNORMSDIST") {
 
576
                result.append("LEGACY.NORMSDIST");
 
577
            } else if (tokenText == "LEGACYNORMSINV") {
 
578
                result.append("LEGACY.NORMSINV");
587
579
            } else {
588
580
                // dump it out unchanged
589
 
                result.append( tokenText );
 
581
                result.append(tokenText);
590
582
            }
591
583
            break;
592
584
 
595
587
        case Token::Integer:
596
588
        case Token::String:
597
589
        default:
598
 
            result.append( tokenText );
 
590
            result.append(tokenText);
599
591
            break;
600
592
        }
601
593
    }