File indexing completed on 2024-05-12 16:40:52
0001 /* This file is part of the KDE project 0002 Copyright (C) 2003-2017 Jarosław Staniek <staniek@kde.org> 0003 Copyright (C) 2012 Dimitrios T. Tanis <dimitrios.tanis@kdemail.net> 0004 0005 This program is free software; you can redistribute it and/or 0006 modify it under the terms of the GNU Library General Public 0007 License as published by the Free Software Foundation; either 0008 version 2 of the License, or (at your option) any later version. 0009 0010 This program is distributed in the hope that it will be useful, 0011 but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 Library General Public License for more details. 0014 0015 You should have received a copy of the GNU Library General Public License 0016 along with this program; see the file COPYING. If not, write to 0017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 * Boston, MA 02110-1301, USA. 0019 */ 0020 0021 #include "KexiConnectionSelectorWidget.h" 0022 #include "ui_KexiConnectionSelector.h" 0023 #include "kexiprjtypeselector.h" 0024 #include "kexidbconnectionwidget.h" 0025 #include "KexiFileWidgetInterface.h" 0026 #include <kexiutils/utils.h> 0027 #include <core/kexi.h> 0028 #include <KexiIcon.h> 0029 #include <KexiServerDriverNotFoundMessage.h> 0030 0031 #include <KDbDriverManager> 0032 #include <KDbDriverMetaData> 0033 #include <KDbConnectionData> 0034 #include <KDbUtils> 0035 #include <KDbMessageHandler> 0036 0037 #include <KMessageBox> 0038 #include <KUrlComboBox> 0039 0040 #include <QDebug> 0041 #include <QDialog> 0042 #include <QPushButton> 0043 #include <QLayout> 0044 #include <QCheckBox> 0045 #include <QVBoxLayout> 0046 #include <QPixmap> 0047 #include <QFrame> 0048 #include <QStackedWidget> 0049 #include <QKeyEvent> 0050 0051 class KexiConnectionSelector : public QWidget, public Ui_KexiConnectionSelector 0052 { 0053 Q_OBJECT 0054 public: 0055 explicit KexiConnectionSelector(QWidget *parent) 0056 : QWidget(parent) 0057 { 0058 setupUi(this); 0059 setObjectName("conn_sel"); 0060 lblIcon->setPixmap(koDesktopIconCStr(Kexi::serverIconName())); 0061 lblIcon->setFixedSize(lblIcon->pixmap()->size()); 0062 btn_add->setToolTip(xi18n("Add a new database connection")); 0063 btn_edit->setToolTip(xi18n("Edit selected database connection")); 0064 btn_remove->setToolTip(xi18n("Delete selected database connections")); 0065 } 0066 ~KexiConnectionSelector() 0067 { 0068 } 0069 }; 0070 0071 /*================================================================*/ 0072 0073 ConnectionDataLVItem::ConnectionDataLVItem(KDbConnectionData *data, 0074 const KDbDriverMetaData &driverMetaData, 0075 QTreeWidget* list) 0076 : QTreeWidgetItem(list) 0077 , m_data(data) 0078 { 0079 update(driverMetaData); 0080 } 0081 0082 ConnectionDataLVItem::~ConnectionDataLVItem() 0083 { 0084 } 0085 0086 void ConnectionDataLVItem::update(const KDbDriverMetaData &driverMetaData) 0087 { 0088 setText(0, m_data->caption() + " "); 0089 const QString sfile = xi18n("File"); 0090 QString driverName = driverMetaData.name(); 0091 QString column1; 0092 if (driverMetaData.isFileBased()) { 0093 column1 = xi18nc("file (driver name)", "%1 (%2)", sfile, driverName); 0094 } else { 0095 column1 = driverName; 0096 } 0097 setText(1, column1 + " "); 0098 setText(2, (driverMetaData.isFileBased() ? QString("<%1>").arg(sfile.toLower()) 0099 : m_data->toUserVisibleString()) + " "); 0100 } 0101 0102 /*================================================================*/ 0103 0104 //! @internal 0105 class Q_DECL_HIDDEN KexiConnectionSelectorWidget::Private 0106 { 0107 public: 0108 Private() 0109 : conn_sel_shown(false) 0110 , confirmOverwrites(true) 0111 { 0112 } 0113 0114 void updateRemoteListColumns() 0115 { 0116 remote->list->resizeColumnToContents(0); // name 0117 remote->list->resizeColumnToContents(1); // type 0118 } 0119 0120 QWidget *fileWidget() 0121 { 0122 return fileIface ? fileIface->widget() : nullptr; 0123 } 0124 0125 KexiFileWidgetInterface *fileIface = nullptr; 0126 KexiConnectionSelector *remote; 0127 QWidget* openExistingWidget; 0128 KexiPrjTypeSelector* prjTypeSelector; 0129 QUrl startDirOrVariable; 0130 KexiConnectionSelectorWidget::OperationMode operationMode; 0131 QStackedWidget *stack; 0132 QPointer<KexiDBConnectionSet> conn_set; 0133 KDbDriverManager manager; 0134 bool conn_sel_shown; //!< helper 0135 bool confirmOverwrites; 0136 KexiUtils::PaintBlocker* descGroupBoxPaintBlocker; 0137 bool isConnectionSelected; 0138 bool fileWidgetFrameVisible = true; 0139 QPointer<KexiServerDriverNotFoundMessage> errorMessagePopup; 0140 }; 0141 0142 /*================================================================*/ 0143 0144 KexiConnectionSelectorWidget::KexiConnectionSelectorWidget( 0145 KexiDBConnectionSet *conn_set, 0146 const QUrl& startDirOrVariable, OperationMode mode, QWidget* parent) 0147 : QWidget(parent) 0148 , d(new Private()) 0149 { 0150 Q_ASSERT(conn_set); 0151 d->conn_set = conn_set; 0152 d->startDirOrVariable = startDirOrVariable; 0153 d->operationMode = mode; 0154 setWindowIcon(Kexi::defaultFileBasedDriverIcon()); 0155 0156 QBoxLayout* globalLyr = new QVBoxLayout(this); 0157 globalLyr->setContentsMargins(QMargins()); 0158 0159 //create header with radio buttons 0160 d->openExistingWidget = new QWidget(this); 0161 d->openExistingWidget->setObjectName("openExistingWidget"); 0162 QVBoxLayout* openExistingWidgetLyr = new QVBoxLayout(d->openExistingWidget); 0163 openExistingWidgetLyr->setContentsMargins(0, 0, 0, 0); 0164 d->prjTypeSelector = new KexiPrjTypeSelector(d->openExistingWidget); 0165 connect(d->prjTypeSelector->buttonGroup, SIGNAL(buttonClicked(QAbstractButton*)), 0166 this, SLOT(slotPrjTypeSelected(QAbstractButton*))); 0167 openExistingWidgetLyr->addWidget(d->prjTypeSelector); 0168 d->prjTypeSelector->setContentsMargins(0, 0, 0, KexiUtils::spacingHint()); 0169 //openExistingWidgetLyr->addSpacing(KexiUtils::spacingHint()); 0170 QFrame* line = new QFrame(d->openExistingWidget); 0171 line->setFrameShape(QFrame::HLine); 0172 line->setFrameShadow(QFrame::Sunken); 0173 openExistingWidgetLyr->addWidget(line); 0174 globalLyr->addWidget(d->openExistingWidget); 0175 0176 d->stack = new QStackedWidget(this); 0177 d->stack->setObjectName("stack"); 0178 globalLyr->addWidget(d->stack, 1); 0179 0180 d->remote = new KexiConnectionSelector(d->stack); 0181 connect(d->remote->btn_add, SIGNAL(clicked()), this, SLOT(slotRemoteAddBtnClicked())); 0182 connect(d->remote->btn_edit, SIGNAL(clicked()), this, SLOT(slotRemoteEditBtnClicked())); 0183 connect(d->remote->btn_remove, SIGNAL(clicked()), this, SLOT(slotRemoteRemoveBtnClicked())); 0184 d->stack->addWidget(d->remote); 0185 if (d->remote->layout()) 0186 d->remote->layout()->setMargin(0); 0187 connect(d->remote->list, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), 0188 this, SLOT(slotConnectionItemExecuted(QTreeWidgetItem*))); 0189 connect(d->remote->list, SIGNAL(itemSelectionChanged()), 0190 this, SLOT(slotConnectionSelectionChanged())); 0191 d->remote->list->installEventFilter(this); 0192 d->descGroupBoxPaintBlocker = new KexiUtils::PaintBlocker(d->remote->descGroupBox); 0193 d->descGroupBoxPaintBlocker->setEnabled(false); 0194 d->isConnectionSelected = false; 0195 } 0196 0197 KexiConnectionSelectorWidget::~KexiConnectionSelectorWidget() 0198 { 0199 delete d; 0200 } 0201 0202 void KexiConnectionSelectorWidget::showAdvancedConnection() 0203 { 0204 d->prjTypeSelector->option_server->setChecked(true); 0205 slotPrjTypeSelected(d->prjTypeSelector->option_server); 0206 } 0207 0208 void KexiConnectionSelectorWidget::slotPrjTypeSelected(QAbstractButton *btn) 0209 { 0210 if (btn == d->prjTypeSelector->option_file) { //file-based prj type 0211 showSimpleConnection(); 0212 } else if (btn == d->prjTypeSelector->option_server) { //server-based prj type 0213 if (KDbDriverManager().hasDatabaseServerDrivers()) { 0214 if (!d->conn_sel_shown) { 0215 d->conn_sel_shown = true; 0216 //show connections (on demand): 0217 foreach(KDbConnectionData* connData, d->conn_set->list()) { 0218 addConnectionData(connData); 0219 // else { 0220 //this error should be more verbose: 0221 // qWarning() << "no driver found for '" << it.current()->driverName << "'!"; 0222 // } 0223 } 0224 if (d->remote->list->topLevelItemCount() > 0) { 0225 d->updateRemoteListColumns(); 0226 d->remote->list->sortByColumn(0, Qt::AscendingOrder); 0227 d->remote->list->topLevelItem(0)->setSelected(true); 0228 } 0229 d->remote->descGroupBox->layout()->setMargin(2); 0230 d->remote->list->setFocus(); 0231 slotConnectionSelectionChanged(); 0232 } 0233 d->stack->setCurrentWidget(d->remote); 0234 } 0235 else { 0236 if (!d->errorMessagePopup) { 0237 QWidget *errorMessagePopupParent = new QWidget(this); 0238 QVBoxLayout *vbox = new QVBoxLayout(errorMessagePopupParent); 0239 d->errorMessagePopup = new KexiServerDriverNotFoundMessage(errorMessagePopupParent); 0240 vbox->addWidget(d->errorMessagePopup); 0241 vbox->addStretch(0); 0242 d->stack->addWidget(errorMessagePopupParent); 0243 d->errorMessagePopup->setAutoDelete(false); 0244 d->stack->setCurrentWidget(d->errorMessagePopup->parentWidget()); 0245 d->errorMessagePopup->animatedShow(); 0246 } 0247 else { 0248 d->stack->setCurrentWidget(d->errorMessagePopup->parentWidget()); 0249 } 0250 } 0251 } 0252 } 0253 0254 ConnectionDataLVItem* KexiConnectionSelectorWidget::addConnectionData(KDbConnectionData* data) 0255 { 0256 const KDbDriverMetaData* driverMetaData = d->manager.driverMetaData(data->driverId()); 0257 return driverMetaData ? 0258 new ConnectionDataLVItem(data, *driverMetaData, d->remote->list) : 0; 0259 } 0260 0261 void KexiConnectionSelectorWidget::showSimpleConnection() 0262 { 0263 d->prjTypeSelector->option_file->setChecked(true); 0264 if (!d->fileIface) { 0265 d->fileIface = KexiFileWidgetInterface::createWidget( 0266 d->startDirOrVariable, d->operationMode == Opening ? KexiFileFilters::Opening 0267 : KexiFileFilters::SavingFileBasedDB, 0268 d->stack); 0269 d->fileIface->setWidgetFrame(d->fileWidgetFrameVisible); 0270 d->fileIface->setConfirmOverwrites(d->confirmOverwrites); 0271 d->stack->addWidget(d->fileIface->widget()); 0272 d->fileIface->connectFileSelectedSignal(this, SLOT(slotFileConnectionSelected(QString))); 0273 } 0274 d->stack->setCurrentWidget(d->fileIface->widget()); 0275 } 0276 0277 void KexiConnectionSelectorWidget::setFileWidgetFrameVisible(bool set) 0278 { 0279 d->fileWidgetFrameVisible = set; 0280 if (d->fileIface) { 0281 d->fileIface->setWidgetFrame(d->fileWidgetFrameVisible); 0282 } 0283 } 0284 0285 KexiConnectionSelectorWidget::ConnectionType KexiConnectionSelectorWidget::selectedConnectionType() const 0286 { 0287 return (d->stack->currentWidget() == d->fileWidget()) ? FileBased : ServerBased; 0288 } 0289 0290 KDbConnectionData* KexiConnectionSelectorWidget::selectedConnectionData() const 0291 { 0292 QList<QTreeWidgetItem *> items = d->remote->list->selectedItems(); 0293 if (items.isEmpty()) 0294 return 0; 0295 ConnectionDataLVItem *item = static_cast<ConnectionDataLVItem*>(items.first()); 0296 if (!item) 0297 return 0; 0298 return item->data(); 0299 } 0300 0301 QString KexiConnectionSelectorWidget::selectedFile() const 0302 { 0303 if (selectedConnectionType() != KexiConnectionSelectorWidget::FileBased) { 0304 return QString(); 0305 } 0306 return d->fileIface->selectedFile(); 0307 } 0308 0309 void KexiConnectionSelectorWidget::setSelectedFile(const QString& name) 0310 { 0311 if (selectedConnectionType() != KexiConnectionSelectorWidget::FileBased) { 0312 return; 0313 } 0314 return d->fileIface->setSelectedFile(name); 0315 } 0316 0317 void KexiConnectionSelectorWidget::slotConnectionItemExecuted(QTreeWidgetItem* item) 0318 { 0319 emit connectionItemExecuted(static_cast<ConnectionDataLVItem*>(item)); 0320 slotConnectionSelected(); 0321 } 0322 0323 void KexiConnectionSelectorWidget::slotConnectionItemExecuted() 0324 { 0325 QList<QTreeWidgetItem *> items = d->remote->list->selectedItems(); 0326 if (items.isEmpty()) 0327 return; 0328 slotConnectionItemExecuted(items.first()); 0329 slotConnectionSelected(); 0330 } 0331 0332 void KexiConnectionSelectorWidget::slotConnectionSelectionChanged() 0333 { 0334 QList<QTreeWidgetItem *> items = d->remote->list->selectedItems(); 0335 if (items.isEmpty()) 0336 return; 0337 ConnectionDataLVItem* item = static_cast<ConnectionDataLVItem*>(items.first()); 0338 d->remote->btn_edit->setEnabled(item); 0339 d->remote->btn_remove->setEnabled(item); 0340 QString desc; 0341 if (item) { 0342 desc = item->data()->description(); 0343 } 0344 d->descGroupBoxPaintBlocker->setEnabled(desc.isEmpty()); 0345 d->remote->descriptionLabel->setText(desc); 0346 emit connectionSelected(d->isConnectionSelected); 0347 emit connectionItemHighlighted(item); 0348 } 0349 0350 QTreeWidget* KexiConnectionSelectorWidget::connectionsList() const 0351 { 0352 return d->remote->list; 0353 } 0354 0355 void KexiConnectionSelectorWidget::setFocus() 0356 { 0357 QWidget::setFocus(); 0358 if (d->stack->currentWidget() == d->fileWidget()) { 0359 d->fileWidget()->setFocus(); 0360 } else { 0361 d->remote->list->setFocus(); 0362 } 0363 } 0364 0365 void KexiConnectionSelectorWidget::hideHelpers() 0366 { 0367 d->openExistingWidget->hide(); 0368 } 0369 0370 void KexiConnectionSelectorWidget::setConfirmOverwrites(bool set) 0371 { 0372 d->confirmOverwrites = set; 0373 if (d->fileIface) { 0374 d->fileIface->setConfirmOverwrites(d->confirmOverwrites); 0375 } 0376 } 0377 0378 bool KexiConnectionSelectorWidget::confirmOverwrites() const 0379 { 0380 return d->confirmOverwrites; 0381 } 0382 0383 void KexiConnectionSelectorWidget::slotRemoteAddBtnClicked() 0384 { 0385 KDbConnectionData data; 0386 KexiDBConnectionDialog dlg(this, data, QString(), 0387 KGuiItem(xi18nc("@action:button Add Database Connection", "&Add"), koIconName("dialog-ok"), xi18n("Add database connection"))); 0388 dlg.setWindowTitle(xi18nc("@title:window", "Add a New Database Connection")); 0389 if (QDialog::Accepted != dlg.exec()) 0390 return; 0391 0392 //store this conn. data 0393 KDbConnectionData *newData 0394 = new KDbConnectionData(*dlg.currentProjectData().connectionData()); 0395 KDbMessageGuard mg(d->conn_set); 0396 if (!d->conn_set->addConnectionData(newData)) { 0397 delete newData; 0398 return; 0399 } 0400 0401 ConnectionDataLVItem* item = addConnectionData(newData); 0402 if (item) { 0403 d->remote->list->clearSelection(); 0404 d->updateRemoteListColumns(); 0405 item->setSelected(true); 0406 slotConnectionSelectionChanged(); 0407 } 0408 } 0409 0410 void KexiConnectionSelectorWidget::slotRemoteEditBtnClicked() 0411 { 0412 QList<QTreeWidgetItem *> items = d->remote->list->selectedItems(); 0413 if (items.isEmpty()) 0414 return; 0415 ConnectionDataLVItem* item = static_cast<ConnectionDataLVItem*>(items.first()); 0416 if (!item) 0417 return; 0418 KexiDBConnectionDialog dlg(this, *item->data(), QString(), 0419 KGuiItem(xi18nc("@action:button Save Database Connection", "&Save"), koIconName("document-save"), 0420 xi18n("Save changes made to this database connection"))); 0421 dlg.setWindowTitle(xi18nc("@title:window", "Edit Database Connection")); 0422 if (QDialog::Accepted != dlg.exec()) 0423 return; 0424 0425 KDbMessageGuard mg(d->conn_set); 0426 if (!d->conn_set->saveConnectionData(item->data(), *dlg.currentProjectData().connectionData())) { 0427 return; 0428 } 0429 const KDbDriverMetaData *driverMetaData = d->manager.driverMetaData(item->data()->driverId()); 0430 if (driverMetaData) { 0431 item->update(*driverMetaData); 0432 d->updateRemoteListColumns(); 0433 slotConnectionSelectionChanged(); //to update descr. edit 0434 } 0435 } 0436 0437 void KexiConnectionSelectorWidget::slotRemoteRemoveBtnClicked() 0438 { 0439 QList<QTreeWidgetItem *> items = d->remote->list->selectedItems(); 0440 if (items.isEmpty()) 0441 return; 0442 ConnectionDataLVItem* item = static_cast<ConnectionDataLVItem*>(items.first()); 0443 if (!item) 0444 return; 0445 if (KMessageBox::Yes != KMessageBox::questionYesNo(this, 0446 xi18nc("@info", 0447 "Do you want to delete database connection <resource>%1</resource> from " 0448 "the list of available connections?", 0449 item->data()->toUserVisibleString()), 0450 QString(), //caption 0451 KStandardGuiItem::del(), KStandardGuiItem::cancel(), 0452 QString(), //dont'ask name 0453 KMessageBox::Notify | KMessageBox::Dangerous)) { 0454 return; 0455 } 0456 0457 QTreeWidgetItem* nextItem = d->remote->list->itemBelow(item); 0458 if (!nextItem) 0459 nextItem = d->remote->list->itemAbove(item); 0460 KDbMessageGuard mg(d->conn_set); 0461 if (!d->conn_set->removeConnectionData(item->data())) 0462 return; 0463 0464 delete item->data(); 0465 delete item; 0466 0467 if (nextItem) 0468 nextItem->setSelected(true); 0469 d->updateRemoteListColumns(); 0470 } 0471 0472 void KexiConnectionSelectorWidget::hideConnectonIcon() 0473 { 0474 d->remote->lblIcon->setFixedWidth(0); 0475 d->remote->lblIcon->setPixmap(QPixmap()); 0476 } 0477 0478 void KexiConnectionSelectorWidget::hideDescription() 0479 { 0480 d->remote->lblIcon->hide(); 0481 d->remote->label->hide(); 0482 } 0483 0484 void KexiConnectionSelectorWidget::setExcludedMimeTypes(const QStringList &mimeTypes) 0485 { 0486 d->fileIface->setExcludedMimeTypes(mimeTypes); 0487 } 0488 0489 bool KexiConnectionSelectorWidget::eventFilter(QObject* watched, QEvent* event) 0490 { 0491 if (event->type() == QEvent::KeyPress) { 0492 QKeyEvent *ke = static_cast<QKeyEvent*>(event); 0493 if ((ke->key() == Qt::Key_Enter || ke->key() == Qt::Key_Return) 0494 && ke->modifiers() == Qt::NoModifier) 0495 { 0496 slotConnectionItemExecuted(); 0497 return true; 0498 } 0499 } 0500 return QWidget::eventFilter(watched, event); 0501 } 0502 0503 void KexiConnectionSelectorWidget::slotFileConnectionSelected(const QString &name) 0504 { 0505 Q_UNUSED(name) 0506 d->isConnectionSelected = !d->fileIface->selectedFile().isEmpty(); 0507 emit connectionSelected(d->isConnectionSelected); 0508 emit fileSelected(name); 0509 } 0510 0511 void KexiConnectionSelectorWidget::slotConnectionSelected() 0512 { 0513 d->isConnectionSelected = !d->remote->list->selectedItems().isEmpty(); 0514 emit connectionSelected(d->isConnectionSelected); 0515 } 0516 0517 bool KexiConnectionSelectorWidget::hasSelectedConnection() const 0518 { 0519 return d->isConnectionSelected; 0520 } 0521 0522 void KexiConnectionSelectorWidget::setFileMode(KexiFileFilters::Mode mode) 0523 { 0524 if (d->fileIface) { 0525 d->fileIface->setMode(mode); 0526 } 0527 } 0528 0529 void KexiConnectionSelectorWidget::setAdditionalMimeTypes(const QStringList &mimeTypes) 0530 { 0531 if (d->fileIface) { 0532 d->fileIface->setAdditionalMimeTypes(mimeTypes); 0533 } 0534 } 0535 0536 bool KexiConnectionSelectorWidget::checkSelectedFile() 0537 { 0538 if (d->fileIface) { 0539 return d->fileIface->checkSelectedFile(); 0540 } 0541 return false; 0542 } 0543 0544 QString KexiConnectionSelectorWidget::highlightedFile() const 0545 { 0546 if (d->fileIface) { 0547 return d->fileIface->highlightedFile(); 0548 } 0549 return QString(); 0550 } 0551 0552 #include "KexiConnectionSelectorWidget.moc"