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"