File indexing completed on 2024-05-05 05:51:37

0001 /* Description : Kate CTags plugin
0002  *
0003  * SPDX-FileCopyrightText: 2008-2011 Kare Sars <kare.sars@iki.fi>
0004  *
0005  * This program is free software; you can redistribute it and/or
0006  * modify it under the terms of the GNU General Public
0007  * License as published by the Free Software Foundation; either
0008  * version 2.1 of the License, or (at your option) version 3, or any
0009  * later version accepted by the membership of KDE e.V. (or its
0010  * successor approved by the membership of KDE e.V.), which shall
0011  * act as a proxy defined in Section 6 of version 3 of the license.
0012  *
0013  * This program is distributed in the hope that it will be useful,
0014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0016  * General Public License for more details.
0017  *
0018  * You should have received a copy of the GNU General Public
0019  * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
0020  */
0021 
0022 #include "kate_ctags_plugin.h"
0023 
0024 #include "hostprocess.h"
0025 
0026 #include <QCheckBox>
0027 #include <QFileDialog>
0028 
0029 #include <KConfigGroup>
0030 #include <KSharedConfig>
0031 
0032 #include <KLocalizedString>
0033 #include <KMessageBox>
0034 #include <ktexteditor/editor.h>
0035 
0036 #include <KPluginFactory>
0037 
0038 K_PLUGIN_FACTORY_WITH_JSON(KateCTagsPluginFactory, "katectagsplugin.json", registerPlugin<KateCTagsPlugin>();)
0039 
0040 /******************************************************************/
0041 KateCTagsPlugin::KateCTagsPlugin(QObject *parent, const QVariantList &)
0042     : KTextEditor::Plugin(parent)
0043 {
0044     // FIXME KF5
0045     // KGlobal::locale()->insertCatalog("kate-ctags-plugin");
0046 }
0047 
0048 /******************************************************************/
0049 QObject *KateCTagsPlugin::createView(KTextEditor::MainWindow *mainWindow)
0050 {
0051     m_view = new KateCTagsView(this, mainWindow);
0052     return m_view;
0053 }
0054 
0055 /******************************************************************/
0056 KTextEditor::ConfigPage *KateCTagsPlugin::configPage(int number, QWidget *parent)
0057 {
0058     if (number != 0) {
0059         return nullptr;
0060     }
0061     return new KateCTagsConfigPage(parent);
0062 }
0063 
0064 /******************************************************************/
0065 void KateCTagsPlugin::readConfig()
0066 {
0067 }
0068 
0069 /******************************************************************/
0070 KateCTagsConfigPage::KateCTagsConfigPage(QWidget *parent)
0071     : KTextEditor::ConfigPage(parent)
0072 {
0073     m_confUi.setupUi(this);
0074     m_confUi.cmdEdit->setText(DEFAULT_CTAGS_CMD);
0075     connect(m_confUi.cmdEdit, &QLineEdit::textEdited, this, &KateCTagsConfigPage::changed);
0076 
0077     m_confUi.addButton->setToolTip(i18n("Add a directory to index."));
0078     m_confUi.addButton->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
0079 
0080     m_confUi.delButton->setToolTip(i18n("Remove a directory."));
0081     m_confUi.delButton->setIcon(QIcon::fromTheme(QStringLiteral("list-remove")));
0082 
0083     m_confUi.updateDB->setToolTip(i18n("(Re-)generate the common CTags database."));
0084     m_confUi.updateDB->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh")));
0085 
0086     connect(m_confUi.updateDB, &QPushButton::clicked, this, &KateCTagsConfigPage::updateGlobalDB);
0087     connect(m_confUi.addButton, &QPushButton::clicked, this, &KateCTagsConfigPage::addGlobalTagTarget);
0088     connect(m_confUi.delButton, &QPushButton::clicked, this, &KateCTagsConfigPage::delGlobalTagTarget);
0089 
0090     connect(&m_proc, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), this, &KateCTagsConfigPage::updateDone);
0091     connect(&m_proc, &QProcess::readyReadStandardError, this, [this]() {
0092         QString error = QString::fromLocal8Bit(m_proc.readAllStandardError());
0093         KMessageBox::error(nullptr, error);
0094     });
0095     reset();
0096 }
0097 
0098 /******************************************************************/
0099 QString KateCTagsConfigPage::name() const
0100 {
0101     return i18n("CTags");
0102 }
0103 
0104 /******************************************************************/
0105 QString KateCTagsConfigPage::fullName() const
0106 {
0107     return i18n("CTags Settings");
0108 }
0109 
0110 /******************************************************************/
0111 QIcon KateCTagsConfigPage::icon() const
0112 {
0113     return QIcon::fromTheme(QStringLiteral("text-x-csrc"));
0114 }
0115 
0116 /******************************************************************/
0117 void KateCTagsConfigPage::apply()
0118 {
0119     KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("CTags"));
0120     config.writeEntry("GlobalCommand", m_confUi.cmdEdit->text());
0121 
0122     config.writeEntry("GlobalNumTargets", m_confUi.targetList->count());
0123 
0124     QString nr;
0125     for (int i = 0; i < m_confUi.targetList->count(); i++) {
0126         nr = QStringLiteral("%1").arg(i, 3);
0127         config.writeEntry(QStringLiteral("GlobalTarget_") + nr, m_confUi.targetList->item(i)->text());
0128     }
0129     config.sync();
0130 }
0131 
0132 /******************************************************************/
0133 void KateCTagsConfigPage::reset()
0134 {
0135     KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("CTags"));
0136     m_confUi.cmdEdit->setText(config.readEntry(QStringLiteral("GlobalCommand"), DEFAULT_CTAGS_CMD));
0137 
0138     int numEntries = config.readEntry(QStringLiteral("GlobalNumTargets"), 0);
0139     QString nr;
0140     QString target;
0141     for (int i = 0; i < numEntries; i++) {
0142         nr = QStringLiteral("%1").arg(i, 3);
0143         target = config.readEntry(QLatin1String("GlobalTarget_") + nr, QString());
0144         if (!listContains(target)) {
0145             new QListWidgetItem(target, m_confUi.targetList);
0146         }
0147     }
0148     config.sync();
0149 }
0150 
0151 /******************************************************************/
0152 void KateCTagsConfigPage::addGlobalTagTarget()
0153 {
0154     QFileDialog dialog;
0155     dialog.setFileMode(QFileDialog::Directory);
0156     // dialog.setMode(KFile::Directory | KFile::Files | KFile::ExistingOnly | KFile::LocalOnly);
0157 
0158     QString dir;
0159     if (m_confUi.targetList->currentItem()) {
0160         dir = m_confUi.targetList->currentItem()->text();
0161     } else if (m_confUi.targetList->item(0)) {
0162         dir = m_confUi.targetList->item(0)->text();
0163     }
0164     dialog.setDirectory(dir);
0165 
0166     // i18n("CTags Database Location"));
0167     if (dialog.exec() != QDialog::Accepted) {
0168         return;
0169     }
0170 
0171     QStringList urls = dialog.selectedFiles();
0172 
0173     for (int i = 0; i < urls.size(); i++) {
0174         if (!listContains(urls[i])) {
0175             new QListWidgetItem(urls[i], m_confUi.targetList);
0176             Q_EMIT changed();
0177         }
0178     }
0179 }
0180 
0181 /******************************************************************/
0182 void KateCTagsConfigPage::delGlobalTagTarget()
0183 {
0184     delete m_confUi.targetList->currentItem();
0185     Q_EMIT changed();
0186 }
0187 
0188 /******************************************************************/
0189 bool KateCTagsConfigPage::listContains(const QString &target)
0190 {
0191     for (int i = 0; i < m_confUi.targetList->count(); i++) {
0192         if (m_confUi.targetList->item(i)->text() == target) {
0193             return true;
0194         }
0195     }
0196     return false;
0197 }
0198 
0199 /******************************************************************/
0200 void KateCTagsConfigPage::updateGlobalDB()
0201 {
0202     if (m_proc.state() != QProcess::NotRunning) {
0203         return;
0204     }
0205 
0206     QStringList targets;
0207     for (int i = 0; i < m_confUi.targetList->count(); i++) {
0208         auto target = m_confUi.targetList->item(i)->text();
0209         if (target.endsWith(QLatin1Char('/')) || target.endsWith(QLatin1Char('\\'))) {
0210             target = target.left(target.size() - 1);
0211         }
0212         targets << target;
0213     }
0214 
0215     QString file = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + QLatin1String("/katectags");
0216     QDir().mkpath(file);
0217     file += QLatin1String("/common_db");
0218 
0219     if (targets.isEmpty()) {
0220         QFile::remove(file);
0221         return;
0222     }
0223 
0224     QStringList arguments = m_proc.splitCommand(m_confUi.cmdEdit->text());
0225     const QString command = arguments.takeFirst();
0226     arguments << QStringLiteral("-f") << file << targets;
0227     startHostProcess(m_proc, command, arguments);
0228 
0229     if (!m_proc.waitForStarted(500)) {
0230         KMessageBox::error(nullptr, i18n("Failed to run. Error: %1, exit code: %2", m_proc.errorString(), m_proc.exitCode()));
0231         return;
0232     }
0233     m_confUi.updateDB->setDisabled(true);
0234     QApplication::setOverrideCursor(QCursor(Qt::BusyCursor));
0235 }
0236 
0237 /******************************************************************/
0238 void KateCTagsConfigPage::updateDone(int exitCode, QProcess::ExitStatus status)
0239 {
0240     if (status == QProcess::CrashExit) {
0241         KMessageBox::error(this, i18n("The CTags executable crashed."));
0242     } else if (exitCode != 0) {
0243         KMessageBox::error(this, i18n("The CTags command exited with code %1", exitCode));
0244     }
0245 
0246     m_confUi.updateDB->setDisabled(false);
0247     QApplication::restoreOverrideCursor();
0248 }
0249 
0250 #include "kate_ctags_plugin.moc"
0251 #include "moc_kate_ctags_plugin.cpp"