1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the Qt Designer of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28 
29 #include "iconselector_p.h"
30 #include "qdesigner_utils_p.h"
31 #include "qtresourcemodel_p.h"
32 #include "qtresourceview_p.h"
33 #include "iconloader_p.h"
34 #include "formwindowbase_p.h"
35 
36 #include <abstractdialoggui_p.h>
37 #include <QtDesigner/abstractformeditor.h>
38 #include <QtDesigner/abstractresourcebrowser.h>
39 #include <QtDesigner/abstractlanguage.h>
40 #include <QtDesigner/abstractintegration.h>
41 #include <QtDesigner/qextensionmanager.h>
42 
43 #include <QtWidgets/qtoolbutton.h>
44 #include <QtWidgets/qcombobox.h>
45 #include <QtWidgets/qaction.h>
46 #include <QtWidgets/qdialogbuttonbox.h>
47 #include <QtWidgets/qpushbutton.h>
48 #include <QtWidgets/qdialog.h>
49 #include <QtWidgets/qmenu.h>
50 #include <QtWidgets/qapplication.h>
51 #include <QtWidgets/qboxlayout.h>
52 #include <QtGui/qimagereader.h>
53 #include <QtWidgets/qdialogbuttonbox.h>
54 #include <QtWidgets/qlineedit.h>
55 #include <QtWidgets/qlabel.h>
56 #include <QtGui/qvalidator.h>
57 #include <QtCore/qdebug.h>
58 #include <QtCore/qvector.h>
59 
60 
61 QT_BEGIN_NAMESPACE
62 
63 namespace qdesigner_internal {
64 
65 // -------------------- LanguageResourceDialogPrivate
66 class LanguageResourceDialogPrivate {
67     LanguageResourceDialog *q_ptr;
68     Q_DECLARE_PUBLIC(LanguageResourceDialog)
69 
70 public:
71     LanguageResourceDialogPrivate(QDesignerResourceBrowserInterface *rb);
72     void init(LanguageResourceDialog *p);
73 
74     void setCurrentPath(const QString &filePath);
75     QString currentPath() const;
76 
77     void slotAccepted();
78     void slotPathChanged(const QString &);
79 
80 private:
setOkButtonEnabled(bool v)81     void setOkButtonEnabled(bool v)         { m_dialogButtonBox->button(QDialogButtonBox::Ok)->setEnabled(v); }
82     static bool checkPath(const QString &p);
83 
84     QDesignerResourceBrowserInterface *m_browser;
85     QDialogButtonBox *m_dialogButtonBox;
86 };
87 
LanguageResourceDialogPrivate(QDesignerResourceBrowserInterface * rb)88 LanguageResourceDialogPrivate::LanguageResourceDialogPrivate(QDesignerResourceBrowserInterface *rb) :
89     q_ptr(nullptr),
90     m_browser(rb),
91     m_dialogButtonBox(new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel))
92 {
93      setOkButtonEnabled(false);
94 }
95 
init(LanguageResourceDialog * p)96 void LanguageResourceDialogPrivate::init(LanguageResourceDialog *p)
97 {
98     q_ptr = p;
99     QLayout *layout = new QVBoxLayout(p);
100     layout->addWidget(m_browser);
101     layout->addWidget(m_dialogButtonBox);
102     QObject::connect(m_dialogButtonBox, SIGNAL(accepted()), p, SLOT(slotAccepted()));
103     QObject::connect(m_dialogButtonBox, &QDialogButtonBox::rejected, p, &QDialog::reject);
104     QObject::connect(m_browser, SIGNAL(currentPathChanged(QString)), p, SLOT(slotPathChanged(QString)));
105     QObject::connect(m_browser, SIGNAL(pathActivated(QString)), p, SLOT(slotAccepted()));
106     p->setModal(true);
107     p->setWindowTitle(LanguageResourceDialog::tr("Choose Resource"));
108     p->setWindowFlags(p->windowFlags() & ~Qt::WindowContextHelpButtonHint);
109     setOkButtonEnabled(false);
110 }
111 
setCurrentPath(const QString & filePath)112 void LanguageResourceDialogPrivate::setCurrentPath(const QString &filePath)
113 {
114     m_browser->setCurrentPath(filePath);
115     setOkButtonEnabled(checkPath(filePath));
116 }
117 
currentPath() const118 QString LanguageResourceDialogPrivate::currentPath() const
119 {
120     return m_browser->currentPath();
121 }
122 
checkPath(const QString & p)123 bool LanguageResourceDialogPrivate::checkPath(const QString &p)
124 {
125     return p.isEmpty() ? false : IconSelector::checkPixmap(p, IconSelector::CheckFast);
126 }
127 
slotAccepted()128 void LanguageResourceDialogPrivate::slotAccepted()
129 {
130     if (checkPath(currentPath()))
131         q_ptr->accept();
132 }
133 
slotPathChanged(const QString & p)134 void LanguageResourceDialogPrivate::slotPathChanged(const QString &p)
135 {
136     setOkButtonEnabled(checkPath(p));
137 }
138 
139 // ------------ LanguageResourceDialog
LanguageResourceDialog(QDesignerResourceBrowserInterface * rb,QWidget * parent)140 LanguageResourceDialog::LanguageResourceDialog(QDesignerResourceBrowserInterface *rb, QWidget *parent) :
141     QDialog(parent),
142     d_ptr(new LanguageResourceDialogPrivate(rb))
143 {
144     d_ptr->init( this);
145 }
146 
147 LanguageResourceDialog::~LanguageResourceDialog() = default;
148 
setCurrentPath(const QString & filePath)149 void LanguageResourceDialog::setCurrentPath(const QString &filePath)
150 {
151     d_ptr->setCurrentPath(filePath);
152 }
153 
currentPath() const154 QString LanguageResourceDialog::currentPath() const
155 {
156     return d_ptr->currentPath();
157 }
158 
create(QDesignerFormEditorInterface * core,QWidget * parent)159 LanguageResourceDialog* LanguageResourceDialog::create(QDesignerFormEditorInterface *core, QWidget *parent)
160 {
161     if (QDesignerLanguageExtension *lang = qt_extension<QDesignerLanguageExtension *>(core->extensionManager(), core))
162         if (QDesignerResourceBrowserInterface *rb = lang->createResourceBrowser(nullptr))
163             return new LanguageResourceDialog(rb, parent);
164     if (QDesignerResourceBrowserInterface *rb = core->integration()->createResourceBrowser(nullptr))
165         return new LanguageResourceDialog(rb, parent);
166     return nullptr;
167 }
168 
169 // ------------ IconSelectorPrivate
170 
emptyPixmap()171 static inline QPixmap emptyPixmap()
172 {
173     QImage img(16, 16, QImage::Format_ARGB32_Premultiplied);
174     img.fill(0);
175     return QPixmap::fromImage(img);
176 }
177 
178 class IconSelectorPrivate
179 {
180     IconSelector *q_ptr = nullptr;
181     Q_DECLARE_PUBLIC(IconSelector)
182 public:
183     IconSelectorPrivate() = default;
184 
185     void slotStateActivated();
186     void slotSetActivated();
187     void slotSetResourceActivated();
188     void slotSetFileActivated();
189     void slotResetActivated();
190     void slotResetAllActivated();
191     void slotUpdate();
192 
193     QVector<QPair<QPair<QIcon::Mode, QIcon::State>, QString> > m_stateToName; // could be static map
194 
195     QMap<QPair<QIcon::Mode, QIcon::State>, int>  m_stateToIndex;
196     QMap<int, QPair<QIcon::Mode, QIcon::State> > m_indexToState;
197 
198     const QIcon m_emptyIcon;
199     QComboBox *m_stateComboBox = nullptr;
200     QToolButton *m_iconButton = nullptr;
201     QAction *m_resetAction = nullptr;
202     QAction *m_resetAllAction = nullptr;
203     PropertySheetIconValue m_icon;
204     DesignerIconCache *m_iconCache = nullptr;
205     DesignerPixmapCache *m_pixmapCache = nullptr;
206     QtResourceModel *m_resourceModel = nullptr;
207     QDesignerFormEditorInterface *m_core = nullptr;
208 };
209 
slotUpdate()210 void IconSelectorPrivate::slotUpdate()
211 {
212     QIcon icon;
213     if (m_iconCache)
214         icon = m_iconCache->icon(m_icon);
215 
216     QMap<QPair<QIcon::Mode, QIcon::State>, PropertySheetPixmapValue> paths = m_icon.paths();
217     for (auto itIndex = m_stateToIndex.cbegin(), end = m_stateToIndex.cend(); itIndex != end; ++itIndex) {
218         const QPair<QIcon::Mode, QIcon::State> state = itIndex.key();
219         const PropertySheetPixmapValue pixmap = paths.value(state);
220         const int index = itIndex.value();
221 
222         QIcon pixmapIcon = QIcon(icon.pixmap(16, 16, state.first, state.second));
223         if (pixmapIcon.isNull())
224             pixmapIcon = m_emptyIcon;
225         m_stateComboBox->setItemIcon(index, pixmapIcon);
226         QFont font = q_ptr->font();
227         if (!pixmap.path().isEmpty())
228             font.setBold(true);
229         m_stateComboBox->setItemData(index, font, Qt::FontRole);
230     }
231 
232     QPair<QIcon::Mode, QIcon::State> state = m_indexToState.value(m_stateComboBox->currentIndex());
233     PropertySheetPixmapValue currentPixmap = paths.value(state);
234     m_resetAction->setEnabled(!currentPixmap.path().isEmpty());
235     m_resetAllAction->setEnabled(!paths.isEmpty());
236     m_stateComboBox->update();
237 }
238 
slotStateActivated()239 void IconSelectorPrivate::slotStateActivated()
240 {
241     slotUpdate();
242 }
243 
slotSetActivated()244 void IconSelectorPrivate::slotSetActivated()
245 {
246     QPair<QIcon::Mode, QIcon::State> state = m_indexToState.value(m_stateComboBox->currentIndex());
247     const PropertySheetPixmapValue pixmap = m_icon.pixmap(state.first, state.second);
248     // Default to resource
249     const PropertySheetPixmapValue::PixmapSource ps = pixmap.path().isEmpty() ? PropertySheetPixmapValue::ResourcePixmap : pixmap.pixmapSource(m_core);
250     switch (ps) {
251     case PropertySheetPixmapValue::LanguageResourcePixmap:
252     case PropertySheetPixmapValue::ResourcePixmap:
253         slotSetResourceActivated();
254         break;
255     case PropertySheetPixmapValue::FilePixmap:
256         slotSetFileActivated();
257         break;
258     }
259 }
260 
261 // Choose a pixmap from resource; use language-dependent resource browser if present
choosePixmapResource(QDesignerFormEditorInterface * core,QtResourceModel * resourceModel,const QString & oldPath,QWidget * parent)262 QString IconSelector::choosePixmapResource(QDesignerFormEditorInterface *core, QtResourceModel *resourceModel, const QString &oldPath, QWidget *parent)
263 {
264     Q_UNUSED(resourceModel);
265     QString rc;
266 
267     if (LanguageResourceDialog* ldlg = LanguageResourceDialog::create(core, parent)) {
268         ldlg->setCurrentPath(oldPath);
269         if (ldlg->exec() == QDialog::Accepted)
270             rc = ldlg->currentPath();
271         delete ldlg;
272     } else {
273         QtResourceViewDialog dlg(core, parent);
274         dlg.setResourceEditingEnabled(core->integration()->hasFeature(QDesignerIntegration::ResourceEditorFeature));
275 
276         dlg.selectResource(oldPath);
277         if (dlg.exec() == QDialog::Accepted)
278             rc = dlg.selectedResource();
279     }
280     return rc;
281 }
282 
slotSetResourceActivated()283 void IconSelectorPrivate::slotSetResourceActivated()
284 {
285     const QPair<QIcon::Mode, QIcon::State> state = m_indexToState.value(m_stateComboBox->currentIndex());
286 
287     PropertySheetPixmapValue pixmap = m_icon.pixmap(state.first, state.second);
288     const QString oldPath = pixmap.path();
289     const QString newPath = IconSelector::choosePixmapResource(m_core, m_resourceModel, oldPath, q_ptr);
290     if (newPath.isEmpty() || newPath == oldPath)
291         return;
292     const PropertySheetPixmapValue newPixmap = PropertySheetPixmapValue(newPath);
293     if (newPixmap != pixmap) {
294         m_icon.setPixmap(state.first, state.second, newPixmap);
295         slotUpdate();
296         emit q_ptr->iconChanged(m_icon);
297     }
298 }
299 
300 // Helpers for choosing image files: Check for valid image.
checkPixmap(const QString & fileName,CheckMode cm,QString * errorMessage)301 bool IconSelector::checkPixmap(const QString &fileName, CheckMode cm, QString *errorMessage)
302 {
303     const QFileInfo fi(fileName);
304     if (!fi.exists() || !fi.isFile() || !fi.isReadable()) {
305         if (errorMessage)
306             *errorMessage = tr("The pixmap file '%1' cannot be read.").arg(fileName);
307         return false;
308     }
309     QImageReader reader(fileName);
310     if (!reader.canRead()) {
311         if (errorMessage)
312             *errorMessage = tr("The file '%1' does not appear to be a valid pixmap file: %2")
313                               .arg(fileName, reader.errorString());
314         return false;
315     }
316     if (cm == CheckFast)
317         return true;
318 
319     const QImage image = reader.read();
320     if (image.isNull()) {
321         if (errorMessage)
322             *errorMessage = tr("The file '%1' could not be read: %2")
323                                .arg(fileName, reader.errorString());
324         return false;
325     }
326     return true;
327 }
328 
329 // Helpers for choosing image files: Return an image filter for QFileDialog, courtesy of StyledButton
imageFilter()330 static QString imageFilter()
331 {
332     QString filter = QApplication::translate("IconSelector", "All Pixmaps (");
333     const auto supportedImageFormats = QImageReader::supportedImageFormats();
334     const QString jpeg = QStringLiteral("JPEG");
335     const int count = supportedImageFormats.count();
336     for (int i = 0; i< count; ++i) {
337         if (i)
338             filter += QLatin1Char(' ');
339         filter += QStringLiteral("*.");
340         const QString outputFormat = QString::fromUtf8(supportedImageFormats.at(i));
341         if (outputFormat != jpeg)
342             filter += outputFormat.toLower();
343         else
344             filter += QStringLiteral("jpg *.jpeg");
345     }
346     filter += QLatin1Char(')');
347     return filter;
348 }
349 
350 // Helpers for choosing image files: Choose a file
choosePixmapFile(const QString & directory,QDesignerDialogGuiInterface * dlgGui,QWidget * parent)351 QString IconSelector::choosePixmapFile(const QString &directory, QDesignerDialogGuiInterface *dlgGui,QWidget *parent)
352 {
353     QString errorMessage;
354     QString newPath;
355     do {
356         const QString title = tr("Choose a Pixmap");
357         static const  QString filter = imageFilter();
358         newPath =  dlgGui->getOpenImageFileName(parent, title, directory, filter);
359         if (newPath.isEmpty())
360             break;
361         if (checkPixmap(newPath, CheckFully, &errorMessage))
362             break;
363         dlgGui->message(parent, QDesignerDialogGuiInterface::ResourceEditorMessage, QMessageBox::Warning, tr("Pixmap Read Error"), errorMessage);
364     } while(true);
365     return  newPath;
366 }
367 
slotSetFileActivated()368 void IconSelectorPrivate::slotSetFileActivated()
369 {
370     QPair<QIcon::Mode, QIcon::State> state = m_indexToState.value(m_stateComboBox->currentIndex());
371 
372     PropertySheetPixmapValue pixmap = m_icon.pixmap(state.first, state.second);
373     const QString newPath = IconSelector::choosePixmapFile(pixmap.path(), m_core->dialogGui(), q_ptr);
374     if (!newPath.isEmpty()) {
375         const PropertySheetPixmapValue newPixmap = PropertySheetPixmapValue(newPath);
376         if (!(newPixmap == pixmap)) {
377             m_icon.setPixmap(state.first, state.second, newPixmap);
378             slotUpdate();
379             emit q_ptr->iconChanged(m_icon);
380         }
381     }
382 }
383 
slotResetActivated()384 void IconSelectorPrivate::slotResetActivated()
385 {
386     QPair<QIcon::Mode, QIcon::State> state = m_indexToState.value(m_stateComboBox->currentIndex());
387 
388     PropertySheetPixmapValue pixmap = m_icon.pixmap(state.first, state.second);
389     const PropertySheetPixmapValue newPixmap;
390     if (!(newPixmap == pixmap)) {
391         m_icon.setPixmap(state.first, state.second, newPixmap);
392         slotUpdate();
393         emit q_ptr->iconChanged(m_icon);
394     }
395 }
396 
slotResetAllActivated()397 void IconSelectorPrivate::slotResetAllActivated()
398 {
399     const PropertySheetIconValue newIcon;
400     if (!(m_icon == newIcon)) {
401         m_icon = newIcon;
402         slotUpdate();
403         emit q_ptr->iconChanged(m_icon);
404     }
405 }
406 
407 // ------------- IconSelector
IconSelector(QWidget * parent)408 IconSelector::IconSelector(QWidget *parent) :
409     QWidget(parent), d_ptr(new IconSelectorPrivate())
410 {
411     d_ptr->q_ptr = this;
412 
413     d_ptr->m_stateComboBox = new QComboBox(this);
414 
415     QHBoxLayout *l = new QHBoxLayout(this);
416     d_ptr->m_iconButton = new QToolButton(this);
417     d_ptr->m_iconButton->setText(tr("..."));
418     d_ptr->m_iconButton->setPopupMode(QToolButton::MenuButtonPopup);
419     l->addWidget(d_ptr->m_stateComboBox);
420     l->addWidget(d_ptr->m_iconButton);
421     l->setContentsMargins(QMargins());
422 
423     d_ptr->m_stateToName << qMakePair(qMakePair(QIcon::Normal,   QIcon::Off), tr("Normal Off")   );
424     d_ptr->m_stateToName << qMakePair(qMakePair(QIcon::Normal,   QIcon::On),  tr("Normal On")    );
425     d_ptr->m_stateToName << qMakePair(qMakePair(QIcon::Disabled, QIcon::Off), tr("Disabled Off") );
426     d_ptr->m_stateToName << qMakePair(qMakePair(QIcon::Disabled, QIcon::On),  tr("Disabled On")  );
427     d_ptr->m_stateToName << qMakePair(qMakePair(QIcon::Active,   QIcon::Off), tr("Active Off")   );
428     d_ptr->m_stateToName << qMakePair(qMakePair(QIcon::Active,   QIcon::On),  tr("Active On")    );
429     d_ptr->m_stateToName << qMakePair(qMakePair(QIcon::Selected, QIcon::Off), tr("Selected Off") );
430     d_ptr->m_stateToName << qMakePair(qMakePair(QIcon::Selected, QIcon::On),  tr("Selected On")  );
431 
432     QMenu *setMenu = new QMenu(this);
433 
434     QAction *setResourceAction = new QAction(tr("Choose Resource..."), this);
435     QAction *setFileAction = new QAction(tr("Choose File..."), this);
436     d_ptr->m_resetAction = new QAction(tr("Reset"), this);
437     d_ptr->m_resetAllAction = new QAction(tr("Reset All"), this);
438     d_ptr->m_resetAction->setEnabled(false);
439     d_ptr->m_resetAllAction->setEnabled(false);
440     //d_ptr->m_resetAction->setIcon(createIconSet(QString::fromUtf8("resetproperty.png")));
441 
442     setMenu->addAction(setResourceAction);
443     setMenu->addAction(setFileAction);
444     setMenu->addSeparator();
445     setMenu->addAction(d_ptr->m_resetAction);
446     setMenu->addAction(d_ptr->m_resetAllAction);
447 
448     int index = 0;
449     QStringList items;
450     for (const auto &item : qAsConst(d_ptr->m_stateToName)) {
451         const QPair<QIcon::Mode, QIcon::State> state = item.first;
452         const QString name = item.second;
453 
454         items.append(name);
455         d_ptr->m_stateToIndex[state] = index;
456         d_ptr->m_indexToState[index] = state;
457         index++;
458     }
459     d_ptr->m_stateComboBox->addItems(items);
460 
461     d_ptr->m_iconButton->setMenu(setMenu);
462 
463     connect(d_ptr->m_stateComboBox, SIGNAL(activated(int)), this, SLOT(slotStateActivated()));
464     connect(d_ptr->m_iconButton, SIGNAL(clicked()), this, SLOT(slotSetActivated()));
465     connect(setResourceAction, SIGNAL(triggered()), this, SLOT(slotSetResourceActivated()));
466     connect(setFileAction, SIGNAL(triggered()), this, SLOT(slotSetFileActivated()));
467     connect(d_ptr->m_resetAction, SIGNAL(triggered()), this, SLOT(slotResetActivated()));
468     connect(d_ptr->m_resetAllAction, SIGNAL(triggered()), this, SLOT(slotResetAllActivated()));
469 
470     d_ptr->slotUpdate();
471 }
472 
473 IconSelector::~IconSelector() = default;
474 
setIcon(const PropertySheetIconValue & icon)475 void IconSelector::setIcon(const PropertySheetIconValue &icon)
476 {
477     if (d_ptr->m_icon == icon)
478         return;
479 
480     d_ptr->m_icon = icon;
481     d_ptr->slotUpdate();
482 }
483 
icon() const484 PropertySheetIconValue IconSelector::icon() const
485 {
486     return d_ptr->m_icon;
487 }
488 
setFormEditor(QDesignerFormEditorInterface * core)489 void IconSelector::setFormEditor(QDesignerFormEditorInterface *core)
490 {
491     d_ptr->m_core = core;
492     d_ptr->m_resourceModel = core->resourceModel();
493     d_ptr->slotUpdate();
494 }
495 
setIconCache(DesignerIconCache * iconCache)496 void IconSelector::setIconCache(DesignerIconCache *iconCache)
497 {
498     d_ptr->m_iconCache = iconCache;
499     connect(iconCache, SIGNAL(reloaded()), this, SLOT(slotUpdate()));
500     d_ptr->slotUpdate();
501 }
502 
setPixmapCache(DesignerPixmapCache * pixmapCache)503 void IconSelector::setPixmapCache(DesignerPixmapCache *pixmapCache)
504 {
505     d_ptr->m_pixmapCache = pixmapCache;
506     connect(pixmapCache, SIGNAL(reloaded()), this, SLOT(slotUpdate()));
507     d_ptr->slotUpdate();
508 }
509 
510 // --- IconThemeEditor
511 
512 // Validator for theme line edit, accepts empty or non-blank strings.
513 class BlankSuppressingValidator : public QValidator {
514 public:
BlankSuppressingValidator(QObject * parent=nullptr)515     explicit BlankSuppressingValidator(QObject * parent = nullptr) : QValidator(parent) {}
516 
validate(QString & input,int & pos) const517     State validate(QString &input, int &pos) const override
518     {
519         const int blankPos = input.indexOf(QLatin1Char(' '));
520         if (blankPos != -1) {
521             pos = blankPos;
522             return Invalid;
523         }
524         return Acceptable;
525     }
526 };
527 
528 struct IconThemeEditorPrivate {
529     IconThemeEditorPrivate();
530 
531     const QPixmap m_emptyPixmap;
532     QLineEdit *m_themeLineEdit;
533     QLabel *m_themeLabel;
534 };
535 
IconThemeEditorPrivate()536 IconThemeEditorPrivate::IconThemeEditorPrivate() :
537     m_emptyPixmap(emptyPixmap()),
538     m_themeLineEdit(new QLineEdit),
539     m_themeLabel(new QLabel)
540 {
541 }
542 
IconThemeEditor(QWidget * parent,bool wantResetButton)543 IconThemeEditor::IconThemeEditor(QWidget *parent, bool wantResetButton) :
544     QWidget (parent), d(new IconThemeEditorPrivate)
545 {
546     QHBoxLayout *mainHLayout = new QHBoxLayout;
547     mainHLayout->setContentsMargins(QMargins());
548 
549     // Vertically center theme preview label
550     d->m_themeLabel->setPixmap(d->m_emptyPixmap);
551 
552     QVBoxLayout *themeLabelVLayout = new QVBoxLayout;
553     d->m_themeLabel->setMargin(1);
554     themeLabelVLayout->setContentsMargins(QMargins());
555     themeLabelVLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding));
556     themeLabelVLayout->addWidget(d->m_themeLabel);
557     themeLabelVLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding));
558     mainHLayout->addLayout(themeLabelVLayout);
559 
560     d->m_themeLineEdit = new QLineEdit;
561     d->m_themeLineEdit->setValidator(new BlankSuppressingValidator(d->m_themeLineEdit));
562     connect(d->m_themeLineEdit, &QLineEdit::textChanged, this, &IconThemeEditor::slotChanged);
563     connect(d->m_themeLineEdit, &QLineEdit::textEdited, this, &IconThemeEditor::edited);
564     mainHLayout->addWidget(d->m_themeLineEdit);
565 
566     if (wantResetButton) {
567         QToolButton *themeResetButton = new QToolButton;
568         themeResetButton->setIcon(createIconSet(QStringLiteral("resetproperty.png")));
569         connect(themeResetButton, &QAbstractButton::clicked, this, &IconThemeEditor::reset);
570         mainHLayout->addWidget(themeResetButton);
571     }
572 
573     setLayout(mainHLayout);
574     setFocusProxy(d->m_themeLineEdit);
575 }
576 
577 IconThemeEditor::~IconThemeEditor() = default;
578 
reset()579 void IconThemeEditor::reset()
580 {
581     d->m_themeLineEdit->clear();
582     emit edited(QString());
583 }
584 
slotChanged(const QString & theme)585 void IconThemeEditor::slotChanged(const QString &theme)
586 {
587     updatePreview(theme);
588 }
589 
updatePreview(const QString & t)590 void IconThemeEditor::updatePreview(const QString &t)
591 {
592     // Update preview label with icon.
593     if (t.isEmpty() || !QIcon::hasThemeIcon(t)) { // Empty
594         if (d->m_themeLabel->pixmap(Qt::ReturnByValue).cacheKey() != d->m_emptyPixmap.cacheKey())
595             d->m_themeLabel->setPixmap(d->m_emptyPixmap);
596     } else {
597         const QIcon icon = QIcon::fromTheme(t);
598         d->m_themeLabel->setPixmap(icon.pixmap(d->m_emptyPixmap.size()));
599     }
600 }
601 
theme() const602 QString IconThemeEditor::theme() const
603 {
604     return d->m_themeLineEdit->text();
605 }
606 
setTheme(const QString & t)607 void IconThemeEditor::setTheme(const QString &t)
608 {
609     d->m_themeLineEdit->setText(t);
610 }
611 
612 } // qdesigner_internal
613 
614 QT_END_NAMESPACE
615 
616 #include "moc_iconselector_p.cpp"
617