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

374 lines
12 KiB

/* This file is part of the KDE project
Copyright (C) 2004-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 "kexicomboboxpopup.h"
#include "kexidatatableview.h"
#include "kexitableview_p.h"
#include "kexitableitem.h"
#include "kexitableedit.h"
#include <kexidb/lookupfieldschema.h>
#include <kexidb/expression.h>
#include <kexidb/parser/sqlparser.h>
#include <kdebug.h>
#include <tqlayout.h>
#include <tqevent.h>
/*! @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 = tqcolorGroup().highlight();
a.rowMouseOverHighlightingTextColor = tqcolorGroup().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()->tqsizeHint().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<uint> 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<uint>::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
// <remove later>
//! @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);
// </remove later>
#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<TQString> 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] <<"'"<<endl;
data->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<KexiTableEdit*>(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 (TQT_BASE_OBJECT(o)==TQT_BASE_OBJECT(this) && e->type()==TQEvent::Hide) {
emit hidden();
}
else if (e->type()==TQEvent::MouseButtonPress) {
kdDebug() << "TQEvent::MousePress" << endl;
}
else if (TQT_BASE_OBJECT(o)==TQT_BASE_OBJECT(d->tv)) {
if (e->type()==TQEvent::KeyPress) {
TQKeyEvent *ke = TQT_TQKEYEVENT(e);
const int k = ke->key();
if ((ke->state()==Qt::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"