adding image name conflict resolution...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2017-11-10 22:39:20 +03:00
parent 01997d9bb1
commit 1ef218f681
3 changed files with 205 additions and 60 deletions

View File

@ -190,6 +190,69 @@ actions.Actions({
}
},
// Consistency checking...
//
imageNameConflicts: ['- File/',
core.doc`Get images with conflicting names...
Check current index for name conflicts...
.imageNameConflicts()
-> conflicts
-> false
Format:
{
// gid name matches...
conflicts: {
// NOTE: each list contains all the matches including
// the conflicts key it was accessed via.
gid: [gid, gid, ...],
...
},
// maximum number of name repetitions...
max_repetitions: number,
}
If there are no conflicts this will return false.
`,
function(){
// build name index...
var conflicts = {}
var max = 0
var names = {}
//var gids = []
this.images
.forEach(function(gid, data){
var name = data.name || gid
var gids
var n = names[name] = names[name] || []
n.push(gid)
// build the conflict set...
if(n.length > 1){
conflicts[gid] = n
n.forEach(function(g){ conflicts[g] = n })
max = Math.max(max, n.length)
}
})
// list only the conflicting gids...
//return gids.length > 0 ?
return Object.keys(conflicts).length > 0 ?
{
conflicts: conflicts,
max_repetitions: max,
}
: false
}],
// Settings...
//
toggleRibbonFocusMode : ['Interface/Ribbon focus mode',
core.makeConfigToggler('ribbon-focus-mode',
function(){ return this.config['ribbon-focus-modes'] })],

View File

