File indexing completed on 2024-05-12 05:43:33

0001 /*
0002     Copyright (C) 2015 Volker Krause <vkrause@kde.org>
0003 
0004     This program is free software; you can redistribute it and/or modify it
0005     under the terms of the GNU Library General Public License as published by
0006     the Free Software Foundation; either version 2 of the License, or (at your
0007     option) any later version.
0008 
0009     This program is distributed in the hope that it will be useful, but WITHOUT
0010     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0011     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
0012     License for more details.
0013 
0014     You should have received a copy of the GNU General Public License
0015     along with this program.  If not, see <https://www.gnu.org/licenses/>.
0016 */
0017 
0018 #include "codenavigator.h"
0019 
0020 #include <QAction>
0021 #include <QInputDialog>
0022 #include <QMenu>
0023 #include <QProcess>
0024 #include <QSettings>
0025 #include <QStandardPaths>
0026 #include <QUrl>
0027 
0028 struct ide_settings_t {
0029     const char* const app;
0030     const char* const args;
0031     const char* const name;
0032     const char* const icon;
0033 };
0034 
0035 static const ide_settings_t ide_settings[] {
0036     { "kdevelop", "%f:%l", QT_TRANSLATE_NOOP("CodeNavigator", "KDevelop"), "kdevelop" },
0037     { "kate", "%f --line %l", QT_TRANSLATE_NOOP("CodeNavigator", "Kate"), "kate" },
0038     { "kwrite", "%f --line %l", QT_TRANSLATE_NOOP("CodeNavigator", "KWrite"), nullptr },
0039     { "qtcreator", "%f", QT_TRANSLATE_NOOP("CodeNavigator", "Qt Creator"), nullptr }
0040 };
0041 
0042 static const int ide_settings_size = sizeof(ide_settings) / sizeof(ide_settings_t);
0043 
0044 
0045 bool CodeNavigator::isValid()
0046 {
0047     return true; // TODO
0048 }
0049 
0050 void CodeNavigator::goTo(const QString& filePath, int line)
0051 {
0052     QSettings settings;
0053     settings.beginGroup(QStringLiteral("CodeNavigator"));
0054     const auto ideIdx = settings.value(QStringLiteral("IDE"), -1).toInt();
0055 
0056     QString command;
0057     if (ideIdx >= 0 && ideIdx < ide_settings_size) {
0058         command += ide_settings[ideIdx].app;
0059         command += ' ';
0060         command += ide_settings[ideIdx].args;
0061     } else {
0062         command = settings.value(QStringLiteral("CustomCommand")).toString();
0063     }
0064 
0065     command.replace(QLatin1String("%f"), filePath);
0066     command.replace(QLatin1String("%l"), QString::number(std::max(0, line)));
0067 
0068     if (!command.isEmpty())
0069         QProcess::startDetached(command);
0070 }
0071 
0072 void CodeNavigator::goTo(const QUrl& url)
0073 {
0074     goTo(url.path(), url.fragment().toInt());
0075 }
0076 
0077 QAction* CodeNavigator::configMenu(QWidget *parent)
0078 {
0079     static QAction *configAction = nullptr;
0080     if (!configAction) {
0081         configAction = new QAction(QIcon::fromTheme(QStringLiteral("applications-development")), QObject::tr("Code Navigation"), parent);
0082         auto menu = new QMenu(parent);
0083         auto group = new QActionGroup(parent);
0084         group->setExclusive(true);
0085 
0086         QSettings settings;
0087         settings.beginGroup(QStringLiteral("CodeNavigator"));
0088         const auto currentIdx = settings.value(QStringLiteral("IDE"), -1).toInt();
0089 
0090         for (int i = 0; i < ide_settings_size; ++i) {
0091             auto action = new QAction(menu);
0092             action->setText(QObject::tr(ide_settings[i].name));
0093             if (ide_settings[i].icon)
0094                 action->setIcon(QIcon::fromTheme(ide_settings[i].icon));
0095             action->setCheckable(true);
0096             action->setChecked(currentIdx == i);
0097             action->setData(i);
0098             action->setEnabled(!QStandardPaths::findExecutable(ide_settings[i].app).isEmpty());
0099             group->addAction(action);
0100             menu->addAction(action);
0101         }
0102         menu->addSeparator();
0103 
0104         auto action = new QAction(menu);
0105         action->setText(QObject::tr("Custom..."));
0106         action->setCheckable(true);
0107         action->setChecked(currentIdx == -1);
0108         group->addAction(action);
0109         menu->addAction(action);
0110 
0111         QObject::connect(group, &QActionGroup::triggered, [parent](QAction *action) {
0112             QSettings settings;
0113             settings.beginGroup(QStringLiteral("CodeNavigator"));
0114 
0115             if (!action->data().isValid()) {
0116                 const auto customCmd = QInputDialog::getText(
0117                     parent, QObject::tr("Custom Code Navigation"),
0118                     QObject::tr("Specify command to use for code navigation, '%f' will be replaced by the file name, '%l' by the line number."),
0119                     QLineEdit::Normal, settings.value(QStringLiteral("CustomCommand")).toString()
0120                 );
0121                 if (!customCmd.isEmpty()) {
0122                     settings.setValue(QStringLiteral("CustomCommand"), customCmd);
0123                     settings.setValue(QStringLiteral("IDE"), -1);
0124                 }
0125                 return;
0126             }
0127 
0128             const auto defaultIdx = action->data().toInt();
0129             settings.setValue(QStringLiteral("IDE"), defaultIdx);
0130         });
0131 
0132         configAction->setMenu(menu);
0133     }
0134 
0135     return configAction;
0136 }