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 "mainwindow.h"
52#include "exportdialog.h"
53
54#include <QtWidgets>
55#include <QSvgRenderer>
56
57#include "svgview.h"
58
59static inline QString picturesLocation()
60{
61 return QStandardPaths::standardLocations(type: QStandardPaths::PicturesLocation).value(i: 0, defaultValue: QDir::currentPath());
62}
63
64MainWindow::MainWindow()
65 : QMainWindow()
66 , m_view(new SvgView)
67 , m_zoomLabel(new QLabel)
68{
69 QToolBar *toolBar = new QToolBar(this);
70 addToolBar(area: Qt::TopToolBarArea, toolbar: toolBar);
71
72 QMenu *fileMenu = menuBar()->addMenu(title: tr(s: "&File"));
73 const QIcon openIcon = QIcon::fromTheme(name: "document-open", fallback: QIcon(":/qt-project.org/styles/commonstyle/images/standardbutton-open-32.png"));
74 QAction *openAction = fileMenu->addAction(actionIcon: openIcon, text: tr(s: "&Open..."), object: this, slot: &MainWindow::openFile);
75 openAction->setShortcut(QKeySequence::Open);
76 toolBar->addAction(action: openAction);
77 const QIcon exportIcon = QIcon::fromTheme(name: "document-save", fallback: QIcon(":/qt-project.org/styles/commonstyle/images/standardbutton-save-32.png"));
78 QAction *exportAction = fileMenu->addAction(actionIcon: exportIcon, text: tr(s: "&Export..."), object: this, slot: &MainWindow::exportImage);
79 exportAction->setToolTip(tr(s: "Export Image"));
80 exportAction->setShortcut(Qt::CTRL + Qt::Key_E);
81 toolBar->addAction(action: exportAction);
82 QAction *quitAction = fileMenu->addAction(text: tr(s: "E&xit"), qApp, slot: QCoreApplication::quit);
83 quitAction->setShortcuts(QKeySequence::Quit);
84
85 QMenu *viewMenu = menuBar()->addMenu(title: tr(s: "&View"));
86 m_backgroundAction = viewMenu->addAction(text: tr(s: "&Background"));
87 m_backgroundAction->setEnabled(false);
88 m_backgroundAction->setCheckable(true);
89 m_backgroundAction->setChecked(false);
90 connect(sender: m_backgroundAction, signal: &QAction::toggled, receiver: m_view, slot: &SvgView::setViewBackground);
91
92 m_outlineAction = viewMenu->addAction(text: tr(s: "&Outline"));
93 m_outlineAction->setEnabled(false);
94 m_outlineAction->setCheckable(true);
95 m_outlineAction->setChecked(true);
96 connect(sender: m_outlineAction, signal: &QAction::toggled, receiver: m_view, slot: &SvgView::setViewOutline);
97
98 viewMenu->addSeparator();
99 QAction *zoomAction = viewMenu->addAction(text: tr(s: "Zoom &In"), object: m_view, slot: &SvgView::zoomIn);
100 zoomAction->setShortcut(QKeySequence::ZoomIn);
101 zoomAction = viewMenu->addAction(text: tr(s: "Zoom &Out"), object: m_view, slot: &SvgView::zoomOut);
102 zoomAction->setShortcut(QKeySequence::ZoomOut);
103 zoomAction = viewMenu->addAction(text: tr(s: "Reset Zoom"), object: m_view, slot: &SvgView::resetZoom);
104 zoomAction->setShortcut(Qt::CTRL + Qt::Key_0);
105
106 QMenu *rendererMenu = menuBar()->addMenu(title: tr(s: "&Renderer"));
107 m_nativeAction = rendererMenu->addAction(text: tr(s: "&Native"));
108 m_nativeAction->setCheckable(true);
109 m_nativeAction->setChecked(true);
110 m_nativeAction->setData(int(SvgView::Native));
111#ifndef QT_NO_OPENGL
112 m_glAction = rendererMenu->addAction(text: tr(s: "&OpenGL"));
113 m_glAction->setCheckable(true);
114 m_glAction->setData(int(SvgView::OpenGL));
115#endif
116 m_imageAction = rendererMenu->addAction(text: tr(s: "&Image"));
117 m_imageAction->setCheckable(true);
118 m_imageAction->setData(int(SvgView::Image));
119
120 rendererMenu->addSeparator();
121 m_antialiasingAction = rendererMenu->addAction(text: tr(s: "&Antialiasing"));
122 m_antialiasingAction->setCheckable(true);
123 m_antialiasingAction->setChecked(false);
124 connect(sender: m_antialiasingAction, signal: &QAction::toggled, receiver: m_view, slot: &SvgView::setAntialiasing);
125
126 QActionGroup *rendererGroup = new QActionGroup(this);
127 rendererGroup->addAction(a: m_nativeAction);
128#ifndef QT_NO_OPENGL
129 rendererGroup->addAction(a: m_glAction);
130#endif
131 rendererGroup->addAction(a: m_imageAction);
132
133 menuBar()->addMenu(menu: rendererMenu);
134
135 connect(sender: rendererGroup, signal: &QActionGroup::triggered,
136 slot: [this] (QAction *a) { setRenderer(a->data().toInt()); });
137
138 QMenu *help = menuBar()->addMenu(title: tr(s: "&Help"));
139 help->addAction(text: tr(s: "About Qt"), qApp, slot: &QApplication::aboutQt);
140
141 setCentralWidget(m_view);
142
143 m_zoomLabel->setToolTip(tr(s: "Use the mouse wheel to zoom"));
144 statusBar()->addPermanentWidget(widget: m_zoomLabel);
145 updateZoomLabel();
146 connect(sender: m_view, signal: &SvgView::zoomChanged, receiver: this, slot: &MainWindow::updateZoomLabel);
147}
148
149void MainWindow::openFile()
150{
151 QFileDialog fileDialog(this);
152 fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
153 fileDialog.setMimeTypeFilters(QStringList() << "image/svg+xml" << "image/svg+xml-compressed");
154 fileDialog.setWindowTitle(tr(s: "Open SVG File"));
155 if (m_currentPath.isEmpty())
156 fileDialog.setDirectory(picturesLocation());
157
158 while (fileDialog.exec() == QDialog::Accepted && !loadFile(path: fileDialog.selectedFiles().constFirst()))
159 ;
160}
161
162bool MainWindow::loadFile(const QString &fileName)
163{
164 if (!QFileInfo::exists(file: fileName) || !m_view->openFile(fileName)) {
165 QMessageBox::critical(parent: this, title: tr(s: "Open SVG File"),
166 text: tr(s: "Could not open file '%1'.").arg(a: QDir::toNativeSeparators(pathName: fileName)));
167 return false;
168 }
169
170 if (!fileName.startsWith(s: ":/")) {
171 m_currentPath = fileName;
172 setWindowFilePath(fileName);
173 const QSize size = m_view->svgSize();
174 const QString message =
175 tr(s: "Opened %1, %2x%3").arg(a: QFileInfo(fileName).fileName()).arg(a: size.width()).arg(a: size.width());
176 statusBar()->showMessage(text: message);
177 }
178
179 m_outlineAction->setEnabled(true);
180 m_backgroundAction->setEnabled(true);
181
182 const QSize availableSize = this->screen()->availableGeometry().size();
183 resize(m_view->sizeHint().expandedTo(otherSize: availableSize / 4) + QSize(80, 80 + menuBar()->height()));
184
185 return true;
186}
187
188void MainWindow::setRenderer(int renderMode)
189{
190 m_view->setRenderer(static_cast<SvgView::RendererType>(renderMode));
191}
192
193void MainWindow::exportImage()
194{
195 ExportDialog exportDialog(this);
196 exportDialog.setExportSize(m_view->svgSize());
197 QString fileName;
198 if (m_currentPath.isEmpty()) {
199 fileName = picturesLocation() + QLatin1String("/export.png");
200 } else {
201 const QFileInfo fi(m_currentPath);
202 fileName = fi.absolutePath() + QLatin1Char('/') + fi.baseName() + QLatin1String(".png");
203 }
204 exportDialog.setExportFileName(fileName);
205
206 while (true) {
207 if (exportDialog.exec() != QDialog::Accepted)
208 break;
209
210 const QSize imageSize = exportDialog.exportSize();
211 QImage image(imageSize, QImage::Format_ARGB32);
212 image.fill(color: Qt::transparent);
213 QPainter painter;
214 painter.begin(&image);
215 m_view->renderer()->render(p: &painter, bounds: QRectF(QPointF(), QSizeF(imageSize)));
216 painter.end();
217
218 const QString fileName = exportDialog.exportFileName();
219 if (image.save(fileName)) {
220
221 const QString message = tr(s: "Exported %1, %2x%3, %4 bytes")
222 .arg(a: QDir::toNativeSeparators(pathName: fileName)).arg(a: imageSize.width()).arg(a: imageSize.height())
223 .arg(a: QFileInfo(fileName).size());
224 statusBar()->showMessage(text: message);
225 break;
226 } else {
227 QMessageBox::critical(parent: this, title: tr(s: "Export Image"),
228 text: tr(s: "Could not write file '%1'.").arg(a: QDir::toNativeSeparators(pathName: fileName)));
229 }
230 }
231}
232
233void MainWindow::updateZoomLabel()
234{
235 const int percent = qRound(d: m_view->zoomFactor() * qreal(100));
236 m_zoomLabel->setText(QString::number(percent) + QLatin1Char('%'));
237}
238

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