added progress indication to workers (STUB?)...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2014-01-23 06:56:17 +04:00
parent 389264f09d
commit ba46bc3707
8 changed files with 231 additions and 39 deletions

View File

@ -109,23 +109,7 @@ Roadmap
[_] 31% Gen 3 current todo
[_] 62% High priority
[_] Might be a good idea to use sparse arrays for things like marks...
| eliminate:
| - need for keeping things sorted all the time
| - speed-up access -- everything has the same index
| - speed-up modification -- just mirror all the operations
| - searching in more than one place
|
| introduce:
| - memory overhead - each array is always N elements
| - conversion on import, export and crop
| need to clear / insert all the nulls
|
| candidates:
| - marks
| - bookmarks
| - tags
[_] 63% High priority
[_] BUG: sorting breaks when at or near the end of a ribbon...
|
| Race condition...
@ -148,6 +132,8 @@ Roadmap
| 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)
|
| NOTE: appears to affect beginning of the ribbon too...
[_] BUG: sorting mis-aligns ribbons in some cases...
| Example:
| oooo... --[reverse]-> ...oooo
@ -560,6 +546,21 @@ Roadmap
| drops to last placeholder
|
[_] single image mode transition (alpha-blend/fade/none)
[X] Might be a good idea to use sparse arrays for things like marks...
| eliminate:
| - need for keeping things sorted all the time
| - speed-up access -- everything has the same index
| - speed-up modification -- just mirror all the operations
| - searching in more than one place
|
| introduce:
| - conversion on import, export and crop
| need to clear / insert all the nulls
|
| candidates:
| - marks
| - bookmarks
| - tags
[X] crop/filter/search dialog...
| make a number of fields each accepting a filter -- string/regexp
[X] Q: how do we mark unsorted sections in base ribbon after aligning?

View File

