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: |
81 | void setOkButtonEnabled(bool v) { m_dialogButtonBox->button(which: QDialogButtonBox::Ok)->setEnabled(v); } |
82 | static bool checkPath(const QString &p); |
83 | |
84 | QDesignerResourceBrowserInterface *m_browser; |
85 | QDialogButtonBox *m_dialogButtonBox; |
86 | }; |
87 | |
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 | |
96 | void LanguageResourceDialogPrivate::init(LanguageResourceDialog *p) |
97 | { |
98 | q_ptr = p; |
99 | QLayout *layout = new QVBoxLayout(p); |
100 | layout->addWidget(w: m_browser); |
101 | layout->addWidget(w: m_dialogButtonBox); |
102 | QObject::connect(sender: m_dialogButtonBox, SIGNAL(accepted()), receiver: p, SLOT(slotAccepted())); |
103 | QObject::connect(sender: m_dialogButtonBox, signal: &QDialogButtonBox::rejected, receiver: p, slot: &QDialog::reject); |
104 | QObject::connect(sender: m_browser, SIGNAL(currentPathChanged(QString)), receiver: p, SLOT(slotPathChanged(QString))); |
105 | QObject::connect(sender: m_browser, SIGNAL(pathActivated(QString)), receiver: p, SLOT(slotAccepted())); |
106 | p->setModal(true); |
107 | p->setWindowTitle(LanguageResourceDialog::tr(s: "Choose Resource" )); |
108 | p->setWindowFlags(p->windowFlags() & ~Qt::WindowContextHelpButtonHint); |
109 | setOkButtonEnabled(false); |
110 | } |
111 | |
112 | void LanguageResourceDialogPrivate::setCurrentPath(const QString &filePath) |
113 | { |
114 | m_browser->setCurrentPath(filePath); |
115 | setOkButtonEnabled(checkPath(p: filePath)); |
116 | } |
117 | |
118 | QString LanguageResourceDialogPrivate::currentPath() const |
119 | { |
120 | return m_browser->currentPath(); |
121 | } |
122 | |
123 | bool LanguageResourceDialogPrivate::checkPath(const QString &p) |
124 | { |
125 | return p.isEmpty() ? false : IconSelector::checkPixmap(fileName: p, cm: IconSelector::CheckFast); |
126 | } |
127 | |
128 | void LanguageResourceDialogPrivate::slotAccepted() |
129 | { |
130 | if (checkPath(p: currentPath())) |
131 | q_ptr->accept(); |
132 | } |
133 | |
134 | void LanguageResourceDialogPrivate::slotPathChanged(const QString &p) |
135 | { |
136 | setOkButtonEnabled(checkPath(p)); |
137 | } |
138 | |
139 | // ------------ LanguageResourceDialog |
140 | LanguageResourceDialog::LanguageResourceDialog(QDesignerResourceBrowserInterface *rb, QWidget *parent) : |
141 | QDialog(parent), |
142 | d_ptr(new LanguageResourceDialogPrivate(rb)) |
143 | { |
144 | d_ptr->init( p: this); |
145 | } |
146 | |
147 | LanguageResourceDialog::~LanguageResourceDialog() = default; |
148 | |
149 | void LanguageResourceDialog::setCurrentPath(const QString &filePath) |
150 | { |
151 | d_ptr->setCurrentPath(filePath); |
152 | } |
153 | |
154 | QString LanguageResourceDialog::currentPath() const |
155 | { |
156 | return d_ptr->currentPath(); |
157 | } |
158 | |
159 | LanguageResourceDialog* LanguageResourceDialog::create(QDesignerFormEditorInterface *core, QWidget *parent) |
160 | { |
161 | if (QDesignerLanguageExtension *lang = qt_extension<QDesignerLanguageExtension *>(manager: core->extensionManager(), object: core)) |
162 | if (QDesignerResourceBrowserInterface *rb = lang->createResourceBrowser(parentWidget: nullptr)) |
163 | return new LanguageResourceDialog(rb, parent); |
164 | if (QDesignerResourceBrowserInterface *rb = core->integration()->createResourceBrowser(parent: nullptr)) |
165 | return new LanguageResourceDialog(rb, parent); |
166 | return nullptr; |
167 | } |
168 | |
169 | // ------------ IconSelectorPrivate |
170 | |
171 | static inline QPixmap emptyPixmap() |
172 | { |
173 | QImage img(16, 16, QImage::Format_ARGB32_Premultiplied); |
174 | img.fill(pixel: 0); |
175 | return QPixmap::fromImage(image: 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 | |
210 | void IconSelectorPrivate::slotUpdate() |
211 | { |
212 | QIcon icon; |
213 | if (m_iconCache) |
214 | icon = m_iconCache->icon(value: 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(akey: state); |
220 | const int index = itIndex.value(); |
221 | |
222 | QIcon pixmapIcon = QIcon(icon.pixmap(w: 16, h: 16, mode: state.first, state: state.second)); |
223 | if (pixmapIcon.isNull()) |
224 | pixmapIcon = m_emptyIcon; |
225 | m_stateComboBox->setItemIcon(index, icon: pixmapIcon); |
226 | QFont font = q_ptr->font(); |
227 | if (!pixmap.path().isEmpty()) |
228 | font.setBold(true); |
229 | m_stateComboBox->setItemData(index, value: font, role: Qt::FontRole); |
230 | } |
231 | |
232 | QPair<QIcon::Mode, QIcon::State> state = m_indexToState.value(akey: m_stateComboBox->currentIndex()); |
233 | PropertySheetPixmapValue currentPixmap = paths.value(akey: state); |
234 | m_resetAction->setEnabled(!currentPixmap.path().isEmpty()); |
235 | m_resetAllAction->setEnabled(!paths.isEmpty()); |
236 | m_stateComboBox->update(); |
237 | } |
238 | |
239 | void IconSelectorPrivate::slotStateActivated() |
240 | { |
241 | slotUpdate(); |
242 | } |
243 | |
244 | void IconSelectorPrivate::slotSetActivated() |
245 | { |
246 | QPair<QIcon::Mode, QIcon::State> state = m_indexToState.value(akey: m_stateComboBox->currentIndex()); |
247 | const PropertySheetPixmapValue pixmap = m_icon.pixmap(mode: state.first, state: state.second); |
248 | // Default to resource |
249 | const PropertySheetPixmapValue::PixmapSource ps = pixmap.path().isEmpty() ? PropertySheetPixmapValue::ResourcePixmap : pixmap.pixmapSource(core: 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 |
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(f: QDesignerIntegration::ResourceEditorFeature)); |
275 | |
276 | dlg.selectResource(path: oldPath); |
277 | if (dlg.exec() == QDialog::Accepted) |
278 | rc = dlg.selectedResource(); |
279 | } |
280 | return rc; |
281 | } |
282 | |
283 | void IconSelectorPrivate::slotSetResourceActivated() |
284 | { |
285 | const QPair<QIcon::Mode, QIcon::State> state = m_indexToState.value(akey: m_stateComboBox->currentIndex()); |
286 | |
287 | PropertySheetPixmapValue pixmap = m_icon.pixmap(mode: state.first, state: state.second); |
288 | const QString oldPath = pixmap.path(); |
289 | const QString newPath = IconSelector::choosePixmapResource(core: m_core, resourceModel: m_resourceModel, oldPath, parent: q_ptr); |
290 | if (newPath.isEmpty() || newPath == oldPath) |
291 | return; |
292 | const PropertySheetPixmapValue newPixmap = PropertySheetPixmapValue(newPath); |
293 | if (newPixmap != pixmap) { |
294 | m_icon.setPixmap(mode: state.first, state: state.second, path: newPixmap); |
295 | slotUpdate(); |
296 | emit q_ptr->iconChanged(icon: m_icon); |
297 | } |
298 | } |
299 | |
300 | // Helpers for choosing image files: Check for valid image. |
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(s: "The pixmap file '%1' cannot be read." ).arg(a: fileName); |
307 | return false; |
308 | } |
309 | QImageReader reader(fileName); |
310 | if (!reader.canRead()) { |
311 | if (errorMessage) |
312 | *errorMessage = tr(s: "The file '%1' does not appear to be a valid pixmap file: %2" ) |
313 | .arg(args: fileName, args: 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(s: "The file '%1' could not be read: %2" ) |
323 | .arg(args: fileName, args: 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 |
330 | static QString imageFilter() |
331 | { |
332 | QString filter = QApplication::translate(context: "IconSelector" , key: "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(str: 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 |
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(s: "Choose a Pixmap" ); |
357 | static const QString filter = imageFilter(); |
358 | newPath = dlgGui->getOpenImageFileName(parent, caption: title, dir: directory, filter); |
359 | if (newPath.isEmpty()) |
360 | break; |
361 | if (checkPixmap(fileName: newPath, cm: CheckFully, errorMessage: &errorMessage)) |
362 | break; |
363 | dlgGui->message(parent, context: QDesignerDialogGuiInterface::ResourceEditorMessage, icon: QMessageBox::Warning, title: tr(s: "Pixmap Read Error" ), text: errorMessage); |
364 | } while(true); |
365 | return newPath; |
366 | } |
367 | |
368 | void IconSelectorPrivate::slotSetFileActivated() |
369 | { |
370 | QPair<QIcon::Mode, QIcon::State> state = m_indexToState.value(akey: m_stateComboBox->currentIndex()); |
371 | |
372 | PropertySheetPixmapValue pixmap = m_icon.pixmap(mode: state.first, state: state.second); |
373 | const QString newPath = IconSelector::choosePixmapFile(directory: pixmap.path(), dlgGui: m_core->dialogGui(), parent: q_ptr); |
374 | if (!newPath.isEmpty()) { |
375 | const PropertySheetPixmapValue newPixmap = PropertySheetPixmapValue(newPath); |
376 | if (!(newPixmap == pixmap)) { |
377 | m_icon.setPixmap(mode: state.first, state: state.second, path: newPixmap); |
378 | slotUpdate(); |
379 | emit q_ptr->iconChanged(icon: m_icon); |
380 | } |
381 | } |
382 | } |
383 | |
384 | void IconSelectorPrivate::slotResetActivated() |
385 | { |
386 | QPair<QIcon::Mode, QIcon::State> state = m_indexToState.value(akey: m_stateComboBox->currentIndex()); |
387 | |
388 | PropertySheetPixmapValue pixmap = m_icon.pixmap(mode: state.first, state: state.second); |
389 | const PropertySheetPixmapValue newPixmap; |
390 | if (!(newPixmap == pixmap)) { |
391 | m_icon.setPixmap(mode: state.first, state: state.second, path: newPixmap); |
392 | slotUpdate(); |
393 | emit q_ptr->iconChanged(icon: m_icon); |
394 | } |
395 | } |
396 | |
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(icon: m_icon); |
404 | } |
405 | } |
406 | |
407 | // ------------- IconSelector |
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(s: "..." )); |
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(x: qMakePair(x: QIcon::Normal, y: QIcon::Off), y: tr(s: "Normal Off" ) ); |
424 | d_ptr->m_stateToName << qMakePair(x: qMakePair(x: QIcon::Normal, y: QIcon::On), y: tr(s: "Normal On" ) ); |
425 | d_ptr->m_stateToName << qMakePair(x: qMakePair(x: QIcon::Disabled, y: QIcon::Off), y: tr(s: "Disabled Off" ) ); |
426 | d_ptr->m_stateToName << qMakePair(x: qMakePair(x: QIcon::Disabled, y: QIcon::On), y: tr(s: "Disabled On" ) ); |
427 | d_ptr->m_stateToName << qMakePair(x: qMakePair(x: QIcon::Active, y: QIcon::Off), y: tr(s: "Active Off" ) ); |
428 | d_ptr->m_stateToName << qMakePair(x: qMakePair(x: QIcon::Active, y: QIcon::On), y: tr(s: "Active On" ) ); |
429 | d_ptr->m_stateToName << qMakePair(x: qMakePair(x: QIcon::Selected, y: QIcon::Off), y: tr(s: "Selected Off" ) ); |
430 | d_ptr->m_stateToName << qMakePair(x: qMakePair(x: QIcon::Selected, y: QIcon::On), y: tr(s: "Selected On" ) ); |
431 | |
432 | QMenu * = new QMenu(this); |
433 | |
434 | QAction *setResourceAction = new QAction(tr(s: "Choose Resource..." ), this); |
435 | QAction *setFileAction = new QAction(tr(s: "Choose File..." ), this); |
436 | d_ptr->m_resetAction = new QAction(tr(s: "Reset" ), this); |
437 | d_ptr->m_resetAllAction = new QAction(tr(s: "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(action: setResourceAction); |
443 | setMenu->addAction(action: setFileAction); |
444 | setMenu->addSeparator(); |
445 | setMenu->addAction(action: d_ptr->m_resetAction); |
446 | setMenu->addAction(action: d_ptr->m_resetAllAction); |
447 | |
448 | int index = 0; |
449 | QStringList items; |
450 | for (const auto &item : qAsConst(t&: d_ptr->m_stateToName)) { |
451 | const QPair<QIcon::Mode, QIcon::State> state = item.first; |
452 | const QString name = item.second; |
453 | |
454 | items.append(t: name); |
455 | d_ptr->m_stateToIndex[state] = index; |
456 | d_ptr->m_indexToState[index] = state; |
457 | index++; |
458 | } |
459 | d_ptr->m_stateComboBox->addItems(texts: items); |
460 | |
461 | d_ptr->m_iconButton->setMenu(setMenu); |
462 | |
463 | connect(sender: d_ptr->m_stateComboBox, SIGNAL(activated(int)), receiver: this, SLOT(slotStateActivated())); |
464 | connect(sender: d_ptr->m_iconButton, SIGNAL(clicked()), receiver: this, SLOT(slotSetActivated())); |
465 | connect(sender: setResourceAction, SIGNAL(triggered()), receiver: this, SLOT(slotSetResourceActivated())); |
466 | connect(sender: setFileAction, SIGNAL(triggered()), receiver: this, SLOT(slotSetFileActivated())); |
467 | connect(sender: d_ptr->m_resetAction, SIGNAL(triggered()), receiver: this, SLOT(slotResetActivated())); |
468 | connect(sender: d_ptr->m_resetAllAction, SIGNAL(triggered()), receiver: this, SLOT(slotResetAllActivated())); |
469 | |
470 | d_ptr->slotUpdate(); |
471 | } |
472 | |
473 | IconSelector::~IconSelector() = default; |
474 | |
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 | |
484 | PropertySheetIconValue IconSelector::icon() const |
485 | { |
486 | return d_ptr->m_icon; |
487 | } |
488 | |
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 | |
496 | void IconSelector::setIconCache(DesignerIconCache *iconCache) |
497 | { |
498 | d_ptr->m_iconCache = iconCache; |
499 | connect(sender: iconCache, SIGNAL(reloaded()), receiver: this, SLOT(slotUpdate())); |
500 | d_ptr->slotUpdate(); |
501 | } |
502 | |
503 | void IconSelector::setPixmapCache(DesignerPixmapCache *pixmapCache) |
504 | { |
505 | d_ptr->m_pixmapCache = pixmapCache; |
506 | connect(sender: pixmapCache, SIGNAL(reloaded()), receiver: 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: |
515 | explicit BlankSuppressingValidator(QObject * parent = nullptr) : QValidator(parent) {} |
516 | |
517 | State validate(QString &input, int &pos) const override |
518 | { |
519 | const int blankPos = input.indexOf(c: 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 | |
536 | IconThemeEditorPrivate::IconThemeEditorPrivate() : |
537 | m_emptyPixmap(emptyPixmap()), |
538 | m_themeLineEdit(new QLineEdit), |
539 | m_themeLabel(new QLabel) |
540 | { |
541 | } |
542 | |
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(spacerItem: new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding)); |
556 | themeLabelVLayout->addWidget(d->m_themeLabel); |
557 | themeLabelVLayout->addSpacerItem(spacerItem: new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding)); |
558 | mainHLayout->addLayout(layout: themeLabelVLayout); |
559 | |
560 | d->m_themeLineEdit = new QLineEdit; |
561 | d->m_themeLineEdit->setValidator(new BlankSuppressingValidator(d->m_themeLineEdit)); |
562 | connect(sender: d->m_themeLineEdit, signal: &QLineEdit::textChanged, receiver: this, slot: &IconThemeEditor::slotChanged); |
563 | connect(sender: d->m_themeLineEdit, signal: &QLineEdit::textEdited, receiver: this, slot: &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(sender: themeResetButton, signal: &QAbstractButton::clicked, receiver: this, slot: &IconThemeEditor::reset); |
570 | mainHLayout->addWidget(themeResetButton); |
571 | } |
572 | |
573 | setLayout(mainHLayout); |
574 | setFocusProxy(d->m_themeLineEdit); |
575 | } |
576 | |
577 | IconThemeEditor::~IconThemeEditor() = default; |
578 | |
579 | void IconThemeEditor::reset() |
580 | { |
581 | d->m_themeLineEdit->clear(); |
582 | emit edited(QString()); |
583 | } |
584 | |
585 | void IconThemeEditor::slotChanged(const QString &theme) |
586 | { |
587 | updatePreview(theme); |
588 | } |
589 | |
590 | void IconThemeEditor::updatePreview(const QString &t) |
591 | { |
592 | // Update preview label with icon. |
593 | if (t.isEmpty() || !QIcon::hasThemeIcon(name: 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(name: t); |
598 | d->m_themeLabel->setPixmap(icon.pixmap(size: d->m_emptyPixmap.size())); |
599 | } |
600 | } |
601 | |
602 | QString IconThemeEditor::theme() const |
603 | { |
604 | return d->m_themeLineEdit->text(); |
605 | } |
606 | |
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 | |