kexi

kexiinputtableedit.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2002 Lucijan Busch <lucijan@gmx.at>
00003    Copyright (C) 2003-2004 Jaroslaw Staniek <js@iidea.pl>
00004 
00005    This program is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this program; see the file COPYING.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019  */
00020 
00021 #include "kexiinputtableedit.h"
00022 
00023 #include <kexidb/field.h>
00024 
00025 #include <qregexp.h>
00026 #include <qevent.h>
00027 #include <qlayout.h>
00028 #include <qtimer.h>
00029 #include <qpainter.h>
00030 
00031 #include <kglobal.h>
00032 #include <klocale.h>
00033 #include <kdebug.h>
00034 #include <kglobalsettings.h>
00035 #include <kcompletionbox.h>
00036 #include <knumvalidator.h>
00037 
00039 class MyLineEdit : public KLineEdit
00040 {
00041     public:
00042         MyLineEdit(QWidget *parent, const char *name) : KLineEdit(parent,name)
00043         {}
00044     protected:
00045         virtual void drawFrame ( QPainter * p ) {
00046             p->setPen( QPen( colorGroup().text() ) );
00047             QRect r = rect();
00048             p->moveTo( r.topLeft() );
00049             p->lineTo( r.topRight() );
00050             p->lineTo( r.bottomRight() );
00051             p->lineTo( r.bottomLeft() );
00052             if (pos().x() == 0) //draw left side only when it is @ the edge
00053                 p->lineTo( r.topLeft() );
00054         }
00055 };
00056 
00057 //======================================================
00058 
00059 //KexiInputTableEdit::KexiInputTableEdit(KexiDB::Field &f, QScrollView *parent, const char* name)
00060 KexiInputTableEdit::KexiInputTableEdit(KexiTableViewColumn &column, QScrollView *parent)
00061  : KexiTableEdit(column, parent, "KexiInputTableEdit")
00062 {
00063 //  m_type = f.type(); //copied because the rest of code uses m_type
00064 //  m_field = &f;
00065 //  m_origValue = value;//original value
00066     init();
00067 }
00068 
00069 KexiInputTableEdit::~KexiInputTableEdit()
00070 {
00071 }
00072 
00073 void KexiInputTableEdit::init()
00074 {
00075     kdDebug() << "KexiInputTableEdit: m_origValue.typeName()==" << m_origValue.typeName() << endl;
00076     kdDebug() << "KexiInputTableEdit: type== " << field()->typeName() << endl;
00077 
00078     //init settings
00079     m_decsym = KGlobal::locale()->decimalSymbol();
00080     if (m_decsym.isEmpty())
00081         m_decsym=".";//default
00082 
00083     const bool align_right = field()->isNumericType();
00084 
00085     if (!align_right) {
00086         //create layer for internal editor
00087         QHBoxLayout *lyr = new QHBoxLayout(this);
00088         lyr->addSpacing(4);
00089         lyr->setAutoAdd(true);
00090     }
00091 
00092     //create internal editor
00093     m_lineedit = new MyLineEdit(this, "KexiInputTableEdit-KLineEdit");
00094     setViewWidget(m_lineedit);
00095     if (align_right)
00096         m_lineedit->setAlignment(AlignRight);
00097 //  m_cview->setFrame(false);
00098 //  m_cview->setFrameStyle( QFrame::Plain | QFrame::Box );
00099 //  m_cview->setLineWidth( 1 );
00100     m_calculatedCell = false;
00101 
00102 #if 0 //js TODO
00103     connect(m_cview->completionBox(), SIGNAL(activated(const QString &)),
00104      this, SLOT(completed(const QString &)));
00105     connect(m_cview->completionBox(), SIGNAL(highlighted(const QString &)),
00106      this, SLOT(completed(const QString &)));
00107      m_cview->completionBox()->setTabHandling(true);
00108 #endif
00109 
00110 }
00111     
00112 void KexiInputTableEdit::setValueInternal(const QVariant& add_, bool removeOld)
00113 {
00114 #if 0 //js
00115     if(!ov.isEmpty())
00116     {
00117         if (m_type==KexiDB::Field::Double || m_type==KexiDB::Field::Float) {
00118             if(ov == KGlobal::locale()->decimalSymbol() || ov == KGlobal::locale()->monetaryDecimalSymbol())
00119                 m_cview->setText(ov);
00120         }
00121         else if (m_type==KexiDB::Field::Integer) {
00122             if(ov == KGlobal::locale()->negativeSign())
00123                 m_cview->setText(ov);
00124         }
00125         else if (   case QVariant::UInt:
00126                 m_cview->setAlignment(AlignRight);
00127                 if(ov == "1" || ov == "2" || ov == "3" || ov == "4" || ov == "5" || ov == "6" || ov == "7" || ov == "8" || ov == "9" || ov == "0")
00128                     m_cview->setText(ov);
00129                 if(ov == "=")
00130                 {
00131                     kdDebug() << "KexiInputTableEdit::KexiInputTableEdit(): calculated!" << endl;
00132                     m_calculatedCell = true;
00133                     m_cview->setText(ov);
00134                 }
00135                 break;
00136 
00137 
00138             default:
00139                 m_cview->setText(ov);
00140                 QTimer::singleShot(1, this, SLOT(setRestrictedCompletion()));
00141                 break;
00142         }
00143     }
00144     else
00145 #endif
00146         QVariant origValue;
00147         if (!removeOld)
00148             origValue = m_origValue;
00149         QString tmp_val;
00150         QString add(add_.toString());
00151 
00152         if (field()->isFPNumericType()) {
00154             tmp_val = QString::number(origValue.toDouble(), 'f', 2/*prec*/);
00155             if (origValue.toDouble() == 0.0) {
00156                 tmp_val=add; //eat 0
00157             }
00158             else {
00160                 QStringList sl = QStringList::split(".", tmp_val);
00161                 if (tmp_val.isEmpty())
00162                     m_lineedit->setText("");
00163                 else if (sl.count()==2) {
00164                     kdDebug() << "sl.count()=="<<sl.count()<< " " <<sl[0] << " | " << sl[1] << endl;
00165                     const QString sl1 = sl[1];
00166                     int pos = sl1.length()-1;
00167                     if (pos>=1) {
00168                         for (;pos>=0 && sl1[pos]=='0';pos--)
00169                             ;
00170                         pos++;
00171                     }
00172                     if (pos>0)
00173                         tmp_val = sl[0] + m_decsym + sl1.left(pos);
00174                     else
00175                         tmp_val = sl[0]; //no decimal point
00176                 }
00177                 tmp_val+=add;
00178             }
00179 //          m_lineedit->setText(tmp_val);
00180             QValidator *validator = new KDoubleValidator(m_lineedit);
00181             m_lineedit->setValidator( validator );
00182         }
00183         else {
00184             tmp_val = origValue.toString();
00185             if (field()->isIntegerType()) {
00186                 if (origValue.toInt() == 0) {
00187                     tmp_val=add; //eat 0
00188                 }
00189                 else {
00190                     tmp_val += add;
00191                 }
00192 //          m_lineedit->setText(tmp_val);
00193             //js: @todo implement ranges here!
00194                 QValidator *validator = new KIntValidator(m_lineedit);
00195                 m_lineedit->setValidator( validator );
00196             }
00197             else {//default: text
00198                 tmp_val+=add;
00199 //          m_lineedit->setText(tmp_val);
00200             }
00201         }
00202 
00203         if (tmp_val.isEmpty()) {
00204             if (origValue.toString().isEmpty()) {
00205                 //we have to set NULL initial value:
00206                 m_lineedit->setText(QString::null);
00207             }
00208         }
00209         else {
00210             m_lineedit->setText(tmp_val);
00211         }
00212         
00213         kdDebug() << "KexiInputTableEdit:  " << m_lineedit->text().length() << endl;
00214 //      m_cview->setSelection(0, m_cview->text().length());
00215 //      QTimer::singleShot(0, m_view, SLOT(selectAll()));
00216 
00217 #if 0
00218 //move to end is better by default
00219         m_cview->selectAll();
00220 #else
00221 //js TODO: by default we're moving to the end of editor, ADD OPTION allowing "select all chars"
00222         m_lineedit->end(false);
00223 #endif
00224 //      setRestrictedCompletion();
00225 
00226 //  m_comp = comp;
00227 //  setFocusProxy(m_lineedit);
00228 
00229     //orig. editor's text
00230     m_origText = m_lineedit->text();
00231 }
00232 
00233 void KexiInputTableEdit::paintEvent ( QPaintEvent * /*e*/ )
00234 {
00235     QPainter p(this);
00236     p.setPen( QPen( colorGroup().text() ) );
00237     p.drawRect( rect() );
00238 }
00239 
00240 
00241 void
00242 KexiInputTableEdit::setRestrictedCompletion()
00243 {
00244 #if 0 //js TODO
00245 kdDebug() << "KexiInputTableEdit::setRestrictedCompletion()" << endl;
00246 //  KLineEdit *content = static_cast<KLineEdit*>(m_view);
00247     if(m_cview->text().isEmpty())
00248         return;
00249 
00250     kdDebug() << "KexiInputTableEdit::setRestrictedCompletion(): something to do" << endl;
00251 
00252     m_cview->useGlobalKeyBindings();
00253 
00254     QStringList newC;
00255     for(QStringList::Iterator it = m_comp.begin(); it != m_comp.end(); ++it)
00256     {
00257         if((*it).startsWith(m_cview->text()))
00258             newC.append(*it);
00259     }
00260     m_cview->setCompletedItems(newC);
00261 #endif
00262 }
00263 
00264 void
00265 KexiInputTableEdit::completed(const QString &s)
00266 {
00267     kdDebug() << "KexiInputTableEdit::completed(): " << s << endl;
00268     m_lineedit->setText(s);
00269 }
00270 
00271 bool KexiInputTableEdit::valueChanged()
00272 {
00273     if (m_lineedit->text()!=m_origText)
00274         return true;
00275     return KexiTableEdit::valueChanged();
00276 }
00277 
00278 bool KexiInputTableEdit::valueIsNull()
00279 {
00280     return m_lineedit->text().isNull();
00281 }
00282 
00283 bool KexiInputTableEdit::valueIsEmpty()
00284 {
00285     return !m_lineedit->text().isNull() && m_lineedit->text().isEmpty();
00286 }
00287 
00288 QVariant KexiInputTableEdit::value()
00289 {
00290     if (field()->isFPNumericType()) {//==KexiDB::Field::Double || m_type==KexiDB::Field::Float) {
00292         QString txt = m_lineedit->text();
00293         if (m_decsym!=".")
00294             txt = txt.replace(m_decsym,".");//convert back
00295         bool ok;
00296         const double result = txt.toDouble(&ok);
00297         return ok ? QVariant(result) : QVariant();
00298     }
00299     else if (field()->isIntegerType()) {
00301         bool ok;
00302         const int result = m_lineedit->text().toInt(&ok);
00303         return ok ? QVariant(result) : QVariant();
00304     }
00305     //default: text
00306 //  ok = true;
00307     return QVariant( m_lineedit->text() );
00308 }
00309 #if 0
00310     //let qt&mysql understand what we mean... (numeric values)
00311     QString v;
00312     switch(m_type)
00313     {
00314         case QVariant::UInt:
00315         case QVariant::Int:
00316         case QVariant::Double:
00317 //          QString v;
00318             if(!m_calculatedCell)
00319             {
00320                 v = m_cview->text().replace(QRegExp("\\" + KGlobal::locale()->thousandsSeparator()), "");
00321                 v = v.replace(QRegExp("\\" + KGlobal::locale()->decimalSymbol()), ".");
00322                 v = v.replace(QRegExp("\\" + KGlobal::locale()->negativeSign()), "-");
00323                 kdDebug() << "KexiInputTableEdit::value() converting => " << v.latin1() << endl;
00324                 return QVariant(v);
00325             }
00326             else
00327             {
00328                 //ok here should the formula be parsed so, just feel like in perl :)
00329                 kdDebug() << "KexiInputTableEdit::value() calculating..." << endl;
00330                 double result = 0;
00331                 QString real = m_cview->text().right(m_cview->text().length() - 1);
00332                 real = real.replace(QRegExp("\\" + KGlobal::locale()->thousandsSeparator()), "");
00333                 real = real.replace(QRegExp("\\" + KGlobal::locale()->decimalSymbol()), ".");
00334                 QStringList values = QStringList::split(QRegExp("[\\+|\\*|\\/|-]"), real, false);
00335                 QStringList ops = QStringList::split(QRegExp("[0-9]{1,8}(?:\\.[0-9]+)?"), real, false);
00336 
00337                 double lastValue = 0;
00338                 QString lastOp = "";
00339                 for(int i=0; i < (int)values.count(); i++)
00340                 {
00341                     double next;
00342 
00343                     QString op = QString((*ops.at(i))).stripWhiteSpace();
00344 
00345                     if(!((*values.at(i+1)).isEmpty()) && i == 0)
00346                     {
00347                         double local = (*values.at(i)).toDouble();
00348                         next = (*values.at(i+1)).toDouble();
00349 
00350                         QString op = (*ops.at(i));
00351                         if(op == "+")
00352                             result = local + next;
00353                         else if(op == "-")
00354                             result = local - next;
00355                         else if(op == "*")
00356                             result = local * next;
00357                         else
00358                             result = local / next;
00359                     }
00360                     else if(!(*values.at(i+1)).isEmpty())
00361                     {
00362                         next = (*values.at(i+1)).toDouble();
00363 
00364                         QString op = QString((*ops.at(i))).stripWhiteSpace();
00365                         if(op == "+")
00366                             result = result + next;
00367                         else if(op == "-")
00368                             result = result - next;
00369                         else if(op == "*")
00370                             result = result * next;
00371                         else
00372                             result = result / next;
00373                     }
00374 
00375                 }
00376 
00377                 return QVariant(result);
00378 
00379             }
00380             break;
00381 
00382         default:
00383             kdDebug() << "KexiInputTableEdit::value() default..." << endl;
00384             return QVariant(m_cview->text());
00385     }
00386 
00387 void
00388 KexiInputTableEdit::end(bool mark)
00389 {
00390     m_cview->end(mark);
00391 }
00392 
00393 void
00394 KexiInputTableEdit::backspace()
00395 {
00396     m_cview->backspace();
00397 }
00398 #endif
00399 
00400 
00401 void
00402 KexiInputTableEdit::clear()
00403 {
00404     m_lineedit->clear();
00405 }
00406 
00407 bool KexiInputTableEdit::cursorAtStart()
00408 {
00409     return m_lineedit->cursorPosition()==0;
00410 }
00411 
00412 bool KexiInputTableEdit::cursorAtEnd()
00413 {
00414     return m_lineedit->cursorPosition()==(int)m_lineedit->text().length();
00415 }
00416 
00417 QSize KexiInputTableEdit::totalSize()
00418 {
00419     if (!m_lineedit)
00420         return size();
00421     return m_lineedit->size();
00422 }
00423 
00424 KEXI_CELLEDITOR_FACTORY_ITEM_IMPL(KexiInputEditorFactoryItem, KexiInputTableEdit)
00425 
00426 #include "kexiinputtableedit.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys