diff --git a/app/actionmanager.cpp b/app/actionmanager.cpp index f1ea52e..eaa882a 100644 --- a/app/actionmanager.cpp +++ b/app/actionmanager.cpp @@ -55,6 +55,7 @@ void ActionManager::setupAction(MainWindow *mainWindow) CREATE_NEW_ACTION(mainWindow, actionAnimationNextFrame); CREATE_NEW_THEMEICON_ACTION(mainWindow, actionOpen, document-open); + CREATE_NEW_THEMEICON_ACTION(mainWindow, actionSaveAs, document-save-as); CREATE_NEW_ACTION(mainWindow, actionHorizontalFlip); CREATE_NEW_ACTION(mainWindow, actionFitInView); CREATE_NEW_ACTION(mainWindow, actionFitByWidth); @@ -84,6 +85,7 @@ void ActionManager::retranslateUi(MainWindow *mainWindow) Q_UNUSED(mainWindow); actionOpen->setText(QCoreApplication::translate("MainWindow", "&Open...", nullptr)); + actionSaveAs->setText(QCoreApplication::translate("MainWindow", "Save &As...", nullptr)); actionActualSize->setText(QCoreApplication::translate("MainWindow", "Actual size", nullptr)); actionToggleMaximize->setText(QCoreApplication::translate("MainWindow", "Toggle maximize", nullptr)); @@ -129,6 +131,7 @@ void ActionManager::retranslateUi(MainWindow *mainWindow) void ActionManager::setupShortcuts() { actionOpen->setShortcut(QKeySequence::Open); + actionSaveAs->setShortcut(QKeySequence::SaveAs); actionActualSize->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_0)); actionZoomIn->setShortcut(QKeySequence::ZoomIn); actionZoomOut->setShortcut(QKeySequence::ZoomOut); diff --git a/app/actionmanager.h b/app/actionmanager.h index 27ee8cd..98eec59 100644 --- a/app/actionmanager.h +++ b/app/actionmanager.h @@ -23,6 +23,7 @@ public: public: QAction *actionOpen; + QAction *actionSaveAs; QAction *actionActualSize; QAction *actionToggleMaximize; diff --git a/app/mainwindow.cpp b/app/mainwindow.cpp index 403eafa..ff904dc 100644 --- a/app/mainwindow.cpp +++ b/app/mainwindow.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #ifdef HAVE_QTDBUS #include @@ -504,6 +505,12 @@ void MainWindow::contextMenuEvent(QContextMenuEvent *event) menu->addAction(paste); } +#if 0 + if (currentFileUrl.isValid()) { + menu->addAction(m_am->actionSaveAs); + } +#endif // 0 + menu->addSeparator(); menu->addAction(m_am->actionHorizontalFlip); @@ -696,6 +703,70 @@ void MainWindow::on_actionOpen_triggered() } } +void MainWindow::on_actionSaveAs_triggered() +{ + QUrl currentFileUrl = currentImageFileUrl(); + if (!currentFileUrl.isValid()) { + QMessageBox::warning(this, tr("Save As"), tr("No image is currently open.")); + return; + } + + QStringList supportedFormats; + QStringList nameFilters; + + const QList imageFormats = QImageWriter::supportedImageFormats(); + for (const QByteArray &format : imageFormats) { + QString formatStr = QString::fromLatin1(format).toLower(); + if (!formatStr.isEmpty()) { + supportedFormats << formatStr; + nameFilters << tr("%1 Image (*.%2)").arg(formatStr.toUpper(), formatStr); + } + } + + if (imageFormats.isEmpty()) { + QMessageBox::warning(this, tr("Save As"), + tr("No supported image formats are available.")); + return; + } + + QString selectedFilter; + QString saveFilePath = QFileDialog::getSaveFileName(this, + tr("Save As"), + QStandardPaths::writableLocation(QStandardPaths::PicturesLocation), + nameFilters.join(";;"), + &selectedFilter); + + if (saveFilePath.isEmpty()) { + return; // User cancelled + } + + // Ensure the file has the correct extension + QString expectedExtension; + + const int filterIndex = nameFilters.indexOf(selectedFilter); + if (filterIndex != -1) { + expectedExtension = supportedFormats.at(filterIndex); + } + + if (!expectedExtension.isEmpty() && !saveFilePath.endsWith('.' + expectedExtension, Qt::CaseInsensitive)) { + saveFilePath += '.' + expectedExtension; + } + + // Save the image + QImageReader imageReader(currentFileUrl.toLocalFile()); + imageReader.setAutoTransform(true); + imageReader.setDecideFormatFromContent(true); + imageReader.setAllocationLimit(0); + QImage img(imageReader.read()); + QImageWriter writer(saveFilePath); + writer.setFormat(expectedExtension.toLatin1()); + if (!writer.write(img)) { + QMessageBox::warning(this, tr("Save As"), + tr("Failed to save image: %1").arg(writer.errorString())); + return; + } +} + void MainWindow::on_actionActualSize_triggered() { m_graphicsView->resetScale(); diff --git a/app/mainwindow.h b/app/mainwindow.h index 7241697..71833f8 100644 --- a/app/mainwindow.h +++ b/app/mainwindow.h @@ -75,6 +75,7 @@ protected: private slots: void on_actionOpen_triggered(); + void on_actionSaveAs_triggered(); void on_actionActualSize_triggered(); void on_actionToggleMaximize_triggered();