You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/kexi/widget/tableview/kexiinputtableedit.cpp

396 lines
11 KiB

/* This file is part of the KDE project
Copyright (C) 2002 Lucijan Busch <lucijan@gmx.at>
Copyright (C) 2003-2007 Jaroslaw Staniek <js@iidea.pl>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "kexiinputtableedit.h"
#include <tqregexp.h>
#include <tqevent.h>
#include <tqlayout.h>
#include <tqtimer.h>
#include <tqpainter.h>
#include <tqapplication.h>
#include <tqclipboard.h>
#include <tqtooltip.h>
#include <kglobal.h>
#include <klocale.h>
#include <kdebug.h>
#include <kglobalsettings.h>
#include <kcompletionbox.h>
#include <knumvalidator.h>
#include <kexiutils/longlongvalidator.h>
#include <kexidb/field.h>
#include <kexidb/fieldvalidator.h>
//! @internal
class MyLineEdit : public KLineEdit
{
public:
MyLineEdit(TQWidget *parent, const char *name) : KLineEdit(parent,name)
{}
protected:
virtual void drawFrame ( TQPainter * p ) {
p->setPen( TQPen( colorGroup().text() ) );
TQRect r = rect();
p->moveTo( r.topLeft() );
p->lineTo( r.topRight() );
p->lineTo( r.bottomRight() );
p->lineTo( r.bottomLeft() );
if (pos().x() == 0) //draw left side only when it is @ the edge
p->lineTo( r.topLeft() );
}
};
//======================================================
KexiInputTableEdit::KexiInputTableEdit(KexiTableViewColumn &column, TQWidget *parent)
: KexiTableEdit(column, parent)
{
setName("KexiInputTableEdit");
// m_type = f.type(); //copied because the rest of code uses m_type
// m_field = &f;
// m_origValue = value;//original value
init();
}
KexiInputTableEdit::~KexiInputTableEdit()
{
}
void KexiInputTableEdit::init()
{
// kdDebug() << "KexiInputTableEdit: m_origValue.typeName()==" << m_origValue.typeName() << endl;
// kdDebug() << "KexiInputTableEdit: type== " << field()->typeName() << endl;
// kdDebug() << "KexiInputTableEdit: displayed type== " << displayedField()->typeName() << endl;
m_textFormatter.setField( field() );
//init settings
m_decsym = KGlobal::locale()->decimalSymbol();
if (m_decsym.isEmpty())
m_decsym=".";//default
const bool align_right = displayedField()->isNumericType();
if (!align_right) {
//create layer for internal editor
TQHBoxLayout *lyr = new TQHBoxLayout(this);
lyr->addSpacing(4);
lyr->setAutoAdd(true);
}
//create internal editor
m_lineedit = new MyLineEdit(this, "KexiInputTableEdit-KLineEdit");
setViewWidget(m_lineedit);
if (align_right)
m_lineedit->setAlignment(AlignRight);
// m_cview->setFrame(false);
// m_cview->setFrameStyle( TQFrame::Plain | TQFrame::Box );
// m_cview->setLineWidth( 1 );
m_calculatedCell = false;
#if 0 //js TODO
connect(m_cview->completionBox(), TQT_SIGNAL(activated(const TQString &)),
this, TQT_SLOT(completed(const TQString &)));
connect(m_cview->completionBox(), TQT_SIGNAL(highlighted(const TQString &)),
this, TQT_SLOT(completed(const TQString &)));
m_cview->completionBox()->setTabHandling(true);
#endif
}
void KexiInputTableEdit::setValueInternal(const TQVariant& add, bool removeOld)
{
TQString text( m_textFormatter.valueToText(removeOld ? TQVariant() : m_origValue, add.toString()) );
if (text.isEmpty()) {
if (m_origValue.toString().isEmpty()) {
//we have to set NULL initial value:
m_lineedit->setText(TQString());
}
}
else {
m_lineedit->setText(text);
}
#if 0
//move to end is better by default
m_cview->selectAll();
#else
//js TODO: by default we're moving to the end of editor, ADD OPTION allowing "select all chars"
m_lineedit->end(false);
#endif
if (!m_lineedit->validator()) {
TQValidator *validator = new KexiDB::FieldValidator(
*field(), m_lineedit, "KexiInputTableEdit-validator");
m_lineedit->setValidator( validator );
}
}
#if 0
//moved to KexiTextFormatter
TQString KexiInputTableEdit::valueToText(KexiDB::Field* field, const TQVariant& value, const TQString& add)
{
TQString text; //result
if (field->isFPNumericType()) {
//! @todo precision!
//! @todo support 'g' format
text = TQString::number(value.toDouble(), 'f',
TQMAX(field->visibleDecimalPlaces(), 10)); //<-- 10 is quite good maximum for fractional digits
//! @todo add command line settings?
if (value.toDouble() == 0.0) {
text = add.isEmpty() ? "0" : add; //eat 0
}
else {
//! @todo (js): get decimal places settings here...
TQStringList sl = TQStringList::split(".", text);
if (text.isEmpty()) {
//nothing
}
else if (sl.count()==2) {
// kdDebug() << "sl.count()=="<<sl.count()<< " " <<sl[0] << " | " << sl[1] << endl;
const TQString sl1 = sl[1];
int pos = sl1.length()-1;
if (pos>=1) {
for (;pos>=0 && sl1[pos]=='0';pos--)
;
pos++;
}
if (pos>0)
text = sl[0] + m_decsym + sl1.left(pos);
else
text = sl[0]; //no decimal point
}
text += add;
}
/*moved to KexiDB::FieldValidator
if (setValidator && !m_lineedit->validator()) {
TQValidator *validator = new KDoubleValidator(m_lineedit);
m_lineedit->setValidator( validator );
}*/
}
else {
text = value.toString();
if (field->isIntegerType()) {
if (value.toInt() == 0) {
text = add; //eat 0
}
else {
text += add;
}
/*moved to KexiDB::FieldValidator
//! @todo implement ranges here!
if (setValidator && !m_lineedit->validator()) {
TQValidator *validator;
if (KexiDB::Field::BigInteger == field()->type()) {
//! @todo use field->isUnsigned() for KexiUtils::ULongLongValidator
validator = new KexiUtils::LongLongValidator(m_lineedit);
}
else {
validator = new KIntValidator(m_lineedit);
}
m_lineedit->setValidator( validator );
}*/
}
else {//default: text
text += add;
}
}
return text;
}
#endif
void KexiInputTableEdit::paintEvent ( TQPaintEvent * /*e*/ )
{
TQPainter p(this);
p.setPen( TQPen( colorGroup().text() ) );
p.drawRect( rect() );
}
void
KexiInputTableEdit::setRestrictedCompletion()
{
#if 0 //js TODO
kdDebug() << "KexiInputTableEdit::setRestrictedCompletion()" << endl;
// KLineEdit *content = static_cast<KLineEdit*>(m_view);
if(m_cview->text().isEmpty())
return;
kdDebug() << "KexiInputTableEdit::setRestrictedCompletion(): something to do" << endl;
m_cview->useGlobalKeyBindings();
TQStringList newC;
TQStringList::ConstIterator it, end( m_comp.constEnd() );
for( it = m_comp.constBegin(); it != end; ++it)
{
if((*it).startsWith(m_cview->text()))
newC.append(*it);
}
m_cview->setCompletedItems(newC);
#endif
}
void
KexiInputTableEdit::completed(const TQString &s)
{
// kdDebug() << "KexiInputTableEdit::completed(): " << s << endl;
m_lineedit->setText(s);
}
bool KexiInputTableEdit::valueChanged()
{
//not needed? if (m_lineedit->text()!=m_origValue.toString())
//not needed? return true;
return KexiTableEdit::valueChanged();
}
bool KexiInputTableEdit::valueIsNull()
{
return m_lineedit->text().isNull();
}
bool KexiInputTableEdit::valueIsEmpty()
{
return !m_lineedit->text().isNull() && m_lineedit->text().isEmpty();
}
TQVariant KexiInputTableEdit::value()
{
if (field()->isFPNumericType()) {//==KexiDB::Field::Double || m_type==KexiDB::Field::Float) {
//! js @todo PRESERVE PRECISION!
TQString txt = m_lineedit->text();
if (m_decsym!=".")
txt = txt.replace(m_decsym,".");//convert back
bool ok;
const double result = txt.toDouble(&ok);
return ok ? TQVariant(result) : TQVariant();
}
else if (field()->isIntegerType()) {
//! @todo check constraints
bool ok;
if (KexiDB::Field::BigInteger == field()->type()) {
if (field()->isUnsigned()) {
const TQ_ULLONG result = m_lineedit->text().toULongLong(&ok);
return ok ? TQVariant(result) : TQVariant();
}
else {
const TQ_LLONG result = m_lineedit->text().toLongLong(&ok);
return ok ? TQVariant(result) : TQVariant();
}
}
if (KexiDB::Field::Integer == field()->type()) {
if (field()->isUnsigned()) {
const uint result = m_lineedit->text().toUInt(&ok);
return ok ? TQVariant(result) : TQVariant();
}
}
//default: signed int
const int result = m_lineedit->text().toInt(&ok);
return ok ? TQVariant(result) : TQVariant();
}
//default: text
return m_lineedit->text();
}
void
KexiInputTableEdit::clear()
{
m_lineedit->clear();
}
bool KexiInputTableEdit::cursorAtStart()
{
return m_lineedit->cursorPosition()==0;
}
bool KexiInputTableEdit::cursorAtEnd()
{
return m_lineedit->cursorPosition()==(int)m_lineedit->text().length();
}
TQSize KexiInputTableEdit::totalSize()
{
if (!m_lineedit)
return size();
return m_lineedit->size();
}
void KexiInputTableEdit::handleCopyAction(const TQVariant& value, const TQVariant& visibleValue)
{
Q_UNUSED(visibleValue);
//! @todo handle rich text?
tqApp->clipboard()->setText( m_textFormatter.valueToText(value, TQString()) );
}
void KexiInputTableEdit::handleAction(const TQString& actionName)
{
const bool alreadyVisible = m_lineedit->isVisible();
if (actionName=="edit_paste") {
if (!alreadyVisible) { //paste as the entire text if the cell was not in edit mode
emit editRequested();
m_lineedit->clear();
}
m_lineedit->paste();
}
else if (actionName=="edit_cut") {
//! @todo handle rich text?
if (!alreadyVisible) { //cut the entire text if the cell was not in edit mode
emit editRequested();
m_lineedit->selectAll();
}
m_lineedit->cut();
}
}
bool KexiInputTableEdit::showToolTipIfNeeded(const TQVariant& value, const TQRect& rect,
const TQFontMetrics& fm, bool focused)
{
TQString text( value.type()==TQVariant::String ? value.toString()
: m_textFormatter.valueToText(value, TQString()) );
TQRect internalRect(rect);
internalRect.setLeft(rect.x()+leftMargin());
internalRect.setWidth(internalRect.width()-rightMargin(focused)-2*3);
kexidbg << rect << " " << internalRect << " " << fm.width(text) << endl;
return fm.width(text) > internalRect.width();
}
void KexiInputTableEdit::moveCursorToEnd()
{
m_lineedit->end(false/*!mark*/);
}
void KexiInputTableEdit::moveCursorToStart()
{
m_lineedit->home(false/*!mark*/);
}
void KexiInputTableEdit::selectAll()
{
m_lineedit->selectAll();
}
KEXI_CELLEDITOR_FACTORY_ITEM_IMPL(KexiInputEditorFactoryItem, KexiInputTableEdit)
#include "kexiinputtableedit.moc"