File indexing completed on 2024-05-19 12:55:38
0001 /* This file is part of the KDE project 0002 Copyright (C) 2005-2016 Jarosław Staniek <staniek@kde.org> 0003 0004 This library is free software; you can redistribute it and/or 0005 modify it under the terms of the GNU Library General Public 0006 License as published by the Free Software Foundation; either 0007 version 2 of the License, or (at your option) any later version. 0008 0009 This library is distributed in the hope that it will be useful, 0010 but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 Library General Public License for more details. 0013 0014 You should have received a copy of the GNU Library General Public License 0015 along with this library; see the file COPYING.LIB. If not, write to 0016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 * Boston, MA 02110-1301, USA. 0018 */ 0019 0020 #include "KexiDataSourceComboBox.h" 0021 #include <KexiIcon.h> 0022 #include <kexi.h> 0023 #include <kexiproject.h> 0024 #include <kexipart.h> 0025 #include <kexipartmanager.h> 0026 #include <kexipartinfo.h> 0027 #include <kexipartitem.h> 0028 0029 #include <KDbConnection> 0030 0031 #include <QDebug> 0032 #include <QLineEdit> 0033 0034 #ifdef KEXI_SHOW_UNIMPLEMENTED 0035 #define ADD_DEFINEQUERY_ROW 0036 #endif 0037 0038 //! @internal 0039 class Q_DECL_HIDDEN KexiDataSourceComboBox::Private 0040 { 0041 public: 0042 Private() 0043 : tableIcon(KexiIcon("table")) 0044 , queryIcon(KexiIcon("query")) 0045 , tablesCount(0) 0046 , prevIndex(-1) 0047 , showTables(true) 0048 , showQueries(true) { 0049 } 0050 int firstTableIndex() const { 0051 int index = 1; //skip empty row 0052 #ifdef ADD_DEFINEQUERY_ROW 0053 index++; /*skip 'define query' row*/ 0054 #endif 0055 return index; 0056 } 0057 int firstQueryIndex() const { 0058 return firstTableIndex() + tablesCount; 0059 } 0060 0061 QPointer<KexiProject> prj; 0062 QIcon tableIcon, queryIcon; 0063 int tablesCount; 0064 int prevIndex; //!< Used in slotActivated() 0065 bool showTables; 0066 bool showQueries; 0067 }; 0068 0069 //------------------------ 0070 0071 KexiDataSourceComboBox::KexiDataSourceComboBox(QWidget *parent) 0072 : KComboBox(true/*rw*/, parent) 0073 , d(new Private()) 0074 { 0075 setInsertPolicy(NoInsert); 0076 setCompletionMode(KCompletion::CompletionPopupAuto); 0077 setMaxVisibleItems(16); 0078 connect(this, SIGNAL(activated(int)), this, SLOT(slotActivated(int))); 0079 connect(this, SIGNAL(returnPressed(QString)), 0080 this, SLOT(slotReturnPressed(QString))); 0081 connect(this, SIGNAL(editTextChanged(QString)), this, SLOT(slotTextChanged(QString))); 0082 } 0083 0084 KexiDataSourceComboBox::~KexiDataSourceComboBox() 0085 { 0086 delete d; 0087 } 0088 0089 KexiProject* KexiDataSourceComboBox::project() const 0090 { 0091 return d->prj; 0092 } 0093 0094 void KexiDataSourceComboBox::setProject(KexiProject *prj, bool showTables, bool showQueries) 0095 { 0096 if (static_cast<KexiProject *>(d->prj) == prj) 0097 return; 0098 0099 if (d->prj) { 0100 disconnect(d->prj, 0, this, 0); 0101 } 0102 d->prj = prj; 0103 d->showTables = showTables; 0104 d->showQueries = showQueries; 0105 clear(); 0106 d->tablesCount = 0; 0107 if (!d->prj) 0108 return; 0109 0110 //needed for updating contents of the combo box 0111 connect(d->prj, SIGNAL(newItemStored(KexiPart::Item*)), 0112 this, SLOT(slotNewItemStored(KexiPart::Item*))); 0113 connect(d->prj, SIGNAL(itemRemoved(KexiPart::Item)), 0114 this, SLOT(slotItemRemoved(KexiPart::Item))); 0115 connect(d->prj, SIGNAL(itemRenamed(KexiPart::Item,QString)), 0116 this, SLOT(slotItemRenamed(KexiPart::Item,QString))); 0117 0118 KDbConnection *conn = d->prj->dbConnection(); 0119 if (!conn) 0120 return; 0121 0122 addItem(""); //special item: empty but not null 0123 #ifdef ADD_DEFINEQUERY_ROW 0124 //special item: define query 0125 addItem(xi18n("Define Query...")); 0126 #endif 0127 0128 KCompletion *comp = completionObject(); 0129 0130 if (d->showTables) { 0131 //tables 0132 KexiPart::Info* partInfo = Kexi::partManager().infoForPluginId("org.kexi-project.table"); 0133 if (!partInfo) 0134 return; 0135 KexiPart::ItemList list; 0136 prj->getSortedItems(&list, partInfo); 0137 list.sort(); 0138 d->tablesCount = 0; 0139 foreach(KexiPart::Item *item, list) { 0140 addItem(d->tableIcon, item->name()); //or caption()? 0141 comp->addItem(item->name()); 0142 d->tablesCount++; 0143 } 0144 } 0145 0146 if (d->showQueries) { 0147 //queries 0148 KexiPart::Info* partInfo = Kexi::partManager().infoForPluginId("org.kexi-project.query"); 0149 if (!partInfo) 0150 return; 0151 KexiPart::ItemList list; 0152 prj->getSortedItems(&list, partInfo); 0153 list.sort(); 0154 foreach(KexiPart::Item *item, list) { 0155 addItem(d->queryIcon, item->name()); //or caption()? 0156 comp->addItem(item->name()); 0157 } 0158 } 0159 setCurrentIndex(0); 0160 } 0161 0162 void KexiDataSourceComboBox::setDataSource(const QString& pluginId, const QString& name) 0163 { 0164 if (name.isEmpty()) { 0165 if (currentIndex() != 0) { 0166 clearEditText(); 0167 setCurrentIndex(0); 0168 d->prevIndex = -1; 0169 emit dataSourceChanged(); 0170 } 0171 return; 0172 } 0173 0174 QString _pluginId(pluginId); 0175 if (_pluginId.isEmpty()) 0176 _pluginId = "org.kexi-project.table"; 0177 int i = findItem(_pluginId, name); 0178 if (i == -1) { 0179 if (pluginId.isEmpty()) 0180 i = findItem("org.kexi-project.query", name); 0181 if (i == -1) { 0182 if (currentIndex() != 0) { 0183 setCurrentIndex(0); 0184 } 0185 return; 0186 } 0187 } 0188 if (currentIndex() != i) { 0189 setCurrentIndex(i); 0190 slotActivated(i); 0191 } 0192 } 0193 0194 void KexiDataSourceComboBox::slotNewItemStored(KexiPart::Item* item) 0195 { 0196 QString name(item->name()); 0197 //insert a new item, maintaining sort order and splitting to tables and queries 0198 if (item->pluginId() == "org.kexi-project.table") { 0199 int i = 1; /*skip empty row*/ 0200 #ifdef ADD_DEFINEQUERY_ROW 0201 i++; /*skip 'define query' row*/ 0202 #endif 0203 for (; i < d->firstQueryIndex() && name >= itemText(i); i++) { 0204 } 0205 insertItem(i, d->tableIcon, name); 0206 completionObject()->addItem(name); 0207 d->tablesCount++; 0208 } else if (item->pluginId() == "org.kexi-project.query") { 0209 int i; 0210 for (i = d->firstQueryIndex(); i < count() && name >= itemText(i); i++) { 0211 } 0212 insertItem(i, d->queryIcon, name); 0213 completionObject()->addItem(name); 0214 } 0215 } 0216 0217 int KexiDataSourceComboBox::findItem(const QString& pluginId, const QString& name) 0218 { 0219 int i, end; 0220 if (pluginId == "org.kexi-project.table") { 0221 i = 0; 0222 #ifdef ADD_DEFINEQUERY_ROW 0223 i++; //skip 'define query' 0224 #endif 0225 end = d->firstQueryIndex(); 0226 } else if (pluginId == "org.kexi-project.query") { 0227 i = d->firstQueryIndex(); 0228 end = count(); 0229 } else 0230 return -1; 0231 0232 QString nameString(name); 0233 0234 for (; i < end; i++) 0235 if (itemText(i) == nameString) 0236 return i; 0237 0238 return -1; 0239 } 0240 0241 void KexiDataSourceComboBox::slotItemRemoved(const KexiPart::Item& item) 0242 { 0243 const int i = findItem(item.pluginId(), item.name()); 0244 if (i == -1) 0245 return; 0246 removeItem(i); 0247 completionObject()->removeItem(item.name()); 0248 if (item.pluginId() == "org.kexi-project.table") 0249 d->tablesCount--; 0250 #if 0 //disabled because even invalid data source can be set 0251 if (currentItem() == i) { 0252 if (i == (count() - 1)) 0253 setCurrentItem(i - 1); 0254 else 0255 setCurrentItem(i); 0256 } 0257 #endif 0258 } 0259 0260 void KexiDataSourceComboBox::slotItemRenamed(const KexiPart::Item& item, const QString& oldName) 0261 { 0262 const int i = findItem(item.pluginId(), QString(oldName)); 0263 if (i == -1) { 0264 return; 0265 } 0266 setItemText(i, item.name()); 0267 completionObject()->removeItem(oldName); 0268 completionObject()->addItem(item.name()); 0269 setEditText(oldName); //still keep old name 0270 } 0271 0272 void KexiDataSourceComboBox::slotActivated(int index) 0273 { 0274 if (index >= 0 && index < count() && d->prevIndex != currentIndex()) { 0275 d->prevIndex = currentIndex(); 0276 emit dataSourceChanged(); 0277 } 0278 } 0279 0280 void KexiDataSourceComboBox::slotTextChanged(const QString &text) 0281 { 0282 Q_UNUSED(text) 0283 //! @todo This place may be useful when we alow to enter values not being on the list 0284 } 0285 0286 QString KexiDataSourceComboBox::selectedPluginId() const 0287 { 0288 if (selectedName().isEmpty()) { 0289 return QString(); 0290 } 0291 const int index = currentIndex(); 0292 if (index >= d->firstTableIndex() && index < (int)d->firstQueryIndex()) { 0293 return "org.kexi-project.table"; 0294 } 0295 else if (index >= (int)d->firstQueryIndex() && index < count()) { 0296 return "org.kexi-project.query"; 0297 } 0298 return QString(); 0299 } 0300 0301 QString KexiDataSourceComboBox::selectedName() const 0302 { 0303 if (isSelectionValid()) { 0304 return itemText(currentIndex()); 0305 } 0306 return currentText(); 0307 } 0308 0309 bool KexiDataSourceComboBox::isSelectionValid() const 0310 { 0311 const int index = currentIndex(); 0312 return index >= d->firstTableIndex() && index < count() && itemText(index) == currentText(); 0313 } 0314 0315 void KexiDataSourceComboBox::slotReturnPressed(const QString & text) 0316 { 0317 //if selected text is valid: no completion is required. 0318 if (isSelectionValid()) { 0319 return; 0320 } 0321 0322 //text is available: select item for this text: 0323 bool changed = false; 0324 if (text.isEmpty() && 0 != currentIndex()) { 0325 setCurrentIndex(0); 0326 changed = true; 0327 } else { 0328 const int index = findText(text, Qt::MatchExactly); 0329 if (index >= 0 && index != currentIndex()) { 0330 setCurrentIndex(index); 0331 changed = true; 0332 } 0333 } 0334 if (changed) { 0335 emit dataSourceChanged(); 0336 } 0337 } 0338 0339 void KexiDataSourceComboBox::focusOutEvent(QFocusEvent *e) 0340 { 0341 KComboBox::focusOutEvent(e); 0342 slotReturnPressed(currentText()); 0343 } 0344