/* This file is part of the KDE project Copyright (C) 2004-2007 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 "kexicomboboxpopup.h" #include "kexidatatableview.h" #include "kexitableview_p.h" #include "kexitableitem.h" #include "kexitableedit.h" #include #include #include #include #include #include /*! @internal Helper for KexiComboBoxPopup. */ class KexiComboBoxPopup_KexiTableView : public KexiDataTableView { public: KexiComboBoxPopup_KexiTableView(TQWidget* parent=0) : KexiDataTableView(parent, "KexiComboBoxPopup_tv") { init(); } void init() { setReadOnly( true ); setLineWidth( 0 ); d->moveCursorOnMouseRelease = true; KexiTableView::Appearance a(appearance()); a.navigatorEnabled = false; //! @todo add option for backgroundAltering?? a.backgroundAltering = false; a.fullRowSelection = true; a.rowHighlightingEnabled = true; a.rowMouseOverHighlightingEnabled = true; a.persistentSelections = false; a.rowMouseOverHighlightingColor = colorGroup().highlight(); a.rowMouseOverHighlightingTextColor = colorGroup().highlightedText(); a.rowHighlightingTextColor = a.rowMouseOverHighlightingTextColor; a.gridEnabled = false; setAppearance(a); setInsertingEnabled( false ); setSortingEnabled( false ); setVerticalHeaderVisible( false ); setHorizontalHeaderVisible( false ); setContextMenuEnabled( false ); setScrollbarToolTipsEnabled( false ); installEventFilter(this); setBottomMarginInternal( - horizontalScrollBar()->sizeHint().height() ); } virtual void setData( KexiTableViewData *data, bool owner = true ) { KexiTableView::setData( data, owner ); } bool setData(KexiDB::Cursor *cursor) { return KexiDataTableView::setData( cursor ); } }; //======================================== //! @internal class KexiComboBoxPopupPrivate { public: KexiComboBoxPopupPrivate() : int_f(0) , privateQuery(0) { max_rows = KexiComboBoxPopup::defaultMaxRows; } ~KexiComboBoxPopupPrivate() { delete int_f; delete privateQuery; } KexiComboBoxPopup_KexiTableView *tv; KexiDB::Field *int_f; //TODO: remove this -temporary KexiDB::QuerySchema* privateQuery; int max_rows; }; //======================================== const int KexiComboBoxPopup::defaultMaxRows = 8; KexiComboBoxPopup::KexiComboBoxPopup(TQWidget* parent, KexiTableViewColumn &column) : TQFrame( parent, "KexiComboBoxPopup", WType_Popup ) { init(); //setup tv data setData(&column, 0); } KexiComboBoxPopup::KexiComboBoxPopup(TQWidget* parent, KexiDB::Field &field) : TQFrame( parent, "KexiComboBoxPopup", WType_Popup ) { init(); //setup tv data setData(0, &field); } KexiComboBoxPopup::~KexiComboBoxPopup() { delete d; } void KexiComboBoxPopup::init() { d = new KexiComboBoxPopupPrivate(); setPaletteBackgroundColor(palette().color(TQPalette::Active,TQColorGroup::Base)); setLineWidth( 1 ); setFrameStyle( Box | Plain ); d->tv = new KexiComboBoxPopup_KexiTableView(this); installEventFilter(this); connect(d->tv, TQT_SIGNAL(itemReturnPressed(KexiTableItem*,int,int)), this, TQT_SLOT(slotTVItemAccepted(KexiTableItem*,int,int))); connect(d->tv, TQT_SIGNAL(itemMouseReleased(KexiTableItem*,int,int)), this, TQT_SLOT(slotTVItemAccepted(KexiTableItem*,int,int))); connect(d->tv, TQT_SIGNAL(itemDblClicked(KexiTableItem*,int,int)), this, TQT_SLOT(slotTVItemAccepted(KexiTableItem*,int,int))); } void KexiComboBoxPopup::setData(KexiTableViewColumn *column, KexiDB::Field *field) { if (column && !field) field = column->field(); if (!field) { kexiwarn << "KexiComboBoxPopup::setData(): !field" << endl; return; } // case 1: simple related data if (column && column->relatedData()) { d->tv->setColumnStretchEnabled( true, -1 ); //only needed when using single column setDataInternal( column->relatedData(), false /*!owner*/ ); return; } // case 2: lookup field KexiDB::LookupFieldSchema *lookupFieldSchema = 0; if (field->table()) lookupFieldSchema = field->table()->lookupFieldSchema( *field ); delete d->privateQuery; d->privateQuery = 0; if (lookupFieldSchema) { const TQValueList visibleColumns( lookupFieldSchema->visibleColumns() ); const bool multipleLookupColumnJoined = visibleColumns.count() > 1; //! @todo support more RowSourceType's, not only table and query KexiDB::Cursor *cursor = 0; switch (lookupFieldSchema->rowSource().type()) { case KexiDB::LookupFieldSchema::RowSource::Table: { KexiDB::TableSchema *lookupTable = field->table()->connection()->tableSchema( lookupFieldSchema->rowSource().name() ); if (!lookupTable) //! @todo errmsg return; if (multipleLookupColumnJoined) { kdDebug() << "--- Orig query: " << endl; lookupTable->query()->debug(); d->privateQuery = new KexiDB::QuerySchema(*lookupTable->query()); } else { cursor = field->table()->connection()->prepareQuery( *lookupTable ); } break; } case KexiDB::LookupFieldSchema::RowSource::Query: { KexiDB::QuerySchema *lookupQuery = field->table()->connection()->querySchema( lookupFieldSchema->rowSource().name() ); if (!lookupQuery) //! @todo errmsg return; if (multipleLookupColumnJoined) { kdDebug() << "--- Orig query: " << endl; lookupQuery->debug(); d->privateQuery = new KexiDB::QuerySchema(*lookupQuery); } else { cursor = field->table()->connection()->prepareQuery( *lookupQuery ); } break; } default:; } if (d->privateQuery) { // append column computed using multiple columns const KexiDB::QueryColumnInfo::Vector fieldsExpanded( d->privateQuery->fieldsExpanded() ); uint fieldsExpandedSize( fieldsExpanded.size() ); KexiDB::BaseExpr *expr = 0; int count = visibleColumns.count(); for (TQValueList::ConstIterator it( visibleColumns.at(count-1) ); count>0; count--, --it) { KexiDB::QueryColumnInfo *ci = ((*it) < fieldsExpandedSize) ? fieldsExpanded.at( *it ) : 0; if (!ci) { kdWarning() << "KexiComboBoxPopup::setData(): " << *it << " >= fieldsExpandedSize" << endl; continue; } KexiDB::VariableExpr *fieldExpr = new KexiDB::VariableExpr( ci->field->table()->name()+"."+ci->field->name() ); fieldExpr->field = ci->field; fieldExpr->tablePositionForField = d->privateQuery->tableBoundToColumn( *it ); if (expr) { //! @todo " " separator hardcoded... //! @todo use SQL sub-parser here... KexiDB::ConstExpr *constExpr = new KexiDB::ConstExpr(CHARACTER_STRING_LITERAL, " "); expr = new KexiDB::BinaryExpr(KexiDBExpr_Arithm, constExpr, CONCATENATION, expr); expr = new KexiDB::BinaryExpr(KexiDBExpr_Arithm, fieldExpr, CONCATENATION, expr); } else expr = fieldExpr; } expr->debug(); kdDebug() << expr->toString() << endl; KexiDB::Field *f = new KexiDB::Field(); f->setExpression( expr ); d->privateQuery->addField( f ); #if 0 //does not work yet // //! @todo temp: improved display by hiding all columns except the computed one const int numColumntoHide = d->privateQuery->fieldsExpanded().count() - 1; for (int i=0; i < numColumntoHide; i++) d->privateQuery->setColumnVisible(i, false); // #endif //todo... kdDebug() << "--- Private query: " << endl; d->privateQuery->debug(); cursor = field->table()->connection()->prepareQuery( *d->privateQuery ); } if (!cursor) //! @todo errmsg return; if (d->tv->KexiDataAwareObjectInterface::data()) d->tv->KexiDataAwareObjectInterface::data()->disconnect( this ); d->tv->setData( cursor ); connect( d->tv, TQT_SIGNAL(dataRefreshed()), this, TQT_SLOT(slotDataReloadRequested())); updateSize(); return; } kdWarning() << "KexiComboBoxPopup::setData(KexiTableViewColumn &): no column relatedData \n - moving to setData(KexiDB::Field &)" << endl; // case 3: enum hints d->tv->setColumnStretchEnabled( true, -1 ); //only needed when using single column //! @todo THIS IS PRIMITIVE: we'd need to employ KexiDB::Reference here! d->int_f = new KexiDB::Field(field->name(), KexiDB::Field::Text); KexiTableViewData *data = new KexiTableViewData(); data->addColumn( new KexiTableViewColumn( *d->int_f ) ); TQValueVector hints = field->enumHints(); for(uint i=0; i < hints.size(); i++) { KexiTableItem *item = data->createItem();//new KexiTableItem(1); (*item)[0]=TQVariant(hints[i]); kdDebug() << "added: '" << hints[i] <<"'"<append( item ); } setDataInternal( data, true ); } void KexiComboBoxPopup::setDataInternal( KexiTableViewData *data, bool owner ) { if (d->tv->KexiDataAwareObjectInterface::data()) d->tv->KexiDataAwareObjectInterface::data()->disconnect( this ); d->tv->setData( data, owner ); connect( d->tv, TQT_SIGNAL(dataRefreshed()), this, TQT_SLOT(slotDataReloadRequested())); updateSize(); } void KexiComboBoxPopup::updateSize(int minWidth) { const int rows = TQMIN( d->max_rows, d->tv->rows() ); d->tv->adjustColumnWidthToContents(-1); KexiTableEdit *te = dynamic_cast(parentWidget()); const int width = TQMAX( d->tv->tableSize().width(), (te ? te->totalSize().width() : (parentWidget()?parentWidget()->width():0/*sanity*/)) ); kexidbg << "KexiComboBoxPopup::updateSize(): size=" << size() << endl; resize( TQMAX(minWidth, width)/*+(d->tv->columns()>1?2:0)*/ /*(d->updateSizeCalled?0:1)*/, d->tv->rowHeight() * rows +2 ); kexidbg << "KexiComboBoxPopup::updateSize(): size after=" << size() << endl; //stretch the last column d->tv->setColumnStretchEnabled(true, d->tv->columns()-1); } KexiTableView* KexiComboBoxPopup::tableView() { return d->tv; } void KexiComboBoxPopup::resize( int w, int h ) { d->tv->horizontalScrollBar()->hide(); d->tv->verticalScrollBar()->hide(); d->tv->move(1,1); d->tv->resize( w-2, h-2 ); TQFrame::resize(w,h); update(); updateGeometry(); } void KexiComboBoxPopup::setMaxRows(int r) { d->max_rows = r; } int KexiComboBoxPopup::maxRows() const { return d->max_rows; } void KexiComboBoxPopup::slotTVItemAccepted(KexiTableItem *item, int row, int) { hide(); emit rowAccepted(item, row); } bool KexiComboBoxPopup::eventFilter( TQObject *o, TQEvent *e ) { if (o==this && e->type()==TQEvent::Hide) { emit hidden(); } else if (e->type()==TQEvent::MouseButtonPress) { kdDebug() << "TQEvent::MousePress" << endl; } else if (o==d->tv) { if (e->type()==TQEvent::KeyPress) { TQKeyEvent *ke = TQT_TQKEYEVENT(e); const int k = ke->key(); if ((ke->state()==TQt::NoButton && (k==Key_Escape || k==Key_F4)) || (ke->state()==AltButton && k==Key_Up)) { hide(); emit cancelled(); return true; } } } return TQFrame::eventFilter( o, e ); } void KexiComboBoxPopup::slotDataReloadRequested() { updateSize(); } #include "kexicomboboxpopup.moc"