/* * This file is part of RawTherapee. * * Copyright (c) 2004-2010 Gabor Horvath * Copyright (c) 2011 Oliver Duis * Copyright (c) 2011 Michael Ezra * * 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 "filebrowser.h" #include #include "options.h" #include "multilangmgr.h" #include "clipboard.h" #include "procparamchangers.h" #include "batchqueue.h" #include "../rtengine/dfmanager.h" #include "../rtengine/ffmanager.h" #include "rtimage.h" #include "threadutils.h" extern Options options; FileBrowser::FileBrowser () : tbl(NULL),numFiltered(0), partialPasteDlg(M("PARTIALPASTE_DIALOGLABEL")) { fbih = new FileBrowserIdleHelper; fbih->fbrowser = this; fbih->destroyed = false; fbih->pending = 0; profileStore.addListener(this); int p = 0; pmenu = new Gtk::Menu (); pmenu->attach (*Gtk::manage(open = new Gtk::MenuItem (M("FILEBROWSER_POPUPOPEN"))), 0, 1, p, p+1); p++; pmenu->attach (*Gtk::manage(develop = new Gtk::ImageMenuItem (M("FILEBROWSER_POPUPPROCESS"))), 0, 1, p, p+1); p++; develop->set_image(*Gtk::manage(new RTImage ("processing.png"))); pmenu->attach (*Gtk::manage(developfast = new Gtk::ImageMenuItem (M("FILEBROWSER_POPUPPROCESSFAST"))), 0, 1, p, p+1); p++; pmenu->attach (*Gtk::manage(new Gtk::SeparatorMenuItem ()), 0, 1, p, p+1); p++; pmenu->attach (*Gtk::manage(selall = new Gtk::MenuItem (M("FILEBROWSER_POPUPSELECTALL"))), 0, 1, p, p+1); p++; /*********************** * rank ***********************/ if (options.menuGroupRank){ pmenu->attach (*Gtk::manage(menuRank = new Gtk::MenuItem (M("FILEBROWSER_POPUPRANK"))), 0, 1, p, p+1); p++; Gtk::Menu* submenuRank = Gtk::manage (new Gtk::Menu ()); submenuRank->attach (*Gtk::manage(rank[0] = new Gtk::MenuItem (M("FILEBROWSER_POPUPUNRANK"))), 0, 1, p, p+1); p++; for (int i=1; i<=5; i++){ submenuRank->attach (*Gtk::manage(rank[i] = new Gtk::MenuItem (M(Glib::ustring::compose("%1%2","FILEBROWSER_POPUPRANK",i)))), 0, 1, p, p+1); p++; } submenuRank->show_all (); menuRank->set_submenu (*submenuRank); } else{ pmenu->attach (*Gtk::manage(rank[0] = new Gtk::MenuItem (M("FILEBROWSER_POPUPUNRANK"))), 0, 1, p, p+1); p++; for (int i=1; i<=5; i++){ pmenu->attach (*Gtk::manage(rank[i] = new Gtk::MenuItem (M(Glib::ustring::compose("%1%2","FILEBROWSER_POPUPRANK",i)))), 0, 1, p, p+1); p++; } pmenu->attach (*Gtk::manage(new Gtk::SeparatorMenuItem ()), 0, 1, p, p+1); p++; } if (!options.menuGroupRank || !options.menuGroupLabel) // separate Rank and Color Labels if either is not grouped pmenu->attach (*Gtk::manage(new Gtk::SeparatorMenuItem ()), 0, 1, p, p+1); p++; /*********************** * color labels ***********************/ if (options.menuGroupLabel){ pmenu->attach (*Gtk::manage(menuLabel = new Gtk::MenuItem (M("FILEBROWSER_POPUPCOLORLABEL"))), 0, 1, p, p+1); p++; Gtk::Menu* submenuLabel = Gtk::manage (new Gtk::Menu ()); for (int i=0; i<=5; i++){ submenuLabel->attach (*Gtk::manage(colorlabel[i] = new Gtk::ImageMenuItem (M(Glib::ustring::compose("%1%2","FILEBROWSER_POPUPCOLORLABEL",i)))), 0, 1, p, p+1); p++; } submenuLabel->show_all (); menuLabel->set_submenu (*submenuLabel); } else{ for (int i=0; i<=5; i++){ pmenu->attach (*Gtk::manage(colorlabel[i] = new Gtk::ImageMenuItem (M(Glib::ustring::compose("%1%2","FILEBROWSER_POPUPCOLORLABEL",i)))), 0, 1, p, p+1); p++; } } //set color label images colorlabel[0]->set_image(*Gtk::manage(new RTImage ("cglabel0.png"))); for (int i=1; i<=5; i++){ colorlabel[i]->set_image(*Gtk::manage(new RTImage (Glib::ustring::compose("%1%2%3","clabel",i,".png")))); } pmenu->attach (*Gtk::manage(new Gtk::SeparatorMenuItem ()), 0, 1, p, p+1); p++; /*********************** * external programs * *********************/ #if defined(WIN32) && defined(PROTECT_VECTORS) Gtk::manage(miOpenDefaultViewer=new Gtk::MenuItem (M("FILEBROWSER_OPENDEFAULTVIEWER"))); #else miOpenDefaultViewer=NULL; #endif // Build a list of menu items mMenuExtProgs.clear(); amiExtProg=NULL; for (std::list::iterator it=extProgStore->lActions.begin();it!=extProgStore->lActions.end();it++) { ExtProgAction* pAct=*it; if (pAct->target==1 || pAct->target==2) mMenuExtProgs[pAct->GetFullName()]=pAct; } // Attach them to menu if (!mMenuExtProgs.empty() || miOpenDefaultViewer!=NULL) { amiExtProg=new Gtk::MenuItem*[mMenuExtProgs.size()]; int itemNo=0; if (options.menuGroupExtProg) { pmenu->attach (*Gtk::manage(menuExtProg = new Gtk::MenuItem (M("FILEBROWSER_EXTPROGMENU"))), 0, 1, p, p+1); p++; Gtk::Menu* submenuExtProg = Gtk::manage (new Gtk::Menu()); if (miOpenDefaultViewer!=NULL) { submenuExtProg->attach (*miOpenDefaultViewer, 0, 1, p, p+1); p++; } for (std::map::iterator it=mMenuExtProgs.begin();it!=mMenuExtProgs.end();it++,itemNo++) { submenuExtProg->attach (*Gtk::manage(amiExtProg[itemNo] = new Gtk::MenuItem ((*it).first)), 0, 1, p, p+1); p++; } submenuExtProg->show_all (); menuExtProg->set_submenu (*submenuExtProg); } else { if (miOpenDefaultViewer!=NULL) { pmenu->attach (*miOpenDefaultViewer, 0, 1, p, p+1); p++; } for (std::map::iterator it=mMenuExtProgs.begin();it!=mMenuExtProgs.end();it++,itemNo++) { pmenu->attach (*Gtk::manage(amiExtProg[itemNo] = new Gtk::MenuItem ((*it).first)), 0, 1, p, p+1); p++; } } pmenu->attach (*Gtk::manage(new Gtk::SeparatorMenuItem ()), 0, 1, p, p+1); p++; } /*********************** * File Operations * *********************/ if (options.menuGroupFileOperations){ pmenu->attach (*Gtk::manage(menuFileOperations = new Gtk::MenuItem (M("FILEBROWSER_POPUPFILEOPERATIONS"))), 0, 1, p, p+1); p++; Gtk::Menu* submenuFileOperations = Gtk::manage (new Gtk::Menu ()); submenuFileOperations->attach (*Gtk::manage(trash = new Gtk::MenuItem (M("FILEBROWSER_POPUPTRASH"))), 0, 1, p, p+1); p++; submenuFileOperations->attach (*Gtk::manage(untrash = new Gtk::MenuItem (M("FILEBROWSER_POPUPUNTRASH"))), 0, 1, p, p+1); p++; submenuFileOperations->attach (*Gtk::manage(new Gtk::SeparatorMenuItem ()), 0, 1, p, p+1); p++; submenuFileOperations->attach (*Gtk::manage(rename = new Gtk::MenuItem (M("FILEBROWSER_POPUPRENAME"))), 0, 1, p, p+1); p++; submenuFileOperations->attach (*Gtk::manage(remove = new Gtk::MenuItem (M("FILEBROWSER_POPUPREMOVE"))), 0, 1, p, p+1); p++; submenuFileOperations->attach (*Gtk::manage(removeInclProc = new Gtk::MenuItem (M("FILEBROWSER_POPUPREMOVEINCLPROC"))), 0, 1, p, p+1); p++; submenuFileOperations->attach (*Gtk::manage(new Gtk::SeparatorMenuItem ()), 0, 1, p, p+1); p++; submenuFileOperations->attach (*Gtk::manage(copyTo = new Gtk::MenuItem (M("FILEBROWSER_POPUPCOPYTO"))), 0, 1, p, p+1); p++; submenuFileOperations->attach (*Gtk::manage(moveTo = new Gtk::MenuItem (M("FILEBROWSER_POPUPMOVETO"))), 0, 1, p, p+1); p++; submenuFileOperations->show_all (); menuFileOperations->set_submenu (*submenuFileOperations); } else{ pmenu->attach (*Gtk::manage(trash = new Gtk::MenuItem (M("FILEBROWSER_POPUPTRASH"))), 0, 1, p, p+1); p++; pmenu->attach (*Gtk::manage(untrash = new Gtk::MenuItem (M("FILEBROWSER_POPUPUNTRASH"))), 0, 1, p, p+1); p++; pmenu->attach (*Gtk::manage(new Gtk::SeparatorMenuItem ()), 0, 1, p, p+1); p++; pmenu->attach (*Gtk::manage(rename = new Gtk::MenuItem (M("FILEBROWSER_POPUPRENAME"))), 0, 1, p, p+1); p++; pmenu->attach (*Gtk::manage(remove = new Gtk::MenuItem (M("FILEBROWSER_POPUPREMOVE"))), 0, 1, p, p+1); p++; pmenu->attach (*Gtk::manage(removeInclProc = new Gtk::MenuItem (M("FILEBROWSER_POPUPREMOVEINCLPROC"))), 0, 1, p, p+1); p++; pmenu->attach (*Gtk::manage(new Gtk::SeparatorMenuItem ()), 0, 1, p, p+1); p++; pmenu->attach (*Gtk::manage(copyTo = new Gtk::MenuItem (M("FILEBROWSER_POPUPCOPYTO"))), 0, 1, p, p+1); p++; pmenu->attach (*Gtk::manage(moveTo = new Gtk::MenuItem (M("FILEBROWSER_POPUPMOVETO"))), 0, 1, p, p+1); p++; } pmenu->attach (*Gtk::manage(new Gtk::SeparatorMenuItem ()), 0, 1, p, p+1); p++; /*********************** * Profile Operations * *********************/ if (options.menuGroupProfileOperations){ pmenu->attach (*Gtk::manage(menuProfileOperations = new Gtk::ImageMenuItem (M("FILEBROWSER_POPUPPROFILEOPERATIONS"))), 0, 1, p, p+1); p++; menuProfileOperations->set_image(*Gtk::manage(new RTImage ("logoicon-wind.png"))); Gtk::Menu* submenuProfileOperations = Gtk::manage (new Gtk::Menu ()); submenuProfileOperations->attach (*Gtk::manage(copyprof = new Gtk::MenuItem (M("FILEBROWSER_COPYPROFILE"))), 0, 1, p, p+1); p++; submenuProfileOperations->attach (*Gtk::manage(pasteprof = new Gtk::MenuItem (M("FILEBROWSER_PASTEPROFILE"))), 0, 1, p, p+1); p++; submenuProfileOperations->attach (*Gtk::manage(partpasteprof = new Gtk::MenuItem (M("FILEBROWSER_PARTIALPASTEPROFILE"))), 0, 1, p, p+1); p++; submenuProfileOperations->attach (*Gtk::manage(applyprof = new Gtk::MenuItem (M("FILEBROWSER_APPLYPROFILE"))), 0, 1, p, p+1); p++; submenuProfileOperations->attach (*Gtk::manage(applypartprof = new Gtk::MenuItem (M("FILEBROWSER_APPLYPROFILE_PARTIAL"))), 0, 1, p, p+1); p++; submenuProfileOperations->attach (*Gtk::manage(execcustprof = new Gtk::MenuItem (M("FILEBROWSER_EXEC_CPB"))), 0, 1, p, p+1); p++; submenuProfileOperations->attach (*Gtk::manage(clearprof = new Gtk::MenuItem (M("FILEBROWSER_CLEARPROFILE"))), 0, 1, p, p+1); p++; submenuProfileOperations->show_all (); menuProfileOperations->set_submenu (*submenuProfileOperations); } else{ pmenu->attach (*Gtk::manage(copyprof = new Gtk::MenuItem (M("FILEBROWSER_COPYPROFILE"))), 0, 1, p, p+1); p++; pmenu->attach (*Gtk::manage(pasteprof = new Gtk::MenuItem (M("FILEBROWSER_PASTEPROFILE"))), 0, 1, p, p+1); p++; pmenu->attach (*Gtk::manage(partpasteprof = new Gtk::MenuItem (M("FILEBROWSER_PARTIALPASTEPROFILE"))), 0, 1, p, p+1); p++; pmenu->attach (*Gtk::manage(applyprof = new Gtk::MenuItem (M("FILEBROWSER_APPLYPROFILE"))), 0, 1, p, p+1); p++; pmenu->attach (*Gtk::manage(applypartprof = new Gtk::MenuItem (M("FILEBROWSER_APPLYPROFILE_PARTIAL"))), 0, 1, p, p+1); p++; pmenu->attach (*Gtk::manage(execcustprof = new Gtk::MenuItem (M("FILEBROWSER_EXEC_CPB"))), 0, 1, p, p+1); p++; pmenu->attach (*Gtk::manage(clearprof = new Gtk::MenuItem (M("FILEBROWSER_CLEARPROFILE"))), 0, 1, p, p+1); p++; } pmenu->attach (*Gtk::manage(new Gtk::SeparatorMenuItem ()), 0, 1, p, p+1); p++; pmenu->attach (*Gtk::manage(menuDF = new Gtk::MenuItem (M("FILEBROWSER_DARKFRAME"))), 0, 1, p, p+1); p++; pmenu->attach (*Gtk::manage(menuFF = new Gtk::MenuItem (M("FILEBROWSER_FLATFIELD"))), 0, 1, p, p+1); p++; pmenu->attach (*Gtk::manage(new Gtk::SeparatorMenuItem ()), 0, 1, p, p+1); p++; pmenu->attach (*Gtk::manage(cachemenu = new Gtk::MenuItem (M("FILEBROWSER_CACHE"))), 0, 1, p, p+1); p++; pmenu->show_all (); /*********************** * Accelerators * *********************/ pmaccelgroup = Gtk::AccelGroup::create (); pmenu->set_accel_group (pmaccelgroup); selall->add_accelerator ("activate", pmenu->get_accel_group(), GDK_a, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE); trash->add_accelerator ("activate", pmenu->get_accel_group(), GDK_Delete, (Gdk::ModifierType)0, Gtk::ACCEL_VISIBLE); untrash->add_accelerator ("activate", pmenu->get_accel_group(), GDK_Delete, Gdk::SHIFT_MASK, Gtk::ACCEL_VISIBLE); open->add_accelerator ("activate", pmenu->get_accel_group(), GDK_Return, (Gdk::ModifierType)0, Gtk::ACCEL_VISIBLE); develop->add_accelerator ("activate", pmenu->get_accel_group(), GDK_B, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE); copyprof->add_accelerator ("activate", pmenu->get_accel_group(), GDK_C, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE); pasteprof->add_accelerator ("activate", pmenu->get_accel_group(), GDK_V, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE); partpasteprof->add_accelerator ("activate", pmenu->get_accel_group(), GDK_V, Gdk::CONTROL_MASK | Gdk::SHIFT_MASK, Gtk::ACCEL_VISIBLE); // Bind to event handlers open->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), open)); for (int i=0; i<6; i++) rank[i]->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), rank[i])); for (int i=0; i<6; i++) colorlabel[i]->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), colorlabel[i])); for (int i=0; isignal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), amiExtProg[i])); if (miOpenDefaultViewer!=NULL) { miOpenDefaultViewer->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), miOpenDefaultViewer)); } trash->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), trash)); untrash->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), untrash)); develop->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), develop)); developfast->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), developfast)); rename->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), rename)); remove->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), remove)); removeInclProc->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), removeInclProc)); selall->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), selall)); copyTo->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), copyTo)); moveTo->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), moveTo)); copyprof->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), copyprof)); pasteprof->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), pasteprof)); partpasteprof->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), partpasteprof)); applyprof->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), applyprof)); applypartprof->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), applypartprof)); execcustprof->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), execcustprof)); clearprof->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), clearprof)); cachemenu->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), cachemenu)); // A separate pop-up menu for Color Labels int c = 0; pmenuColorLabels = new Gtk::Menu (); for (int i=0; i<=5; i++){ pmenuColorLabels->attach (*Gtk::manage(colorlabel_pop[i] = new Gtk::ImageMenuItem (M(Glib::ustring::compose("%1%2","FILEBROWSER_POPUPCOLORLABEL",i)))), 0, 1, c, c+1); c++; } //set color label images colorlabel_pop[0]->set_image(*Gtk::manage(new RTImage ("cglabel0.png"))); for (int i=1; i<=5; i++){ colorlabel_pop[i]->set_image(*Gtk::manage(new RTImage (Glib::ustring::compose("%1%2%3","clabel",i,".png")))); } pmenuColorLabels->show_all (); // Has to be located after creation of applyprof and applypartprof updateProfileList (); // Bind to event handlers for (int i=0; i<=5; i++) colorlabel_pop[i]->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuColorlabelActivated), colorlabel_pop[i])); } FileBrowser::~FileBrowser () { profileStore.removeListener(this); delete pmenu; delete pmenuColorLabels; delete[] amiExtProg; } void FileBrowser::rightClicked (ThumbBrowserEntryBase* entry) { { #if PROTECT_VECTORS MYREADERLOCK(l, entryRW); #endif trash->set_sensitive (false); untrash->set_sensitive (false); for (size_t i=0; i(selected[i]))->thumbnail->getStage()==1) { untrash->set_sensitive (true); break; } for (size_t i=0; i(selected[i]))->thumbnail->getStage()==0) { trash->set_sensitive (true); break; } pasteprof->set_sensitive (clipboard.hasProcParams()); partpasteprof->set_sensitive (clipboard.hasProcParams()); copyprof->set_sensitive (selected.size()==1); clearprof->set_sensitive (!selected.empty()); } // submenuDF int p = 0; Gtk::Menu* submenuDF = Gtk::manage (new Gtk::Menu ()); submenuDF->attach (*Gtk::manage(selectDF = new Gtk::MenuItem (M("FILEBROWSER_SELECTDARKFRAME"))), 0, 1, p, p+1); p++; submenuDF->attach (*Gtk::manage(autoDF = new Gtk::MenuItem (M("FILEBROWSER_AUTODARKFRAME"))), 0, 1, p, p+1); p++; submenuDF->attach (*Gtk::manage(thisIsDF = new Gtk::MenuItem (M("FILEBROWSER_MOVETODARKFDIR"))), 0, 1, p, p+1); p++; selectDF->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), selectDF)); autoDF->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), autoDF)); thisIsDF->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated),thisIsDF )); submenuDF->show_all (); menuDF->set_submenu (*submenuDF); // submenuFF p = 0; Gtk::Menu* submenuFF = Gtk::manage (new Gtk::Menu ()); submenuFF->attach (*Gtk::manage(selectFF = new Gtk::MenuItem (M("FILEBROWSER_SELECTFLATFIELD"))), 0, 1, p, p+1); p++; submenuFF->attach (*Gtk::manage(autoFF = new Gtk::MenuItem (M("FILEBROWSER_AUTOFLATFIELD"))), 0, 1, p, p+1); p++; submenuFF->attach (*Gtk::manage(thisIsFF = new Gtk::MenuItem (M("FILEBROWSER_MOVETOFLATFIELDDIR"))), 0, 1, p, p+1); p++; selectFF->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), selectFF)); autoFF->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), autoFF)); thisIsFF->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated),thisIsFF )); submenuFF->show_all (); menuFF->set_submenu (*submenuFF); // build cache sub menu p = 0; Gtk::Menu* cachesubmenu = Gtk::manage (new Gtk::Menu ()); cachesubmenu->attach (*Gtk::manage(clearFromCache = new Gtk::MenuItem (M("FILEBROWSER_CACHECLEARFROMPARTIAL"))), 0, 1, p, p+1); p++; cachesubmenu->attach (*Gtk::manage(clearFromCacheFull = new Gtk::MenuItem (M("FILEBROWSER_CACHECLEARFROMFULL"))), 0, 1, p, p+1); p++; clearFromCache->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), clearFromCache)); clearFromCacheFull->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), clearFromCacheFull)); cachesubmenu->show_all (); cachemenu->set_submenu (*cachesubmenu); pmenu->popup (3, this->eventTime); } void FileBrowser::doubleClicked (ThumbBrowserEntryBase* entry) { if (tbl && entry) { std::vector entries; entries.push_back ((static_cast(entry))->thumbnail); tbl->openRequested (entries); } } struct addparams { FileBrowserIdleHelper* fbih; FileBrowserEntry* entry; }; int AddEntryUIThread (void* data) { addparams* ap = static_cast(data); FileBrowserIdleHelper* fbih = ap->fbih; if (fbih->destroyed) { if (fbih->pending == 1) delete fbih; else fbih->pending--; delete ap->entry; delete ap; return 0; } ap->fbih->fbrowser->addEntry_ (ap->entry); delete ap; fbih->pending--; return 0; } void FileBrowser::addEntry (FileBrowserEntry* entry) { fbih->pending++; entry->setParent (this); addparams* ap = new addparams; ap->fbih = fbih; ap->entry = entry; g_idle_add (AddEntryUIThread, ap); } void FileBrowser::addEntry_ (FileBrowserEntry* entry) { GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected entry->selected = false; entry->drawable = false; entry->framed = editedFiles.find (entry->filename)!=editedFiles.end(); // add button set to the thumbbrowserentry entry->addButtonSet (new FileThumbnailButtonSet (entry)); entry->getThumbButtonSet()->setRank (entry->thumbnail->getRank()); entry->getThumbButtonSet()->setColorLabel (entry->thumbnail->getColorLabel()); entry->getThumbButtonSet()->setInTrash (entry->thumbnail->getStage()==1); entry->getThumbButtonSet()->setButtonListener (this); entry->resize (getThumbnailHeight()); // find place in abc order { #if PROTECT_VECTORS MYWRITERLOCK(l, entryRW); #endif std::vector::iterator i = fd.begin(); while (i!=fd.end() && *entry < *((FileBrowserEntry*)*i)) i++; fd.insert (i, entry); initEntry (entry); } redraw (); // newly added item might have been already trashed in a previous session trash_changed().emit(); } FileBrowserEntry* FileBrowser::delEntry (const Glib::ustring& fname) { #if PROTECT_VECTORS MYWRITERLOCK(l, entryRW); #endif for (std::vector::iterator i=fd.begin(); i!=fd.end(); i++) if ((*i)->filename==fname) { ThumbBrowserEntryBase* entry = *i; entry->selected = false; fd.erase (i); std::vector::iterator j = std::find (selected.begin(), selected.end(), entry); #if PROTECT_VECTORS MYWRITERLOCK_RELEASE(l); #endif if (j!=selected.end()) { if (checkFilter (*j)) numFiltered--; selected.erase (j); notifySelectionListener (); } if (lastClicked==entry) lastClicked = NULL; redraw (); return (static_cast(entry)); } return NULL; } void FileBrowser::close () { if (fbih->pending) fbih->destroyed = true; else delete fbih; fbih = new FileBrowserIdleHelper; fbih->fbrowser = this; fbih->destroyed = false; fbih->pending = 0; { #if PROTECT_VECTORS MYWRITERLOCK(l, entryRW); #endif selected.clear (); #if PROTECT_VECTORS MYWRITERLOCK_RELEASE(l); // notifySelectionListener will need read access! #endif notifySelectionListener (); #if PROTECT_VECTORS MYWRITERLOCK_ACQUIRE(l); #endif // The listener merges parameters with old values, so delete afterwards for (size_t i=0; i tbe; tbe.push_back (static_cast(colorLabel_actionData)); for (int i=0; i<6; i++) if (m==colorlabel_pop[i]) { colorlabelRequested (tbe, i); return; } } void FileBrowser::menuItemActivated (Gtk::MenuItem* m) { std::vector mselected; { #if PROTECT_VECTORS MYREADERLOCK(l, entryRW); #endif for (size_t i=0; i(selected[i])); } if (!tbl || (m!=selall && mselected.empty()) ) return; for (int i=0; i<6; i++) if (m==rank[i]) { rankingRequested (mselected, i); return; } for (int i=0; i<6; i++) if (m==colorlabel[i]) { colorlabelRequested (mselected, i); return; } for (int j=0; jget_label()]; // Build vector of all file names std::vector selFileNames; for (int i=0; ithumbnail->getFileName(); // Maybe batch processed version if (pAct->target==2) fn = Glib::ustring::compose ("%1.%2", BatchQueue::calcAutoFileNameBase(fn), options.saveFormatBatch.format); selFileNames.push_back(fn); } pAct->Execute(selFileNames); return; } } if (m==open) openRequested(mselected); else if (m==remove) tbl->deleteRequested (mselected, false); else if (m==removeInclProc) tbl->deleteRequested (mselected, true); else if (m==trash) toTrashRequested (mselected); else if (m==untrash) fromTrashRequested (mselected); else if (m==develop) tbl->developRequested (mselected, false); else if (m==developfast) tbl->developRequested (mselected, true); else if (m==rename) tbl->renameRequested (mselected); else if (m==selall) { lastClicked = NULL; { #if PROTECT_VECTORS MYWRITERLOCK(l, entryRW); #endif selected.clear (); for (size_t i=0; iselected = true; selected.push_back (fd[i]); } } queue_draw (); notifySelectionListener (); } else if( m==copyTo){ tbl->copyMoveRequested (mselected, false); } else if( m==moveTo){ tbl->copyMoveRequested (mselected, true); } else if (m==autoDF){ if (!mselected.empty() && bppcl) bppcl->beginBatchPParamsChange(mselected.size()); for (size_t i=0; ithumbnail->getProcParams(); pp.raw.df_autoselect= true; pp.raw.dark_frame.clear(); mselected[i]->thumbnail->setProcParams(pp,NULL,FILEBROWSER,false); } if (!mselected.empty() && bppcl) bppcl->endBatchPParamsChange(); }else if (m==selectDF){ if( !mselected.empty() ){ rtengine::procparams::ProcParams pp=mselected[0]->thumbnail->getProcParams(); Gtk::FileChooserDialog fc("Dark Frame",Gtk::FILE_CHOOSER_ACTION_OPEN ); FileChooserLastFolderPersister persister(&fc, options.lastDarkframeDir); fc.add_button( Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL); fc.add_button( Gtk::StockID("gtk-apply"), Gtk::RESPONSE_APPLY); if(!pp.raw.dark_frame.empty()) fc.set_filename( pp.raw.dark_frame ); if( fc.run() == Gtk::RESPONSE_APPLY ) { if (bppcl) bppcl->beginBatchPParamsChange(mselected.size()); for (size_t i=0; ithumbnail->getProcParams(); pp.raw.dark_frame= fc.get_filename(); pp.raw.df_autoselect= false; mselected[i]->thumbnail->setProcParams(pp,NULL,FILEBROWSER,false); } if (bppcl) bppcl->endBatchPParamsChange(); } } }else if( m==thisIsDF){ if( !options.rtSettings.darkFramesPath.empty()) { if (Gio::File::create_for_path(options.rtSettings.darkFramesPath)->query_exists() ){ for (size_t i=0; i file = Gio::File::create_for_path ( mselected[i]->filename ); if( !file )continue; Glib::ustring destName = options.rtSettings.darkFramesPath+ "/" + file->get_basename(); Glib::RefPtr dest = Gio::File::create_for_path ( destName ); file->move( dest ); } // Reinit cache rtengine::dfm.init( options.rtSettings.darkFramesPath ); } else { // Target directory creation failed, we clear the darkFramesPath setting options.rtSettings.darkFramesPath.clear(); Glib::ustring msg_ = Glib::ustring::compose (M("MAIN_MSG_PATHDOESNTEXIST"), options.rtSettings.darkFramesPath) +"\n\n"+M("MAIN_MSG_OPERATIONCANCELLED"); Gtk::MessageDialog msgd (msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); msgd.set_title(M("TP_DARKFRAME_LABEL")); msgd.run (); } } else { Glib::ustring msg_ = M("MAIN_MSG_SETPATHFIRST")+"\n\n"+M("MAIN_MSG_OPERATIONCANCELLED"); Gtk::MessageDialog msgd (msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); msgd.set_title(M("TP_DARKFRAME_LABEL")); msgd.run (); } } else if (m==autoFF){ if (!mselected.empty() && bppcl) bppcl->beginBatchPParamsChange(mselected.size()); for (size_t i=0; ithumbnail->getProcParams(); pp.raw.ff_AutoSelect= true; pp.raw.ff_file.clear(); mselected[i]->thumbnail->setProcParams(pp,NULL,FILEBROWSER,false); } if (!mselected.empty() && bppcl) bppcl->endBatchPParamsChange(); } else if (m==selectFF){ if( !mselected.empty() ){ rtengine::procparams::ProcParams pp=mselected[0]->thumbnail->getProcParams(); Gtk::FileChooserDialog fc("Flat Field",Gtk::FILE_CHOOSER_ACTION_OPEN ); FileChooserLastFolderPersister persister(&fc, options.lastFlatfieldDir); fc.add_button( Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL); fc.add_button( Gtk::StockID("gtk-apply"), Gtk::RESPONSE_APPLY); if(!pp.raw.ff_file.empty()) fc.set_filename( pp.raw.ff_file ); if( fc.run() == Gtk::RESPONSE_APPLY ) { if (bppcl) bppcl->beginBatchPParamsChange(mselected.size()); for (size_t i=0; ithumbnail->getProcParams(); pp.raw.ff_file= fc.get_filename(); pp.raw.ff_AutoSelect= false; mselected[i]->thumbnail->setProcParams(pp,NULL,FILEBROWSER,false); } if (bppcl) bppcl->endBatchPParamsChange(); } } } else if( m==thisIsFF){ if( !options.rtSettings.flatFieldsPath.empty()) { if (Gio::File::create_for_path(options.rtSettings.flatFieldsPath)->query_exists() ){ for (size_t i=0; i file = Gio::File::create_for_path ( mselected[i]->filename ); if( !file )continue; Glib::ustring destName = options.rtSettings.flatFieldsPath+ "/" + file->get_basename(); Glib::RefPtr dest = Gio::File::create_for_path ( destName ); file->move( dest ); } // Reinit cache rtengine::ffm.init( options.rtSettings.flatFieldsPath ); } else { // Target directory creation failed, we clear the flatFieldsPath setting options.rtSettings.flatFieldsPath.clear(); Glib::ustring msg_ = Glib::ustring::compose (M("MAIN_MSG_PATHDOESNTEXIST"), options.rtSettings.flatFieldsPath) +"\n\n"+M("MAIN_MSG_OPERATIONCANCELLED"); Gtk::MessageDialog msgd (msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); msgd.set_title(M("TP_FLATFIELD_LABEL")); msgd.run (); } } else { Glib::ustring msg_ = M("MAIN_MSG_SETPATHFIRST")+"\n\n"+M("MAIN_MSG_OPERATIONCANCELLED"); Gtk::MessageDialog msgd (msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); msgd.set_title(M("TP_FLATFIELD_LABEL")); msgd.run (); } } else if (m==copyprof) copyProfile (); else if (m==pasteprof) pasteProfile (); else if (m==partpasteprof) partPasteProfile (); else if (m==clearprof) { for (size_t i=0; ithumbnail->clearProcParams (FILEBROWSER); queue_draw (); } else if (m==execcustprof) { if (!mselected.empty() && bppcl) bppcl->beginBatchPParamsChange(mselected.size()); for (size_t i=0; ithumbnail->createProcParamsForUpdate (false, true); // Empty run to update the thumb rtengine::procparams::ProcParams params = mselected[i]->thumbnail->getProcParams (); mselected[i]->thumbnail->setProcParams (params, NULL, FILEBROWSER); } if (!mselected.empty() && bppcl) bppcl->endBatchPParamsChange(); } else if (m==clearFromCache) { for (size_t i=0; iclearFromCacheRequested (mselected, false); //queue_draw (); } else if (m==clearFromCacheFull) { for (size_t i=0; iclearFromCacheRequested (mselected, true); //queue_draw (); } else if (miOpenDefaultViewer!=NULL && m==miOpenDefaultViewer) { openDefaultViewer(1); } } void FileBrowser::copyProfile () { #if PROTECT_VECTORS MYREADERLOCK(l, entryRW); #endif if (selected.size()==1) clipboard.setProcParams ((static_cast(selected[0]))->thumbnail->getProcParams()); } void FileBrowser::pasteProfile () { if (clipboard.hasProcParams()) { std::vector mselected; { #if PROTECT_VECTORS MYREADERLOCK(l, entryRW); #endif for (unsigned int i=0; i(selected[i])); } if (!tbl || mselected.empty()) return; if (!mselected.empty() && bppcl) bppcl->beginBatchPParamsChange(mselected.size()); for (unsigned int i=0; ithumbnail->setProcParams (*pastedPartProf.pparams, pastedPartProf.pedited, FILEBROWSER); pastedPartProf.deleteInstance(); } if (!mselected.empty() && bppcl) bppcl->endBatchPParamsChange(); queue_draw (); } } void FileBrowser::partPasteProfile () { if (clipboard.hasProcParams()) { std::vector mselected; { #if PROTECT_VECTORS MYREADERLOCK(l, entryRW); #endif for (unsigned int i=0; i(selected[i])); } if (!tbl || mselected.empty()) return; int i = partialPasteDlg.run (); if (i == Gtk::RESPONSE_OK) { if (!mselected.empty() && bppcl) bppcl->beginBatchPParamsChange(mselected.size()); for (unsigned int i=0; ithumbnail->createProcParamsForUpdate(false,false); // this can execute customprofilebuilder to generate param file rtengine::procparams::PartialProfile cbPartProf = clipboard.getPartialProfile(); rtengine::procparams::PartialProfile pastedPartProf(&mselected[i]->thumbnail->getProcParams (), NULL); // pushing the selected values of the clipboard PartialProfile to the temporary PartialProfile partialPasteDlg.applyPaste (pastedPartProf.pparams, pastedPartProf.pedited, cbPartProf.pparams, cbPartProf.pedited); // applying the temporary PartialProfile to the thumb's ProcParams mselected[i]->thumbnail->setProcParams (*pastedPartProf.pparams, pastedPartProf.pedited, FILEBROWSER); pastedPartProf.deleteInstance(); } if (!mselected.empty() && bppcl) bppcl->endBatchPParamsChange(); queue_draw (); } partialPasteDlg.hide (); } } void FileBrowser::openDefaultViewer (int destination) { bool success=true; { #if PROTECT_VECTORS MYREADERLOCK(l, entryRW); #endif if (selected.size()==1) success=(static_cast(selected[0]))->thumbnail->openDefaultViewer(destination); } if (!success) { Gtk::MessageDialog msgd (M("MAIN_MSG_IMAGEUNPROCESSED"), true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); msgd.run (); } } bool FileBrowser::keyPressed (GdkEventKey* event) { bool ctrl = event->state & GDK_CONTROL_MASK; bool shift = event->state & GDK_SHIFT_MASK; bool alt = event->state & GDK_MOD1_MASK; bool altgr = event->state & GDK_MOD2_MASK; if ((event->keyval==GDK_C || event->keyval==GDK_c || event->keyval==GDK_Insert) && ctrl) { copyProfile (); return true; } else if ((event->keyval==GDK_V || event->keyval==GDK_v) && ctrl && !shift) { pasteProfile (); return true; } else if (event->keyval==GDK_Insert && shift) { pasteProfile (); return true; } else if ((event->keyval==GDK_V || event->keyval==GDK_v) && ctrl && shift) { partPasteProfile (); return true; } else if (event->keyval==GDK_Delete && !shift) { menuItemActivated (trash); return true; } else if (event->keyval==GDK_Delete && shift) { menuItemActivated (untrash); return true; } else if ((event->keyval==GDK_B || event->keyval==GDK_b) && ctrl) { menuItemActivated (develop); return true; } else if ((event->keyval==GDK_A || event->keyval==GDK_a) && ctrl) { menuItemActivated (selall); return true; } else if (event->keyval==GDK_F2 && !ctrl) { menuItemActivated (rename); return true; } else if (event->keyval==GDK_F3 && !(ctrl || shift || alt)) { // open Previous image from FileBrowser perspective FileBrowser::openPrevImage (); return true; } else if (event->keyval==GDK_F4 && !(ctrl || shift || alt)) { // open Next image from FileBrowser perspective FileBrowser::openNextImage (); return true; } else if (event->keyval==GDK_Left) { selectPrev (1, shift); return true; } else if (event->keyval==GDK_Right) { selectNext (1, shift); return true; } else if (event->keyval==GDK_Up) { selectPrev (numOfCols, shift); return true; } else if (event->keyval==GDK_Down) { selectNext (numOfCols, shift); return true; } else if (event->keyval==GDK_Home) { selectFirst (shift); return true; } else if (event->keyval==GDK_End) { selectLast (shift); return true; } else if(event->keyval==GDK_Return || event->keyval==GDK_KP_Enter) { std::vector mselected; for (size_t i=0; i(selected[i])); openRequested(mselected); } else if (event->keyval==GDK_F5) { int dest = 1; if (event->state & GDK_SHIFT_MASK) dest = 2; else if (event->state & GDK_CONTROL_MASK) dest = 3; openDefaultViewer (dest); return true; } else if (event->keyval==GDK_Page_Up) { scrollPage(GDK_SCROLL_UP); return true; } else if (event->keyval==GDK_Page_Down) { scrollPage(GDK_SCROLL_DOWN); return true; } #ifdef __WIN32__ else if (shift && !ctrl && !alt && !altgr) { // rank switch(event->hardware_keycode) { case 0x30: // 0-key requestRanking (0); return true; case 0x31: // 1-key requestRanking (1); return true; case 0x32: // 2-key requestRanking (2); return true; case 0x33: // 3-key requestRanking (3); return true; case 0x34: // 4-key requestRanking (4); return true; case 0x35: // 5-key requestRanking (5); return true; } } else if (shift && ctrl && !alt && !altgr) { // color labels switch(event->hardware_keycode) { case 0x30: // 0-key requestColorLabel (0); return true; case 0x31: // 1-key requestColorLabel (1); return true; case 0x32: // 2-key requestColorLabel (2); return true; case 0x33: // 3-key requestColorLabel (3); return true; case 0x34: // 4-key requestColorLabel (4); return true; case 0x35: // 5-key requestColorLabel (5); return true; } } #else else if (shift && !ctrl && !alt) { // rank switch(event->hardware_keycode) { case 0x13: requestRanking (0); return true; case 0x0a: requestRanking (1); return true; case 0x0b: requestRanking (2); return true; case 0x0c: requestRanking (3); return true; case 0x0d: requestRanking (4); return true; case 0x0e: requestRanking (5); return true; } } else if (shift && ctrl && !alt) { // color labels switch(event->hardware_keycode) { case 0x13: requestColorLabel (0); return true; case 0x0a: requestColorLabel (1); return true; case 0x0b: requestColorLabel (2); return true; case 0x0c: requestColorLabel (3); return true; case 0x0d: requestColorLabel (4); return true; case 0x0e: requestColorLabel (5); return true; } } #endif return false; } void FileBrowser::saveThumbnailHeight (int height) { if (!options.sameThumbSize && getLocation()==THLOC_EDITOR) options.thumbSizeTab = height; else options.thumbSize = height; } int FileBrowser::getThumbnailHeight () { // The user could have manually forced the option to a too big value if (!options.sameThumbSize && getLocation()==THLOC_EDITOR) return std::max(std::min(options.thumbSizeTab, 800), 10); else return std::max(std::min(options.thumbSize, 800), 10); } void FileBrowser::applyMenuItemActivated (ProfileStoreLabel *label) { #if PROTECT_VECTORS MYREADERLOCK(l, entryRW); #endif const rtengine::procparams::PartialProfile* partProfile = profileStore.getProfile (label->entry); if (partProfile->pparams && !selected.empty()) { if (bppcl) bppcl->beginBatchPParamsChange(selected.size()); for (size_t i=0; i(selected[i]))->thumbnail->setProcParams (*partProfile->pparams, partProfile->pedited, FILEBROWSER); if (bppcl) bppcl->endBatchPParamsChange(); queue_draw (); } } void FileBrowser::applyPartialMenuItemActivated (ProfileStoreLabel *label) { { #if PROTECT_VECTORS MYREADERLOCK(l, entryRW); #endif if (!tbl || selected.empty()) return; } const rtengine::procparams::PartialProfile* srcProfiles = profileStore.getProfile (label->entry); if (srcProfiles->pparams) { if (partialPasteDlg.run()==Gtk::RESPONSE_OK) { #if PROTECT_VECTORS MYREADERLOCK(l, entryRW); #endif if (bppcl) bppcl->beginBatchPParamsChange(selected.size()); for (size_t i=0; ithumbnail->createProcParamsForUpdate(false, false); // this can execute customprofilebuilder to generate param file rtengine::procparams::PartialProfile dstProfile(true); *dstProfile.pparams = (static_cast(selected[i]))->thumbnail->getProcParams (); dstProfile.set(true); partialPasteDlg.applyPaste (dstProfile.pparams, dstProfile.pedited, srcProfiles->pparams, srcProfiles->pedited); (static_cast(selected[i]))->thumbnail->setProcParams (*dstProfile.pparams, dstProfile.pedited, FILEBROWSER); dstProfile.deleteInstance(); } if (bppcl) bppcl->endBatchPParamsChange(); queue_draw (); } partialPasteDlg.hide (); } } void FileBrowser::applyFilter (const BrowserFilter& filter) { this->filter = filter; // remove items not complying the filter from the selection bool selchanged = false; numFiltered=0; { #if PROTECT_VECTORS MYWRITERLOCK(l, entryRW); // Don't make this a writer lock! HOMBRE: Why? 'selected' is modified here #endif for (size_t i=0; iselected ) { fd[i]->selected = false; std::vector::iterator j = std::find (selected.begin(), selected.end(), fd[i]); selected.erase (j); if (lastClicked==fd[i]) lastClicked = NULL; selchanged = true; } } } if (selchanged) notifySelectionListener (); tbl->filterApplied(); redraw (); } bool FileBrowser::checkFilter (ThumbBrowserEntryBase* entryb) { // true -> entry complies filter FileBrowserEntry* entry = static_cast(entryb); // return false if basic filter settings are not satisfied if ((filter.showRanked[entry->thumbnail->getRank()]==false ) || (filter.showCLabeled[entry->thumbnail->getColorLabel()]==false ) || ((entry->thumbnail->hasProcParams() && filter.showEdited[0]) && !filter.showEdited[1]) || ((!entry->thumbnail->hasProcParams() && filter.showEdited[1])&& !filter.showEdited[0]) || ((entry->thumbnail->isRecentlySaved() && filter.showRecentlySaved[0]) && !filter.showRecentlySaved[1]) || ((!entry->thumbnail->isRecentlySaved() && filter.showRecentlySaved[1]) && !filter.showRecentlySaved[0]) || (entry->thumbnail->getStage()==1 && !filter.showTrash) || (entry->thumbnail->getStage()==0 && !filter.showNotTrash)) return false; // return false is query is not satisfied if (!filter.queryFileName.empty()){ // check if image's FileName contains queryFileName (case insensitive) // TODO should we provide case-sensitive search option via preferences? Glib::ustring FileName; FileName = Glib::path_get_basename (entry->thumbnail->getFileName()); FileName = FileName.uppercase(); //printf("FileBrowser::checkFilter FileName = '%s'; find() result= %i \n",FileName.c_str(), FileName.find(filter.queryFileName.uppercase())); Glib::ustring decodedQueryFileName; bool MatchEqual; // Determine the match mode - check if the first 2 characters are equal to "!=" if (filter.queryFileName.find("!=")==0){ decodedQueryFileName = filter.queryFileName.substr (2,filter.queryFileName.length()-2); MatchEqual = false; } else { decodedQueryFileName = filter.queryFileName; MatchEqual = true; } // Consider that queryFileName consist of comma separated values (FilterString) // Evaluate if ANY of these FilterString are contained in the filename // This will construct OR filter within the filter.queryFileName int iFilenameMatch=0; std::vector vFilterStrings = Glib::Regex::split_simple(",", decodedQueryFileName.uppercase()); for(int i=0; i0) // match is found for at least one of vFilterStrings in FileName return false; } /*experimental Regex support, this is unlikely to be useful to photographers*/ //bool matchfound=Glib::Regex::match_simple(filter.queryFileName.uppercase(),FileName); //if (!matchfound) return false; } // check exif filter const CacheImageData* cfs = entry->thumbnail->getCacheImageData(); double tol = 0.01; double tol2 = 1e-8; if (!filter.exifFilterEnabled) return true; Glib::ustring camera(cfs->getCamera()); if (!cfs->exifValid) return (!filter.exifFilter.filterCamera || filter.exifFilter.cameras.count(camera)>0) && (!filter.exifFilter.filterLens || filter.exifFilter.lenses.count(cfs->lens)>0) && (!filter.exifFilter.filterFiletype || filter.exifFilter.filetypes.count(cfs->filetype)>0) && (!filter.exifFilter.filterExpComp || filter.exifFilter.expcomp.count(cfs->expcomp)>0); return (!filter.exifFilter.filterShutter || (rtengine::ImageMetaData::shutterFromString(rtengine::ImageMetaData::shutterToString(cfs->shutter)) >= filter.exifFilter.shutterFrom-tol2 && rtengine::ImageMetaData::shutterFromString(rtengine::ImageMetaData::shutterToString(cfs->shutter)) <= filter.exifFilter.shutterTo+tol2)) && (!filter.exifFilter.filterFNumber || (rtengine::ImageMetaData::apertureFromString(rtengine::ImageMetaData::apertureToString(cfs->fnumber)) >= filter.exifFilter.fnumberFrom-tol2 && rtengine::ImageMetaData::apertureFromString(rtengine::ImageMetaData::apertureToString(cfs->fnumber)) <= filter.exifFilter.fnumberTo+tol2)) && (!filter.exifFilter.filterFocalLen || (cfs->focalLen >= filter.exifFilter.focalFrom-tol && cfs->focalLen <= filter.exifFilter.focalTo+tol)) && (!filter.exifFilter.filterISO || (cfs->iso >= filter.exifFilter.isoFrom && cfs->iso <= filter.exifFilter.isoTo)) && (!filter.exifFilter.filterExpComp || filter.exifFilter.expcomp.count(cfs->expcomp)>0) && (!filter.exifFilter.filterCamera || filter.exifFilter.cameras.count(camera)>0) && (!filter.exifFilter.filterLens || filter.exifFilter.lenses.count(cfs->lens)>0) && (!filter.exifFilter.filterFiletype || filter.exifFilter.filetypes.count(cfs->filetype)>0); } void FileBrowser::toTrashRequested (std::vector tbe) { for (size_t i=0; ithumbnail->createProcParamsForUpdate(false, false, true); // this can execute customprofilebuilder to generate param file in "flagging" mode // no need to notify listeners as item goes to trash, likely to be deleted if (tbe[i]->thumbnail->getStage()==1) continue; tbe[i]->thumbnail->setStage (1); if (tbe[i]->getThumbButtonSet()) { tbe[i]->getThumbButtonSet()->setRank (tbe[i]->thumbnail->getRank()); tbe[i]->getThumbButtonSet()->setColorLabel (tbe[i]->thumbnail->getColorLabel()); tbe[i]->getThumbButtonSet()->setInTrash (true); tbe[i]->thumbnail->updateCache (); // needed to save the colorlabel to disk in the procparam file(s) and the cache image data file } } trash_changed().emit(); applyFilter (filter); } void FileBrowser::fromTrashRequested (std::vector tbe) { for (size_t i=0; ithumbnail->getStage()==0) continue; tbe[i]->thumbnail->setStage (0); if (tbe[i]->getThumbButtonSet()) { tbe[i]->getThumbButtonSet()->setRank (tbe[i]->thumbnail->getRank()); tbe[i]->getThumbButtonSet()->setColorLabel (tbe[i]->thumbnail->getColorLabel()); tbe[i]->getThumbButtonSet()->setInTrash (false); tbe[i]->thumbnail->updateCache (); // needed to save the colorlabel to disk in the procparam file(s) and the cache image data file } } trash_changed().emit(); applyFilter (filter); } void FileBrowser::rankingRequested (std::vector tbe, int rank) { if (!tbe.empty() && bppcl) bppcl->beginBatchPParamsChange(tbe.size()); for (size_t i=0; ithumbnail->createProcParamsForUpdate(false, false, true); // this can execute customprofilebuilder to generate param file in "flagging" mode // notify listeners TODO: should do this ONLY when params changed by customprofilebuilder? tbe[i]->thumbnail->notifylisterners_procParamsChanged(FILEBROWSER); tbe[i]->thumbnail->setRank (rank); tbe[i]->thumbnail->updateCache (); // needed to save the colorlabel to disk in the procparam file(s) and the cache image data file //TODO? - should update pparams instead? if (tbe[i]->getThumbButtonSet()) tbe[i]->getThumbButtonSet()->setRank (tbe[i]->thumbnail->getRank()); } applyFilter (filter); if (!tbe.empty() && bppcl) bppcl->endBatchPParamsChange(); } void FileBrowser::colorlabelRequested (std::vector tbe, int colorlabel) { if (!tbe.empty() && bppcl) bppcl->beginBatchPParamsChange(tbe.size()); for (size_t i=0; ithumbnail->createProcParamsForUpdate(false, false, true); // this can execute customprofilebuilder to generate param file in "flagging" mode // notify listeners TODO: should do this ONLY when params changed by customprofilebuilder? tbe[i]->thumbnail->notifylisterners_procParamsChanged(FILEBROWSER); tbe[i]->thumbnail->setColorLabel (colorlabel); tbe[i]->thumbnail->updateCache(); // needed to save the colorlabel to disk in the procparam file(s) and the cache image data file //TODO? - should update pparams instead? if (tbe[i]->getThumbButtonSet()) tbe[i]->getThumbButtonSet()->setColorLabel (tbe[i]->thumbnail->getColorLabel()); } applyFilter (filter); if (!tbe.empty() && bppcl) bppcl->endBatchPParamsChange(); } void FileBrowser::requestRanking(int rank){ std::vector mselected; { #if PROTECT_VECTORS MYREADERLOCK(l, entryRW); #endif for (size_t i=0; i(selected[i])); } rankingRequested (mselected, rank); } void FileBrowser::requestColorLabel(int colorlabel){ std::vector mselected; { #if PROTECT_VECTORS MYREADERLOCK(l, entryRW); #endif for (size_t i=0; i(selected[i])); } colorlabelRequested (mselected, colorlabel); } void FileBrowser::buttonPressed (LWButton* button, int actionCode, void* actionData) { if (actionCode>=0 && actionCode<=5) { // rank std::vector tbe; tbe.push_back (static_cast(actionData)); rankingRequested (tbe, actionCode); } else if (actionCode==6 && tbl) { // to processing queue std::vector tbe; tbe.push_back (static_cast(actionData)); tbl->developRequested (tbe, false); // not a fast, but a FULL mode } else if (actionCode==7) { // to trash / undelete std::vector tbe; FileBrowserEntry* entry = static_cast(actionData); tbe.push_back (entry); if (entry->thumbnail->getStage()==0) toTrashRequested (tbe); else fromTrashRequested (tbe); } else if (actionCode==8 && tbl) { // color label // show popup menu colorLabel_actionData = actionData;// this will be reused when pmenuColorLabels is clicked pmenuColorLabels->popup (3, this->eventTime); } } void FileBrowser::openNextImage () { #if PROTECT_VECTORS MYWRITERLOCK(l, entryRW); #endif if (!fd.empty() && selected.size()>0 && !options.tabbedUI) { for (size_t i=0; ithumbnail->getFileName()==fd[i]->filename) {// located 1-st image in current selection if (ifiltered/*checkFilter (fd[k])*/){ // clear current selection for (size_t j=0; jselected = false; selected.clear (); // set new selection fd[k]->selected = true; selected.push_back (fd[k]); //queue_draw (); #if PROTECT_VECTORS MYWRITERLOCK_RELEASE(l); #endif // this will require a read access notifySelectionListener (); #if PROTECT_VECTORS MYWRITERLOCK_ACQUIRE(l); #endif // scroll to the selected position double h1, v1; getScrollPosition(h1,v1); double h2=selected[0]->getStartX(); double v2=selected[0]->getStartY(); Thumbnail* thumb = (static_cast(fd[k]))->thumbnail; int minWidth = get_width()-fd[k]->getMinimalWidth(); #if PROTECT_VECTORS MYWRITERLOCK_RELEASE(l); #endif // scroll only when selected[0] is outside of the displayed bounds if (h2+minWidth-h1 > get_width()) setScrollPosition(h2-minWidth,v2); if (h1>h2) setScrollPosition(h2,v2); // open the selected image std::vector entries; entries.push_back (thumb); tbl->openRequested (entries); return; } } } } } } } void FileBrowser::openPrevImage () { #if PROTECT_VECTORS MYWRITERLOCK(l, entryRW); #endif if (!fd.empty() && selected.size()>0 && !options.tabbedUI) { for (size_t i=1; ithumbnail->getFileName()==fd[i]->filename) {// located 1-st image in current selection if (i>0 && tbl) { // find the first not-filtered-out (previous) image for (ssize_t k=(ssize_t)i-1; k>=0; k--){ if (!fd[k]->filtered/*checkFilter (fd[k])*/){ // clear current selection for (size_t j=0; jselected = false; selected.clear (); // set new selection fd[k]->selected = true; selected.push_back (fd[k]); //queue_draw (); #if PROTECT_VECTORS MYWRITERLOCK_RELEASE(l); #endif // this will require a read access notifySelectionListener (); #if PROTECT_VECTORS MYWRITERLOCK_ACQUIRE(l); #endif // scroll to the selected position double h1, v1; getScrollPosition(h1,v1); double h2=selected[0]->getStartX(); double v2=selected[0]->getStartY(); Thumbnail* thumb = (static_cast(fd[k]))->thumbnail; int minWidth = get_width()-fd[k]->getMinimalWidth(); #if PROTECT_VECTORS MYWRITERLOCK_RELEASE(l); #endif // scroll only when selected[0] is outside of the displayed bounds if (h2+minWidth-h1 > get_width()) setScrollPosition(h2-minWidth,v2); if (h1>h2) setScrollPosition(h2,v2); // open the selected image std::vector entries; entries.push_back (thumb); tbl->openRequested (entries); return; } } } } } } } void FileBrowser::selectImage (Glib::ustring fname) { // need to clear the filter in filecatalog #if PROTECT_VECTORS MYWRITERLOCK(l, entryRW); #endif if (!fd.empty() && !options.tabbedUI) { for (size_t i=0; ifilename && !fd[i]->filtered) { // matching file found for sync // clear current selection for (size_t j=0; jselected = false; selected.clear (); // set new selection fd[i]->selected = true; selected.push_back (fd[i]); queue_draw (); #if PROTECT_VECTORS MYWRITERLOCK_RELEASE(l); #endif // this will require a read access notifySelectionListener (); #if PROTECT_VECTORS MYWRITERLOCK_ACQUIRE(l); #endif // scroll to the selected position double h=selected[0]->getStartX(); double v=selected[0]->getStartY(); #if PROTECT_VECTORS MYWRITERLOCK_RELEASE(l); #endif setScrollPosition(h,v); return; } } } } void FileBrowser::openNextPreviousEditorImage (Glib::ustring fname, eRTNav nextPrevious) { // let FileBrowser acquire Editor's perspective selectImage (fname); // now switch to the requested image if (nextPrevious==NAV_NEXT) openNextImage(); else if (nextPrevious==NAV_PREVIOUS) openPrevImage(); } int refreshThumbImagesUI (void* data) { (static_cast(data))->_thumbRearrangementNeeded (); return 0; } void FileBrowser::_thumbRearrangementNeeded () { refreshThumbImages (); // arrangeFiles is NOT enough } void FileBrowser::thumbRearrangementNeeded () { // refreshThumbImagesUI will handle thread safety itself g_idle_add (refreshThumbImagesUI, this); } void FileBrowser::selectionChanged () { notifySelectionListener (); } void FileBrowser::notifySelectionListener () { if (tbl) { #if PROTECT_VECTORS MYREADERLOCK(l, entryRW); #endif std::vector thm; for (size_t i=0; i(selected[i]))->thumbnail); tbl->selectionChanged (thm); } } void FileBrowser::redrawNeeded (LWButton* button) { GThreadLock lock; queue_draw (); } FileBrowser::type_trash_changed FileBrowser::trash_changed () { return m_trash_changed; } // ExportPanel interface void FileBrowser::exportRequested (){ FileBrowser::menuItemActivated(developfast); } void FileBrowser::setExportPanel (ExportPanel* expanel) { exportPanel = expanel; exportPanel->set_sensitive (false); exportPanel->setExportPanelListener (this); } void FileBrowser::updateProfileList () { // submenu applmenu int p = 0; const std::vector *profEntries = profileStore.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 subMenuList[0] = Gtk::manage (new Gtk::Menu ()); // adding the root submenu // iterate the profile store's profile list for (size_t i=0; isize(); i++) { // create a new label for the current entry (be it a folder or file) ProfileStoreLabel *currLabel = Gtk::manage(new ProfileStoreLabel( profEntries->at(i) )); // create the MenuItem object Gtk::MenuItem* mi = Gtk::manage (new Gtk::MenuItem (*currLabel)); // create a new Menu object if the entry is a folder and not the root one if (currLabel->entry->type == PSET_FOLDER) { // creating the new sub-menu Gtk::Menu* subMenu = Gtk::manage (new Gtk::Menu ()); // add it to the menu list subMenuList[currLabel->entry->folderId] = subMenu; // add it to the parent MenuItem mi->set_submenu(*subMenu); } // Hombre: ... does parentMenuId sounds like a hack? ... Yes. int parentMenuId = !options.useBundledProfiles && currLabel->entry->parentFolderId==1 ? 0 : currLabel->entry->parentFolderId; subMenuList[parentMenuId]->attach (*mi, 0, 1, p, p+1); p++; if (currLabel->entry->type == PSET_FILE) mi->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::applyMenuItemActivated), currLabel)); mi->show (); } if (subMenuList.size() && applyprof) // TODO: Check that the previous one has been deleted, including all childrens applyprof->set_submenu (*(subMenuList.at(0))); subMenuList.clear(); subMenuList[0] = Gtk::manage (new Gtk::Menu ()); // adding the root submenu // keep profEntries list // submenu applpartmenu p = 0; for (size_t i=0; isize(); i++) { ProfileStoreLabel *currLabel = Gtk::manage(new ProfileStoreLabel( profEntries->at(i) )); Gtk::MenuItem* mi = Gtk::manage (new Gtk::MenuItem (*currLabel)); if (currLabel->entry->type == PSET_FOLDER) { // creating the new sub-menu Gtk::Menu* subMenu = Gtk::manage (new Gtk::Menu ()); // add it to the menu list subMenuList[currLabel->entry->folderId] = subMenu; // add it to the parent MenuItem mi->set_submenu(*subMenu); } // Hombre: ... does parentMenuId sounds like a hack? ... yes. int parentMenuId = !options.useBundledProfiles && currLabel->entry->parentFolderId==1 ? 0 : currLabel->entry->parentFolderId; subMenuList[parentMenuId]->attach (*mi, 0, 1, p, p+1); p++; if (currLabel->entry->type == PSET_FILE) mi->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::applyPartialMenuItemActivated), currLabel)); mi->show (); } if (subMenuList.size() && applypartprof) // TODO: Check that the previous one has been deleted, including all childrens applypartprof->set_submenu (*(subMenuList.at(0))); profileStore.releaseFileList(); subMenuList.clear(); } void FileBrowser::openRequested( std::vector mselected) { std::vector entries; // in Single Editor Mode open only last selected image size_t openStart = options.tabbedUI ? 0 : ( mselected.size() > 0 ? mselected.size()-1 : 0); for (size_t i=openStart; ithumbnail); tbl->openRequested (entries); }