kexi

kexidatasourcecombobox.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2005-2006 Jaroslaw Staniek <js@iidea.pl>
00003 
00004    This library 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 library 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 library; see the file COPYING.LIB.  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 "kexidatasourcecombobox.h"
00021 
00022 #include <kdebug.h>
00023 #include <kiconloader.h>
00024 #include <klistbox.h>
00025 
00026 #include <kexi.h>
00027 #include <kexiproject.h>
00028 #include <keximainwindow.h>
00029 #include <kexipart.h>
00030 #include <kexipartmanager.h>
00031 #include <kexipartinfo.h>
00032 #include <kexipartitem.h>
00033 
00034 #include <kexidb/connection.h>
00035 
00036 #ifdef KEXI_SHOW_UNIMPLEMENTED
00037 #define ADD_DEFINEQUERY_ROW
00038 #endif
00039 
00041 class KexiDataSourceComboBox::Private
00042 {
00043     public:
00044         Private()
00045          : tablesCount(0)
00046          , prevIndex(-1)
00047          , showTables(true)
00048          , showQueries(true)
00049         {
00050         }
00051         int firstTableIndex() const {
00052             int index = 1; //skip empty row
00053 #ifdef ADD_DEFINEQUERY_ROW
00054             index++; /*skip 'define query' row*/
00055 #endif
00056             return index;
00057         }
00058         int firstQueryIndex() const {
00059             return firstTableIndex() + tablesCount;
00060         }
00061 
00062         QGuardedPtr<KexiProject> prj;
00063         QPixmap tableIcon, queryIcon;
00064         int tablesCount;
00065         int prevIndex; 
00066         bool showTables : 1;
00067         bool showQueries : 1;
00068 };
00069 
00070 //------------------------
00071 
00072 KexiDataSourceComboBox::KexiDataSourceComboBox(QWidget *parent, const char *name)
00073  : KComboBox(true/*rw*/, parent, name)
00074  , d(new Private())
00075 {
00076     setInsertionPolicy(NoInsertion);
00077     setCompletionMode(KGlobalSettings::CompletionPopupAuto);
00078     setSizeLimit( 16 );
00079     connect(this, SIGNAL(activated(int)), this, SLOT(slotActivated(int)));
00080     connect(this, SIGNAL(returnPressed(const QString &)), this, SLOT(slotReturnPressed(const QString &)));
00081 
00082     d->tableIcon = SmallIcon("table");
00083     d->queryIcon = SmallIcon("query");
00084 }
00085 
00086 KexiDataSourceComboBox::~KexiDataSourceComboBox()
00087 {
00088     delete d;
00089 }
00090 
00091 KexiProject* KexiDataSourceComboBox::project() const
00092 {
00093     return d->prj;
00094 }
00095 
00096 void KexiDataSourceComboBox::setProject(KexiProject *prj, bool showTables, bool showQueries)
00097 {
00098     if ((KexiProject*)d->prj == prj)
00099         return;
00100 
00101     if (d->prj) {
00102         disconnect(d->prj, 0, this, 0);
00103     }
00104     d->prj = prj;
00105     d->showTables = showTables;
00106     d->showQueries = showQueries;
00107     clear();
00108     d->tablesCount = 0;
00109     if (!d->prj)
00110         return;
00111 
00112     //needed for updating contents of the combo box
00113     connect(d->prj, SIGNAL(newItemStored(KexiPart::Item&)),
00114         this, SLOT(slotNewItemStored(KexiPart::Item&)));
00115     connect(d->prj, SIGNAL(itemRemoved(const KexiPart::Item&)),
00116         this, SLOT(slotItemRemoved(const KexiPart::Item&)));
00117     connect(d->prj, SIGNAL(itemRenamed(const KexiPart::Item&, const QCString&)),
00118         this, SLOT(slotItemRenamed(const KexiPart::Item&, const QCString&)));
00119 
00120     KexiDB::Connection *conn = d->prj->dbConnection();
00121     if (!conn)
00122         return;
00123 
00124     //special item: empty
00125     insertItem("");
00126 #ifdef ADD_DEFINEQUERY_ROW
00127     //special item: define query
00128     insertItem(i18n("Define Query..."));
00129 #endif
00130 
00131     KCompletion *comp = completionObject();
00132 
00133     if (d->showTables) {
00134         //tables
00135         KexiPart::Info* partInfo = Kexi::partManager().infoForMimeType("kexi/table");
00136         if (!partInfo)
00137             return;
00138         KexiPart::ItemList list;
00139         prj->getSortedItems(list, partInfo);
00140         list.sort();
00141         d->tablesCount = 0;
00142         for (KexiPart::ItemListIterator it(list); it.current(); ++it, d->tablesCount++) {
00143             insertItem(d->tableIcon, it.current()->name()); //or caption()? 
00144             comp->addItem(it.current()->name());
00145         }
00146     }
00147 
00148     if (d->showQueries) {
00149         //queries
00150         KexiPart::Info* partInfo = Kexi::partManager().infoForMimeType("kexi/query");
00151         if (!partInfo)
00152             return;
00153         KexiPart::ItemList list;
00154         prj->getSortedItems(list, partInfo);
00155         list.sort();
00156         for (KexiPart::ItemListIterator it(list); it.current(); ++it) {
00157             insertItem(d->queryIcon, it.current()->name()); //or caption()? 
00158             comp->addItem(it.current()->name());
00159         }
00160     }
00161 //  setCurrentText("");
00162     setCurrentItem(0);
00163 }
00164 
00165 void KexiDataSourceComboBox::setDataSource(const QString& mimeType, const QString& name)
00166 {
00167     if (name.isEmpty()) {
00168         clearEdit();
00169         setCurrentItem(0);
00170         d->prevIndex = -1;
00171         emit dataSourceChanged();
00172         return;
00173     }
00174 
00175     QString mt(mimeType);
00176     if (mimeType.isEmpty())
00177         mt="kexi/table";
00178     int i = findItem(mt, name);
00179     if (i==-1) {
00180         if (mimeType.isEmpty())
00181             i = findItem("kexi/query", name);
00182         if (i==-1) {
00183             setCurrentItem(0);
00184             return;
00185         }
00186     }
00187     setCurrentItem(i);
00188     slotActivated(i);
00189 }
00190 
00191 void KexiDataSourceComboBox::slotNewItemStored(KexiPart::Item& item)
00192 {
00193     QString name(item.name());
00194     //insert a new item, maintaining sort order and splitting to tables and queries
00195     if (item.mimeType()=="kexi/table") {
00196         int i = 1; /*skip empty row*/
00197 #ifdef ADD_DEFINEQUERY_ROW
00198         i++; /*skip 'define query' row*/
00199 #endif
00200         for (; i < d->firstQueryIndex() && name>=text(i); i++)
00201             ;
00202         insertItem(d->tableIcon, name, i);
00203         completionObject()->addItem(name);
00204         d->tablesCount++;
00205     }
00206     else if (item.mimeType()=="kexi/query") {
00207         int i;
00208         for (i=d->firstQueryIndex(); i<count() && name>=text(i); i++)
00209             ;
00210         insertItem(d->queryIcon, name, i);
00211         completionObject()->addItem(name);
00212     }
00213 }
00214 
00215 int KexiDataSourceComboBox::findItem(const QString& mimeType, const QString& name)
00216 {
00217     int i, end;
00218     if (mimeType=="kexi/table") {
00219         i = 0;
00220 #ifdef ADD_DEFINEQUERY_ROW
00221         i++; //skip 'define query'
00222 #endif
00223         end = d->firstQueryIndex();
00224     }
00225     else if (mimeType=="kexi/query") {
00226         i = d->firstQueryIndex();
00227         end = count();
00228     }
00229     else
00230         return -1;
00231 
00232     QString nameString(name);
00233 
00234     for (; i<end; i++)
00235         if (text(i)==nameString)
00236             return i;
00237     
00238     return -1;
00239 }
00240 
00241 void KexiDataSourceComboBox::slotItemRemoved(const KexiPart::Item& item)
00242 {
00243     const int i = findItem(item.mimeType(), item.name());
00244     if (i==-1)
00245         return;
00246     removeItem(i);
00247     completionObject()->removeItem(item.name());
00248     if (item.mimeType()=="kexi/table")
00249         d->tablesCount--;
00250 #if 0 //disabled because even invalid data source can be set
00251     if (currentItem()==i) {
00252         if (i==(count()-1))
00253             setCurrentItem(i-1);
00254         else
00255             setCurrentItem(i);
00256     }
00257 #endif
00258 }
00259 
00260 void KexiDataSourceComboBox::slotItemRenamed(const KexiPart::Item& item, const QCString& oldName)
00261 {
00262     const int i = findItem(item.mimeType(), QString(oldName));
00263     if (i==-1)
00264         return;
00265     changeItem(item.name(), i);
00266     completionObject()->removeItem(QString(oldName));
00267     completionObject()->addItem(item.name());
00268     setCurrentText(oldName); //still keep old name
00269 }
00270 
00271 void KexiDataSourceComboBox::slotActivated( int index )
00272 {
00273     if (index >= d->firstTableIndex() && index < count() && d->prevIndex!=currentItem()) {
00274         d->prevIndex = currentItem();
00275         emit dataSourceChanged();
00276     }
00277 }
00278 
00279 QString KexiDataSourceComboBox::selectedMimeType() const
00280 {
00281     if (selectedName().isEmpty())
00282         return "";
00283     const int index = currentItem();
00284     if (index >= d->firstTableIndex() && index < (int)d->firstQueryIndex())
00285         return "kexi/table";
00286     else if (index >= (int)d->firstQueryIndex() && index < count())
00287         return "kexi/query";
00288     return "";
00289 }
00290 
00291 QString KexiDataSourceComboBox::selectedName() const
00292 {
00293     if (isSelectionValid())
00294         return text(currentItem());
00295     return currentText();
00296 }
00297 
00298 bool KexiDataSourceComboBox::isSelectionValid() const
00299 {
00300     const int index = currentItem();
00301     return index >= d->firstTableIndex() && index < count() && text(index)==currentText();
00302 }
00303 
00304 void KexiDataSourceComboBox::slotReturnPressed(const QString & text)
00305 {
00306     //text is available: select item for this text:
00307     bool changed = false;
00308     if (text.isEmpty() && 0!=currentItem()) {
00309         setCurrentItem(0);
00310         changed = true;
00311     }
00312     else {
00313         QListBoxItem *item = listBox()->findItem( text, Qt::ExactMatch );
00314         if (item) {
00315             int index = listBox()->index( item );
00316             //if (index < d->firstTableIndex())
00317             if (index>=0 && index!=currentItem()) {
00318                 setCurrentItem( index );
00319                 changed = true;
00320             }
00321         }
00322     }
00323     if (changed)
00324         emit dataSourceChanged();
00325 }
00326 
00327 void KexiDataSourceComboBox::focusOutEvent( QFocusEvent *e )
00328 {
00329     KComboBox::focusOutEvent( e );
00330     slotReturnPressed(currentText());
00331 }
00332 
00333 #include "kexidatasourcecombobox.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys