File indexing completed on 2024-05-12 16:40:53

0001 /* This file is part of the KDE project
0002    Copyright (C) 2005-2014 Jarosław Staniek <staniek@kde.org>
0003    Copyright (C) 2014 Roman Shtemberko <shtemberko@gmail.com>
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 "kexidbconnectionwidget.h"
0022 #include <kexi.h>
0023 #include <kexiguimsghandler.h>
0024 #include <widget/KexiDBPasswordDialog.h>
0025 #include "kexidbdrivercombobox.h"
0026 #include <KexiIcon.h>
0027 #include <kexiutils/utils.h>
0028 
0029 #include <KDbConnection>
0030 
0031 #include <KStandardAction>
0032 
0033 #include <QCheckBox>
0034 #include <QVBoxLayout>
0035 #include <QHBoxLayout>
0036 #include <QWhatsThis>
0037 #include <QDialogButtonBox>
0038 #include <QPushButton>
0039 
0040 //! Templorary hides db list
0041 //! @todo reenable this when implemented
0042 #define NO_LOAD_DB_LIST
0043 
0044 // @internal
0045 class Q_DECL_HIDDEN KexiDBConnectionWidget::Private
0046 {
0047 public:
0048     Private()
0049             : connectionOnly(false) {
0050     }
0051 
0052     QPushButton *btnSaveChanges, *btnTestConnection;
0053     bool connectionOnly;
0054     KexiProjectData data;
0055     KexiDBDriverComboBox *driversCombo;
0056     QAction *savePasswordHelpAction;
0057 };
0058 
0059 class Q_DECL_HIDDEN KexiDBConnectionDialog::Private
0060 {
0061 public:
0062     Private() { }
0063 
0064     KexiDBConnectionTabWidget *tabWidget;
0065     QDialogButtonBox *buttonBox;
0066 };
0067 
0068 //---------
0069 
0070 KexiDBConnectionWidget::KexiDBConnectionWidget(QWidget* parent)
0071         : QWidget(parent)
0072         , d(new Private)
0073 {
0074     setupUi(this);
0075     setObjectName("KexiConnectionSelectorWidget");
0076     iconLabel->setPixmap(koDesktopIconCStr(Kexi::serverIconName()));
0077 
0078     QVBoxLayout *driversComboLyr = new QVBoxLayout(frmEngine);
0079     driversComboLyr->setMargin(0);
0080     d->driversCombo = new KexiDBDriverComboBox(frmEngine, KexiDBDriverComboBox::ShowServerDrivers);
0081     driversComboLyr->addWidget(d->driversCombo);
0082     frmEngine->setFocusProxy(d->driversCombo);
0083     lblEngine->setBuddy(d->driversCombo);
0084     QWidget::setTabOrder(lblEngine, d->driversCombo);
0085 
0086 #ifdef NO_LOAD_DB_LIST
0087     btnLoadDBList->hide();
0088 #endif
0089     btnLoadDBList->setIcon(koIcon("view-refresh"));
0090     btnLoadDBList->setToolTip(xi18n("Load database list from the server"));
0091     btnLoadDBList->setWhatsThis(
0092         xi18n("Loads database list from the server, so you can select one using the <interface>Name</interface> combo box."));
0093 
0094     btnSavePasswordHelp->setIcon(koIcon("help-about"));
0095     btnSavePasswordHelp->setToolTip(KStandardAction::whatsThis(0, 0, btnSavePasswordHelp)->text().remove('&'));
0096     d->savePasswordHelpAction = QWhatsThis::createAction(chkSavePassword);
0097     connect(btnSavePasswordHelp, SIGNAL(clicked()), this, SLOT(slotShowSavePasswordHelp()));
0098 
0099     QHBoxLayout *hbox = new QHBoxLayout(frmBottom);
0100     hbox->addStretch(2);
0101     d->btnSaveChanges = new QPushButton(frmBottom);
0102     KGuiItem::assign(d->btnSaveChanges,
0103                      KGuiItem(xi18nc("@action:button", "Save Changes"), "document-save",
0104                               xi18n("Save all changes made to this connection information"),
0105                               xi18n("Save all changes made to this connection information. "
0106                                     "You can later reuse this information.")));
0107     d->btnSaveChanges->setObjectName("savechanges");
0108     hbox->addWidget(d->btnSaveChanges);
0109     hbox->addSpacing(KexiUtils::spacingHint());
0110     QWidget::setTabOrder(titleEdit, d->btnSaveChanges);
0111     d->btnSaveChanges->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
0112 
0113     d->btnTestConnection = new QPushButton(frmBottom);
0114 //! @todo add Test Connection icon
0115     KGuiItem::assign(d->btnTestConnection,
0116                      KGuiItem(xi18nc("@action:button", "&Test Connection"), QString(),
0117                               xi18n("Test database connection"),
0118                               xi18n("Tests database connection. "
0119                                     "You can check validity of connection information.")));
0120     d->btnTestConnection->setObjectName("testConnection");
0121     hbox->addWidget(d->btnTestConnection);
0122     setTabOrder(d->btnSaveChanges, d->btnTestConnection);
0123     d->btnTestConnection->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
0124 
0125     connect(localhostRBtn, SIGNAL(clicked()), this, SLOT(slotLocationRadioClicked()));
0126     connect(remotehostRBtn, SIGNAL(clicked()), this, SLOT(slotLocationRadioClicked()));
0127     connect(chkPortDefault, SIGNAL(toggled(bool)), this , SLOT(slotCBToggled(bool)));
0128     connect(btnLoadDBList, SIGNAL(clicked()), this, SIGNAL(loadDBList()));
0129     connect(d->btnSaveChanges, SIGNAL(clicked()), this, SIGNAL(saveChanges()));
0130 }
0131 
0132 KexiDBConnectionWidget::~KexiDBConnectionWidget()
0133 {
0134     delete d;
0135 }
0136 
0137 bool KexiDBConnectionWidget::connectionOnly() const
0138 {
0139     return d->connectionOnly;
0140 }
0141 
0142 void KexiDBConnectionWidget::setDataInternal(const KexiProjectData& data, bool connectionOnly,
0143         const QString& shortcutFileName)
0144 {
0145     d->data = data;
0146     d->connectionOnly = connectionOnly;
0147 
0148     if (d->connectionOnly) {
0149         nameLabel->hide();
0150         nameCombo->hide();
0151         btnLoadDBList->hide();
0152         dbGroupBox->setTitle(xi18n("Database Connection"));
0153     } else {
0154         nameLabel->show();
0155         nameCombo->show();
0156 #ifndef NO_LOAD_DB_LIST
0157         btnLoadDBList->show();
0158 #endif
0159         nameCombo->setEditText(d->data.databaseName());
0160         dbGroupBox->setTitle(xi18n("Database"));
0161     }
0162 //! @todo what if there's no such driver name?
0163     d->driversCombo->setCurrentDriverId(d->data.connectionData()->driverId());
0164     hostEdit->setText(d->data.connectionData()->hostName());
0165     if (d->data.connectionData()->hostName().isEmpty()) {
0166         localhostRBtn->setChecked(true);
0167     }
0168     else {
0169         remotehostRBtn->setChecked(true);
0170     }
0171     slotLocationRadioClicked();
0172     if (d->data.connectionData()->port() != 0) {
0173         chkPortDefault->setChecked(false);
0174         customPortEdit->setValue(d->data.connectionData()->port());
0175     } else {
0176         chkPortDefault->setChecked(true);
0177         /* @todo default port # instead of 0 */
0178         customPortEdit->setValue(0);
0179     }
0180     userEdit->setText(d->data.connectionData()->userName());
0181     passwordEdit->setText(d->data.connectionData()->password());
0182     if (d->connectionOnly)
0183         titleEdit->setText(d->data.connectionData()->caption());
0184     else
0185         titleEdit->setText(d->data.caption());
0186 
0187     if (shortcutFileName.isEmpty()) {
0188         d->btnSaveChanges->hide();
0189     } else {
0190         if (!QFileInfo(shortcutFileName).isWritable()) {
0191             d->btnSaveChanges->setEnabled(false);
0192         }
0193     }
0194     chkSavePassword->setChecked(d->data.connectionData()->savePassword());
0195     adjustSize();
0196 }
0197 
0198 void KexiDBConnectionWidget::setData(const KexiProjectData& data, const QString& shortcutFileName)
0199 {
0200     setDataInternal(data, false /*!connectionOnly*/, shortcutFileName);
0201 }
0202 
0203 void KexiDBConnectionWidget::setData(const KDbConnectionData& data, const QString& shortcutFileName)
0204 {
0205     KexiProjectData pdata(data);
0206     setDataInternal(pdata, true /*connectionOnly*/, shortcutFileName);
0207 }
0208 
0209 QPushButton* KexiDBConnectionWidget::saveChangesButton() const
0210 {
0211     return d->btnSaveChanges;
0212 }
0213 
0214 QPushButton* KexiDBConnectionWidget::testConnectionButton() const
0215 {
0216     return d->btnTestConnection;
0217 }
0218 
0219 KexiDBDriverComboBox* KexiDBConnectionWidget::driversCombo() const
0220 {
0221     return d->driversCombo;
0222 }
0223 
0224 
0225 KexiProjectData KexiDBConnectionWidget::data()
0226 {
0227     return d->data;
0228 }
0229 
0230 void KexiDBConnectionWidget::slotLocationRadioClicked()
0231 {
0232     hostLbl->setEnabled(remotehostRBtn->isChecked());
0233     hostEdit->setEnabled(remotehostRBtn->isChecked());
0234 }
0235 
0236 void KexiDBConnectionWidget::slotCBToggled(bool on)
0237 {
0238     if (sender() == chkPortDefault) {
0239         customPortEdit->setEnabled(!on);
0240         portLbl->setEnabled(!on);
0241         if (on) {
0242             portLbl->setBuddy(customPortEdit);
0243         }
0244     }
0245 }
0246 
0247 void KexiDBConnectionWidget::slotShowSavePasswordHelp()
0248 {
0249     QWhatsThis::showText(chkSavePassword->mapToGlobal(QPoint(0, chkSavePassword->height())),
0250                          chkSavePassword->whatsThis());
0251 }
0252 
0253 //-----------
0254 
0255 KexiDBConnectionWidgetDetails::KexiDBConnectionWidgetDetails(QWidget* parent)
0256         : QWidget(parent)
0257 {
0258     setupUi(this);
0259     customSocketEdit->setMode(KFile::File | KFile::ExistingOnly | KFile::LocalOnly);
0260 }
0261 
0262 KexiDBConnectionWidgetDetails::~KexiDBConnectionWidgetDetails()
0263 {
0264 }
0265 
0266 //-----------
0267 
0268 KexiDBConnectionTabWidget::KexiDBConnectionTabWidget(QWidget* parent)
0269         : QTabWidget(parent)
0270 {
0271     mainWidget = new KexiDBConnectionWidget(this);
0272     mainWidget->setObjectName("mainWidget");
0273     mainWidget->layout()->setMargin(KexiUtils::marginHint());
0274     addTab(mainWidget, xi18n("Parameters"));
0275 
0276     detailsWidget = new KexiDBConnectionWidgetDetails(this);
0277     detailsWidget->setObjectName("detailsWidget");
0278     addTab(detailsWidget, xi18n("Details"));
0279     connect(detailsWidget->chkSocketDefault, SIGNAL(toggled(bool)),
0280             this, SLOT(slotSocketComboboxToggled(bool)));
0281     connect(detailsWidget->chkUseSocket, SIGNAL(toggled(bool)),
0282             this, SLOT(slotSocketComboboxToggled(bool)));
0283 
0284     connect(mainWidget->testConnectionButton(), SIGNAL(clicked()),
0285             this, SLOT(slotTestConnection()));
0286 }
0287 
0288 KexiDBConnectionTabWidget::~KexiDBConnectionTabWidget()
0289 {
0290 }
0291 
0292 void KexiDBConnectionTabWidget::setData(const KexiProjectData& data, const QString& shortcutFileName)
0293 {
0294     setData(*data.connectionData(), shortcutFileName);
0295 }
0296 
0297 void KexiDBConnectionTabWidget::setData(const KDbConnectionData& data,
0298                                         const QString& shortcutFileName)
0299 {
0300     mainWidget->setData(data, shortcutFileName);
0301     detailsWidget->chkUseSocket->setChecked(data.useLocalSocketFile());
0302     detailsWidget->customSocketEdit->setUrl(QUrl::fromLocalFile(data.localSocketFileName()));
0303     detailsWidget->customSocketEdit->setEnabled(detailsWidget->chkUseSocket->isChecked());
0304     detailsWidget->chkSocketDefault->setChecked(data.localSocketFileName().isEmpty());
0305     detailsWidget->chkSocketDefault->setEnabled(detailsWidget->chkUseSocket->isChecked());
0306     detailsWidget->descriptionEdit->setText(data.description());
0307 }
0308 
0309 KexiProjectData KexiDBConnectionTabWidget::currentProjectData()
0310 {
0311     KexiProjectData data;
0312 
0313 //! @todo check if that's database of connection shortcut. Now we're assuming db shortcut only!
0314 
0315     // collect data from the form's fields
0316     if (mainWidget->connectionOnly()) {
0317         data.connectionData()->setCaption(mainWidget->titleEdit->text());
0318         data.setCaption(QString());
0319         data.connectionData()->setDescription(detailsWidget->descriptionEdit->toPlainText());
0320         data.setDatabaseName(QString());
0321     } else {
0322         data.connectionData()->caption().clear(); /* connection name is not specified... */
0323         data.setCaption(mainWidget->titleEdit->text());
0324         data.setDescription(detailsWidget->descriptionEdit->toPlainText());
0325         data.setDatabaseName(mainWidget->nameCombo->currentText());
0326     }
0327     data.connectionData()->setDriverId(mainWidget->driversCombo()->currentDriverId());
0328     data.connectionData()->setHostName(
0329         (mainWidget->remotehostRBtn->isChecked()/*remote*/)
0330         ? mainWidget->hostEdit->text() : QString());
0331     data.connectionData()->setPort(mainWidget->chkPortDefault->isChecked()
0332                                    ? 0 : mainWidget->customPortEdit->value());
0333     data.connectionData()->setLocalSocketFileName(detailsWidget->chkSocketDefault->isChecked()
0334             ? QString() : detailsWidget->customSocketEdit->url().toLocalFile());
0335     data.connectionData()->setUseLocalSocketFile(detailsWidget->chkUseSocket->isChecked());
0336 //UNSAFE!!!!
0337     data.connectionData()->setUserName(mainWidget->userEdit->text());
0338     if (mainWidget->chkSavePassword->isChecked()) {
0339         // avoid keeping potentially wrong password that then will be re-used
0340         data.connectionData()->setPassword(mainWidget->passwordEdit->text());
0341     }
0342     data.connectionData()->setSavePassword(mainWidget->chkSavePassword->isChecked());
0343     /*! @todo add "options=", eg. as string list? */
0344     return data;
0345 }
0346 
0347 bool KexiDBConnectionTabWidget::savePasswordOptionSelected() const
0348 {
0349     return mainWidget->chkSavePassword->isChecked();
0350 }
0351 
0352 void KexiDBConnectionTabWidget::slotTestConnection()
0353 {
0354     KDbConnectionData connectionData = *currentProjectData().connectionData();
0355     bool savePasswordChecked = connectionData.savePassword();
0356     if (!savePasswordChecked) {
0357         connectionData.setPassword(mainWidget->passwordEdit->text()); //not saved otherwise
0358     }
0359     if (mainWidget->passwordEdit->text().isEmpty()) {
0360         connectionData.setPassword(QString());
0361         if (savePasswordChecked) {
0362             connectionData.setSavePassword(false); //for getPasswordIfNeeded()
0363         }
0364         if (~KexiDBPasswordDialog::getPasswordIfNeeded(&connectionData,this)) {
0365             return;
0366         }
0367     }
0368     KexiGUIMessageHandler msgHandler;
0369     KDb::showConnectionTestDialog(this, connectionData, &msgHandler);
0370 }
0371 
0372 void KexiDBConnectionTabWidget::slotSocketComboboxToggled(bool on)
0373 {
0374     if (sender() == detailsWidget->chkSocketDefault) {
0375         detailsWidget->customSocketEdit->setEnabled(!on);
0376     } else if (sender() == detailsWidget->chkUseSocket) {
0377         detailsWidget->customSocketEdit->setEnabled(
0378             on && !detailsWidget->chkSocketDefault->isChecked());
0379         detailsWidget->chkSocketDefault->setEnabled(on);
0380     }
0381 }
0382 
0383 //--------
0384 
0385 //! @todo set proper help ctxt ID
0386 
0387 KexiDBConnectionDialog::KexiDBConnectionDialog(QWidget* parent, const KexiProjectData& data,
0388         const QString& shortcutFileName, const KGuiItem& acceptButtonGuiItem)
0389         : QDialog(parent)
0390         , d(new Private)
0391 {
0392     setWindowTitle(xi18nc("@title:window", "Open Database"));
0393     d->tabWidget = new KexiDBConnectionTabWidget(this);
0394     d->tabWidget->setData(data, shortcutFileName);
0395     init(acceptButtonGuiItem);
0396 }
0397 
0398 KexiDBConnectionDialog::KexiDBConnectionDialog(QWidget* parent,
0399         const KDbConnectionData& data,
0400         const QString& shortcutFileName, const KGuiItem& acceptButtonGuiItem)
0401         : QDialog(parent)
0402         , d(new Private)
0403 {
0404     setWindowTitle(xi18nc("@title:window", "Connect to a Database Server"));
0405     d->tabWidget = new KexiDBConnectionTabWidget(this);
0406     d->tabWidget->setData(data, shortcutFileName);
0407     init(acceptButtonGuiItem);
0408 }
0409 
0410 KexiDBConnectionDialog::~KexiDBConnectionDialog()
0411 {
0412     delete d;
0413 }
0414 
0415 void KexiDBConnectionDialog::init(const KGuiItem& acceptButtonGuiItem)
0416 {
0417     setObjectName("KexiDBConnectionDialog");
0418     setModal(true);
0419 
0420     QVBoxLayout *mainLayout = new QVBoxLayout;
0421     setLayout(mainLayout);
0422 
0423     mainLayout->addWidget(d->tabWidget);
0424     connect(d->tabWidget->mainWidget, SIGNAL(saveChanges()), this, SIGNAL(saveChanges()));
0425     connect(d->tabWidget, SIGNAL(testConnection()), this, SIGNAL(testConnection()));
0426 
0427     if (d->tabWidget->mainWidget->connectionOnly())
0428         d->tabWidget->mainWidget->driversCombo()->setFocus();
0429     else if (d->tabWidget->mainWidget->nameCombo->currentText().isEmpty())
0430         d->tabWidget->mainWidget->nameCombo->setFocus();
0431     else if (d->tabWidget->mainWidget->userEdit->text().isEmpty())
0432         d->tabWidget->mainWidget->userEdit->setFocus();
0433     else if (d->tabWidget->mainWidget->passwordEdit->text().isEmpty())
0434         d->tabWidget->mainWidget->passwordEdit->setFocus();
0435     else //back
0436         d->tabWidget->mainWidget->nameCombo->setFocus();
0437 
0438     // buttons
0439     d->buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel|QDialogButtonBox::Help);
0440     connect(d->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
0441     connect(d->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
0442     KGuiItem::assign(d->buttonBox->button(QDialogButtonBox::Ok),
0443                      acceptButtonGuiItem.text().isEmpty()
0444                      ? KGuiItem(xi18nc("@action:button", "&Open"), koIconName("document-open"), xi18n("Open Database Connection"))
0445                      : acceptButtonGuiItem
0446                     );
0447     mainLayout->addWidget(d->buttonBox);
0448 
0449     adjustSize();
0450     resize(width(), d->tabWidget->height());
0451 }
0452 
0453 KexiProjectData KexiDBConnectionDialog::currentProjectData()
0454 {
0455     return d->tabWidget->currentProjectData();
0456 }
0457 
0458 bool KexiDBConnectionDialog::savePasswordOptionSelected() const
0459 {
0460     return d->tabWidget->savePasswordOptionSelected();
0461 }
0462 
0463 KexiDBConnectionWidget* KexiDBConnectionDialog::mainWidget() const
0464 {
0465     return d->tabWidget->mainWidget;
0466 }
0467 
0468 KexiDBConnectionWidgetDetails* KexiDBConnectionDialog::detailsWidget() const
0469 {
0470     return d->tabWidget->detailsWidget;
0471 }
0472