diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index 273abb65f..c9a2b395b 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -50,6 +50,7 @@ set(RTENGINESOURCEFILES dfmanager.cc diagonalcurves.cc dirpyr_equalizer.cc + dynamicprofile.cc expo_before_b.cc fast_demo.cc ffmanager.cc @@ -98,6 +99,7 @@ set(RTENGINESOURCEFILES previewimage.cc processingjob.cc procparams.cc + profilestore.cc rawimage.cc rawimagesource.cc refreshmap.cc diff --git a/rtgui/dynamicprofile.cc b/rtengine/dynamicprofile.cc similarity index 81% rename from rtgui/dynamicprofile.cc rename to rtengine/dynamicprofile.cc index 4439a1562..4ee76dda6 100644 --- a/rtgui/dynamicprofile.cc +++ b/rtengine/dynamicprofile.cc @@ -17,8 +17,8 @@ * along with RawTherapee. If not, see . */ -#include "dynamicprofile.h" -#include "profilestore.h" +#include "../rtengine/dynamicprofile.h" + #include #include @@ -36,6 +36,7 @@ const double EXPCOMP_MAX = 20.0; } // namespace +DynamicProfileRules dynamicProfileRules; bool DynamicProfileRule::Optional::operator()(const Glib::ustring &val) const { @@ -44,8 +45,7 @@ bool DynamicProfileRule::Optional::operator()(const Glib::ustring &val) const } if (value.find("re:") == 0) { // this is a regexp - return Glib::Regex::match_simple(value.substr(3), val, - Glib::REGEX_CASELESS); + return Glib::Regex::match_simple(value.substr(3), val, Glib::REGEX_CASELESS); } else { // normal string comparison return value.casefold() == val.casefold(); @@ -156,14 +156,12 @@ void set_optional(Glib::KeyFile &kf, const Glib::ustring &group, } // namespace - -bool loadDynamicProfileRules(std::vector &out) +bool DynamicProfileRules::loadRules() { - out.clear(); + dynamicRules.clear(); Glib::KeyFile kf; try { - if (!kf.load_from_file( - Glib::build_filename(Options::rtdir, "dynamicprofile.cfg"))) { + if (!kf.load_from_file(Glib::build_filename(Options::rtdir, "dynamicprofile.cfg"))) { return false; } } catch (Glib::Error &e) { @@ -186,9 +184,9 @@ bool loadDynamicProfileRules(std::vector &out) if (options.rtSettings.verbose) { printf(" loading rule %d\n", serial); } - - out.emplace_back(DynamicProfileRule()); - DynamicProfileRule &rule = out.back(); + + dynamicRules.emplace_back(DynamicProfileRule()); + DynamicProfileRule &rule = dynamicRules.back(); rule.serial_number = serial; get_int_range(rule.iso, kf, group, "iso"); get_double_range(rule.fnumber, kf, group, "fnumber"); @@ -200,21 +198,21 @@ bool loadDynamicProfileRules(std::vector &out) try { rule.profilepath = kf.get_string(group, "profilepath"); } catch (Glib::KeyFileError &) { - out.pop_back(); + dynamicRules.pop_back(); } } - std::sort(out.begin(), out.end()); + std::sort(dynamicRules.begin(), dynamicRules.end()); + rulesLoaded = true; return true; } - -bool storeDynamicProfileRules(const std::vector &rules) +bool DynamicProfileRules::storeRules() { if (options.rtSettings.verbose) { printf("saving dynamic profiles...\n"); } Glib::KeyFile kf; - for (auto &rule : rules) { + for (auto &rule : dynamicRules) { std::ostringstream buf; buf << "rule " << rule.serial_number; Glib::ustring group = buf.str(); @@ -227,29 +225,15 @@ bool storeDynamicProfileRules(const std::vector &rules) set_optional(kf, group, "lens", rule.lens); kf.set_string(group, "profilepath", rule.profilepath); } - return kf.save_to_file( - Glib::build_filename(Options::rtdir, "dynamicprofile.cfg")); + return kf.save_to_file(Glib::build_filename(Options::rtdir, "dynamicprofile.cfg")); } - -PartialProfile *loadDynamicProfile(const ImageMetaData *im) +const std::vector &DynamicProfileRules::getRules() const { - PartialProfile *ret = new PartialProfile(true, true); - for (auto &rule : profileStore.getDynamicProfileRules()) { - if (rule.matches(im)) { - if (options.rtSettings.verbose) { - printf("found matching profile %s\n", - rule.profilepath.c_str()); - } - const PartialProfile *p = - profileStore.getProfile(rule.profilepath); - if (p != nullptr) { - p->applyTo(ret->pparams); - } else { - printf("ERROR loading matching profile from: %s\n", - rule.profilepath.c_str()); - } - } - } - return ret; + return dynamicRules; +} + +void DynamicProfileRules::setRules(const std::vector &r) +{ + dynamicRules = r; } diff --git a/rtgui/dynamicprofile.h b/rtengine/dynamicprofile.h similarity index 83% rename from rtgui/dynamicprofile.h rename to rtengine/dynamicprofile.h index 4c5e552e4..45c28f07c 100644 --- a/rtgui/dynamicprofile.h +++ b/rtengine/dynamicprofile.h @@ -21,8 +21,7 @@ #include #include -#include "options.h" - +#include "../rtgui/options.h" class DynamicProfileRule { public: @@ -46,7 +45,7 @@ public: bool operator()(const Glib::ustring &val) const; }; - + DynamicProfileRule(); bool matches(const rtengine::ImageMetaData *im) const; bool operator<(const DynamicProfileRule &other) const; @@ -62,13 +61,17 @@ public: Glib::ustring profilepath; }; +class DynamicProfileRules { +protected: + /** cache for dynamic profile rules */ + std::vector dynamicRules; + bool rulesLoaded; -bool loadDynamicProfileRules(std::vector &out); -bool storeDynamicProfileRules( - const std::vector &rules); - -rtengine::procparams::PartialProfile *loadDynamicProfile( - const rtengine::ImageMetaData *im); - +public: + bool loadRules(); + bool storeRules(); + const std::vector &getRules() const; + void setRules(const std::vector &r); +}; #endif // _DYNAMICPROFILE_H_ diff --git a/rtengine/init.cc b/rtengine/init.cc index 4c66cea68..2d157c762 100644 --- a/rtengine/init.cc +++ b/rtengine/init.cc @@ -16,6 +16,7 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ +#include "../rtgui/profilestorecombobox.h" #include "rtengine.h" #include "iccstore.h" #include "dcp.h" @@ -27,7 +28,7 @@ #include "dfmanager.h" #include "ffmanager.h" #include "rtthumbnail.h" -#include "../rtgui/profilestore.h" +#include "profilestore.h" #include "../rtgui/threadutils.h" namespace rtengine @@ -40,6 +41,7 @@ MyMutex* lcmsMutex = nullptr; int init (const Settings* s, Glib::ustring baseDir, Glib::ustring userSettingsDir, bool loadAll) { settings = s; + ProfileStore::getInstance()->init (loadAll); ICCStore::getInstance()->init (s->iccDirectory, Glib::build_filename (baseDir, "iccprofiles"), loadAll); DCPStore::getInstance()->init (Glib::build_filename (baseDir, "dcpprofiles"), loadAll); diff --git a/rtgui/profilestore.cc b/rtengine/profilestore.cc similarity index 54% rename from rtgui/profilestore.cc rename to rtengine/profilestore.cc index d7bf18ab5..38619f0eb 100644 --- a/rtgui/profilestore.cc +++ b/rtengine/profilestore.cc @@ -17,49 +17,55 @@ * along with RawTherapee. If not, see . */ #include "profilestore.h" -#include "options.h" -#include "toolpanel.h" -#include "guiutils.h" -#include "dynamicprofile.h" -ProfileStore profileStore; +#include "dynamicprofile.h" +#include "../rtgui/options.h" +#include "../rtgui/multilangmgr.h" using namespace rtengine; using namespace rtengine::procparams; -ProfileStore::ProfileStore () : parseMutex(nullptr), storeState(STORESTATE_NOTINITIALIZED), internalDefaultProfile(nullptr), internalDefaultEntry(nullptr), internalDynamicEntry(nullptr), dynamicRules(new std::vector()) +ProfileStore::ProfileStore () : storeState(STORESTATE_NOTINITIALIZED), internalDefaultProfile(nullptr), internalDefaultEntry(nullptr), internalDynamicEntry(nullptr), loadAll(true) { internalDefaultProfile = new AutoPartialProfile(); internalDefaultProfile->set(true); } -bool ProfileStore::init () +ProfileStore* ProfileStore::getInstance() +{ + static ProfileStore instance; + return &instance; +} + + +bool ProfileStore::init (bool loadAll) { if (storeState == STORESTATE_DELETED) { return false; } - if (storeState == STORESTATE_NOTINITIALIZED) { + this->loadAll = loadAll; + + if (storeState == STORESTATE_NOTINITIALIZED && loadAll) { storeState = STORESTATE_BEINGINITIALIZED; - parseMutex = new MyMutex(); _parseProfiles (); - loadDynamicProfileRules(*dynamicRules); storeState = STORESTATE_INITIALIZED; } - return true; + return storeState == STORESTATE_INITIALIZED; } ProfileStore::~ProfileStore () { - if (storeState == STORESTATE_NOTINITIALIZED) { return; } // This lock prevent object's suppression while scanning the directories storeState = STORESTATE_DELETED; - MyMutex::MyLock lock(*parseMutex); + + { + MyMutex::MyLock lock(parseMutex); clearProfileList (); partProfiles.clear (); @@ -67,9 +73,7 @@ ProfileStore::~ProfileStore () delete internalDefaultProfile; delete internalDefaultEntry; delete internalDynamicEntry; - lock.release(); - delete parseMutex; - parseMutex = nullptr; + } } /* @@ -84,21 +88,11 @@ ProfileStore::~ProfileStore () void ProfileStore::parseProfiles () { - if (!init()) - // I don't even know if this situation can occur - { - return; - } - for (auto listener : listeners) { listener->storeCurrentValue(); } - { - MyMutex::MyLock lock(*parseMutex); - - _parseProfiles (); - } + init (true); // safe even if already initialized for (auto listener : listeners) { listener->updateProfileList(); @@ -108,10 +102,6 @@ void ProfileStore::parseProfiles () void ProfileStore::_parseProfiles () { - - // Acquire the GUI, since the tree model can interact with combobox - GThreadLock threadLock; - // clear loaded profiles folders.clear(); clearFileList(); @@ -170,7 +160,6 @@ void ProfileStore::_parseProfiles () /// @return Returns true if some files has been found (directories are ignored) bool ProfileStore::parseDir (Glib::ustring& realPath, Glib::ustring& virtualPath, Glib::ustring& currDir, unsigned int parentId, unsigned char level, bool displayLevel0) { - bool fileFound = false; // reload the available profiles from the profile dir @@ -260,6 +249,7 @@ bool ProfileStore::parseDir (Glib::ustring& realPath, Glib::ustring& virtualPath int ProfileStore::findFolderId(const Glib::ustring &path) { + // initialization must have been done when calling this for (std::vector::iterator i = folders.begin(); i != folders.end(); ++i) { if (*i == path) { return i - folders.begin(); @@ -281,6 +271,10 @@ const ProfileStoreEntry* ProfileStore::findEntryFromFullPathU(Glib::ustring path return nullptr; } + if (storeState == STORESTATE_NOTINITIALIZED) { + parseProfiles(); + } + if (path == DEFPROFILE_INTERNAL || path == DEFPROFILE_DYNAMIC) { return internalDefaultEntry; } @@ -324,9 +318,11 @@ const ProfileStoreEntry* ProfileStore::findEntryFromFullPathU(Glib::ustring path } // 2. find the entry that match the given filename and parentFolderId - for (auto entry : entries) { - if (entry->parentFolderId == parentFolderId && entry->label == fName) { - return entry; + if (parentFolderId >= 0) { + for (auto entry : entries) { + if (entry->parentFolderId == parentFolderId && entry->label == fName) { + return entry; + } } } @@ -336,17 +332,15 @@ const ProfileStoreEntry* ProfileStore::findEntryFromFullPathU(Glib::ustring path /** Protected version of findEntryFromFullPathU */ const ProfileStoreEntry* ProfileStore::findEntryFromFullPath(Glib::ustring path) { - MyMutex::MyLock lock(*parseMutex); + MyMutex::MyLock lock(parseMutex); return findEntryFromFullPathU(path); } const PartialProfile* ProfileStore::getProfile (Glib::ustring path) { - if (!init()) - // I don't even know if this situation can occur - { - return nullptr; + if (storeState == STORESTATE_NOTINITIALIZED) { + parseProfiles(); } const ProfileStoreEntry *pse = findEntryFromFullPath(path); @@ -361,13 +355,11 @@ const PartialProfile* ProfileStore::getProfile (Glib::ustring path) const PartialProfile* ProfileStore::getProfile (const ProfileStoreEntry* entry) { - if (!init()) - // I don't even know if this situation can occur - { - return nullptr; + if (storeState == STORESTATE_NOTINITIALIZED) { + parseProfiles(); } - MyMutex::MyLock lock(*parseMutex); + MyMutex::MyLock lock(parseMutex); if (entry == internalDefaultEntry) { return internalDefaultProfile; @@ -393,19 +385,19 @@ const PartialProfile* ProfileStore::getProfile (const ProfileStoreEntry* entry) */ const std::vector* ProfileStore::getFileList () { - /*if (!init()) { - // I don't even know if this situation can occur - return NULL; - }*/ - parseMutex->lock(); + if (storeState == STORESTATE_NOTINITIALIZED) { + parseProfiles(); + } + + parseMutex.lock(); return &entries; } void ProfileStore::releaseFileList() { - parseMutex->unlock(); + parseMutex.unlock(); } /* @@ -416,13 +408,8 @@ void ProfileStore::releaseFileList() const ProcParams* ProfileStore::getDefaultProcParams (bool isRaw) { - if (!init()) - // I don't even know if this situation can occur - { - return nullptr; - } - //Note: the mutex is locked in getProfile, called below + // eventual initialization is done there too const PartialProfile* pProf = getProfile (isRaw ? options.defProfRaw : options.defProfImg); @@ -441,13 +428,8 @@ const ProcParams* ProfileStore::getDefaultProcParams (bool isRaw) const PartialProfile* ProfileStore::getDefaultPartialProfile (bool isRaw) { - if (!init()) - // I don't even know if this situation can occur - { - return nullptr; - } - //Note: the mutex is locked in getProfile, called below + // eventual initialization is done there too const PartialProfile* pProf = getProfile (isRaw ? options.defProfRaw : options.defProfImg); @@ -460,6 +442,7 @@ const PartialProfile* ProfileStore::getDefaultPartialProfile (bool isRaw) const Glib::ustring ProfileStore::getPathFromId(int folderId) { + // initialization must have been done when calling this return folders.at(folderId); } @@ -507,20 +490,34 @@ void ProfileStore::dumpFolderList() printf("\n"); } - -const std::vector &ProfileStore::getDynamicProfileRules() const +PartialProfile *ProfileStore::loadDynamicProfile(const ImageMetaData *im) { - return *dynamicRules; + if (storeState == STORESTATE_NOTINITIALIZED) { + parseProfiles(); + } + + PartialProfile *ret = new PartialProfile(true, true); + + if (!rulesLoaded) { + loadRules(); + } + + for (auto rule : dynamicRules) { + if (rule.matches(im)) { + if (options.rtSettings.verbose) { + printf("found matching profile %s\n", rule.profilepath.c_str()); + } + const PartialProfile *p = getProfile(rule.profilepath); + if (p != nullptr) { + p->applyTo(ret->pparams); + } else { + printf("ERROR loading matching profile from: %s\n", rule.profilepath.c_str()); + } + } + } + return ret; } - -void ProfileStore::setDynamicProfileRules(const std::vector &r) -{ - *dynamicRules = r; -} - - - ProfileStoreEntry::ProfileStoreEntry() : label(""), type(PSET_FOLDER), parentFolderId(0), folderId(0) {} ProfileStoreEntry::ProfileStoreEntry(Glib::ustring label, PSEType type, unsigned short parentFolder, unsigned short folder) : label(label), type(type), parentFolderId(parentFolder), folderId(folder) {} @@ -533,330 +530,3 @@ void ProfileStoreEntry::setValues(Glib::ustring label, PSEType type, unsigned sh folderId = folder; } -ProfileStoreLabel::ProfileStoreLabel(const ProfileStoreEntry *entry) : Gtk::Label(entry->label), entry(entry) -{ - set_alignment(0, 0.5); - set_ellipsize(Pango::ELLIPSIZE_END); - show(); -} - -ProfileStoreComboBox::ProfileStoreComboBox () -{ - updateProfileList(); - setPreferredWidth(50, 120); -} - -Glib::ustring ProfileStoreComboBox::getCurrentLabel() -{ - Glib::ustring currLabel; - Gtk::TreeModel::iterator currRow = get_active(); - - if (currRow) { - const ProfileStoreEntry *currEntry = (*currRow)[methodColumns.profileStoreEntry]; - return currEntry->label; - } - - return currLabel; -} - -const ProfileStoreEntry* ProfileStoreComboBox::getSelectedEntry() -{ - Gtk::TreeModel::iterator currRow_ = get_active(); - Gtk::TreeModel::Row currRow = *currRow_; - - if (currRow) { - return currRow[methodColumns.profileStoreEntry]; - } else { - return nullptr; - } -} - -/** @brief Recursive method to update the combobox entries */ -void ProfileStoreComboBox::refreshProfileList_ (Gtk::TreeModel::Row *parentRow, int parentFolderId, bool initial, const std::vector *entryList) -{ - for (auto entry : *entryList) { - if (entry->parentFolderId == parentFolderId) { // filtering the entry of the same folder - if (entry->type == PSET_FOLDER) { - Glib::ustring folderPath( profileStore.getPathFromId(entry->folderId) ); - - if (options.useBundledProfiles || ((folderPath != "${G}" ) && (folderPath != "${U}" ))) { - // creating the new submenu - Gtk::TreeModel::Row newSubMenu; - - if (initial) { - newSubMenu = *(refTreeModel->append()); - } else { - newSubMenu = *(refTreeModel->append(parentRow->children())); - } - - // creating and assigning the custom Label object - newSubMenu[methodColumns.label] = entry->label; - newSubMenu[methodColumns.profileStoreEntry] = entry; -#if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION == 18 - // HACK: Workaround for bug in Gtk+ 3.18... - Gtk::TreeModel::Row menuHeader = *(refTreeModel->append(newSubMenu->children())); - menuHeader[methodColumns.label] = "-"; - menuHeader[methodColumns.profileStoreEntry] = entry; -#endif - refreshProfileList_ (&newSubMenu, entry->folderId, false, entryList); - } else { - refreshProfileList_ (parentRow, entry->folderId, true, entryList); - } - } else { - Gtk::TreeModel::Row newItem; - - // creating a menu entry - if (initial) { - newItem = *(refTreeModel->append()); - } else { - newItem = *(refTreeModel->append(parentRow->children())); - } - - newItem[methodColumns.label] = entry->label; - newItem[methodColumns.profileStoreEntry] = entry; - } - } - } -} -/** @brief Get the ProfileStore's entry list and recreate the combobox entries. - * If you want to update the ProfileStore list itself (rescan the dir tree), use the "ProfileStore::parseProfiles" method instead - * - * This method has to be called by the ProfileStoreListener having a ProfileStoreComboBox. - */ -void ProfileStoreComboBox::updateProfileList () -{ - // clear items - clear(); - refTreeModel.clear(); - // Create the Tree model - refTreeModel = Gtk::TreeStore::create(methodColumns); - // Assign the model to the Combobox - set_model(refTreeModel); - - // this will lock the profilestore's entry list too - const std::vector *entryList = profileStore.getFileList(); - - //profileStore.dumpFolderList(); - refreshProfileList_ (NULL, entryList->at(0)->parentFolderId, true, entryList); - - if (entryList->at(0)->parentFolderId != 0) { - // special case for the Internal default entry - addRow(profileStore.getInternalDefaultPSE()); - } - - // releasing the profilestore's entry list mutex - profileStore.releaseFileList(); - - pack_start(methodColumns.label, false); - - Gtk::CellRendererText* cellRenderer = dynamic_cast(get_first_cell()); - cellRenderer->property_ellipsize() = Pango::ELLIPSIZE_MIDDLE; - cellRenderer->property_ellipsize_set() = true; -} - -Gtk::TreeIter ProfileStoreComboBox::findRowFromEntry_ (Gtk::TreeModel::Children childs, const ProfileStoreEntry *pse) -{ - Gtk::TreeModel::Row row; - Gtk::TreeIter rowInSubLevel; - - for(Gtk::TreeModel::Children::iterator iter = childs.begin(); iter != childs.end(); ++iter) { - row = *iter; - // Hombre: is there a smarter way of knowing if this row has childs? - const ProfileStoreEntry *pse_ = row[methodColumns.profileStoreEntry]; - - if (pse_->type == PSET_FOLDER) { - rowInSubLevel = findRowFromEntry_ (iter->children(), pse); - - if (rowInSubLevel) { - // entry found - return rowInSubLevel; - } - } else if (pse_ == pse) { - // entry found - return iter; - } - } - - return childs.end(); -} - -Gtk::TreeIter ProfileStoreComboBox::findRowFromEntry (const ProfileStoreEntry *pse) -{ - Gtk::TreeModel::Children childs = refTreeModel->children(); - - if (pse) { - Gtk::TreeIter row = findRowFromEntry_ (childs, pse); - return row; - } - - return childs.end(); -} - -Gtk::TreeIter ProfileStoreComboBox::findRowFromFullPath_ (Gtk::TreeModel::Children childs, int parentFolderId, Glib::ustring &name) -{ - Gtk::TreeModel::Row row; - Gtk::TreeIter rowInSubLevel; - - for(Gtk::TreeModel::Children::iterator iter = childs.begin(); iter != childs.end(); ++iter) { - row = *iter; - // Hombre: is there a smarter way of knowing if this row has childs? - const ProfileStoreEntry *pse = row[methodColumns.profileStoreEntry]; - - if (pse->type == PSET_FOLDER) { - rowInSubLevel = findRowFromFullPath_ (iter->children(), parentFolderId, name); - - if (rowInSubLevel) { - // entry found - return rowInSubLevel; - } - } else if (parentFolderId == pse->parentFolderId && name == pse->label) { - // entry found - return iter; - } - } - - return childs.end(); -} - -Gtk::TreeIter ProfileStoreComboBox::findRowFromFullPath (Glib::ustring path) -{ - Gtk::TreeIter row; - - if (path.empty()) { - return row; - } - - if (path == DEFPROFILE_INTERNAL) { - row = findRowFromEntry(profileStore.getInternalDefaultPSE()); - return row; - } - - if (path == DEFPROFILE_DYNAMIC) { - row = findRowFromEntry(profileStore.getInternalDynamicPSE()); - return row; - } - - // removing the filename - Glib::ustring fName = Glib::path_get_basename(path); - - if (!fName.empty()) { - path = path.substr(0, path.length() - fName.length()); - } else { - // path is malformed; - return row; - } - - path = Glib::path_get_dirname(path); - int parentFolderId = profileStore.findFolderId(path); - - // 1. find the path in the folder list - if (parentFolderId != -1) { - row = findRowFromFullPath_ (refTreeModel->children(), parentFolderId, fName); - } - - return row; -} - -/** @brief Get the absolute full path of the active row entry. - * @return The absolute full path of the active row entry, or the "Internal" keyword, - * or an empty string if the ComboBox is in an invalid state - */ -Glib::ustring ProfileStoreComboBox::getFullPathFromActiveRow() -{ - Glib::ustring path; - Gtk::TreeModel::iterator currRowI = get_active(); - - if (!currRowI) { - return path; - } - - Gtk::TreeModel::Row currRow = *currRowI; - - if (currRow) { - - const ProfileStoreEntry *currEntry = currRow[methodColumns.profileStoreEntry]; - - if (!currEntry) { - return path; - } - - if (currEntry == profileStore.getInternalDefaultPSE()) { - return Glib::ustring(DEFPROFILE_INTERNAL); - } - - if (currEntry == profileStore.getInternalDynamicPSE()) { - return Glib::ustring(DEFPROFILE_DYNAMIC); - } - - path = Glib::build_filename(profileStore.getPathFromId(currEntry->parentFolderId), currEntry->label); - } - - return path; -} - -bool ProfileStoreComboBox::setActiveRowFromFullPath(Glib::ustring path) -{ - if (!path.empty()) { - Gtk::TreeIter row = findRowFromFullPath(path); - - if (row) { - set_active(row); - return true; - } - } - - return false; -} - -bool ProfileStoreComboBox::setActiveRowFromEntry(const ProfileStoreEntry *pse) -{ - if (pse) { - Gtk::TreeIter row = findRowFromEntry(pse); - - if (row) { - set_active(row); - return true; - } - } - - return false; -} - -bool ProfileStoreComboBox::setInternalEntry () -{ - return setActiveRowFromEntry(profileStore.getInternalDefaultPSE()); -} - -/** @brief Get the row from the first level of the tree that match the provided name */ -Gtk::TreeIter ProfileStoreComboBox::getRowFromLabel(Glib::ustring name) -{ - Gtk::TreeIter row; - Gtk::TreeModel::Children childs = refTreeModel->children(); - - if (!name.empty()) { - Gtk::TreeModel::Row currRow; - - for(Gtk::TreeModel::Children::iterator iter = childs.begin(); iter != childs.end(); ++iter) { - currRow = *iter; - const ProfileStoreEntry *pse = currRow[methodColumns.profileStoreEntry]; - - if (pse->label == name) { - return currRow; - } - } - } - - return childs.end(); - //return refTreeModel->get_iter(""); // is this fast? We want to send back a null, anvalid or end() iterator object here -} - -/** @brief Add a new row to the first level of the tree */ -Gtk::TreeIter ProfileStoreComboBox::addRow(const ProfileStoreEntry *profileStoreEntry) -{ - Gtk::TreeIter newEntry = refTreeModel->append(); - Gtk::TreeModel::Row row = *newEntry; - row[methodColumns.label] = profileStoreEntry->label; - row[methodColumns.profileStoreEntry] = profileStoreEntry; - return newEntry; -} - diff --git a/rtgui/profilestore.h b/rtengine/profilestore.h similarity index 73% rename from rtgui/profilestore.h rename to rtengine/profilestore.h index ad569c180..8ca5bf42a 100644 --- a/rtgui/profilestore.h +++ b/rtengine/profilestore.h @@ -23,16 +23,14 @@ #include #include -#include "../rtengine/rtengine.h" -#include "../rtengine/noncopyable.h" - -#include "threadutils.h" -#include "paramsedited.h" -#include "guiutils.h" +#include "rtengine.h" +#include "noncopyable.h" +#include "dynamicprofile.h" // forward decl class DynamicProfileRule; +class DynamicProfileRules; /** @brief This will implement callback functions for the ProfileStore * @@ -95,41 +93,17 @@ public: }; -/** - * @brief subclass of Gtk::Label with extra fields for Combobox and Menu, to link with a ProfileStoreEntry - */ -class ProfileStoreLabel : public Gtk::Label -{ - -public: - const ProfileStoreEntry *entry; - -#ifndef NDEBUG - ProfileStoreLabel() : Gtk::Label("*** error ***"), entry(nullptr) {} -#else - ProfileStoreLabel() : Gtk::Label(""), entry(NULL) {} -#endif - - /** @brief Create a new ProfileStoreLabel - * - * @param entry Pointer to the ProfileStoreEntry object, be it a directory or a file - */ - explicit ProfileStoreLabel(const ProfileStoreEntry *entry); - ProfileStoreLabel (const ProfileStoreLabel &other); -}; - - /** @brief Store the profiles bundled with RawTharapee and created by the user. * * This store can be queried by the GUI to display a Tree of the profiles available * in the user's and system's profile directory and subdirectories. */ -class ProfileStore : - public rtengine::NonCopyable +class ProfileStore : public rtengine::NonCopyable, public DynamicProfileRules { typedef enum { STORESTATE_NOTINITIALIZED, + STORESTATE_LIGHTWEIGHT, STORESTATE_BEINGINITIALIZED, STORESTATE_INITIALIZED, STORESTATE_DELETED @@ -143,7 +117,7 @@ private: } }; - MyMutex *parseMutex; + MyMutex parseMutex; StoreState storeState; rtengine::procparams::AutoPartialProfile *internalDefaultProfile; ProfileStoreEntry *internalDefaultEntry; @@ -164,8 +138,8 @@ private: /** List of the client of this store */ std::list listeners; - /** cache for dynamic profile rules */ - std::unique_ptr> dynamicRules; + /** whereas we have to load all profile at init time or one by one upon request */ + bool loadAll; /** @brief Method to recursively parse a profile folder with a level depth arbitrarily limited to 3 * @@ -189,7 +163,9 @@ public: ProfileStore(); ~ProfileStore(); - bool init (); + static ProfileStore* getInstance(); + + bool init (bool loadAll = true); void parseProfiles (); int findFolderId(const Glib::ustring &path); const ProfileStoreEntry* findEntryFromFullPath(Glib::ustring path); @@ -210,53 +186,12 @@ public: return internalDynamicEntry; } - const std::vector &getDynamicProfileRules() const; - void setDynamicProfileRules(const std::vector &r); - void addListener(ProfileStoreListener *listener); void removeListener(ProfileStoreListener *listener); + rtengine::procparams::PartialProfile* loadDynamicProfile(const rtengine::ImageMetaData *im); + void dumpFolderList(); - }; -class ProfileStoreComboBox : public MyComboBox -{ - -protected: - class MethodColumns : public Gtk::TreeModel::ColumnRecord - { - public: - Gtk::TreeModelColumn label; - Gtk::TreeModelColumn profileStoreEntry; - MethodColumns() - { - add(label); - add(profileStoreEntry); - } - }; - - Glib::RefPtr refTreeModel; - MethodColumns methodColumns; - void refreshProfileList_ (Gtk::TreeModel::Row *parentRow, int parentFolderId, bool initial, const std::vector *entryList); - Gtk::TreeIter findRowFromEntry_ (Gtk::TreeModel::Children childs, const ProfileStoreEntry *pse); - Gtk::TreeIter findRowFromFullPath_(Gtk::TreeModel::Children childs, int parentFolderId, Glib::ustring &name); - -public: - ProfileStoreComboBox(); - void updateProfileList(); - Glib::ustring getCurrentLabel(); - const ProfileStoreEntry* getSelectedEntry(); - Gtk::TreeIter findRowFromEntry (const ProfileStoreEntry *pse); - Gtk::TreeIter findRowFromFullPath (Glib::ustring path); - Glib::ustring getFullPathFromActiveRow (); - bool setActiveRowFromFullPath (Glib::ustring oldPath); - bool setActiveRowFromEntry (const ProfileStoreEntry *pse); - bool setInternalEntry (); - Gtk::TreeIter getRowFromLabel(Glib::ustring name); - Gtk::TreeIter addRow(const ProfileStoreEntry *profileStoreEntry); -}; - -extern ProfileStore profileStore; - #endif diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index 300491e85..c317f8525 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -46,7 +46,6 @@ set(NONCLISOURCEFILES dirpyrdenoise.cc dirpyrequalizer.cc distortion.cc - dynamicprofile.cc dynamicprofilepanel.cc edit.cc editorpanel.cc @@ -107,7 +106,7 @@ set(NONCLISOURCEFILES previewmodepanel.cc previewwindow.cc profilepanel.cc - profilestore.cc + profilestorecombobox.cc prsharpening.cc rawcacorrection.cc rawexposure.cc @@ -219,15 +218,15 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" "${CMAKE_CURRENT_BINARY # Create new executables targets add_executable(rth ${EXTRA_SRC_NONCLI} ${NONCLISOURCEFILES}) -#add_executable(rth-cli ${EXTRA_SRC_CLI} ${CLISOURCEFILES}) +add_executable(rth-cli ${EXTRA_SRC_CLI} ${CLISOURCEFILES}) # Add dependencies to executables targets add_dependencies(rth UpdateInfo) -#add_dependencies(rth-cli UpdateInfo) +add_dependencies(rth-cli UpdateInfo) # Set executables targets properties, i.e. output filename and compile flags set_target_properties(rth PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS}" OUTPUT_NAME rawtherapee) -#set_target_properties(rth-cli PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS}" OUTPUT_NAME rawtherapee-cli) +set_target_properties(rth-cli PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS}" OUTPUT_NAME rawtherapee-cli) # Add linked libraries dependencies to executables targets target_link_libraries(rth rtengine @@ -251,25 +250,25 @@ target_link_libraries(rth rtengine ${ZLIB_LIBRARIES} ) -#target_link_libraries(rth-cli rtengine -# ${CAIROMM_LIBRARIES} -# ${EXPAT_LIBRARIES} -# ${EXTRA_LIB_RTGUI} -# ${FFTW3F_LIBRARIES} -# ${GIOMM_LIBRARIES} -# ${GIO_LIBRARIES} -# ${GLIB2_LIBRARIES} -# ${GLIBMM_LIBRARIES} -# ${GOBJECT_LIBRARIES} -# ${GTHREAD_LIBRARIES} -# ${IPTCDATA_LIBRARIES} -# ${JPEG_LIBRARIES} -# ${LCMS_LIBRARIES} -# ${PNG_LIBRARIES} -# ${TIFF_LIBRARIES} -# ${ZLIB_LIBRARIES} -# ) +target_link_libraries(rth-cli rtengine + ${CAIROMM_LIBRARIES} + ${EXPAT_LIBRARIES} + ${EXTRA_LIB_RTGUI} + ${FFTW3F_LIBRARIES} + ${GIOMM_LIBRARIES} + ${GIO_LIBRARIES} + ${GLIB2_LIBRARIES} + ${GLIBMM_LIBRARIES} + ${GOBJECT_LIBRARIES} + ${GTHREAD_LIBRARIES} + ${IPTCDATA_LIBRARIES} + ${JPEG_LIBRARIES} + ${LCMS_LIBRARIES} + ${PNG_LIBRARIES} + ${TIFF_LIBRARIES} + ${ZLIB_LIBRARIES} + ) # Install executables install(TARGETS rth DESTINATION ${BINDIR}) -#install(TARGETS rth-cli DESTINATION ${BINDIR}) +install(TARGETS rth-cli DESTINATION ${BINDIR}) diff --git a/rtgui/dynamicprofilepanel.cc b/rtgui/dynamicprofilepanel.cc index 172c06f47..eca96ece6 100644 --- a/rtgui/dynamicprofilepanel.cc +++ b/rtgui/dynamicprofilepanel.cc @@ -19,8 +19,9 @@ #include "dynamicprofilepanel.h" #include "multilangmgr.h" -#include "profilestore.h" +#include "../rtengine/profilestore.h" #include "../rtengine/rtengine.h" +#include "../rtengine/dynamicprofile.h" #include #include @@ -297,7 +298,7 @@ DynamicProfilePanel::DynamicProfilePanel(): show_all_children(); - for (auto &r : profileStore.getDynamicProfileRules()) { + for (auto &r : ProfileStore::getInstance()->getRules()) { add_rule(r); } } @@ -346,7 +347,7 @@ void DynamicProfilePanel::render_profilepath( auto row = *iter; Gtk::CellRendererText *ct = static_cast(cell); auto value = row[columns_.profilepath]; - auto pse = profileStore.findEntryFromFullPath(value); + auto pse = ProfileStore::getInstance()->findEntryFromFullPath(value); if (pse != nullptr) { ct->property_text() = pse->label; } else { @@ -521,12 +522,12 @@ void DynamicProfilePanel::save() for (auto row : treemodel_->children()) { rules.emplace_back(to_rule(row, serial++)); } - if (!storeDynamicProfileRules(rules)) { + + ProfileStore::getInstance()->setRules(rules); + + if (!ProfileStore::getInstance()->storeRules()) { printf("Error in saving dynamic profile rules\n"); - } else { - profileStore.setDynamicProfileRules(rules); - if (options.rtSettings.verbose) { - printf("Saved %d dynamic profile rules\n", int(rules.size())); - } + } else if (options.rtSettings.verbose) { + printf("Saved %d dynamic profile rules\n", int(rules.size())); } } diff --git a/rtgui/dynamicprofilepanel.h b/rtgui/dynamicprofilepanel.h index 72ff95b9a..629c5d9d4 100644 --- a/rtgui/dynamicprofilepanel.h +++ b/rtgui/dynamicprofilepanel.h @@ -20,8 +20,8 @@ #define _DYNAMICPROFILEPANEL_H_ #include -#include "dynamicprofile.h" -#include "profilestore.h" +#include "../rtengine/dynamicprofile.h" +#include "profilestorecombobox.h" class DynamicProfilePanel: public Gtk::VBox { public: diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index d96a89d09..dd37a740b 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -134,7 +134,7 @@ FileBrowser::FileBrowser () fbih->destroyed = false; fbih->pending = 0; - profileStore.addListener(this); + ProfileStore::getInstance()->addListener(this); int p = 0; pmenu = new Gtk::Menu (); @@ -457,7 +457,7 @@ FileBrowser::~FileBrowser () { idle_register.destroy(); - profileStore.removeListener(this); + ProfileStore::getInstance()->removeListener(this); delete pmenu; delete pmenuColorLabels; delete[] amiExtProg; @@ -1346,7 +1346,7 @@ void FileBrowser::applyMenuItemActivated (ProfileStoreLabel *label) { MYREADERLOCK(l, entryRW); - const rtengine::procparams::PartialProfile* partProfile = profileStore.getProfile (label->entry); + const rtengine::procparams::PartialProfile* partProfile = ProfileStore::getInstance()->getProfile (label->entry); if (partProfile->pparams && !selected.empty()) { if (bppcl) { @@ -1376,7 +1376,7 @@ void FileBrowser::applyPartialMenuItemActivated (ProfileStoreLabel *label) } } - const rtengine::procparams::PartialProfile* srcProfiles = profileStore.getProfile (label->entry); + const rtengine::procparams::PartialProfile* srcProfiles = ProfileStore::getInstance()->getProfile (label->entry); if (srcProfiles->pparams) { @@ -1982,7 +1982,7 @@ void FileBrowser::updateProfileList () // submenu applmenu int p = 0; - const std::vector *profEntries = profileStore.getFileList(); // lock and get a pointer to the profiles' list + const std::vector *profEntries = ProfileStore::getInstance()->getFileList(); // lock and get a pointer to the profiles' list std::map subMenuList; // store the Gtk::Menu that Gtk::MenuItem will have to be attached to @@ -2067,7 +2067,7 @@ void FileBrowser::updateProfileList () applypartprof->set_submenu (*(subMenuList.at(0))); } - profileStore.releaseFileList(); + ProfileStore::getInstance()->releaseFileList(); subMenuList.clear(); } diff --git a/rtgui/filebrowser.h b/rtgui/filebrowser.h index faede2d8c..4bad832eb 100644 --- a/rtgui/filebrowser.h +++ b/rtgui/filebrowser.h @@ -29,7 +29,7 @@ #include "partialpastedlg.h" #include "exportpanel.h" #include "extprog.h" -#include "profilestore.h" +#include "profilestorecombobox.h" class ProfileStoreLabel; class FileBrowser; diff --git a/rtgui/main-cli.cc b/rtgui/main-cli.cc index 3a601e18e..e59ebaf09 100644 --- a/rtgui/main-cli.cc +++ b/rtgui/main-cli.cc @@ -49,6 +49,9 @@ #include "conio.h" #endif +// Set this to 1 to make RT work when started with Eclipse and arguments, at least on Windows platform +#define ECLIPSE_ARGS 0 + extern Options options; // stores path to data files @@ -175,7 +178,11 @@ int main(int argc, char **argv) SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); if (argc > 1 || options.rtSettings.verbose) { - if (options.rtSettings.verbose || ( !Glib::file_test (fname_to_utf8 (argv[1]), Glib::FILE_TEST_EXISTS ) && !Glib::file_test (fname_to_utf8 (argv[1]), Glib::FILE_TEST_IS_DIR))) { + Glib::ustring fname(fname_to_utf8 (argv[1])); +#if ECLIPSE_ARGS + fname = fname.substr(1, fname.length()-2); +#endif + if (options.rtSettings.verbose || ( !Glib::file_test (fname, Glib::FILE_TEST_EXISTS ) && !Glib::file_test (fname, Glib::FILE_TEST_IS_DIR))) { bool stdoutRedirectedtoFile = (GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)) == 0x0001); bool stderrRedirectedtoFile = (GetFileType(GetStdHandle(STD_ERROR_HANDLE)) == 0x0001); @@ -268,8 +275,12 @@ void deleteProcParams(std::vector &pparam bool dontLoadCache( int argc, char **argv ) { - for( int iArg = 1; iArg < argc; iArg++) { - if( argv[iArg][0] == '-' && argv[iArg][1] == 'q' ) { + for (int iArg = 1; iArg < argc; iArg++) { + Glib::ustring currParam(argv[iArg]); +#if ECLIPSE_ARGS + currParam = currParam.substr(1, currParam.length()-2); +#endif + if( currParam.at(0) == '-' && currParam.at(1) == 'q' ) { return true; } } @@ -297,16 +308,22 @@ int processLineParams( int argc, char **argv ) unsigned errors = 0; for( int iArg = 1; iArg < argc; iArg++) { - if( argv[iArg][0] == '-' ) { - switch( argv[iArg][1] ) { + Glib::ustring currParam(argv[iArg]); +#if ECLIPSE_ARGS + currParam = currParam.substr(1, currParam.length()-2); +#endif + if( currParam.at(0) == '-' ) { + switch( currParam.at(1) ) { case 'O': copyParamsFile = true; case 'o': // outputfile or dir if( iArg + 1 < argc ) { iArg++; - outputPath = fname_to_utf8 (argv[iArg]); - + outputPath = Glib::ustring(fname_to_utf8(argv[iArg])); +#if ECLIPSE_ARGS + outputPath = outputPath.substr(1, outputPath.length()-2); +#endif if( Glib::file_test (outputPath, Glib::FILE_TEST_IS_DIR)) { outputDirectory = true; } @@ -319,7 +336,10 @@ int processLineParams( int argc, char **argv ) // RT stop if any of them can't be loaded for any reason. if( iArg + 1 < argc ) { iArg++; - Glib::ustring fname = fname_to_utf8 (argv[iArg]); + Glib::ustring fname(fname_to_utf8(argv[iArg])); +#if ECLIPSE_ARGS + fname = fname.substr(1, fname.length()-2); +#endif if (fname.at(0) == '-') { std::cerr << "Error: filename missing next to the -p switch" << std::endl; @@ -360,15 +380,15 @@ int processLineParams( int argc, char **argv ) break; case 'j': - if (strlen(argv[iArg]) > 2 && argv[iArg][2] == 's') { - if (strlen(argv[iArg]) == 3) { + if (currParam.length() > 2 && currParam.at(2) == 's') { + if (currParam.length() == 3) { std::cerr << "Error: the -js switch requires a mandatory value!" << std::endl; deleteProcParams(processingParams); return -3; } // looking for the subsampling parameter - sscanf(&argv[iArg][3], "%d", &subsampling); + subsampling = atoi(currParam.substr(3).c_str()); if (subsampling < 1 || subsampling > 3) { std::cerr << "Error: the value accompanying the -js switch has to be in the [1-3] range!" << std::endl; @@ -377,7 +397,7 @@ int processLineParams( int argc, char **argv ) } } else { outputType = "jpg"; - sscanf(&argv[iArg][2], "%d", &compression); + compression = atoi(currParam.substr(2).c_str()); if (compression < 0 || compression > 100) { std::cerr << "Error: the value accompanying the -j switch has to be in the [0-100] range!" << std::endl; @@ -389,7 +409,7 @@ int processLineParams( int argc, char **argv ) break; case 'b': - sscanf(&argv[iArg][2], "%d", &bits); + bits = atoi(currParam.substr(2).c_str()); if (bits != 8 && bits != 16) { std::cerr << "Error: specify -b8 for 8-bit or -b16 for 16-bit output." << std::endl; @@ -401,7 +421,7 @@ int processLineParams( int argc, char **argv ) case 't': outputType = "tif"; - compression = ((argv[iArg][2] != 'z') ? 0 : 1); + compression = ((currParam.at(2) != 'z') ? 0 : 1); break; case 'n': @@ -416,8 +436,10 @@ int processLineParams( int argc, char **argv ) case 'c': // MUST be last option while (iArg + 1 < argc) { iArg++; - - const auto argument = fname_to_utf8 (argv[iArg]); + Glib::ustring argument(fname_to_utf8(argv[iArg])); +#if ECLIPSE_ARGS + argument = argument.substr(1, argument.length()-2); +#endif if (Glib::file_test (argument, Glib::FILE_TEST_IS_REGULAR)) { inputFiles.emplace_back (argument); @@ -546,7 +568,10 @@ int processLineParams( int argc, char **argv ) } } } else { - argv1 = fname_to_utf8 (argv[iArg]); + argv1 = Glib::ustring(fname_to_utf8(argv[iArg])); +#if ECLIPSE_ARGS + argv1 = argv1.substr(1, argv1.length()-2); +#endif if( outputDirectory ) { options.savePathFolder = outputPath; @@ -587,7 +612,7 @@ int processLineParams( int argc, char **argv ) rawParams = new rtengine::procparams::PartialProfile(true, true); Glib::ustring profPath = options.findProfilePath(options.defProfRaw); - if (options.is_defProfRawMissing() || profPath.empty() || (profPath != DEFPROFILE_DYNAMIC && rawParams->load(profPath == DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename(profPath, options.defProfRaw.substr(5) + paramFileExtension)))) { + if (options.is_defProfRawMissing() || profPath.empty() || (profPath != DEFPROFILE_DYNAMIC && rawParams->load(profPath == DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename(profPath, Glib::path_get_basename(options.defProfRaw) + paramFileExtension)))) { std::cerr << "Error: default raw processing profile not found" << std::endl; rawParams->deleteInstance(); delete rawParams; @@ -598,7 +623,7 @@ int processLineParams( int argc, char **argv ) imgParams = new rtengine::procparams::PartialProfile(true); profPath = options.findProfilePath(options.defProfImg); - if (options.is_defProfImgMissing() || profPath.empty() || (profPath != DEFPROFILE_DYNAMIC && imgParams->load(profPath == DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename(profPath, options.defProfImg.substr(5) + paramFileExtension)))) { + if (options.is_defProfImgMissing() || profPath.empty() || (profPath != DEFPROFILE_DYNAMIC && imgParams->load(profPath == DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename(profPath, Glib::path_get_basename(options.defProfImg) + paramFileExtension)))) { std::cerr << "Error: default non-raw processing profile not found" << std::endl; imgParams->deleteInstance(); delete imgParams; @@ -635,7 +660,7 @@ int processLineParams( int argc, char **argv ) } else if( outputDirectory ) { Glib::ustring s = Glib::path_get_basename( inputFile ); Glib::ustring::size_type ext = s.find_last_of('.'); - outputFile = outputPath + "/" + s.substr(0, ext) + "." + outputType; + outputFile = Glib::build_filename(outputPath, s.substr(0, ext) + "." + outputType); } else { Glib::ustring s = outputPath; Glib::ustring::size_type ext = s.find_last_of('.'); @@ -673,7 +698,7 @@ int processLineParams( int argc, char **argv ) if (options.defProfRaw == DEFPROFILE_DYNAMIC) { rawParams->deleteInstance(); delete rawParams; - rawParams = loadDynamicProfile(ii->getMetaData()); + rawParams = ProfileStore::getInstance()->loadDynamicProfile(ii->getMetaData()); } std::cout << " Merging default raw processing profile" << std::endl; rawParams->applyTo(¤tParams); @@ -681,7 +706,7 @@ int processLineParams( int argc, char **argv ) if (options.defProfImg == DEFPROFILE_DYNAMIC) { imgParams->deleteInstance(); delete imgParams; - imgParams = loadDynamicProfile(ii->getMetaData()); + imgParams = ProfileStore::getInstance()->loadDynamicProfile(ii->getMetaData()); } std::cout << " Merging default non-raw processing profile" << std::endl; imgParams->applyTo(¤tParams); diff --git a/rtgui/main.cc b/rtgui/main.cc index 88dc4ead4..495374f50 100644 --- a/rtgui/main.cc +++ b/rtgui/main.cc @@ -38,7 +38,7 @@ #include "rtimage.h" #include "version.h" #include "extprog.h" -#include "dynamicprofile.h" +#include "../rtengine/dynamicprofile.h" #ifndef WIN32 #include @@ -50,6 +50,9 @@ #include "conio.h" #endif +// Set this to 1 to make RT work when started with Eclipse and arguments, at least on Windows platform +#define ECLIPSE_ARGS 0 + extern Options options; // stores path to data files @@ -177,7 +180,6 @@ int main(int argc, char **argv) return -2; } - profileStore.init (); extProgStore->init(); SoundManager::init(); @@ -416,8 +418,12 @@ int processLineParams( int argc, char **argv ) unsigned errors = 0; for( int iArg = 1; iArg < argc; iArg++) { - if( argv[iArg][0] == '-' ) { - switch( argv[iArg][1] ) { + Glib::ustring currParam(argv[iArg]); +#if ECLIPSE_ARGS + currParam = currParam.substr(1, currParam.length()-2); +#endif + if( currParam.at(0) == '-' ) { + switch( currParam.at(1) ) { #ifdef WIN32 case 'w': // This case is handled outside this function @@ -437,9 +443,9 @@ int processLineParams( int argc, char **argv ) std::cout << std::endl; std::cout << "Symbols:" << std::endl; std::cout << " indicate parameters you can change." << std::endl; - std::cout << " [Square brackets] mean the parameter is optional." << std::endl; - std::cout << " The pipe symbol | indicates a choice of one or the other." << std::endl; - std::cout << " The dash symbol - denotes a range of possible values from one to the other." << std::endl; + //std::cout << " [Square brackets] mean the parameter is optional." << std::endl; + //std::cout << " The pipe symbol | indicates a choice of one or the other." << std::endl; + //std::cout << " The dash symbol - denotes a range of possible values from one to the other." << std::endl; std::cout << std::endl; std::cout << "Usage:" << std::endl; std::cout << " " << Glib::path_get_basename(argv[0]) << " Start File Browser inside folder." << std::endl; @@ -454,7 +460,10 @@ int processLineParams( int argc, char **argv ) } } } else { - argv1 = fname_to_utf8 (argv[iArg]); + argv1 = Glib::ustring(fname_to_utf8(argv[iArg])); +#if ECLIPSE_ARGS + argv1 = argv1.substr(1, argv1.length()-2); +#endif break; } } diff --git a/rtgui/options.cc b/rtgui/options.cc index 55b257ec8..daf11e62c 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -227,7 +227,7 @@ Glib::ustring Options::getPreferredProfilePath() /** @brief Get the absolute path of the given filename or the "Neutral" special value * *@param profName path + filename of the procparam to look for. A filename without path can be provided for backward compatibility. - * In this case, this parameter will be update with the new format. + * In this case, this parameter will be updated with the new format. *@return Send back the absolute path of the given filename or "Neutral" if "Neutral" has been set to profName. Implementor will have * to test for this particular value. If the absolute path is invalid (e.g. the file doesn't exist), it will return an empty string. */ diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 1acb7cfb4..12d6c2de7 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -100,7 +100,7 @@ Preferences::Preferences (RTWindow *rtwindow) #endif nb->set_current_page (0); - profileStore.addListener(this); + ProfileStore::getInstance()->addListener(this); fillPreferences (); @@ -111,7 +111,7 @@ Preferences::Preferences (RTWindow *rtwindow) Preferences::~Preferences () { - profileStore.removeListener(this); + ProfileStore::getInstance()->removeListener(this); get_size(options.preferencesWidth, options.preferencesHeight); } @@ -445,13 +445,14 @@ Gtk::Widget* Preferences::getProcParamsPanel () Gtk::VBox* vbpp = Gtk::manage (new Gtk::VBox ()); Gtk::Label* drlab = Gtk::manage (new Gtk::Label (M("PREFERENCES_FORRAW") + ":", Gtk::ALIGN_START)); rprofiles = Gtk::manage (new ProfileStoreComboBox ()); - rprofiles->addRow(profileStore.getInternalDynamicPSE()); + const ProfileStoreEntry* dynpse = ProfileStore::getInstance()->getInternalDynamicPSE(); + rprofiles->addRow(dynpse); setExpandAlignProperties(rprofiles, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); rprofiles->set_size_request(50, -1); rpconn = rprofiles->signal_changed().connect( sigc::mem_fun(*this, &Preferences::forRAWComboChanged) ); Gtk::Label* drimg = Gtk::manage (new Gtk::Label (M("PREFERENCES_FORIMAGE") + ":", Gtk::ALIGN_START)); iprofiles = Gtk::manage (new ProfileStoreComboBox ()); - iprofiles->addRow(profileStore.getInternalDynamicPSE()); + iprofiles->addRow(dynpse); iprofiles->set_size_request(50, -1); setExpandAlignProperties(iprofiles, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); ipconn = iprofiles->signal_changed().connect( sigc::mem_fun(*this, &Preferences::forImageComboChanged) ); @@ -2197,7 +2198,7 @@ void Preferences::bundledProfilesChanged () options.useBundledProfiles = useBundledProfiles->get_active (); // rescan the file's tree - profileStore.parseProfiles(); // This will call Preferences::updateProfileList in return + ProfileStore::getInstance()->parseProfiles(); // This will call Preferences::updateProfileList in return // restoring back the old value options.useBundledProfiles = currValue; @@ -2232,8 +2233,9 @@ void Preferences::updateProfileList() { rprofiles->updateProfileList(); iprofiles->updateProfileList(); - rprofiles->addRow(profileStore.getInternalDynamicPSE()); - iprofiles->addRow(profileStore.getInternalDynamicPSE()); + const ProfileStoreEntry* dynpse = ProfileStore::getInstance()->getInternalDynamicPSE(); + rprofiles->addRow(dynpse); + iprofiles->addRow(dynpse); } void Preferences::restoreValue() diff --git a/rtgui/profilepanel.cc b/rtgui/profilepanel.cc index b988418f0..06768cf56 100644 --- a/rtgui/profilepanel.cc +++ b/rtgui/profilepanel.cc @@ -18,9 +18,9 @@ */ #include "profilepanel.h" #include "options.h" -#include "profilestore.h" #include "clipboard.h" #include "multilangmgr.h" +#include "profilestorecombobox.h" #include "rtimage.h" using namespace rtengine; @@ -99,7 +99,7 @@ ProfilePanel::ProfilePanel () : storedPProfile(nullptr), lastFilename(""), image lastsaved = nullptr; dontupdate = false; - profileStore.addListener(this); + ProfileStore::getInstance()->addListener(this); changeconn = profiles->signal_changed().connect( sigc::mem_fun(*this, &ProfilePanel::selection_changed) ); @@ -114,7 +114,7 @@ ProfilePanel::ProfilePanel () : storedPProfile(nullptr), lastFilename(""), image ProfilePanel::~ProfilePanel () { - profileStore.removeListener(this); + ProfileStore::getInstance()->removeListener(this); if (custom) { custom->deleteInstance(); @@ -188,7 +188,7 @@ void ProfilePanel::storeCurrentValue () const ProfileStoreEntry *entry = profiles->getSelectedEntry(); const PartialProfile *currProfile; - if (entry && (currProfile = profileStore.getProfile(entry)) != nullptr) { + if (entry && (currProfile = ProfileStore::getInstance()->getProfile(entry)) != nullptr) { // now storedPProfile has the current entry's values storedPProfile = new PartialProfile(currProfile->pparams, currProfile->pedited, true); } else { @@ -318,7 +318,7 @@ void ProfilePanel::save_clicked (GdkEventButton* event) toSave = lastsaved; } else { const ProfileStoreEntry* entry = profiles->getSelectedEntry(); - toSave = entry ? profileStore.getProfile (profiles->getSelectedEntry()) : nullptr; + toSave = entry ? ProfileStore::getInstance()->getProfile (profiles->getSelectedEntry()) : nullptr; } if (toSave) { @@ -343,7 +343,7 @@ void ProfilePanel::save_clicked (GdkEventButton* event) } else { done = true; bool ccPrevState = changeconn.block(true); - profileStore.parseProfiles(); + ProfileStore::getInstance()->parseProfiles(); changeconn.block (ccPrevState); } } else { @@ -355,7 +355,7 @@ void ProfilePanel::save_clicked (GdkEventButton* event) } else { done = true; bool ccPrevState = changeconn.block(true); - profileStore.parseProfiles(); + ProfileStore::getInstance()->parseProfiles(); changeconn.block (ccPrevState); } } @@ -388,7 +388,7 @@ void ProfilePanel::copy_clicked (GdkEventButton* event) toSave = lastsaved; } else { const ProfileStoreEntry* entry = profiles->getSelectedEntry(); - toSave = entry ? profileStore.getProfile (entry) : nullptr; + toSave = entry ? ProfileStore::getInstance()->getProfile (entry) : nullptr; } // toSave has to be a complete procparams @@ -559,7 +559,7 @@ void ProfilePanel::paste_clicked (GdkEventButton* event) const ProfileStoreEntry* entry = profiles->getSelectedEntry(); if (entry) { - const PartialProfile* partProfile = profileStore.getProfile (entry); + const PartialProfile* partProfile = ProfileStore::getInstance()->getProfile (entry); *custom->pparams = *partProfile->pparams; } } @@ -576,7 +576,7 @@ void ProfilePanel::paste_clicked (GdkEventButton* event) const ProfileStoreEntry* entry = profiles->getSelectedEntry(); if (entry) { - const PartialProfile* partProfile = profileStore.getProfile (entry); + const PartialProfile* partProfile = ProfileStore::getInstance()->getProfile (entry); *custom->pparams = *partProfile->pparams; } } @@ -660,7 +660,7 @@ void ProfilePanel::selection_changed () currRow = profiles->get_active(); } - const PartialProfile* s = profileStore.getProfile (pse); + const PartialProfile* s = ProfileStore::getInstance()->getProfile (pse); if (s) { if (fillMode->get_active() && s->pedited) { @@ -745,12 +745,12 @@ void ProfilePanel::initProfile (const Glib::ustring& profileFullPath, ProcParams lasSavedEntry = getLastSavedRow(); } - if (!(pse = profileStore.findEntryFromFullPath(profileFullPath))) { + if (!(pse = ProfileStore::getInstance()->findEntryFromFullPath(profileFullPath))) { // entry not found, pse = the Internal ProfileStoreEntry - pse = profileStore.getInternalDefaultPSE(); + pse = ProfileStore::getInstance()->getInternalDefaultPSE(); } - defprofile = profileStore.getProfile (pse); + defprofile = ProfileStore::getInstance()->getProfile (pse); // selecting the "Internal" entry profiles->setInternalEntry (); diff --git a/rtgui/profilepanel.h b/rtgui/profilepanel.h index 8293c1803..72c9db36b 100644 --- a/rtgui/profilepanel.h +++ b/rtgui/profilepanel.h @@ -24,9 +24,9 @@ #include "../rtengine/rtengine.h" #include "pparamschangelistener.h" #include "profilechangelistener.h" -#include "profilestore.h" #include "partialpastedlg.h" #include "guiutils.h" +#include "profilestorecombobox.h" #include "rtimage.h" class ProfilePanel : public Gtk::Grid, public PParamsChangeListener, public ProfileStoreListener diff --git a/rtgui/profilestorecombobox.cc b/rtgui/profilestorecombobox.cc new file mode 100644 index 000000000..bfdb406e7 --- /dev/null +++ b/rtgui/profilestorecombobox.cc @@ -0,0 +1,358 @@ +/* + * 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 "../rtengine/profilestore.h" +#include "profilestorecombobox.h" + +#include "../rtengine/dynamicprofile.h" +#include "options.h" +#include "toolpanel.h" +#include "guiutils.h" + +using namespace rtengine; +using namespace rtengine::procparams; + +ProfileStoreLabel::ProfileStoreLabel(const ProfileStoreEntry *entry) : Gtk::Label(entry->label), entry(entry) +{ + set_alignment(0, 0.5); + set_ellipsize(Pango::ELLIPSIZE_END); + show(); +} + +ProfileStoreComboBox::ProfileStoreComboBox () +{ + updateProfileList(); + setPreferredWidth(50, 120); +} + +Glib::ustring ProfileStoreComboBox::getCurrentLabel() +{ + Glib::ustring currLabel; + Gtk::TreeModel::iterator currRow = get_active(); + + if (currRow) { + const ProfileStoreEntry *currEntry = (*currRow)[methodColumns.profileStoreEntry]; + return currEntry->label; + } + + return currLabel; +} + +const ProfileStoreEntry* ProfileStoreComboBox::getSelectedEntry() +{ + Gtk::TreeModel::iterator currRow_ = get_active(); + Gtk::TreeModel::Row currRow = *currRow_; + + if (currRow) { + return currRow[methodColumns.profileStoreEntry]; + } else { + return nullptr; + } +} + +/** @brief Recursive method to update the combobox entries */ +void ProfileStoreComboBox::refreshProfileList_ (Gtk::TreeModel::Row *parentRow, int parentFolderId, bool initial, const std::vector *entryList) +{ + for (auto entry : *entryList) { + if (entry->parentFolderId == parentFolderId) { // filtering the entry of the same folder + if (entry->type == PSET_FOLDER) { + Glib::ustring folderPath( ProfileStore::getInstance()->getPathFromId(entry->folderId) ); + + if (options.useBundledProfiles || ((folderPath != "${G}" ) && (folderPath != "${U}" ))) { + // creating the new submenu + Gtk::TreeModel::Row newSubMenu; + + if (initial) { + newSubMenu = *(refTreeModel->append()); + } else { + newSubMenu = *(refTreeModel->append(parentRow->children())); + } + + // creating and assigning the custom Label object + newSubMenu[methodColumns.label] = entry->label; + newSubMenu[methodColumns.profileStoreEntry] = entry; +#if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION == 18 + // HACK: Workaround for bug in Gtk+ 3.18... + Gtk::TreeModel::Row menuHeader = *(refTreeModel->append(newSubMenu->children())); + menuHeader[methodColumns.label] = "-"; + menuHeader[methodColumns.profileStoreEntry] = entry; +#endif + refreshProfileList_ (&newSubMenu, entry->folderId, false, entryList); + } else { + refreshProfileList_ (parentRow, entry->folderId, true, entryList); + } + } else { + Gtk::TreeModel::Row newItem; + + // creating a menu entry + if (initial) { + newItem = *(refTreeModel->append()); + } else { + newItem = *(refTreeModel->append(parentRow->children())); + } + + newItem[methodColumns.label] = entry->label; + newItem[methodColumns.profileStoreEntry] = entry; + } + } + } +} +/** @brief Get the ProfileStore's entry list and recreate the combobox entries. + * If you want to update the ProfileStore list itself (rescan the dir tree), use the "ProfileStore::parseProfiles" method instead + * + * This method has to be called by the ProfileStoreListener having a ProfileStoreComboBox. + */ +void ProfileStoreComboBox::updateProfileList () +{ + // clear items + clear(); + refTreeModel.clear(); + // Create the Tree model + refTreeModel = Gtk::TreeStore::create(methodColumns); + // Assign the model to the Combobox + set_model(refTreeModel); + + // this will lock the profilestore's entry list too + const std::vector *entryList = ProfileStore::getInstance()->getFileList(); + + //profileStore.dumpFolderList(); + refreshProfileList_ (NULL, entryList->at(0)->parentFolderId, true, entryList); + + if (entryList->at(0)->parentFolderId != 0) { + // special case for the Internal default entry + addRow(ProfileStore::getInstance()->getInternalDefaultPSE()); + } + + // releasing the profilestore's entry list mutex + ProfileStore::getInstance()->releaseFileList(); + + pack_start(methodColumns.label, false); + + Gtk::CellRendererText* cellRenderer = dynamic_cast(get_first_cell()); + cellRenderer->property_ellipsize() = Pango::ELLIPSIZE_MIDDLE; + cellRenderer->property_ellipsize_set() = true; +} + +Gtk::TreeIter ProfileStoreComboBox::findRowFromEntry_ (Gtk::TreeModel::Children childs, const ProfileStoreEntry *pse) +{ + Gtk::TreeModel::Row row; + Gtk::TreeIter rowInSubLevel; + + for(Gtk::TreeModel::Children::iterator iter = childs.begin(); iter != childs.end(); ++iter) { + row = *iter; + // Hombre: is there a smarter way of knowing if this row has childs? + const ProfileStoreEntry *pse_ = row[methodColumns.profileStoreEntry]; + + if (pse_->type == PSET_FOLDER) { + rowInSubLevel = findRowFromEntry_ (iter->children(), pse); + + if (rowInSubLevel) { + // entry found + return rowInSubLevel; + } + } else if (pse_ == pse) { + // entry found + return iter; + } + } + + return childs.end(); +} + +Gtk::TreeIter ProfileStoreComboBox::findRowFromEntry (const ProfileStoreEntry *pse) +{ + Gtk::TreeModel::Children childs = refTreeModel->children(); + + if (pse) { + Gtk::TreeIter row = findRowFromEntry_ (childs, pse); + return row; + } + + return childs.end(); +} + +Gtk::TreeIter ProfileStoreComboBox::findRowFromFullPath_ (Gtk::TreeModel::Children childs, int parentFolderId, Glib::ustring &name) +{ + Gtk::TreeModel::Row row; + Gtk::TreeIter rowInSubLevel; + + for(Gtk::TreeModel::Children::iterator iter = childs.begin(); iter != childs.end(); ++iter) { + row = *iter; + // Hombre: is there a smarter way of knowing if this row has childs? + const ProfileStoreEntry *pse = row[methodColumns.profileStoreEntry]; + + if (pse->type == PSET_FOLDER) { + rowInSubLevel = findRowFromFullPath_ (iter->children(), parentFolderId, name); + + if (rowInSubLevel) { + // entry found + return rowInSubLevel; + } + } else if (parentFolderId == pse->parentFolderId && name == pse->label) { + // entry found + return iter; + } + } + + return childs.end(); +} + +Gtk::TreeIter ProfileStoreComboBox::findRowFromFullPath (Glib::ustring path) +{ + Gtk::TreeIter row; + ProfileStore *profileStore = ProfileStore::getInstance(); + + if (path.empty()) { + return row; + } + + if (path == DEFPROFILE_INTERNAL) { + row = findRowFromEntry(profileStore->getInternalDefaultPSE()); + return row; + } + + if (path == DEFPROFILE_DYNAMIC) { + row = findRowFromEntry(profileStore->getInternalDynamicPSE()); + return row; + } + + // removing the filename + Glib::ustring fName = Glib::path_get_basename(path); + + if (!fName.empty()) { + path = path.substr(0, path.length() - fName.length()); + } else { + // path is malformed; + return row; + } + + path = Glib::path_get_dirname(path); + int parentFolderId = profileStore->findFolderId(path); + + // 1. find the path in the folder list + if (parentFolderId != -1) { + row = findRowFromFullPath_ (refTreeModel->children(), parentFolderId, fName); + } + + return row; +} + +/** @brief Get the absolute full path of the active row entry. + * @return The absolute full path of the active row entry, or the "Internal" keyword, + * or an empty string if the ComboBox is in an invalid state + */ +Glib::ustring ProfileStoreComboBox::getFullPathFromActiveRow() +{ + Glib::ustring path; + Gtk::TreeModel::iterator currRowI = get_active(); + ProfileStore *profileStore = ProfileStore::getInstance(); + + if (!currRowI) { + return path; + } + + Gtk::TreeModel::Row currRow = *currRowI; + + if (currRow) { + + const ProfileStoreEntry *currEntry = currRow[methodColumns.profileStoreEntry]; + + if (!currEntry) { + return path; + } + + if (currEntry == profileStore->getInternalDefaultPSE()) { + return Glib::ustring(DEFPROFILE_INTERNAL); + } + + if (currEntry == profileStore->getInternalDynamicPSE()) { + return Glib::ustring(DEFPROFILE_DYNAMIC); + } + + path = Glib::build_filename(profileStore->getPathFromId(currEntry->parentFolderId), currEntry->label); + } + + return path; +} + +bool ProfileStoreComboBox::setActiveRowFromFullPath(Glib::ustring path) +{ + if (!path.empty()) { + Gtk::TreeIter row = findRowFromFullPath(path); + + if (row) { + set_active(row); + return true; + } + } + + return false; +} + +bool ProfileStoreComboBox::setActiveRowFromEntry(const ProfileStoreEntry *pse) +{ + if (pse) { + Gtk::TreeIter row = findRowFromEntry(pse); + + if (row) { + set_active(row); + return true; + } + } + + return false; +} + +bool ProfileStoreComboBox::setInternalEntry () +{ + return setActiveRowFromEntry(ProfileStore::getInstance()->getInternalDefaultPSE()); +} + +/** @brief Get the row from the first level of the tree that match the provided name */ +Gtk::TreeIter ProfileStoreComboBox::getRowFromLabel(Glib::ustring name) +{ + Gtk::TreeIter row; + Gtk::TreeModel::Children childs = refTreeModel->children(); + + if (!name.empty()) { + Gtk::TreeModel::Row currRow; + + for(Gtk::TreeModel::Children::iterator iter = childs.begin(); iter != childs.end(); ++iter) { + currRow = *iter; + const ProfileStoreEntry *pse = currRow[methodColumns.profileStoreEntry]; + + if (pse->label == name) { + return currRow; + } + } + } + + return childs.end(); + //return refTreeModel->get_iter(""); // is this fast? We want to send back a null, anvalid or end() iterator object here +} + +/** @brief Add a new row to the first level of the tree */ +Gtk::TreeIter ProfileStoreComboBox::addRow(const ProfileStoreEntry *profileStoreEntry) +{ + Gtk::TreeIter newEntry = refTreeModel->append(); + Gtk::TreeModel::Row row = *newEntry; + row[methodColumns.label] = profileStoreEntry->label; + row[methodColumns.profileStoreEntry] = profileStoreEntry; + return newEntry; +} + diff --git a/rtgui/profilestorecombobox.h b/rtgui/profilestorecombobox.h new file mode 100644 index 000000000..70ccd9298 --- /dev/null +++ b/rtgui/profilestorecombobox.h @@ -0,0 +1,95 @@ +/* + * 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 . + */ +#ifndef _PROFILESTORECOMBOBOX_ +#define _PROFILESTORECOMBOBOX_ + +#include +#include +#include + +#include "../rtengine/rtengine.h" +#include "../rtengine/noncopyable.h" +#include "../rtengine/profilestore.h" + +#include "threadutils.h" +#include "paramsedited.h" +#include "guiutils.h" + + +/** + * @brief subclass of Gtk::Label with extra fields for Combobox and Menu, to link with a ProfileStoreEntry + */ +class ProfileStoreLabel : public Gtk::Label +{ + +public: + const ProfileStoreEntry *entry; + +#ifndef NDEBUG + ProfileStoreLabel() : Gtk::Label("*** error ***"), entry(nullptr) {} +#else + ProfileStoreLabel() : Gtk::Label(""), entry(NULL) {} +#endif + + /** @brief Create a new ProfileStoreLabel + * + * @param entry Pointer to the ProfileStoreEntry object, be it a directory or a file + */ + explicit ProfileStoreLabel(const ProfileStoreEntry *entry); + ProfileStoreLabel (const ProfileStoreLabel &other); +}; + +class ProfileStoreComboBox : public MyComboBox +{ + +protected: + class MethodColumns : public Gtk::TreeModel::ColumnRecord + { + public: + Gtk::TreeModelColumn label; + Gtk::TreeModelColumn profileStoreEntry; + MethodColumns() + { + add(label); + add(profileStoreEntry); + } + }; + + Glib::RefPtr refTreeModel; + MethodColumns methodColumns; + void refreshProfileList_ (Gtk::TreeModel::Row *parentRow, int parentFolderId, bool initial, const std::vector *entryList); + Gtk::TreeIter findRowFromEntry_ (Gtk::TreeModel::Children childs, const ProfileStoreEntry *pse); + Gtk::TreeIter findRowFromFullPath_(Gtk::TreeModel::Children childs, int parentFolderId, Glib::ustring &name); + +public: + ProfileStoreComboBox(); + void updateProfileList(); + Glib::ustring getCurrentLabel(); + const ProfileStoreEntry* getSelectedEntry(); + Gtk::TreeIter findRowFromEntry (const ProfileStoreEntry *pse); + Gtk::TreeIter findRowFromFullPath (Glib::ustring path); + Glib::ustring getFullPathFromActiveRow (); + bool setActiveRowFromFullPath (Glib::ustring oldPath); + bool setActiveRowFromEntry (const ProfileStoreEntry *pse); + bool setInternalEntry (); + Gtk::TreeIter getRowFromLabel(Glib::ustring name); + Gtk::TreeIter addRow(const ProfileStoreEntry *profileStoreEntry); +}; + +#endif diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index cd33f393d..54527a5d5 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -26,11 +26,12 @@ #include #include "../rtengine/imagedata.h" #include + +#include "../rtengine/dynamicprofile.h" #include "guiutils.h" -#include "profilestore.h" #include "batchqueue.h" #include "extprog.h" -#include "dynamicprofile.h" +#include "profilestorecombobox.h" using namespace rtengine::procparams; @@ -177,7 +178,7 @@ const ProcParams& Thumbnail::getProcParamsU () if (pparamsValid) { return pparams; } else { - pparams = *(profileStore.getDefaultProcParams (getType() == FT_Raw)); + pparams = *(ProfileStore::getInstance()->getDefaultProcParams (getType() == FT_Raw)); if (pparams.wb.method == "Camera") { double ct; @@ -231,7 +232,7 @@ rtengine::procparams::ProcParams* Thumbnail::createProcParamsForUpdate(bool retu } else { imageMetaData = rtengine::ImageMetaData::fromFile (fname, nullptr); } - PartialProfile *pp = loadDynamicProfile(imageMetaData); + PartialProfile *pp = ProfileStore::getInstance()->loadDynamicProfile(imageMetaData); int err = pp->pparams->save(outFName); pp->deleteInstance(); delete pp; @@ -239,7 +240,7 @@ rtengine::procparams::ProcParams* Thumbnail::createProcParamsForUpdate(bool retu loadProcParams(); } } else if (create && defProf != DEFPROFILE_DYNAMIC) { - const PartialProfile *p = profileStore.getProfile(defProf); + const PartialProfile *p = ProfileStore::getInstance()->getProfile(defProf); if (p && !p->pparams->save(outFName)) { loadProcParams(); } @@ -315,7 +316,7 @@ void Thumbnail::loadProcParams () pparamsValid = false; pparams.setDefaults(); - const PartialProfile *defaultPP = profileStore.getDefaultPartialProfile(getType() == FT_Raw); + const PartialProfile *defaultPP = ProfileStore::getInstance()->getDefaultPartialProfile(getType() == FT_Raw); defaultPP->applyTo(&pparams); if (options.paramsLoadLocation == PLL_Input) {