File indexing completed on 2025-01-12 04:35:48
0001 /*************************************************************************** 0002 * SPDX-License-Identifier: GPL-2.0-or-later 0003 * * 0004 * SPDX-FileCopyrightText: 2004-2023 Thomas Fischer <fischer@unix-ag.uni-kl.de> 0005 * and contributors * 0006 * * 0007 * Contributions to this file were made by * 0008 * - Jurgen Spitzmuller <juergen@spitzmueller.org> * 0009 * * 0010 * This program is free software; you can redistribute it and/or modify * 0011 * it under the terms of the GNU General Public License as published by * 0012 * the Free Software Foundation; either version 2 of the License, or * 0013 * (at your option) any later version. * 0014 * * 0015 * This program is distributed in the hope that it will be useful, * 0016 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0018 * GNU General Public License for more details. * 0019 * * 0020 * You should have received a copy of the GNU General Public License * 0021 * along with this program; if not, see <https://www.gnu.org/licenses/>. * 0022 ***************************************************************************/ 0023 0024 #include "referencepreview.h" 0025 0026 #include <QFrame> 0027 #include <QBuffer> 0028 #include <QTextDocument> 0029 #include <QLayout> 0030 #include <QApplication> 0031 #include <QTextStream> 0032 #include <QTemporaryFile> 0033 #include <QPalette> 0034 #include <QMimeType> 0035 #include <QFileDialog> 0036 #include <QPushButton> 0037 #include <QFontDatabase> 0038 #include <QComboBox> 0039 #include <QPointer> 0040 0041 #include <kio_version.h> 0042 #include <KLocalizedString> 0043 #if KIO_VERSION >= QT_VERSION_CHECK(5, 71, 0) 0044 #include <KIO/OpenUrlJob> 0045 #if KIO_VERSION >= QT_VERSION_CHECK(5, 98, 0) 0046 #include <KIO/JobUiDelegateFactory> 0047 #else // < 5.98.0 0048 #include <KIO/JobUiDelegate> 0049 #endif // QT_VERSION_CHECK(5, 98, 0) 0050 #else // < 5.71.0 0051 #include <KRun> 0052 #endif // KIO_VERSION >= QT_VERSION_CHECK(5, 71, 0) 0053 #include <KIO/CopyJob> 0054 #include <KJobWidgets> 0055 #include <KSharedConfig> 0056 #include <KConfigGroup> 0057 #include <KTextEdit> 0058 0059 #include <Element> 0060 #include <Entry> 0061 #include <File> 0062 #include <FileExporterBibTeX> 0063 #include <FileExporterBibTeX2HTML> 0064 #include <FileExporterRIS> 0065 #include <FileExporterXML> 0066 #include <file/FileView> 0067 #include "logging_program.h" 0068 0069 typedef struct { 0070 int id; 0071 QString label; 0072 QHash<QString, QVariant> attributes; 0073 } PreviewStyle; 0074 0075 Q_DECLARE_METATYPE(PreviewStyle) 0076 0077 class ReferencePreview::Private 0078 { 0079 private: 0080 ReferencePreview *p; 0081 0082 QVector<PreviewStyle> previewStyles() const { 0083 static QVector<PreviewStyle> listOfStyles; 0084 if (listOfStyles.isEmpty()) { 0085 listOfStyles = { 0086 {1000, i18n("Source (BibTeX)"), {{QStringLiteral("exporter"), QStringLiteral("bibtex")}, {QStringLiteral("fixed-font"), true}}}, 0087 {1010, i18n("Source (RIS)"), {{QStringLiteral("exporter"), QStringLiteral("ris")}, {QStringLiteral("fixed-font"), true}}}, 0088 {1210, i18n("Standard"), {{QStringLiteral("exporter"), QStringLiteral("xml")}, {QStringLiteral("style"), QVariant::fromValue(FileExporterXML::OutputStyle::HTML_Standard)}, {QStringLiteral("html"), true}}}, 0089 {1220, i18n("Wikipedia Citation"), {{QStringLiteral("exporter"), QStringLiteral("xml")}, {QStringLiteral("style"), QVariant::fromValue(FileExporterXML::OutputStyle::Plain_WikipediaCite)}, {QStringLiteral("fixed-font"), true}}}, 0090 {1230, i18n("Abstract-only"), {{QStringLiteral("exporter"), QStringLiteral("xml")}, {QStringLiteral("style"), QVariant::fromValue(FileExporterXML::OutputStyle::HTML_AbstractOnly)}, {QStringLiteral("html"), true}}} 0091 }; 0092 if (!QStandardPaths::findExecutable(QStringLiteral("bibtex2html")).isEmpty()) { 0093 // If 'bibtex2html' binary is available ... 0094 int id = 2000; 0095 // Query from FileExporterBibTeX2HTML which BibTeX styles are available 0096 for (const QString &bibtex2htmlStyle : FileExporterBibTeX2HTML::availableLaTeXBibliographyStyles()) { 0097 const QString label{QString(QStringLiteral("%2 (bibtex2html)")).arg(bibtex2htmlStyle)}; 0098 listOfStyles.append({id++, label, {{QStringLiteral("exporter"), QStringLiteral("bibtex2html")}, {QStringLiteral("html"), true}, {QStringLiteral("externalprogram"), true}, {QStringLiteral("bibtexstyle"), bibtex2htmlStyle}}}); 0099 } 0100 } 0101 } 0102 return listOfStyles; 0103 } 0104 0105 public: 0106 KSharedConfigPtr config; 0107 static const QString configGroupName; 0108 static const QString configKeyName; 0109 static const QString errorMessageInnerTemplate; 0110 const QString htmlStart, errorMessageOuterTemplate; 0111 0112 QPushButton *buttonOpen, *buttonSaveAsHTML; 0113 QString htmlText; 0114 QUrl baseUrl; 0115 QTextDocument *htmlDocument; 0116 KTextEdit *htmlView; 0117 QComboBox *comboBox; 0118 QSharedPointer<const Element> element; 0119 const File *file; 0120 FileView *fileView; 0121 0122 Private(ReferencePreview *parent) 0123 : p(parent), config(KSharedConfig::openConfig(QStringLiteral("kbibtexrc"))), 0124 htmlStart(QString(QStringLiteral("<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<style type=\"text/css\">\npre {\n white-space: pre-wrap;\n white-space: -moz-pre-wrap;\n white-space: -pre-wrap;\n white-space: -o-pre-wrap;\n word-wrap: break-word;\n}\n</style>\n</head>\n<body style=\"color: %1; background-color: '%2'; font-family: '%3'; font-size: %4pt\">")).arg(QApplication::palette().text().color().name(QColor::HexRgb), QApplication::palette().base().color().name(QColor::HexRgb), QFontDatabase::systemFont(QFontDatabase::GeneralFont).family(), QString::number(QFontDatabase::systemFont(QFontDatabase::GeneralFont).pointSize()))), 0125 errorMessageOuterTemplate(htmlStart + errorMessageInnerTemplate + QStringLiteral("</body></html>")), 0126 file(nullptr), fileView(nullptr) 0127 { 0128 QGridLayout *gridLayout = new QGridLayout(p); 0129 gridLayout->setContentsMargins(0, 0, 0, 0); 0130 gridLayout->setColumnStretch(0, 1); 0131 gridLayout->setColumnStretch(1, 0); 0132 gridLayout->setColumnStretch(2, 0); 0133 0134 comboBox = new QComboBox(p); 0135 gridLayout->addWidget(comboBox, 0, 0, 1, 3); 0136 0137 QFrame *frame = new QFrame(p); 0138 gridLayout->addWidget(frame, 1, 0, 1, 3); 0139 frame->setFrameShadow(QFrame::Sunken); 0140 frame->setFrameShape(QFrame::StyledPanel); 0141 0142 QVBoxLayout *layout = new QVBoxLayout(frame); 0143 layout->setContentsMargins(0, 0, 0, 0); 0144 htmlView = new KTextEdit(frame); 0145 htmlView->setReadOnly(true); 0146 htmlDocument = new QTextDocument(htmlView); 0147 htmlView->setDocument(htmlDocument); 0148 layout->addWidget(htmlView); 0149 0150 buttonOpen = new QPushButton(QIcon::fromTheme(QStringLiteral("document-open")), i18n("Open"), p); 0151 buttonOpen->setToolTip(i18n("Open reference in web browser.")); 0152 gridLayout->addWidget(buttonOpen, 2, 1, 1, 1); 0153 0154 buttonSaveAsHTML = new QPushButton(QIcon::fromTheme(QStringLiteral("document-save")), i18n("Save as HTML"), p); 0155 buttonSaveAsHTML->setToolTip(i18n("Save reference as HTML fragment.")); 0156 gridLayout->addWidget(buttonSaveAsHTML, 2, 2, 1, 1); 0157 } 0158 0159 bool saveHTML(const QUrl &url) const { 0160 QTemporaryFile tempFile; 0161 tempFile.setAutoRemove(true); 0162 0163 bool result = saveHTML(tempFile); 0164 0165 if (result) { 0166 KIO::CopyJob *copyJob = KIO::copy(QUrl::fromLocalFile(tempFile.fileName()), url, KIO::Overwrite); 0167 KJobWidgets::setWindow(copyJob, p); 0168 result = copyJob->exec(); 0169 } 0170 0171 return result; 0172 } 0173 0174 bool saveHTML(QTemporaryFile &tempFile) const { 0175 if (tempFile.open()) { 0176 QTextStream ts(&tempFile); 0177 // https://forum.qt.io/topic/135724/qt-6-replacement-for-qtextcodec 0178 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) 0179 ts.setCodec("utf-8"); 0180 #else 0181 ts.setEncoding(QStringConverter::Utf8); 0182 #endif 0183 static const QRegularExpression kbibtexHrefRegExp(QStringLiteral("<a[^>]+href=\"kbibtex:[^>]+>(.+?)</a>")); 0184 QString modifiedHtmlText = htmlText; 0185 modifiedHtmlText = modifiedHtmlText.replace(kbibtexHrefRegExp, QStringLiteral("\\1")); 0186 ts << modifiedHtmlText; 0187 tempFile.close(); 0188 return true; 0189 } 0190 0191 return false; 0192 } 0193 0194 void loadState() { 0195 KConfigGroup configGroup(config, configGroupName); 0196 const int previousStyleId = configGroup.readEntry(configKeyName, -1); 0197 0198 comboBox->clear(); 0199 0200 int styleIndex = 0, c = 0; 0201 for (const PreviewStyle &previewStyle : previewStyles()) { 0202 comboBox->addItem(previewStyle.label, QVariant::fromValue(previewStyle)); 0203 if (previousStyleId == previewStyle.id) 0204 styleIndex = c; 0205 ++c; 0206 } 0207 comboBox->setCurrentIndex(styleIndex); 0208 } 0209 0210 void saveState() { 0211 KConfigGroup configGroup(config, configGroupName); 0212 configGroup.writeEntry(configKeyName, comboBox->itemData(comboBox->currentIndex()).value<PreviewStyle>().id); 0213 config->sync(); 0214 } 0215 0216 void setHtml(const QString &html, bool buttonsEnabled) 0217 { 0218 htmlText = QString(html).remove(QStringLiteral("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")); 0219 htmlDocument->setHtml(htmlText); 0220 buttonOpen->setEnabled(buttonsEnabled); 0221 buttonSaveAsHTML->setEnabled(buttonsEnabled); 0222 } 0223 }; 0224 0225 const QString ReferencePreview::Private::configGroupName {QStringLiteral("Reference Preview Docklet")}; 0226 const QString ReferencePreview::Private::configKeyName {QStringLiteral("Style")}; 0227 const QString ReferencePreview::Private::errorMessageInnerTemplate {QString(QStringLiteral("<p style=\"font-style: italic;\">%1</p><p style=\"font-size: 90%;\">%2 %3</p>")).arg(i18n("No preview available"), i18n("Reason:"))}; 0228 0229 ReferencePreview::ReferencePreview(QWidget *parent) 0230 : QWidget(parent), d(new Private(this)) 0231 { 0232 d->loadState(); 0233 0234 connect(d->buttonOpen, &QPushButton::clicked, this, &ReferencePreview::openAsHTML); 0235 connect(d->buttonSaveAsHTML, &QPushButton::clicked, this, &ReferencePreview::saveAsHTML); 0236 connect(d->comboBox, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ReferencePreview::renderHTML); 0237 0238 setEnabled(false); 0239 } 0240 0241 ReferencePreview::~ReferencePreview() 0242 { 0243 delete d; 0244 } 0245 0246 void ReferencePreview::setEnabled(bool enabled) 0247 { 0248 if (enabled) 0249 d->setHtml(d->htmlText, true); 0250 else 0251 d->setHtml(d->errorMessageOuterTemplate.arg(i18nc("Message in case reference preview widget is disabled", "Preview disabled")), false); 0252 d->htmlView->setEnabled(enabled); 0253 d->comboBox->setEnabled(enabled); 0254 } 0255 0256 void ReferencePreview::setElement(QSharedPointer<const Element> element, const File *file) 0257 { 0258 d->element = element; 0259 d->file = file; 0260 renderHTML(); 0261 } 0262 0263 void ReferencePreview::renderHTML() 0264 { 0265 if (d->element.isNull()) { 0266 d->setHtml(d->errorMessageOuterTemplate.arg(i18nc("Message in case no bibliographic element is selected for preview", "No element selected")), false); 0267 return; 0268 } 0269 0270 const bool elementIsEntry {!d->element.dynamicCast<const Entry>().isNull()}; 0271 const PreviewStyle previewStyle = d->comboBox->itemData(d->comboBox->currentIndex()).value<PreviewStyle>(); 0272 0273 const QString exporterName = previewStyle.attributes.value(QStringLiteral("exporter"), QString()).toString(); 0274 QScopedPointer<FileExporter> exporter([this, &previewStyle, &exporterName]() { 0275 if (exporterName == QStringLiteral("bibtex")) { 0276 FileExporterBibTeX *exporterBibTeX = new FileExporterBibTeX(this); 0277 exporterBibTeX->setEncoding(QStringLiteral("utf-8")); 0278 return qobject_cast<FileExporter *>(exporterBibTeX); 0279 } else if (exporterName == QStringLiteral("ris")) 0280 return qobject_cast<FileExporter * >(new FileExporterRIS(this)); 0281 else if (exporterName == QStringLiteral("bibtex2html")) { 0282 FileExporterBibTeX2HTML *exporterBibTeX2HTML = new FileExporterBibTeX2HTML(this); 0283 exporterBibTeX2HTML->setLaTeXBibliographyStyle(previewStyle.attributes.value(QStringLiteral("bibtexstyle"), QString()).toString()); 0284 return qobject_cast<FileExporter *>(exporterBibTeX2HTML); 0285 } else if (exporterName == QStringLiteral("xml")) { 0286 FileExporterXML *exporterXML = new FileExporterXML(this); 0287 exporterXML->setOutputStyle(previewStyle.attributes.value(QStringLiteral("style"), QVariant::fromValue(FileExporterXML::OutputStyle::XML_KBibTeX)).value<FileExporterXML::OutputStyle>()); 0288 return qobject_cast<FileExporter *>(exporterXML); 0289 } else if (!exporterName.isEmpty()) 0290 qCWarning(LOG_KBIBTEX_PROGRAM) << "Don't know how to handle exporter " << exporterName << " for preview style " << previewStyle.label << "(" << previewStyle.id << ")"; 0291 0292 return static_cast<FileExporter *>(nullptr); 0293 }()); 0294 0295 QString text; 0296 bool exporterResult = false; 0297 bool textIsErrorMessage = false; 0298 if (!exporter.isNull()) { 0299 const bool externalProgramInvocation {previewStyle.attributes.value(QStringLiteral("externalprogram"), false).toBool()}; 0300 if (externalProgramInvocation) { 0301 // Exporter may invoke external programs which take time, so set the busy cursor 0302 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); 0303 } 0304 QBuffer buffer(this); 0305 buffer.open(QBuffer::WriteOnly); 0306 exporterResult = exporter->save(&buffer, d->element, d->file); 0307 buffer.close(); 0308 if (externalProgramInvocation) 0309 QApplication::restoreOverrideCursor(); 0310 0311 buffer.open(QBuffer::ReadOnly); 0312 text = QString::fromUtf8(buffer.readAll().constData()).trimmed(); 0313 buffer.close(); 0314 } else { 0315 text = d->errorMessageInnerTemplate.arg(i18nc("No exporter clould be located to generate output", "No output generated")); 0316 textIsErrorMessage = true; 0317 } 0318 0319 // Remove comments 0320 int p = 0; 0321 while ((p = text.indexOf(QStringLiteral("<!--"), p)) >= 0) { 0322 const int p2 = text.indexOf(QStringLiteral("-->"), p + 3); 0323 if (p2 > p) { 0324 text = text.left(p).trimmed() + text.mid(p2 + 3).trimmed(); 0325 } else 0326 break; 0327 } 0328 0329 if (exporterName == QStringLiteral("bibtex")) { 0330 // Remove special comments from BibTeX code 0331 int xsomethingpos = 0; 0332 while ((xsomethingpos = text.indexOf(QStringLiteral("@comment{x-"), xsomethingpos)) >= 0) { 0333 int endofxsomethingpos = text.indexOf(QStringLiteral("}"), xsomethingpos + 11); 0334 if (endofxsomethingpos > xsomethingpos) { 0335 // Trim empty lines around match 0336 while (xsomethingpos > 0 && text[xsomethingpos - 1] == QLatin1Char('\n')) --xsomethingpos; 0337 while (endofxsomethingpos + 1 < text.length() && text[endofxsomethingpos + 1] == QLatin1Char('\n')) ++endofxsomethingpos; 0338 // Clip comment out of text 0339 text = text.left(xsomethingpos) + text.mid(endofxsomethingpos + 1); 0340 } 0341 } 0342 } else if (exporterName == QStringLiteral("bibtex2html")) { 0343 // Remove bibtex2html's output after the horizontal line 0344 const int hrPos = text.indexOf(QStringLiteral("<hr")); 0345 if (hrPos >= 0) 0346 text = text.left(hrPos); 0347 0348 // Remove various HTML artifacts 0349 static const QSet<const QRegularExpression> toBeRemovedSet{QRegularExpression(QStringLiteral("<[/]?(font)[^>]*>")), QRegularExpression(QStringLiteral("^.*?<td.*?</td.*?<td>")), QRegularExpression(QStringLiteral("</td>.*$")), QRegularExpression(QStringLiteral("\\[ <a.*?</a> \\]"))}; 0350 for (const auto &toBeRemoved : toBeRemovedSet) 0351 text.remove(toBeRemoved); 0352 } 0353 0354 if ((!exporterResult || text.isEmpty()) && !elementIsEntry) { 0355 // Some exporters do not handle things like macros or preamble. 0356 // Assume that this is the case here and provide an approriate error message for that 0357 text = d->errorMessageInnerTemplate.arg(i18n("Cannot show a preview for this type of element")); 0358 textIsErrorMessage = true; 0359 } 0360 0361 if (!textIsErrorMessage && previewStyle.attributes.value(QStringLiteral("fixed-font"), false).toBool()) { 0362 // Preview text gets formatted as verbatim text in monospaced font 0363 text.prepend(QStringLiteral("';\">")); 0364 text.prepend(QFontDatabase::systemFont(QFontDatabase::FixedFont).family()); 0365 text.prepend(QStringLiteral("<pre style=\"font-family: '")); 0366 text.append(QStringLiteral("</pre>")); 0367 } else if (!textIsErrorMessage && previewStyle.attributes.value(QStringLiteral("html"), false).toBool()) { 0368 // Remove existing header up to and including <body> 0369 int p = text.indexOf(QStringLiteral("<body")); 0370 if (p >= 0) { 0371 p = text.indexOf(QStringLiteral(">"), p + 4); 0372 if (p >= 0) 0373 text = text.mid(p + 1).trimmed(); 0374 } 0375 // Remove existing footer starting with </body> 0376 p = text.indexOf(QStringLiteral("</body")); 0377 if (p >= 0) 0378 text = text.left(p).trimmed(); 0379 } 0380 0381 if (previewStyle.attributes.value(QStringLiteral("style"), QVariant::fromValue(FileExporterXML::OutputStyle::XML_KBibTeX)).value<FileExporterXML::OutputStyle>() == FileExporterXML::OutputStyle::Plain_WikipediaCite) 0382 text.remove(QStringLiteral("\n")).replace(QStringLiteral("| "), QStringLiteral("|")); 0383 else if (previewStyle.attributes.value(QStringLiteral("style"), QVariant::fromValue(FileExporterXML::OutputStyle::XML_KBibTeX)).value<FileExporterXML::OutputStyle>() == FileExporterXML::OutputStyle::HTML_AbstractOnly) { 0384 if (text.isEmpty()) { 0385 text = d->errorMessageInnerTemplate.arg(i18nc("Cannot show a reference preview as entry does not contain an abstract", "No abstract")); 0386 textIsErrorMessage = true; 0387 } 0388 } 0389 0390 // Beautify text 0391 text.replace(QStringLiteral("``"), QStringLiteral("“")); 0392 text.replace(QStringLiteral("''"), QStringLiteral("”")); 0393 static const QRegularExpression openingSingleQuotationRegExp(QStringLiteral("(^|[> ,.;:!?])`(\\S)")); 0394 static const QRegularExpression closingSingleQuotationRegExp(QStringLiteral("(\\S)'([ ,.;:!?<]|$)")); 0395 text.replace(openingSingleQuotationRegExp, QStringLiteral("\\1‘\\2")); 0396 text.replace(closingSingleQuotationRegExp, QStringLiteral("\\1’\\2")); 0397 0398 // Replace ASCII art with Unicode characters 0399 text.replace(QStringLiteral("---"), QString(QChar(0x2014))); 0400 text.replace(QStringLiteral("--"), QString(QChar(0x2013))); 0401 0402 // Add common HTML start and end 0403 text.prepend(d->htmlStart); 0404 text.append(QStringLiteral("</body></html>")); 0405 0406 d->setHtml(text, !textIsErrorMessage); 0407 d->saveState(); 0408 } 0409 0410 void ReferencePreview::openAsHTML() 0411 { 0412 QTemporaryFile file(QStandardPaths::writableLocation(QStandardPaths::TempLocation) + QDir::separator() + QStringLiteral("referencePreview-openAsHTML-XXXXXX.html")); 0413 file.setAutoRemove(false); /// let file stay alive for browser 0414 d->saveHTML(file); 0415 0416 /// Ask KDE subsystem to open url in viewer matching mime type 0417 const QUrl url{QUrl::fromLocalFile(file.fileName())}; 0418 #if KIO_VERSION < QT_VERSION_CHECK(5, 71, 0) 0419 KRun::runUrl(url, QStringLiteral("text/html"), this, KRun::RunFlags()); 0420 #else // KIO_VERSION < QT_VERSION_CHECK(5, 71, 0) // >= 5.71.0 0421 KIO::OpenUrlJob *job = new KIO::OpenUrlJob(url, QStringLiteral("text/html")); 0422 #if KIO_VERSION < QT_VERSION_CHECK(5, 98, 0) // < 5.98.0 0423 job->setUiDelegate(new KIO::JobUiDelegate()); 0424 #else // KIO_VERSION < QT_VERSION_CHECK(5, 98, 0) // >= 5.98.0 0425 job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this)); 0426 #endif // KIO_VERSION < QT_VERSION_CHECK(5, 98, 0) 0427 job->start(); 0428 #endif // KIO_VERSION < QT_VERSION_CHECK(5, 71, 0) 0429 } 0430 0431 void ReferencePreview::saveAsHTML() 0432 { 0433 QPointer<QFileDialog> dlg = new QFileDialog(this, i18n("Save as HTML")); 0434 dlg->setMimeTypeFilters({QStringLiteral("text/html")}); 0435 const int result = dlg->exec(); 0436 QUrl url; 0437 if (result == QDialog::Accepted && !dlg->selectedUrls().isEmpty() && (url = dlg->selectedUrls().first()).isValid()) 0438 d->saveHTML(url); 0439 } 0440 0441 void ReferencePreview::linkClicked(const QUrl &url) 0442 { 0443 QString text = url.toDisplayString(); 0444 if (text.startsWith(QStringLiteral("kbibtex:filter:"))) { 0445 text = text.mid(15); 0446 if (d->fileView != nullptr) { 0447 int p = text.indexOf(QStringLiteral("=")); 0448 SortFilterFileModel::FilterQuery fq; 0449 fq.terms << text.mid(p + 1); 0450 fq.combination = SortFilterFileModel::FilterCombination::EveryTerm; 0451 fq.field = text.left(p); 0452 fq.searchPDFfiles = false; 0453 d->fileView->setFilterBarFilter(fq); 0454 } 0455 } 0456 } 0457 0458 void ReferencePreview::setFileView(FileView *fileView) 0459 { 0460 d->fileView = fileView; 0461 }