File indexing completed on 2024-05-12 05:36:48
0001 /* 0002 SPDX-FileCopyrightText: 2023 ivan tkachenko <me@ratijas.tk> 0003 SPDX-FileCopyrightText: 2023 David Edmundson <davidedmundson@kde.org> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include <QApplication> 0009 #include <QCommandLineOption> 0010 #include <QCommandLineParser> 0011 #include <QCoreApplication> 0012 #include <QDir> 0013 #include <QQmlAbstractUrlInterceptor> 0014 #include <QQmlComponent> 0015 #include <QQmlContext> 0016 #include <QQmlEngine> 0017 #include <QQuickItem> 0018 #include <QQuickView> 0019 0020 #include <QScopedPointer> 0021 #include <QStringList> 0022 #include <QTimer> 0023 0024 #include <KDirWatch> 0025 #include <KLocalizedContext> 0026 #include <KLocalizedString> 0027 0028 #include <PlasmaQuick/QuickViewSharedEngine> 0029 #include <PlasmaQuick/SharedQmlEngine> 0030 0031 #include <stdio.h> 0032 0033 void noFilesGiven() 0034 { 0035 printf("kqml: No files specified. Terminating.\n"); 0036 exit(1); 0037 } 0038 0039 class QmlFileChangeWatcher : public QObject, public QQmlAbstractUrlInterceptor 0040 { 0041 Q_OBJECT 0042 public: 0043 QmlFileChangeWatcher(std::shared_ptr<QQmlEngine>, QObject *parent); 0044 QUrl intercept(const QUrl &path, DataType type) override; 0045 0046 Q_SIGNALS: 0047 void dirty(); 0048 0049 private: 0050 void init(); 0051 std::unique_ptr<KDirWatch> m_fileWatcher; 0052 QTimer m_resetTimer; 0053 }; 0054 0055 int main(int argc, char *argv[]) 0056 { 0057 QApplication app(argc, argv); 0058 0059 app.setApplicationName("KDE QML Runtime"); 0060 app.setOrganizationName("KDE"); 0061 app.setOrganizationDomain("kde.org"); 0062 QApplication::setApplicationVersion(QLatin1String(PROJECT_VERSION)); 0063 0064 QStringList files; 0065 0066 // Handle main arguments 0067 QCommandLineParser parser; 0068 parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions); 0069 parser.setOptionsAfterPositionalArgumentsMode(QCommandLineParser::ParseAsPositionalArguments); 0070 parser.addHelpOption(); 0071 parser.addVersionOption(); 0072 0073 QCommandLineOption applicationDomainOption(QStringList{QStringLiteral("d"), QStringLiteral("domain")}, 0074 QStringLiteral("The main localization domain"), 0075 QStringLiteral("domain")); 0076 parser.addOption(applicationDomainOption); 0077 0078 // Positional arguments 0079 parser.addPositionalArgument("files", QStringLiteral("Any number of QML files can be loaded. They will share the same engine."), "[files...]"); 0080 parser.addPositionalArgument("args", 0081 QStringLiteral("Arguments after '--' are ignored, but passed through to the application.arguments variable in QML."), 0082 "[-- args...]"); 0083 0084 parser.process(app); 0085 0086 QString applicationDomain; 0087 if (parser.isSet(applicationDomainOption)) { 0088 applicationDomain = parser.value(applicationDomainOption); 0089 } else { 0090 applicationDomain = QStringLiteral("kqml"); 0091 } 0092 0093 for (QString posArg : parser.positionalArguments()) { 0094 if (posArg == QLatin1String("--")) { 0095 break; 0096 } else { 0097 files.append(posArg); 0098 } 0099 } 0100 0101 if (files.size() <= 0) { 0102 noFilesGiven(); 0103 } 0104 0105 auto engine = PlasmaQuick::SharedQmlEngine().engine(); 0106 auto watcher = new QmlFileChangeWatcher(engine, &app); 0107 QObject::connect(watcher, &QmlFileChangeWatcher::dirty, [&engine, files]() { 0108 engine->clearComponentCache(); 0109 // engine->clearSingletons(); 0110 }); 0111 0112 // Load files 0113 for (const QString &path : std::as_const(files)) { 0114 QUrl url = QUrl::fromUserInput(path, QDir::currentPath(), QUrl::AssumeLocalFile); 0115 auto window = new PlasmaQuick::QuickViewSharedEngine(); 0116 window->setTranslationDomain(applicationDomain); 0117 window->setTitle(url.fileName()); 0118 window->setSource(url); 0119 window->show(); 0120 0121 QObject::connect(watcher, &QmlFileChangeWatcher::dirty, window, [window]() { 0122 window->setSource(QUrl()); 0123 delete window->rootObject(); 0124 }); 0125 0126 QObject::connect( 0127 watcher, 0128 &QmlFileChangeWatcher::dirty, 0129 window, 0130 [window, url]() { 0131 qDebug() << "Reloading"; 0132 qDebug() << "-------------------"; 0133 window->setSource(url); 0134 }, 0135 Qt::QueuedConnection); 0136 0137 QObject::connect(window, &PlasmaQuick::QuickViewSharedEngine::statusChanged, window, [window](QQmlComponent::Status status) { 0138 if (status == QQmlComponent::Error) { 0139 qWarning() << "Error loading file"; 0140 } 0141 }); 0142 // status changed 0143 } 0144 0145 return app.exec(); 0146 } 0147 0148 QmlFileChangeWatcher::QmlFileChangeWatcher(std::shared_ptr<QQmlEngine> engine, QObject *parent) 0149 : QObject(parent) 0150 { 0151 engine->addUrlInterceptor(this); 0152 m_resetTimer.setInterval(1000); 0153 m_resetTimer.setSingleShot(true); 0154 connect(&m_resetTimer, &QTimer::timeout, this, [this, engine]() { 0155 // reset watched files 0156 init(); 0157 Q_EMIT dirty(); 0158 }); 0159 init(); 0160 } 0161 0162 void QmlFileChangeWatcher::init() 0163 { 0164 m_fileWatcher.reset(new KDirWatch(this)); 0165 connect(m_fileWatcher.get(), &KDirWatch::dirty, this, [this]() { 0166 if (!m_resetTimer.isActive()) { 0167 m_resetTimer.start(); 0168 } 0169 }); 0170 } 0171 0172 QUrl QmlFileChangeWatcher::intercept(const QUrl &path, DataType type) 0173 { 0174 switch (type) { 0175 case QmlFile: 0176 case JavaScriptFile: 0177 case QmldirFile: 0178 m_fileWatcher->addFile(path.toLocalFile()); 0179 break; 0180 default: 0181 break; 0182 } 0183 return path; 0184 } 0185 0186 #include "main.moc"