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/kexicomboboxtableedit.cpp

447 lines
12 KiB

/* This file is part of the KDE project
Copyright (C) 2002 Peter Simonsson <psn@linux.se>
Copyright (C) 2003-2006 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 <tqlayout.h>
#include <tqstyle.h>
#include <tqwindowsstyle.h>
#include <tqpainter.h>
#include <tqapplication.h>
#include <tqclipboard.h>
#include "kexicomboboxtableedit.h"
#include <widget/utils/kexicomboboxdropdownbutton.h>
#include "kexicomboboxpopup.h"
#include "kexitableview.h"
#include "kexitableitem.h"
#include "kexi.h"
#include <klineedit.h>
//! @internal
class KexiComboBoxTableEdit::Private
{
public:
Private()
: popup(0)
, currentEditorWidth(0)
, visibleTableViewColumn(0)
, internalEditor(0)
{
}
~Private()
{
delete internalEditor;
delete visibleTableViewColumn;
}
KPushButton *button;
KexiComboBoxPopup *popup;
int currentEditorWidth;
TQSize totalSize;
KexiTableViewColumn* visibleTableViewColumn;
KexiTableEdit* internalEditor;
};
//======================================================
KexiComboBoxTableEdit::KexiComboBoxTableEdit(KexiTableViewColumn &column, TQWidget *tqparent)
: KexiInputTableEdit(column, tqparent)
, KexiComboBoxBase()
, d(new Private())
{
setName("KexiComboBoxTableEdit");
m_setVisibleValueOnSetValueInternal = true;
d->button = new KexiComboBoxDropDownButton( parentWidget() /*usually a viewport*/ );
d->button->hide();
d->button->setFocusPolicy( TQ_NoFocus );
connect(d->button, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotButtonClicked()));
connect(m_lineedit, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(slotLineEditTextChanged(const TQString&)));
// m_lineedit = new KLineEdit(this, "lineedit");
// m_lineedit->setFrame(false);
// m_lineedit->setFrameStyle( TQFrame::Plain | TQFrame::Box );
// m_lineedit->setLineWidth( 1 );
// if (f.isNumericType()) {
// m_lineedit->tqsetAlignment(AlignRight);
// }
// setView( m_lineedit );
// tqlayout->addWidget(m_view);
// m_combo->setEditable( true );
// m_combo->clear();
// m_combo->insertStringList(f.enumHints());
// TQStringList::ConstIterator it, end( f.enumHints().constEnd() );
// for ( it = f.enumHints().constBegin(); it != end; ++it) {
// if(!hints.at(i).isEmpty())
// m_combo->insertItem(hints.at(i));
// }
//js: TODO
//js static_cast<KComboBox*>(m_view)->insertStringList(list);
//js static_cast<KComboBox*>(m_view)->setCurrentItem(static_cast<int>(t));
}
KexiComboBoxTableEdit::~KexiComboBoxTableEdit()
{
delete d;
}
void KexiComboBoxTableEdit::createInternalEditor(KexiDB::QuerySchema& schema)
{
if (!m_column->visibleLookupColumnInfo || d->visibleTableViewColumn/*sanity*/)
return;
const KexiDB::Field::Type t = m_column->visibleLookupColumnInfo->field->type();
//! @todo subtype?
KexiCellEditorFactoryItem *item = KexiCellEditorFactory::item(t);
if (!item || item->className()=="KexiInputTableEdit")
return; //unsupported type or there is no need to use subeditor for KexiInputTableEdit
//special cases: BLOB, Bool datatypes
//todo
//find real type to display
KexiDB::QueryColumnInfo *ci = m_column->visibleLookupColumnInfo;
KexiDB::QueryColumnInfo *visibleLookupColumnInfo = 0;
if (ci->indexForVisibleLookupValue() != -1) {
//Lookup field is defined
visibleLookupColumnInfo = schema.expandedOrInternalField( ci->indexForVisibleLookupValue() );
}
d->visibleTableViewColumn = new KexiTableViewColumn(schema, *ci, visibleLookupColumnInfo);
//! todo set d->internalEditor visible and use it to enable data entering by hand
d->internalEditor = KexiCellEditorFactory::createEditor(*d->visibleTableViewColumn, 0);
m_lineedit->hide();
}
KexiComboBoxPopup *KexiComboBoxTableEdit::popup() const
{
return d->popup;
}
void KexiComboBoxTableEdit::setPopup(KexiComboBoxPopup *popup)
{
d->popup = popup;
}
void KexiComboBoxTableEdit::showFocus( const TQRect& r, bool readOnly )
{
// d->button->move( pos().x()+ width(), pos().y() );
updateFocus( r );
d->button->setEnabled(!readOnly);
if (readOnly)
d->button->hide();
else
d->button->show();
}
void KexiComboBoxTableEdit::resize(int w, int h)
{
d->totalSize = TQSize(w,h);
if (!column()->isReadOnly()) {
d->button->resize( h, h );
TQWidget::resize(w - d->button->width(), h);
}
m_rightMarginWhenFocused = m_rightMargin + (column()->isReadOnly() ? 0 : d->button->width());
TQRect r( pos().x(), pos().y(), w+1, h+1 );
if (m_scrollView)
r.moveBy(m_scrollView->contentsX(), m_scrollView->contentsY());
updateFocus( r );
if (popup()) {
popup()->updateSize();
}
}
// internal
void KexiComboBoxTableEdit::updateFocus( const TQRect& r )
{
if (!column()->isReadOnly()) {
if (d->button->width() > r.width())
moveChild(d->button, r.right() + 1, r.top());
else
moveChild(d->button, r.right() - d->button->width(), r.top() );
}
}
void KexiComboBoxTableEdit::hideFocus()
{
d->button->hide();
}
TQVariant KexiComboBoxTableEdit::visibleValue()
{
return KexiComboBoxBase::visibleValue();
/* KexiDB::LookupFieldSchema *lookupFieldSchema = this->lookupFieldSchema();
if (!popup() || !lookupFieldSchema)
return TQVariant();
KexiTableItem *it = popup()->tableView()->selectedItem();
return it ? it->at( lookupFieldSchema->visibleColumn() ) : TQVariant();*/
}
void KexiComboBoxTableEdit::clear()
{
m_lineedit->clear();
KexiComboBoxBase::clear();
}
bool KexiComboBoxTableEdit::valueChanged()
{
const tristate res = valueChangedInternal();
if (~res) //no result: just compare values
return KexiInputTableEdit::valueChanged();
return res == true;
}
void KexiComboBoxTableEdit::paintFocusBorders( TQPainter *p, TQVariant &, int x, int y, int w, int h )
{
// d->currentEditorWidth = w;
if (!column()->isReadOnly()) {
if (w > d->button->width())
w -= d->button->width();
}
p->drawRect(x, y, w, h);
}
void KexiComboBoxTableEdit::setupContents( TQPainter *p, bool focused, const TQVariant& val,
TQString &txt, int &align, int &x, int &y_offset, int &w, int &h )
{
if (d->internalEditor) {
d->internalEditor->setupContents( p, focused, val, txt, align, x, y_offset, w, h );
}
else {
KexiInputTableEdit::setupContents( p, focused, val, txt, align, x, y_offset, w, h );
}
if (!column()->isReadOnly() && focused && (w > d->button->width()))
w -= (d->button->width() - x);
if (!val.isNull()) {
KexiTableViewData *relData = column()->relatedData();
KexiDB::LookupFieldSchema *lookupFieldSchema = 0;
if (relData) {
int rowToHighlight;
txt = valueForString(val.toString(), &rowToHighlight, 0, 1);
}
else if ((lookupFieldSchema = this->lookupFieldSchema())) {
/* handled at at KexiTableView level
if (popup()) {
KexiTableItem *it = popup()->tableView()->selectedItem();
if (it && lookupFieldSchema->visibleColumn()!=-1 && (int)it->size() >= lookupFieldSchema->visibleColumn())
txt = it->at( lookupFieldSchema->visibleColumn() ).toString();
}*/
}
else {
//use 'enum hints' model
txt = field()->enumHint( val.toInt() );
}
}
}
void KexiComboBoxTableEdit::slotButtonClicked()
{
// this method is sometimes called by hand:
// do not allow to simulate clicks when the button is disabled
if (column()->isReadOnly() || !d->button->isEnabled())
return;
if (m_mouseBtnPressedWhenPopupVisible) {
m_mouseBtnPressedWhenPopupVisible = false;
d->button->setOn(false);
return;
}
kdDebug() << "KexiComboBoxTableEdit::slotButtonClicked()" << endl;
if (!popup() || !popup()->isVisible()) {
kdDebug() << "SHOW POPUP" << endl;
showPopup();
d->button->setOn(true);
}
}
void KexiComboBoxTableEdit::slotPopupHidden()
{
d->button->setOn(false);
// d->currentEditorWidth = 0;
}
void KexiComboBoxTableEdit::updateButton()
{
d->button->setOn(popup()->isVisible());
}
void KexiComboBoxTableEdit::hide()
{
KexiInputTableEdit::hide();
KexiComboBoxBase::hide();
d->button->setOn(false);
}
void KexiComboBoxTableEdit::show()
{
KexiInputTableEdit::show();
if (!column()->isReadOnly()) {
d->button->show();
}
}
bool KexiComboBoxTableEdit::handleKeyPress( TQKeyEvent *ke, bool editorActive )
{
const int k = ke->key();
if ((ke->state()==Qt::NoButton && k==TQt::Key_F4)
|| (ke->state()==AltButton && k==TQt::Key_Down))
{
//show popup
slotButtonClicked();
return true;
}
else if (editorActive) {
const bool enterPressed = k==TQt::Key_Enter || k==TQt::Key_Return;
if (enterPressed && m_internalEditorValueChanged) {
createPopup(false);
selectItemForEnteredValueInLookupTable( m_userEnteredValue );
return false;
}
return handleKeyPressForPopup( ke );
}
return false;
}
void KexiComboBoxTableEdit::slotLineEditTextChanged(const TQString& s)
{
slotInternalEditorValueChanged(s);
}
int KexiComboBoxTableEdit::widthForValue( TQVariant &val, const TQFontMetrics &fm )
{
KexiTableViewData *relData = column() ? column()->relatedData() : 0;
if (lookupFieldSchema() || relData) {
// in 'lookupFieldSchema' or or 'related table data' model
// we're assuming val is already the text, not the index
//! @todo ok?
return TQMAX(KEXITV_MINIMUM_COLUMN_WIDTH, fm.width(val.toString()));
}
//use 'enum hints' model
TQValueVector<TQString> hints = field()->enumHints();
bool ok;
int idx = val.toInt(&ok);
if (!ok || idx < 0 || idx > int(hints.size()-1))
return KEXITV_MINIMUM_COLUMN_WIDTH;
TQString txt = hints.at( idx, &ok );
if (!ok)
return KEXITV_MINIMUM_COLUMN_WIDTH;
return fm.width( txt );
}
bool KexiComboBoxTableEdit::eventFilter( TQObject *o, TQEvent *e )
{
if (!column()->isReadOnly() && e->type()==TQEvent::MouseButtonPress && m_scrollView) {
TQPoint gp = TQT_TQMOUSEEVENT(e)->globalPos()
+ TQPoint(m_scrollView->childX(d->button), m_scrollView->childY(d->button));
TQRect r(d->button->mapToGlobal(d->button->tqgeometry().topLeft()),
d->button->mapToGlobal(d->button->tqgeometry().bottomRight()));
if (TQT_BASE_OBJECT(o)==TQT_BASE_OBJECT(popup()) && popup()->isVisible() && r.contains( gp )) {
m_mouseBtnPressedWhenPopupVisible = true;
}
}
return false;
}
TQSize KexiComboBoxTableEdit::totalSize() const
{
return d->totalSize;
}
TQWidget *KexiComboBoxTableEdit::internalEditor() const
{
return m_lineedit;
}
void KexiComboBoxTableEdit::moveCursorToEndInInternalEditor()
{
moveCursorToEnd();
}
void KexiComboBoxTableEdit::selectAllInInternalEditor()
{
selectAll();
}
void KexiComboBoxTableEdit::moveCursorToEnd()
{
m_lineedit->end(false/*!mark*/);
}
void KexiComboBoxTableEdit::moveCursorToStart()
{
m_lineedit->home(false/*!mark*/);
}
void KexiComboBoxTableEdit::selectAll()
{
m_lineedit->selectAll();
}
void KexiComboBoxTableEdit::setValueInInternalEditor(const TQVariant& value)
{
m_lineedit->setText(value.toString());
}
TQVariant KexiComboBoxTableEdit::valueFromInternalEditor()
{
return m_lineedit->text();
}
TQPoint KexiComboBoxTableEdit::mapFromParentToGlobal(const TQPoint& pos) const
{
KexiTableView *tv = dynamic_cast<KexiTableView*>(m_scrollView);
if (!tv)
return TQPoint(-1,-1);
return tv->viewport()->mapToGlobal(pos);
}
int KexiComboBoxTableEdit::popupWidthHint() const
{
return m_lineedit->width() + m_leftMargin + m_rightMarginWhenFocused; //TQMAX(popup()->width(), d->currentEditorWidth);
}
void KexiComboBoxTableEdit::handleCopyAction(const TQVariant& value, const TQVariant& visibleValue)
{
Q_UNUSED(value);
//! @todo does not work with BLOBs!
tqApp->clipboard()->setText( visibleValue.toString() );
}
void KexiComboBoxTableEdit::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();
}
//! @todo does not work with BLOBs!
setValueInInternalEditor( tqApp->tqclipboard()->text() );
}
else
KexiInputTableEdit::handleAction(actionName);
}
KEXI_CELLEDITOR_FACTORY_ITEM_IMPL(KexiComboBoxEditorFactoryItem, KexiComboBoxTableEdit)
#include "kexicomboboxtableedit.moc"