filecatalog: further speedups; also remember last copy/move destination

This commit is contained in:
Ingo Weyrich 2019-07-16 20:07:29 +02:00
parent 3130fe7ca3
commit d68b33effc
4 changed files with 112 additions and 144 deletions

View File

@ -571,16 +571,13 @@ std::vector<Glib::ustring> FileCatalog::getFileList()
BENCHFUN
std::vector<Glib::ustring> names;
std::set<std::string> extensions;
for (const auto& parsedExt : options.parsedExtensions) {
extensions.emplace(parsedExt.lowercase());
}
const std::set<std::string>& extensions = options.parsedExtensionsSet;
try {
const auto dir = Gio::File::create_for_path(selectedDirectory);
auto enumerator = dir->enumerate_children("standard::name");
auto enumerator = dir->enumerate_children("standard::name,standard::type,standard::is-hidden");
while (true) {
try {
@ -589,18 +586,26 @@ std::vector<Glib::ustring> FileCatalog::getFileList()
break;
}
if (file->get_file_type() == Gio::FILE_TYPE_DIRECTORY) {
continue;
}
if (!options.fbShowHidden && file->is_hidden()) {
continue;
}
const Glib::ustring fname = file->get_name();
const auto lastdot = fname.find_last_of('.');
const auto lastdot = fname.find_last_of ('.');
if (lastdot >= fname.length () - 1) {
if (lastdot >= fname.length() - 1) {
continue;
}
if (extensions.count(fname.substr(lastdot + 1).lowercase()) == 0) {
if (extensions.find(fname.substr(lastdot + 1).lowercase()) == extensions.end()) {
continue;
}
names.emplace_back(Glib::build_filename(selectedDirectory, fname));
names.push_back(Glib::build_filename(selectedDirectory, fname));
} catch (Glib::Exception& exception) {
if (options.rtSettings.verbose) {
std::cerr << exception.what() << std::endl;
@ -621,7 +626,7 @@ std::vector<Glib::ustring> FileCatalog::getFileList()
void FileCatalog::dirSelected (const Glib::ustring& dirname, const Glib::ustring& openfile)
{
BENCHFUN
try {
Glib::RefPtr<Gio::File> dir = Gio::File::create_for_path (dirname);
@ -629,7 +634,7 @@ void FileCatalog::dirSelected (const Glib::ustring& dirname, const Glib::ustring
return;
}
closeDir ();
closeDir();
previewsToLoad = 0;
previewsLoaded = 0;
@ -639,16 +644,14 @@ void FileCatalog::dirSelected (const Glib::ustring& dirname, const Glib::ustring
}
selectedDirectory = dir->get_parse_name();
//printf("FileCatalog::dirSelected selectedDirectory = %s\n",selectedDirectory.c_str());
BrowsePath->set_text (selectedDirectory);
buttonBrowsePath->set_image (*iRefreshWhite);
fileNameList = getFileList ();
BrowsePath->set_text(selectedDirectory);
buttonBrowsePath->set_image(*iRefreshWhite);
fileNameList = getFileList();
for (unsigned int i = 0; i < fileNameList.size(); i++) {
Glib::RefPtr<Gio::File> f = Gio::File::create_for_path(fileNameList[i]);
if (f->get_parse_name() != openfile) { // if we opened a file at the beginning don't add it again
checkAndAddFile (f);
if (openfile.empty() || fileNameList[i] != openfile) { // if we opened a file at the beginning don't add it again
addFile(fileNameList[i]);
}
}
@ -699,34 +702,33 @@ void FileCatalog::_refreshProgressBar ()
// In tab mode, no progress bar at all
// Also mention that this progress bar only measures the FIRST pass (quick thumbnails)
// The second, usually longer pass is done multithreaded down in the single entries and is NOT measured by this
if (!inTabMode) {
if (!inTabMode && (!previewsToLoad || std::floor(100.f * previewsLoaded / previewsToLoad) != std::floor(100.f * (previewsLoaded - 1) / previewsToLoad))) {
GThreadLock lock; // All GUI access from idle_add callbacks or separate thread HAVE to be protected
Gtk::Notebook *nb = (Gtk::Notebook *)(filepanel->get_parent());
Gtk::Grid* grid = Gtk::manage (new Gtk::Grid ());
Gtk::Grid* grid = Gtk::manage(new Gtk::Grid());
Gtk::Label *label = nullptr;
if (!previewsToLoad ) {
grid->attach_next_to(*Gtk::manage (new RTImage ("folder-closed.png")), options.mainNBVertical ? Gtk::POS_TOP : Gtk::POS_RIGHT, 1, 1);
if (!previewsToLoad) {
grid->attach_next_to(*Gtk::manage(new RTImage("folder-closed.png")), options.mainNBVertical ? Gtk::POS_TOP : Gtk::POS_RIGHT, 1, 1);
int filteredCount = min(fileBrowser->getNumFiltered(), previewsLoaded);
label = Gtk::manage (new Gtk::Label (M("MAIN_FRAME_FILEBROWSER") +
(filteredCount != previewsLoaded ? " [" + Glib::ustring::format(filteredCount) + "/" : " (")
+ Glib::ustring::format(previewsLoaded) +
(filteredCount != previewsLoaded ? "]" : ")")));
label = Gtk::manage(new Gtk::Label(M("MAIN_FRAME_FILEBROWSER") +
(filteredCount != previewsLoaded ? " [" + Glib::ustring::format(filteredCount) + "/" : " (")
+ Glib::ustring::format(previewsLoaded) +
(filteredCount != previewsLoaded ? "]" : ")")));
} else {
grid->attach_next_to(*Gtk::manage (new RTImage ("magnifier.png")), options.mainNBVertical ? Gtk::POS_TOP : Gtk::POS_RIGHT, 1, 1);
label = Gtk::manage (new Gtk::Label (M("MAIN_FRAME_FILEBROWSER") + " [" + Glib::ustring::format(std::fixed, std::setprecision(0), std::setw(3), (double)previewsLoaded / previewsToLoad * 100 ) + "%]" ));
grid->attach_next_to(*Gtk::manage(new RTImage("magnifier.png")), options.mainNBVertical ? Gtk::POS_TOP : Gtk::POS_RIGHT, 1, 1);
label = Gtk::manage(new Gtk::Label(M("MAIN_FRAME_FILEBROWSER") + " [" + Glib::ustring::format(std::fixed, std::setprecision(0), std::setw(3), (double)previewsLoaded / previewsToLoad * 100 ) + "%]" ));
filepanel->loadingThumbs("", (double)previewsLoaded / previewsToLoad);
}
if( options.mainNBVertical ) {
if (options.mainNBVertical) {
label->set_angle(90);
}
grid->attach_next_to(*label, options.mainNBVertical ? Gtk::POS_TOP : Gtk::POS_RIGHT, 1, 1);
grid->set_tooltip_markup (M("MAIN_FRAME_FILEBROWSER_TOOLTIP"));
grid->show_all ();
grid->set_tooltip_markup(M("MAIN_FRAME_FILEBROWSER_TOOLTIP"));
grid->show_all();
if (nb) {
nb->set_tab_label(*filepanel, *grid);
@ -1008,12 +1010,16 @@ void FileCatalog::copyMoveRequested(const std::vector<FileBrowserEntry*>& tbe, b
Gtk::FileChooserDialog fc (getToplevelWindow (this), fc_title, Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER );
fc.add_button( M("GENERAL_CANCEL"), Gtk::RESPONSE_CANCEL);
fc.add_button( M("GENERAL_OK"), Gtk::RESPONSE_OK);
// open dialog at the 1-st file's path
fc.set_filename(tbe[0]->filename);
if (!options.lastCopyMovePath.empty() && Glib::file_test(options.lastCopyMovePath, Glib::FILE_TEST_IS_DIR)) {
fc.set_current_folder(options.lastCopyMovePath);
} else {
// open dialog at the 1-st file's path
fc.set_current_folder(Glib::path_get_dirname(tbe[0]->filename));
}
//!!! TODO prevent dialog closing on "enter" key press
if( fc.run() == Gtk::RESPONSE_OK ) {
Glib::ustring dest_Dir = fc.get_current_folder();
options.lastCopyMovePath = fc.get_current_folder();
// iterate through selected files
for (unsigned int i = 0; i < tbe.size(); i++) {
@ -1030,10 +1036,10 @@ void FileCatalog::copyMoveRequested(const std::vector<FileBrowserEntry*>& tbe, b
Glib::ustring fname_Ext = getExtension(fname);
// construct destination File Paths
Glib::ustring dest_fPath = Glib::build_filename (dest_Dir, fname);
Glib::ustring dest_fPath = Glib::build_filename (options.lastCopyMovePath, fname);
Glib::ustring dest_fPath_param = dest_fPath + paramFileExtension;
if (moveRequested && (src_Dir == dest_Dir)) {
if (moveRequested && (src_Dir == options.lastCopyMovePath)) {
continue;
}
@ -1088,7 +1094,7 @@ void FileCatalog::copyMoveRequested(const std::vector<FileBrowserEntry*>& tbe, b
// adjust destination fname to avoid conflicts (append "_<index>", preserve extension)
Glib::ustring dest_fname = Glib::ustring::compose("%1%2%3%4%5", fname_noExt, "_", i_copyindex, ".", fname_Ext);
// re-construct destination File Paths
dest_fPath = Glib::build_filename (dest_Dir, dest_fname);
dest_fPath = Glib::build_filename (options.lastCopyMovePath, dest_fname);
dest_fPath_param = dest_fPath + paramFileExtension;
i_copyindex++;
}
@ -1680,47 +1686,46 @@ BENCHFUN
return;
}
if (!Glib::file_test (selectedDirectory, Glib::FILE_TEST_IS_DIR)) {
closeDir ();
if (!Glib::file_test(selectedDirectory, Glib::FILE_TEST_IS_DIR)) {
closeDir();
return;
}
std::vector<Glib::ustring> nfileNameList = getFileList ();
// check if a thumbnailed file has been deleted
const std::vector<ThumbBrowserEntryBase*>& t = fileBrowser->getEntries ();
const std::vector<ThumbBrowserEntryBase*>& t = fileBrowser->getEntries();
std::vector<Glib::ustring> fileNamesToDel;
for (size_t i = 0; i < t.size(); i++)
if (!Glib::file_test (t[i]->filename, Glib::FILE_TEST_EXISTS)) {
fileNamesToDel.push_back (t[i]->filename);
for (const auto& entry : t) {
if (!Glib::file_test(entry->filename, Glib::FILE_TEST_EXISTS)) {
fileNamesToDel.push_back(entry->filename);
}
for (size_t i = 0; i < fileNamesToDel.size(); i++) {
delete fileBrowser->delEntry (fileNamesToDel[i]);
cacheMgr->deleteEntry (fileNamesToDel[i]);
previewsLoaded--;
}
if (!fileNamesToDel.empty ()) {
for (const auto& toDelete : fileNamesToDel) {
delete fileBrowser->delEntry(toDelete);
cacheMgr->deleteEntry(toDelete);
--previewsLoaded;
}
if (!fileNamesToDel.empty()) {
_refreshProgressBar();
}
// check if a new file has been added
// build a set of collate-keys for faster search
std::set<std::string> oldNames;
for (size_t j = 0; j < fileNameList.size(); j++) {
oldNames.insert(fileNameList[j].collate_key());
for (const auto& oldName : fileNameList) {
oldNames.insert(oldName.collate_key());
}
for (size_t i = 0; i < nfileNameList.size(); i++) {
if (oldNames.count(nfileNameList[i].collate_key()) == 0) {
checkAndAddFile (Gio::File::create_for_parse_name(nfileNameList[i]));
_refreshProgressBar ();
fileNameList = getFileList();
for (const auto& newName : fileNameList) {
if (oldNames.find(newName.collate_key()) == oldNames.end()) {
addFile(newName);
_refreshProgressBar();
}
}
fileNameList = nfileNameList;
}
void FileCatalog::on_dir_changed (const Glib::RefPtr<Gio::File>& file, const Glib::RefPtr<Gio::File>& other_file, Gio::FileMonitorEvent event_type, bool internal)
@ -1737,85 +1742,55 @@ void FileCatalog::on_dir_changed (const Glib::RefPtr<Gio::File>& file, const Gli
}
}
void FileCatalog::checkAndAddFile (Glib::RefPtr<Gio::File> file)
void FileCatalog::addFile (const Glib::ustring& fName)
{
if (!file) {
return;
}
try {
const auto info = file->query_info("standard::*");
if (!info || info->get_file_type() == Gio::FILE_TYPE_DIRECTORY) {
return;
}
if (!options.fbShowHidden && info->is_hidden()) {
return;
}
Glib::ustring ext;
const auto lastdot = info->get_name().find_last_of('.');
if (lastdot != Glib::ustring::npos) {
ext = info->get_name().substr(lastdot + 1);
}
if (!options.is_extention_enabled(ext)) {
return;
}
previewLoader->add(selectedDirectoryId, file->get_parse_name(), this);
if (!fName.empty()) {
previewLoader->add(selectedDirectoryId, fName, this);
previewsToLoad++;
} catch(Gio::Error&) {}
}
}
void FileCatalog::addAndOpenFile (const Glib::ustring& fname)
{
auto file = Gio::File::create_for_path (fname);
auto file = Gio::File::create_for_path(fname);
if (!file ) {
return;
}
if (!file->query_exists ()) {
if (!file->query_exists()) {
return;
}
try {
auto info = file->query_info ();
const auto info = file->query_info();
if (!info) {
return;
}
Glib::ustring ext;
auto lastdot = info->get_name().find_last_of ('.');
const auto lastdot = info->get_name().find_last_of('.');
if (lastdot != Glib::ustring::npos) {
ext = info->get_name ().substr (lastdot + 1);
}
if (!options.is_extention_enabled(ext)) {
if (!options.is_extention_enabled(info->get_name().substr(lastdot + 1))) {
return;
}
} else {
return;
}
// if supported, load thumbnail first
const auto tmb = cacheMgr->getEntry (file->get_parse_name ());
const auto tmb = cacheMgr->getEntry(file->get_parse_name());
if (!tmb) {
return;
}
FileBrowserEntry* entry = new FileBrowserEntry (tmb, file->get_parse_name ());
previewReady (selectedDirectoryId, entry);
FileBrowserEntry* entry = new FileBrowserEntry(tmb, file->get_parse_name());
previewReady(selectedDirectoryId, entry);
// open the file
tmb->increaseRef ();
tmb->increaseRef();
idle_register.add(
[this, tmb]() -> bool
{
@ -1830,27 +1805,30 @@ void FileCatalog::addAndOpenFile (const Glib::ustring& fname)
void FileCatalog::emptyTrash ()
{
const std::vector<ThumbBrowserEntryBase*> t = fileBrowser->getEntries ();
const auto& t = fileBrowser->getEntries();
std::vector<FileBrowserEntry*> toDel;
for (size_t i = 0; i < t.size(); i++)
if ((static_cast<FileBrowserEntry*>(t[i]))->thumbnail->getStage() == 1) {
toDel.push_back (static_cast<FileBrowserEntry*>(t[i]));
for (const auto entry : t) {
if ((static_cast<FileBrowserEntry*>(entry))->thumbnail->getStage() == 1) {
toDel.push_back(static_cast<FileBrowserEntry*>(entry));
}
deleteRequested (toDel, false, false);
trashChanged();
}
if (toDel.size() > 0) {
deleteRequested(toDel, false, false);
trashChanged();
}
}
bool FileCatalog::trashIsEmpty ()
{
const std::vector<ThumbBrowserEntryBase*> t = fileBrowser->getEntries ();
for (size_t i = 0; i < t.size(); i++)
if ((static_cast<FileBrowserEntry*>(t[i]))->thumbnail->getStage() == 1) {
const auto& t = fileBrowser->getEntries();
for (const auto entry : t) {
if ((static_cast<FileBrowserEntry*>(entry))->thumbnail->getStage() == 1) {
return false;
}
}
return true;
}

View File

@ -141,7 +141,7 @@ private:
IdleRegister idle_register;
void addAndOpenFile (const Glib::ustring& fname);
void checkAndAddFile (Glib::RefPtr<Gio::File> info);
void addFile (const Glib::ustring& fName);
std::vector<Glib::ustring> getFileList ();
BrowserFilter getFilter ();
void trashChanged ();

View File

@ -369,6 +369,7 @@ void Options::setDefaults()
multiUser = true;
profilePath = "profiles";
loadSaveProfilePath = ""; // will be corrected in load as otherwise construction fails
lastCopyMovePath = "";
version = "0.0.0.0"; // temporary value; will be correctly set in RTWindow::on_realize
thumbSize = 160;
thumbSizeTab = 160;
@ -412,6 +413,7 @@ void Options::setDefaults()
favorites.clear();
parseExtensionsEnabled.clear();
parsedExtensions.clear();
parsedExtensionsSet.clear();
renameUseTemplates = false;
renameTemplates.clear();
thumbnailZoomRatios.clear();
@ -648,10 +650,12 @@ Options* Options::copyFrom(Options* other)
void Options::filterOutParsedExtensions()
{
parsedExtensions.clear();
parsedExtensionsSet.clear();
for (unsigned int i = 0; i < parseExtensions.size(); i++)
if (parseExtensionsEnabled[i]) {
parsedExtensions.push_back(parseExtensions[i].lowercase());
parsedExtensionsSet.emplace(parseExtensions[i].lowercase());
}
}
@ -1836,6 +1840,7 @@ void Options::readFromFile(Glib::ustring fname)
safeDirGet(keyFile, "Dialogs", "LastProfilingReferenceDir", lastProfilingReferenceDir);
safeDirGet(keyFile, "Dialogs", "LastLensProfileDir", lastLensProfileDir);
safeDirGet(keyFile, "Dialogs", "LastICCProfCreatorDir", lastICCProfCreatorDir);
safeDirGet(keyFile, "Dialogs", "LastCopyMovePath", lastCopyMovePath);
if (keyFile.has_key("Dialogs", "GimpPluginShowInfoDialog")) {
gimpPluginShowInfoDialog = keyFile.get_boolean("Dialogs", "GimpPluginShowInfoDialog");
@ -2229,6 +2234,7 @@ void Options::saveToFile(Glib::ustring fname)
keyFile.set_string("Dialogs", "LastProfilingReferenceDir", lastProfilingReferenceDir);
keyFile.set_string("Dialogs", "LastLensProfileDir", lastLensProfileDir);
keyFile.set_string("Dialogs", "LastICCProfCreatorDir", lastICCProfCreatorDir);
keyFile.set_string("Dialogs", "LastCopyMovePath", lastCopyMovePath);
keyFile.set_boolean("Dialogs", "GimpPluginShowInfoDialog", gimpPluginShowInfoDialog);
keyFile.set_string("Lensfun", "DBDirectory", rtSettings.lensfunDbDirectory);
@ -2464,36 +2470,17 @@ bool Options::is_parse_extention(Glib::ustring fname)
/*
* return true if fname ends with one of the retained image file extensions
*/
bool Options::has_retained_extention(Glib::ustring fname)
bool Options::has_retained_extention(const Glib::ustring& fname)
{
Glib::ustring ext = getExtension(fname).lowercase();
if (!ext.empty()) {
// there is an extension to the filename
// look out if it has one of the retained extensions
for (unsigned int i = 0; i < parsedExtensions.size(); i++) {
if (ext == parsedExtensions[i]) {
return true;
}
}
}
return false;
return parsedExtensionsSet.find(getExtension(fname).lowercase()) != parsedExtensionsSet.end();
}
/*
* return true if ext is an enabled extension
*/
bool Options::is_extention_enabled(Glib::ustring ext)
bool Options::is_extention_enabled(const Glib::ustring& ext)
{
for (int j = 0; j < (int)parseExtensions.size(); j++)
if (parseExtensions[j].casefold() == ext.casefold()) {
return j >= (int)parseExtensionsEnabled.size() || parseExtensionsEnabled[j];
}
return false;
return parsedExtensionsSet.find(ext.lowercase()) != parsedExtensionsSet.end();
}
Glib::ustring Options::getUserProfilePath()

View File

@ -19,6 +19,7 @@
#ifndef _OPTIONS_
#define _OPTIONS_
#include <set>
#include <gtkmm.h>
#include "../rtengine/rtengine.h"
#include <exception>
@ -174,6 +175,7 @@ public:
Glib::ustring startupPath;
Glib::ustring profilePath; // can be an absolute or relative path; depending on this value, bundled profiles may not be found
bool useBundledProfiles; // only used if multiUser == true
Glib::ustring lastCopyMovePath;
Glib::ustring loadSaveProfilePath;
Glib::ustring lastSaveAsPath;
int saveAsDialogWidth;
@ -259,6 +261,7 @@ public:
std::vector<Glib::ustring> parseExtensions; // List containing all extensions type
std::vector<int> parseExtensionsEnabled; // List of bool to retain extension or not
std::vector<Glib::ustring> parsedExtensions; // List containing all retained extensions (lowercase)
std::set<std::string> parsedExtensionsSet; // Set containing all retained extensions (lowercase)
std::vector<int> tpOpen;
bool autoSaveTpOpen;
//std::vector<int> crvOpen;
@ -422,8 +425,8 @@ public:
Glib::ustring getGlobalProfilePath();
Glib::ustring findProfilePath (Glib::ustring &profName);
bool is_parse_extention (Glib::ustring fname);
bool has_retained_extention (Glib::ustring fname);
bool is_extention_enabled (Glib::ustring ext);
bool has_retained_extention (const Glib::ustring& fname);
bool is_extention_enabled (const Glib::ustring& ext);
bool is_defProfRawMissing();
bool is_bundledDefProfRawMissing();
bool is_defProfImgMissing();