diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index 294c074bb..5e1dd734e 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -19,6 +19,7 @@ * along with RawTherapee. If not, see . */ #include "filebrowser.h" +#include #include #include "options.h" #include "multilangmgr.h" @@ -32,6 +33,96 @@ extern Options options; +namespace +{ + +const Glib::ustring* getOriginalExtension (const ThumbBrowserEntryBase* entry) +{ + // We use the parsed extensions as a priority list, + // i.e. what comes earlier in the list is considered an original of what comes later. + typedef std::vector ExtensionVector; + typedef ExtensionVector::const_iterator ExtensionIterator; + + const ExtensionVector& originalExtensions = options.parsedExtensions; + + // Extract extension from basename + const Glib::ustring basename = Glib::path_get_basename (entry->filename.lowercase()); + + const Glib::ustring::size_type pos = basename.find_last_of ('.'); + if (pos >= basename.length () - 1) { + return NULL; + } + + const Glib::ustring extension = basename.substr (pos + 1); + + // Try to find a matching original extension + for (ExtensionIterator originalExtension = originalExtensions.begin(); originalExtension != originalExtensions.end(); ++originalExtension) { + if (*originalExtension == extension) { + return &*originalExtension; + } + } + + return NULL; +} + +ThumbBrowserEntryBase* selectOriginalEntry (ThumbBrowserEntryBase* original, ThumbBrowserEntryBase* candidate) +{ + // The candidate will become the new original, if it has an original extension + // and if its extension is higher in the list than the old original. + if (const Glib::ustring* candidateExtension = getOriginalExtension (candidate)) { + if (original == NULL) { + return candidate; + } else if (const Glib::ustring* originalExtension = getOriginalExtension (original)) { + return candidateExtension < originalExtension ? candidate : original; + } + } else { + return original; + } +} + +void findOriginalEntries (const std::vector& entries) +{ + typedef std::vector EntryVector; + typedef EntryVector::const_iterator EntryIterator; + typedef std::map BasenameMap; + typedef BasenameMap::const_iterator BasenameIterator; + + // Sort all entries into buckets by basename without extension + BasenameMap byBasename; + + for (EntryIterator entry = entries.begin (); entry != entries.end (); ++entry) { + const Glib::ustring basename = Glib::path_get_basename ((*entry)->filename.lowercase()); + + const Glib::ustring::size_type pos = basename.find_last_of ('.'); + if (pos >= basename.length () - 1) { + (*entry)->setOriginal (NULL); + continue; + } + + const Glib::ustring withoutExtension = basename.substr (0, pos); + + byBasename[withoutExtension].push_back (*entry); + } + + // Find the original image for each bucket + for (BasenameIterator bucket = byBasename.begin (); bucket != byBasename.end (); ++bucket) { + const EntryVector& entries = bucket->second; + ThumbBrowserEntryBase* original = NULL; + + // Select the most likely original in a first pass... + for (EntryIterator entry = entries.begin (); entry != entries.end (); ++entry) { + original = selectOriginalEntry (original, *entry); + } + + // ...and link all other images to it in a second pass. + for (EntryIterator entry = entries.begin (); entry != entries.end (); ++entry) { + (*entry)->setOriginal (*entry != original ? original : NULL); + } + } +} + +} + FileBrowser::FileBrowser () : tbl(NULL), numFiltered(0), partialPasteDlg(M("PARTIALPASTE_DIALOGLABEL")) { @@ -1370,6 +1461,10 @@ void FileBrowser::applyFilter (const BrowserFilter& filter) MYWRITERLOCK(l, entryRW); // Don't make this a writer lock! HOMBRE: Why? 'selected' is modified here #endif + if (true/* TODO: filterOriginal */) { + findOriginalEntries(fd); + } + for (size_t i = 0; i < fd.size(); i++) { if (checkFilter (fd[i])) { numFiltered++; @@ -1400,6 +1495,10 @@ bool FileBrowser::checkFilter (ThumbBrowserEntryBase* entryb) // true -> entry FileBrowserEntry* entry = static_cast(entryb); + if (true/* TODO: filterOriginal */ && entry->getOriginal() != NULL) { + return false; + } + // return false if basic filter settings are not satisfied if ((filter.showRanked[entry->thumbnail->getRank()] == false ) || (filter.showCLabeled[entry->thumbnail->getColorLabel()] == false ) || diff --git a/rtgui/thumbbrowserentrybase.cc b/rtgui/thumbbrowserentrybase.cc index f9f8f9f1e..d1d7adc51 100644 --- a/rtgui/thumbbrowserentrybase.cc +++ b/rtgui/thumbbrowserentrybase.cc @@ -26,7 +26,7 @@ ThumbBrowserEntryBase::ThumbBrowserEntryBase (const Glib::ustring& fname) prex(0), prey(0), upperMargin(6), borderWidth(1), textGap(6), sideMargin(8), lowerMargin(8), preview(NULL), dispname(Glib::path_get_basename (fname)), buttonSet(NULL), width(0), height(0), exp_width(0), exp_height(0), startx(0), starty(0), ofsX(0), ofsY(0), redrawRequests(0), - parent(NULL), bbSelected(false), bbFramed(false), bbPreview(NULL), + parent(NULL), original(NULL), bbSelected(false), bbFramed(false), bbPreview(NULL), thumbnail(NULL), filename(fname), shortname(dispname), exifline(""), datetimeline(""), selected(false), drawable(false), filtered(false), framed(false), processing(false), italicstyle(false), edited(false), recentlysaved(false), updatepriority(false), withFilename(WFNAME_NONE) {} @@ -544,6 +544,17 @@ bool ThumbBrowserEntryBase::insideWindow (int x, int y, int w, int h) return !(ofsX + startx > x + w || ofsX + startx + exp_width < x || ofsY + starty > y + h || ofsY + starty + exp_height < y); } +std::vector > ThumbBrowserEntryBase::getIconsOnImageArea() +{ + return std::vector >(); +} + +void ThumbBrowserEntryBase::getIconSize(int& w, int& h) +{ + w = 0; + h = 0; +} + bool ThumbBrowserEntryBase::motionNotify (int x, int y) { diff --git a/rtgui/thumbbrowserentrybase.h b/rtgui/thumbbrowserentrybase.h index e910aedd0..1b7f0691a 100644 --- a/rtgui/thumbbrowserentrybase.h +++ b/rtgui/thumbbrowserentrybase.h @@ -72,6 +72,7 @@ protected: int redrawRequests; ThumbBrowserBase* parent; + ThumbBrowserEntryBase* original; Glib::RefPtr backBuffer; bool bbSelected, bbFramed; @@ -168,22 +169,17 @@ public: return shortname.casefold() > other.shortname.casefold(); } + ThumbBrowserEntryBase* getOriginal () const; + void setOriginal (ThumbBrowserEntryBase* original); + virtual void refreshThumbnailImage () {} virtual void refreshQuickThumbnailImage () {} virtual void calcThumbnailSize () {} virtual void drawProgressBar (Glib::RefPtr win, Glib::RefPtr gc, const Gdk::Color& foregr, const Gdk::Color& backgr, int x, int w, int y, int h) {} - virtual std::vector > getIconsOnImageArea () - { - std::vector > r; - return r; - } - virtual void getIconSize (int& w, int& h) - { - w = 0; - h = 0; - } + virtual std::vector > getIconsOnImageArea (); + virtual void getIconSize (int& w, int& h); virtual bool motionNotify (int x, int y); virtual bool pressNotify (int button, int type, int bstate, int x, int y); @@ -191,4 +187,14 @@ public: virtual Glib::ustring getToolTip (int x, int y); }; +inline ThumbBrowserEntryBase* ThumbBrowserEntryBase::getOriginal() const +{ + return original; +} + +inline void ThumbBrowserEntryBase::setOriginal(ThumbBrowserEntryBase* original) +{ + this->original = original; +} + #endif