rawTherapee/rtgui/saveasdlg.cc
2019-10-30 16:38:02 +01:00

379 lines
11 KiB
C++

/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* RawTherapee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RawTherapee is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <https://www.gnu.org/licenses/>.
*/
#include <functional>
#include "saveasdlg.h"
#include "guiutils.h"
#include "multilangmgr.h"
#include "rtimage.h"
#include "../rtengine/utils.h"
namespace
{
Glib::ustring getCurrentFilename(const Gtk::FileChooserWidget* fchooser)
{
Glib::ustring res = fchooser->get_filename();
// NB: There seem to be a bug in Gtkmm2.22 / FileChooserWidget : if you suppress the filename entry and
// click on a folder in the list, the filename field is empty but get_filename will return the folder's path :/
if (Glib::file_test(res, Glib::FILE_TEST_IS_DIR)) {
res = fchooser->get_current_name();
}
return res;
}
}
SaveAsDialog::SaveAsDialog (const Glib::ustring &initialDir, Gtk::Window* parent)
: Gtk::Dialog (M("GENERAL_SAVE"), *parent)
{
Gtk::Box* box = get_content_area ();
fchooser = Gtk::manage( new Gtk::FileChooserWidget (Gtk::FILE_CHOOSER_ACTION_SAVE) );
fchooser->set_current_folder (initialDir);
fchooser->signal_file_activated().connect(sigc::mem_fun(*this, &SaveAsDialog::okPressed));
filter_jpg = Gtk::FileFilter::create();
filter_jpg->set_name(M("SAVEDLG_JPGFILTER"));
filter_jpg->add_pattern("*.jpg");
filter_jpg->add_pattern("*.JPG");
filter_jpg->add_pattern("*.jpeg");
filter_jpg->add_pattern("*.JPEG");
filter_jpg->add_pattern("*.jpe");
filter_jpg->add_pattern("*.JPE");
filter_tif = Gtk::FileFilter::create();
filter_tif->set_name(M("SAVEDLG_JPGFILTER"));
filter_tif->add_pattern("*.tif");
filter_tif->add_pattern("*.TIF");
filter_tif->add_pattern("*.tiff");
filter_tif->add_pattern("*.TIFF");
filter_png = Gtk::FileFilter::create();
filter_png->set_name(M("SAVEDLG_JPGFILTER"));
filter_png->add_pattern("*.png");
filter_png->add_pattern("*.PNG");
formatChanged (options.saveFormat.format);
// Output Options
// ~~~~~~~~~~~~~~
formatOpts = Gtk::manage( new SaveFormatPanel () );
setExpandAlignProperties(formatOpts, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START);
formatOpts->setListener (this);
// queue/immediate
// ~~~~~~~~~~~~~~~
saveMethod[0] = Gtk::manage( new Gtk::RadioButton (M("SAVEDLG_SAVEIMMEDIATELY")) );
saveMethod[1] = Gtk::manage( new Gtk::RadioButton (M("SAVEDLG_PUTTOQUEUEHEAD")) );
saveMethod[2] = Gtk::manage( new Gtk::RadioButton (M("SAVEDLG_PUTTOQUEUETAIL")) );
Gtk::RadioButton::Group g = saveMethod[0]->get_group();
saveMethod[1]->set_group (g);
saveMethod[2]->set_group (g);
if (options.saveMethodNum >= 0 && options.saveMethodNum < 3) {
saveMethod[options.saveMethodNum]->set_active (true);
}
saveMethod[0]->signal_clicked().connect( sigc::mem_fun(*this, &SaveAsDialog::saveImmediatlyClicked) );
saveMethod[1]->signal_clicked().connect( sigc::mem_fun(*this, &SaveAsDialog::putToQueueClicked) );
saveMethod[2]->signal_clicked().connect( sigc::mem_fun(*this, &SaveAsDialog::putToQueueClicked) );
// Force output format option
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
forceFormatOpts = Gtk::manage( new Gtk::CheckButton (M("SAVEDLG_FORCEFORMATOPTS")) );
forceFormatOpts->set_active(options.forceFormatOpts);
forceFormatOpts->set_sensitive(options.saveMethodNum > 0);
forceFormatOpts->signal_clicked().connect( sigc::mem_fun(*this, &SaveAsDialog::forceFmtOptsSwitched) );
// update sensitivity of the SaveFormatPanel
formatOpts->set_sensitive(options.saveMethodNum == 0 || options.forceFormatOpts);
// Unique filename option
// ~~~~~~~~~~~~~~~~~~~~~~
autoSuffix = Gtk::manage( new Gtk::CheckButton (M("SAVEDLG_AUTOSUFFIX")) );
autoSuffix->set_active(options.autoSuffix);
// buttons
// ~~~~~~~
Gtk::Button* ok = Gtk::manage( new Gtk::Button (M("GENERAL_OK")) );
Gtk::Button* cancel = Gtk::manage( new Gtk::Button (M("GENERAL_CANCEL")) );
ok->set_tooltip_markup (M("TP_SAVEDIALOG_OK_TIP"));
ok->signal_clicked().connect( sigc::mem_fun(*this, &SaveAsDialog::okPressed) );
cancel->signal_clicked().connect( sigc::mem_fun(*this, &SaveAsDialog::cancelPressed) );
// pack everything
// ~~~~~~~~~~~~~~~
Gtk::VBox* vbox_bottomRight = Gtk::manage(new Gtk::VBox ());
// There is no queue in simple mode, so no need to choose
if (!simpleEditor) {
vbox_bottomRight->pack_start (*saveMethod[0], Gtk::PACK_SHRINK, 2);
vbox_bottomRight->pack_start (*saveMethod[1], Gtk::PACK_SHRINK, 2);
vbox_bottomRight->pack_start (*saveMethod[2], Gtk::PACK_SHRINK, 2);
vbox_bottomRight->pack_start (*Gtk::manage(new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 5);
}
vbox_bottomRight->pack_start (*forceFormatOpts, Gtk::PACK_SHRINK, 4);
vbox_bottomRight->pack_start (*autoSuffix, Gtk::PACK_SHRINK, 4);
Gtk::HBox* hbox_bottom = Gtk::manage( new Gtk::HBox() );
hbox_bottom->pack_start (*formatOpts, Gtk::PACK_EXPAND_WIDGET, 2);
hbox_bottom->pack_start (*Gtk::manage(new Gtk::VSeparator ()), Gtk::PACK_SHRINK, 2);
hbox_bottom->pack_start (*vbox_bottomRight, Gtk::PACK_EXPAND_WIDGET, 2);
box->pack_start (*fchooser);
box->pack_start (*hbox_bottom, Gtk::PACK_SHRINK, 2);
get_action_area()->pack_end (*ok, Gtk::PACK_SHRINK, 4);
get_action_area()->pack_end (*cancel, Gtk::PACK_SHRINK, 4);
show_all_children ();
formatOpts->init (options.saveFormat);
signal_key_press_event().connect( sigc::mem_fun(*this, &SaveAsDialog::keyPressed) );
}
void SaveAsDialog::saveImmediatlyClicked ()
{
forceFormatOpts->set_sensitive(false);
formatOpts->set_sensitive(true);
}
void SaveAsDialog::putToQueueClicked ()
{
forceFormatOpts->set_sensitive(true);
formatOpts->set_sensitive(forceFormatOpts->get_active());
}
void SaveAsDialog::forceFmtOptsSwitched ()
{
formatOpts->set_sensitive(forceFormatOpts->get_active());
}
bool SaveAsDialog::getForceFormatOpts ()
{
return forceFormatOpts->get_active();
}
bool SaveAsDialog::getAutoSuffix ()
{
return autoSuffix->get_active();
}
bool SaveAsDialog::getImmediately ()
{
return simpleEditor ? true : saveMethod[0]->get_active ();
}
bool SaveAsDialog::getToHeadOfQueue ()
{
return saveMethod[1]->get_active ();
}
bool SaveAsDialog::getToTailOfQueue ()
{
return saveMethod[2]->get_active ();
}
int SaveAsDialog::getSaveMethodNum ()
{
if (simpleEditor) {
return 0;
}
for (int i = 0; i < 3; i++)
if (saveMethod[i]->get_active()) {
return i;
}
return -1;
}
Glib::ustring SaveAsDialog::getFileName ()
{
return fname;
}
Glib::ustring SaveAsDialog::getDirectory ()
{
return fchooser->get_current_folder ();
}
SaveFormat SaveAsDialog::getFormat ()
{
return formatOpts->getFormat ();
}
void SaveAsDialog::okPressed ()
{
fname = getCurrentFilename(fchooser);
// Checking if the filename field is empty. The user have to click Cancel if he don't want to specify a filename
if (fname.empty()) {
Gtk::MessageDialog(
*this,
Glib::ustring("<b>")
+ M("MAIN_MSG_EMPTYFILENAME")
+ "</b>",
true,
Gtk::MESSAGE_WARNING,
Gtk::BUTTONS_OK,
true
).run();
return;
}
if (getExtension(fname).empty()) {
// Extension is either empty or unfamiliar
fname += '.' + formatOpts->getFormat().format;
} else if (
(
formatOpts->getFormat().format == "jpg"
&& !rtengine::hasJpegExtension(fname)
)
|| (
formatOpts->getFormat().format == "tif"
&& !rtengine::hasTiffExtension(fname)
)
|| (
formatOpts->getFormat().format == "png"
&& !rtengine::hasPngExtension(fname)
)
) {
// Create dialog to warn user that the filename may have two extensions on the end
Gtk::MessageDialog msgd(
*this,
Glib::ustring("<b>")
+ M("GENERAL_WARNING")
+ ": "
+ M("SAVEDLG_WARNFILENAME")
+ " \""
+ Glib::path_get_basename (fname)
+ '.'
+ formatOpts->getFormat().format
+ "\"</b>",
true,
Gtk::MESSAGE_WARNING,
Gtk::BUTTONS_OK_CANCEL,
true
);
if (msgd.run() == Gtk::RESPONSE_OK) {
fname += "." + formatOpts->getFormat().format;
} else {
return;
}
}
response (Gtk::RESPONSE_OK);
}
void SaveAsDialog::cancelPressed ()
{
response (Gtk::RESPONSE_CANCEL);
}
void SaveAsDialog::formatChanged(const Glib::ustring& format)
{
const auto sanitize_suffix =
[this, format](const std::function<bool (const Glib::ustring&)>& has_suffix)
{
const Glib::ustring name = getCurrentFilename(fchooser);
if (!has_suffix(name)) {
fchooser->set_current_name(removeExtension(Glib::path_get_basename(name)) + '.' + format);
}
};
if (format == "jpg") {
fchooser->set_filter (filter_jpg);
sanitize_suffix(
[](const Glib::ustring& filename)
{
return rtengine::hasJpegExtension(filename);
}
);
} else if (format == "png") {
fchooser->set_filter (filter_png);
sanitize_suffix(
[](const Glib::ustring& filename)
{
return rtengine::hasPngExtension(filename);
}
);
} else if (format == "tif") {
fchooser->set_filter (filter_tif);
sanitize_suffix(
[](const Glib::ustring& filename)
{
return rtengine::hasTiffExtension(filename);
}
);
}
}
void SaveAsDialog::setInitialFileName (const Glib::ustring& fname)
{
this->fname = fname;
fchooser->set_current_name(fname);
}
void SaveAsDialog::setImagePath (const Glib::ustring& imagePath)
{
const auto dirName = Glib::path_get_dirname (imagePath);
try {
fchooser->add_shortcut_folder (dirName);
} catch (Glib::Error&) {}
}
bool SaveAsDialog::keyPressed (GdkEventKey* event)
{
bool ctrl = event->state & GDK_CONTROL_MASK;
if (ctrl) {
switch(event->keyval) {
case GDK_KEY_Return: // Ctrl-Enter equivalent to pressing OK button
case GDK_KEY_KP_Enter:
SaveAsDialog::okPressed();
return true;
}
}
return false;
}