kexi

kexicomboboxpopup.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2004-2007 Jaroslaw Staniek <js@iidea.pl>
00003 
00004    This program is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this program; see the file COPYING.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018  */
00019 
00020 #include "kexicomboboxpopup.h"
00021 
00022 #include "kexidatatableview.h"
00023 #include "kexitableview_p.h"
00024 #include "kexitableitem.h"
00025 #include "kexitableedit.h"
00026 
00027 #include <kexidb/lookupfieldschema.h>
00028 #include <kexidb/expression.h>
00029 #include <kexidb/parser/sqlparser.h>
00030 
00031 #include <kdebug.h>
00032 
00033 #include <qlayout.h>
00034 #include <qevent.h>
00035 
00038 class KexiComboBoxPopup_KexiTableView : public KexiDataTableView
00039 {
00040     public:
00041         KexiComboBoxPopup_KexiTableView(QWidget* parent=0)
00042          : KexiDataTableView(parent, "KexiComboBoxPopup_tv")
00043         {
00044             init();
00045         }
00046         void init()
00047         {
00048             setReadOnly( true );
00049             setLineWidth( 0 );
00050             d->moveCursorOnMouseRelease = true;
00051             KexiTableView::Appearance a(appearance());
00052             a.navigatorEnabled = false;
00054             a.backgroundAltering = false;
00055             a.fullRowSelection = true;
00056             a.rowHighlightingEnabled = true;
00057             a.rowMouseOverHighlightingEnabled = true;
00058             a.persistentSelections = false;
00059             a.rowMouseOverHighlightingColor = colorGroup().highlight();
00060             a.rowMouseOverHighlightingTextColor = colorGroup().highlightedText();
00061             a.rowHighlightingTextColor = a.rowMouseOverHighlightingTextColor;
00062             a.gridEnabled = false;
00063             setAppearance(a);
00064             setInsertingEnabled( false );
00065             setSortingEnabled( false );
00066             setVerticalHeaderVisible( false );
00067             setHorizontalHeaderVisible( false );
00068             setContextMenuEnabled( false );
00069             setScrollbarToolTipsEnabled( false );
00070             installEventFilter(this);
00071             setBottomMarginInternal( - horizontalScrollBar()->sizeHint().height() );
00072         }
00073         virtual void setData( KexiTableViewData *data, bool owner = true )
00074             { KexiTableView::setData( data, owner ); }
00075         bool setData(KexiDB::Cursor *cursor)
00076     { return KexiDataTableView::setData( cursor ); }
00077 };
00078 
00079 //========================================
00080 
00082 class KexiComboBoxPopupPrivate
00083 {
00084     public:
00085         KexiComboBoxPopupPrivate() 
00086          : int_f(0)
00087          , privateQuery(0)
00088         {
00089             max_rows = KexiComboBoxPopup::defaultMaxRows;
00090         }
00091         ~KexiComboBoxPopupPrivate() {
00092             delete int_f;
00093             delete privateQuery;
00094         }
00095         
00096         KexiComboBoxPopup_KexiTableView *tv;
00097         KexiDB::Field *int_f; //TODO: remove this -temporary
00098         KexiDB::QuerySchema* privateQuery;
00099         int max_rows;
00100 };
00101 
00102 //========================================
00103 
00104 const int KexiComboBoxPopup::defaultMaxRows = 8;
00105 
00106 KexiComboBoxPopup::KexiComboBoxPopup(QWidget* parent, KexiTableViewColumn &column)
00107  : QFrame( parent, "KexiComboBoxPopup", WType_Popup )
00108 {
00109     init();
00110     //setup tv data
00111     setData(&column, 0);
00112 }
00113 
00114 KexiComboBoxPopup::KexiComboBoxPopup(QWidget* parent, KexiDB::Field &field)
00115  : QFrame( parent, "KexiComboBoxPopup", WType_Popup )
00116 {
00117     init();
00118     //setup tv data
00119     setData(0, &field);
00120 }
00121 
00122 KexiComboBoxPopup::~KexiComboBoxPopup()
00123 {
00124     delete d;
00125 }
00126 
00127 void KexiComboBoxPopup::init()
00128 {
00129     d = new KexiComboBoxPopupPrivate();
00130     setPaletteBackgroundColor(palette().color(QPalette::Active,QColorGroup::Base));
00131     setLineWidth( 1 );
00132     setFrameStyle( Box | Plain );
00133     
00134     d->tv = new KexiComboBoxPopup_KexiTableView(this);
00135     installEventFilter(this);
00136     
00137     connect(d->tv, SIGNAL(itemReturnPressed(KexiTableItem*,int,int)),
00138         this, SLOT(slotTVItemAccepted(KexiTableItem*,int,int)));
00139 
00140     connect(d->tv, SIGNAL(itemMouseReleased(KexiTableItem*,int,int)),
00141         this, SLOT(slotTVItemAccepted(KexiTableItem*,int,int)));
00142 
00143     connect(d->tv, SIGNAL(itemDblClicked(KexiTableItem*,int,int)),
00144         this, SLOT(slotTVItemAccepted(KexiTableItem*,int,int)));
00145 }
00146 
00147 void KexiComboBoxPopup::setData(KexiTableViewColumn *column, KexiDB::Field *field)
00148 {
00149     if (column && !field)
00150         field = column->field();
00151     if (!field) {
00152         kexiwarn << "KexiComboBoxPopup::setData(): !field" << endl;
00153         return;
00154     }
00155 
00156     // case 1: simple related data
00157     if (column && column->relatedData()) {
00158         d->tv->setColumnStretchEnabled( true, -1 ); //only needed when using single column
00159         setDataInternal( column->relatedData(), false  );
00160         return;
00161     }
00162     // case 2: lookup field
00163     KexiDB::LookupFieldSchema *lookupFieldSchema = 0;
00164     if (field->table())
00165         lookupFieldSchema = field->table()->lookupFieldSchema( *field );
00166     delete d->privateQuery;
00167     d->privateQuery = 0;
00168     if (lookupFieldSchema) {
00169         const QValueList<uint> visibleColumns( lookupFieldSchema->visibleColumns() );
00170         const bool multipleLookupColumnJoined = visibleColumns.count() > 1;
00172         KexiDB::Cursor *cursor = 0;
00173         switch (lookupFieldSchema->rowSource().type()) {
00174         case KexiDB::LookupFieldSchema::RowSource::Table: {
00175             KexiDB::TableSchema *lookupTable 
00176                 = field->table()->connection()->tableSchema( lookupFieldSchema->rowSource().name() );
00177             if (!lookupTable)
00179                 return;
00180             if (multipleLookupColumnJoined) {
00181                 kdDebug() << "--- Orig query: " << endl;
00182                 lookupTable->query()->debug();
00183                 d->privateQuery = new KexiDB::QuerySchema(*lookupTable->query());
00184             }
00185             else {
00186                 cursor = field->table()->connection()->prepareQuery( *lookupTable );
00187             }
00188             break;
00189         }
00190         case KexiDB::LookupFieldSchema::RowSource::Query: {
00191             KexiDB::QuerySchema *lookupQuery 
00192                 = field->table()->connection()->querySchema( lookupFieldSchema->rowSource().name() );
00193             if (!lookupQuery)
00195                 return;
00196             if (multipleLookupColumnJoined) {
00197                 kdDebug() << "--- Orig query: " << endl;
00198                 lookupQuery->debug();
00199                 d->privateQuery = new KexiDB::QuerySchema(*lookupQuery);
00200             }
00201             else {
00202                 cursor = field->table()->connection()->prepareQuery( *lookupQuery );
00203             }
00204             break;
00205         }
00206         default:;
00207         }
00208         if (d->privateQuery) {
00209             // append column computed using multiple columns
00210             const KexiDB::QueryColumnInfo::Vector fieldsExpanded( d->privateQuery->fieldsExpanded() );
00211             uint fieldsExpandedSize( fieldsExpanded.size() );
00212             KexiDB::BaseExpr *expr = 0;
00213             int count = visibleColumns.count();
00214             for (QValueList<uint>::ConstIterator it( visibleColumns.at(count-1) ); count>0; count--, --it) {
00215                 KexiDB::QueryColumnInfo *ci = ((*it) < fieldsExpandedSize) ? fieldsExpanded.at( *it ) : 0;
00216                 if (!ci) {
00217                     kdWarning() << "KexiComboBoxPopup::setData(): " << *it << " >= fieldsExpandedSize" << endl;
00218                     continue;
00219                 }
00220                 KexiDB::VariableExpr *fieldExpr
00221                     = new KexiDB::VariableExpr( ci->field->table()->name()+"."+ci->field->name() );
00222                 fieldExpr->field = ci->field;
00223                 fieldExpr->tablePositionForField = d->privateQuery->tableBoundToColumn( *it );
00224                 if (expr) {
00227                     KexiDB::ConstExpr *constExpr = new KexiDB::ConstExpr(CHARACTER_STRING_LITERAL, " ");
00228                     expr = new KexiDB::BinaryExpr(KexiDBExpr_Arithm, constExpr, CONCATENATION, expr);
00229                     expr = new KexiDB::BinaryExpr(KexiDBExpr_Arithm, fieldExpr, CONCATENATION, expr);
00230                 }
00231                 else
00232                     expr = fieldExpr;
00233             }
00234             expr->debug();
00235             kdDebug() << expr->toString() << endl;
00236 
00237             KexiDB::Field *f = new KexiDB::Field();
00238             f->setExpression( expr );
00239             d->privateQuery->addField( f );
00240 #if 0 //does not work yet
00241 // <remove later>
00243             const int numColumntoHide = d->privateQuery->fieldsExpanded().count() - 1;
00244             for (int i=0; i < numColumntoHide; i++)
00245                 d->privateQuery->setColumnVisible(i, false);
00246 // </remove later>
00247 #endif
00248 //todo...
00249             kdDebug() << "--- Private query: " << endl;
00250             d->privateQuery->debug();
00251             cursor = field->table()->connection()->prepareQuery( *d->privateQuery );
00252         }
00253         if (!cursor)
00255             return;
00256 
00257         if (d->tv->data())
00258             d->tv->data()->disconnect( this );
00259         d->tv->setData( cursor );
00260 
00261         connect( d->tv, SIGNAL(dataRefreshed()), this, SLOT(slotDataReloadRequested()));
00262         updateSize();
00263         return;
00264     }
00265     
00266     kdWarning() << "KexiComboBoxPopup::setData(KexiTableViewColumn &): no column relatedData \n - moving to setData(KexiDB::Field &)" << endl;
00267 
00268     // case 3: enum hints
00269     d->tv->setColumnStretchEnabled( true, -1 ); //only needed when using single column
00270 
00272     d->int_f = new KexiDB::Field(field->name(), KexiDB::Field::Text);
00273     KexiTableViewData *data = new KexiTableViewData();
00274     data->addColumn( new KexiTableViewColumn( *d->int_f ) );
00275     QValueVector<QString> hints = field->enumHints();
00276     for(uint i=0; i < hints.size(); i++) {
00277         KexiTableItem *item = data->createItem();//new KexiTableItem(1);
00278         (*item)[0]=QVariant(hints[i]);
00279         kdDebug() << "added: '" << hints[i] <<"'"<<endl;
00280         data->append( item );
00281     }
00282     setDataInternal( data, true );
00283 }
00284 
00285 void KexiComboBoxPopup::setDataInternal( KexiTableViewData *data, bool owner )
00286 {
00287     if (d->tv->data())
00288         d->tv->data()->disconnect( this );
00289     d->tv->setData( data, owner );
00290     connect( d->tv, SIGNAL(dataRefreshed()), this, SLOT(slotDataReloadRequested()));
00291 
00292     updateSize();
00293 }
00294 
00295 void KexiComboBoxPopup::updateSize(int minWidth)
00296 {
00297     const int rows = QMIN( d->max_rows, d->tv->rows() );
00298 
00299     d->tv->adjustColumnWidthToContents(-1);
00300 
00301     KexiTableEdit *te = dynamic_cast<KexiTableEdit*>(parentWidget());
00302     const int width = QMAX( d->tv->tableSize().width(), 
00303         (te ? te->totalSize().width() : (parentWidget()?parentWidget()->width():0/*sanity*/)) );
00304     kexidbg << "KexiComboBoxPopup::updateSize(): size=" << size() << endl;
00305     resize( QMAX(minWidth, width)/*+(d->tv->columns()>1?2:0)*/ /*(d->updateSizeCalled?0:1)*/, d->tv->rowHeight() * rows +2 );
00306     kexidbg << "KexiComboBoxPopup::updateSize(): size after=" << size() << endl;
00307 
00308     //stretch the last column
00309     d->tv->setColumnStretchEnabled(true, d->tv->columns()-1);
00310 }
00311 
00312 KexiTableView* KexiComboBoxPopup::tableView()
00313 {
00314     return d->tv;
00315 }
00316 
00317 void KexiComboBoxPopup::resize( int w, int h )
00318 {
00319     d->tv->horizontalScrollBar()->hide();
00320     d->tv->verticalScrollBar()->hide();
00321     d->tv->move(1,1);
00322     d->tv->resize( w-2, h-2 );
00323     QFrame::resize(w,h);
00324     update();
00325     updateGeometry();
00326 }
00327 
00328 void KexiComboBoxPopup::setMaxRows(int r)
00329 {
00330     d->max_rows = r;
00331 }
00332 
00333 int KexiComboBoxPopup::maxRows() const
00334 {
00335     return d->max_rows;
00336 }
00337 
00338 void KexiComboBoxPopup::slotTVItemAccepted(KexiTableItem *item, int row, int)
00339 {
00340     hide();
00341     emit rowAccepted(item, row);
00342 }
00343 
00344 bool KexiComboBoxPopup::eventFilter( QObject *o, QEvent *e )
00345 {
00346     if (o==this && e->type()==QEvent::Hide) {
00347         emit hidden();
00348     }
00349     else if (e->type()==QEvent::MouseButtonPress) {
00350         kdDebug() << "QEvent::MousePress" << endl;
00351     }
00352     else if (o==d->tv) {
00353         if (e->type()==QEvent::KeyPress) {
00354             QKeyEvent *ke = static_cast<QKeyEvent*>(e);
00355             const int k = ke->key();
00356             if ((ke->state()==NoButton && (k==Key_Escape || k==Key_F4))
00357                 || (ke->state()==AltButton && k==Key_Up))
00358             {
00359                 hide();
00360                 emit cancelled();
00361                 return true;
00362             }
00363         }
00364     }
00365     return QFrame::eventFilter( o, e );
00366 }
00367 
00368 void KexiComboBoxPopup::slotDataReloadRequested()
00369 {
00370     updateSize();
00371 }
00372 
00373 #include "kexicomboboxpopup.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys