diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index ecb3fe0dc..fe05585e4 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -409,7 +409,7 @@ deterministic begin - update Storage set DiskSpace = DiskSpace + space where Id = StorageId; + update Storage set DiskSpace = COALESCE(DiskSpace,0) + COALESCE(space,0) where Id = StorageId; end; @@ -496,7 +496,9 @@ DROP TRIGGER IF EXISTS event_delete_trigger// CREATE TRIGGER event_delete_trigger BEFORE DELETE ON Events FOR EACH ROW BEGIN - call update_storage_stats(OLD.StorageId, -OLD.DiskSpace); + IF ( OLD.DiskSpace ) THEN + call update_storage_stats(OLD.StorageId, -OLD.DiskSpace); + END IF; DELETE FROM Events_Hour WHERE EventId=OLD.Id; DELETE FROM Events_Day WHERE EventId=OLD.Id; DELETE FROM Events_Week WHERE EventId=OLD.Id; diff --git a/db/zm_update-1.31.37.sql b/db/zm_update-1.31.37.sql new file mode 100644 index 000000000..866fd9330 --- /dev/null +++ b/db/zm_update-1.31.37.sql @@ -0,0 +1,49 @@ +DROP PROCEDURE IF EXISTS update_storage_stats; + +DELIMITER // + +CREATE PROCEDURE update_storage_stats(IN StorageId smallint(5), IN space BIGINT) + +sql security invoker + +deterministic + +begin + + update Storage set DiskSpace = COALESCE(DiskSpace,0) + COALESCE(space,0) where Id = StorageId; + +end; + +// + +DROP TRIGGER IF EXISTS event_delete_trigger// + +CREATE TRIGGER event_delete_trigger BEFORE DELETE ON Events +FOR EACH ROW + BEGIN + IF ( OLD.DiskSpace ) THEN + call update_storage_stats(OLD.StorageId, -OLD.DiskSpace); + END IF; + DELETE FROM Events_Hour WHERE EventId=OLD.Id; + DELETE FROM Events_Day WHERE EventId=OLD.Id; + DELETE FROM Events_Week WHERE EventId=OLD.Id; + DELETE FROM Events_Month WHERE EventId=OLD.Id; + IF ( OLD.Archived ) THEN + DELETE FROM Events_Archived WHERE EventId=OLD.Id; + UPDATE Monitors SET + ArchivedEvents = ArchivedEvents - 1, + ArchivedEventDiskSpace = COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0), + TotalEvents = TotalEvents - 1, + TotalEventDiskSpace = COALESCE(TotalEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) + WHERE Id=OLD.MonitorId; + ELSE + UPDATE Monitors SET + TotalEvents = TotalEvents-1, + TotalEventDiskSpace=COALESCE(TotalEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) + WHERE Id=OLD.MonitorId; + END IF; + END; + +// + +UPDATE Storage SET DiskSpace=(SELECT SUM(COALESCE(DiskSpace,0)) FROM Events WHERE StorageId=Storage.Id)// diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm index 766436a84..0eb9e2763 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm @@ -470,7 +470,7 @@ sub DiskSpace { $_[0]{DiskSpace} = $size; Debug("DiskSpace for event $_[0]{Id} at $_[0]{Path} Updated to $size bytes"); } else { - Warning("Event does not exist at $_[0]{Path}"); + Warning("DiskSpace: Event does not exist at $_[0]{Path}:" . $Event->to_string() ); } } # end if ! defined DiskSpace return $_[0]{DiskSpace}; diff --git a/version b/version index c2db3b3d2..c6e42f25b 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.31.36 +1.31.37 diff --git a/web/skins/classic/css/base/views/montagereview.css b/web/skins/classic/css/base/views/montagereview.css index e82e5ae95..4fb55a337 100644 --- a/web/skins/classic/css/base/views/montagereview.css +++ b/web/skins/classic/css/base/views/montagereview.css @@ -2,7 +2,6 @@ #SpeedDiv{ vertical-align: top; display: inline-flex; - border: 1px solid black; width: 25%; padding: 4px; } @@ -10,6 +9,14 @@ #SpeedDiv label { margin: 0; } +#ButtonsDiv { + display: inline-flex; + flex-flow: row-wrap; +} +#ButtonsDiv button { +display: inline-flex; +min-width: 0; +} #DateTimeDiv { display: inline-flex; } @@ -23,7 +30,7 @@ #timelinediv { margin: 2px auto; position:relative; - width:93%; + width:100%; } #timeline { diff --git a/web/skins/classic/css/base/views/zone.css b/web/skins/classic/css/base/views/zone.css index 6b35ca287..c2feb6734 100644 --- a/web/skins/classic/css/base/views/zone.css +++ b/web/skins/classic/css/base/views/zone.css @@ -52,11 +52,11 @@ } #imageFrame div { - background-image: url(../../../graphics/point-g.png); + background-image: url(/zm/skins/classic/graphics/point-g.png); } #imageFrame div.highlight { - background-image: url(../../../graphics/point-o.png); + background-image: url(/zm/skins/classic/graphics/point-o.png); } #imageFrame div.active { diff --git a/web/skins/classic/includes/export_functions.php b/web/skins/classic/includes/export_functions.php index 246554564..5d23b1125 100644 --- a/web/skins/classic/includes/export_functions.php +++ b/web/skins/classic/includes/export_functions.php @@ -72,7 +72,7 @@ html ul.tabs li.active, html ul.tabs li.active a:hover { --> @@ -140,7 +141,11 @@ echo output_link_if_exists( array( + + - - - - - + + + + $limit ) { $nEvents = $limit; } $pages = (int)ceil($nEvents/ZM_WEB_EVENTS_PER_PAGE); +#Logger::Debug("Page $page Limit $limit #vents: $nEvents pages: $pages "); if ( !empty($page) ) { if ( $page < 0 ) $page = 1; - else if ( $page > $pages ) + else if ( $pages and ( $page > $pages ) ) $page = $pages; $limitStart = (($page-1)*ZM_WEB_EVENTS_PER_PAGE); diff --git a/web/skins/classic/views/js/console.js b/web/skins/classic/views/js/console.js index 2121b6e39..b6d08e525 100644 --- a/web/skins/classic/views/js/console.js +++ b/web/skins/classic/views/js/console.js @@ -1,22 +1,35 @@ -var jsTranslatedAddText; -var jsTranslatedCloneText; function setButtonStates( element ) { var form = element.form; var checked = 0; - for ( var i = 0; i < form.elements.length; i++ ) { - if ( form.elements[i].type == "checkbox" ) { + for ( var i=0; i < form.elements.length; i++ ) { + if ( + form.elements[i].type=="checkbox" + && + form.elements[i].name=="markMids[]" + ) { + var tr = $j(form.elements[i]).closest("tr"); if ( form.elements[i].checked ) { - if ( checked++ > 1 ) - break; + checked ++; + tr.addClass("danger"); + } else { + tr.removeClass("danger"); } } } - $(element).closest("tr").toggleClass("danger"); - form.editBtn.disabled = checked ? false : true; - form.addBtn.value = (checked==1) ? jsTranslatedCloneText:jsTranslatedAddText; - - form.deleteBtn.disabled = (checked==0); + if ( checked ) { + form.editBtn.disabled = false; + form.deleteBtn.disabled = false; + if ( checked == 1 ) { + $j(form.cloneBtn).css('display','inline'); + } else { + form.cloneBtn.hide(); + } + } else { + form.cloneBtn.hide(); + form.editBtn.disabled = true; + form.deleteBtn.disabled = true; + } } function addMonitor(element) { @@ -75,8 +88,6 @@ function reloadWindow() { } function initPage() { - jsTranslatedAddText = translatedAddText; - jsTranslatedCloneText = translatedCloneText; reloadWindow.periodical( consoleRefreshTimeout ); if ( showVersionPopup ) createPopup( '?view=version', 'zmVersion', 'version' ); @@ -84,7 +95,7 @@ function initPage() { createPopup( '?view=donate', 'zmDonate', 'donate' ); // Makes table sortable -$j( function() { + $j( function() { $j( "#consoleTableBody" ).sortable({ handle: ".glyphicon-sort", update: applySort, diff --git a/web/skins/classic/views/js/console.js.php b/web/skins/classic/views/js/console.js.php index 006cfc565..f5e65332d 100644 --- a/web/skins/classic/views/js/console.js.php +++ b/web/skins/classic/views/js/console.js.php @@ -18,5 +18,3 @@ if ( ZM_CHECK_FOR_UPDATES && canEdit('System') && ZM_DYN_LAST_VERSION && ( verNu ?> var showVersionPopup = ; var showDonatePopup = ; -var translatedAddText = ""; -var translatedCloneText = ""; diff --git a/web/skins/classic/views/js/montagereview.js b/web/skins/classic/views/js/montagereview.js index a07a0ccc6..63fce8910 100644 --- a/web/skins/classic/views/js/montagereview.js +++ b/web/skins/classic/views/js/montagereview.js @@ -49,28 +49,28 @@ function SetImageSource( monId, time ) { if ( liveMode == 1 ) { return monitorImageObject[monId].src.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) )); - } else { - for ( var i=0, eIdlength = eId.length; i < eIdlength; i++ ) { - // Search for the event matching this time. Would be more efficient if we had events indexed by monitor - if ( eMonId[i] == monId && time >= eStartSecs[i] && time <= eEndSecs[i] ) { - var duration = eEndSecs[i]-eStartSecs[i]; - var frame = parseInt((time - eStartSecs[i])/(duration)*eventFrames[i])+1; - var storage = Storage[eStorageId[i]]; - if ( storage.ServerId ) { - var server = Servers[storage.ServerId]; - if ( server ) { -//console.log( server.Hostname + " for event " + eId[i] ); - return location.protocol + '//' + server.Hostname + '/index.php?view=image&eid=' + eId[i] + '&fid='+frame + "&width=" + monitorCanvasObj[monId].width + "&height=" + monitorCanvasObj[monId].height; - } else { - console.log("No server found for " + storage.ServerId ); - } - } - //console.log("No storage found for " + eStorageId[i] ); - return "index.php?view=image&eid=" + eId[i] + '&fid='+frame + "&width=" + monitorCanvasObj[monId].width + "&height=" + monitorCanvasObj[monId].height; - } - } // end for - return "no data"; } + + for ( var i=0, eIdlength = eId.length; i < eIdlength; i++ ) { + // Search for the event matching this time. Would be more efficient if we had events indexed by monitor + if ( eMonId[i] == monId && time >= eStartSecs[i] && time <= eEndSecs[i] ) { + var duration = eEndSecs[i]-eStartSecs[i]; + var frame = parseInt((time - eStartSecs[i])/(duration)*eventFrames[i])+1; + var storage = Storage[eStorageId[i]]; + if ( storage.ServerId ) { + var server = Servers[storage.ServerId]; + if ( server ) { +//console.log( server.Hostname + " for event " + eId[i] ); + return location.protocol + '//' + server.Hostname + '/index.php?view=image&eid=' + eId[i] + '&fid='+frame + "&width=" + monitorCanvasObj[monId].width + "&height=" + monitorCanvasObj[monId].height; + } else { + console.log("No server found for " + storage.ServerId ); + } + } + //console.log("No storage found for " + eStorageId[i] ); + return "index.php?view=image&eid=" + eId[i] + '&fid='+frame + "&width=" + monitorCanvasObj[monId].width + "&height=" + monitorCanvasObj[monId].height; + } + } // end for + return "no data"; } // callback when loading an image. Will load itself to the canvas, or draw no data @@ -164,7 +164,7 @@ function loadImage2Monitor( monId, url ) { function timerFire() { // See if we need to reschedule - if ( currentDisplayInterval != timerInterval || currentSpeed == 0 ) { + if ( ( currentDisplayInterval != timerInterval ) || ( currentSpeed == 0 ) ) { // zero just turn off interrupts clearInterval(timerObj); timerInterval=currentDisplayInterval; @@ -335,60 +335,61 @@ function drawGraph() { } function redrawScreen() { - if ( liveMode == 1 ) { + if ( liveMode == 1 ) { // if we are not in live view switch to history -- this has to come before fit in case we re-establish the timeline - $('DateTimeDiv').style.display="none"; - $('SpeedDiv').style.display="none"; - $('timelinediv').style.display="none"; - $('live').innerHTML="History"; - $('zoomin').style.display="none"; - $('zoomout').style.display="none"; - $('panleft').style.display="none"; - $('panright').style.display="none"; - if ($('downloadVideo')) $('downloadVideo').style.display="none"; + $('DateTimeDiv').style.display="none"; + $('SpeedDiv').style.display="none"; + $('timelinediv').style.display="none"; + $('live').innerHTML="History"; + $('zoomin').style.display="none"; + $('zoomout').style.display="none"; + $('panleft').style.display="none"; + $('panright').style.display="none"; + if ($('downloadVideo')) $('downloadVideo').style.display="none"; - } else { + } else { // switch out of liveview mode - $('DateTimeDiv').style.display="inline"; - $('SpeedDiv').style.display="inline"; - $('SpeedDiv').style.display="inline-flex"; - $('timelinediv').style.display=null; - $('live').innerHTML="Live"; - $('zoomin').style.display="inline"; - $('zoomin').style.display="inline-flex"; - $('zoomout').style.display="inline"; - $('zoomout').style.display="inline-flex"; - $('panleft').style.display="inline"; - $('panleft').style.display="inline-flex"; - $('panright').style.display="inline"; - $('panright').style.display="inline-flex"; - if ($('downloadVideo')) $('downloadVideo').style.display="inline"; - } + $('DateTimeDiv').style.display="inline"; + $('DateTimeDiv').style.display="inline-flex"; + $('SpeedDiv').style.display="inline"; + $('SpeedDiv').style.display="inline-flex"; + $('timelinediv').style.display=null; + $('live').innerHTML="Live"; + $('zoomin').style.display="inline"; + $('zoomin').style.display="inline-flex"; + $('zoomout').style.display="inline"; + $('zoomout').style.display="inline-flex"; + $('panleft').style.display="inline"; + $('panleft').style.display="inline-flex"; + $('panright').style.display="inline"; + $('panright').style.display="inline-flex"; + if ($('downloadVideo')) $('downloadVideo').style.display="inline"; + } - if ( fitMode == 1 ) { - $('ScaleDiv').style.display="none"; - $('fit').innerHTML="Scale"; - var vh=window.innerHeight; - var vw=window.innerWidth; - var pos=$('monitors').getPosition(); - var mh=(vh - pos.y - $('fps').getSize().y); - $('monitors').setStyle('height',mh.toString() + "px"); // leave a small gap at bottom - if(maxfit2($('monitors').getSize().x,$('monitors').getSize().y) == 0) /// if we fail to fix we back out of fit mode -- ??? This may need some better handling - fitMode=1-fitMode; - } else { - // switch out of fit mode - // if we fit, then monitors were absolutely positioned already (or will be) otherwise release them to float - for( var i=0; i fps -
+