1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the examples of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:BSD$
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** BSD License Usage
18** Alternatively, you may use this file under the terms of the BSD license
19** as follows:
20**
21** "Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions are
23** met:
24** * Redistributions of source code must retain the above copyright
25** notice, this list of conditions and the following disclaimer.
26** * Redistributions in binary form must reproduce the above copyright
27** notice, this list of conditions and the following disclaimer in
28** the documentation and/or other materials provided with the
29** distribution.
30** * Neither the name of The Qt Company Ltd nor the names of its
31** contributors may be used to endorse or promote products derived
32** from this software without specific prior written permission.
33**
34**
35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46**
47** $QT_END_LICENSE$
48**
49****************************************************************************/
50
51#include "exportdialog.h"
52
53#include <QApplication>
54#include <QDialogButtonBox>
55#include <QFileDialog>
56#include <QFormLayout>
57#include <QHBoxLayout>
58#include <QMessageBox>
59#include <QLabel>
60#include <QLineEdit>
61#include <QPushButton>
62#include <QScreen>
63#include <QSpinBox>
64#include <QToolButton>
65#include <QVBoxLayout>
66
67#include <QImageWriter>
68
69#include <QDebug>
70
71#include <QDir>
72#include <QFileInfo>
73
74enum { exportMinimumSize = 1, exportMaximumSize = 2000 };
75
76ExportDialog::ExportDialog(QWidget *parent)
77 : QDialog(parent)
78 , m_fileNameLineEdit(new QLineEdit(this))
79 , m_widthSpinBox(new QSpinBox(this))
80 , m_heightSpinBox(new QSpinBox(this))
81 , m_aspectRatio(1)
82{
83 typedef void (QSpinBox::*QSpinBoxIntSignal)(int);
84
85 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
86 setWindowTitle(tr(s: "Export"));
87
88 QFormLayout *formLayout = new QFormLayout(this);
89
90 QHBoxLayout *fileLayout = new QHBoxLayout;
91 fileLayout->addWidget(m_fileNameLineEdit);
92 m_fileNameLineEdit->setMinimumWidth(this->screen()->availableGeometry() .width() / 6);
93 QPushButton *browseButton = new QPushButton(tr(s: "Browse..."), this);
94 fileLayout->addWidget(browseButton);
95 connect(sender: browseButton, signal: &QAbstractButton::clicked, receiver: this, slot: &ExportDialog::browse);
96 formLayout->addRow(labelText: tr(s: "File:"), field: fileLayout);
97
98 QHBoxLayout *sizeLayout = new QHBoxLayout;
99 sizeLayout->addStretch();
100 m_widthSpinBox->setMinimum(exportMinimumSize);
101 m_widthSpinBox->setMaximum(exportMaximumSize);
102 connect(sender: m_widthSpinBox, signal: static_cast<QSpinBoxIntSignal>(&QSpinBox::valueChanged),
103 receiver: this, slot: &ExportDialog::exportWidthChanged);
104 sizeLayout->addWidget(m_widthSpinBox);
105 //: Multiplication, as in 32x32
106 sizeLayout->addWidget(new QLabel(tr(s: "x")));
107 m_heightSpinBox->setMinimum(exportMinimumSize);
108 m_heightSpinBox->setMaximum(exportMaximumSize);
109 connect(sender: m_heightSpinBox, signal: static_cast<QSpinBoxIntSignal>(&QSpinBox::valueChanged),
110 receiver: this, slot: &ExportDialog::exportHeightChanged);
111 sizeLayout->addWidget(m_heightSpinBox);
112 QToolButton *resetButton = new QToolButton(this);
113 resetButton->setIcon(QIcon(":/qt-project.org/styles/commonstyle/images/refresh-32.png"));
114 sizeLayout->addWidget(resetButton);
115 connect(sender: resetButton, signal: &QAbstractButton::clicked, receiver: this, slot: &ExportDialog::resetExportSize);
116 formLayout->addRow(labelText: tr(s: "Size:"), field: sizeLayout);
117
118 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
119 connect(sender: buttonBox, signal: &QDialogButtonBox::accepted, receiver: this, slot: &QDialog::accept);
120 connect(sender: buttonBox, signal: &QDialogButtonBox::rejected, receiver: this, slot: &QDialog::reject);
121 formLayout->addRow(widget: buttonBox);
122}
123
124void ExportDialog::accept()
125{
126 const QString fileName = exportFileName();
127 if (fileName.isEmpty()) {
128 QMessageBox::warning(parent: this, title: windowTitle(), text: tr(s: "Please enter a file name"));
129 return;
130 }
131 QFileInfo fi(fileName);
132 if (fi.exists()) {
133 const QString question = tr(s: "%1 already exists.\nWould you like to overwrite it?").arg(a: QDir::toNativeSeparators(pathName: fileName));
134 if (QMessageBox::question(parent: this, title: windowTitle(), text: question, buttons: QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes)
135 return;
136 }
137 QDialog::accept();
138}
139
140QSize ExportDialog::exportSize() const
141{
142 return QSize(m_widthSpinBox->value(), m_heightSpinBox->value());
143}
144
145void ExportDialog::setExportSize(const QSize &size)
146{
147 m_defaultSize = size;
148 QSizeF defaultSizeF(m_defaultSize);
149 m_aspectRatio = defaultSizeF.width() / defaultSizeF.height();
150 setExportWidthBlocked(size.width());
151 setExportHeightBlocked(size.height());
152}
153
154void ExportDialog::resetExportSize()
155{
156 setExportWidthBlocked(m_defaultSize.width());
157 setExportHeightBlocked(m_defaultSize.height());
158}
159
160void ExportDialog::setExportWidthBlocked(int width)
161{
162 if (m_widthSpinBox->value() != width) {
163 const bool blockSignals = m_widthSpinBox->blockSignals(b: true);
164 m_widthSpinBox->setValue(width);
165 m_widthSpinBox->blockSignals(b: blockSignals);
166 }
167}
168
169void ExportDialog::setExportHeightBlocked(int height)
170{
171 if (m_heightSpinBox->value() != height) {
172 const bool blockSignals = m_heightSpinBox->blockSignals(b: true);
173 m_heightSpinBox->setValue(height);
174 m_heightSpinBox->blockSignals(b: blockSignals);
175 }
176}
177
178void ExportDialog::exportWidthChanged(int width)
179{
180 const bool square = m_defaultSize.width() == m_defaultSize.height();
181 setExportHeightBlocked(square ? width : qRound(d: qreal(width) / m_aspectRatio));
182}
183
184void ExportDialog::exportHeightChanged(int height)
185{
186 const bool square = m_defaultSize.width() == m_defaultSize.height();
187 setExportWidthBlocked(square ? height : qRound(d: qreal(height) * m_aspectRatio));
188}
189
190QString ExportDialog::exportFileName() const
191{
192 return QDir::cleanPath(path: m_fileNameLineEdit->text().trimmed());
193}
194
195void ExportDialog::setExportFileName(const QString &f)
196{
197 m_fileNameLineEdit->setText(QDir::toNativeSeparators(pathName: f));
198}
199
200void ExportDialog::browse()
201{
202 QFileDialog fileDialog(this);
203 fileDialog.setAcceptMode(QFileDialog::AcceptSave);
204 const QString fileName = exportFileName();
205 if (!fileName.isEmpty())
206 fileDialog.setDirectory(QFileInfo(fileName).absolutePath());
207 QStringList mimeTypes;
208 const auto supportedMimeTypes = QImageWriter::supportedMimeTypes();
209 for (const QByteArray &mimeType : supportedMimeTypes)
210 mimeTypes.append(t: QLatin1String(mimeType));
211 fileDialog.setMimeTypeFilters(mimeTypes);
212 const int pngIndex = mimeTypes.indexOf(t: "image/png");
213 if (pngIndex >= 0) {
214 fileDialog.selectMimeTypeFilter(filter: mimeTypes.at(i: pngIndex));
215 fileDialog.setDefaultSuffix("png");
216 }
217 if (fileDialog.exec() == QDialog::Accepted)
218 setExportFileName(fileDialog.selectedFiles().constFirst());
219}
220

source code of qtsvg/examples/svg/svgviewer/exportdialog.cpp