added a filter dialog...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2014-01-13 06:37:08 +04:00
parent 71141dd571
commit d2cff759ac
8 changed files with 265 additions and 39 deletions

View File

@ -112,6 +112,8 @@ Roadmap
[_] 62% High priority
[_] BUG: sorting breaks when at or near the end of a ribbon...
|
| Race condition...
|
| Procedure:
| - go to end of a ribbon
| - shift-s
@ -125,7 +127,28 @@ Roadmap
| - check "Descending" in the sort dialog
| NOTE: this breaks because current the current image is not
| yet loaded/created when reloadViewer(..) tries to focus it...
|
| Temporary workaround:
| because there is nothing wrong with sorting itself, just the
| UI, the resulting state can be fixed by simply reloading the
| viewer (reloadViewer(true) or ctrl-alt-r)
[_] BUG: sorting mis-aligns ribbons in some cases...
| Example:
| oooo... --[reverse]-> ...oooo
| ...oooo[o]oooo... ...oooo[o]oooo...
|
| Should be:
| oooo... --[reverse]-> ...oooo
| ...oooo[o]oooo... ...oooo[o]oooo...
|
| The above can happen when, for example, sorting the images via data
| and then sorting them in the same way with reverse checked...
|
| XXX is this related to?
| BUG: sorting breaks when at or near the end of a ribbon...
[_] BUG: panels: open/close events get triggered on panel drag/sort...
[_] crop/filter/search dialog...
| make a number of fields each accepting a filter -- string/regexp
[_] buildcache: add option to control image sort...
[_] ASAP: Need visual indicators for long operations...
[_] 66% tags
@ -269,17 +292,6 @@ Roadmap
[_] 0% metadata
[_] comment
[_] tags
[_] BUG: sorting mis-aligns ribbons in some cases...
| Example:
| oooo... --[reverse]-> ...oooo
| ...oooo[o]oooo... ...oooo[o]oooo...
|
| Should be:
| oooo... --[reverse]-> ...oooo
| ...oooo[o]oooo... ...oooo[o]oooo...
|
| The above can happen when, for example, sorting the images via data
| and then sorting them in the same way with reverse checked...
[_] BUG: opening a dir form history sometimes loads wrong size previews
| this happens in part of the view and a refresh, reload or image
| update (updateImages()) fixes the issue...

View File

