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 "newformwidget_p.h" |
30 | #include "ui_newformwidget.h" |
31 | #include "qdesigner_formbuilder_p.h" |
32 | #include "sheet_delegate_p.h" |
33 | #include "widgetdatabase_p.h" |
34 | #include "shared_settings_p.h" |
35 | |
36 | #include <QtDesigner/abstractformeditor.h> |
37 | #include <QtDesigner/abstractformwindow.h> |
38 | #include <QtDesigner/qextensionmanager.h> |
39 | #include <QtDesigner/abstractlanguage.h> |
40 | #include <QtDesigner/abstractwidgetdatabase.h> |
41 | |
42 | #include <QtCore/qdir.h> |
43 | #include <QtCore/qfile.h> |
44 | #include <QtCore/qfileinfo.h> |
45 | #include <QtCore/qdebug.h> |
46 | #include <QtCore/qbytearray.h> |
47 | #include <QtCore/qbuffer.h> |
48 | #include <QtCore/qdir.h> |
49 | #include <QtCore/qtextstream.h> |
50 | |
51 | #include <QtWidgets/qapplication.h> |
52 | #include <QtWidgets/qdesktopwidget.h> |
53 | #include <QtWidgets/qheaderview.h> |
54 | #include <QtWidgets/qtreewidget.h> |
55 | #include <QtGui/qpainter.h> |
56 | #include <QtWidgets/qpushbutton.h> |
57 | |
58 | QT_BEGIN_NAMESPACE |
59 | |
60 | enum { profileComboIndexOffset = 1 }; |
61 | enum { debugNewFormWidget = 0 }; |
62 | |
63 | enum NewForm_CustomRole { |
64 | // File name (templates from resources, paths) |
65 | TemplateNameRole = Qt::UserRole + 100, |
66 | // Class name (widgets from Widget data base) |
67 | ClassNameRole = Qt::UserRole + 101 |
68 | }; |
69 | |
70 | static const char *newFormObjectNameC = "Form" ; |
71 | |
72 | // Create a form name for an arbitrary class. If it is Qt, qtify it, |
73 | // else return "Form". |
74 | static QString formName(const QString &className) |
75 | { |
76 | if (!className.startsWith(c: QLatin1Char('Q'))) |
77 | return QLatin1String(newFormObjectNameC); |
78 | QString rc = className; |
79 | rc.remove(i: 0, len: 1); |
80 | return rc; |
81 | } |
82 | |
83 | namespace qdesigner_internal { |
84 | |
85 | struct TemplateSize { |
86 | const char *name; |
87 | int width; |
88 | int height; |
89 | }; |
90 | |
91 | static const struct TemplateSize templateSizes[] = |
92 | { |
93 | { QT_TRANSLATE_NOOP("qdesigner_internal::NewFormWidget" , "Default size" ), .width: 0, .height: 0 }, |
94 | { QT_TRANSLATE_NOOP("qdesigner_internal::NewFormWidget" , "QVGA portrait (240x320)" ), .width: 240, .height: 320 }, |
95 | { QT_TRANSLATE_NOOP("qdesigner_internal::NewFormWidget" , "QVGA landscape (320x240)" ), .width: 320, .height: 240 }, |
96 | { QT_TRANSLATE_NOOP("qdesigner_internal::NewFormWidget" , "VGA portrait (480x640)" ), .width: 480, .height: 640 }, |
97 | { QT_TRANSLATE_NOOP("qdesigner_internal::NewFormWidget" , "VGA landscape (640x480)" ), .width: 640, .height: 480 } |
98 | }; |
99 | |
100 | /* -------------- NewForm dialog. |
101 | * Designer takes new form templates from: |
102 | * 1) Files located in directories specified in resources |
103 | * 2) Files located in directories specified as user templates |
104 | * 3) XML from container widgets deemed usable for form templates by the widget |
105 | * database |
106 | * 4) XML from custom container widgets deemed usable for form templates by the |
107 | * widget database |
108 | * |
109 | * The widget database provides helper functions to obtain lists of names |
110 | * and xml for 3,4. |
111 | * |
112 | * Fixed-size forms for embedded platforms are obtained as follows: |
113 | * 1) If the origin is a file: |
114 | * - Check if the file exists in the subdirectory "/<width>x<height>/" of |
115 | * the path (currently the case for the dialog box because the button box |
116 | * needs to be positioned) |
117 | * - Scale the form using the QWidgetDatabase::scaleFormTemplate routine. |
118 | * 2) If the origin is XML: |
119 | * - Scale the form using the QWidgetDatabase::scaleFormTemplate routine. |
120 | * |
121 | * The tree widget item roles indicate which type of entry it is |
122 | * (TemplateNameRole = file name 1,2, ClassNameRole = class name 3,4) |
123 | */ |
124 | |
125 | NewFormWidget::NewFormWidget(QDesignerFormEditorInterface *core, QWidget *parentWidget) : |
126 | QDesignerNewFormWidgetInterface(parentWidget), |
127 | m_core(core), |
128 | m_ui(new Ui::NewFormWidget), |
129 | m_currentItem(nullptr), |
130 | m_acceptedItem(nullptr) |
131 | { |
132 | m_ui->setupUi(this); |
133 | m_ui->treeWidget->setItemDelegate(new qdesigner_internal::SheetDelegate(m_ui->treeWidget, this)); |
134 | m_ui->treeWidget->header()->hide(); |
135 | m_ui->treeWidget->header()->setStretchLastSection(true); |
136 | m_ui->lblPreview->setBackgroundRole(QPalette::Base); |
137 | QDesignerSharedSettings settings(m_core); |
138 | |
139 | QString uiExtension = QStringLiteral("ui" ); |
140 | QString templatePath = QStringLiteral(":/qt-project.org/designer/templates/forms" ); |
141 | |
142 | QDesignerLanguageExtension *lang = qt_extension<QDesignerLanguageExtension *>(manager: core->extensionManager(), object: core); |
143 | if (lang) { |
144 | templatePath = QStringLiteral(":/templates/forms" ); |
145 | uiExtension = lang->uiExtension(); |
146 | } |
147 | |
148 | // Resource templates |
149 | const QString formTemplate = settings.formTemplate(); |
150 | QTreeWidgetItem *selectedItem = nullptr; |
151 | loadFrom(path: templatePath, resourceFile: true, uiExtension, selectedItem: formTemplate, selectedItemFound&: selectedItem); |
152 | // Additional template paths |
153 | const QStringList formTemplatePaths = settings.formTemplatePaths(); |
154 | const QStringList::const_iterator ftcend = formTemplatePaths.constEnd(); |
155 | for (QStringList::const_iterator it = formTemplatePaths.constBegin(); it != ftcend; ++it) |
156 | loadFrom(path: *it, resourceFile: false, uiExtension, selectedItem: formTemplate, selectedItemFound&: selectedItem); |
157 | |
158 | // Widgets/custom widgets |
159 | if (!lang) { |
160 | //: New Form Dialog Categories |
161 | loadFrom(title: tr(s: "Widgets" ), nameList: qdesigner_internal::WidgetDataBase::formWidgetClasses(core), selectedItem: formTemplate, selectedItemFound&: selectedItem); |
162 | loadFrom(title: tr(s: "Custom Widgets" ), nameList: qdesigner_internal::WidgetDataBase::customFormWidgetClasses(core), selectedItem: formTemplate, selectedItemFound&: selectedItem); |
163 | } |
164 | |
165 | // Still no selection - default to first item |
166 | if (selectedItem == nullptr && m_ui->treeWidget->topLevelItemCount() != 0) { |
167 | QTreeWidgetItem *firstTopLevel = m_ui->treeWidget->topLevelItem(index: 0); |
168 | if (firstTopLevel->childCount() > 0) |
169 | selectedItem = firstTopLevel->child(index: 0); |
170 | } |
171 | |
172 | // Open parent, select and make visible |
173 | if (selectedItem) { |
174 | m_ui->treeWidget->setCurrentItem(selectedItem); |
175 | selectedItem->setSelected(true); |
176 | m_ui->treeWidget->scrollToItem(item: selectedItem->parent()); |
177 | } |
178 | // Fill profile combo |
179 | m_deviceProfiles = settings.deviceProfiles(); |
180 | m_ui->profileComboBox->addItem(atext: tr(s: "None" )); |
181 | connect(sender: m_ui->profileComboBox, |
182 | signal: QOverload<int>::of(ptr: &QComboBox::currentIndexChanged), |
183 | receiver: this, slot: &NewFormWidget::slotDeviceProfileIndexChanged); |
184 | if (m_deviceProfiles.isEmpty()) { |
185 | m_ui->profileComboBox->setEnabled(false); |
186 | } else { |
187 | for (const auto &deviceProfile : qAsConst(t&: m_deviceProfiles)) |
188 | m_ui->profileComboBox->addItem(atext: deviceProfile.name()); |
189 | const int ci = settings.currentDeviceProfileIndex(); |
190 | if (ci >= 0) |
191 | m_ui->profileComboBox->setCurrentIndex(ci + profileComboIndexOffset); |
192 | } |
193 | // Fill size combo |
194 | for (const TemplateSize &t : templateSizes) |
195 | m_ui->sizeComboBox->addItem(atext: tr(s: t.name), auserData: QSize(t.width, t.height)); |
196 | |
197 | setTemplateSize(settings.newFormSize()); |
198 | |
199 | if (debugNewFormWidget) |
200 | qDebug() << Q_FUNC_INFO << "Leaving" ; |
201 | } |
202 | |
203 | NewFormWidget::~NewFormWidget() |
204 | { |
205 | QDesignerSharedSettings settings (m_core); |
206 | settings.setNewFormSize(templateSize()); |
207 | // Do not change previously stored item if dialog was rejected |
208 | if (m_acceptedItem) |
209 | settings.setFormTemplate(m_acceptedItem->text(column: 0)); |
210 | delete m_ui; |
211 | } |
212 | |
213 | void NewFormWidget::on_treeWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *) |
214 | { |
215 | if (debugNewFormWidget) |
216 | qDebug() << Q_FUNC_INFO << current; |
217 | if (!current) |
218 | return; |
219 | |
220 | if (!current->parent()) { // Top level item: Ensure expanded when browsing down |
221 | return; |
222 | } |
223 | |
224 | m_currentItem = current; |
225 | |
226 | emit currentTemplateChanged(templateSelected: showCurrentItemPixmap()); |
227 | } |
228 | |
229 | bool NewFormWidget::showCurrentItemPixmap() |
230 | { |
231 | bool rc = false; |
232 | if (m_currentItem) { |
233 | const QPixmap pixmap = formPreviewPixmap(item: m_currentItem); |
234 | if (pixmap.isNull()) { |
235 | m_ui->lblPreview->setText(tr(s: "Error loading form" )); |
236 | } else { |
237 | m_ui->lblPreview->setPixmap(pixmap); |
238 | rc = true; |
239 | } |
240 | } |
241 | return rc; |
242 | } |
243 | |
244 | void NewFormWidget::on_treeWidget_itemActivated(QTreeWidgetItem *item) |
245 | { |
246 | if (debugNewFormWidget) |
247 | qDebug() << Q_FUNC_INFO << item; |
248 | |
249 | if (item->data(column: 0, role: TemplateNameRole).isValid() || item->data(column: 0, role: ClassNameRole).isValid()) |
250 | emit templateActivated(); |
251 | } |
252 | |
253 | QPixmap NewFormWidget::formPreviewPixmap(const QTreeWidgetItem *item) |
254 | { |
255 | // Cache pixmaps per item/device profile |
256 | const ItemPixmapCacheKey cacheKey(item, profileComboIndex()); |
257 | ItemPixmapCache::iterator it = m_itemPixmapCache.find(akey: cacheKey); |
258 | if (it == m_itemPixmapCache.end()) { |
259 | // file or string? |
260 | const QVariant fileName = item->data(column: 0, role: TemplateNameRole); |
261 | QPixmap rc; |
262 | if (fileName.type() == QVariant::String) { |
263 | rc = formPreviewPixmap(fileName: fileName.toString()); |
264 | } else { |
265 | const QVariant classNameV = item->data(column: 0, role: ClassNameRole); |
266 | Q_ASSERT(classNameV.type() == QVariant::String); |
267 | const QString className = classNameV.toString(); |
268 | QByteArray data = qdesigner_internal::WidgetDataBase::formTemplate(core: m_core, className, objectName: formName(className)).toUtf8(); |
269 | QBuffer buffer(&data); |
270 | buffer.open(openMode: QIODevice::ReadOnly); |
271 | rc = formPreviewPixmap(file&: buffer); |
272 | } |
273 | if (rc.isNull()) // Retry invalid ones |
274 | return rc; |
275 | it = m_itemPixmapCache.insert(akey: cacheKey, avalue: rc); |
276 | } |
277 | return it.value(); |
278 | } |
279 | |
280 | QPixmap NewFormWidget::formPreviewPixmap(const QString &fileName) const |
281 | { |
282 | QFile f(fileName); |
283 | if (f.open(flags: QFile::ReadOnly)) { |
284 | QFileInfo fi(fileName); |
285 | const QPixmap rc = formPreviewPixmap(file&: f, workingDir: fi.absolutePath()); |
286 | f.close(); |
287 | return rc; |
288 | } |
289 | qWarning() << "The file " << fileName << " could not be opened: " << f.errorString(); |
290 | return QPixmap(); |
291 | } |
292 | |
293 | QImage NewFormWidget::grabForm(QDesignerFormEditorInterface *core, |
294 | QIODevice &file, |
295 | const QString &workingDir, |
296 | const qdesigner_internal::DeviceProfile &dp) |
297 | { |
298 | qdesigner_internal::NewFormWidgetFormBuilder |
299 | formBuilder(core, dp); |
300 | if (!workingDir.isEmpty()) |
301 | formBuilder.setWorkingDirectory(workingDir); |
302 | |
303 | QWidget *widget = formBuilder.load(dev: &file, parentWidget: nullptr); |
304 | if (!widget) |
305 | return QImage(); |
306 | |
307 | const QPixmap pixmap = widget->grab(rectangle: QRect(0, 0, -1, -1)); |
308 | widget->deleteLater(); |
309 | return pixmap.toImage(); |
310 | } |
311 | |
312 | QPixmap NewFormWidget::formPreviewPixmap(QIODevice &file, const QString &workingDir) const |
313 | { |
314 | const QSizeF screenSize(QApplication::desktop()->screenGeometry(widget: this).size()); |
315 | const int previewSize = qRound(d: screenSize.width() / 7.5); // 256 on 1920px screens. |
316 | const int margin = previewSize / 32 - 1; // 7 on 1920px screens. |
317 | const int shadow = margin; |
318 | |
319 | const QImage wimage = grabForm(core: m_core, file, workingDir, dp: currentDeviceProfile()); |
320 | if (wimage.isNull()) |
321 | return QPixmap(); |
322 | const qreal devicePixelRatio = wimage.devicePixelRatioF(); |
323 | const QSize imageSize(previewSize - margin * 2, previewSize - margin * 2); |
324 | QImage image = wimage.scaled(s: (QSizeF(imageSize) * devicePixelRatio).toSize(), |
325 | aspectMode: Qt::KeepAspectRatio, mode: Qt::SmoothTransformation); |
326 | image.setDevicePixelRatio(devicePixelRatio); |
327 | |
328 | QImage dest((QSizeF(previewSize, previewSize) * devicePixelRatio).toSize(), |
329 | QImage::Format_ARGB32_Premultiplied); |
330 | dest.setDevicePixelRatio(devicePixelRatio); |
331 | dest.fill(pixel: 0); |
332 | |
333 | QPainter p(&dest); |
334 | p.drawImage(x: margin, y: margin, image); |
335 | |
336 | p.setPen(QPen(palette().brush(cr: QPalette::WindowText), 0)); |
337 | |
338 | p.drawRect(rect: QRectF(margin - 1, margin - 1, imageSize.width() + 1.5, imageSize.height() + 1.5)); |
339 | |
340 | const QColor dark(Qt::darkGray); |
341 | const QColor light(Qt::transparent); |
342 | |
343 | // right shadow |
344 | { |
345 | const QRect rect(margin + imageSize.width() + 1, margin + shadow, shadow, imageSize.height() - shadow + 1); |
346 | QLinearGradient lg(rect.topLeft(), rect.topRight()); |
347 | lg.setColorAt(pos: 0, color: dark); |
348 | lg.setColorAt(pos: 1, color: light); |
349 | p.fillRect(rect, lg); |
350 | } |
351 | |
352 | // bottom shadow |
353 | { |
354 | const QRect rect(margin + shadow, margin + imageSize.height() + 1, imageSize.width() - shadow + 1, shadow); |
355 | QLinearGradient lg(rect.topLeft(), rect.bottomLeft()); |
356 | lg.setColorAt(pos: 0, color: dark); |
357 | lg.setColorAt(pos: 1, color: light); |
358 | p.fillRect(rect, lg); |
359 | } |
360 | |
361 | // bottom/right corner shadow |
362 | { |
363 | const QRect rect(margin + imageSize.width() + 1, margin + imageSize.height() + 1, shadow, shadow); |
364 | QRadialGradient g(rect.topLeft(), shadow - 1); |
365 | g.setColorAt(pos: 0, color: dark); |
366 | g.setColorAt(pos: 1, color: light); |
367 | p.fillRect(rect, g); |
368 | } |
369 | |
370 | // top/right corner |
371 | { |
372 | const QRect rect(margin + imageSize.width() + 1, margin, shadow, shadow); |
373 | QRadialGradient g(rect.bottomLeft(), shadow - 1); |
374 | g.setColorAt(pos: 0, color: dark); |
375 | g.setColorAt(pos: 1, color: light); |
376 | p.fillRect(rect, g); |
377 | } |
378 | |
379 | // bottom/left corner |
380 | { |
381 | const QRect rect(margin, margin + imageSize.height() + 1, shadow, shadow); |
382 | QRadialGradient g(rect.topRight(), shadow - 1); |
383 | g.setColorAt(pos: 0, color: dark); |
384 | g.setColorAt(pos: 1, color: light); |
385 | p.fillRect(rect, g); |
386 | } |
387 | |
388 | p.end(); |
389 | |
390 | return QPixmap::fromImage(image: dest); |
391 | } |
392 | |
393 | void NewFormWidget::loadFrom(const QString &path, bool resourceFile, const QString &uiExtension, |
394 | const QString &selectedItem, QTreeWidgetItem *&selectedItemFound) |
395 | { |
396 | const QDir dir(path); |
397 | |
398 | if (!dir.exists()) |
399 | return; |
400 | |
401 | // Iterate through the directory and add the templates |
402 | const QFileInfoList list = dir.entryInfoList(nameFilters: QStringList(QStringLiteral("*." ) + uiExtension), |
403 | filters: QDir::Files); |
404 | |
405 | if (list.isEmpty()) |
406 | return; |
407 | |
408 | const QChar separator = resourceFile ? QChar(QLatin1Char('/')) |
409 | : QDir::separator(); |
410 | QTreeWidgetItem *root = new QTreeWidgetItem(m_ui->treeWidget); |
411 | root->setFlags(root->flags() & ~Qt::ItemIsSelectable); |
412 | // Try to get something that is easy to read. |
413 | QString visiblePath = path; |
414 | int index = visiblePath.lastIndexOf(c: separator); |
415 | if (index != -1) { |
416 | // try to find a second slash, just to be a bit better. |
417 | const int index2 = visiblePath.lastIndexOf(c: separator, from: index - 1); |
418 | if (index2 != -1) |
419 | index = index2; |
420 | visiblePath = visiblePath.mid(position: index + 1); |
421 | visiblePath = QDir::toNativeSeparators(pathName: visiblePath); |
422 | } |
423 | |
424 | const QChar underscore = QLatin1Char('_'); |
425 | const QChar blank = QLatin1Char(' '); |
426 | root->setText(column: 0, atext: visiblePath.replace(before: underscore, after: blank)); |
427 | root->setToolTip(column: 0, atoolTip: path); |
428 | |
429 | const QFileInfoList::const_iterator lcend = list.constEnd(); |
430 | for (QFileInfoList::const_iterator it = list.constBegin(); it != lcend; ++it) { |
431 | if (!it->isFile()) |
432 | continue; |
433 | |
434 | QTreeWidgetItem *item = new QTreeWidgetItem(root); |
435 | const QString text = it->baseName().replace(before: underscore, after: blank); |
436 | if (selectedItemFound == nullptr && text == selectedItem) |
437 | selectedItemFound = item; |
438 | item->setText(column: 0, atext: text); |
439 | item->setData(column: 0, role: TemplateNameRole, value: it->absoluteFilePath()); |
440 | } |
441 | } |
442 | |
443 | void NewFormWidget::loadFrom(const QString &title, const QStringList &nameList, |
444 | const QString &selectedItem, QTreeWidgetItem *&selectedItemFound) |
445 | { |
446 | if (nameList.isEmpty()) |
447 | return; |
448 | QTreeWidgetItem *root = new QTreeWidgetItem(m_ui->treeWidget); |
449 | root->setFlags(root->flags() & ~Qt::ItemIsSelectable); |
450 | root->setText(column: 0, atext: title); |
451 | const QStringList::const_iterator cend = nameList.constEnd(); |
452 | for (QStringList::const_iterator it = nameList.constBegin(); it != cend; ++it) { |
453 | const QString text = *it; |
454 | QTreeWidgetItem *item = new QTreeWidgetItem(root); |
455 | item->setText(column: 0, atext: text); |
456 | if (selectedItemFound == nullptr && text == selectedItem) |
457 | selectedItemFound = item; |
458 | item->setData(column: 0, role: ClassNameRole, value: *it); |
459 | } |
460 | } |
461 | |
462 | void NewFormWidget::on_treeWidget_itemPressed(QTreeWidgetItem *item) |
463 | { |
464 | if (item && !item->parent()) |
465 | item->setExpanded(!item->isExpanded()); |
466 | } |
467 | |
468 | QSize NewFormWidget::templateSize() const |
469 | { |
470 | return m_ui->sizeComboBox->itemData(index: m_ui->sizeComboBox->currentIndex()).toSize(); |
471 | } |
472 | |
473 | void NewFormWidget::setTemplateSize(const QSize &s) |
474 | { |
475 | const int index = s.isNull() ? 0 : m_ui->sizeComboBox->findData(data: s); |
476 | if (index != -1) |
477 | m_ui->sizeComboBox->setCurrentIndex(index); |
478 | } |
479 | |
480 | static QString readAll(const QString &fileName, QString *errorMessage) |
481 | { |
482 | QFile file(fileName); |
483 | if (!file.open(flags: QIODevice::ReadOnly|QIODevice::Text)) { |
484 | *errorMessage = NewFormWidget::tr(s: "Unable to open the form template file '%1': %2" ).arg(args: fileName, args: file.errorString()); |
485 | return QString(); |
486 | } |
487 | return QString::fromUtf8(str: file.readAll()); |
488 | } |
489 | |
490 | QString NewFormWidget::itemToTemplate(const QTreeWidgetItem *item, QString *errorMessage) const |
491 | { |
492 | const QSize size = templateSize(); |
493 | // file name or string contents? |
494 | const QVariant templateFileName = item->data(column: 0, role: TemplateNameRole); |
495 | if (templateFileName.type() == QVariant::String) { |
496 | const QString fileName = templateFileName.toString(); |
497 | // No fixed size: just open. |
498 | if (size.isNull()) |
499 | return readAll(fileName, errorMessage); |
500 | // try to find a file matching the size, like "../640x480/xx.ui" |
501 | const QFileInfo fiBase(fileName); |
502 | QString sizeFileName; |
503 | QTextStream(&sizeFileName) << fiBase.path() << QDir::separator() |
504 | << size.width() << QLatin1Char('x') << size.height() << QDir::separator() |
505 | << fiBase.fileName(); |
506 | if (QFileInfo(sizeFileName).isFile()) |
507 | return readAll(fileName: sizeFileName, errorMessage); |
508 | // Nothing found, scale via DOM/temporary file |
509 | QString contents = readAll(fileName, errorMessage); |
510 | if (!contents.isEmpty()) |
511 | contents = qdesigner_internal::WidgetDataBase::scaleFormTemplate(xml: contents, size, fixed: false); |
512 | return contents; |
513 | } |
514 | // Content. |
515 | const QString className = item->data(column: 0, role: ClassNameRole).toString(); |
516 | QString contents = qdesigner_internal::WidgetDataBase::formTemplate(core: m_core, className, objectName: formName(className)); |
517 | if (!size.isNull()) |
518 | contents = qdesigner_internal::WidgetDataBase::scaleFormTemplate(xml: contents, size, fixed: false); |
519 | return contents; |
520 | } |
521 | |
522 | void NewFormWidget::slotDeviceProfileIndexChanged(int idx) |
523 | { |
524 | // Store index for form windows to take effect and refresh pixmap |
525 | QDesignerSharedSettings settings(m_core); |
526 | settings.setCurrentDeviceProfileIndex(idx - profileComboIndexOffset); |
527 | showCurrentItemPixmap(); |
528 | } |
529 | |
530 | int NewFormWidget::profileComboIndex() const |
531 | { |
532 | return m_ui->profileComboBox->currentIndex(); |
533 | } |
534 | |
535 | qdesigner_internal::DeviceProfile NewFormWidget::currentDeviceProfile() const |
536 | { |
537 | const int ci = profileComboIndex(); |
538 | if (ci > 0) |
539 | return m_deviceProfiles.at(i: ci - profileComboIndexOffset); |
540 | return qdesigner_internal::DeviceProfile(); |
541 | } |
542 | |
543 | bool NewFormWidget::hasCurrentTemplate() const |
544 | { |
545 | return m_currentItem != nullptr; |
546 | } |
547 | |
548 | QString NewFormWidget::currentTemplateI(QString *ptrToErrorMessage) |
549 | { |
550 | if (m_currentItem == nullptr) { |
551 | *ptrToErrorMessage = tr(s: "Internal error: No template selected." ); |
552 | return QString(); |
553 | } |
554 | const QString contents = itemToTemplate(item: m_currentItem, errorMessage: ptrToErrorMessage); |
555 | if (contents.isEmpty()) |
556 | return contents; |
557 | |
558 | m_acceptedItem = m_currentItem; |
559 | return contents; |
560 | } |
561 | |
562 | QString NewFormWidget::currentTemplate(QString *ptrToErrorMessage) |
563 | { |
564 | if (ptrToErrorMessage) |
565 | return currentTemplateI(ptrToErrorMessage); |
566 | // Do not loose the error |
567 | QString errorMessage; |
568 | const QString contents = currentTemplateI(ptrToErrorMessage: &errorMessage); |
569 | if (!errorMessage.isEmpty()) |
570 | qWarning(msg: "%s" , errorMessage.toUtf8().constData()); |
571 | return contents; |
572 | } |
573 | |
574 | } |
575 | |
576 | QT_END_NAMESPACE |
577 | |