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