1 /*
2   SPDX-FileCopyrightText: 2012-2021 Laurent Montel <montel@kde.org>
3 
4   SPDX-License-Identifier: LGPL-2.0-or-later
5 
6 */
7 #include "insertimagewidget.h"
8 
9 #include <KLineEdit>
10 #include <KLocalizedString>
11 #include <KSeparator>
12 #include <KUrlRequester>
13 
14 #include <QCheckBox>
15 #include <QHBoxLayout>
16 #include <QImageReader>
17 #include <QLabel>
18 #include <QMimeDatabase>
19 #include <QSpinBox>
20 #include <QVBoxLayout>
21 
22 namespace KPIMTextEdit
23 {
resolveAlias(const QString & name)24 static inline QString resolveAlias(const QString &name)
25 {
26     QMimeDatabase db;
27     const QString str = db.mimeTypeForName(name).name();
28     return str;
29 }
30 
31 class InsertImageWidgetPrivate
32 {
33 public:
InsertImageWidgetPrivate(InsertImageWidget * qq)34     explicit InsertImageWidgetPrivate(InsertImageWidget *qq)
35         : q(qq)
36     {
37         auto lay = new QVBoxLayout(q);
38         lay->setContentsMargins({});
39         auto hbox = new QHBoxLayout;
40         QLabel *lab = new QLabel(i18n("Image Location:"));
41         imageUrlRequester = new KUrlRequester;
42 
43         QStringList lstMimeTypes;
44         const QList<QByteArray> mimetypes = QImageReader::supportedMimeTypes();
45         lstMimeTypes.reserve(mimetypes.count());
46         for (const QByteArray &ba : mimetypes) {
47             const QString resolvedAlias = resolveAlias(QString::fromUtf8(ba));
48             if (!resolvedAlias.isEmpty()) {
49                 lstMimeTypes << resolvedAlias;
50             }
51         }
52         imageUrlRequester->setMimeTypeFilters(lstMimeTypes);
53         imageUrlRequester->setWindowTitle(i18nc("@title:window", "Add Image"));
54         imageUrlRequester->setMode(KFile::File);
55         q->connect(imageUrlRequester->lineEdit(), &KLineEdit::textChanged, q, [this](const QString &str) {
56             _k_slotUrlChanged(str);
57         });
58 
59         hbox->addWidget(lab);
60         hbox->addWidget(imageUrlRequester);
61         lab->setBuddy(imageUrlRequester);
62         lay->addLayout(hbox);
63 
64         keepOriginalSize = new QCheckBox(i18n("Keep Original Size"));
65         q->connect(keepOriginalSize, &QCheckBox::clicked, q, [this](bool b) {
66             _k_slotKeepOriginalSizeClicked(b);
67         });
68         keepOriginalSize->setChecked(true);
69         lay->addWidget(keepOriginalSize);
70 
71         keepImageRatio = new QCheckBox(i18n("Keep Image Ratio"));
72         keepImageRatio->setChecked(true);
73         keepImageRatio->setEnabled(false);
74         lay->addWidget(keepImageRatio);
75 
76         hbox = new QHBoxLayout;
77         lab = new QLabel(i18n("Width:"));
78         width = new QSpinBox;
79         width->setMinimum(1);
80         width->setMaximum(99999);
81         width->setEnabled(false);
82         width->setSuffix(i18n(" px"));
83         lab->setBuddy(width);
84         q->connect(width, &QSpinBox::valueChanged, q, [this](int val) {
85             _k_slotImageWidthChanged(val);
86         });
87         hbox->addWidget(lab);
88         hbox->addWidget(width);
89         lay->addLayout(hbox);
90 
91         hbox = new QHBoxLayout;
92         lab = new QLabel(i18n("Height:"));
93         height = new QSpinBox;
94         height->setMinimum(1);
95         height->setMaximum(99999);
96         height->setEnabled(false);
97         height->setSuffix(i18n(" px"));
98         lab->setBuddy(height);
99         q->connect(height, &QSpinBox::valueChanged, q, [this](int val) {
100             _k_slotImageHeightChanged(val);
101         });
102         hbox->addWidget(lab);
103         hbox->addWidget(height);
104         lay->addLayout(hbox);
105 
106         KSeparator *sep = new KSeparator;
107         lay->addWidget(sep);
108 
109         hbox = new QHBoxLayout;
110         lab = new QLabel(i18n("Image Preview:"));
111         hbox->addWidget(lab);
112         preview = new QLabel;
113         preview->setFrameStyle(QFrame::Box);
114         preview->setFixedSize(50, 50);
115         hbox->addWidget(preview);
116         lay->addLayout(hbox);
117     }
118 
119     void _k_slotKeepOriginalSizeClicked(bool);
120     void _k_slotUrlChanged(const QString &);
121     void _k_slotImageWidthChanged(int);
122     void _k_slotImageHeightChanged(int);
123 
124     qreal imageRatio = -1;
125     QCheckBox *keepOriginalSize = nullptr;
126     QCheckBox *keepImageRatio = nullptr;
127     QSpinBox *width = nullptr;
128     QSpinBox *height = nullptr;
129     KUrlRequester *imageUrlRequester = nullptr;
130     QLabel *preview = nullptr;
131     InsertImageWidget *const q;
132 };
133 
_k_slotKeepOriginalSizeClicked(bool checked)134 void InsertImageWidgetPrivate::_k_slotKeepOriginalSizeClicked(bool checked)
135 {
136     height->setEnabled(!checked);
137     width->setEnabled(!checked);
138     keepImageRatio->setEnabled(!checked);
139     // Update default size
140     _k_slotUrlChanged(imageUrlRequester->text());
141 }
142 
_k_slotUrlChanged(const QString & text)143 void InsertImageWidgetPrivate::_k_slotUrlChanged(const QString &text)
144 {
145     QImage image(text);
146     if (!image.isNull()) {
147         height->setValue(image.height());
148         width->setValue(image.width());
149 
150         imageRatio = (double)((double)image.height() / (double)image.width());
151         preview->setPixmap(QPixmap::fromImage(image));
152     } else {
153         preview->clear();
154         imageRatio = -1;
155     }
156     Q_EMIT q->enableButtonOk(!text.trimmed().isEmpty());
157 }
158 
_k_slotImageWidthChanged(int value)159 void InsertImageWidgetPrivate::_k_slotImageWidthChanged(int value)
160 {
161     if (keepImageRatio->isChecked() && !keepOriginalSize->isChecked()) {
162         if (imageRatio != -1) {
163             height->blockSignals(true);
164             height->setValue(value * imageRatio);
165             height->blockSignals(false);
166         }
167     }
168 }
169 
_k_slotImageHeightChanged(int value)170 void InsertImageWidgetPrivate::_k_slotImageHeightChanged(int value)
171 {
172     if (keepImageRatio->isChecked() && !keepOriginalSize->isChecked()) {
173         if (imageRatio != -1) {
174             width->blockSignals(true);
175             width->setValue(value / imageRatio);
176             width->blockSignals(false);
177         }
178     }
179 }
180 
InsertImageWidget(QWidget * parent)181 InsertImageWidget::InsertImageWidget(QWidget *parent)
182     : QWidget(parent)
183     , d(new InsertImageWidgetPrivate(this))
184 {
185 }
186 
187 InsertImageWidget::~InsertImageWidget() = default;
188 
imageWidth() const189 int InsertImageWidget::imageWidth() const
190 {
191     return d->width->value();
192 }
193 
imageHeight() const194 int InsertImageWidget::imageHeight() const
195 {
196     return d->height->value();
197 }
198 
setImageWidth(int value)199 void InsertImageWidget::setImageWidth(int value)
200 {
201     d->width->setValue(value);
202 }
203 
setImageHeight(int value)204 void InsertImageWidget::setImageHeight(int value)
205 {
206     d->height->setValue(value);
207 }
208 
imageUrl() const209 QUrl InsertImageWidget::imageUrl() const
210 {
211     return d->imageUrlRequester->url();
212 }
213 
setImageUrl(const QUrl & url)214 void InsertImageWidget::setImageUrl(const QUrl &url)
215 {
216     d->imageUrlRequester->setUrl(url);
217 }
218 
keepOriginalSize() const219 bool InsertImageWidget::keepOriginalSize() const
220 {
221     return d->keepOriginalSize->isChecked();
222 }
223 }
224 
225 #include "moc_insertimagewidget.cpp"
226