1 /*
2 * Cantata
3 *
4 * Copyright (c) 2011-2020 Craig Drummond <craig.p.drummond@gmail.com>
5 *
6 * ----
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; see the file COPYING. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24 #include "textbrowser.h"
25 #include <QFile>
26 #include <QImage>
27 #include <QScrollBar>
28 #include <QEvent>
29 #include <QStyle>
30 #include <QTimer>
31
TextBrowser(QWidget * p)32 TextBrowser::TextBrowser(QWidget *p)
33 : QTextBrowser(p)
34 , timer(nullptr)
35 , lastImageSize(0)
36 , fullWidthImg(false)
37 , haveImg(false)
38 {
39 }
40
41 // QTextEdit/QTextBrowser seems to do FastTransformation when scaling images, and this looks bad.
loadResource(int type,const QUrl & name)42 QVariant TextBrowser::loadResource(int type, const QUrl &name)
43 {
44 if (QTextDocument::ImageResource==type) {
45 QImage img;
46 if ((name.scheme().isEmpty() || QLatin1String("file")==name.scheme())) {
47 img.load(name.path());
48 if (img.isNull()) {
49 // Failed to load, perhaps extension is wrong? If so try to guess from plain data without hint from file name.
50 QFile file(name.path());
51 if (file.open(QIODevice::ReadOnly)) {
52 QByteArray data=file.readAll();
53 img.loadFromData(data);
54 }
55 }
56 } else if (QLatin1String("data")==name.scheme()) {
57 QByteArray encoded=name.toEncoded();
58 static const QString constStart("data:image/png;base64,");
59 encoded=QByteArray::fromBase64(encoded.mid(constStart.length()));
60 img.loadFromData(encoded);
61 }
62 if (!img.isNull()) {
63 haveImg=true;
64 return img.scaled(imageSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
65 }
66 }
67 return QTextBrowser::loadResource(type, name);
68 }
69
setFullWidthImage(bool s)70 void TextBrowser::setFullWidthImage(bool s)
71 {
72 if (s!=fullWidthImg) {
73 fullWidthImg=s;
74 verticalScrollBar()->removeEventFilter(this);
75 if (fullWidthImg) {
76 verticalScrollBar()->installEventFilter(this);
77 }
78 if (haveImg) {
79 setHtml(toHtml());
80 }
81 }
82 }
83
setPal(const QPalette & pal)84 void TextBrowser::setPal(const QPalette &pal)
85 {
86 setPalette(pal);
87 verticalScrollBar()->setPalette(pal);
88 horizontalScrollBar()->setPalette(pal);
89 }
90
resizeEvent(QResizeEvent * e)91 void TextBrowser::resizeEvent(QResizeEvent *e)
92 {
93 handleSizeChange();
94 QTextBrowser::resizeEvent(e);
95 }
96
eventFilter(QObject * obj,QEvent * ev)97 bool TextBrowser::eventFilter(QObject *obj, QEvent *ev)
98 {
99 if (obj==verticalScrollBar() && (QEvent::Show==ev->type() || QEvent::Hide==ev->type())) {
100 handleSizeChange();
101 }
102 return QTextBrowser::eventFilter(obj, ev);
103 }
104
refreshHtml()105 void TextBrowser::refreshHtml()
106 {
107 setHtml(toHtml());
108 }
109
handleSizeChange()110 void TextBrowser::handleSizeChange()
111 {
112 if (haveImg) {
113 int imgSize=imageSize().width();
114 if (imgSize!=lastImageSize) {
115 if (timer) {
116 timer->stop();
117 } else {
118 timer=new QTimer(this);
119 timer->setSingleShot(true);
120 connect(timer, SIGNAL(timeout()), SLOT(refreshHtml()));
121 }
122 lastImageSize=imgSize;
123 timer->start();
124 }
125 }
126 }
127
imageSize() const128 QSize TextBrowser::imageSize() const
129 {
130 QSize sz;
131
132 int sbarSpacing = style()->pixelMetric(QStyle::PM_ScrollView_ScrollBarSpacing);
133 if (sbarSpacing<0) {
134 sz=size()-QSize(4, 0);
135 } else {
136 QScrollBar *sb=verticalScrollBar();
137 int sbarWidth=sb && sb->isVisible() ? 0 : style()->pixelMetric(QStyle::PM_ScrollBarExtent);
138 sz=size()-QSize(4 + sbarSpacing + sbarWidth, 0);
139 }
140 if (fullWidthImg || sz.width()<=picSize().width()) {
141 return sz.width()<32 || sz.height()<32 ? QSize(32, 32) : sz;
142 }
143 return picSize();
144 }
145
146 #include "moc_textbrowser.cpp"
147