Changeset View
Changeset View
Standalone View
Standalone View
plugins/qthelp/qthelpproviderabstract.cpp
Show All 17 Lines | 1 | /* This file is part of KDevelop | |||
---|---|---|---|---|---|
18 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 18 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
19 | Boston, MA 02110-1301, USA. | 19 | Boston, MA 02110-1301, USA. | ||
20 | */ | 20 | */ | ||
21 | 21 | | |||
22 | #include "qthelpprovider.h" | 22 | #include "qthelpprovider.h" | ||
23 | 23 | | |||
24 | #include <QHelpIndexModel> | 24 | #include <QHelpIndexModel> | ||
25 | #include <QHelpContentModel> | 25 | #include <QHelpContentModel> | ||
26 | #include <QHelpSearchEngine> | ||||
26 | 27 | | |||
27 | #include <QStandardPaths> | 28 | #include <QStandardPaths> | ||
28 | 29 | | |||
30 | #include <QString> | ||||
31 | #include <QProcess> | ||||
32 | #include <QApplication> | ||||
33 | | ||||
29 | #include <language/duchain/duchain.h> | 34 | #include <language/duchain/duchain.h> | ||
30 | #include <language/duchain/declaration.h> | 35 | #include <language/duchain/declaration.h> | ||
31 | #include <language/duchain/duchainlock.h> | 36 | #include <language/duchain/duchainlock.h> | ||
32 | #include <language/duchain/parsingenvironment.h> | 37 | #include <language/duchain/parsingenvironment.h> | ||
33 | 38 | | |||
34 | #include "qthelpnetwork.h" | 39 | #include "qthelpnetwork.h" | ||
35 | #include "qthelpdocumentation.h" | 40 | #include "qthelpdocumentation.h" | ||
36 | #include "debug.h" | 41 | #include "debug.h" | ||
37 | 42 | | |||
38 | using namespace KDevelop; | 43 | using namespace KDevelop; | ||
39 | 44 | | |||
45 | // subclass QProcess so we can be our own exit watchdog | ||||
46 | class ExternalViewerProcess : public QProcess | ||||
47 | { | ||||
48 | Q_OBJECT | ||||
49 | public: | ||||
50 | ExternalViewerProcess(QObject* parent); | ||||
51 | ~ExternalViewerProcess() | ||||
52 | { | ||||
53 | #ifdef Q_OS_UNIX | ||||
54 | qint64 pid = processId(); | ||||
55 | if (pid > 0) { | ||||
56 | QProcess *hup = new QProcess(this); | ||||
57 | hup->startDetached(QString::fromLatin1("kill -1 %1").arg(pid)); | ||||
58 | hup->waitForFinished(500); | ||||
59 | } | ||||
60 | QProcess::waitForFinished(500); | ||||
61 | #endif | ||||
62 | } | ||||
63 | public Q_SLOTS: | ||||
64 | void externalViewerExit(int exitCode, QProcess::ExitStatus exitStatus); | ||||
65 | }; | ||||
66 | | ||||
67 | ExternalViewerProcess* QtHelpProviderAbstract::m_externalViewerProcess = Q_NULLPTR; | ||||
68 | bool QtHelpProviderAbstract::s_useExternalViewer = false; | ||||
69 | | ||||
70 | ExternalViewerProcess::ExternalViewerProcess(QObject *parent) | ||||
71 | : QProcess(parent) | ||||
72 | { | ||||
73 | connect(this, static_cast<void(ExternalViewerProcess::*)(int, QProcess::ExitStatus)>(&ExternalViewerProcess::finished), | ||||
74 | &ExternalViewerProcess::externalViewerExit); | ||||
75 | } | ||||
76 | | ||||
77 | void ExternalViewerProcess::externalViewerExit(int exitCode, QProcess::ExitStatus exitStatus) | ||||
78 | { | ||||
79 | if (this == QtHelpProviderAbstract::m_externalViewerProcess) { | ||||
80 | qCDebug(QTHELP) << Q_FUNC_INFO << "externalViewer" << this << "has exited with code" | ||||
81 | << exitCode << "and status" << exitStatus; | ||||
82 | deleteLater(); | ||||
83 | QtHelpProviderAbstract::m_externalViewerProcess = Q_NULLPTR; | ||||
84 | } | ||||
85 | } | ||||
86 | | ||||
40 | QtHelpProviderAbstract::QtHelpProviderAbstract(QObject *parent, const QString &collectionFileName, const QVariantList &args) | 87 | QtHelpProviderAbstract::QtHelpProviderAbstract(QObject *parent, const QString &collectionFileName, const QVariantList &args) | ||
41 | : QObject(parent) | 88 | : QObject(parent) | ||
42 | , m_engine(QStandardPaths::writableLocation(QStandardPaths::DataLocation)+'/'+collectionFileName) | 89 | , m_engine(QStandardPaths::writableLocation(QStandardPaths::DataLocation)+'/'+collectionFileName) | ||
43 | , m_nam(new HelpNetworkAccessManager(&m_engine, this)) | 90 | , m_nam(new HelpNetworkAccessManager(&m_engine, this)) | ||
44 | { | 91 | { | ||
45 | Q_UNUSED(args); | 92 | Q_UNUSED(args); | ||
46 | if( !m_engine.setupData() ) { | 93 | if( !m_engine.setupData() ) { | ||
47 | qCWarning(QTHELP) << "Couldn't setup QtHelp Collection file"; | 94 | qCWarning(QTHELP) << "Couldn't setup QtHelp Collection file"; | ||
48 | } | 95 | } | ||
96 | s_useExternalViewer = false; | ||||
49 | } | 97 | } | ||
50 | 98 | | |||
51 | | ||||
52 | QtHelpProviderAbstract::~QtHelpProviderAbstract() | 99 | QtHelpProviderAbstract::~QtHelpProviderAbstract() | ||
53 | { | 100 | { | ||
54 | } | 101 | } | ||
55 | 102 | | |||
103 | void QtHelpProviderAbstract::setUseExternalViewer(const bool extViewer) | ||||
104 | { | ||||
105 | s_useExternalViewer = extViewer; | ||||
106 | } | ||||
107 | | ||||
108 | ExternalViewerProcess* QtHelpProviderAbstract::externalViewer() const | ||||
109 | { | ||||
110 | // turning off the use of an external help viewer shouldn't terminate | ||||
111 | // an already running viewer process, we just stop using it. | ||||
112 | if (!s_useExternalViewer) { | ||||
113 | return Q_NULLPTR; | ||||
114 | } | ||||
115 | if (!m_externalViewerProcess) { | ||||
116 | m_externalViewerProcess = new ExternalViewerProcess(qApp); | ||||
117 | QStringList args = {"-enableRemoteControl"}; | ||||
118 | m_externalViewerProcess->start(QStandardPaths::findExecutable(QLatin1String("kdevelop-qthelp-viewer")), | ||||
119 | args, QIODevice::WriteOnly|QIODevice::Append); | ||||
120 | if (!m_externalViewerProcess->waitForStarted()) { | ||||
121 | m_externalViewerProcess->deleteLater(); | ||||
122 | m_externalViewerProcess = NULL; | ||||
123 | } | ||||
124 | } | ||||
125 | return m_externalViewerProcess; | ||||
126 | } | ||||
127 | | ||||
128 | bool QtHelpProviderAbstract::externalViewerCommand(const QByteArray& command) const | ||||
129 | { | ||||
130 | if (externalViewer()) { | ||||
131 | return externalViewer()->write(command) >= 0; | ||||
132 | } else { | ||||
133 | return false; | ||||
134 | } | ||||
135 | } | ||||
136 | | ||||
137 | bool QtHelpProviderAbstract::externalViewerCommand(const char* command) const | ||||
138 | { | ||||
139 | if (externalViewer()) { | ||||
140 | return externalViewer()->write(command) >= 0; | ||||
141 | } else { | ||||
142 | return false; | ||||
143 | } | ||||
144 | } | ||||
145 | | ||||
56 | IDocumentation::Ptr QtHelpProviderAbstract::documentationForDeclaration(Declaration* dec) const | 146 | IDocumentation::Ptr QtHelpProviderAbstract::documentationForDeclaration(Declaration* dec) const | ||
57 | { | 147 | { | ||
58 | QtHelpDocumentation::s_provider = const_cast<QtHelpProviderAbstract*>(this); | 148 | QtHelpDocumentation::s_provider = const_cast<QtHelpProviderAbstract*>(this); | ||
59 | if (dec) { | 149 | if (dec) { | ||
60 | static const IndexedString qmlJs("QML/JS"); | 150 | static const IndexedString qmlJs("QML/JS"); | ||
61 | QString id; | 151 | QString id; | ||
62 | 152 | | |||
63 | { | 153 | { | ||
64 | DUChainReadLocker lock; | 154 | DUChainReadLocker lock; | ||
65 | id = dec->qualifiedIdentifier().toString(RemoveTemplateInformation); | 155 | id = dec->qualifiedIdentifier().toString(RemoveTemplateInformation); | ||
66 | if (dec->topContext()->parsingEnvironmentFile()->language() == qmlJs && !id.isEmpty()) | 156 | if (dec->topContext()->parsingEnvironmentFile()->language() == qmlJs && !id.isEmpty()) | ||
67 | id = QLatin1String("QML.") + id; | 157 | id = QLatin1String("QML.") + id; | ||
68 | } | 158 | } | ||
69 | 159 | | |||
70 | if (!id.isEmpty()) { | 160 | if (!id.isEmpty()) { | ||
71 | QMap<QString, QUrl> links = m_engine.linksForIdentifier(id); | 161 | QMap<QString, QUrl> links = m_engine.linksForIdentifier(id); | ||
72 | 162 | | |||
73 | if(!links.isEmpty()) | 163 | if (!links.isEmpty()) { | ||
164 | // if (externalViewer()) { | ||||
165 | // QByteArray ba; | ||||
166 | // const auto urls = links.values(); | ||||
167 | // foreach (const auto url, urls) { | ||||
168 | // if (!url.isEmpty()) { | ||||
169 | // ba.append("setSource " + url.toString().toUtf8() + "\n"); | ||||
170 | // } | ||||
171 | // } | ||||
172 | // qCDebug(QTHELP) << Q_FUNC_INFO << "Id=" << id << "links=" << links << "->" << ba; | ||||
173 | // externalViewerCommand(ba); | ||||
174 | // externalViewerCommand("show contents\n"); | ||||
175 | // externalViewerCommand("syncContents\n"); | ||||
176 | // } | ||||
74 | return IDocumentation::Ptr(new QtHelpDocumentation(id, links)); | 177 | return IDocumentation::Ptr(new QtHelpDocumentation(id, links)); | ||
75 | } | 178 | } | ||
76 | } | 179 | } | ||
180 | } | ||||
77 | 181 | | |||
78 | return {}; | 182 | return {}; | ||
79 | } | 183 | } | ||
80 | 184 | | |||
81 | QAbstractItemModel* QtHelpProviderAbstract::indexModel() const | 185 | QAbstractItemModel* QtHelpProviderAbstract::indexModel() const | ||
82 | { | 186 | { | ||
83 | QtHelpDocumentation::s_provider = const_cast<QtHelpProviderAbstract*>(this); | 187 | QtHelpDocumentation::s_provider = const_cast<QtHelpProviderAbstract*>(this); | ||
84 | return m_engine.indexModel(); | 188 | return m_engine.indexModel(); | ||
85 | } | 189 | } | ||
86 | 190 | | |||
87 | IDocumentation::Ptr QtHelpProviderAbstract::documentationForIndex(const QModelIndex& idx) const | 191 | IDocumentation::Ptr QtHelpProviderAbstract::documentationForIndex(const QModelIndex& idx) const | ||
88 | { | 192 | { | ||
89 | QtHelpDocumentation::s_provider = const_cast<QtHelpProviderAbstract*>(this); | 193 | QtHelpDocumentation::s_provider = const_cast<QtHelpProviderAbstract*>(this); | ||
90 | QString name=idx.data(Qt::DisplayRole).toString(); | 194 | QString name=idx.data(Qt::DisplayRole).toString(); | ||
91 | return IDocumentation::Ptr(new QtHelpDocumentation(name, m_engine.indexModel()->linksForKeyword(name))); | 195 | QMap<QString, QUrl> links = m_engine.indexModel()->linksForKeyword(name); | ||
196 | if(!links.isEmpty() && externalViewer()) { | ||||
197 | QByteArray ba; | ||||
198 | const auto urls = links.values(); | ||||
199 | foreach (const auto url, urls) { | ||||
200 | if (!url.isEmpty()) { | ||||
201 | ba.append("setSource " + url.toString().toUtf8() + "\n"); | ||||
202 | ba.append(QLatin1String("show contents\n")); | ||||
203 | } | ||||
204 | } | ||||
205 | qCWarning(QTHELP) << Q_FUNC_INFO << "name=" << name << "->" << ba; | ||||
206 | externalViewerCommand(ba); | ||||
207 | externalViewerCommand("syncContents\n"); | ||||
208 | } | ||||
209 | return IDocumentation::Ptr(new QtHelpDocumentation(name, links)); | ||||
92 | } | 210 | } | ||
93 | 211 | | |||
94 | void QtHelpProviderAbstract::jumpedTo(const QUrl& newUrl) const | 212 | void QtHelpProviderAbstract::jumpedTo(const QUrl& newUrl) const | ||
95 | { | 213 | { | ||
96 | QtHelpDocumentation::s_provider = const_cast<QtHelpProviderAbstract*>(this); | 214 | QtHelpDocumentation::s_provider = const_cast<QtHelpProviderAbstract*>(this); | ||
97 | QMap<QString, QUrl> info; | 215 | QMap<QString, QUrl> info; | ||
98 | info.insert(newUrl.toString(), newUrl); | 216 | info.insert(newUrl.toString(), newUrl); | ||
99 | IDocumentation::Ptr doc(new QtHelpDocumentation(newUrl.toString(), info)); | 217 | IDocumentation::Ptr doc(new QtHelpDocumentation(newUrl.toString(), info)); | ||
Show All 10 Lines | |||||
110 | { | 228 | { | ||
111 | return !m_engine.registeredDocumentations().isEmpty(); | 229 | return !m_engine.registeredDocumentations().isEmpty(); | ||
112 | } | 230 | } | ||
113 | 231 | | |||
114 | HelpNetworkAccessManager * QtHelpProviderAbstract::networkAccess() const | 232 | HelpNetworkAccessManager * QtHelpProviderAbstract::networkAccess() const | ||
115 | { | 233 | { | ||
116 | return m_nam; | 234 | return m_nam; | ||
117 | } | 235 | } | ||
236 | | ||||
237 | #include "qthelpproviderabstract.moc" |