File indexing completed on 2024-04-28 05:49:36

0001 /*
0002     SPDX-FileCopyrightText: 2022 Christoph Cullmann <cullmann@kde.org>
0003     SPDX-FileCopyrightText: 2022 Waqar Ahmed <waqar.17a@gmail.com>
0004     SPDX-License-Identifier: MIT
0005 */
0006 
0007 #include "ktexteditor_utils.h"
0008 #include "diagnostics/diagnosticview.h"
0009 #include "diffwidget.h"
0010 
0011 #include <QDir>
0012 #include <QFontDatabase>
0013 #include <QIcon>
0014 #include <QMimeDatabase>
0015 #include <QPointer>
0016 #include <QScrollBar>
0017 #include <QVariant>
0018 
0019 #include <KActionCollection>
0020 #include <KLocalizedString>
0021 #include <KTextEditor/Application>
0022 #include <KTextEditor/Editor>
0023 #include <KTextEditor/MainWindow>
0024 #include <KTextEditor/Plugin>
0025 #include <KTextEditor/View>
0026 #include <KXMLGUIFactory>
0027 
0028 namespace Utils
0029 {
0030 
0031 class KateScrollBarRestorerPrivate
0032 {
0033 public:
0034     explicit KateScrollBarRestorerPrivate(KTextEditor::View *view)
0035     {
0036         // Find KateScrollBar
0037         const auto scrollBars = view->findChildren<QScrollBar *>();
0038         kateScrollBar = [scrollBars] {
0039             for (auto scrollBar : scrollBars) {
0040                 if (qstrcmp(scrollBar->metaObject()->className(), "KateScrollBar") == 0) {
0041                     return scrollBar;
0042                 }
0043             }
0044             return static_cast<QScrollBar *>(nullptr);
0045         }();
0046 
0047         if (kateScrollBar) {
0048             oldScrollValue = kateScrollBar->value();
0049         }
0050     }
0051 
0052     void restore()
0053     {
0054         if (restored) {
0055             return;
0056         }
0057 
0058         if (kateScrollBar) {
0059             kateScrollBar->setValue(oldScrollValue);
0060         }
0061         restored = true;
0062     }
0063 
0064     ~KateScrollBarRestorerPrivate()
0065     {
0066         restore();
0067     }
0068 
0069 private:
0070     QPointer<QScrollBar> kateScrollBar = nullptr;
0071     int oldScrollValue = 0;
0072     bool restored = false;
0073 };
0074 
0075 KateScrollBarRestorer::KateScrollBarRestorer(KTextEditor::View *view)
0076     : d(new KateScrollBarRestorerPrivate(view))
0077 {
0078 }
0079 
0080 void KateScrollBarRestorer::restore()
0081 {
0082     d->restore();
0083 }
0084 
0085 KateScrollBarRestorer::~KateScrollBarRestorer()
0086 {
0087     delete d;
0088 }
0089 
0090 QFont editorFont()
0091 {
0092     if (KTextEditor::Editor::instance()) {
0093         return KTextEditor::Editor::instance()->font();
0094     }
0095     qWarning() << __func__ << "Editor::instance() is null! falling back to system fixed font";
0096     return QFontDatabase::systemFont(QFontDatabase::FixedFont);
0097 }
0098 
0099 KATE_PRIVATE_EXPORT KTextEditor::Range getVisibleRange(KTextEditor::View *view)
0100 {
0101     Q_ASSERT(view);
0102     auto doc = view->document();
0103     auto first = view->firstDisplayedLine();
0104     auto last = view->lastDisplayedLine();
0105     auto lastLineLen = doc->line(last).size();
0106     return KTextEditor::Range(first, 0, last, lastLineLen);
0107 }
0108 
0109 QIcon iconForDocument(KTextEditor::Document *doc)
0110 {
0111     // simple modified indicator if modified
0112     QIcon icon;
0113     if (doc->isModified()) {
0114         icon = QIcon::fromTheme(QStringLiteral("modified"));
0115     }
0116 
0117     // else mime-type icon
0118     else {
0119         icon = QIcon::fromTheme(QMimeDatabase().mimeTypeForName(doc->mimeType()).iconName());
0120     }
0121 
0122     // ensure we always have a valid icon
0123     if (icon.isNull()) {
0124         icon = QIcon::fromTheme(QStringLiteral("text-plain"));
0125     }
0126     return icon;
0127 }
0128 
0129 QAction *toolviewShowAction(KTextEditor::MainWindow *mainWindow, const QString &toolviewName)
0130 {
0131     Q_ASSERT(mainWindow);
0132 
0133     const auto clients = mainWindow->guiFactory()->clients();
0134     static const QString prefix = QStringLiteral("kate_mdi_toolview_");
0135     auto it = std::find_if(clients.begin(), clients.end(), [](const KXMLGUIClient *c) {
0136         return c->componentName() == QStringLiteral("toolviewmanager");
0137     });
0138 
0139     if (it == clients.end()) {
0140         qWarning() << Q_FUNC_INFO << "Unexpected unable to find toolviewmanager KXMLGUIClient, toolviewName: " << toolviewName;
0141         return nullptr;
0142     }
0143     return (*it)->actionCollection()->action(prefix + toolviewName);
0144 }
0145 
0146 QWidget *toolviewForName(KTextEditor::MainWindow *mainWindow, const QString &toolviewName)
0147 {
0148     QWidget *toolView = nullptr;
0149     QMetaObject::invokeMethod(mainWindow->parent(), "toolviewForName", Qt::DirectConnection, Q_RETURN_ARG(QWidget *, toolView), Q_ARG(QString, toolviewName));
0150     return toolView;
0151 }
0152 
0153 void showMessage(const QString &message, const QIcon &icon, const QString &category, MessageType type, KTextEditor::MainWindow *mainWindow)
0154 {
0155     Q_ASSERT(type >= MessageType::Log && type <= MessageType::Error);
0156     QVariantMap msg;
0157     static const QString msgToString[] = {
0158         QStringLiteral("Log"),
0159         QStringLiteral("Info"),
0160         QStringLiteral("Warning"),
0161         QStringLiteral("Error"),
0162     };
0163     msg.insert(QStringLiteral("type"), msgToString[type]);
0164     msg.insert(QStringLiteral("category"), category);
0165     msg.insert(QStringLiteral("categoryIcon"), icon);
0166     msg.insert(QStringLiteral("text"), message);
0167     showMessage(msg, mainWindow);
0168 }
0169 
0170 void showMessage(const QVariantMap &map, KTextEditor::MainWindow *mainWindow)
0171 {
0172     if (!mainWindow) {
0173         mainWindow = KTextEditor::Editor::instance()->application()->activeMainWindow();
0174     }
0175     QMetaObject::invokeMethod(mainWindow->parent(), "showMessage", Qt::DirectConnection, Q_ARG(QVariantMap, map));
0176 }
0177 
0178 void showDiff(const QByteArray &diff, const DiffParams &params, KTextEditor::MainWindow *mainWindow)
0179 {
0180     DiffWidgetManager::openDiff(diff, params, mainWindow);
0181 }
0182 
0183 void addWidget(QWidget *widget, KTextEditor::MainWindow *mainWindow)
0184 {
0185     QMetaObject::invokeMethod(mainWindow->parent(), "addWidget", Qt::DirectConnection, Q_ARG(QWidget *, widget));
0186 }
0187 
0188 void activateWidget(QWidget *widget, KTextEditor::MainWindow *mainWindow)
0189 {
0190     QMetaObject::invokeMethod(mainWindow->parent(), "activateWidget", Qt::DirectConnection, Q_ARG(QWidget *, widget));
0191 }
0192 
0193 QWidgetList widgets(KTextEditor::MainWindow *mainWindow)
0194 {
0195     QWidgetList ret;
0196     QMetaObject::invokeMethod(mainWindow->parent(), "widgets", Qt::DirectConnection, Q_RETURN_ARG(QWidgetList, ret));
0197     return ret;
0198 }
0199 
0200 void insertWidgetInStatusbar(QWidget *widget, KTextEditor::MainWindow *mainWindow)
0201 {
0202     QMetaObject::invokeMethod(mainWindow->parent(), "insertWidgetInStatusbar", Qt::DirectConnection, Q_ARG(QWidget *, widget));
0203 }
0204 
0205 void addPositionToHistory(const QUrl &url, KTextEditor::Cursor c, KTextEditor::MainWindow *mainWindow)
0206 {
0207     QMetaObject::invokeMethod(mainWindow->parent(), "addPositionToHistory", Qt::DirectConnection, Q_ARG(QUrl, url), Q_ARG(KTextEditor::Cursor, c));
0208 }
0209 
0210 QString projectBaseDirForDocument(KTextEditor::Document *doc)
0211 {
0212     QString baseDir;
0213     if (QObject *plugin = KTextEditor::Editor::instance()->application()->plugin(QStringLiteral("kateprojectplugin"))) {
0214         QMetaObject::invokeMethod(plugin, "projectBaseDirForDocument", Q_RETURN_ARG(QString, baseDir), Q_ARG(KTextEditor::Document *, doc));
0215     }
0216     return baseDir;
0217 }
0218 
0219 QVariantMap projectMapForDocument(KTextEditor::Document *doc)
0220 {
0221     QVariantMap projectMap;
0222     if (QObject *plugin = KTextEditor::Editor::instance()->application()->plugin(QStringLiteral("kateprojectplugin"))) {
0223         QMetaObject::invokeMethod(plugin, "projectMapForDocument", Q_RETURN_ARG(QVariantMap, projectMap), Q_ARG(KTextEditor::Document *, doc));
0224     }
0225     return projectMap;
0226 }
0227 
0228 QString niceFileNameWithPath(const QUrl &url)
0229 {
0230     // we want some filename @ folder output to have chance to keep important stuff even on elide
0231     if (url.isLocalFile()) {
0232         // perhaps shorten the path
0233         const QString homePath = QDir::homePath();
0234         QString path = url.toString(QUrl::RemoveFilename | QUrl::PreferLocalFile | QUrl::StripTrailingSlash);
0235         if (path.startsWith(homePath)) {
0236             path = QLatin1String("~") + path.right(path.length() - homePath.length());
0237         }
0238         return url.fileName() + QStringLiteral(" @ ") + path;
0239     }
0240     return url.toDisplayString();
0241 }
0242 }