Update the UI to show if a scenario has been modified.

master
Pacman Ghost 4 years ago
parent 54008b118e
commit 04f1755415
  1. 8
      vasl_templates/main_window.py
  2. 11
      vasl_templates/web_channel.py
  3. 12
      vasl_templates/webapp/static/main.js
  4. 24
      vasl_templates/webapp/static/snippets.js
  5. 22
      vasl_templates/webapp/tests/test_dirty_scenario_checks.py
  6. 2
      vasl_templates/webapp/tests/test_scenario_persistence.py

@ -297,11 +297,11 @@ class MainWindow( QWidget ):
for key,val in user_settings.items():
app_settings.setValue( "UserSettings/{}".format(key), val )
@pyqtSlot( str )
@pyqtSlot( str, bool )
@catch_exceptions( caption="SLOT EXCEPTION" )
def on_scenario_details_change( self, val ):
"""Update the main window title to show the scenario details."""
self._web_channel_handler.on_scenario_details_change( val )
def on_update_scenario_status( self, caption, is_dirty ):
"""Update the UI to show the scenario's status."""
self._web_channel_handler.on_update_scenario_status( caption, is_dirty )
@pyqtSlot( str )
@catch_exceptions( caption="SLOT EXCEPTION" )

@ -53,11 +53,14 @@ class WebChannelHandler:
return None
return self.scenario_file_dialog.curr_fname
def on_scenario_details_change( self, val ):
def on_update_scenario_status( self, caption, is_dirty ):
"""Update the main window title to show the scenario details."""
self.parent.setWindowTitle(
"{} - {}".format( APP_NAME, val ) if val else APP_NAME
)
title = APP_NAME
if caption:
title += " - {}".format( caption )
if is_dirty:
title += " (*)"
self.parent.setWindowTitle( title )
def on_snippet_image( self, img_data ): #pylint: disable=no-self-use
"""Called when a snippet image has been generated."""

@ -335,12 +335,12 @@ $(document).ready( function () {
.button( {} ) ;
// watch for changes to the scenario details
$("input[name='SCENARIO_NAME']").on( "input propertychange paste", function() {
on_scenario_details_change() ;
} ) ;
$("input[name='SCENARIO_ID']").on( "input propertychange paste", function() {
on_scenario_details_change() ;
} ) ;
$("input[name='SCENARIO_NAME']").on( "input propertychange paste", update_scenario_status ) ;
$("input[name='SCENARIO_ID']").on( "input propertychange paste", update_scenario_status ) ;
// NOTE: The following is to add/remove the "scenario modified" indicator. It's pretty inefficent
// to do this using a timer, but we would otherwise have to attach a "on change" event handler
// to every single input field, simple note, etc., which would be far more complicated and error-prone.
setInterval( update_scenario_status, 1*1000 ) ;
// adjust the layout on resize
$(window).resize( function() {

@ -1485,8 +1485,8 @@ function do_load_scenario_data( params )
// update the UI
$("#tabs").tabs( "option", "active", 0 ) ;
on_scenario_details_change() ;
on_scenario_date_change() ;
update_scenario_status() ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1716,10 +1716,10 @@ function reset_scenario()
// --------------------------------------------------------------------
function is_scenario_dirty()
function is_scenario_dirty( force )
{
// nb: confirming operations is insanely annoying during development :-/
if ( getUrlParam( "disable-dirty-scenario-check" ) )
if ( !force && getUrlParam( "disable-dirty-scenario-check" ) )
return false ;
// check if the scenario has been changed since it was loaded, or last saved
@ -1731,7 +1731,7 @@ function is_scenario_dirty()
last_saved_scenario[key] = gLastSavedScenario[key] ;
}
var params = unload_params_for_save( false ) ;
return (JSON.stringify(params) != JSON.stringify(last_saved_scenario) ) ;
return JSON.stringify( params ) != JSON.stringify( last_saved_scenario ) ;
}
// --------------------------------------------------------------------
@ -1980,9 +1980,9 @@ function _update_vo_sortable2_entries()
// --------------------------------------------------------------------
function on_scenario_details_change()
function update_scenario_status()
{
// update the document title to include the scenario details
// get the scenario details
var scenario_name = $("input[name='SCENARIO_NAME']").val().trim() ;
var scenario_id = $("input[name='SCENARIO_ID']").val().trim() ;
var caption = "" ;
@ -1992,13 +1992,19 @@ function on_scenario_details_change()
caption = scenario_name ;
else if ( scenario_id )
caption = scenario_id ;
document.title = gAppName ;
// update the window title
var title = gAppName ;
if ( caption )
document.title += " - " + caption ;
title += " - " + caption ;
var is_dirty = is_scenario_dirty( true ) ;
if ( is_dirty )
title += " (*)" ;
document.title = title ;
// notify the PyQt wrapper application
if ( gWebChannelHandler )
gWebChannelHandler.on_scenario_details_change( caption ) ;
gWebChannelHandler.on_update_scenario_status( caption, is_dirty ) ;
}
function on_scenario_theater_change()

@ -103,12 +103,29 @@ def test_dirty_scenario_checks( webapp, webdriver ):
else:
assert False
def check_is_dirty( expected ):
"""Check if the scenario is being flagged as dirty."""
if expected:
func = lambda: webdriver.title.endswith( " (*)" )
else:
func = lambda: not webdriver.title.endswith( " (*)" )
# NOTE: There is a race condition here if things are not working properly. Since the window title
# is updated on a timer, if we're expecting it to be (say) not modified, but the UI thinks that
# it is modified, we could check the window title here, see that the scenario is being flagged
# as not modified and continue on. The timer then fires, updates the UI to flag the scenario
# as modified, and we will have missed the error.
# To fix this, we force the scenario status to be updated.
webdriver.execute_script( "update_scenario_status()" )
wait_for( 2, func )
def do_test( tab_id, param ):
"""Test checking for a dirty scenario."""
# change the specified field
check_is_dirty( False )
select_tab( tab_id )
state = change_field( param )
check_is_dirty( True )
# make sure we get asked to confirm a "new scenario" operation
select_menu_option( "new_scenario" )
@ -120,9 +137,11 @@ def test_dirty_scenario_checks( webapp, webdriver ):
click_dialog_button( "Cancel" )
select_tab( tab_id )
check_field( param, state )
check_is_dirty( True )
# revert the change
revert_field( param, state )
check_is_dirty( False )
# we should now be able to reset the scenario without a confirmation
_ = set_stored_msg_marker( "_last-info_" )
@ -132,6 +151,7 @@ def test_dirty_scenario_checks( webapp, webdriver ):
# change the field again
select_tab( tab_id )
state = change_field( param )
check_is_dirty( True )
# make sure we get asked to confirm a "load scenario" operation
select_menu_option( "load_scenario" )
@ -143,9 +163,11 @@ def test_dirty_scenario_checks( webapp, webdriver ):
click_dialog_button( "Cancel" )
select_tab( tab_id )
check_field( param, state )
check_is_dirty( True )
# revert the change
revert_field( param, state )
check_is_dirty( False )
# we should be able to load a scenario without a confirmation
# NOTE: We don't do this, since it will cause the OPEN FILE dialog to come up :-/

@ -110,7 +110,7 @@ def test_scenario_persistence( webapp, webdriver ): #pylint: disable=too-many-st
},
}
load_scenario_params( SCENARIO_PARAMS )
check_window_title( "my test scenario (xyz123)" )
check_window_title( "my test scenario (xyz123) (*)" )
check_ob_tabs( "russian", "german" )
assert_scenario_params_complete( SCENARIO_PARAMS, True )

Loading…
Cancel
Save