File indexing completed on 2024-04-28 05:48:40

0001 /*
0002    SPDX-FileCopyrightText: 2010 Marco Mentasti <marcomentasti@gmail.com>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-only
0005 */
0006 
0007 #include "katesqlview.h"
0008 #include "connectionmodel.h"
0009 #include "connectionwizard.h"
0010 #include "dataoutputmodel.h"
0011 #include "dataoutputview.h"
0012 #include "dataoutputwidget.h"
0013 #include "katesqlplugin.h"
0014 #include "outputwidget.h"
0015 #include "schemabrowserwidget.h"
0016 #include "schemawidget.h"
0017 #include "sqlmanager.h"
0018 #include "textoutputwidget.h"
0019 
0020 #include <ktexteditor/application.h>
0021 #include <ktexteditor/document.h>
0022 #include <ktexteditor/plugin.h>
0023 #include <ktexteditor/view.h>
0024 
0025 #include <KActionCollection>
0026 #include <KComboBox>
0027 #include <KConfig>
0028 #include <KConfigGroup>
0029 #include <KLocalizedString>
0030 #include <KSharedConfig>
0031 #include <KXMLGUIFactory>
0032 #include <QAction>
0033 
0034 #include <QActionGroup>
0035 #include <QMenu>
0036 #include <QSqlQuery>
0037 #include <QString>
0038 #include <QWidgetAction>
0039 
0040 KateSQLView::KateSQLView(KTextEditor::Plugin *plugin, KTextEditor::MainWindow *mw)
0041     : QObject(mw)
0042     , m_manager(new SQLManager(this))
0043     , m_mainWindow(mw)
0044 {
0045     KXMLGUIClient::setComponentName(QStringLiteral("katesql"), i18n("SQL"));
0046     setXMLFile(QStringLiteral("ui.rc"));
0047 
0048     m_outputToolView = mw->createToolView(plugin,
0049                                           QStringLiteral("kate_private_plugin_katesql_output"),
0050                                           KTextEditor::MainWindow::Bottom,
0051                                           QIcon::fromTheme(QStringLiteral("server-database")),
0052                                           i18nc("@title:window", "SQL"));
0053 
0054     m_schemaBrowserToolView = mw->createToolView(plugin,
0055                                                  QStringLiteral("kate_private_plugin_katesql_schemabrowser"),
0056                                                  KTextEditor::MainWindow::Left,
0057                                                  QIcon::fromTheme(QStringLiteral("server-database")),
0058                                                  i18nc("@title:window", "SQL Schema"));
0059 
0060     m_outputWidget = new KateSQLOutputWidget(m_outputToolView);
0061 
0062     m_schemaBrowserWidget = new SchemaBrowserWidget(m_schemaBrowserToolView, m_manager);
0063 
0064     m_connectionsComboBox = new KComboBox(false);
0065     m_connectionsComboBox->setEditable(false);
0066     m_connectionsComboBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
0067     m_connectionsComboBox->setModel(m_manager->connectionModel());
0068 
0069     setupActions();
0070 
0071     m_mainWindow->guiFactory()->addClient(this);
0072 
0073     QMenu *sqlMenu = static_cast<QMenu *>(factory()->container(QStringLiteral("SQL"), this));
0074 
0075     m_connectionsGroup = new QActionGroup(sqlMenu);
0076     m_connectionsGroup->setExclusive(true);
0077 
0078     connect(sqlMenu, &QMenu::aboutToShow, this, &KateSQLView::slotSQLMenuAboutToShow);
0079     connect(m_connectionsGroup, &QActionGroup::triggered, this, &KateSQLView::slotConnectionSelectedFromMenu);
0080     connect(m_manager, &SQLManager::error, this, &KateSQLView::slotError);
0081     connect(m_manager, &SQLManager::success, this, &KateSQLView::slotSuccess);
0082     connect(m_manager, &SQLManager::queryActivated, this, &KateSQLView::slotQueryActivated);
0083     connect(m_manager, &SQLManager::connectionCreated, this, &KateSQLView::slotConnectionCreated);
0084     connect(m_manager, &SQLManager::connectionAboutToBeClosed, this, &KateSQLView::slotConnectionAboutToBeClosed);
0085     connect(m_connectionsComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &KateSQLView::slotConnectionChanged);
0086 
0087     stateChanged(QStringLiteral("has_connection_selected"), KXMLGUIClient::StateReverse);
0088 }
0089 
0090 KateSQLView::~KateSQLView()
0091 {
0092     m_mainWindow->guiFactory()->removeClient(this);
0093 
0094     delete m_outputToolView;
0095     delete m_schemaBrowserToolView;
0096 
0097     delete m_manager;
0098 }
0099 
0100 void KateSQLView::setupActions()
0101 {
0102     QAction *action;
0103     KActionCollection *collection = actionCollection();
0104 
0105     action = collection->addAction(QStringLiteral("connection_create"));
0106     action->setText(i18nc("@action:inmenu", "Add Connection..."));
0107     action->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
0108     connect(action, &QAction::triggered, this, &KateSQLView::slotConnectionCreate);
0109 
0110     action = collection->addAction(QStringLiteral("connection_remove"));
0111     action->setText(i18nc("@action:inmenu", "Remove Connection"));
0112     action->setIcon(QIcon::fromTheme(QStringLiteral("list-remove")));
0113     connect(action, &QAction::triggered, this, &KateSQLView::slotConnectionRemove);
0114 
0115     action = collection->addAction(QStringLiteral("connection_edit"));
0116     action->setText(i18nc("@action:inmenu", "Edit Connection..."));
0117     action->setIcon(QIcon::fromTheme(QStringLiteral("configure")));
0118     connect(action, &QAction::triggered, this, &KateSQLView::slotConnectionEdit);
0119 
0120     action = collection->addAction(QStringLiteral("connection_reconnect"));
0121     action->setText(i18nc("@action:inmenu", "Reconnect"));
0122     action->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh")));
0123     connect(action, &QAction::triggered, this, &KateSQLView::slotConnectionReconnect);
0124 
0125     QWidgetAction *wa = new QWidgetAction(this);
0126     collection->addAction(QStringLiteral("connection_chooser"), wa);
0127     wa->setText(i18nc("@action:intoolbar", "Connection"));
0128     wa->setDefaultWidget(m_connectionsComboBox);
0129 
0130     action = collection->addAction(QStringLiteral("query_run"));
0131     action->setText(i18nc("@action:inmenu", "Run Query"));
0132     action->setIcon(QIcon::fromTheme(QStringLiteral("quickopen")));
0133     connect(action, &QAction::triggered, this, &KateSQLView::slotRunQuery);
0134 
0135     /// TODO: stop sql query
0136     //   action = collection->addAction("sql_stop");
0137     //   action->setText( i18n("Stop query") );
0138     //   action->setIcon( KIcon("process-stop") );
0139     //   action->setShortcut( QKeySequence(Qt::ALT | Qt::Key_F5) );
0140     //   connect( action , SIGNAL(triggered()) , this , SLOT(stopQuery()));
0141 }
0142 
0143 void KateSQLView::slotSQLMenuAboutToShow()
0144 {
0145     qDeleteAll(m_connectionsGroup->actions());
0146 
0147     QMenu *sqlMenu = static_cast<QMenu *>(factory()->container(QStringLiteral("SQL"), this));
0148     QAction *before = action("query_run");
0149     QAbstractItemModel *model = m_manager->connectionModel();
0150 
0151     int rows = model->rowCount(QModelIndex());
0152 
0153     for (int row = 0; row < rows; row++) {
0154         QModelIndex index = model->index(row, 0, QModelIndex());
0155 
0156         Q_ASSERT(index.isValid());
0157 
0158         QString connectionName = index.data(Qt::DisplayRole).toString();
0159 
0160         QAction *act = new QAction(connectionName, m_connectionsGroup);
0161         act->setCheckable(true);
0162 
0163         if (m_connectionsComboBox->currentText() == connectionName) {
0164             act->setChecked(true);
0165         }
0166 
0167         sqlMenu->insertAction(before, act);
0168     }
0169 
0170     sqlMenu->insertSeparator(before);
0171 }
0172 
0173 void KateSQLView::slotConnectionSelectedFromMenu(QAction *action)
0174 {
0175     m_connectionsComboBox->setCurrentItem(action->text());
0176 }
0177 
0178 void KateSQLView::slotConnectionChanged(int index)
0179 {
0180     if (index >= 0) {
0181         const QString connection = m_connectionsComboBox->itemText(index);
0182         stateChanged(QStringLiteral("has_connection_selected"), (connection.isEmpty()) ? KXMLGUIClient::StateReverse : KXMLGUIClient::StateNoReverse);
0183 
0184         m_schemaBrowserWidget->schemaWidget()->buildTree(connection);
0185     }
0186 }
0187 
0188 void KateSQLView::slotGlobalSettingsChanged()
0189 {
0190     m_outputWidget->dataOutputWidget()->model()->readConfig();
0191 }
0192 
0193 void KateSQLView::readSessionConfig(KConfigGroup const &group)
0194 {
0195     m_manager->loadConnections(group);
0196 
0197     QString lastConnection = group.readEntry("LastUsed");
0198 
0199     if (m_connectionsComboBox->contains(lastConnection)) {
0200         m_connectionsComboBox->setCurrentItem(lastConnection);
0201     }
0202 }
0203 
0204 void KateSQLView::writeSessionConfig(KConfigGroup &group)
0205 {
0206     group.deleteGroup(QLatin1String());
0207 
0208     KConfigGroup globalConfig(KSharedConfig::openConfig(), QStringLiteral("KateSQLPlugin"));
0209     bool saveConnections = globalConfig.readEntry("SaveConnections", true);
0210 
0211     if (saveConnections) {
0212         m_manager->saveConnections(&group);
0213 
0214         group.writeEntry("LastUsed", m_connectionsComboBox->currentText());
0215     }
0216     group.config()->sync();
0217 }
0218 
0219 void KateSQLView::slotConnectionCreate()
0220 {
0221     Connection c;
0222 
0223     ConnectionWizard wizard(m_manager, &c);
0224 
0225     if (wizard.exec() != QDialog::Accepted) {
0226         return;
0227     }
0228 
0229     for (int i = 1; QSqlDatabase::contains(c.name); i++) {
0230         c.name = QStringLiteral("%1 (%2)").arg(c.name).arg(i);
0231     }
0232 
0233     m_manager->createConnection(c);
0234 
0235     if (m_manager->storeCredentials(c) != SQLManager::K_WALLET_CONNECTION_SUCCESSFUL) {
0236         qDebug() << "Connection credentials not saved";
0237     }
0238 }
0239 
0240 void KateSQLView::slotConnectionEdit()
0241 {
0242     int i = m_connectionsComboBox->currentIndex();
0243 
0244     if (i == -1) {
0245         return;
0246     }
0247 
0248     ConnectionModel *model = m_manager->connectionModel();
0249     Connection c = model->data(model->index(i), Qt::UserRole).value<Connection>();
0250 
0251     QString previousName = c.name;
0252 
0253     ConnectionWizard wizard(m_manager, &c);
0254 
0255     if (wizard.exec() != QDialog::Accepted) {
0256         return;
0257     }
0258 
0259     m_manager->removeConnection(previousName);
0260     m_manager->createConnection(c);
0261 
0262     if (m_manager->storeCredentials(c) != SQLManager::K_WALLET_CONNECTION_SUCCESSFUL) {
0263         qDebug() << "Connection credentials not saved";
0264     }
0265 }
0266 
0267 void KateSQLView::slotConnectionRemove()
0268 {
0269     QString connection = m_connectionsComboBox->currentText();
0270 
0271     if (!connection.isEmpty()) {
0272         m_manager->removeConnection(connection);
0273     }
0274 }
0275 
0276 void KateSQLView::slotConnectionReconnect()
0277 {
0278     QString connection = m_connectionsComboBox->currentText();
0279 
0280     if (!connection.isEmpty()) {
0281         m_manager->reopenConnection(connection);
0282     }
0283 }
0284 
0285 void KateSQLView::slotConnectionAboutToBeClosed(const QString &name)
0286 {
0287     /// must delete the QSqlQuery object inside the model before closing connection
0288 
0289     if (name == m_currentResultsetConnection) {
0290         m_outputWidget->dataOutputWidget()->clearResults();
0291     }
0292 }
0293 
0294 void KateSQLView::slotRunQuery()
0295 {
0296     /// TODO:
0297     /// bind parameters dialog?
0298 
0299     QString connection = m_connectionsComboBox->currentText();
0300 
0301     if (connection.isEmpty()) {
0302         slotConnectionCreate();
0303         return;
0304     }
0305 
0306     KTextEditor::View *view = m_mainWindow->activeView();
0307 
0308     if (!view) {
0309         return;
0310     }
0311 
0312     QString text = (view->selection()) ? view->selectionText() : view->document()->text();
0313     text = text.trimmed();
0314 
0315     if (text.isEmpty()) {
0316         return;
0317     }
0318 
0319     m_manager->runQuery(text, connection);
0320 }
0321 
0322 void KateSQLView::slotError(const QString &message)
0323 {
0324     m_outputWidget->textOutputWidget()->showErrorMessage(message);
0325     m_outputWidget->setCurrentWidget(m_outputWidget->textOutputWidget());
0326     m_mainWindow->showToolView(m_outputToolView);
0327 }
0328 
0329 void KateSQLView::slotSuccess(const QString &message)
0330 {
0331     m_outputWidget->textOutputWidget()->showSuccessMessage(message);
0332     m_outputWidget->setCurrentWidget(m_outputWidget->textOutputWidget());
0333     m_mainWindow->showToolView(m_outputToolView);
0334 }
0335 
0336 void KateSQLView::slotQueryActivated(QSqlQuery &query, const QString &connection)
0337 {
0338     if (query.isSelect()) {
0339         m_currentResultsetConnection = connection;
0340 
0341         m_outputWidget->dataOutputWidget()->showQueryResultSets(query);
0342         m_outputWidget->setCurrentWidget(m_outputWidget->dataOutputWidget());
0343         m_mainWindow->showToolView(m_outputToolView);
0344     }
0345 }
0346 
0347 void KateSQLView::slotConnectionCreated(const QString &name)
0348 {
0349     m_connectionsComboBox->setCurrentItem(name);
0350 
0351     m_schemaBrowserWidget->schemaWidget()->buildTree(name);
0352 }
0353 
0354 // END KateSQLView
0355 
0356 #include "moc_katesqlview.cpp"