diff --git a/rtdata/languages/default b/rtdata/languages/default index e5e053655..a33b2a9cd 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -166,6 +166,7 @@ FILEBROWSER_POPUPREMOVE;Delete permanently FILEBROWSER_POPUPREMOVEINCLPROC;Delete permanently, including queue-processed version FILEBROWSER_POPUPRENAME;Rename FILEBROWSER_POPUPSELECTALL;Select all +FILEBROWSER_POPUPSORTBY;Sort Files FILEBROWSER_POPUPTRASH;Move to trash FILEBROWSER_POPUPUNRANK;Unrank FILEBROWSER_POPUPUNTRASH;Remove from trash @@ -2060,6 +2061,13 @@ SAVEDLG_WARNFILENAME;File will be named SHCSELECTOR_TOOLTIP;Click right mouse button to reset the position of those 3 sliders. SOFTPROOF_GAMUTCHECK_TOOLTIP;Highlight pixels with out-of-gamut colors with respect to:\n- the printer profile, if one is set and soft-proofing is enabled,\n- the output profile, if a printer profile is not set and soft-proofing is enabled,\n- the monitor profile, if soft-proofing is disabled. SOFTPROOF_TOOLTIP;Soft-proofing simulates the appearance of the image:\n- when printed, if a printer profile is set in Preferences > Color Management,\n- when viewed on a display that uses the current output profile, if a printer profile is not set. +SORT_ASCENDING;Ascending +SORT_BY_NAME;By Name +SORT_BY_DATE;By Date +SORT_BY_EXIF;By EXIF +SORT_BY_RANK;By Rank +SORT_BY_LABEL;By Color Label +SORT_DESCENDING;Descending TC_PRIM_BLUX;Bx TC_PRIM_BLUY;By TC_PRIM_GREX;Gx diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 3c10e7dc0..fb2fcaf3a 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -19,6 +19,7 @@ #include #include +#include #include @@ -57,7 +58,8 @@ template T getFromFrame( const std::vector>& frames, std::size_t frame, - const std::function& function + const std::function& function, + T defval = {} ) { if (frame < frames.size()) { @@ -66,7 +68,7 @@ T getFromFrame( if (!frames.empty()) { return function(*frames[0]); } - return {}; + return defval; } const std::string& validateUft8(const std::string& str, const std::string& on_error = "???") @@ -85,11 +87,21 @@ FramesMetaData* FramesMetaData::fromFile(const Glib::ustring& fname, std::unique return new FramesData(fname, std::move(rml), firstFrameOnly); } -FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* rootDir, rtexif::TagDirectory* firstRootDir) : +static struct tm timeFromTS(const time_t ts) +{ +#if !defined(WIN32) + struct tm tm; + return *gmtime_r(&ts, &tm); +#else + return *gmtime(&ts); +#endif +} + +FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* rootDir, rtexif::TagDirectory* firstRootDir, time_t ts) : frameRootDir(frameRootDir_), iptc(nullptr), - time{}, - timeStamp{}, + time(timeFromTS(ts)), + timeStamp(ts), iso_speed(0), aperture(0.), focal_len(0.), @@ -1068,7 +1080,8 @@ tm FramesData::getDateTime(unsigned int frame) const [](const FrameData& frame_data) { return frame_data.getDateTime(); - } + }, + modTime ); } @@ -1080,7 +1093,8 @@ time_t FramesData::getDateTimeAsTS(unsigned int frame) const [](const FrameData& frame_data) { return frame_data.getDateTimeAsTS(); - } + }, + modTimeStamp ); } @@ -1366,6 +1380,11 @@ failure: FramesData::FramesData(const Glib::ustring& fname, std::unique_ptr rml, bool firstFrameOnly) : iptc(nullptr), dcrawFrameCount(0) { + GStatBuf statbuf = {}; + g_stat(fname.c_str(), &statbuf); + modTimeStamp = statbuf.st_mtime; + modTime = timeFromTS(modTimeStamp); + if (rml && (rml->exifBase >= 0 || rml->ciffBase >= 0)) { FILE* f = g_fopen(fname.c_str(), "rb"); @@ -1384,7 +1403,7 @@ FramesData::FramesData(const Glib::ustring& fname, std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); + frames.push_back(std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0), modTimeStamp))); } for (auto currRoot : roots) { @@ -1410,7 +1429,7 @@ FramesData::FramesData(const Glib::ustring& fname, std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); + frames.push_back(std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0), modTimeStamp))); } rewind(exifManager.f); // Not sure this is necessary @@ -1430,7 +1449,7 @@ FramesData::FramesData(const Glib::ustring& fname, std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); + frames.push_back(std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0), modTimeStamp))); } for (auto currRoot : roots) { diff --git a/rtengine/imagedata.h b/rtengine/imagedata.h index 4bf9bdf5b..752fafab3 100644 --- a/rtengine/imagedata.h +++ b/rtengine/imagedata.h @@ -72,7 +72,7 @@ protected: public: - FrameData (rtexif::TagDirectory* frameRootDir, rtexif::TagDirectory* rootDir, rtexif::TagDirectory* firstRootDir); + FrameData (rtexif::TagDirectory* frameRootDir, rtexif::TagDirectory* rootDir, rtexif::TagDirectory* firstRootDir, time_t ts = 0); virtual ~FrameData (); bool getPixelShift () const; @@ -109,6 +109,8 @@ private: std::vector roots; IptcData* iptc; unsigned int dcrawFrameCount; + struct tm modTime; + time_t modTimeStamp; public: explicit FramesData (const Glib::ustring& fname, std::unique_ptr rml = nullptr, bool firstFrameOnly = false); diff --git a/rtgui/batchqueueentry.cc b/rtgui/batchqueueentry.cc index 31a6f40c7..9fe4dd605 100644 --- a/rtgui/batchqueueentry.cc +++ b/rtgui/batchqueueentry.cc @@ -34,7 +34,7 @@ bool BatchQueueEntry::iconsLoaded(false); Glib::RefPtr BatchQueueEntry::savedAsIcon; BatchQueueEntry::BatchQueueEntry (rtengine::ProcessingJob* pjob, const rtengine::procparams::ProcParams& pparams, Glib::ustring fname, int prevw, int prevh, Thumbnail* thm, bool overwrite) : - ThumbBrowserEntryBase(fname), + ThumbBrowserEntryBase(fname, thm), opreview(nullptr), origpw(prevw), origph(prevh), diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index 66c84d86e..ac4a27dec 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -167,6 +167,41 @@ FileBrowser::FileBrowser () : pmenu->attach (*Gtk::manage(selall = new Gtk::MenuItem (M("FILEBROWSER_POPUPSELECTALL"))), 0, 1, p, p + 1); p++; + /*********************** + * sort + ***********************/ + const std::array cnameSortOrders = { + M("SORT_ASCENDING"), + M("SORT_DESCENDING"), + }; + + const std::array cnameSortMethods = { + M("SORT_BY_NAME"), + M("SORT_BY_DATE"), + M("SORT_BY_EXIF"), + M("SORT_BY_RANK"), + M("SORT_BY_LABEL"), + }; + + pmenu->attach (*Gtk::manage(menuSort = new Gtk::MenuItem (M("FILEBROWSER_POPUPSORTBY"))), 0, 1, p, p + 1); + p++; + Gtk::Menu* submenuSort = Gtk::manage (new Gtk::Menu ()); + Gtk::RadioButtonGroup sortOrderGroup, sortMethodGroup; + for (size_t i = 0; i < cnameSortOrders.size(); i++) { + submenuSort->attach (*Gtk::manage(sortOrder[i] = new Gtk::RadioMenuItem (sortOrderGroup, cnameSortOrders[i])), 0, 1, p, p + 1); + p++; + sortOrder[i]->set_active (i == options.sortDescending); + } + submenuSort->attach (*Gtk::manage(new Gtk::SeparatorMenuItem ()), 0, 1, p, p + 1); + p++; + for (size_t i = 0; i < cnameSortMethods.size(); i++) { + submenuSort->attach (*Gtk::manage(sortMethod[i] = new Gtk::RadioMenuItem (sortMethodGroup, cnameSortMethods[i])), 0, 1, p, p + 1); + p++; + sortMethod[i]->set_active (i == options.sortMethod); + } + submenuSort->show_all (); + menuSort->set_submenu (*submenuSort); + /*********************** * rank ***********************/ @@ -427,6 +462,14 @@ FileBrowser::FileBrowser () : inspect->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), inspect)); } + for (int i = 0; i < 2; i++) { + sortOrder[i]->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), sortOrder[i])); + } + + for (int i = 0; i < Options::SORT_METHOD_COUNT; i++) { + sortMethod[i]->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), sortMethod[i])); + } + for (int i = 0; i < 6; i++) { rank[i]->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), rank[i])); } @@ -610,27 +653,7 @@ void FileBrowser::addEntry_ (FileBrowserEntry* entry) entry->getThumbButtonSet()->setButtonListener(this); entry->resize(getThumbnailHeight()); entry->filtered = !checkFilter(entry); - - // find place in abc order - { - MYWRITERLOCK(l, entryRW); - - fd.insert( - std::lower_bound( - fd.begin(), - fd.end(), - entry, - [](const ThumbBrowserEntryBase* a, const ThumbBrowserEntryBase* b) - { - return *a < *b; - } - ), - entry - ); - - initEntry(entry); - } - redraw(entry); + insertEntry(entry); } FileBrowserEntry* FileBrowser::delEntry (const Glib::ustring& fname) @@ -724,6 +747,18 @@ void FileBrowser::menuItemActivated (Gtk::MenuItem* m) return; } + for (int i = 0; i < 2; i++) + if (m == sortOrder[i]) { + sortOrderRequested (i); + return; + } + + for (int i = 0; i < Options::SORT_METHOD_COUNT; i++) + if (m == sortMethod[i]) { + sortMethodRequested (i); + return; + } + for (int i = 0; i < 6; i++) if (m == rank[i]) { rankingRequested (mselected, i); @@ -1632,6 +1667,18 @@ void FileBrowser::fromTrashRequested (std::vector tbe) applyFilter (filter); } +void FileBrowser::sortMethodRequested (int method) +{ + options.sortMethod = Options::SortMethod(method); + resort (); +} + +void FileBrowser::sortOrderRequested (int order) +{ + options.sortDescending = !!order; + resort (); +} + void FileBrowser::rankingRequested (std::vector tbe, int rank) { diff --git a/rtgui/filebrowser.h b/rtgui/filebrowser.h index 4602ba9bb..0df1cf9eb 100644 --- a/rtgui/filebrowser.h +++ b/rtgui/filebrowser.h @@ -83,9 +83,12 @@ protected: Gtk::MenuItem* open; Gtk::MenuItem* inspect; Gtk::MenuItem* selall; + Gtk::RadioMenuItem* sortMethod[Options::SORT_METHOD_COUNT]; + Gtk::RadioMenuItem* sortOrder[2]; Gtk::MenuItem* copyTo; Gtk::MenuItem* moveTo; + Gtk::MenuItem* menuSort; Gtk::MenuItem* menuRank; Gtk::MenuItem* menuLabel; Gtk::MenuItem* menuFileOperations; @@ -131,6 +134,8 @@ protected: void toTrashRequested (std::vector tbe); void fromTrashRequested (std::vector tbe); + void sortMethodRequested (int method); + void sortOrderRequested (int order); void rankingRequested (std::vector tbe, int rank); void colorlabelRequested (std::vector tbe, int colorlabel); void requestRanking (int rank); diff --git a/rtgui/filebrowserentry.cc b/rtgui/filebrowserentry.cc index bf3f11a79..b89fe340d 100644 --- a/rtgui/filebrowserentry.cc +++ b/rtgui/filebrowserentry.cc @@ -45,10 +45,8 @@ Glib::RefPtr FileBrowserEntry::hdr; Glib::RefPtr FileBrowserEntry::ps; FileBrowserEntry::FileBrowserEntry (Thumbnail* thm, const Glib::ustring& fname) - : ThumbBrowserEntryBase (fname), wasInside(false), iatlistener(nullptr), press_x(0), press_y(0), action_x(0), action_y(0), rot_deg(0.0), landscape(true), cropParams(new rtengine::procparams::CropParams), cropgl(nullptr), state(SNormal), crop_custom_ratio(0.f) + : ThumbBrowserEntryBase (fname, thm), wasInside(false), iatlistener(nullptr), press_x(0), press_y(0), action_x(0), action_y(0), rot_deg(0.0), landscape(true), cropParams(new rtengine::procparams::CropParams), cropgl(nullptr), state(SNormal), crop_custom_ratio(0.f) { - thumbnail = thm; - feih = new FileBrowserEntryIdleHelper; feih->fbentry = this; feih->destroyed = false; diff --git a/rtgui/options.cc b/rtgui/options.cc index a1cc88c03..b2ef17d77 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -685,6 +685,8 @@ void Options::setDefaults() lastICCProfCreatorDir = ""; gimpPluginShowInfoDialog = true; maxRecentFolders = 15; + sortMethod = SORT_BY_NAME; + sortDescending = false; rtSettings.lensfunDbDirectory = ""; // set also in main.cc and main-cli.cc cropGuides = CROP_GUIDE_FULL; cropAutoFit = false; @@ -1150,6 +1152,19 @@ void Options::readFromFile(Glib::ustring fname) if (keyFile.has_key("File Browser", "RecentFolders")) { recentFolders = keyFile.get_string_list("File Browser", "RecentFolders"); } + + if (keyFile.has_key("File Browser", "SortMethod")) { + int v = keyFile.get_integer("File Browser", "SortMethod"); + if (v < int(0) || v >= int(SORT_METHOD_COUNT)) { + sortMethod = SORT_BY_NAME; + } else { + sortMethod = SortMethod(v); + } + } + + if (keyFile.has_key("File Browser", "SortDescending")) { + sortDescending = keyFile.get_boolean("File Browser", "SortDescending"); + } } if (keyFile.has_group("Clipping Indication")) { @@ -2217,6 +2232,8 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_string_list("File Browser", "RecentFolders", temp); } + keyFile.set_integer("File Browser", "SortMethod", sortMethod); + keyFile.set_boolean("File Browser", "SortDescending", sortDescending); keyFile.set_integer("Clipping Indication", "HighlightThreshold", highlightThreshold); keyFile.set_integer("Clipping Indication", "ShadowThreshold", shadowThreshold); keyFile.set_boolean("Clipping Indication", "BlinkClipped", blinkClipped); diff --git a/rtgui/options.h b/rtgui/options.h index bc5e41c91..d7523e699 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -452,6 +452,17 @@ public: size_t maxRecentFolders; // max. number of recent folders stored in options file std::vector recentFolders; // List containing all recent folders + enum SortMethod { + SORT_BY_NAME, + SORT_BY_DATE, + SORT_BY_EXIF, + SORT_BY_RANK, + SORT_BY_LABEL, + SORT_METHOD_COUNT, + }; + SortMethod sortMethod; // remembers current state of file browser + bool sortDescending; + Options (); diff --git a/rtgui/thumbbrowserbase.cc b/rtgui/thumbbrowserbase.cc index 06c662e51..8f3499c2a 100644 --- a/rtgui/thumbbrowserbase.cc +++ b/rtgui/thumbbrowserbase.cc @@ -1091,6 +1091,25 @@ bool ThumbBrowserBase::Internal::on_scroll_event (GdkEventScroll* event) } +void ThumbBrowserBase::resort () +{ + { + MYWRITERLOCK(l, entryRW); + + std::sort( + fd.begin(), + fd.end(), + [](const ThumbBrowserEntryBase* a, const ThumbBrowserEntryBase* b) + { + bool lt = a->compare(*b, options.sortMethod); + return options.sortDescending ? !lt : lt; + } + ); + } + + redraw (); +} + void ThumbBrowserBase::redraw (ThumbBrowserEntryBase* entry) { @@ -1218,9 +1237,30 @@ void ThumbBrowserBase::enableTabMode(bool enable) } } -void ThumbBrowserBase::initEntry (ThumbBrowserEntryBase* entry) +void ThumbBrowserBase::insertEntry (ThumbBrowserEntryBase* entry) { - entry->setOffset ((int)(hscroll.get_value()), (int)(vscroll.get_value())); + // find place in sort order + { + MYWRITERLOCK(l, entryRW); + + fd.insert( + std::lower_bound( + fd.begin(), + fd.end(), + entry, + [](const ThumbBrowserEntryBase* a, const ThumbBrowserEntryBase* b) + { + bool lt = a->compare(*b, options.sortMethod); + return options.sortDescending ? !lt : lt; + } + ), + entry + ); + + entry->setOffset ((int)(hscroll.get_value()), (int)(vscroll.get_value())); + } + + redraw (); } void ThumbBrowserBase::getScrollPosition (double& h, double& v) diff --git a/rtgui/thumbbrowserbase.h b/rtgui/thumbbrowserbase.h index 2d41cdfab..8c1ec49c8 100644 --- a/rtgui/thumbbrowserbase.h +++ b/rtgui/thumbbrowserbase.h @@ -208,12 +208,13 @@ public: return fd; } void on_style_updated () override; + void resort (); // re-apply sort method void redraw (ThumbBrowserEntryBase* entry = nullptr); // arrange files and draw area void refreshThumbImages (); // refresh thumbnail sizes, re-generate thumbnail images, arrange and draw void refreshQuickThumbImages (); // refresh thumbnail sizes, re-generate thumbnail images, arrange and draw void refreshEditedState (const std::set& efiles); - void initEntry (ThumbBrowserEntryBase* entry); + void insertEntry (ThumbBrowserEntryBase* entry); void getScrollPosition (double& h, double& v); void setScrollPosition (double h, double v); diff --git a/rtgui/thumbbrowserentrybase.cc b/rtgui/thumbbrowserentrybase.cc index 306b491be..3d1e6bdc4 100644 --- a/rtgui/thumbbrowserentrybase.cc +++ b/rtgui/thumbbrowserentrybase.cc @@ -119,7 +119,7 @@ Glib::ustring getPaddedName(const Glib::ustring& name) } -ThumbBrowserEntryBase::ThumbBrowserEntryBase (const Glib::ustring& fname) : +ThumbBrowserEntryBase::ThumbBrowserEntryBase (const Glib::ustring& fname, Thumbnail *thm) : fnlabw(0), fnlabh(0), dtlabw(0), @@ -153,7 +153,8 @@ ThumbBrowserEntryBase::ThumbBrowserEntryBase (const Glib::ustring& fname) : bbPreview(nullptr), cursor_type(CSUndefined), collate_name(getPaddedName(dispname).casefold_collate_key()), - thumbnail(nullptr), + collate_exif(getPaddedName(thm->getExifString()).casefold_collate_key()), + thumbnail(thm), filename(fname), selected(false), drawable(false), diff --git a/rtgui/thumbbrowserentrybase.h b/rtgui/thumbbrowserentrybase.h index 764f806fd..3db03a96e 100644 --- a/rtgui/thumbbrowserentrybase.h +++ b/rtgui/thumbbrowserentrybase.h @@ -26,6 +26,8 @@ #include "guiutils.h" #include "lwbuttonset.h" #include "threadutils.h" +#include "options.h" +#include "thumbnail.h" #include "../rtengine/coord2d.h" @@ -95,6 +97,7 @@ protected: private: const std::string collate_name; + const std::string collate_exif; public: @@ -117,7 +120,7 @@ public: bool updatepriority; eWithFilename withFilename; - explicit ThumbBrowserEntryBase (const Glib::ustring& fname); + explicit ThumbBrowserEntryBase (const Glib::ustring& fname, Thumbnail *thm); virtual ~ThumbBrowserEntryBase (); void setParent (ThumbBrowserBase* l) @@ -174,9 +177,32 @@ public: void setPosition (int x, int y, int w, int h); void setOffset (int x, int y); - bool operator <(const ThumbBrowserEntryBase& other) const + bool compare (const ThumbBrowserEntryBase& other, Options::SortMethod method) const { - return collate_name < other.collate_name; + int cmp = 0; + switch (method){ + case Options::SORT_BY_NAME: + return collate_name < other.collate_name; + case Options::SORT_BY_DATE: + cmp = thumbnail->getDateTime().compare(other.thumbnail->getDateTime()); + break; + case Options::SORT_BY_EXIF: + cmp = collate_exif.compare(other.collate_exif); + break; + case Options::SORT_BY_RANK: + cmp = thumbnail->getRank() - other.thumbnail->getRank(); + break; + case Options::SORT_BY_LABEL: + cmp = thumbnail->getColorLabel() - other.thumbnail->getColorLabel(); + break; + case Options::SORT_METHOD_COUNT: abort(); + } + + // Always fall back to sorting by name + if (!cmp) + cmp = collate_name.compare(other.collate_name); + + return cmp < 0; } virtual void refreshThumbnailImage () = 0; diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index 2baf03247..30766ebc9 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -31,6 +31,7 @@ #include "../rtengine/procparams.h" #include "../rtengine/rtthumbnail.h" #include +#include #include "../rtengine/dynamicprofile.h" #include "../rtengine/profilestore.h" @@ -718,11 +719,44 @@ rtengine::IImage8* Thumbnail::upgradeThumbImage (const rtengine::procparams::Pro void Thumbnail::generateExifDateTimeStrings () { + if (cfs.timeValid) { + std::string dateFormat = options.dateFormat; + std::ostringstream ostr; + bool spec = false; - exifString = ""; - dateTimeString = ""; + for (size_t i = 0; i < dateFormat.size(); i++) + if (spec && dateFormat[i] == 'y') { + ostr << cfs.year; + spec = false; + } else if (spec && dateFormat[i] == 'm') { + ostr << (int)cfs.month; + spec = false; + } else if (spec && dateFormat[i] == 'd') { + ostr << (int)cfs.day; + spec = false; + } else if (dateFormat[i] == '%') { + spec = true; + } else { + ostr << (char)dateFormat[i]; + spec = false; + } + + ostr << " " << (int)cfs.hour; + ostr << ":" << std::setw(2) << std::setfill('0') << (int)cfs.min; + ostr << ":" << std::setw(2) << std::setfill('0') << (int)cfs.sec; + + dateTimeString = ostr.str (); + dateTime = Glib::DateTime::create_local(cfs.year, cfs.month, cfs.day, + cfs.hour, cfs.min, cfs.sec); + } + + if (!dateTime.gobj() || !cfs.timeValid) { + dateTimeString = ""; + dateTime = Glib::DateTime::create_now_utc(0); + } if (!cfs.exifValid) { + exifString = ""; return; } @@ -731,33 +765,6 @@ void Thumbnail::generateExifDateTimeStrings () if (options.fbShowExpComp && cfs.expcomp != "0.00" && !cfs.expcomp.empty()) { // don't show exposure compensation if it is 0.00EV;old cache files do not have ExpComp, so value will not be displayed. exifString = Glib::ustring::compose ("%1 %2EV", exifString, cfs.expcomp); // append exposure compensation to exifString } - - std::string dateFormat = options.dateFormat; - std::ostringstream ostr; - bool spec = false; - - for (size_t i = 0; i < dateFormat.size(); i++) - if (spec && dateFormat[i] == 'y') { - ostr << cfs.year; - spec = false; - } else if (spec && dateFormat[i] == 'm') { - ostr << (int)cfs.month; - spec = false; - } else if (spec && dateFormat[i] == 'd') { - ostr << (int)cfs.day; - spec = false; - } else if (dateFormat[i] == '%') { - spec = true; - } else { - ostr << (char)dateFormat[i]; - spec = false; - } - - ostr << " " << (int)cfs.hour; - ostr << ":" << std::setw(2) << std::setfill('0') << (int)cfs.min; - ostr << ":" << std::setw(2) << std::setfill('0') << (int)cfs.sec; - - dateTimeString = ostr.str (); } const Glib::ustring& Thumbnail::getExifString () const @@ -772,6 +779,12 @@ const Glib::ustring& Thumbnail::getDateTimeString () const return dateTimeString; } +const Glib::DateTime& Thumbnail::getDateTime () const +{ + + return dateTime; +} + void Thumbnail::getAutoWB (double& temp, double& green, double equal, double tempBias) { if (cfs.redAWBMul != -1.0) { @@ -802,6 +815,16 @@ int Thumbnail::infoFromImage (const Glib::ustring& fname, std::unique_ptrgetDateTimeAsTS() > 0) { + cfs.year = 1900 + idata->getDateTime().tm_year; + cfs.month = idata->getDateTime().tm_mon + 1; + cfs.day = idata->getDateTime().tm_mday; + cfs.hour = idata->getDateTime().tm_hour; + cfs.min = idata->getDateTime().tm_min; + cfs.sec = idata->getDateTime().tm_sec; + cfs.timeValid = true; + } + if (idata->hasExif()) { cfs.shutter = idata->getShutterSpeed (); cfs.fnumber = idata->getFNumber (); @@ -814,18 +837,11 @@ int Thumbnail::infoFromImage (const Glib::ustring& fname, std::unique_ptrgetPixelShift (); cfs.frameCount = idata->getFrameCount (); cfs.sampleFormat = idata->getSampleFormat (); - cfs.year = 1900 + idata->getDateTime().tm_year; - cfs.month = idata->getDateTime().tm_mon + 1; - cfs.day = idata->getDateTime().tm_mday; - cfs.hour = idata->getDateTime().tm_hour; - cfs.min = idata->getDateTime().tm_min; - cfs.sec = idata->getDateTime().tm_sec; - cfs.timeValid = true; - cfs.exifValid = true; cfs.lens = idata->getLens(); cfs.camMake = idata->getMake(); cfs.camModel = idata->getModel(); cfs.rating = idata->getRating(); + cfs.exifValid = true; if (idata->getOrientation() == "Rotate 90 CW") { deg = 90; diff --git a/rtgui/thumbnail.h b/rtgui/thumbnail.h index cda69f030..491151028 100644 --- a/rtgui/thumbnail.h +++ b/rtgui/thumbnail.h @@ -22,6 +22,7 @@ #include #include +#include #include "cacheimagedata.h" #include "threadutils.h" @@ -73,6 +74,7 @@ class Thumbnail // exif & date/time strings Glib::ustring exifString; Glib::ustring dateTimeString; + Glib::DateTime dateTime; bool initial_; @@ -124,6 +126,7 @@ public: const Glib::ustring& getExifString () const; const Glib::ustring& getDateTimeString () const; + const Glib::DateTime& getDateTime () const; void getCamWB (double& temp, double& green) const; void getAutoWB (double& temp, double& green, double equal, double tempBias); void getSpotWB (int x, int y, int rect, double& temp, double& green);