@ -364,14 +364,14 @@ if(window.CEF_dumpJSON != null){
window.makeImagesPreviewsQ = function(gids, sizes, mode){
gids = gids == null ? getClosestGIDs() : gids
var queue = getWorkerQueue('preview_generator')
var queue = getWorkerQueue('Generate previews', 4)
// attach the workers to the queue...
$.each(gids, function(_, gid){
queue.enqueue(null, makeImagePreviews, gid, sizes, mode)
queue.enqueue(makeImagePreviews, gid, sizes, mode)
// XXX do we need to report seporate previews???
//.progress(function(state){ queue.notify(state) })
.always(function(){ queue.notify(gid, 'done') })
.always(function(){ console.log(gid, 'done') })
})
return queue

View File

@ -684,7 +684,7 @@ function loadRawDir(path, no_preview_processing, prefix){
if(!no_preview_processing){
res.notify(prefix, 'Loading/Generating', 'Previews.')
var p = makeImagesPreviewsQ()
.done(function(){
.depleted(function(){
res.notify(prefix, 'Loaded', 'Previews.')
})
@ -844,7 +844,8 @@ function exportImagesTo(path, im_name, dir_name, size){
var z = (('10e' + (selection.length + '').length) * 1 + '').slice(2)
// use an external pool...
var pool = makeDeferredPool()
//var pool = makeDeferredPool()
var pool = getWorkerQueue('Export previews', 64)
.depleted(function(){
showStatusQ('Export: done.')
res.resolve()
@ -929,7 +930,7 @@ function readImagesOrientation(gids, no_update_loaded){
function readImagesOrientationQ(gids, no_update_loaded){
gids = gids == null ? getClosestGIDs() : gids
var queue = getWorkerQueue('image_orientation_reader')
var queue = getWorkerQueue('Read images orientation', 4)
var last = null
@ -963,7 +964,7 @@ function readImagesDates(images){
function readImagesDatesQ(images){
images = images == null ? IMAGES : images
var queue = getWorkerQueue('date_reader')
var queue = getWorkerQueue('Read images dates', 4)
$.each(images, function(gid, img){
queue.enqueue(readImageDate, gid, images)
@ -1020,7 +1021,7 @@ function updateImagesGIDs(images, data){
function updateImagesGIDsQ(images, data){
images = images == null ? IMAGES : images
var queue = getWorkerQueue('gid_updater')
var queue = getWorkerQueue('Update GIDs', 4)
$.each(images, function(_, key){
queue.enqueue(updateImageGID, key, images, data)

View File

@ -79,7 +79,10 @@ var KEYBOARD_CONFIG = {
},
F5: doc('Full reload viewer',
function(){
reload()
killAllWorkers()
.done(function(){
reload()
})
return false
}),
F12: doc('Show devTools',

View File

@ -1141,6 +1141,64 @@ button:hover {
font-size: 14px;
opacity: 0.8;
}
/*************************************************** Progress bars ***/
progress {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
height: 8px;
}
progress::-webkit-progress-bar {
background: transparent;
border: solid 1px gray;
border-radius: 3px;
padding: 1px;
box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.2) inset;
}
progress::-webkit-progress-value {
background: yellow;
border-radius: 2px;
box-shadow: -1px -1px 5px -2px rgba(0, 0, 0, 0.8) inset;
}
/*
progress:not(value)::-webkit-progress-bar {
background: transparent;
background-image:
-webkit-linear-gradient(-45deg, transparent 33%, rgba(0,0,0,0.2) 33%,
rgba(0,0,0,0.2) 66%, transparent 66%),
-webkit-linear-gradient(left, yellow, orange, yellow);
background-size: 50px 50px;
-webkit-animation: animate-progress 5s linear infinite;
animation: animate-progress 5s linear infinite;
}
@-webkit-keyframes animate-progress {
100% {
background-position: -100% 0px;
}
}
@keyframes animate-progress {
100% {
background-position: -100% 0px;
}
}
*/
.progress-container {
position: absolute;
}
.progress-container:empty {
display: none;
}
.progress-bar {
color: silver;
font-size: 10px;
margin: 10px;
}
.progress-bar progress {
display: block;
width: 300px;
}
/********************************************** Mode: single image ***/
.single-image-mode.viewer .ribbon {
background-color: transparent;

View File

@ -1186,6 +1186,71 @@ button:hover {
/*************************************************** Progress bars ***/
progress {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
height: 8px;
}
progress::-webkit-progress-bar {
background: transparent;
border: solid 1px gray;
border-radius: 3px;
padding: 1px;
box-shadow: 0px 2px 5px rgba(0,0,0,0.2) inset;
}
progress::-webkit-progress-value {
background: yellow;
border-radius: 2px;
box-shadow: -1px -1px 5px -2px rgba(0,0,0,0.8) inset;
}
/*
progress:not(value)::-webkit-progress-bar {
background: transparent;
background-image:
-webkit-linear-gradient(-45deg, transparent 33%, rgba(0,0,0,0.2) 33%,
rgba(0,0,0,0.2) 66%, transparent 66%),
-webkit-linear-gradient(left, yellow, orange, yellow);
background-size: 50px 50px;
-webkit-animation: animate-progress 5s linear infinite;
animation: animate-progress 5s linear infinite;
}
@-webkit-keyframes animate-progress {
100% {
background-position: -100% 0px;
}
}
@keyframes animate-progress {
100% {
background-position: -100% 0px;
}
}
*/
.progress-container {
position: absolute;
}
.progress-container:empty {
display: none;
}
.progress-bar {
color: silver;
font-size: 10px;
margin: 10px;
}
.progress-bar progress {
display: block;
width: 300px;
}
/********************************************** Mode: single image ***/
.single-image-mode.viewer .ribbon {

View File

@ -628,7 +628,6 @@ jQuery.fn.sortChildren = function(func){
// Register a progress handler.
// The handler is called after each worker is done and will get
// passed:
// - pool
// - workers done count
// - workers total count
// NOTE: the total number of workers can change as new workers
@ -638,7 +637,6 @@ jQuery.fn.sortChildren = function(func){
// Register a worker fail handler.
// The handler is called when a worker goes into the fail state.
// This will get passed:
// - pool
// - workers done count
// - workers total count
// NOTE: this will not stop the execution of other handlers.
@ -698,7 +696,7 @@ function makeDeferredPool(size, paused){
var i = pool.indexOf(worker)
Pool._progress_handlers.forEach(function(func){
func(worker, pool.length - pool.len(), pool.length + queue.length)
func(pool.length - pool.len(), pool.length + queue.length)
})
// remove self from queue...
@ -715,7 +713,7 @@ function makeDeferredPool(size, paused){
// if pool is empty fire the pause event...
if(pool.len() == 0){
Pool._pause_handlers.forEach(function(func){
func(that)
func()
})
}
return
@ -730,12 +728,13 @@ function makeDeferredPool(size, paused){
// empty queue AND empty pool mean we are done...
} else if(pool.len() == 0){
var l = pool.length
// NOTE: potential race condition -- something can be
// pushed to pool just before it's "compacted"...
pool.length = 0
that._deplete_handlers.forEach(function(func){
func(that)
func(l)
})
}
@ -744,7 +743,7 @@ function makeDeferredPool(size, paused){
})
.fail(function(){
Pool._fail_handlers.forEach(function(func){
func(that, pool.length - pool.len(), pool.length + queue.length)
func(pool.length - pool.len(), pool.length + queue.length)
})
deferred.reject.apply(deferred, arguments)
})

View File

@ -16,16 +16,61 @@ var WORKERS = {}
// get/create a named worker queue...
//
// XXX rename this to task-related.... (???)
function getWorkerQueue(name, pool_size, no_auto_start){
// XXX rename this to something task-related.... (???)
function getWorkerQueue(name, pool_size, no_auto_start, no_progress){
// XXX 1 is the default for compatibility...
pool_size = pool_size == null ? 1 : pool_size
// XXX experimental -- STUB...
if(!no_progress){
var container = $('.progress-container')
if(container.length == 0){
container = $('<div class="progress-container"/>')
.appendTo($('.viewer'))
}
var progress = $('<div class="progress-bar">'+name+'</div>')
.appendTo(container)
var progress_state = $('<span class="state"/>')
.appendTo(progress)
var progress_bar = $('<progress id="'+name+'"/>')
.appendTo(progress)
// XXX for some reason without this, here the progress handlers
// later lose context...
progress = $(progress[0])
progress_bar = $(progress_bar[0])
}
// create a new worker queue...
if(WORKERS[name] == null){
var queue = makeDeferredPool(pool_size, no_auto_start)
WORKERS[name] = queue
// XXX experimental...
if(!no_progress){
queue
.progress(function(done, total){
progress_bar
.attr({
value: done,
max: total
})
progress_state
.text(' ('+done+' of '+total+')')
})
.depleted(function(done){
progress_bar
.attr('value', done)
progress_state
.text(' (done)')
setTimeout(function(){
progress
.remove()
}, 1500)
})
}
// return existing worker queue...
} else {
var queue = WORKERS[name]
@ -35,15 +80,35 @@ function getWorkerQueue(name, pool_size, no_auto_start){
}
// kill all worker queues...
// Kill all worker queues...
//
// Returns a deffered object that will get resolved when all workers are
// actually stopped...
function killAllWorkers(){
for(var k in WORKERS){
var res = $.Deferred()
var w = []
Object.keys(WORKERS).forEach(function(k){
if(WORKERS[k].isRunning()){
console.log('Worker: Stopped:', k)
var wd = $.Deferred()
w.push(wd)
WORKERS[k]
.depleted(function(){
console.log('Worker: Stopped:', k)
wd.resolve()
})
}
WORKERS[k].dropQueue()
}
WORKERS[k]
.dropQueue()
})
WORKERS = {}
$.when.apply(null, w)
.done(function(){
console.log('Worker: All workers stopped.')
res.resolve()
})
return res
}