@ -1672,7 +1672,6 @@ var FileSystemWriterActions = actions.Actions({
'export-preview-size-limit': 'no limit',
},
// Save index...
//
// Returns:
@ -1726,6 +1725,7 @@ var FileSystemWriterActions = actions.Actions({
var full_path = path +'/'+ this.config['index-dir']
return file.writeIndex(
index.index,
// XXX should we check if index dir is present in path???
@ -1766,6 +1766,8 @@ var FileSystemWriterActions = actions.Actions({
// Export current state as a full loadable index
//
// XXX add name conflict resolution strategies (pattern)...
// ...use the same strategy as for .exportDirs(..)
// XXX resolve env variables in path...
// XXX what should happen if no path is given???
// XXX add preview selection...
@ -1824,6 +1826,15 @@ var FileSystemWriterActions = actions.Actions({
// XXX should also optionally populate the base dir and nested favs...
var base_dir = this.location.path
// check if we have naming conflicts...
// XXX use this to update names...
var conflicts = this.imageNameConflicts()
// XXX
conflicts
&& console.log('ERR: images with conflicting names present.')
var queue = []
gids.map(function(gid){
@ -1910,26 +1921,116 @@ var FileSystemWriterActions = actions.Actions({
return Promise.all(queue)
}],
formatImageName: ['- File/',
core.doc`
Filename patterns:
%f - full file name (same as: %n%e)
%n - name without extension
%e - extension with leading dot
%gid - full image gid
%g - short gid
%i - image index in ribbon
%I - global image index
%t - total number of images in ribbon
%T - total number of images
%(...)m - add text in braces if image marked
%(...)b - add text in braces if image is bookmark
%(...)c - add text in braces if there are name conflicts.
NOTE: this will be added to all images.
%(...)C - add text in braces if there are name conflicts
present, but only if the current image has a
conflicting name.
%c - number in set of conflicting names (default: 0).
NOTE: all group patterns (i.e. '%(..)x') can include other patterns.
`,
function(pattern, name, data){
pattern = pattern || '%f'
data = data || {}
var gid = data.gid
if(!gid && name in this.images){
gid = name
name = this.images[gid].name || gid
}
gid = gid || this.current
var ribbon = this.data.getRibbon(gid)
var img = this.image
name = name || pathlib.basename(img.path || (img.name + img.ext))
var ext = pathlib.extname(name)
var tags = data.tags || this.data.getTags(gid)
// XXX revise defaults...
var len = data.len || this.data.ribbons[ribbon].len
var total_len = data.total_len || this.data.length
var i = data.i || this.data.getImageOrder('ribbon', gid)
var I = data.I || this.data.getImageOrder('loaded', gid)
// pad with zeros...
i = (i+'').padStart((len + '').length, '0')
I = (I+'').padStart((total_len + '').length, '0')
//i = ((('1e'+(len+'').length)*1 + i) + '').slice(1)
//I = ((('1e'+(total_len+'').length)*1 + I) + '').slice(1)
var conflicts = data.conflicts
return pattern
// file name...
.replace(/%f/, name)
.replace(/%n/, name.replace(ext, ''))
.replace(/%e/, ext)
// gid...
.replace(/%gid/, gid)
// XXX get the correct short gid length...
.replace(/%g/, gid.slice(-7, -1))
// order...
.replace(/%i/, i)
.replace(/%I/, I)
// totals...
.replace(/%t/, len)
.replace(/%T/, total_len)
// conflict count...
.replace(/%c/, (conflicts && conflicts[gid]) ?
conflicts[gid].indexOf(gid)
: 0)
// metadata...
// XXX
// Group patterns...
// tags...
// XXX test: %n%(b)b%(m)m%e
.replace(
/%\(([^)]*)\)m/, tags.indexOf('selected') >= 0 ? '$1' : '')
.replace(
/%\(([^)]*)\)b/, tags.indexOf('bookmark') >= 0 ? '$1' : '')
// conflicts...
.replace(
/%\(([^)]*)\)c/, conflicts ? '$1' : '')
.replace(
/%\(([^)]*)\)C/, (conflicts || {})[gid] ? '$1' : '')
}],
//
// Filename patterns:
// %f - full file name (same as: %n%e)
// %n - name without extension
// %e - extension with leading dot
//
// %gid - full image gid
// %g - short gid (XXX set length in options)
//
// %i - image index in ribbon
// %I - global image index (XXX global or crop???)
//
// %t - total number of images in ribbon
// %T - total number of images (XXX global or crop???)
//
// %(...)m - add text in braces if image marked
// %(...)b - add text in braces if image is bookmark
//
//
// XXX add name conflict resolution strategies (pattern)...
// ...use the same strategy as for .exportIndex(..)
// XXX should %T / %I be global or current crop???
// XXX set length of %g in options...
// XXX might also be good to save/load the export options to .ImageGrid-export.json
// XXX resolve env variables in path... (???)
// XXX make custom previews (option)...
@ -1939,6 +2040,9 @@ var FileSystemWriterActions = actions.Actions({
// XXX use tasks...
// XXX check global index ('%I') in crop...
exportDirs: ['- File/Export/Export ribbons as directories',
core.doc`Export ribbons as directories
`,
function(path, pattern, level_dir, size, logger){
logger = logger || this.logger
logger = logger && logger.push('Export dirs')
@ -1966,6 +2070,15 @@ var FileSystemWriterActions = actions.Actions({
size = size || this.config['export-preview-size'] || 1000
pattern = pattern || this.config['export-preview-name-pattern'] || '%f'
// check if we have naming conflicts...
// XXX use this to update names...
var conflicts = this.imageNameConflicts()
// XXX
conflicts
&& console.log('ERR: images with conflicting names present.')
// XXX need to abort on fatal errors...
return Promise.all(this.data.ribbon_order
.slice()
@ -1995,50 +2108,19 @@ var FileSystemWriterActions = actions.Actions({
+'/'
+ that.images.getBestPreview(gid, size).url)
// XXX see if we need to make a preview (sharp)
// XXX
// XXX get/form image name...
// XXX might be a good idea to connect this to the info framework...
var ext = pathlib.extname(img_name)
var tags = that.data.getTags(gid)
var i = that.data.getImageOrder('ribbon', gid)
var I = that.data.getImageOrder('global', gid)
// pad indexes...
// XXX should these be optional???
i = ((('1e'+(len+'').length)*1 + i) + '').slice(1)
I = ((('1e'+(total_len+'').length)*1 + I) + '').slice(1)
var name = pattern
// file name...
.replace(/%f/, img_name)
.replace(/%n/, img_name.replace(ext, ''))
.replace(/%e/, ext)
// gid...
.replace(/%gid/, gid)
// XXX get the correct short gid length...
.replace(/%g/, gid.slice(-7, -1))
// order...
.replace(/%i/, i)
.replace(/%I/, I)
// totals...
.replace(/%t/, len)
.replace(/%T/, total_len)
// tags...
// XXX test: %n%(b)b%(m)m%e
.replace(
/%\(([^)]*)\)m/, tags.indexOf('selected') >= 0 ? '$1' : '')
.replace(
/%\(([^)]*)\)b/, tags.indexOf('bookmark') >= 0 ? '$1' : '')
// metadata...
// XXX
var name = that.formatImageName(pattern,
gid,
{
len: len,
total_len: total_len,
conflicts: conflicts.conflicts,
})
var to = img_dir +'/'+ name

View File

@ -993,7 +993,7 @@ var DataPrototype = {
// appropriate before/after image in that ribbon and get it's
// order.
getImageOrder: function(context, target, mode, list){
if(context == 'loaded'){
if(context == 'loaded' || context == 'global'){
return this.getImages('loaded').indexOf(this.getImage(target, mode, list))
} else if(context == 'ribbon'){