/* * This file is part of RawTherapee. * * Copyright (c) 2004-2010 Gabor Horvath * * 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 . */ #include #include "saveasdlg.h" #include "guiutils.h" #include "multilangmgr.h" #include "pathutils.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_TOOLTIP")); ok->signal_clicked().connect( sigc::mem_fun(*this, &SaveAsDialog::okPressed) ); cancel->signal_clicked().connect( sigc::mem_fun(*this, &SaveAsDialog::cancelPressed) ); // pack everything // ~~~~~~~~~~~~~~~ Gtk::Box* vbox_bottomRight = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); // 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::Separator(Gtk::ORIENTATION_HORIZONTAL)), Gtk::PACK_SHRINK, 5); } vbox_bottomRight->pack_start (*forceFormatOpts, Gtk::PACK_SHRINK, 4); vbox_bottomRight->pack_start (*autoSuffix, Gtk::PACK_SHRINK, 4); Gtk::Box* hbox_bottom = Gtk::manage( new Gtk::Box() ); hbox_bottom->pack_start (*formatOpts, Gtk::PACK_EXPAND_WIDGET, 2); hbox_bottom->pack_start (*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_VERTICAL)), 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("") + M("MAIN_MSG_EMPTYFILENAME") + "", 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("") + M("GENERAL_WARNING") + ": " + M("SAVEDLG_WARNFILENAME") + " \"" + escapeHtmlChars(Glib::path_get_basename (fname)) + '.' + escapeHtmlChars(formatOpts->getFormat().format) + "\"", 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& 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; }