diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 81e135ae8..4353ac7e5 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -274,7 +274,11 @@ void ProcParams::setDefaults () { ppVersion = PPVERSION; } -int ProcParams::save (Glib::ustring fname) const { +int ProcParams::save (Glib::ustring fname, Glib::ustring fname2) const { + + if (!fname.length() && !fname2.length()) + return 0; + SafeKeyFile keyFile; keyFile.set_string ("Version", "AppVersion", APPVERSION); @@ -531,15 +535,29 @@ int ProcParams::save (Glib::ustring fname) const { keyFile.set_string_list ("IPTC", iptc[i].field, values); } - FILE *f = safe_g_fopen (fname, "wt"); - - if (f==NULL) - return 1; - else { - fprintf (f, "%s", keyFile.to_data().c_str()); - fclose (f); - return 0; + Glib::ustring sPParams = keyFile.to_data(); + + int error1, error2; + error1 = write (fname , sPParams); + error2 = write (fname2, sPParams); + return error1 & error2; +} + +int ProcParams::write (Glib::ustring &fname, Glib::ustring &content) const { + + int error = 0; + if (fname.length()) { + FILE *f; + f = safe_g_fopen (fname, "wt"); + + if (f==NULL) + error = 1; + else { + fprintf (f, "%s", content.c_str()); + fclose (f); + } } + return error; } int ProcParams::load (Glib::ustring fname) { diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 989fcee60..cea1450a2 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -496,11 +496,13 @@ class ProcParams { */ void setDefaults (); /** - * Saves the parameters to a file. - * @param fname the name of the file - * @return Error code (=0 if no error) + * Saves the parameters to possibly two files. This is a performance improvement if a function has to + * save the same file in two different location, i.e. the cache and the image's directory + * @param fname the name of the first file (can be an empty string) + * @param fname2 the name of the second file (can be an empty string) (optional) + * @return Error code (=0 if all supplied filenames where created correctly) */ - int save (Glib::ustring fname) const; + int save (Glib::ustring fname, Glib::ustring fname2 = "") const; /** * Loads the parameters from a file. * @param fname the name of the file @@ -518,6 +520,15 @@ class ProcParams { bool operator== (const ProcParams& other); bool operator!= (const ProcParams& other); + + private: + /** Write the ProcParams's text in the file of the given name. + * @param fname the name of the file + * @param content the text to write + * @return Error code (=0 if no error) + * */ + int write (Glib::ustring &fname, Glib::ustring &content) const; + }; } } diff --git a/rtengine/safegtk.cc b/rtengine/safegtk.cc index dcc56696d..fcd6117d2 100644 --- a/rtengine/safegtk.cc +++ b/rtengine/safegtk.cc @@ -106,13 +106,45 @@ void safe_build_file_list (Glib::RefPtr &dir, std::vector &dir, std::vector &names, const Glib::ustring &directory) +/* + * safe_build_file_list can now filter out at the source all files that doesn't have the extensions specified (if provided) + */ +void safe_build_file_list (Glib::RefPtr &dir, std::vector &names, const Glib::ustring &directory, const std::vector *extensions) { Glib::RefPtr dirList; + if (dir) { - SAFE_ENUMERATOR_CODE_START - names.push_back (Glib::build_filename (directory, info->get_name())); - SAFE_ENUMERATOR_CODE_END; + if (!extensions) { + SAFE_ENUMERATOR_CODE_START + names.push_back (Glib::build_filename (directory, info->get_name())); + SAFE_ENUMERATOR_CODE_END; + } + else { + // convert extensions to lowercase in a new vector list + std::vector lcExtensions; + for (unsigned int i=0; isize(); i++) + lcExtensions.push_back ((*extensions)[i].lowercase()); + + SAFE_ENUMERATOR_CODE_START + // convert the current filename to lowercase in a new ustring + Glib::ustring fname = Glib::ustring(info->get_name()).lowercase(); + + int pos = fname.find_last_of('.'); + if (pos > -1 && pos < (fname.length()-1)) { + // there is an extension to the filename + + Glib::ustring lcFileExt = fname.substr(pos+1).lowercase(); + + // look out if it has one of the retained extensions + for (unsigned int i=0; iget_name())); + break; + } + } + } + SAFE_ENUMERATOR_CODE_END; + } } } diff --git a/rtengine/safegtk.h b/rtengine/safegtk.h index 53b55fe7b..010044d59 100644 --- a/rtengine/safegtk.h +++ b/rtengine/safegtk.h @@ -20,7 +20,7 @@ class FileMTimeInfo { Glib::RefPtr safe_query_file_info (Glib::RefPtr &file); void safe_build_file_list (Glib::RefPtr &dir, std::vector &flist); -void safe_build_file_list (Glib::RefPtr &dir, std::vector &names, const Glib::ustring &directory = ""); +void safe_build_file_list (Glib::RefPtr &dir, std::vector &names, const Glib::ustring &directory = "", const std::vector *extensions=NULL); void safe_build_subdir_list (Glib::RefPtr &dir, std::vector &subDirs, bool add_hidden); bool safe_spawn_command_line_async (const Glib::ustring& cmd_utf8); diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index bb2d6b6eb..25a2ecb9d 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -471,9 +471,7 @@ void EditorPanel::saveProfile () { ProcParams params; ipc->getParams (¶ms); - if (options.saveParamsFile) - params.save (openThm->getFileName() + paramFileExtension); - if (options.saveParamsCache) + // Will call updateCache, which will update both the cached and sidecar files if necessary openThm->setProcParams (params, EDITOR); } } diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index 8d81599e0..fc7271998 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -832,7 +832,7 @@ void FileBrowser::toTrashRequested (std::vector tbe) { tbe[i]->getThumbButtonSet()->setRank (tbe[i]->thumbnail->getRank()); tbe[i]->getThumbButtonSet()->setColorLabel (tbe[i]->thumbnail->getColorLabel()); tbe[i]->getThumbButtonSet()->setInTrash (true); - tbe[i]->thumbnail->updateCache(); // needed to save the rank to disk + tbe[i]->thumbnail->updateCache (); // needed to save the colorlabel to disk in the procparam file(s) and the cache image data file } } trash_changed().emit(); @@ -851,7 +851,7 @@ void FileBrowser::fromTrashRequested (std::vector tbe) { tbe[i]->getThumbButtonSet()->setRank (tbe[i]->thumbnail->getRank()); tbe[i]->getThumbButtonSet()->setColorLabel (tbe[i]->thumbnail->getColorLabel()); tbe[i]->getThumbButtonSet()->setInTrash (false); - tbe[i]->thumbnail->updateCache(); // needed to save the rank to disk + tbe[i]->thumbnail->updateCache (); // needed to save the colorlabel to disk in the procparam file(s) and the cache image data file } } trash_changed().emit(); @@ -868,7 +868,7 @@ void FileBrowser::rankingRequested (std::vector tbe, int rank tbe[i]->thumbnail->notifylisterners_procParamsChanged(FILEBROWSER); tbe[i]->thumbnail->setRank (rank); - tbe[i]->thumbnail->updateCache(); // needed to save the rank to disk + tbe[i]->thumbnail->updateCache (); // needed to save the colorlabel to disk in the procparam file(s) and the cache image data file //TODO? - should update pparams instead? if (tbe[i]->getThumbButtonSet()) @@ -887,7 +887,7 @@ void FileBrowser::colorlabelRequested (std::vector tbe, int c tbe[i]->thumbnail->notifylisterners_procParamsChanged(FILEBROWSER); tbe[i]->thumbnail->setColorLabel (colorlabel); - tbe[i]->thumbnail->updateCache(); // needed to save the colorlabel to disk + tbe[i]->thumbnail->updateCache(); // needed to save the colorlabel to disk in the procparam file(s) and the cache image data file //TODO? - should update pparams instead? if (tbe[i]->getThumbButtonSet()) tbe[i]->getThumbButtonSet()->setColorLabel (tbe[i]->thumbnail->getColorLabel()); diff --git a/rtgui/filebrowser.h b/rtgui/filebrowser.h index 2451241a5..57abad04e 100644 --- a/rtgui/filebrowser.h +++ b/rtgui/filebrowser.h @@ -46,6 +46,9 @@ struct FileBrowserIdleHelper { int pending; }; +/* + * Class handling actions common to all thumbnails of the file browser + */ class FileBrowser : public ThumbBrowserBase, public LWButtonListener { typedef sigc::signal type_trash_changed; diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index 0c69cd00f..3fcbaa2ee 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -464,7 +464,7 @@ std::vector FileCatalog::getFileList () { std::vector names; Glib::RefPtr dir = Gio::File::create_for_path (selectedDirectory); - safe_build_file_list (dir, names, selectedDirectory); + safe_build_file_list (dir, names, selectedDirectory, &(options.parsedExtensions)); return names; } @@ -666,9 +666,10 @@ void FileCatalog::_openImage (std::vector tmb) { bool continueToLoad=true; for (size_t i=0; i< tmb.size() && continueToLoad; i++) { if (editedFiles.find (tmb[i]->getFileName())==editedFiles.end()){ - listener->fileSelected (tmb[i]); - if( !options.tabbedUI ) - continueToLoad = false; + // Open the image here, and stop if in Single Editor mode, or if an image couldn't + // be opened, would it be because the file doesn't exist or because of lack of RAM + if( !(listener->fileSelected (tmb[i])) && !options.tabbedUI ) + continueToLoad = false; } tmb[i]->decreaseRef (); } @@ -1276,20 +1277,25 @@ int winDirChangedUITread (void* cat) { void FileCatalog::winDirChanged () { g_idle_add(winDirChangedUITread, this); } -#endif + +#else void FileCatalog::on_dir_changed (const Glib::RefPtr& file, const Glib::RefPtr& other_file, Gio::FileMonitorEvent event_type, bool internal) { - if (!internal) - gdk_threads_enter(); + if (options.has_retained_extention(file->get_parse_name())) { + if (!internal) + gdk_threads_enter(); - if (event_type == Gio::FILE_MONITOR_EVENT_CREATED || event_type == Gio::FILE_MONITOR_EVENT_DELETED || event_type == Gio::FILE_MONITOR_EVENT_CHANGED) - reparseDirectory (); + if (event_type == Gio::FILE_MONITOR_EVENT_CREATED || event_type == Gio::FILE_MONITOR_EVENT_DELETED || event_type == Gio::FILE_MONITOR_EVENT_CHANGED) + reparseDirectory (); - if (!internal) - gdk_threads_leave(); + if (!internal) + gdk_threads_leave(); + } } +#endif + void FileCatalog::checkAndAddFile (Glib::RefPtr file) { if (!file ) diff --git a/rtgui/filecatalog.h b/rtgui/filecatalog.h index c317cad9b..84a814e80 100644 --- a/rtgui/filecatalog.h +++ b/rtgui/filecatalog.h @@ -49,6 +49,12 @@ class DirEntry { } }; class FilePanel; +/* + * Class: + * - handling the list of file (add/remove them) + * - handling the thumbnail toolbar, + * - monitoring the directory (for any change) + */ class FileCatalog : public Gtk::VBox, public DirSelectionListener, public PreviewLoaderListener, @@ -59,6 +65,7 @@ class FileCatalog : public Gtk::VBox, #endif { + private: FilePanel* filepanel; Gtk::HBox* hBox; Glib::ustring selectedDirectory; @@ -127,22 +134,20 @@ class FileCatalog : public Gtk::VBox, FilterPanel* filterPanel; - Glib::RefPtr dirMonitor; - int previewsToLoad; int previewsLoaded; -#ifdef WIN32 - WinDirMonitor* wdMonitor; - public: - void winDirChanged (); - private: -#endif std::vector fileNameList; std::set editedFiles; guint modifierKey; // any modifiers held when rank button was pressed +#ifndef _WIN32 + Glib::RefPtr dirMonitor; +#else + WinDirMonitor* wdMonitor; +#endif + void addAndOpenFile (const Glib::ustring& fname); void checkAndAddFile (Glib::RefPtr info); std::vector getFileList (); @@ -203,7 +208,6 @@ class FileCatalog : public Gtk::VBox, void runFilterDialog (); void on_realize(); - void on_dir_changed (const Glib::RefPtr& file, const Glib::RefPtr& other_file, Gio::FileMonitorEvent event_type, bool internal); void reparseDirectory (); void _openImage (std::vector tmb); @@ -226,6 +230,13 @@ class FileCatalog : public Gtk::VBox, bool CheckSidePanelsVisibility(); void toggleSidePanels(); + +#ifndef _WIN32 + void on_dir_changed (const Glib::RefPtr& file, const Glib::RefPtr& other_file, Gio::FileMonitorEvent event_type, bool internal); +#else + void winDirChanged (); +#endif + }; #endif diff --git a/rtgui/options.cc b/rtgui/options.cc index 056bb9b63..bc2c64fb6 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "version.h" @@ -121,6 +122,7 @@ void Options::setDefaults () { //crvOpen.clear (); parseExtensions.clear (); parseExtensionsEnabled.clear (); + parsedExtensions.clear (); renameUseTemplates = false; renameTemplates.clear (); thumbnailZoomRatios.clear (); @@ -227,6 +229,12 @@ Options* Options::copyFrom (Options* other) { return this; } +void Options::filterOutParsedExtensions () { + parsedExtensions.clear(); + for (unsigned int i=0; i parseExtensions; - std::vector parseExtensionsEnabled; + std::vector parseExtensions; // List containing all extensions type + std::vector parseExtensionsEnabled; // List of bool to retain extension or not + std::vector parsedExtensions; // List containing all retained extensions (lowercase) std::vector tpOpen; //std::vector crvOpen; std::vector baBehav; @@ -158,12 +159,14 @@ class Options { Options (); Options* copyFrom (Options* other); + void filterOutParsedExtensions (); void setDefaults (); int readFromFile (Glib::ustring fname); int saveToFile (Glib::ustring fname); static void load (); static void save (); + bool has_retained_extention (Glib::ustring fname); bool is_extention_enabled(Glib::ustring ext); }; diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 9a8c27076..2df2a2a3b 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -1197,6 +1197,7 @@ void Preferences::okPressed () { storePreferences (); workflowUpdate(); options.copyFrom (&moptions); + options.filterOutParsedExtensions(); Options::save (); hide (); } diff --git a/rtgui/thumbbrowserbase.h b/rtgui/thumbbrowserbase.h index 4bfc3f39c..3095ee5d4 100644 --- a/rtgui/thumbbrowserbase.h +++ b/rtgui/thumbbrowserbase.h @@ -23,6 +23,9 @@ #include #include +/* + * Class handling the list of ThumbBrowserEntry objects and their position in it's allocated space + */ class ThumbBrowserBase : public Gtk::VBox { class Internal : public Gtk::DrawingArea { diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index 1bd3cb8f4..4500c0a83 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -618,15 +618,15 @@ void Thumbnail::saveThumbnail () _saveThumbnail(); } -void Thumbnail::updateCache () { +void Thumbnail::updateCache (bool updatePParams, bool updateCacheImageData) { - if (pparamsValid) { - if (options.saveParamsCache) - pparams.save (getCacheFileName ("profiles")+paramFileExtension); - if (options.saveParamsFile) -// pparams.save (removeExtension(fname) + paramFileExtension); - pparams.save (fname + paramFileExtension); + if (updatePParams && pparamsValid) { + pparams.save ( + options.saveParamsCache ? getCacheFileName ("profiles")+paramFileExtension : "", + options.saveParamsFile ? fname + paramFileExtension : "" + ); } + if (updateCacheImageData) cfs.save (getCacheFileName ("data")+".txt"); } diff --git a/rtgui/thumbnail.h b/rtgui/thumbnail.h index c780ade90..6a6c28a5e 100644 --- a/rtgui/thumbnail.h +++ b/rtgui/thumbnail.h @@ -135,7 +135,7 @@ class Thumbnail { void increaseRef (); void decreaseRef (); - void updateCache (); + void updateCache (bool updatePParams = true, bool updateCacheImageData = true); void saveThumbnail (); bool openDefaultViewer(int destination); diff --git a/rtgui/windirmonitor.cc b/rtgui/windirmonitor.cc index d7269da1a..d0437c961 100644 --- a/rtgui/windirmonitor.cc +++ b/rtgui/windirmonitor.cc @@ -17,18 +17,86 @@ * along with RawTherapee. If not, see . */ #include +#include static void CALLBACK current_directory_monitor_callback (DWORD error, DWORD nBytes, LPOVERLAPPED lpOverlapped) { + + DWORD dwOffset = 0; + FILE_NOTIFY_INFORMATION* pInfo = NULL; + WinDirMonitor::MonitorData* monData = (WinDirMonitor::MonitorData*)lpOverlapped; if (!nBytes) { delete monData; return; } + bool notify = false; + // Analysis of the modifications + do { + Glib::ustring fname = ""; + Glib::ustring action = ""; + int strLen = 0; + + // Get a pointer to the first change record... + pInfo = (FILE_NOTIFY_INFORMATION*) &monData->file_notify_buffer[dwOffset]; + + char fnameC[(MAX_PATH+1)*2] = {0}; + strLen = WideCharToMultiByte(CP_UTF8,0,pInfo->FileName,pInfo->FileNameLength/sizeof(WCHAR),fnameC,sizeof(fnameC),0,0); + fnameC[strLen] = 0; + fname = fnameC; + + if (options.has_retained_extention(fname)) + { + switch (pInfo->Action) + { + case (FILE_ACTION_ADDED): + action = "FILE_ACTION_ADDED"; + break; + case (FILE_ACTION_REMOVED): + action = "FILE_ACTION_REMOVED"; + break; + case (FILE_ACTION_MODIFIED): + action = "FILE_ACTION_MODIFIED"; + break; + case (FILE_ACTION_RENAMED_OLD_NAME): + action = "FILE_ACTION_RENAMED_OLD_NAME"; + break; + case (FILE_ACTION_RENAMED_NEW_NAME): + action = "FILE_ACTION_RENAMED_NEW_NAME"; + break; + case (FILE_ACTION_REMOVED_BY_DELETE): + action = "FILE_ACTION_REMOVED_BY_DELETE"; + /* break; + case (FILE_ACTION_ADDED_STREAM): + action = "FILE_ACTION_ADDED_STREAM"; + break; + case (FILE_ACTION_REMOVED_STREAM): + action = "FILE_ACTION_REMOVED_STREAM"; + break; + case (FILE_ACTION_MODIFIED_STREAM): + action = "FILE_ACTION_MODIFIED_STREAM"; + break; + case (FILE_ACTION_ID_NOT_TUNNELLED): + action = "FILE_ACTION_ID_NOT_TUNNELLED"; + break; + case (FILE_ACTION_TUNNELLED_ID_COLLISION): + action = "FILE_ACTION_TUNNELLED_ID_COLLISION";*/ + default: + break; + } + notify = true; + } + + // More than one change may happen at the same time. Load the next change and continue... + dwOffset += pInfo->NextEntryOffset; + } + while (pInfo->NextEntryOffset != 0); + // ReadDirectoryChangesW sometimes emits multiple events per change (one for each change type) // To make sure it's not flooding update, this gets filtered. time_t curTime= ::time(NULL); - if (monData->listener && ::difftime(curTime, monData->lastTimeUpdateDir)>1.0) { + if (notify && monData->listener && ::difftime(curTime, monData->lastTimeUpdateDir)>1.0) { + printf("----- Appel de WinDirChanged -----\n"); monData->listener->winDirChanged (); monData->lastTimeUpdateDir = curTime; }