| /**************************************************************************** |
| ** |
| ** Copyright (C) 2017 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the examples of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:BSD$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** BSD License Usage |
| ** Alternatively, you may use this file under the terms of the BSD license |
| ** as follows: |
| ** |
| ** "Redistribution and use in source and binary forms, with or without |
| ** modification, are permitted provided that the following conditions are |
| ** met: |
| ** * Redistributions of source code must retain the above copyright |
| ** notice, this list of conditions and the following disclaimer. |
| ** * Redistributions in binary form must reproduce the above copyright |
| ** notice, this list of conditions and the following disclaimer in |
| ** the documentation and/or other materials provided with the |
| ** distribution. |
| ** * Neither the name of The Qt Company Ltd nor the names of its |
| ** contributors may be used to endorse or promote products derived |
| ** from this software without specific prior written permission. |
| ** |
| ** |
| ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "mainwindow.h" |
| #include "exportdialog.h" |
| |
| #include <QtWidgets> |
| #include <QSvgRenderer> |
| |
| #include "svgview.h" |
| |
| static inline QString picturesLocation() |
| { |
| return QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).value(0, QDir::currentPath()); |
| } |
| |
| MainWindow::MainWindow() |
| : QMainWindow() |
| , m_view(new SvgView) |
| , m_zoomLabel(new QLabel) |
| { |
| QToolBar *toolBar = new QToolBar(this); |
| addToolBar(Qt::TopToolBarArea, toolBar); |
| |
| QMenu *fileMenu = menuBar()->addMenu(tr("&File")); |
| const QIcon openIcon = QIcon::fromTheme("document-open", QIcon(":/qt-project.org/styles/commonstyle/images/standardbutton-open-32.png")); |
| QAction *openAction = fileMenu->addAction(openIcon, tr("&Open..."), this, &MainWindow::openFile); |
| openAction->setShortcut(QKeySequence::Open); |
| toolBar->addAction(openAction); |
| const QIcon exportIcon = QIcon::fromTheme("document-save", QIcon(":/qt-project.org/styles/commonstyle/images/standardbutton-save-32.png")); |
| QAction *exportAction = fileMenu->addAction(exportIcon, tr("&Export..."), this, &MainWindow::exportImage); |
| exportAction->setToolTip(tr("Export Image")); |
| exportAction->setShortcut(Qt::CTRL + Qt::Key_E); |
| toolBar->addAction(exportAction); |
| QAction *quitAction = fileMenu->addAction(tr("E&xit"), qApp, QCoreApplication::quit); |
| quitAction->setShortcuts(QKeySequence::Quit); |
| |
| QMenu *viewMenu = menuBar()->addMenu(tr("&View")); |
| m_backgroundAction = viewMenu->addAction(tr("&Background")); |
| m_backgroundAction->setEnabled(false); |
| m_backgroundAction->setCheckable(true); |
| m_backgroundAction->setChecked(false); |
| connect(m_backgroundAction, &QAction::toggled, m_view, &SvgView::setViewBackground); |
| |
| m_outlineAction = viewMenu->addAction(tr("&Outline")); |
| m_outlineAction->setEnabled(false); |
| m_outlineAction->setCheckable(true); |
| m_outlineAction->setChecked(true); |
| connect(m_outlineAction, &QAction::toggled, m_view, &SvgView::setViewOutline); |
| |
| viewMenu->addSeparator(); |
| QAction *zoomAction = viewMenu->addAction(tr("Zoom &In"), m_view, &SvgView::zoomIn); |
| zoomAction->setShortcut(QKeySequence::ZoomIn); |
| zoomAction = viewMenu->addAction(tr("Zoom &Out"), m_view, &SvgView::zoomOut); |
| zoomAction->setShortcut(QKeySequence::ZoomOut); |
| zoomAction = viewMenu->addAction(tr("Reset Zoom"), m_view, &SvgView::resetZoom); |
| zoomAction->setShortcut(Qt::CTRL + Qt::Key_0); |
| |
| QMenu *rendererMenu = menuBar()->addMenu(tr("&Renderer")); |
| m_nativeAction = rendererMenu->addAction(tr("&Native")); |
| m_nativeAction->setCheckable(true); |
| m_nativeAction->setChecked(true); |
| m_nativeAction->setData(int(SvgView::Native)); |
| #ifndef QT_NO_OPENGL |
| m_glAction = rendererMenu->addAction(tr("&OpenGL")); |
| m_glAction->setCheckable(true); |
| m_glAction->setData(int(SvgView::OpenGL)); |
| #endif |
| m_imageAction = rendererMenu->addAction(tr("&Image")); |
| m_imageAction->setCheckable(true); |
| m_imageAction->setData(int(SvgView::Image)); |
| |
| rendererMenu->addSeparator(); |
| m_antialiasingAction = rendererMenu->addAction(tr("&Antialiasing")); |
| m_antialiasingAction->setCheckable(true); |
| m_antialiasingAction->setChecked(false); |
| connect(m_antialiasingAction, &QAction::toggled, m_view, &SvgView::setAntialiasing); |
| |
| QActionGroup *rendererGroup = new QActionGroup(this); |
| rendererGroup->addAction(m_nativeAction); |
| #ifndef QT_NO_OPENGL |
| rendererGroup->addAction(m_glAction); |
| #endif |
| rendererGroup->addAction(m_imageAction); |
| |
| menuBar()->addMenu(rendererMenu); |
| |
| connect(rendererGroup, &QActionGroup::triggered, |
| [this] (QAction *a) { setRenderer(a->data().toInt()); }); |
| |
| QMenu *help = menuBar()->addMenu(tr("&Help")); |
| help->addAction(tr("About Qt"), qApp, &QApplication::aboutQt); |
| |
| setCentralWidget(m_view); |
| |
| m_zoomLabel->setToolTip(tr("Use the mouse wheel to zoom")); |
| statusBar()->addPermanentWidget(m_zoomLabel); |
| updateZoomLabel(); |
| connect(m_view, &SvgView::zoomChanged, this, &MainWindow::updateZoomLabel); |
| } |
| |
| void MainWindow::openFile() |
| { |
| QFileDialog fileDialog(this); |
| fileDialog.setAcceptMode(QFileDialog::AcceptOpen); |
| fileDialog.setMimeTypeFilters(QStringList() << "image/svg+xml" << "image/svg+xml-compressed"); |
| fileDialog.setWindowTitle(tr("Open SVG File")); |
| if (m_currentPath.isEmpty()) |
| fileDialog.setDirectory(picturesLocation()); |
| |
| while (fileDialog.exec() == QDialog::Accepted && !loadFile(fileDialog.selectedFiles().constFirst())) |
| ; |
| } |
| |
| bool MainWindow::loadFile(const QString &fileName) |
| { |
| if (!QFileInfo::exists(fileName) || !m_view->openFile(fileName)) { |
| QMessageBox::critical(this, tr("Open SVG File"), |
| tr("Could not open file '%1'.").arg(QDir::toNativeSeparators(fileName))); |
| return false; |
| } |
| |
| if (!fileName.startsWith(":/")) { |
| m_currentPath = fileName; |
| setWindowFilePath(fileName); |
| const QSize size = m_view->svgSize(); |
| const QString message = |
| tr("Opened %1, %2x%3").arg(QFileInfo(fileName).fileName()).arg(size.width()).arg(size.width()); |
| statusBar()->showMessage(message); |
| } |
| |
| m_outlineAction->setEnabled(true); |
| m_backgroundAction->setEnabled(true); |
| |
| const QSize availableSize = this->screen()->availableGeometry().size(); |
| resize(m_view->sizeHint().expandedTo(availableSize / 4) + QSize(80, 80 + menuBar()->height())); |
| |
| return true; |
| } |
| |
| void MainWindow::setRenderer(int renderMode) |
| { |
| m_view->setRenderer(static_cast<SvgView::RendererType>(renderMode)); |
| } |
| |
| void MainWindow::exportImage() |
| { |
| ExportDialog exportDialog(this); |
| exportDialog.setExportSize(m_view->svgSize()); |
| QString fileName; |
| if (m_currentPath.isEmpty()) { |
| fileName = picturesLocation() + QLatin1String("/export.png"); |
| } else { |
| const QFileInfo fi(m_currentPath); |
| fileName = fi.absolutePath() + QLatin1Char('/') + fi.baseName() + QLatin1String(".png"); |
| } |
| exportDialog.setExportFileName(fileName); |
| |
| while (true) { |
| if (exportDialog.exec() != QDialog::Accepted) |
| break; |
| |
| const QSize imageSize = exportDialog.exportSize(); |
| QImage image(imageSize, QImage::Format_ARGB32); |
| image.fill(Qt::transparent); |
| QPainter painter; |
| painter.begin(&image); |
| m_view->renderer()->render(&painter, QRectF(QPointF(), QSizeF(imageSize))); |
| painter.end(); |
| |
| const QString fileName = exportDialog.exportFileName(); |
| if (image.save(fileName)) { |
| |
| const QString message = tr("Exported %1, %2x%3, %4 bytes") |
| .arg(QDir::toNativeSeparators(fileName)).arg(imageSize.width()).arg(imageSize.height()) |
| .arg(QFileInfo(fileName).size()); |
| statusBar()->showMessage(message); |
| break; |
| } else { |
| QMessageBox::critical(this, tr("Export Image"), |
| tr("Could not write file '%1'.").arg(QDir::toNativeSeparators(fileName))); |
| } |
| } |
| } |
| |
| void MainWindow::updateZoomLabel() |
| { |
| const int percent = qRound(m_view->zoomFactor() * qreal(100)); |
| m_zoomLabel->setText(QString::number(percent) + QLatin1Char('%')); |
| } |