File indexing completed on 2024-04-28 03:51:15
0001 /*. 0002 SPDX-FileCopyrightText: 2007 Vladimir Kuznetsov <ks.vladimir@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "infobrowser.h" 0008 0009 #include "worldmodel.h" 0010 #include "settings.h" 0011 0012 #include <QAction> 0013 #include <QCoreApplication> 0014 #include <QDesktopServices> 0015 #include <QFile> 0016 #include <QIcon> 0017 #include <QItemSelectionModel> 0018 #include <QStandardPaths> 0019 #include <QVBoxLayout> 0020 0021 #include <KIO/Job> 0022 #include <KLocalizedString> 0023 #include <KToolBar> 0024 0025 InfoBrowser::InfoBrowser(WorldModel* worldModel, QWidget* parent) 0026 : QDockWidget(i18n("Context Info"), parent), 0027 _worldModel(worldModel), _selectionChanged(false) 0028 { 0029 QWidget* widget = new QWidget(this); 0030 setWidget(widget); 0031 0032 QVBoxLayout* layout = new QVBoxLayout(widget); 0033 layout->setContentsMargins(0,0,0,0); 0034 layout->setSpacing(0); 0035 0036 _toolBar = new KToolBar(widget); 0037 layout->addWidget(_toolBar); 0038 _toolBar->setMovable(false); 0039 _toolBar->setFloatable(false); 0040 _toolBar->setIconDimensions(16); 0041 _toolBar->setContextMenuPolicy(Qt::NoContextMenu); 0042 _toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly); 0043 0044 _backAction = _toolBar->addAction(QIcon::fromTheme(QStringLiteral("go-previous")), i18n("Back"), this, SLOT(back())); 0045 _backAction->setEnabled(false); 0046 _forwardAction = _toolBar->addAction(QIcon::fromTheme(QStringLiteral("go-next")), i18n("Forward"), this, SLOT(forward())); 0047 _forwardAction->setEnabled(false); 0048 0049 _toolBar->addSeparator(); 0050 _syncAction = _toolBar->addAction(QIcon::fromTheme(QStringLiteral("goto-page")), i18n("Sync selection"), this, SLOT(syncSelection())); // XXX: icon 0051 _syncAction->setEnabled(false); 0052 _followAction = _toolBar->addAction(QIcon::fromTheme(QStringLiteral("note2")), i18n("Follow selection")/*, this, SLOT(syncSelection(bool))*/); // XXX: icon 0053 _followAction->setCheckable(true); 0054 _followAction->setChecked(true); 0055 0056 _toolBar->addSeparator(); 0057 _execAction = _toolBar->addAction(QIcon::fromTheme(QStringLiteral("system-run")), i18n("Open in Browser"), this, SLOT(openInBrowser())); 0058 _execAction->setEnabled(false); 0059 0060 _htmlBrowser = new QTextBrowser(widget); 0061 _htmlBrowser->setOpenLinks(false); 0062 layout->addWidget(_htmlBrowser); 0063 0064 connect(_htmlBrowser, &QTextBrowser::anchorClicked, this, [=](const QUrl &url){ 0065 openUrl(url); 0066 }); 0067 0068 connect(_worldModel->selectionModel(), &QItemSelectionModel::currentChanged, 0069 this, &InfoBrowser::worldCurrentChanged); 0070 0071 syncSelection(); 0072 } 0073 0074 void InfoBrowser::showEvent(QShowEvent* event) 0075 { 0076 QDockWidget::showEvent(event); 0077 if(_selectionChanged) { 0078 _selectionChanged = false; 0079 QModelIndex current = _worldModel->selectionModel()->currentIndex(); 0080 worldCurrentChanged(current, QModelIndex()); 0081 } 0082 } 0083 0084 void InfoBrowser::worldCurrentChanged(const QModelIndex& /*current*/, const QModelIndex& /*previous*/) 0085 { 0086 if(isVisible()) { 0087 if(_followAction->isChecked()) syncSelection(); 0088 else updateSyncSelection(); 0089 } else { 0090 _selectionChanged = true; 0091 } 0092 } 0093 0094 void InfoBrowser::syncSelection(bool checked) 0095 { 0096 if(checked) { 0097 const QModelIndex current = _worldModel->selectionModel()->currentIndex(); 0098 const QUrl url(QStringLiteral("objinfo:").append(current.data(WorldModel::ClassNameRole).toString())); 0099 openUrl(url, true); 0100 } 0101 } 0102 0103 void InfoBrowser::updateSyncSelection() 0104 { 0105 if(_htmlBrowser->source().scheme() == QLatin1String("objinfo")) { 0106 QModelIndex current = _worldModel->selectionModel()->currentIndex(); 0107 if(_htmlBrowser->source().path() == current.data(WorldModel::ClassNameRole).toString()) { 0108 _syncAction->setEnabled(false); 0109 return; 0110 } 0111 } 0112 _syncAction->setEnabled(true); 0113 } 0114 0115 void InfoBrowser::openUrl(const QUrl& url, bool clearHistory, bool fromHistory) 0116 { 0117 if(url.scheme() == QLatin1String("objinfo")) { 0118 if(clearHistory) { 0119 _forwardHistory.clear(); 0120 _forwardAction->setEnabled(false); 0121 _backHistory.clear(); 0122 _backAction->setEnabled(false); 0123 fromHistory = true; 0124 } 0125 QString className = url.path(); 0126 if(className.isEmpty()) { 0127 setHtml("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />" 0128 "</head><body>\n" 0129 "<div id='doc_box' class='box'>\n" 0130 "<div id='doc_box-header' class='box-header'>\n" 0131 "<span id='doc_box-header-title' class='box-header-title'>\n" 0132 + i18n( "Documentation" ) + 0133 "</span>\n" 0134 "</div>\n" 0135 "<div id='doc_box-body' class='box-body'>\n" 0136 "<div class='info'><p>\n" 0137 + i18n("No current object.") + 0138 "</p></div>\n" 0139 "</div>\n" 0140 "</div>\n" 0141 "</body></html>", fromHistory, url ); 0142 return; 0143 } 0144 QString fileName = KLocalizedString::localizedFilePath(QStandardPaths::locate(QStandardPaths::AppLocalDataLocation, QStringLiteral("objinfo/%1.html").arg(className.toLower()))); 0145 if(!fileName.isEmpty()) { 0146 QFile file(fileName); 0147 if(file.open(QIODevice::ReadOnly | QIODevice::Text)) { 0148 setHtml(QString::fromUtf8(file.readAll()), fromHistory, url); 0149 return; 0150 } else { 0151 qWarning() << "Could not open help file at location:" << fileName; 0152 } 0153 } 0154 setHtml("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />" 0155 "</head><body>\n" 0156 "<div id='doc_box' class='box'>\n" 0157 "<div id='doc_box-header' class='box-header'>\n" 0158 "<span id='doc_box-header-title' class='box-header-title'>\n" 0159 + i18n( "Documentation error" ) + 0160 "</span>\n" 0161 "</div>\n" 0162 "<div id='doc_box-body' class='box-body'>\n" 0163 "<div class='error'><p>\n" 0164 + i18n("Documentation for %1 not available. ", QCoreApplication::translate("ObjectClass", className.toUtf8().constData())) 0165 + i18n("You can help <a href=\"https://edu.kde.org/step\">Step</a> by writing it!") + 0166 "</p></div>\n" 0167 "</div>\n" 0168 "</div>\n" 0169 "</body></html>", fromHistory, url ); 0170 show(); 0171 } else if(url.scheme() == QLatin1String("https") || url.scheme() == QLatin1String("http")) { 0172 // do not clear history when open external URL 0173 QDesktopServices::openUrl(url); 0174 } else { 0175 qWarning() << "Unknown URL scheme detected, skipping:" << url; 0176 } 0177 } 0178 0179 void InfoBrowser::setHtml(const QString& data, bool fromHistory, const QUrl& url) 0180 { 0181 if(!fromHistory) { 0182 _forwardAction->setEnabled(false); 0183 _forwardHistory.clear(); 0184 0185 QString oldUrl = _htmlBrowser->source().url(); 0186 if(!oldUrl.isEmpty()) { 0187 _backHistory << oldUrl; 0188 _backAction->setEnabled(true); 0189 } 0190 } 0191 0192 if(url.scheme() == QLatin1String("http")) { 0193 _execAction->setEnabled(true); 0194 } 0195 else { 0196 _execAction->setEnabled(false); 0197 } 0198 0199 _htmlBrowser->setSource(url); 0200 _htmlBrowser->setHtml(data); 0201 0202 updateSyncSelection(); 0203 } 0204 0205 void InfoBrowser::back() 0206 { 0207 Q_ASSERT(!_backHistory.isEmpty()); 0208 0209 QString url(_backHistory.takeLast()); 0210 if(_backHistory.isEmpty()) 0211 _backAction->setEnabled(false); 0212 0213 QString curUrl = _htmlBrowser->source().url(); 0214 if(!curUrl.isEmpty()) { 0215 _forwardHistory << curUrl; 0216 _forwardAction->setEnabled(true); 0217 } 0218 0219 openUrl(QUrl(url), false, true); 0220 } 0221 0222 void InfoBrowser::forward() 0223 { 0224 Q_ASSERT(!_forwardHistory.isEmpty()); 0225 0226 QString url(_forwardHistory.takeLast()); 0227 if(_forwardHistory.isEmpty()) 0228 _forwardAction->setEnabled(false); 0229 0230 QString curUrl = _htmlBrowser->source().url(); 0231 if(!curUrl.isEmpty()) { 0232 _backHistory << curUrl; 0233 _backAction->setEnabled(true); 0234 } 0235 0236 openUrl(QUrl(url), false, true); 0237 } 0238 0239 void InfoBrowser::openInBrowser() 0240 { 0241 if(_htmlBrowser->source().scheme() == QLatin1String("https")) { 0242 QDesktopServices::openUrl(_htmlBrowser->source()); 0243 } 0244 } 0245 0246 #include "moc_infobrowser.cpp"