diff --git a/rtdata/languages/default b/rtdata/languages/default index 5f589b0f3..6af289209 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1466,6 +1466,7 @@ TP_EXPOS_WHITEPOINT_LABEL;Raw White Points TP_FILMSIMULATION_LABEL;Film Simulation TP_FILMSIMULATION_STRENGTH;Strength TP_FILMSIMULATION_ZEROCLUTSFOUND;Set HaldCLUT directory in Preferences +TP_FILMSIMULATION_SLOWPARSEDIR;The Film Simulation HaldCLUT folder you pointed RawTherapee to is taking too long to load. Reduce the number of files in that folder or point RawTherapee to an empty one instead.\n\nSee Preferences > Image Processing > Film Simulation TP_FLATFIELD_AUTOSELECT;Auto-selection TP_FLATFIELD_BLURRADIUS;Blur radius TP_FLATFIELD_BLURTYPE;Blur type diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc index b77da03dd..ff29c72ab 100644 --- a/rtengine/iccstore.cc +++ b/rtengine/iccstore.cc @@ -54,7 +54,7 @@ void loadProfiles (const Glib::ustring& dirName, const Glib::ustring extension = fileName.substr (fileName.size () - 4).casefold (); - if (extension.compare(".icc") == 0 && extension.compare(".icm") == 0) + if (extension.compare (".icc") != 0 && extension.compare (".icm") != 0) continue; const Glib::ustring filePath = Glib::build_filename (dirName, fileName); diff --git a/rtgui/filmsimulation.cc b/rtgui/filmsimulation.cc index 907f5578a..6052fdc87 100644 --- a/rtgui/filmsimulation.cc +++ b/rtgui/filmsimulation.cc @@ -1,4 +1,7 @@ #include "filmsimulation.h" + +#include + #include "options.h" #include "../rtengine/clutstore.h" #include "../rtengine/safegtk.h" @@ -6,6 +9,30 @@ using namespace rtengine; using namespace rtengine::procparams; +namespace +{ + +void notifySlowParseDir (const std::chrono::system_clock::time_point& startedAt) +{ + static bool alreadyNotified = false; + + if (alreadyNotified) { + return; + } + + const auto now = std::chrono::system_clock::now (); + if (now - startedAt < std::chrono::seconds (10)) { + return; + } + + Gtk::MessageDialog dialog (M ("TP_FILMSIMULATION_SLOWPARSEDIR"), false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true); + dialog.run (); + + alreadyNotified = true; +} + +} + typedef std::vector Strings; FilmSimulation::FilmSimulation() @@ -143,83 +170,119 @@ ClutComboBox::ClutColumns::ClutColumns() add( clutFilename ); } -int ClutComboBox::fillFromDir( Glib::ustring path ) +int ClutComboBox::fillFromDir (const Glib::ustring& path) { - int result = 0; + m_model = Gtk::TreeStore::create (m_columns); + set_model (m_model); - if ( !path.empty() ) { - m_model.clear(); - m_model = Gtk::TreeStore::create( m_columns ); - set_model( m_model ); - result = parseDir( path, 0 ); - pack_start( m_columns.label, false ); + const auto result = parseDir (path); + + if (result > 0) { + pack_start (m_columns.label, false); } return result; } -Gtk::TreeIter appendToModel( Glib::RefPtr model, Gtk::TreeModel::Row *parent ) +int ClutComboBox::parseDir (const Glib::ustring& path) { - Gtk::TreeIter result; - - if ( parent ) { - result = model->append( parent->children() ); - - } else { - result = model->append(); + if (path.empty () || !Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) { + return 0; } - return result; -} + const auto startedAt = std::chrono::system_clock::now (); -int ClutComboBox::parseDir( Glib::ustring path, Gtk::TreeModel::Row *parentRow ) -{ - int result = 0; + // Build menu of limited directory structure using breadth-first search + using Dirs = std::vector>; + Dirs dirs; - if ( path.empty() || !safe_file_test( path, Glib::FILE_TEST_EXISTS ) || !safe_file_test ( path, Glib::FILE_TEST_IS_DIR ) ) { - return result; - } + { + Dirs currDirs; + Dirs nextDirs; - Glib::Dir* dir = new Glib::Dir( path ); + currDirs.emplace_back (path, Gtk::TreeModel::Row ()); - Strings names; + while (!currDirs.empty ()) { - for( Glib::DirIterator it = dir->begin(); it != dir->end(); ++it ) { - Glib::ustring current = *it; + for (auto& dir : currDirs) { - if ( current != "." && current != ".." ) { - names.push_back( current ); - } - } + const auto& path = dir.first; + const auto& row = dir.second; - std::sort( names.begin(), names.end() ); + try { + for (const auto& entry : Glib::Dir (path)) { - for ( Strings::iterator it = names.begin(); it != names.end(); ++it ) { - Glib::ustring current = *it; - Glib::ustring fullname = Glib::build_filename( path, current ); + const auto entryPath = Glib::build_filename (path, entry); - if ( safe_file_test( fullname, Glib::FILE_TEST_IS_DIR ) ) { + if (!Glib::file_test (entryPath, Glib::FILE_TEST_IS_DIR)) { + continue; + } - Gtk::TreeModel::Row newFolderMenu = *appendToModel( m_model, parentRow ); - newFolderMenu[ m_columns.label ] = current; - result += parseDir( fullname, &newFolderMenu ); - } else { - Glib::ustring name, extension, profileName; - splitClutFilename( current, name, extension, profileName ); + auto newRow = row ? *m_model->append (row.children ()) : *m_model->append (); + newRow[m_columns.label] = entry; - if ( extension == "tif" || - extension == "TIF" || - extension == "png" || - extension == "PNG" ) { - Gtk::TreeModel::Row newClut = *appendToModel( m_model, parentRow ); - newClut[ m_columns.label ] = name; - newClut[ m_columns.clutFilename ] = fullname; - ++result; + nextDirs.emplace_back (entryPath, newRow); + } + } catch (Glib::Exception&) {} + + dirs.push_back (std::move (dir)); + + notifySlowParseDir (startedAt); } + + currDirs.clear (); + currDirs.swap (nextDirs); } } - return result; + // Fill menu structure with CLUT files + Strings entries; + + auto fileCount = 0; + + for (const auto& dir : dirs) { + + const auto& path = dir.first; + const auto& row = dir.second; + + entries.clear (); + + try { + for (const auto& entry : Glib::Dir (path)) { + + const auto entryPath = Glib::build_filename (path, entry); + + if (!Glib::file_test (entryPath, Glib::FILE_TEST_IS_REGULAR)) { + continue; + } + + entries.push_back (entryPath); + } + } catch (Glib::Exception&) {} + + std::sort (entries.begin (), entries.end ()); + + for (const auto& entry : entries) { + + Glib::ustring name, extension, profileName; + splitClutFilename (entry, name, extension, profileName); + + extension = extension.casefold (); + if (extension.compare ("tif") != 0 && extension.compare ("png") != 0) { + continue; + } + + auto newRow = row ? *m_model->append (row.children ()) : *m_model->append (); + newRow[m_columns.label] = name; + newRow[m_columns.clutFilename] = entry; + + ++fileCount; + + notifySlowParseDir (startedAt); + } + } + + return fileCount; } Glib::ustring ClutComboBox::getSelectedClut() diff --git a/rtgui/filmsimulation.h b/rtgui/filmsimulation.h index 89e9f6fa3..440bf0c9e 100644 --- a/rtgui/filmsimulation.h +++ b/rtgui/filmsimulation.h @@ -11,7 +11,7 @@ class ClutComboBox : public MyComboBox { public: - int fillFromDir( Glib::ustring path ); + int fillFromDir (const Glib::ustring& path); Glib::ustring getSelectedClut(); void setSelectedClut( Glib::ustring filename ); void addUnchangedEntry(); @@ -25,7 +25,7 @@ private: ClutColumns(); }; - int parseDir( Glib::ustring path, Gtk::TreeModel::Row *parentRow ); + int parseDir (const Glib::ustring& path); Gtk::TreeIter findRowByClutFilename( Gtk::TreeModel::Children childs, Glib::ustring filename ); Glib::RefPtr m_model;