Merge branch 'master' into gtk3

This commit is contained in:
Hombre
2016-01-11 00:54:25 +01:00
69 changed files with 1940 additions and 1001 deletions

View File

@@ -37,13 +37,13 @@
using namespace std;
using namespace rtengine;
BatchQueue::BatchQueue (FileCatalog* aFileCatalog) : processing(NULL), fileCatalog(aFileCatalog), sequence(0), listener(NULL)
BatchQueue::BatchQueue (FileCatalog* aFileCatalog) : processing(NULL), fileCatalog(aFileCatalog), sequence(0), listener(NULL),
pmenu (new Gtk::Menu ())
{
location = THLOC_BATCHQUEUE;
int p = 0;
pmenu = new Gtk::Menu ();
pmenu->attach (*Gtk::manage(open = new Gtk::MenuItem (M("FILEBROWSER_POPUPOPENINEDITOR"))), 0, 1, p, p + 1);
p++;
@@ -76,9 +76,9 @@ BatchQueue::BatchQueue (FileCatalog* aFileCatalog) : processing(NULL), fileCatal
cancel->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_Delete, (Gdk::ModifierType)0, Gtk::ACCEL_VISIBLE);
open->signal_activate().connect(sigc::mem_fun(*this, &BatchQueue::openLastSelectedItemInEditor));
cancel->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &BatchQueue::cancelItems), &selected));
head->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &BatchQueue::headItems), &selected));
tail->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &BatchQueue::tailItems), &selected));
cancel->signal_activate().connect (std::bind (&BatchQueue::cancelItems, this, selected));
head->signal_activate().connect (std::bind (&BatchQueue::headItems, this, selected));
tail->signal_activate().connect (std::bind (&BatchQueue::tailItems, this, selected));
selall->signal_activate().connect (sigc::mem_fun(*this, &BatchQueue::selectAll));
setArrangement (ThumbBrowserBase::TB_Vertical);
@@ -96,20 +96,18 @@ BatchQueue::~BatchQueue ()
}
fd.clear ();
delete pmenu;
}
void BatchQueue::resizeLoadedQueue()
{
// TODO: Check for Linux
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW);
#endif
for (size_t i = 0; i < fd.size(); i++) {
fd.at(i)->resize(getThumbnailHeight());
}
const auto height = getThumbnailHeight ();
for (const auto entry : fd)
entry->resize(height);
}
// Reduce the max size of a thumb, since thumb is processed synchronously on adding to queue
@@ -158,328 +156,220 @@ bool BatchQueue::keyPressed (GdkEventKey* event)
openLastSelectedItemInEditor();
return true;
} else if (event->keyval == GDK_KEY_Home) {
headItems (&selected);
headItems (selected);
return true;
} else if (event->keyval == GDK_KEY_End) {
tailItems (&selected);
tailItems (selected);
return true;
} else if (event->keyval == GDK_KEY_Delete) {
cancelItems (&selected);
cancelItems (selected);
return true;
}
return false;
}
void BatchQueue::addEntries ( std::vector<BatchQueueEntry*> &entries, bool head, bool save)
void BatchQueue::addEntries (const std::vector<BatchQueueEntry*>& entries, bool head, bool save)
{
{
// TODO: Check for Linux
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW);
#endif
for( std::vector<BatchQueueEntry*>::iterator entry = entries.begin(); entry != entries.end(); entry++ ) {
(*entry)->setParent (this);
for (const auto entry : entries) {
// BatchQueueButtonSet HAVE TO be added before resizing to take them into account
BatchQueueButtonSet* bqbs = new BatchQueueButtonSet (*entry);
entry->setParent (this);
// BatchQueueButtonSet have to be added before resizing to take them into account
const auto bqbs = new BatchQueueButtonSet (entry);
bqbs->setButtonListener (this);
(*entry)->addButtonSet (bqbs);
entry->addButtonSet (bqbs);
(*entry)->resize (getThumbnailHeight()); // batch queue might have smaller, restricted size
Glib::ustring tempFile = getTempFilenameForParams( (*entry)->filename );
// batch queue might have smaller, restricted size
entry->resize (getThumbnailHeight());
// recovery save
if( !(*entry)->params.save( tempFile ) ) {
(*entry)->savedParamsFile = tempFile;
}
const auto tempFile = getTempFilenameForParams (entry->filename);
(*entry)->selected = false;
if (!entry->params.save (tempFile))
entry->savedParamsFile = tempFile;
if (!head) {
fd.push_back (*entry);
} else {
std::vector<ThumbBrowserEntryBase*>::iterator pos;
entry->selected = false;
for (pos = fd.begin(); pos != fd.end(); pos++)
if (!(*pos)->processing) {
fd.insert (pos, *entry);
break;
}
// insert either at the end, or before the first non-processing entry
auto pos = fd.end ();
if (pos == fd.end()) {
fd.push_back (*entry);
}
}
if (head)
pos = std::find_if (fd.begin (), fd.end (), [] (const ThumbBrowserEntryBase* fdEntry) { return !fdEntry->processing; });
if ((*entry)->thumbnail) {
(*entry)->thumbnail->imageEnqueued ();
}
fd.insert (pos, entry);
if (entry->thumbnail)
entry->thumbnail->imageEnqueued ();
}
}
if (save) {
saveBatchQueue( );
}
if (save)
saveBatchQueue ();
redraw();
redraw ();
notifyListener (false);
}
bool BatchQueue::saveBatchQueue( )
bool BatchQueue::saveBatchQueue ()
{
Glib::ustring savedQueueFile;
savedQueueFile = options.rtdir + "/batch/queue.csv";
FILE *f = safe_g_fopen (savedQueueFile, "wt");
const auto fileName = Glib::build_filename (options.rtdir, "batch", "queue.csv");
if (f == NULL) {
std::ofstream file (fileName, std::ios::trunc);
if (!file.is_open ())
return false;
}
{
// TODO: Check for Linux
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW);
#endif
if (fd.empty ())
return true;
if (fd.size())
// The column's header is mandatory (the first line will be skipped when loaded)
fprintf(f, "input image full path|param file full path|output image full path|file format|jpeg quality|jpeg subsampling|"
"png bit depth|png compression|tiff bit depth|uncompressed tiff|save output params|force format options|<end of line>\n");
// The column's header is mandatory (the first line will be skipped when loaded)
file << "input image full path|param file full path|output image full path|file format|jpeg quality|jpeg subsampling|"
<< "png bit depth|png compression|tiff bit depth|uncompressed tiff|save output params|force format options|<end of line>"
<< std::endl;
// method is already running with entryLock, so no need to lock again
for (std::vector<ThumbBrowserEntryBase*>::iterator pos = fd.begin(); pos != fd.end(); pos++) {
BatchQueueEntry* bqe = reinterpret_cast<BatchQueueEntry*>(*pos);
for (const auto fdEntry : fd) {
const auto entry = static_cast<BatchQueueEntry*> (fdEntry);
const auto& saveFormat = entry->saveFormat;
// Warning: for code's simplicity in loadBatchQueue, each field must end by the '|' character, safer than ';' or ',' since it can't be used in paths
fprintf(f, "%s|%s|%s|%s|%d|%d|%d|%d|%d|%d|%d|%d|\n",
bqe->filename.c_str(), bqe->savedParamsFile.c_str(), bqe->outFileName.c_str(), bqe->saveFormat.format.c_str(),
bqe->saveFormat.jpegQuality, bqe->saveFormat.jpegSubSamp,
bqe->saveFormat.pngBits, bqe->saveFormat.pngCompression,
bqe->saveFormat.tiffBits, bqe->saveFormat.tiffUncompressed,
bqe->saveFormat.saveParams, bqe->forceFormatOpts
);
file << entry->filename << '|' << entry->savedParamsFile << '|' << entry->outFileName << '|' << saveFormat.format << '|'
<< saveFormat.jpegQuality << '|' << saveFormat.jpegSubSamp << '|'
<< saveFormat.pngBits << '|' << saveFormat.pngCompression << '|'
<< saveFormat.tiffBits << '|' << saveFormat.tiffUncompressed << '|'
<< saveFormat.saveParams << '|' << entry->forceFormatOpts << '|'
<< std::endl;
}
}
fclose (f);
return true;
}
bool BatchQueue::loadBatchQueue( )
bool BatchQueue::loadBatchQueue ()
{
Glib::ustring savedQueueFile;
savedQueueFile = options.rtdir + "/batch/queue.csv";
FILE *f = safe_g_fopen (savedQueueFile, "rt");
const auto fileName = Glib::build_filename (options.rtdir, "batch", "queue.csv");
if (f != NULL) {
char *buffer = new char[1024];
unsigned numLoaded = 0;
// skipping the first line
bool firstLine = true;
std::ifstream file (fileName);
if (file.is_open ()) {
// Yes, it's better to get the lock for the whole file reading,
// to update the list in one shot without any other concurrent access!
// TODO: Check for Linux
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW);
#endif
while (fgets (buffer, 1024, f)) {
std::string row, column;
std::vector<std::string> values;
if (firstLine) {
// skipping the column's title line
firstLine = false;
// skipping the first row
std::getline (file, row);
while (std::getline (file, row)) {
std::istringstream line (row);
values.clear ();
while (std::getline(line, column, '|')) {
values.push_back (column);
}
auto value = values.begin ();
const auto nextStringOr = [&] (const Glib::ustring& defaultValue) -> Glib::ustring
{
return value != values.end () ? Glib::ustring(*value++) : defaultValue;
};
const auto nextIntOr = [&] (int defaultValue) -> int
{
try {
return value != values.end () ? std::stoi(*value++) : defaultValue;
}
catch (std::exception&) {
return defaultValue;
}
};
const auto source = nextStringOr (Glib::ustring ());
const auto paramsFile = nextStringOr (Glib::ustring ());
if (source.empty () || paramsFile.empty ())
continue;
const auto outputFile = nextStringOr (Glib::ustring ());
const auto saveFmt = nextStringOr (options.saveFormat.format);
const auto jpegQuality = nextIntOr (options.saveFormat.jpegQuality);
const auto jpegSubSamp = nextIntOr (options.saveFormat.jpegSubSamp);
const auto pngBits = nextIntOr (options.saveFormat.pngBits);
const auto pngCompression = nextIntOr (options.saveFormat.pngCompression);
const auto tiffBits = nextIntOr (options.saveFormat.tiffBits);
const auto tiffUncompressed = nextIntOr (options.saveFormat.tiffUncompressed);
const auto saveParams = nextIntOr (options.saveFormat.saveParams);
const auto forceFormatOpts = nextIntOr (options.forceFormatOpts);
rtengine::procparams::ProcParams pparams;
if (pparams.load (paramsFile))
continue;
auto thumb = CacheManager::getInstance ()->getEntry (source);
if (!thumb)
continue;
auto job = rtengine::ProcessingJob::create (source, thumb->getType () == FT_Raw, pparams);
auto prevh = getMaxThumbnailHeight ();
auto prevw = prevh;
thumb->getThumbnailSize (prevw, prevh, &pparams);
auto entry = new BatchQueueEntry (job, pparams, source, prevw, prevh, thumb);
thumb->decreaseRef (); // Removing the refCount acquired by cacheMgr->getEntry
entry->setParent (this);
// BatchQueueButtonSet have to be added before resizing to take them into account
auto bqbs = new BatchQueueButtonSet (entry);
bqbs->setButtonListener (this);
entry->addButtonSet (bqbs);
entry->savedParamsFile = paramsFile;
entry->selected = false;
entry->outFileName = outputFile;
if (!outputFile.empty ()) {
auto& saveFormat = entry->saveFormat;
saveFormat.format = saveFmt;
saveFormat.jpegQuality = jpegQuality;
saveFormat.jpegSubSamp = jpegSubSamp;
saveFormat.pngBits = pngBits;
saveFormat.pngCompression = pngCompression;
saveFormat.tiffBits = tiffBits;
saveFormat.tiffUncompressed = tiffUncompressed != 0;
saveFormat.saveParams = saveParams != 0;
entry->forceFormatOpts = forceFormatOpts != 0;
} else {
entry->forceFormatOpts = false;
}
size_t pos;
Glib::ustring source;
Glib::ustring paramsFile;
Glib::ustring outputFile;
Glib::ustring saveFmt(options.saveFormat.format);
int jpegQuality = options.saveFormat.jpegQuality, jpegSubSamp = options.saveFormat.jpegSubSamp;
int pngBits = options.saveFormat.pngBits, pngCompression = options.saveFormat.pngCompression;
int tiffBits = options.saveFormat.tiffBits, tiffUncompressed = options.saveFormat.tiffUncompressed;
int saveParams = options.saveFormat.saveParams;
int forceFormatOpts = options.forceFormatOpts;
Glib::ustring currLine(buffer);
int a = 0;
if (currLine.rfind('\n') != Glib::ustring::npos) {
a++;
}
if (currLine.rfind('\r') != Glib::ustring::npos) {
a++;
}
if (a) {
currLine = currLine.substr(0, currLine.length() - a);
}
// Looking for the image's full path
pos = currLine.find('|');
if (pos != Glib::ustring::npos) {
source = currLine.substr(0, pos);
currLine = currLine.substr(pos + 1);
// Looking for the procparams' full path
pos = currLine.find('|');
if (pos != Glib::ustring::npos) {
paramsFile = currLine.substr(0, pos);
currLine = currLine.substr(pos + 1);
// Looking for the full output path; if empty, it'll use the template string
pos = currLine.find('|');
if (pos != Glib::ustring::npos) {
outputFile = currLine.substr(0, pos);
currLine = currLine.substr(pos + 1);
// No need to bother reading the last options, they will be ignored if outputFile is empty!
if (!outputFile.empty()) {
// Looking for the saving format
pos = currLine.find('|');
if (pos != Glib::ustring::npos) {
saveFmt = currLine.substr(0, pos);
currLine = currLine.substr(pos + 1);
// Looking for the jpeg quality
pos = currLine.find('|');
if (pos != Glib::ustring::npos) {
jpegQuality = atoi(currLine.substr(0, pos).c_str());
currLine = currLine.substr(pos + 1);
// Looking for the jpeg subsampling
pos = currLine.find('|');
if (pos != Glib::ustring::npos) {
jpegSubSamp = atoi(currLine.substr(0, pos).c_str());
currLine = currLine.substr(pos + 1);
// Looking for the png bit depth
pos = currLine.find('|');
if (pos != Glib::ustring::npos) {
pngBits = atoi(currLine.substr(0, pos).c_str());
currLine = currLine.substr(pos + 1);
// Looking for the png compression
pos = currLine.find('|');
if (pos != Glib::ustring::npos) {
pngCompression = atoi(currLine.substr(0, pos).c_str());
currLine = currLine.substr(pos + 1);
// Looking for the tiff bit depth
pos = currLine.find('|');
if (pos != Glib::ustring::npos) {
tiffBits = atoi(currLine.substr(0, pos).c_str());
currLine = currLine.substr(pos + 1);
// Looking for the tiff uncompression
pos = currLine.find('|');
if (pos != Glib::ustring::npos) {
tiffUncompressed = atoi(currLine.substr(0, pos).c_str());
currLine = currLine.substr(pos + 1);
// Looking out if we have to save the procparams
pos = currLine.find('|');
if (pos != Glib::ustring::npos) {
saveParams = atoi(currLine.substr(0, pos).c_str());
currLine = currLine.substr(pos + 1);
// Looking out if we have to to use the format options
pos = currLine.find('|');
if (pos != Glib::ustring::npos) {
forceFormatOpts = atoi(currLine.substr(0, pos).c_str());
// currLine = currLine.substr(pos+1);
}
}
}
}
}
}
}
}
}
}
}
}
}
if( !source.empty() && !paramsFile.empty() ) {
rtengine::procparams::ProcParams pparams;
if( pparams.load( paramsFile ) ) {
continue;
}
::Thumbnail *thumb = cacheMgr->getEntry( source );
if( thumb ) {
rtengine::ProcessingJob* job = rtengine::ProcessingJob::create(source, thumb->getType() == FT_Raw, pparams);
int prevh = getMaxThumbnailHeight();
int prevw = prevh;
thumb->getThumbnailSize (prevw, prevh, &pparams);
BatchQueueEntry *entry = new BatchQueueEntry(job, pparams, source, prevw, prevh, thumb);
thumb->decreaseRef(); // Removing the refCount acquired by cacheMgr->getEntry
entry->setParent(this);
// BatchQueueButtonSet HAVE TO be added before resizing to take them into account
BatchQueueButtonSet* bqbs = new BatchQueueButtonSet(entry);
bqbs->setButtonListener(this);
entry->addButtonSet(bqbs);
//entry->resize(getThumbnailHeight());
entry->savedParamsFile = paramsFile;
entry->selected = false;
entry->outFileName = outputFile;
if (!outputFile.empty()) {
entry->saveFormat.format = saveFmt;
entry->saveFormat.jpegQuality = jpegQuality;
entry->saveFormat.jpegSubSamp = jpegSubSamp;
entry->saveFormat.pngBits = pngBits;
entry->saveFormat.pngCompression = pngCompression;
entry->saveFormat.tiffBits = tiffBits;
entry->saveFormat.tiffUncompressed = tiffUncompressed != 0;
entry->saveFormat.saveParams = saveParams != 0;
entry->forceFormatOpts = forceFormatOpts != 0;
} else {
entry->forceFormatOpts = false;
}
fd.push_back(entry);
numLoaded++;
}
}
fd.push_back (entry);
}
delete [] buffer;
fclose(f);
}
redraw();
notifyListener(false);
redraw ();
notifyListener (false);
return !fd.empty();
return !fd.empty ();
}
Glib::ustring BatchQueue::getTempFilenameForParams( const Glib::ustring filename )
@@ -506,107 +396,106 @@ int cancelItemUI (void* data)
return 0;
}
void BatchQueue::cancelItems (std::vector<ThumbBrowserEntryBase*>* items)
void BatchQueue::cancelItems (const std::vector<ThumbBrowserEntryBase*>& items)
{
{
// TODO: Check for Linux
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW);
#endif
for (size_t i = 0; i < items->size(); i++) {
BatchQueueEntry* entry = (BatchQueueEntry*)(*items)[i];
for (const auto item : items) {
if (entry->processing) {
const auto entry = static_cast<BatchQueueEntry*> (item);
if (entry->processing)
continue;
}
std::vector<ThumbBrowserEntryBase*>::iterator pos = std::find (fd.begin(), fd.end(), entry);
const auto pos = std::find (fd.begin (), fd.end (), entry);
if (pos != fd.end()) {
fd.erase (pos);
rtengine::ProcessingJob::destroy (entry->job);
if (pos == fd.end ())
continue;
if (entry->thumbnail) {
entry->thumbnail->imageRemovedFromQueue ();
}
fd.erase (pos);
g_idle_add (cancelItemUI, entry);
}
rtengine::ProcessingJob::destroy (entry->job);
if (entry->thumbnail)
entry->thumbnail->imageRemovedFromQueue ();
g_idle_add (cancelItemUI, entry);
}
for (size_t i = 0; i < fd.size(); i++) {
fd[i]->selected = false;
}
for (const auto entry : fd)
entry->selected = false;
lastClicked = NULL;
lastClicked = nullptr;
selected.clear ();
}
saveBatchQueue( );
saveBatchQueue ();
redraw ();
notifyListener (false);
}
void BatchQueue::headItems (std::vector<ThumbBrowserEntryBase*>* items)
void BatchQueue::headItems (const std::vector<ThumbBrowserEntryBase*>& items)
{
{
// TODO: Check for Linux
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW);
#endif
for (auto item = items.rbegin(); item != items.rend(); ++item) {
for (int i = items->size() - 1; i >= 0; i--) {
BatchQueueEntry* entry = (BatchQueueEntry*)(*items)[i];
const auto entry = static_cast<BatchQueueEntry*> (*item);
if (entry->processing) {
if (entry->processing)
continue;
}
std::vector<ThumbBrowserEntryBase*>::iterator pos = std::find (fd.begin(), fd.end(), entry);
const auto pos = std::find (fd.begin (), fd.end (), entry);
if (pos != fd.end() && pos != fd.begin()) {
fd.erase (pos);
if (pos == fd.end () || pos == fd.begin ())
continue;
// find the first item that is not under processing
for (pos = fd.begin(); pos != fd.end(); pos++)
if (!(*pos)->processing) {
fd.insert (pos, entry);
break;
}
}
fd.erase (pos);
// find the first item that is not under processing
const auto newPos = std::find_if (fd.begin (), fd.end (), [] (const ThumbBrowserEntryBase* fdEntry) { return !fdEntry->processing; });
fd.insert (newPos, entry);
}
}
saveBatchQueue( );
saveBatchQueue ();
redraw ();
}
void BatchQueue::tailItems (std::vector<ThumbBrowserEntryBase*>* items)
void BatchQueue::tailItems (const std::vector<ThumbBrowserEntryBase*>& items)
{
{
// TODO: Check for Linux
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW);
#endif
for (size_t i = 0; i < items->size(); i++) {
BatchQueueEntry* entry = (BatchQueueEntry*)(*items)[i];
for (const auto item : items) {
if (entry->processing) {
const auto entry = static_cast<BatchQueueEntry*> (item);
if (entry->processing)
continue;
}
std::vector<ThumbBrowserEntryBase*>::iterator pos = std::find (fd.begin(), fd.end(), entry);
const auto pos = std::find (fd.begin (), fd.end (), entry);
if (pos != fd.end()) {
fd.erase (pos);
fd.push_back (entry);
}
if (pos == fd.end ())
continue;
fd.erase (pos);
fd.push_back (entry);
}
}
saveBatchQueue( );
saveBatchQueue ();
redraw ();
}
@@ -1031,11 +920,11 @@ void BatchQueue::buttonPressed (LWButton* button, int actionCode, void* actionDa
bqe.push_back (static_cast<BatchQueueEntry*>(actionData));
if (actionCode == 10) { // cancel
cancelItems (&bqe);
cancelItems (bqe);
} else if (actionCode == 8) { // to head
headItems (&bqe);
headItems (bqe);
} else if (actionCode == 9) { // to tail
tailItems (&bqe);
tailItems (bqe);
}
}