@ -7,7 +7,7 @@
// list of bookmarked gids...
//
// NOTE: this must be sorted in the same order as DATA.order
var BOOKMARKS= []
var BOOKMARKS = []
// bookmark data
//
@ -24,6 +24,9 @@ var BOOKMARKS_FILE_PATTERN = /^[0-9]*-bookmarked.json$/
* Helpers
*/
var getBookmarked = makeMarkedLister(function(){ return BOOKMARKS })
var getUnbookmarked = makeUnmarkedLister(function(){ return BOOKMARKS })
var getBookmarkedGIDBefore = makeGIDBeforeGetterFromList(
function(){
return BOOKMARKS

View File

@ -273,6 +273,135 @@ function cropImagesDialog(){
}
function filterImagesDialog(){
updateStatus('Filter...').show()
cfg = {}
cfg['sep0'] = '---'
cfg['Name'] = ''
cfg['Path |'
+'this applies to the non-common\n'
+'part of the relative path.'] = ''
cfg['Comment'] = ''
cfg['Tags |'
+'an image will match if at least\n'
+'one tag matches'] = ''
// XXX date...
cfg['Rotated'] = {select: [
'',
'no',
'90&deg; or 270&deg;',
'0&deg; or 180&deg;',
'90&deg; only',
'180&deg; only',
'270&deg; only'
]}
cfg['Flipped'] = {select: [
'',
'no',
'vertical',
'horizontal'
]}
cfg['sep1'] = '---'
cfg['Marked'] = {select: [
'',
'yes',
'no'
]}
cfg['Bookmarked'] = {select: [
'',
'yes',
'no'
]}
cfg['sep2'] = '---'
cfg['Keep ribbons'] = false
formDialog(null,
'Filter images | NOTE: all filter text fields\n'
+'support regular expressions.',
cfg,
'OK',
'filterImagesDialog')
.done(function(res){
var gids
showStatusQ('Filtering...')
// XXX date...
var filter = {}
// build the filter...
for(var field in res){
if(/^Name/.test(field) && res[field].trim() != ''){
filter['name'] = res[field]
} else if(/^Path/.test(field) && res[field].trim() != ''){
filter['path'] = res[field]
} else if(/^Comment/.test(field) && res[field].trim() != ''){
filter['comment'] = res[field]
} else if(/^Tags/.test(field) && res[field].trim() != ''){
filter['tags'] = res[field]
} else if(/^Rotated/.test(field) && res[field].trim() != ''){
if(res[field] == 'no'){
filter['orientation'] = '^0$|undefined|null'
} else if(/or/.test(res[field])){
filter['orientation'] = res[field]
.split('or')
.map(function(e){
e = parseInt(e)
if(e == 0){
return '^0$|undefined|null'
}
return e
})
.join('|')
} else {
filter['orientation'] = RegExp(parseInt(res[field]))
}
} else if(/^Flipped/.test(field) && res[field].trim() != ''){
if(res[field] == 'no'){
filter['flipped'] = 'undefined|null'
} else {
filter['flipped'] = res[field]
}
} else if(/^Bookmarked/.test(field) && res[field].trim() != ''){
if(res[field] == 'yes'){
gids = getBookmarked(gids)
} else {
gids = getUnbookmarked(gids)
}
} else if(/^Marked/.test(field) && res[field].trim() != ''){
if(res[field] == 'yes'){
gids = getMarked(gids)
} else {
gids = getUnmarked(gids)
}
}
}
var keep_ribbons = res['Keep ribbons']
gids = filterGIDs(filter, gids)
if(gids.length > 0){
cropDataTo(gids, keep_ribbons)
} else {
showStatusQ('Filter: nothing matched.')
}
})
.fail(function(){
showStatusQ('Filter: canceled.')
})
}
/**********************************************************************
* vim:set ts=4 sw=4 : */

View File

@ -748,12 +748,17 @@ function getAllGids(data){
// Get all the currently loaded gids...
//
// NOTE: this will return an unsorted list of gids...
function getLoadedGIDs(data){
function getLoadedGIDs(gids, data){
data = data == null ? DATA : data
var res = []
data.ribbons.forEach(function(r){
res = res.concat(r)
})
if(gids != null){
return gids.filter(function(e){
return res.indexOf(e) >= 0
})
}
return res
}
@ -1405,6 +1410,47 @@ function makePrevFromListAction(get_closest, get_list, restrict_to_ribbon){
}
// XXX also need a date filter -- separate function?
function filterGIDs(filter, gids, data, images){
images = images == null ? IMAGES : images
gids = gids == null ? getLoadedGIDs(null, data) : gids
// normalize filter...
for(var k in filter){
if(typeof(filter[k]) == typeof('str')){
filter[k] = RegExp(filter[k])
}
}
var res = gids.filter(function(gid){
var img = images[gid]
for(var k in filter){
// if key does not exist we have no match...
if(!(k in img)){
return false
}
var f = filter[k]
var val = img[k]
val = typeof(val) == typeof('str') ? val.trim() : val
// value is a list, check items, at least one needs to match...
if(val.constructor.name == 'Array'
&& val.filter(function(e){ return f.test(e) }).length < 1){
return false
// check the whole value...
} else if(!f.test(val)){
return false
}
}
return true
})
return res
}
/**********************************************************************
* Constructors and general data manipulation

View File

@ -78,7 +78,10 @@ var KEYBOARD_CONFIG = {
// NOTE: this is handled by the wrapper at this point, so we do
// not have to do anything here...
F11: doc('Toggle full screen view', function(){ toggleFullscreenMode() }),
F11: doc('Toggle full screen view', function(){
toggleFullscreenMode()
return false
}),
F: {
ctrl: 'F11',
},
@ -380,6 +383,7 @@ var KEYBOARD_CONFIG = {
// cropping...
C: doc('Show ribbon crop dialog', cropImagesDialog),
F: doc('Filter images', filterImagesDialog),
// XXX add a non FXX key for macs...
F2: {

View File

@ -74,38 +74,70 @@ function invalidateMarksCache(){
}
// Get list of unmarked images...
function makeMarkedLister(get_marked){
return function(mode){
var marked = get_marked()
mode = mode == null ? 'all' : mode
var gids = mode == 'all' ? getLoadedGIDs(marked)
: mode.constructor.name == 'Array' ? getLoadedGIDs(mode)
: typeof(mode) == typeof(123) ? getRibbonGIDs(mode)
: getRibbonGIDs()
if(mode == 'all'){
return gids
}
return gids.filter(function(e){
return marked.indexOf(e) >= 0
})
}
}
// Make lister of unmarked images...
//
// mode can be:
// - 'ribbon'
// - 'all'
// - number - ribbon index
// - list - list of gids used as source
// - null - same as all
function getUnmarked(mode){
mode = mode == null ? 'all' : mode
var gids = mode == 'all' ? getLoadedGIDs()
: typeof(mode) == typeof(123) ? getRibbonGIDs(mode)
: getRibbonGIDs()
mode = mode == 'ribbon' ? getRibbonIndex() : mode
function makeUnmarkedLister(get_marked, get_cache){
return function(mode){
var marked = get_marked()
var cache = get_cache != null ? get_cache() : null
// get the cached set...
if(_UNMARKED_CACHE != null && mode in _UNMARKED_CACHE){
return _UNMARKED_CACHE[mode]
mode = mode == null ? 'all' : mode
var gids = mode == 'all' ? getLoadedGIDs()
: mode.constructor.name == 'Array' ? getLoadedGIDs(mode)
: typeof(mode) == typeof(123) ? getRibbonGIDs(mode)
: getRibbonGIDs()
mode = mode == 'ribbon' ? getRibbonIndex() : mode
// get the cached set...
if(cache != null && mode in cache){
return cache[mode]
}
// calculate the set...
var res = gids.filter(function(e){
// keep only unmarked...
return marked.indexOf(e) < 0
})
if(cache != null && typeof(mode) == typeof(123)){
cache[mode] = res
}
return res
}
// calculate the set...
var res = gids.filter(function(e){
// keep only unmarked...
return MARKED.indexOf(e) < 0
})
if(_UNMARKED_CACHE != null){
_UNMARKED_CACHE[mode] = res
}
return res
}
var getMarked = makeMarkedLister(function(){ return MARKED })
var getUnmarked = makeUnmarkedLister(
function(){ return MARKED },
function(){ return _UNMARKED_CACHE })
var getMarkedGIDBefore = makeGIDBeforeGetterFromList(
function(){
return MARKED

View File

@ -418,9 +418,9 @@ function sortImagesDialog(){
cfg = {}
cfg[alg] = [
'Date |'+
'fall back to file sequence then\n'+
'file name when the earlier is equal.',
'Date |'
+'fall back to file sequence then\n'
+'file name when the earlier is equal.',
'Sequence number',
'Sequence number with overflow',
'File name'

View File

@ -808,7 +808,7 @@ var FIELD_TYPES = {
var select = field.find('select')
for(var i=0; i < value.select.length; i++){
item
.text(value.select[i])
.html(value.select[i])
.val(value.select[i])
item.appendTo(select)