/* This file is part of the KDE project Copyright (C) 2002 Peter Simonsson Copyright (C) 2003-2006 Jaroslaw Staniek 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 #include #include #include #include #include #include "kexicomboboxtableedit.h" #include #include "kexicomboboxpopup.h" #include "kexitableview.h" #include "kexitableitem.h" #include "kexi.h" #include //! @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( tqparentWidget() /*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(m_view)->insertStringList(list); //js static_cast(m_view)->setCurrentItem(static_cast(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 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.tqcontains( 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(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"