diff -Nru ecflow-4.10.0/ACore/src/ecflow_version.h ecflow-4.11.1/ACore/src/ecflow_version.h --- ecflow-4.10.0/ACore/src/ecflow_version.h 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/ACore/src/ecflow_version.h 2018-10-23 11:41:34.000000000 +0000 @@ -1,9 +1,9 @@ #ifndef ecflow_version_config_h #define ecflow_version_config_h -#define ECFLOW_VERSION "4.10.0" +#define ECFLOW_VERSION "4.11.1" #define ECFLOW_RELEASE "4" -#define ECFLOW_MAJOR "10" -#define ECFLOW_MINOR "0" +#define ECFLOW_MAJOR "11" +#define ECFLOW_MINOR "1" #endif diff -Nru ecflow-4.10.0/ACore/test/TestStr.cpp ecflow-4.11.1/ACore/test/TestStr.cpp --- ecflow-4.10.0/ACore/test/TestStr.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/ACore/test/TestStr.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -691,4 +691,64 @@ // } //} + +BOOST_AUTO_TEST_CASE( test_str_valid_name ) +{ + cout << "ACore:: ...test_str_valid_name\n"; + + std::vector valid; + valid.push_back("a"); + valid.push_back("a122345"); + valid.push_back("_a122345"); + valid.push_back("_"); + valid.push_back("0"); + valid.push_back("1"); + valid.push_back("2"); + valid.push_back("3"); + valid.push_back("4"); + valid.push_back("5"); + valid.push_back("6"); + valid.push_back("7"); + valid.push_back("8"); + valid.push_back("9"); + valid.push_back("11"); + valid.push_back("111"); + for(size_t i = 0; i < valid.size(); i++) { + std::string msg; + BOOST_CHECK_MESSAGE( Str::valid_name( valid[i],msg ) ,"Expected " << valid[i] << " to be valid" ); + BOOST_CHECK_MESSAGE( Str::valid_name( valid[i]) ,"Expected " << valid[i] << " to be valid" ); + } + + BOOST_CHECK_MESSAGE( !Str::valid_name( "") ,"Expected empty string to be in-valid" ); + BOOST_CHECK_MESSAGE( !Str::valid_name( ".") ,"Expected '.' string to be in-valid" ); + std::vector invalid; + invalid.push_back("?"); + invalid.push_back("!"); + invalid.push_back("\""); + invalid.push_back("$"); + invalid.push_back("%"); + invalid.push_back("^"); + invalid.push_back("*"); + invalid.push_back("("); + invalid.push_back(")"); + invalid.push_back("-"); + invalid.push_back("+"); + invalid.push_back(":"); + invalid.push_back(";"); + invalid.push_back("@"); + invalid.push_back("~"); + invalid.push_back("<"); + invalid.push_back(">"); + invalid.push_back("!"); + for(size_t i = 0; i < invalid.size(); i++) { + std::string msg; + BOOST_CHECK_MESSAGE( !Str::valid_name( invalid[i],msg ) ,"Expected " << invalid[i] << " to be in-valid" ); + BOOST_CHECK_MESSAGE( !Str::valid_name( invalid[i]) ,"Expected " << invalid[i] << " to be in-valid" ); + + std::string s = "a" + invalid[i]; + BOOST_CHECK_MESSAGE( !Str::valid_name( s,msg ) ,"Expected " << s << " to be in-valid" ); + BOOST_CHECK_MESSAGE( !Str::valid_name( s ) ,"Expected " << s << " to be in-valid" ); + } +} + BOOST_AUTO_TEST_SUITE_END() diff -Nru ecflow-4.10.0/ANattr/src/RepeatAttr.hpp ecflow-4.11.1/ANattr/src/RepeatAttr.hpp --- ecflow-4.10.0/ANattr/src/RepeatAttr.hpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/ANattr/src/RepeatAttr.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -463,6 +463,13 @@ friend class boost::serialization::access; template void serialize(Archive & ar, const unsigned int /*version*/) { +#if defined(__clang__) + ar.register_type(static_cast(NULL)); + ar.register_type(static_cast(NULL)); + ar.register_type(static_cast(NULL)); + ar.register_type(static_cast(NULL)); + ar.register_type(static_cast(NULL)); +#endif ar & repeatType_; } }; diff -Nru ecflow-4.10.0/ANode/src/Attr.cpp ecflow-4.11.1/ANode/src/Attr.cpp --- ecflow-4.10.0/ANode/src/Attr.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/ANode/src/Attr.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -18,8 +18,6 @@ namespace ecf { -enum Type { EVENT =0, METER=1, LABEL=2, LIMIT=3, VARIABLE=4, }; - const char* Attr::to_string( Attr::Type s ) { switch ( s ) { case Attr::EVENT: @@ -37,6 +35,9 @@ case Attr::VARIABLE: return "variable"; break; + case Attr::ALL: + return "all"; + break; case Attr::UNKNOWN: return "unknown"; break; @@ -53,6 +54,7 @@ if ( str == "label" ) return Attr::LABEL; if ( str == "limit" ) return Attr::LIMIT; if ( str == "variable" ) return Attr::VARIABLE; + if ( str == "all" ) return Attr::ALL; return Attr::UNKNOWN; } @@ -62,25 +64,27 @@ std::vector< std::string > Attr::all_attrs() { std::vector vec; - vec.reserve( 5 ); + vec.reserve( 6 ); vec.push_back( "event" ); vec.push_back( "meter" ); vec.push_back( "label" ); vec.push_back( "limit" ); vec.push_back( "variable" ); + vec.push_back( "all" ); return vec; } std::vector Attr::attrs() { std::vector vec; - vec.reserve(5); + vec.reserve(6); vec.push_back( Attr::UNKNOWN ); vec.push_back( Attr::EVENT ); vec.push_back( Attr::METER ); vec.push_back( Attr::LABEL ); vec.push_back( Attr::LIMIT ); vec.push_back( Attr::VARIABLE ); + vec.push_back( Attr::ALL ); return vec; } } diff -Nru ecflow-4.10.0/ANode/src/Attr.hpp ecflow-4.11.1/ANode/src/Attr.hpp --- ecflow-4.10.0/ANode/src/Attr.hpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/ANode/src/Attr.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -22,7 +22,7 @@ namespace ecf { class Attr : private boost::noncopyable { public: - enum Type { UNKNOWN=0, EVENT=1, METER=2, LABEL=3, LIMIT=4, VARIABLE=5 }; + enum Type { UNKNOWN=0, EVENT=1, METER=2, LABEL=3, LIMIT=4, VARIABLE=5, ALL=6 }; static const char* to_string(Attr::Type s); static Attr::Type to_attr(const std::string& attr); diff -Nru ecflow-4.10.0/ANode/src/ChildAttrs.cpp ecflow-4.11.1/ANode/src/ChildAttrs.cpp --- ecflow-4.10.0/ANode/src/ChildAttrs.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/ANode/src/ChildAttrs.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -76,6 +76,17 @@ boost::bind(&Label::name,_1), boost::bind(&Label::name,_2))); break; + case Attr::ALL: + sort(events_.begin(),events_.end(),boost::bind(Str::caseInsLess, + boost::bind(&Event::name_or_number,_1), + boost::bind(&Event::name_or_number,_2))); + sort(meters_.begin(),meters_.end(),boost::bind(Str::caseInsLess, + boost::bind(&Meter::name,_1), + boost::bind(&Meter::name,_2))); + sort(labels_.begin(),labels_.end(),boost::bind(Str::caseInsLess, + boost::bind(&Label::name,_1), + boost::bind(&Label::name,_2))); + break; case Attr::LIMIT: break; case Attr::VARIABLE: break; case Attr::UNKNOWN: break; diff -Nru ecflow-4.10.0/ANode/src/Defs.cpp ecflow-4.11.1/ANode/src/Defs.cpp --- ecflow-4.10.0/ANode/src/Defs.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/ANode/src/Defs.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -547,7 +547,7 @@ void Defs::sort_attributes(ecf::Attr::Type attr,bool recursive) { - if (attr == ecf::Attr::VARIABLE) server_.sort_variables(); + if (attr == ecf::Attr::VARIABLE || attr == ecf::Attr::ALL) server_.sort_variables(); if (recursive) { size_t theSuiteVecSize = suiteVec_.size(); diff -Nru ecflow-4.10.0/ANode/src/ExprAst.cpp ecflow-4.11.1/ANode/src/ExprAst.cpp --- ecflow-4.10.0/ANode/src/ExprAst.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/ANode/src/ExprAst.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -45,7 +45,7 @@ theReasonWhy = "expression "; theReasonWhy += why_expression(html); // provide additional state - theReasonWhy += " does not evaluate"; + theReasonWhy += " is false"; #ifdef DEBUG_WHY std::cout << " Ast::why reason = " << theReasonWhy << "\n"; #endif diff -Nru ecflow-4.10.0/ANode/src/Node.cpp ecflow-4.11.1/ANode/src/Node.cpp --- ecflow-4.10.0/ANode/src/Node.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/ANode/src/Node.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -2216,6 +2216,15 @@ boost::bind(&Variable::name,_1), boost::bind(&Variable::name,_2))); break; + case Attr::ALL: + if (child_attrs_) child_attrs_->sort_attributes(attr); + sort(limitVec_.begin(),limitVec_.end(),boost::bind(Str::caseInsLess, + boost::bind(&Limit::name,_1), + boost::bind(&Limit::name,_2))); + sort(varVec_.begin(),varVec_.end(),boost::bind(Str::caseInsLess, + boost::bind(&Variable::name,_1), + boost::bind(&Variable::name,_2))); + break; case Attr::UNKNOWN: break; default: break; } diff -Nru ecflow-4.10.0/Base/src/cts/AlterCmd.cpp ecflow-4.11.1/Base/src/cts/AlterCmd.cpp --- ecflow-4.10.0/Base/src/cts/AlterCmd.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Base/src/cts/AlterCmd.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -478,7 +478,7 @@ " ecfcmd_failed | no_script | killed | migrated | late |\n" " message | complete | queue_limit | task_waiting | locked | zombie ]\n" " For sort:\n" - " [ event | meter | label | variable| limit ]\n" + " [ event | meter | label | variable| limit | all ]\n" "arg3 = name/value\n" " when changing, attributes like variable,meter,event,label,limits,late\n" " we expect arguments to be quoted. For sort this argument can be called 'recursive'\n" @@ -1173,7 +1173,7 @@ void AlterCmd::create_sort_attributes(Cmd_ptr& cmd,const std::vector& options,const std::vector& paths) const { // options[0] - sort - // options[1] - [ event | meter | label | limit | variable ] + // options[1] - [ event | meter | label | limit | variable | all ] // options[2] - recursive std::stringstream ss; diff -Nru ecflow-4.10.0/build_scripts/boost_build.sh ecflow-4.11.1/build_scripts/boost_build.sh --- ecflow-4.10.0/build_scripts/boost_build.sh 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/build_scripts/boost_build.sh 2018-10-23 11:41:34.000000000 +0000 @@ -211,22 +211,31 @@ # # ========================================================================================== # PYTHON3: - # Build: - # 1/ module load python3, this update the $PATH + # To build BOTH python2 and Python 3 libraries, the order is important. + # - First build python3 and then python2. This is because in boost 1.53 not all python libs have the 3 tag. + # + # Python 3: + # 0/ ./b2 --with-python --clean # Clean previous build + # 1/ module unload python; module load python3, this update the $PATH # 2/ ./bootstrap.sh --with-python=/usr/local/apps/python3/3.5.1-01/bin/python3 - # 3/ Need to manually edit $BOOST_ROOT/project-config.jam, make sure file '$BOOST_ROOT/project-config.jam' has: + # 3/ Comment out any other 'using python' then + # manually edit $BOOST_ROOT/project-config.jam, make sure file '$BOOST_ROOT/project-config.jam' has: # # using python # : 3.5 - # : /usr/local/apps/python3/3.5.1-01/bin/python3 # ***** If this is left as python3, includes get messed up, have mix of python2 & 3 - # : /usr/local/apps/python3/3.5.1-01/include/python3.5m # include directory + # : /usr/local/apps/python3/3.6.5-01/bin/python3 # ***** If this is left as python3, includes get messed up, have mix of python2 & 3 + # : /usr/local/apps/python3/3.6.5-01/include/python3.6m # include directory # ; - # ... - # option.set includedir : /usr/local/apps/python3/3.5.1-01/include/python3.5m ; # ***MAKE*** sure this is set # # ***** cmd/prefix must be path to python3, otherwise compilation include files has a mixture of # python 2.7 and 3.5, YUK, took ages to debug # + # Python 2: + # 0/ ./b2 --with-python --clean # Clean previous build + # 1/ module unload python; module load python2 + # 2/ ./bootstrap.sh --with-python=/path/to/python2.7 + # 3/ invoke this script + # # Check: # To check the build make sure we don't have symbol pulled in from python2 libs # cd $BOOST_ROOT/stage/lib @@ -234,8 +243,6 @@ # nm -D /tmp/ma0/workspace/bdir/release/ecflow/Pyext/ecflow.so | grep PyClass_Type # check ecflow.so # =============================================================================== -# ./bjam toolset=$tool link=shared variant=debug "$CXXFLAGS" stage --layout=$layout threading=multi --with-python -d2 -j2 -# ./bjam toolset=$tool link=static variant=debug "$CXXFLAGS" stage --layout=$layout threading=multi --with-python -d2 -j2 ./bjam toolset=$tool link=shared variant=release "$CXXFLAGS" stage --layout=$layout threading=multi --with-python -d2 -j2 ./bjam toolset=$tool link=static variant=release "$CXXFLAGS" stage --layout=$layout threading=multi --with-python -d2 -j2 fi diff -Nru ecflow-4.10.0/Client/test/TestSignalSIGTERM.cpp ecflow-4.11.1/Client/test/TestSignalSIGTERM.cpp --- ecflow-4.10.0/Client/test/TestSignalSIGTERM.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Client/test/TestSignalSIGTERM.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -59,7 +59,7 @@ // Send a SIGTERM to the server and ensure that a check point file is created std::string sigterm = "kill -15 " + ecf_pid ; system(sigterm.c_str()); - sleep(2); // allow time for system call + sleep(3); // allow time for system call // We expect a check point file to be save to disk, but *no* backup BOOST_REQUIRE_MESSAGE(fs::exists(invokeServer.ecf_checkpt_file()),CtsApi::checkPtDefs() << " failed file(" << invokeServer.ecf_checkpt_file() << ") not saved"); @@ -71,7 +71,7 @@ // Send a SIGTERM again. This time we expect the backup check point file to be created. system(sigterm.c_str()); - sleep(2); // allow time for system call + sleep(3); // allow time for system call BOOST_REQUIRE_MESSAGE(fs::exists(invokeServer.ecf_checkpt_file()),CtsApi::checkPtDefs() << " failed No check pt file(" << invokeServer.ecf_checkpt_file() << ") saved"); BOOST_REQUIRE_MESSAGE(fs::file_size(invokeServer.ecf_checkpt_file()) !=0,"Expected check point file(" << invokeServer.ecf_checkpt_file() << ") to have file size > 0 "); diff -Nru ecflow-4.10.0/cmake/ecbuild_add_library.cmake ecflow-4.11.1/cmake/ecbuild_add_library.cmake --- ecflow-4.10.0/cmake/ecbuild_add_library.cmake 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/cmake/ecbuild_add_library.cmake 2018-10-23 11:41:34.000000000 +0000 @@ -419,7 +419,7 @@ endif() endif() - if( ECBUILD_IMPLICIT_LINK_LIBRARIES ) + if( NOT _PAR_TYPE MATCHES "OBJECT" AND ECBUILD_IMPLICIT_LINK_LIBRARIES ) target_link_libraries( ${_PAR_TARGET} ${ECBUILD_IMPLICIT_LINK_LIBRARIES} ) endif() diff -Nru ecflow-4.10.0/cmake/ecbuild_add_test.cmake ecflow-4.11.1/cmake/ecbuild_add_test.cmake --- ecflow-4.10.0/cmake/ecbuild_add_test.cmake 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/cmake/ecbuild_add_test.cmake 2018-10-23 11:41:34.000000000 +0000 @@ -177,8 +177,14 @@ set( _PAR_ENABLED 0 ) elseif( _PAR_MPI ) # Check for MPIEXEC if it not set - find_program( MPIEXEC NAMES mpiexec mpirun lamexec srun - DOC "Executable for running MPI programs." ) + if( MPIEXEC_EXECUTABLE ) + set( MPIEXEC ${MPIEXEC_EXECUTABLE} ) + endif() + if( NOT MPIEXEC ) + find_program( MPIEXEC NAMES mpiexec mpirun lamexec srun + DOC "Executable for running MPI programs." ) + endif() + if( MPIEXEC ) set(MPIEXEC_NUMPROC_FLAG "-np" CACHE STRING "Flag used by MPI to specify the number of processes for MPIEXEC") ecbuild_debug("ecbuild_add_test(${_PAR_TARGET}): Running using ${MPIEXEC} on ${_PAR_MPI} MPI rank(s)") diff -Nru ecflow-4.10.0/cmake/ecbuild-config.cmake ecflow-4.11.1/cmake/ecbuild-config.cmake --- ecflow-4.10.0/cmake/ecbuild-config.cmake 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/cmake/ecbuild-config.cmake 2018-10-23 11:41:34.000000000 +0000 @@ -28,9 +28,9 @@ set( ECBUILD_TPL_DEFINITIONS "" ) set( ECBUILD_TPL_LIBRARIES "" ) -set( ECBUILD_VERSION "2.9.0" ) -set( ECBUILD_GIT_SHA1 "10d46b3d22df192405aa4da148e5c80bd7a814e0" ) -set( ECBUILD_GIT_SHA1_SHORT "10d46b3" ) +set( ECBUILD_VERSION "2.9.1" ) +set( ECBUILD_GIT_SHA1 "d8c1b6ca7554f0a823c25fdc1f375c3d88c21a5c" ) +set( ECBUILD_GIT_SHA1_SHORT "d8c1b6c" ) ### export include paths as absolute paths diff -Nru ecflow-4.10.0/cmake/ecbuild-config-version.cmake ecflow-4.11.1/cmake/ecbuild-config-version.cmake --- ecflow-4.10.0/cmake/ecbuild-config-version.cmake 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/cmake/ecbuild-config-version.cmake 2018-10-23 11:41:34.000000000 +0000 @@ -1,4 +1,4 @@ -set(PACKAGE_VERSION "2.9.0") +set(PACKAGE_VERSION "2.9.1") # check whether the requested PACKAGE_FIND_VERSION is compatible diff -Nru ecflow-4.10.0/cmake/ecbuild_generate_fortran_interfaces.cmake ecflow-4.11.1/cmake/ecbuild_generate_fortran_interfaces.cmake --- ecflow-4.10.0/cmake/ecbuild_generate_fortran_interfaces.cmake 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/cmake/ecbuild_generate_fortran_interfaces.cmake 2018-10-23 11:41:34.000000000 +0000 @@ -33,7 +33,7 @@ endif() set( options ) - set( single_value_args TARGET DESTINATION PARALLEL INCLUDE_DIRS GENERATED SOURCE_DIR FCM_CONFIG_FILE ) + set( single_value_args TARGET DESTINATION PARALLEL INCLUDE_DIRS GENERATED SOURCE_DIR SUFFIX FCM_CONFIG_FILE ) set( multi_value_args DIRECTORIES ) cmake_parse_arguments( P "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} ) @@ -57,7 +57,11 @@ ecbuild_debug_var( P_PARALLEL ) if( NOT DEFINED P_SOURCE_DIR ) - ecbuild_error( "ecbuild_generate_fortran_interfaces: SOURCE_DIR argument missing") + set( P_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" ) + endif() + + if( NOT DEFINED P_SUFFIX ) + set( P_SUFFIX ".intfb.h" ) endif() if( DEFINED P_FCM_CONFIG_FILE ) @@ -75,13 +79,9 @@ endif() if( NOT FCM_CONFIG_FILE ) - set( DEFAULT_FCM_CONFIG_FILE "${ECBUILD_MACROS_DIR}/fcm-make-interfaces.cfg" ) - if( EXISTS ${DEFAULT_FCM_CONFIG_FILE} ) - set( FCM_CONFIG_FILE ${DEFAULT_FCM_CONFIG_FILE} ) - ecbuild_debug( "ecbuild_generate_fortran_interfaces: fcm configuration found in ${DEFAULT_FCM_CONFIG_FILE}" ) - else() - ecbuild_debug( "ecbuild_generate_fortran_interfaces: fcm configuration not found in ${DEFAULT_FCM_CONFIG_FILE}" ) - endif() + set( FCM_CONFIG_FILE "${ECBUILD_MACROS_DIR}/fcm-make-interfaces.cfg" ) + set( FCM_CONFIG_FILE "${CMAKE_CURRENT_BINARY_DIR}/fcm-make-interfaces.${P_TARGET}.cfg" ) + configure_file( "${ECBUILD_MACROS_DIR}/fcm-make-interfaces.cfg.in" "${FCM_CONFIG_FILE}" @ONLY ) endif() ecbuild_debug_var( FCM_CONFIG_FILE ) @@ -110,7 +110,7 @@ foreach( fortran_file ${fortran_files} ) #list( APPEND fullpath_fortran_files ${CMAKE_CURRENT_SOURCE_DIR}/${fortran_file} ) get_filename_component(base ${fortran_file} NAME_WE) - set( interface_file "${CMAKE_CURRENT_BINARY_DIR}/interfaces/include/${base}.intfb.h" ) + set( interface_file "${CMAKE_CURRENT_BINARY_DIR}/interfaces/include/${base}${P_SUFFIX}" ) list( APPEND interface_files ${interface_file} ) set_source_files_properties( ${interface_file} PROPERTIES GENERATED TRUE ) math(EXPR _cnt "${_cnt}+1") diff -Nru ecflow-4.10.0/cmake/ecbuild_get_test_data.cmake ecflow-4.11.1/cmake/ecbuild_get_test_data.cmake --- ecflow-4.10.0/cmake/ecbuild_get_test_data.cmake 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/cmake/ecbuild_get_test_data.cmake 2018-10-23 11:41:34.000000000 +0000 @@ -405,12 +405,16 @@ TARGET __get_data_${_p_TARGET}_${_name} NAME ${_file} ${_dirname} ${_md5} ${_extract} ${_nocheck} ) - # The option /fast disables dependency checking on a target, see - # https://cmake.org/Wiki/CMake_FAQ#Is_there_a_way_to_skip_checking_of_dependent_libraries_when_compiling.3F - if( WIN32 ) - set( _fast "\fast" ) + if ( ${CMAKE_GENERATOR} MATCHES Ninja ) + set( _fast "" ) else() - set( _fast "/fast" ) + # The option /fast disables dependency checking on a target, see + # https://cmake.org/Wiki/CMake_FAQ#Is_there_a_way_to_skip_checking_of_dependent_libraries_when_compiling.3F + if( WIN32 ) + set( _fast "\fast" ) + else() + set( _fast "/fast" ) + endif() endif() file( APPEND ${_script} "exec_check( \"${CMAKE_COMMAND}\" --build \"${CMAKE_BINARY_DIR}\" --target __get_data_${_p_TARGET}_${_name}${_fast} )\n" ) diff -Nru ecflow-4.10.0/cmake/ecbuild_try_run.cmake ecflow-4.11.1/cmake/ecbuild_try_run.cmake --- ecflow-4.10.0/cmake/ecbuild_try_run.cmake 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/cmake/ecbuild_try_run.cmake 2018-10-23 11:41:34.000000000 +0000 @@ -127,6 +127,10 @@ ecbuild_critical("Unknown keywords given to ecbuild_try_run(): \"${_p_UNPARSED_ARGUMENTS}\"") endif() + if( CMAKE_EXE_LINKER_FLAGS ) + set( _p_LINK_LIBRARIES "${_p_LINK_LIBRARIES} ${CMAKE_EXE_LINKER_FLAGS}" ) + endif() + # Build argument list for try_compile foreach( _opt CMAKE_FLAGS COMPILE_DEFINITIONS LINK_LIBRARIES ) if( _p_${_opt} ) diff -Nru ecflow-4.10.0/cmake/fcm-make-interfaces.cfg ecflow-4.11.1/cmake/fcm-make-interfaces.cfg --- ecflow-4.10.0/cmake/fcm-make-interfaces.cfg 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/cmake/fcm-make-interfaces.cfg 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -# (C) Copyright 2011- ECMWF. -# -# This software is licensed under the terms of the Apache Licence Version 2.0 -# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. -# In applying this licence, ECMWF does not waive the privileges and immunities -# granted to it by virtue of its status as an intergovernmental organisation -# nor does it submit to any jurisdiction. - -# FCM configuration file used to auto-generate interface files -# for F77 and F90 files. -# Interface files will have the extention ".intfb.h" -# Results will be in a directory "interfaces/include" relative to cwd - -# Usage: fcm make --config-file= \ -# interfaces.ns-incl="" - -$SRC{?} = $HERE - -step.class[interfaces] = build -steps = interfaces - -interfaces.target{task} = ext-iface -interfaces.target{category} = include - -interfaces.source = $SRC - -# Exclude all -interfaces.ns-excl = / - -# Include some -# interfaces.ns-incl = - -# Extention of interface files -interfaces.prop{file-ext.f90-interface} = .intfb.h - -# Do not follow includes -interfaces.prop{no-dep.f.module} = * -interfaces.prop{no-dep.include} = * - diff -Nru ecflow-4.10.0/cmake/fcm-make-interfaces.cfg.in ecflow-4.11.1/cmake/fcm-make-interfaces.cfg.in --- ecflow-4.10.0/cmake/fcm-make-interfaces.cfg.in 1970-01-01 00:00:00.000000000 +0000 +++ ecflow-4.11.1/cmake/fcm-make-interfaces.cfg.in 2018-10-23 11:41:34.000000000 +0000 @@ -0,0 +1,39 @@ +# (C) Copyright 2011- ECMWF. +# +# This software is licensed under the terms of the Apache Licence Version 2.0 +# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +# In applying this licence, ECMWF does not waive the privileges and immunities +# granted to it by virtue of its status as an intergovernmental organisation +# nor does it submit to any jurisdiction. + +# FCM configuration file used to auto-generate interface files +# for F77 and F90 files. +# Interface files will have the extention "@P_SUFFIX@" +# Results will be in a directory "interfaces/include" relative to cwd + +# Usage: fcm make --config-file= \ +# interfaces.ns-incl="" + +$SRC{?} = $HERE + +step.class[interfaces] = build +steps = interfaces + +interfaces.target{task} = ext-iface +interfaces.target{category} = include + +interfaces.source = $SRC + +# Exclude all +interfaces.ns-excl = / + +# Include some +# interfaces.ns-incl = + +# Extention of interface files +interfaces.prop{file-ext.f90-interface} = @P_SUFFIX@ + +# Do not follow includes +interfaces.prop{no-dep.f.module} = * +interfaces.prop{no-dep.include} = * + diff -Nru ecflow-4.10.0/cmake/FindFFTW.cmake ecflow-4.11.1/cmake/FindFFTW.cmake --- ecflow-4.10.0/cmake/FindFFTW.cmake 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/cmake/FindFFTW.cmake 2018-10-23 11:41:34.000000000 +0000 @@ -51,8 +51,8 @@ # :FFTW_ROOT: if set, this path is exclusively searched # :FFTW_DIR: equivalent to FFTW_ROOT # :FFTW_PATH: equivalent to FFTW_ROOT -# :FFTW_LIBRARY: FFTW library to use -# :FFTW_INCLUDE_DIR: FFTW include directory +# :FFTW_LIBRARIES: User overriden FFTW libraries +# :FFTW_INCLUDES: User overriden FFTW includes directories # ############################################################################## @@ -104,6 +104,7 @@ set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_SHARED_LIBRARY_SUFFIX} ) endif() + if( FFTW_FIND_COMPONENTS ) ecbuild_debug( "FindFFTW: looking for components: ${FFTW_FIND_COMPONENTS}" ) foreach( _component ${FFTW_FIND_COMPONENTS} ) @@ -136,96 +137,99 @@ set( _include_paths ${PKG_FFTW_INCLUDE_DIRS} ${INCLUDE_INSTALL_DIR} ) endif() -#find includes +# find includes -find_path( - FFTW_INCLUDES - NAMES "fftw3.h" - PATHS ${_include_paths} - PATH_SUFFIXES "include" - ${_default_paths} -) - -if( NOT FFTW_INCLUDES ) - ecbuild_warn("FindFFTW: fftw include headers not found") -endif() - -#find libs - -if( _require_dp ) - find_library( - FFTW_LIB - NAMES "fftw3" - PATHS ${_lib_paths} - PATH_SUFFIXES "lib" "lib64" - ${_default_paths} - ) - if( NOT FFTW_LIB ) - ecbuild_warn("FindFFTW: double precision required, but fftw3 was not found") - endif() -endif() +if( NOT FFTW_INCLUDES ) # allow user to override with FFTW_INCLUDES -if( _require_sp ) - find_library( - FFTWF_LIB - NAMES "fftw3f" - PATHS ${_lib_paths} - PATH_SUFFIXES "lib" "lib64" - ${_default_paths} - ) - if( NOT FFTWF_LIB ) - ecbuild_warn("FindFFTW: single precision required, but fftw3f was not found") - endif() -endif() + find_path( + FFTW_INCLUDES + NAMES "fftw3.h" + PATHS ${_include_paths} + PATH_SUFFIXES "include" + ${_default_paths} + ) -if( _require_lp ) - find_library( - FFTWL_LIB - NAMES "fftw3l" - PATHS ${_lib_paths} - PATH_SUFFIXES "lib" "lib64" - ${_default_paths} - ) - if( NOT FFTWL_LIB ) - ecbuild_warn("FindFFTW: long double precision required, but fftw3l was not found") - endif() -endif() + if( NOT FFTW_INCLUDES ) + ecbuild_warn("FindFFTW: fftw include headers not found") + endif() -if( _require_qp ) - find_library( - FFTWQ_LIB - NAMES "fftw3q" - PATHS ${_lib_paths} - PATH_SUFFIXES "lib" "lib64" - ${_default_paths} - ) - if( NOT FFTWQ_LIB ) - ecbuild_warn("FindFFTW: quad precision required, but fftw3q was not found") - endif() endif() -set(FFTW_LIBRARIES ${FFTW_LIB} ${FFTWF_LIB} ${FFTWL_LIB} ${FFTWQ_LIB}) +# find libs +if( NOT FFTW_LIBRARIES ) # allow user to override with FFTW_LIBRARIES (e.g. for MKL implementation) + + if( _require_dp ) + find_library( + FFTW_LIB + NAMES "fftw3" + PATHS ${_lib_paths} + PATH_SUFFIXES "lib" "lib64" + ${_default_paths} + ) + if( NOT FFTW_LIB ) + ecbuild_warn("FindFFTW: double precision required, but fftw3 was not found") + else() + ecbuild_info("FFTW double precision: ${FFTW_LIB}") + endif() + endif() + + if( _require_sp ) + find_library( + FFTWF_LIB + NAMES "fftw3f" + PATHS ${_lib_paths} + PATH_SUFFIXES "lib" "lib64" + ${_default_paths} + ) + if( NOT FFTWF_LIB ) + ecbuild_warn("FindFFTW: single precision required, but fftw3f was not found") + else() + ecbuild_info("FFTW single precision: ${FFTWF_LIB}") + endif() + endif() + + if( _require_lp ) + find_library( + FFTWL_LIB + NAMES "fftw3l" + PATHS ${_lib_paths} + PATH_SUFFIXES "lib" "lib64" + ${_default_paths} + ) + if( NOT FFTWL_LIB ) + ecbuild_warn("FindFFTW: long double precision required, but fftw3l was not found") + else() + ecbuild_info("FFTW long double precision: ${FFTWL_LIB}") + endif() + endif() + + if( _require_qp ) + find_library( + FFTWQ_LIB + NAMES "fftw3q" + PATHS ${_lib_paths} + PATH_SUFFIXES "lib" "lib64" + ${_default_paths} + ) + if( NOT FFTWQ_LIB ) + ecbuild_warn("FindFFTW: quad precision required, but fftw3q was not found") + else() + ecbuild_info("FFTW quad precision: ${FFTWQ_LIB}") + endif() + endif() + + set(FFTW_LIBRARIES ${FFTW_LIB} ${FFTWF_LIB} ${FFTWL_LIB} ${FFTWQ_LIB}) -ecbuild_info("FFTW summary:") -ecbuild_info("FFTW includes: ${FFTW_INCLUDES}") -if( _require_dp ) - ecbuild_info("FFTW double precision: ${FFTW_LIB}") -endif() -if( _require_sp ) - ecbuild_info("FFTW single precision: ${FFTWF_LIB}") -endif() -if( _require_lp ) - ecbuild_info("FFTW long double precision: ${FFTWL_LIB}") -endif() -if( _require_qp ) - ecbuild_info("FFTW quad precision: ${FFTWQ_LIB}") endif() +ecbuild_info("FFTW includes : ${FFTW_INCLUDES}") +ecbuild_info("FFTW libraries: ${FFTW_LIBRARIES}") + set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_SAV} ) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(FFTW DEFAULT_MSG FFTW_INCLUDES FFTW_LIBRARIES) -mark_as_advanced(FFTW_INCLUDES FFTW_LIBRARIES FFTW_LIB FFTWF_LIB FFTWL_LIB) +mark_as_advanced(FFTW_INCLUDES FFTW_LIBRARIES FFTW_LIB FFTWF_LIB FFTWL_LIB FFTWQ_LIB) diff -Nru ecflow-4.10.0/cmake/FindNAG.cmake ecflow-4.11.1/cmake/FindNAG.cmake --- ecflow-4.10.0/cmake/FindNAG.cmake 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/cmake/FindNAG.cmake 2018-10-23 11:41:34.000000000 +0000 @@ -18,13 +18,13 @@ # NAG_DIR - root folder of the NAG installation # NAG_PATH - root folder of the NAG installation -find_path( NAG_INCLUDE_DIR nag_library.mod +find_path( NAG_INCLUDE_DIR nag_precisions.mod PATHS ${NAG_PATH} ENV NAG_PATH ${NAG_DIR} ENV NAG_DIR PATH_SUFFIXES include NO_DEFAULT_PATH ) -find_library( NAG_LIBRARY NAMES nag nag_nag +find_library( NAG_LIBRARY NAMES nag PATHS ${NAG_PATH} ENV NAG_PATH ${NAG_DIR} ENV NAG_DIR PATH_SUFFIXES lib lib64 diff -Nru ecflow-4.10.0/cmake/VERSION.cmake ecflow-4.11.1/cmake/VERSION.cmake --- ecflow-4.10.0/cmake/VERSION.cmake 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/cmake/VERSION.cmake 2018-10-23 11:41:34.000000000 +0000 @@ -1,7 +1,7 @@ set( ECBUILD_MAJOR_VERSION "2" ) set( ECBUILD_MINOR_VERSION "9" ) -set( ECBUILD_PATCH_VERSION "0" ) +set( ECBUILD_PATCH_VERSION "1" ) -set( ECBUILD_VERSION_STR "2.9.0" ) +set( ECBUILD_VERSION_STR "2.9.1" ) set( ECBUILD_MACRO_VERSION "${ECBUILD_VERSION_STR}" ) diff -Nru ecflow-4.10.0/CMakeLists.txt ecflow-4.11.1/CMakeLists.txt --- ecflow-4.10.0/CMakeLists.txt 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/CMakeLists.txt 2018-10-23 11:41:34.000000000 +0000 @@ -13,6 +13,7 @@ # -DBUILD_SHARED_LIBS=OFF ############################################################################## +# Need cmake(3.12.0) for boost python3 libs to be found. cmake_minimum_required( VERSION 2.8.11 FATAL_ERROR ) # =========================================================================== @@ -216,6 +217,31 @@ endif() # ========================================================================================= +# Python: Must be done before BOOST +# ========================================================================================= + +if (ENABLE_PYTHON) + ecbuild_find_python( VERSION 2.6 REQUIRED ) + if( NOT PYTHON_FOUND ) + ecbuild_error("ecflow python extension is enabled, but python interpreter or libraries not found") + endif() + if ( NOT PYTHONLIBS_FOUND ) + ecbuild_error("ecflow python extension is enabled, but python libraries not found") + endif() + if ( PYTHON_VERSION_MAJOR EQUAL 3) + cmake_minimum_required( VERSION 3.12.0 FATAL_ERROR ) + endif() + message( STATUS " PYTHON_VERSION_STRING : ${PYTHON_VERSION_STRING}" ) + message( STATUS " PYTHON_VERSION_MAJOR : ${PYTHON_VERSION_MAJOR}" ) + message( STATUS " PYTHON_VERSION_MINOR : ${PYTHON_VERSION_MINOR}" ) + message( STATUS " PYTHON_VERSION_PATCH : ${PYTHON_VERSION_PATCH}" ) + message( STATUS " PYTHON_CONFIG_EXECUTABLE : ${PYTHON_CONFIG_EXECUTABLE}" ) + message( STATUS " PYTHON_EXECUTABLE : ${PYTHON_EXECUTABLE}" ) + message( STATUS " PYTHON_INCLUDE_DIRS : ${PYTHON_INCLUDE_DIRS}" ) + message( STATUS " PYTHON_LIBRARIES : ${PYTHON_LIBRARIES}" ) +endif() + +# ========================================================================================= # Boost # ========================================================================================= @@ -239,27 +265,17 @@ set(Boost_DETAILED_FAILURE_MSG ON) #set(Boost_DEBUG ON) +find_package( Boost 1.53.0 REQUIRED COMPONENTS serialization system thread unit_test_framework test_exec_monitor filesystem program_options date_time regex) if ( ENABLE_PYTHON ) - find_package( Boost 1.53.0 REQUIRED COMPONENTS python serialization system thread unit_test_framework test_exec_monitor filesystem program_options date_time regex) -else() - find_package( Boost 1.53.0 REQUIRED COMPONENTS serialization system thread unit_test_framework test_exec_monitor filesystem program_options date_time regex) -endif() - -# Available boost lib should be referenced as: -# -# ${Boost_SYSTEM_LIBRARY} -# ${Boost_SERIALIZATION_LIBRARY} -# ${Boost_THREAD_LIBRARY} -# ${Boost_FILESYSTEM_LIBRARY} -# ${Boost_PROGRAM_OPTIONS_LIBRARY} -# ${Boost_DATE_TIME_LIBRARY} -# -# ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} -# ${Boost_TEST_EXEC_MONITOR_LIBRARY} + if ( PYTHON_VERSION_MAJOR EQUAL 3) + find_package( Boost 1.53.0 REQUIRED COMPONENTS python3 ) + else() + find_package( Boost 1.53.0 REQUIRED COMPONENTS python ) + endif() +endif() #ecbuild_info( "Boost_LIBRARIES : ${Boost_LIBRARIES}" ) - if (NOT "${CMAKE_PREFIX_PATH}" EQUAL "${_CMAKE_PREFIX_PATH_BACKUP}") set (CMAKE_PREFIX_PATH ${_CMAKE_PREFIX_PATH_BACKUP}) # restore CMAKE_PREFIX_PATH ecbuild_debug("Resetting CMAKE_PREFIX_PATH to ${CMAKE_PREFIX_PATH}") @@ -324,18 +340,9 @@ endif() if (ENABLE_PYTHON) - ecbuild_find_python( VERSION 2.6 REQUIRED ) - # ecbuild_debug_var(PYTHON_LIBRARIES) - # ecbuild_debug_var(PYTHON_INCLUDE_DIR) - - if( NOT PYTHON_FOUND ) - ecbuild_error("ecflow python extension is enabled, but python interpreter or libraries not found") - endif() - if ( ENABLE_PYTHON_PTR_REGISTER ) add_definitions( -DECF_ENABLE_PYTHON_PTR_REGISTER ) endif() - add_subdirectory( Pyext ) endif() @@ -372,7 +379,6 @@ build_scripts/.pydevproject ) - # ========================================================================================= # final # ========================================================================================= diff -Nru ecflow-4.10.0/cmake.sh ecflow-4.11.1/cmake.sh --- ecflow-4.10.0/cmake.sh 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/cmake.sh 2018-10-23 11:41:34.000000000 +0000 @@ -139,20 +139,23 @@ # ==================== modules ================================================ # To load module automatically requires Korn shell, system start scripts -module load cmake/3.10.2 +module load cmake/3.10.2 # need cmake 3.12.0 to build python3. Allow boost python libs to be found module load ecbuild/2.9.0 +#module load boost/1.53.0 # uncomment to use local BOOST_ROOT cmake_extra_options="" if [[ "$clang_arg" = clang || "$clang_tidy_arg" = clang_tidy ]] ; then - module unload gnu - module load clang/5.0.1 - cmake_extra_options="-DBOOST_ROOT=/var/tmp/ma0/boost/clang-5.0.1/boost_1_53_0" - - CXX_FLAGS="$CXX_FLAGS -Wno-expansion-to-defined" - - #CXX_FLAGS="" # latest clang with latest boost, should not need any warning suppression - #cmake_extra_options="-DBOOST_ROOT=/var/tmp/ma0/boost/clang-5.0.1/boost_1_66_0" - + # ecflow fails to write boost ser' files with clang 6.0.1, but in debug all tests pass + # Had to apply fix: http://clang-developers.42468.n3.nabble.com/boost-serialization-crash-with-clang-5-0-0-td4058283.html + # - still have other crashes n serilisation see: ECFLOW-1328 + module unload gnu + module unload clang + module load clang/6.0.1 + cmake_extra_options="-DBOOST_ROOT=/var/tmp/ma0/boost/clang-6.0.1/boost_1_53_0" + + CXX_FLAGS="" + CXX_FLAGS="$CXX_FLAGS -Wno-deprecated-declarations -Wno-deprecated-register -Wno-expansion-to-defined" + if [[ "$clang_tidy_arg" = clang_tidy ]] ; then cmake_extra_options="$cmake_extra_options -DCMAKE_EXPORT_COMPILE_COMMANDS=ON" fi @@ -198,9 +201,12 @@ if [[ "$python3_arg" = python3 ]] ; then module unload python - module load python3/3.5.1-01 - cmake_extra_options="$cmake_extra_options -DPYTHON_EXECUTABLE=/usr/local/apps/python3/3.5.1-01/bin/python3.5" - cmake_extra_options="$cmake_extra_options -DBOOST_ROOT=/var/tmp/ma0/boost/boost_1_53_0.python3" + module load python3/3.6.5-01 + + module unload cmake # need cmake 3.12.0 to build python3. Allow boost python libs to be found + module load cmake/3.12.0 + + cmake_extra_options="$cmake_extra_options -DPYTHON_EXECUTABLE=/usr/local/apps/python3/3.6.5-01/bin/python3.6" fi # ==================================================================================== @@ -342,7 +348,7 @@ ${ssl_options} \ ${secure_user_options} \ ${log_options} \ - ${test_options} + ${test_options} # -DCMAKE_PREFIX_PATH="/tmp/$USER/opt/qt5/" #-DCMAKE_EXE_LINKER_FLAGS='-fsanitize=memory -fPIE -pie' #-DENABLE_STATIC_BOOST_LIBS=ON \ @@ -357,7 +363,8 @@ #-DENABLE_SERVER=OFF \ #-DENABLE_PROFILING=ON \ #-DECBUILD_GPROF_FLAGS \ - +# export PATH=/tmp/$USER/opt/qt5/bin:$PATH + if [[ "$clang_tidy_arg" = clang_tidy ]] ; then python $WK/build_scripts/run-clang-tidy.py fi diff -Nru ecflow-4.10.0/debian/changelog ecflow-4.11.1/debian/changelog --- ecflow-4.10.0/debian/changelog 2018-11-03 12:12:23.000000000 +0000 +++ ecflow-4.11.1/debian/changelog 2018-11-06 14:21:45.000000000 +0000 @@ -1,8 +1,16 @@ -ecflow (4.10.0-2ubuntu2) disco; urgency=medium +ecflow (4.11.1-1ubuntu1) disco; urgency=medium - * No-change rebuild to build without python3.6 support. + * Merge with Debian; remaining changes: + - Fix boost build. + - Build-depend on python3-all-dev. - -- Matthias Klose Sat, 03 Nov 2018 12:12:23 +0000 + -- Matthias Klose Tue, 06 Nov 2018 15:21:45 +0100 + +ecflow (4.11.1-1) unstable; urgency=medium + + * New upstream release + + -- Alastair McKinstry Tue, 23 Oct 2018 12:41:24 +0100 ecflow (4.10.0-2ubuntu1) cosmic; urgency=medium @@ -10,6 +18,29 @@ -- Dimitri John Ledkov Wed, 19 Sep 2018 12:09:59 +0200 +ecflow (4.11.0-1) unstable; urgency=medium + + * New upstream release + * Remove obsolete patches: + - set-paths.patch + - logsvr_syntax_fix.patch + - boost_python_tuple.patch + - qt5-11-transition.patch + * New patch + - boost python.patch (for Debian python lib name) + * Standards-Version: 4.2.1 + * Remove hard-coded xz compression for debian tarball + + -- Alastair McKinstry Thu, 18 Oct 2018 11:57:51 +0100 + +ecflow (4.10.0-3) unstable; urgency=medium + + * Add python3.7 B-D (temporarily needed on i386? ) + * Standards-Version: 4.2.0 + * Build -fPIC on i386. + + -- Alastair McKinstry Mon, 03 Sep 2018 14:56:32 +0100 + ecflow (4.10.0-2) unstable; urgency=medium * Fix for FTBFS with Qt5.11 diff -Nru ecflow-4.10.0/debian/control ecflow-4.11.1/debian/control --- ecflow-4.10.0/debian/control 2018-09-19 10:09:59.000000000 +0000 +++ ecflow-4.11.1/debian/control 2018-11-06 14:21:45.000000000 +0000 @@ -26,7 +26,7 @@ libboost-thread-dev, libboost-regex-dev, libboost-python-dev, libboost-program-options-dev, libboost-filesystem-dev -Standards-Version: 4.1.5 +Standards-Version: 4.2.1 Homepage: https://software.ecmwf.int/wiki/display/ECFLOW/The+ECFLOW+Pre-processor Vcs-Browser: https://salsa.debian.org:/science-team/ecflow.git Vcs-Git: https://salsa.debian.org:/science-team/ecflow.git diff -Nru ecflow-4.10.0/debian/patches/boost-python3.patch ecflow-4.11.1/debian/patches/boost-python3.patch --- ecflow-4.10.0/debian/patches/boost-python3.patch 1970-01-01 00:00:00.000000000 +0000 +++ ecflow-4.11.1/debian/patches/boost-python3.patch 2018-10-23 11:41:24.000000000 +0000 @@ -0,0 +1,26 @@ +Description: Build Fix for boost python3 library name in Debian + Ignore python3 missing; its named differently +Author: Alastair McKinstry +Last-Updated: 2018-10-18 +Forwarded: not-needed + +Index: ecflow-4.11.0/CMakeLists.txt +=================================================================== +--- ecflow-4.11.0.orig/CMakeLists.txt ++++ ecflow-4.11.0/CMakeLists.txt +@@ -267,11 +267,11 @@ set(Boost_DETAILED_FAILURE_MSG ON) + + find_package( Boost 1.53.0 REQUIRED COMPONENTS serialization system thread unit_test_framework test_exec_monitor filesystem program_options date_time regex) + if ( ENABLE_PYTHON ) +- if ( PYTHON_VERSION_MAJOR EQUAL 3) +- find_package( Boost 1.53.0 REQUIRED COMPONENTS python3 ) +- else() ++# if ( PYTHON_VERSION_MAJOR EQUAL 3) ++# find_package( Boost 1.53.0 REQUIRED COMPONENTS python3 ) ++# else() + find_package( Boost 1.53.0 REQUIRED COMPONENTS python ) +- endif() ++# endif() + endif() + + #ecbuild_info( "Boost_LIBRARIES : ${Boost_LIBRARIES}" ) diff -Nru ecflow-4.10.0/debian/patches/boost_python_tuple.patch ecflow-4.11.1/debian/patches/boost_python_tuple.patch --- ecflow-4.10.0/debian/patches/boost_python_tuple.patch 2018-07-28 07:43:18.000000000 +0000 +++ ecflow-4.11.1/debian/patches/boost_python_tuple.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,98 +0,0 @@ -Description: Fix for python::boost tuple issue - With latest C++ standards, 'tuple' is ambiguous, so we explicitly - declare boost::python::tuple -Author: Alastair McKinstry -Last-Updated: 2018-02-01 -Forwarded: no - -Index: ecflow-4.8.0/Pyext/src/Edit.cpp -=================================================================== ---- ecflow-4.8.0.orig/Pyext/src/Edit.cpp -+++ ecflow-4.8.0/Pyext/src/Edit.cpp -@@ -24,7 +24,7 @@ namespace bp = boost::python; - Edit::Edit(const boost::python::dict& dict){BoostPythonUtil::dict_to_str_vec(dict,vec_);} - Edit::Edit(const boost::python::dict& dict,const boost::python::dict& dict2){BoostPythonUtil::dict_to_str_vec(dict,vec_);BoostPythonUtil::dict_to_str_vec(dict2,vec_);} - --object Edit::init(tuple args, dict kw) { -+object Edit::init(boost::python::tuple args, dict kw) { - //cout << "Edit::init args: " << len(args) << " kwargs " << len(kw) << "\n"; - // args[0] is Edit(i.e self) - for (int i = 1; i < len(args) ; ++i) { -@@ -34,6 +34,6 @@ object Edit::init(tuple args, dict kw) { - } - else throw std::runtime_error("Edit::Edit: only accepts dictionary and key word arguments"); - } -- tuple rest(args.slice(1,_)); -+ boost::python::tuple rest(args.slice(1,_)); - return args[0].attr("__init__")(kw); // calls -> .def(init() -> Edit(const boost::python::dict& dict) - } -Index: ecflow-4.8.0/Pyext/src/ExportDefs.cpp -=================================================================== ---- ecflow-4.8.0.orig/Pyext/src/ExportDefs.cpp -+++ ecflow-4.8.0/Pyext/src/ExportDefs.cpp -@@ -190,7 +190,7 @@ static object do_add(defs_ptr self, cons - return object(self); - } - --static object add(tuple args, dict kwargs) { -+static object add(boost::python::tuple args, dict kwargs) { - int the_list_size = len(args); - defs_ptr self = extract(args[0]); // self - if (!self) throw std::runtime_error("ExportDefs::add() : first argument is not a Defs"); -@@ -221,7 +221,7 @@ static object defs_getattr(defs_ptr self - return object(); - } - --object defs_raw_constructor(tuple args, dict kw) { -+object defs_raw_constructor(boost::python::tuple args, dict kw) { - // cout << "defs_raw_constructor len(args):" << len(args) << endl; - // args[0] is Defs(i.e self) - bp::list the_list; -Index: ecflow-4.8.0/Pyext/src/ExportNodeAttr.cpp -=================================================================== ---- ecflow-4.8.0.orig/Pyext/src/ExportNodeAttr.cpp -+++ ecflow-4.8.0/Pyext/src/ExportNodeAttr.cpp -@@ -49,7 +49,7 @@ namespace bp = boost::python; - - // See: http://wiki.python.org/moin/boost.python/HowTo#boost.function_objects - /////////////////////////////////////////////////////////////////////////////////////////////////// --object late_raw_constructor(tuple args, dict kw) { -+object late_raw_constructor(boost::python::tuple args, dict kw) { - //cout << "late_raw_constructor len(args):" << len(args) << endl; - // args[0] is Late(i.e self) - if (len(args) > 1) throw std::runtime_error("late_raw_constructor: Late only expects keyword arguments, ie. Late(submitted='00:20',active='15:00',complete='+30:00')"); -@@ -87,7 +87,7 @@ static boost::shared_ptr late_ - - - /////////////////////////////////////////////////////////////////////////////////////////////////// --object cron_raw_constructor(tuple args, dict kw) { -+object cron_raw_constructor(boost::python::tuple args, dict kw) { - //cout << "cron_raw_constructor len(args):" << len(args) << endl; - // args[0] is Cron(i.e self) args[1] is string name - for (int i = 1; i < len(args) ; ++i) { -Index: ecflow-4.8.0/Pyext/src/ExportNode.cpp -=================================================================== ---- ecflow-4.8.0.orig/Pyext/src/ExportNode.cpp -+++ ecflow-4.8.0/Pyext/src/ExportNode.cpp -@@ -175,7 +175,7 @@ static object do_lshift(node_ptr self, c - return object(self); - } - --static object add(tuple args, dict kwargs) -+static object add(boost::python::tuple args, dict kwargs) - { - int the_list_size = len(args); - node_ptr self = extract(args[0]); // self -Index: ecflow-4.8.0/Pyext/src/NodeUtil.cpp -=================================================================== ---- ecflow-4.8.0.orig/Pyext/src/NodeUtil.cpp -+++ ecflow-4.8.0/Pyext/src/NodeUtil.cpp -@@ -47,7 +47,7 @@ using namespace ecf; - namespace bp = boost::python; - - --object NodeUtil::node_raw_constructor(tuple args, dict kw) { -+object NodeUtil::node_raw_constructor(boost::python::tuple args, dict kw) { - // cout << "node_raw_constructor len(args):" << len(args) << endl; - // args[0] is Task(i.e self) args[1] is string name - bp::list the_list; diff -Nru ecflow-4.10.0/debian/patches/logsvr_syntax_fix.patch ecflow-4.11.1/debian/patches/logsvr_syntax_fix.patch --- ecflow-4.10.0/debian/patches/logsvr_syntax_fix.patch 2018-07-28 07:43:18.000000000 +0000 +++ ecflow-4.11.1/debian/patches/logsvr_syntax_fix.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -Description: Fix syntax error -Author: Alastair McKinstry -Last-Updated: 2017-10-14 -Forwarded: no - -Index: ecflow-4.8.0/tools/ecflow_logsvr.sh -=================================================================== ---- ecflow-4.8.0.orig/tools/ecflow_logsvr.sh -+++ ecflow-4.8.0/tools/ecflow_logsvr.sh -@@ -37,7 +37,7 @@ LOGMAP=/emos_esuite:/emos_esuite:/vol/em - log=/var/log/emos/logsvr.log - if [[ -x /usr/sbin/logsvr.pl ]] ; then - LOGSVR=/usr/sbin/logsvr.pl --if [[ -x /usr/local/lib/metaps/perl/logsvr.pl ]] ; then -+elif [[ -x /usr/local/lib/metaps/perl/logsvr.pl ]] ; then - LOGSVR=/usr/local/lib/metaps/perl/logsvr.pl - elif [[ -x /usr/local/apps/sms/bin/logsvr.pl ]] ; then - LOGSVR=/usr/local/apps/sms/bin/logsvr.pl diff -Nru ecflow-4.10.0/debian/patches/minver.patch ecflow-4.11.1/debian/patches/minver.patch --- ecflow-4.10.0/debian/patches/minver.patch 2018-07-28 07:43:18.000000000 +0000 +++ ecflow-4.11.1/debian/patches/minver.patch 2018-10-23 11:41:24.000000000 +0000 @@ -5,16 +5,16 @@ Last-Updated: 2017-07-11 Forwarded: no -Index: ecflow-4.10.0/CMakeLists.txt +Index: ecflow-4.11.0/CMakeLists.txt =================================================================== ---- ecflow-4.10.0.orig/CMakeLists.txt -+++ ecflow-4.10.0/CMakeLists.txt -@@ -324,7 +324,7 @@ if (ENABLE_SERVER) - endif() +--- ecflow-4.11.0.orig/CMakeLists.txt ++++ ecflow-4.11.0/CMakeLists.txt +@@ -221,7 +221,7 @@ endif() + # ========================================================================================= if (ENABLE_PYTHON) - ecbuild_find_python( VERSION 2.6 REQUIRED ) + ecbuild_find_python( VERSION ${PYTHON_MIN_VERSION} REQUIRED ) - # ecbuild_debug_var(PYTHON_LIBRARIES) - # ecbuild_debug_var(PYTHON_INCLUDE_DIR) - + if( NOT PYTHON_FOUND ) + ecbuild_error("ecflow python extension is enabled, but python interpreter or libraries not found") + endif() diff -Nru ecflow-4.10.0/debian/patches/qt5-11-transition.patch ecflow-4.11.1/debian/patches/qt5-11-transition.patch --- ecflow-4.10.0/debian/patches/qt5-11-transition.patch 2018-07-28 07:43:18.000000000 +0000 +++ ecflow-4.11.1/debian/patches/qt5-11-transition.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -Author: Alastair McKinstry -Description: Fix for stricter header files in QT5.11 -Last-Updated: 2018-07-28 -Forwarded: no - -Index: ecflow-4.10.0/Viewer/ecflowUI/src/VariableSearchLine.cpp -=================================================================== ---- ecflow-4.10.0.orig/Viewer/ecflowUI/src/VariableSearchLine.cpp -+++ ecflow-4.10.0/Viewer/ecflowUI/src/VariableSearchLine.cpp -@@ -9,6 +9,7 @@ - - #include - -+#include - #include - #include - #include diff -Nru ecflow-4.10.0/debian/patches/reproducible.patch ecflow-4.11.1/debian/patches/reproducible.patch --- ecflow-4.10.0/debian/patches/reproducible.patch 2018-07-28 07:43:18.000000000 +0000 +++ ecflow-4.11.1/debian/patches/reproducible.patch 2018-10-23 11:41:24.000000000 +0000 @@ -3,10 +3,10 @@ Last-Updated: 2017-07-11 Forwarded: no -Index: ecflow-4.10.0/ACore/src/Version.cpp +Index: ecflow-4.11.0/ACore/src/Version.cpp =================================================================== ---- ecflow-4.10.0.orig/ACore/src/Version.cpp -+++ ecflow-4.10.0/ACore/src/Version.cpp +--- ecflow-4.11.0.orig/ACore/src/Version.cpp ++++ ecflow-4.11.0/ACore/src/Version.cpp @@ -85,7 +85,7 @@ std::string Version::description() ss << " openssl"; #endif diff -Nru ecflow-4.10.0/debian/patches/series ecflow-4.11.1/debian/patches/series --- ecflow-4.10.0/debian/patches/series 2018-07-28 07:43:18.000000000 +0000 +++ ecflow-4.11.1/debian/patches/series 2018-10-23 11:41:24.000000000 +0000 @@ -5,7 +5,4 @@ reproducible.patch minver.patch soname.patch -# set-paths.patch -# logsvr_syntax_fix.patch -# boost_python_tuple.patch -qt5-11-transition.patch +boost-python3.patch diff -Nru ecflow-4.10.0/debian/patches/set-paths.patch ecflow-4.11.1/debian/patches/set-paths.patch --- ecflow-4.10.0/debian/patches/set-paths.patch 2018-07-28 07:43:18.000000000 +0000 +++ ecflow-4.11.1/debian/patches/set-paths.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -Description: Set paths to Debian locations -Author: Alastair McKinstry -Last-Updated: 2017-07-17 -Forwarded: not-needed - -Index: ecflow-4.8.0/tools/ecflow_logsvr.sh -=================================================================== ---- ecflow-4.8.0.orig/tools/ecflow_logsvr.sh -+++ ecflow-4.8.0/tools/ecflow_logsvr.sh -@@ -30,6 +30,13 @@ else - log=/sms/logsvr.log - fi - -+# Debian -+LOGPATH=/var/log/emos -+LOGMAP=/emos_esuite:/emos_esuite:/vol/emos/output:/emos_esuite:/vol/emos/output:/$MACHINE_NAME/emos_dir:/$MACHINE_NAME/emos_dir:/$MACHINE_NAME/emos_dir:/emos_esuite:/e\ -+ mos_esuite:/vol/emos/output:/emos_dir:/emos_dir:/emos_dir -+log=/var/log/emos/logsvr.log -+if [[ -x /usr/sbin/logsvr.pl ]] ; then -+ LOGSVR=/usr/sbin/logsvr.pl - if [[ -x /usr/local/lib/metaps/perl/logsvr.pl ]] ; then - LOGSVR=/usr/local/lib/metaps/perl/logsvr.pl - elif [[ -x /usr/local/apps/sms/bin/logsvr.pl ]] ; then diff -Nru ecflow-4.10.0/debian/patches/soname.patch ecflow-4.11.1/debian/patches/soname.patch --- ecflow-4.10.0/debian/patches/soname.patch 2018-07-28 07:43:18.000000000 +0000 +++ ecflow-4.11.1/debian/patches/soname.patch 2018-10-23 11:41:24.000000000 +0000 @@ -1,10 +1,10 @@ Description: Add a version number and name to package -Index: ecflow-4.10.0/view/CMakeLists.txt +Index: ecflow-4.11.0/view/CMakeLists.txt =================================================================== ---- ecflow-4.10.0.orig/view/CMakeLists.txt -+++ ecflow-4.10.0/view/CMakeLists.txt +--- ecflow-4.11.0.orig/view/CMakeLists.txt ++++ ecflow-4.11.0/view/CMakeLists.txt @@ -206,7 +206,9 @@ ecbuild_add_library(TARGET ecflow_vie CONDITION MOTIF_FOUND AND X11_FOUND AND CMAKE_THREAD_LIBS_INIT diff -Nru ecflow-4.10.0/debian/rules ecflow-4.11.1/debian/rules --- ecflow-4.10.0/debian/rules 2018-09-19 10:09:59.000000000 +0000 +++ ecflow-4.11.1/debian/rules 2018-11-06 14:21:45.000000000 +0000 @@ -19,6 +19,9 @@ ifeq ($(TARGET_ARCH), hppa) FPIC:= -fPIC endif +ifeq ($(TARGET_ARCH), i386) + FPIC:= -fPIC +endif CFLAGS:=$(shell dpkg-buildflags --get CFLAGS) $(FPIC) $(CPPFLAGS) -DNO_REGEXP LDFLAGS:=$(shell dpkg-buildflags --get LDFLAGS) $(FPIC) diff -Nru ecflow-4.10.0/debian/source/options ecflow-4.11.1/debian/source/options --- ecflow-4.10.0/debian/source/options 2018-07-28 07:43:18.000000000 +0000 +++ ecflow-4.11.1/debian/source/options 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -compression = "xz" diff -Nru ecflow-4.10.0/project_summary.cmake ecflow-4.11.1/project_summary.cmake --- ecflow-4.10.0/project_summary.cmake 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/project_summary.cmake 2018-10-23 11:41:34.000000000 +0000 @@ -1,26 +1,31 @@ message( STATUS "------------------------------------------------------" ) if(Boost_FOUND) - message( STATUS " Boost include : [${Boost_INCLUDE_DIRS}]" ) - message( STATUS " libs : [${Boost_SYSTEM_LIBRARY}]" ) - message( STATUS " libs : [${Boost_SERIALIZATION_LIBRARY}]" ) - message( STATUS " libs : [${Boost_THREAD_LIBRARY}]" ) - message( STATUS " libs : [${Boost_FILESYSTEM_LIBRARY}]" ) - message( STATUS " libs : [${Boost_PROGRAM_OPTIONS_LIBRARY}]" ) - message( STATUS " libs : [${Boost_DATE_TIME_LIBRARY}]" ) - message( STATUS " libs : [${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}]" ) - message( STATUS " libs : [${Boost_TEST_EXEC_MONITOR_LIBRARY}]" ) - message( STATUS " libs : [${Boost_PYTHON_LIBRARY}]" ) -endif() - -if( PYTHONINTERP_FOUND ) - message( STATUS "Python exec : ${PYTHON_EXECUTABLE}" ) - message( STATUS " include : ${PYTHON_INCLUDE_DIRS}" ) - message( STATUS " libs : ${PYTHON_LIBRARIES}" ) + message( STATUS " Boost_MAJOR_VERSION : [${Boost_MAJOR_VERSION}]" ) + message( STATUS " Boost_MINOR_VERSION : [${Boost_MINOR_VERSION}]" ) + message( STATUS " Boost_SUBMINOR_VERSION : [${Boost_SUBMINOR_VERSION}]" ) + message( STATUS " Boost_INCLUDE_DIRS : [${Boost_INCLUDE_DIRS}]" ) + message( STATUS " Boost_LIBRARY_DIR_RELEASE : [${Boost_LIBRARY_DIR_RELEASE}]" ) + message( STATUS " Boost_SYSTEM_LIBRARY : [${Boost_SYSTEM_LIBRARY}]" ) + message( STATUS " Boost_THREAD_LIBRARY : [${Boost_THREAD_LIBRARY}]" ) + message( STATUS " Boost_FILESYSTEM_LIBRARY : [${Boost_FILESYSTEM_LIBRARY}]" ) + message( STATUS " Boost_PROGRAM_OPTIONS_LIBRARY : [${Boost_PROGRAM_OPTIONS_LIBRARY}]" ) + message( STATUS " Boost_DATE_TIME_LIBRARY : [${Boost_DATE_TIME_LIBRARY}]" ) + message( STATUS " Boost_UNIT_TEST_FRAMEWORK_LIBRARY : [${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}]" ) + message( STATUS " Boost_TEST_EXEC_MONITOR_LIBRARY : [${Boost_TEST_EXEC_MONITOR_LIBRARY}]" ) + message( STATUS " Boost_REGEX_LIBRARY : [${Boost_REGEX_LIBRARY}]" ) + message( STATUS " Boost_PYTHON_LIBRARY : [${Boost_PYTHON_LIBRARY}]" ) + message( STATUS " Boost_PYTHON_LIBRARY_RELEASE : [${Boost_PYTHON_LIBRARY_RELEASE}]" ) + message( STATUS " Boost_PYTHON3_LIBRARY : [${Boost_PYTHON3_LIBRARY}]" ) + message( STATUS " Boost_PYTHON3_LIBRARY_RELEASE : [${Boost_PYTHON3_LIBRARY_RELEASE}]" ) + message( STATUS " Boost_PYTHON27_LIBRARY : [${Boost_PYTHON27_LIBRARY}]" ) + message( STATUS " Boost_PYTHON27_LIBRARY_RELEASE : [${Boost_PYTHON27_LIBRARY_RELEASE}]" ) + message( STATUS " Boost_PYTHON36_LIBRARY : [${Boost_PYTHON36_LIBRARY}]" ) + message( STATUS " Boost_PYTHON36_LIBRARY_RELEASE : [${Boost_PYTHON36_LIBRARY_RELEASE}]" ) endif() if (ENABLE_SSL) ecbuild_info("OpenSSL VERSION ${OPENSSL_VERSION}") ecbuild_info(" LIBS ${OPENSSL_LIBRARIES}") ecbuild_info(" INCLUDES ${OPENSSL_INCLUDE_DIR}") -endif() \ No newline at end of file +endif() diff -Nru ecflow-4.10.0/Pyext/CMakeLists.txt ecflow-4.11.1/Pyext/CMakeLists.txt --- ecflow-4.10.0/Pyext/CMakeLists.txt 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Pyext/CMakeLists.txt 2018-10-23 11:41:34.000000000 +0000 @@ -52,9 +52,10 @@ # This ensures that for debug config, we only link with debug boost libs, for other configs, we link with optimised boost libs -if ( PYTHONLIBS_FOUND ) - target_link_libraries(ecflow debug ${Boost_PYTHON_LIBRARY_DEBUG} ) - target_link_libraries(ecflow optimized ${Boost_PYTHON_LIBRARY_RELEASE} ) +if ( PYTHON_VERSION_MAJOR EQUAL 3) + target_link_libraries(ecflow ${Boost_PYTHON3_LIBRARY_RELEASE} ) +else() + target_link_libraries(ecflow ${Boost_PYTHON_LIBRARY_RELEASE} ) endif() # diff -Nru ecflow-4.10.0/Pyext/ecflow/__init__.py ecflow-4.11.1/Pyext/ecflow/__init__.py --- ecflow-4.10.0/Pyext/ecflow/__init__.py 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Pyext/ecflow/__init__.py 2018-10-23 11:41:34.000000000 +0000 @@ -15,6 +15,6 @@ The ecFlow python module """ -__version__ = '4.10.0' +__version__ = '4.11.1' # http://stackoverflow.com/questions/13040646/how-do-i-create-documentation-with-pydoc diff -Nru ecflow-4.10.0/Pyext/samples/overview.py ecflow-4.11.1/Pyext/samples/overview.py --- ecflow-4.10.0/Pyext/samples/overview.py 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Pyext/samples/overview.py 2018-10-23 11:41:34.000000000 +0000 @@ -1,8 +1,10 @@ #!/usr/bin/env python +# -*- coding= UTF-8 -*- """ tkinter example with ecflow """ - +from __future__ import with_statement, print_function import Tkinter as tki +from Tkinter import * import Queue import sys import time @@ -33,6 +35,24 @@ "unknwon": "grey"} running = [True] +ONCE = False + + +def show_check(one): + print(one) + sep = ',' + if sep not in one: return + exp = one.split(sep) + if len(exp) != 4: return + host, qid = exp[2], exp[3] + check = os.getenv("CHECK_TASK", "check_task.py") + global ONCE + if check is not None: + print(check + " -n %s -j %s" % (host, qid)) + elif ONCE: + print("#WAR: export CHECK_TASK=$HOME/bin/check_task.py; overview.py $ECF_HOST@$ECF_PORT,") + ONCE = True + class Label(object): """ a class to encapsulate what was a global variable""" @@ -52,12 +72,19 @@ def __init__(self, parent): tki.Frame.__init__(self, parent) + self.parent = parent self.__helpButton = self.__createHelp() self.__helpButton.grid(row=0, column=3) + self.__quitButton = tki.Button(self, text='Quit', font=BUTTON_FONT, + command=root.destroy) + self.__quitButton.grid(row=0, column=1) self.__updateButton = tki.Button(self, text='Update', font=BUTTON_FONT, command=parent.update) self.__updateButton.grid(row=0, column=2) + def quit(self, event=None): + self.parent.quit() + def __createHelp(self): mb = tki.Menubutton(self, font=BUTTON_FONT, relief=tki.RAISED, text='Help') @@ -73,31 +100,67 @@ return mb def __url(self, url=None): - if url is None: - return - os.system("firefox " + url) + if url is not None: + os.system("${BROWSER:=firefox} %s" % url) class TaskList(tki.Frame): """ a class to host all tasks""" - WIDTH = 40 - LINES = 80 + # WIDTH = w / 30 + # LINES = h / 10 def __init__(self, parent, kind): - tki.Frame.__init__(self, parent) + tki.Frame.__init__(self, parent, + # side="bottom", + # fill="both", + # expand=True, + # sticky="nsew", + ) + self.WIDTH = 80 + self.LINES = 80 self.__kind = kind self.__callback = None - self.__label = tki.Label( - self, font=BUTTON_FONT, background=COLORS[kind], text=kind) - self.__label.grid(row=0, column=0, sticky=tki.W) + #self.__label = tki.Label( + # self, font=BUTTON_FONT, background=COLORS[kind], text=kind) + #self.__label.grid(row=0, column=0, sticky=tki.W) + select = tki.Button(self, text=kind, + font=BUTTON_FONT, + background=COLORS[kind], + command=self.select) + select.grid(row=1, column=0, sticky=tki.W) + + selectall = tki.Button(self, text="select all", + font=BUTTON_FONT, + # background=COLORS[kind], + command=self.select_all) + selectall.grid(row=2, column=0, sticky=tki.W) + self.__scrolledList = ScrolledList( - self, width=self.WIDTH, height=self.LINES, + self, + # sticky="nsew", + width=self.WIDTH, + height=self.LINES, # selectmode=tki.EXTENDED, callback=self.__callback) - self.__scrolledList.grid(row=1, column=0) + self.__scrolledList.grid(row=3, column=0) - def insert(self, path): self.__scrolledList.append(path) + def select_all(self): + res = set() + item = self.__scrolledList.listbox.get(0, tki.END) + for one in item: + print(one) + + def select(self): + res = set() + selected = self.__scrolledList.listbox.curselection() + for i in selected: + item = self.__scrolledList.listbox.get(i) + res.add(item) + for one in res: + show_check(one) + + def insert(self, path): self.__scrolledList.append(path) - def clear(self): self.__scrolledList.clear() + def clear(self): self.__scrolledList.clear() class PaceKeeper(): @@ -124,31 +187,25 @@ class Client(object): """ a class to focus on client-ecFlow-server comm""" - def __init__(self, one="local-localhost@31415"): - try: - nick, hhh = one.split("-") - except: - hhh = one - nick = None - try: - host, port = hhh.split("@") - except: - host = "localhost" - port = 31415 - - if nick is None: - self.nick = "%s@%d" % (host, port) - print "# client creation", nick, host, port - self.nick = nick + def __init__(self, one="localhost@31415"): + # try: nick, hhh = one.split("-") + # except: hhh = one; nick = None + if "@" in one: + host, port = one.split("@") + # except: + else: host = "localhost"; port = 31415 + self.nick = one + # if nick is None: self.nick = "%s@%s" % (host, port) + print("# client creation", self.nick, host, port) self.client = ec.Client(host, port) def process(self, win): - Label.update() + # Label.update() self.client.sync_local() defs = self.client.get_defs() if defs is None: print("# %s-%: empty content" % (self.host, self.port)) - Label.update() + # Label.update() for suite in defs.suites: self.process_nc(suite, win) @@ -159,12 +216,21 @@ else: self.process_nc(item, win) - def process_node(self, node, wins): + def process_node(self, item, wins): for kind, win in wins.items(): - status = "%s" % node.get_state() + status = "%s" % item.get_state() if status != kind: continue - win.insert("%s:%s" % (self.nick, node.get_abs_node_path())) + change = item.get_state_change_time() + line = "#%s:%s,%s" % ( + self.nick, item.get_abs_node_path(), change) + try: + import check_task as ct + qid = str(ct.display_var(item, "qid")) + host = ct.display_var(item, "ECF_JOB_CMD") + line += ",%s,%s" % (host, qid) + except: pass + win.insert(line) try: sys.path.append('/usr/local/apps/sms/lib/') @@ -194,7 +260,7 @@ user = get_username() if DEBUG: - print "#MSG: login:", nick, host, port, user + print("#MSG: login:", nick, host, port, user) handle, rc = cdp.sms_client_login(host, user, passwd, timeout, port, tree) self.handle = handle @@ -219,7 +285,7 @@ path = cdp.sms_node_full_name(node) win.insert("%s:%s" % (self.nick, path)) if DEBUG: - print self.host, self.port, path, state + print(self.host, self.port, path, state) def process(self, win): rc = cdp.sms_client_news(self.handle, self.num) @@ -253,40 +319,59 @@ def __exit__(self): cdp.sms_client_logout(self.handle) - print "# logout from", self.nick + print("# logout from", self.nick) def __delete__(self): cdp.sms_client_logout(self.handle) - print "# logout from", self.nick + print("# logout from", self.nick) + class Application(tki.Frame): """ main """ - def __init__(self, master=None, client=None, queue=None): - tki.Frame.__init__(self, master) + def __init__(self, parent=None, client=None, queue=None): + if parent is None: parent = tki.Tk() + w, h = parent.winfo_screenwidth(), parent.winfo_screenheight() + tki.Frame.__init__(self, parent) if client is None: - self.__clients = [Client("localhost@31415"), ] - elif type(client) == set: + raise Exception("#ERR: please provide a client...\n./overview.py $ECF_HOST@$ECF_PORT") + elif type(client) in (set, tuple): self.__clients = client else: self.__clients = [client] - self.__queue = queue - width = 640 - height = 780 + # width = 640; height = 780 + width = w; height = h self.canvas = tki.Canvas(width=width, height=height, bg='black') self.grid() self.createWidgets() self.canvas.after(50, self.check_queue) + self.bind_all("", self.update) + # self.bind_all("Control_q", self.quit) + # self.bind_all("Control_z", self.resize) + self.bind_all("", self.quit) + self.bind_all("", self.resize) + + def resize(self, event=None): print("New size is: {}x{}".format(event.width, event.height)) + + def quit(self, event=None): + print("quit...") + self.destroy() + # global running; running = [ False, ] + # sys.exit(0) + def createWidgets(self): - rowx = 1 - glob = Label(tki.StringVar(self)) + global root root = self + rowx = 1 + var = tki.StringVar(self) + glob = Label(root) + # glob = Label(var) self.__menuBar = MenuBar(root) self.__menuBar.grid(row=0, column=0, sticky=tki.W) - self.label = tki.Label(root, textvariable=Label.inst) + self.label = tki.Label(root, textvariable=var) # Label.inst) self.label.grid(row=0, column=2, sticky=tki.E) self.__wins = dict() rowx += 1 @@ -308,8 +393,8 @@ self.update() self.canvas.after(50, self.check_queue) - def update(self): - Label.update() + def update(self, event=None): + self.label.update() for kind, win in self.__wins.items(): win.clear() for client in self.__clients: @@ -317,10 +402,7 @@ for clt in client: clt.process(self.__wins) else: - try: - client.process(self.__wins) - except: - pass + client.process(self.__wins) def get_username(): return pwd.getpwuid(os.getuid())[0] @@ -335,23 +417,30 @@ except: port = 31415 - if len(sys.argv) > 0: + if len(sys.argv) > 1: clients = [] - for num in xrange(1, len(sys.argv)): - clients.append(Client(sys.argv[num])) - else: - clients = [Client("localhost%d" % port)] + for num in xrange(1, len(sys.argv)): + sep = ',' + arg = sys.argv[num] + if sep in arg: + for one in arg.split(sep): + client = Client(one) + else: + client = Client(arg) + clients.append(client) + else: + one = "localhost%d" % port + print("# using", one) + clients = [Client(one), ] queue = Queue.Queue() - # app = AppSms(host, port, queue) app = Application(client=clients, queue=queue) app.master.title(PROGRAM_NAME) app.columnconfigure(0, weight=1) app.rowconfigure(0, weight=1) - PaceKeeper(app, queue) app.mainloop() """ -python ./overview.py localhost-localhost@31415 +python ./overview.py localhost@31415, """ diff -Nru ecflow-4.10.0/Pyext/src/ExportNodeAttr.cpp ecflow-4.11.1/Pyext/src/ExportNodeAttr.cpp --- ecflow-4.10.0/Pyext/src/ExportNodeAttr.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Pyext/src/ExportNodeAttr.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -354,12 +354,13 @@ .value("complete",Child::COMPLETE) ; - enum_("AttrType", "Sortable attribute type, currently [event | meter | label | limit | variable ]") + enum_("AttrType", "Sortable attribute type, currently [event | meter | label | limit | variable | all ]") .value("event", Attr::EVENT) .value("meter", Attr::METER) .value("label", Attr::LABEL) .value("limit", Attr::LIMIT) .value("variable",Attr::VARIABLE) + .value("all", Attr::ALL) ; // ZombieAttr(ecf::Child::ZombieType t, const std::vector& c, ecf::User::Action a, int zombie_lifetime); diff -Nru ecflow-4.10.0/Pyext/test/py_s_TestClientApi.py ecflow-4.11.1/Pyext/test/py_s_TestClientApi.py --- ecflow-4.10.0/Pyext/test/py_s_TestClientApi.py 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Pyext/test/py_s_TestClientApi.py 2018-10-23 11:41:34.000000000 +0000 @@ -1770,7 +1770,7 @@ #print("Handle:",local_ci .ch_handle()) local_ci.ch_suites() #raise RuntimeError("xxx") #check exeption is still caught - except RuntimeError, e: + except RuntimeError as e: print("Exception",e) print("after with:") # really need a way to get hold of the suites, via python api. diff -Nru ecflow-4.10.0/Pyext/test/py_u_TestAddDelete.py ecflow-4.11.1/Pyext/test/py_u_TestAddDelete.py --- ecflow-4.10.0/Pyext/test/py_u_TestAddDelete.py 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Pyext/test/py_u_TestAddDelete.py 2018-10-23 11:41:34.000000000 +0000 @@ -41,12 +41,33 @@ expected = ['AECF_URL','XECF_URL_BASE','YECF_URL_CMD','ZFRED'] actual = [] defs.sort_attributes("variable"); + for v in defs.user_variables: actual.append(v.name()) + assert actual == expected,"Attributes not sorted, expected:" + str(expected) + " but found:" + str(actual) + + expected = ['AECF_URL','XECF_URL_BASE','YECF_URL_CMD','ZFRED','ZZ'] + actual = [] + defs.add_variable("ZZ", "x") defs.sort_attributes(ecflow.AttrType.variable); for v in defs.user_variables: actual.append(v.name()) assert actual == expected,"Attributes not sorted, expected:" + str(expected) + " but found:" + str(actual) + + expected = ['AA', 'AECF_URL','XECF_URL_BASE','YECF_URL_CMD','ZFRED','ZZ'] + actual = [] + defs.add_variable("AA", "x") + defs.sort_attributes("all"); + for v in defs.user_variables: actual.append(v.name()) + assert actual == expected,"Attributes not sorted, expected:" + str(expected) + " but found:" + str(actual) + + expected = ['AA', 'AECF_URL', 'BB','XECF_URL_BASE','YECF_URL_CMD','ZFRED','ZZ'] + actual = [] + defs.add_variable("BB", "x") + defs.sort_attributes(ecflow.AttrType.all ); + for v in defs.user_variables: actual.append(v.name()) + assert actual == expected,"Attributes not sorted, expected:" + str(expected) + " but found:" + str(actual) + - defs.delete_variable("ZFRED");assert len(list(defs.user_variables)) == 3, "Expected 3 variables since we just delete FRED" + defs.delete_variable("ZFRED");assert len(list(defs.user_variables)) == 6, "Expected 6 variables since we just delete ZFRED" defs.delete_variable(""); assert len(list(defs.user_variables)) == 0, "Expected 0 variables since we should have deleted all" a_dict = { "name":"value", "name2":"value2", "name3":"value3", "name4":"value4" } diff -Nru ecflow-4.10.0/Pyext/test/py_u_TestCopy.py ecflow-4.11.1/Pyext/test/py_u_TestCopy.py --- ecflow-4.10.0/Pyext/test/py_u_TestCopy.py 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Pyext/test/py_u_TestCopy.py 2018-10-23 11:41:34.000000000 +0000 @@ -24,6 +24,7 @@ print("Running ecflow version " + ecflow.Client().version() + " debug build(" + str(ecflow.debug_build()) +")") print("PYTHONPATH: " + str(os.environ['PYTHONPATH'].split(os.pathsep))) print("sys.path: " + str(sys.path)) + print("Python version: " + str(sys.version_info[0]) + "." + str(sys.version_info[1])) print("####################################################################") defs = ecflow.Defs() diff -Nru ecflow-4.10.0/share/ecflow/etc/ecflowview_gui.json ecflow-4.11.1/share/ecflow/etc/ecflowview_gui.json --- ecflow-4.10.0/share/ecflow/etc/ecflowview_gui.json 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/share/ecflow/etc/ecflowview_gui.json 2018-10-23 11:41:34.000000000 +0000 @@ -3,7 +3,8 @@ "hidden" : { "visible" : "false", - "line" : "panel.variable.showShadowed" + "line" : "panel.variable.showShadowed", + "line" : "view.table.variableColumns" }, "appearance": { @@ -119,6 +120,7 @@ "title" : "Options", "prefix" : "view", + "line" : "tree.autoExpandLeafNode", "line" : "tree.displayNodeType", "line" : "tree.display_child_count", "line" : "tree.indentation", @@ -253,12 +255,22 @@ "line" : "server.menu.nodeMenuMode", "note" : { - "default" : "Operator and Administrator modes allow suites to be begun, nodes to be removed and servers to be unlocked. Administrator mode additionally enables the Force and Order menus." - }, + "default" : "Operator and Administrator modes allow suites to be begun, nodes to be removed and servers to be unlocked. Administrator mode additionally enables the Force and Order menus." + }, "note" : { "default" : "These settings can be customised for each server separately" } }, + + "group" : { + "title" : "Node context menu control", + + "line" : "server.menu.defStatusMenuModeControl", + "note" : { + "default" : "These settings can be customised for each server separately" + } + }, + "group" : { "title" : "Request confirmation when:", "prefix" : "menu.confirm", diff -Nru ecflow-4.10.0/share/ecflow/etc/ecflowview_gui_server.json ecflow-4.11.1/share/ecflow/etc/ecflowview_gui_server.json --- ecflow-4.10.0/share/ecflow/etc/ecflowview_gui_server.json 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/share/ecflow/etc/ecflowview_gui_server.json 2018-10-23 11:41:34.000000000 +0000 @@ -37,7 +37,8 @@ "title" : "Menus", "prefix" : "server.menu", - "line" : "nodeMenuMode" + "line" : "nodeMenuMode", + "line" : "defStatusMenuModeControl" }, "custom-notification" : { diff -Nru ecflow-4.10.0/share/ecflow/etc/ecflowview_icon_conf.json ecflow-4.11.1/share/ecflow/etc/ecflowview_icon_conf.json --- ecflow-4.10.0/share/ecflow/etc/ecflowview_icon_conf.json 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/share/ecflow/etc/ecflowview_icon_conf.json 2018-10-23 11:41:34.000000000 +0000 @@ -38,12 +38,20 @@ }, "time" : { "label" : "Time", - "tooltip" : "Node has a time dependency.", - "shortDesc" : "Has time dependency", + "tooltip" : "Node has a holding time dependency.", + "shortDesc" : "Has holding time dependency", "icon" : { "default" : "icon_clock.svg" } }, + "time_free" : { + "label" : "Time (non-holding)", + "tooltip" : "Node has a non-holding time dependency.", + "shortDesc" : "Has non-holding time dependency", + "icon" : { + "default" : "icon_clock_free.svg" + } + }, "date" : { "label" : "Date", "tooltip" : "Node has date or day dependency.", diff -Nru ecflow-4.10.0/share/ecflow/etc/ecflowview_menus.json ecflow-4.11.1/share/ecflow/etc/ecflowview_menus.json --- ecflow-4.10.0/share/ecflow/etc/ecflowview_menus.json 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/share/ecflow/etc/ecflowview_menus.json 2018-10-23 11:41:34.000000000 +0000 @@ -223,7 +223,7 @@ "name" : "Defstatus", "type" : "Submenu", "menu" : "Node", - "visible_for" : "node or alias", + "visible_for" : "(node or alias) and (defStatusMenuModeControl)", "command" : "None" }, @@ -465,26 +465,51 @@ { "menu" : "Special", - "name" : "Check", - "command" : "sh ecflow_client --port %ECF_PORT% --host %ECF_HOST% --check /%SUITE%/%FAMILY:%%TASK:%", + "name" : "-" + }, + + { + "menu" : "Special", + "name" : "URL command", + "command" : "sh %ECF_URL_CMD%", "multi" : "false", "status_tip" : "__cmd__" }, + { + "menu" : "Special", + "name" : "-" + }, { "menu" : "Special", - "name" : "Free password", - "visible_for" : "(task or alias)", - "command" : "ecflow_client --alter add variable ECF_PASS FREE ", + "name" : "Create JSD ticket", + "visible_for" : "(task or alias) and ECFLOWUI_ECMWF_OPERATOR_MODE)", + "command" : "create_jsd_ticket", + "multi" : "false", "status_tip" : "__cmd__" }, { "menu" : "Special", - "name" : "Clear zombie flag", - "visible_for" : "(task or alias)", - "command" : "ecflow_client --alter clear_flag zombie ", + "name" : "-", + "visible_for" : "(task or alias) and ECFLOWUI_ECMWF_OPERATOR_MODE)" + }, + + { + "menu" : "Special", + "name" : "Check", + "command" : "sh ecflow_client --port %ECF_PORT% --host %ECF_HOST% --check /%SUITE%/%FAMILY:%%TASK:%", + "multi" : "false", + "status_tip" : "__cmd__" + }, + + { + "menu" : "Special", + "name" : "Check node state in UI", + "visible_for" : "(server or node) and ECFLOWUI_DEVELOP_MODE)", + "command" : "check_ui_node_state", + "multi" : "false", "status_tip" : "__cmd__" }, @@ -514,6 +539,14 @@ { "menu" : "Special", + "name" : "Clear zombie flag", + "visible_for" : "(task or alias)", + "command" : "ecflow_client --alter clear_flag zombie ", + "status_tip" : "__cmd__" + }, + + { + "menu" : "Special", "name" : "Details", "visible_for" : "task", "command" : "sh grep %ECF_NAME% %ECF_LOG%", @@ -530,6 +563,14 @@ "status_tip" : "__cmd__" }, +{ + "menu" : "Special", + "name" : "Free password", + "visible_for" : "(task or alias)", + "command" : "ecflow_client --alter add variable ECF_PASS FREE ", + "status_tip" : "__cmd__" + }, + { "menu" : "Special", "name" : "Mark for move", diff -Nru ecflow-4.10.0/share/ecflow/etc/ecflowview_server_conf.json ecflow-4.11.1/share/ecflow/etc/ecflowview_server_conf.json --- ecflow-4.10.0/share/ecflow/etc/ecflowview_server_conf.json 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/share/ecflow/etc/ecflowview_server_conf.json 2018-10-23 11:41:34.000000000 +0000 @@ -91,7 +91,16 @@ "values" : "user/oper/admin", "values_label" : "User/Operator/Administrator", "default": "user" - } + }, + + "defStatusMenuModeControl": { + "label": "Enable Defstatus submenu in these modes", + "tooltip" : "Controls when the Defstatus submenu is available", + "values" : "user/oper/admin", + "values_label" : "User/Operator/Administrator", + "default": "user/oper/admin", + "multi" : "true" + } }, "notification": { diff -Nru ecflow-4.10.0/share/ecflow/etc/ecflowview_view_conf.json ecflow-4.11.1/share/ecflow/etc/ecflowview_view_conf.json --- ecflow-4.10.0/share/ecflow/etc/ecflowview_view_conf.json 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/share/ecflow/etc/ecflowview_view_conf.json 2018-10-23 11:41:34.000000000 +0000 @@ -27,6 +27,12 @@ "values" : "standard/compact", "values_label" : "Standard/Compact" }, + + "autoExpandLeafNode" : { + "label" : "Automatically expand leaf nodes", + "default" : "false" + }, + "nodeFont" : { "label" : "Nodes", "default": "font(,)" @@ -109,6 +115,10 @@ "popupFilter" : { "label" : "Popup filter dialog when new table view is added", "default" : "true" + }, + "variableColumns" : { + "label" : "Variable columns", + "default" : "__none__" } }, @@ -236,7 +246,9 @@ }, "table_columns": { - + + "__config__" : "view.table.variableColumns", + "path" : { "label" : "Node", "tooltip" : "Node" diff -Nru ecflow-4.10.0/tools/ecflow_logserver.sh ecflow-4.11.1/tools/ecflow_logserver.sh --- ecflow-4.10.0/tools/ecflow_logserver.sh 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/tools/ecflow_logserver.sh 2018-10-23 11:41:34.000000000 +0000 @@ -1,4 +1,4 @@ -#!/bin/ksh +#!/bin/bash #========================================================================================= # Syntax @@ -6,7 +6,7 @@ # #========================================================================================= -USAGE(){ +USAGE() { echo "Usage: $0 [-d ] [-m ] [-l ] [-h]" echo " -d specify the directory name where files will be served" echo " from - default is \$HOME" @@ -54,17 +54,17 @@ fi -if [[ "${EC_TIMECRIT_UID}" = "yes" ]] ; then +if [[ "${EC_TIMECRIT_UID}" == "yes" ]] ; then # Time-critical user with no $HOME set - if [[ "${server_dir:-}" = "" ]] ; then + if [[ "${server_dir:-}" == "" ]] ; then echo "Set the location of the server directory with -d" echo "" USAGE exit 1 fi - if [[ "${server_logfile:-}" = "" ]] ; then + if [[ "${server_logfile:-}" == "" ]] ; then echo "Set the location of the server log file with -l" echo "" USAGE @@ -92,22 +92,21 @@ # prognum is set based on the unique users numeric uid. -username=`id -u` +username=$(id -u) base=35000 prognum=$((base+username)) -PROG=`which $0` -PROG_PATH=`readlink -f $PROG` +PROG=$(which $0) +PROG_PATH=$(readlink -f $PROG) PATH_NAME=$ecflow_DIR/bin -# `dirname $PROG_PATH` export LOGPORT=$prognum -LOGDIR=`dirname $LOGFILE` +LOGDIR=$(dirname $LOGFILE) [[ ! -d $LOGDIR ]] && mkdir -p $LOGDIR -check=`ps -fu ${USER} | grep ecflow_logsvr.pl | grep -v grep 1>/dev/null 2>&1 \ - && echo 1 || echo 0` +check=$(ps -fu ${USER} | grep ecflow_logsvr.pl | grep -v grep 1>/dev/null 2>&1 \ + && echo 1 || echo 0) if [ $check = 0 ] ; then nohup $PATH_NAME/ecflow_logsvr.pl 1>$LOGFILE 2>&1 & else @@ -116,8 +115,8 @@ sleep 1 -check=`ps -fu ${USER} | grep ecflow_logsvr.pl | grep -v grep 1>/dev/null 2>&1 \ - && echo 1 || echo 0` +check=$(ps -fu ${USER} | grep ecflow_logsvr.pl | grep -v grep 1>/dev/null 2>&1 \ + && echo 1 || echo 0) if [ $check = 0 ] ; then /usr/bin/tail -n 30 $LOGFILE | /bin/mail -s "$(hostname -s): logserver for ${USER} did not start. Please investigate..." -c "root" ${USER} exit 1 @@ -125,7 +124,7 @@ if [[ -f ${LOGSERVERLIST} ]] ; then - logserverfound=`grep $LOGPORT ${LOGSERVERLIST} | grep $USER` + logserverfound=$(grep $LOGPORT ${LOGSERVERLIST} | grep $USER) if [[ -z $logserverfound ]]; then echo $USER $LOGPORT $LOGPATH $LOGMAP>> ${LOGSERVERLIST} fi diff -Nru ecflow-4.10.0/tools/ecflow_standalone.c ecflow-4.11.1/tools/ecflow_standalone.c --- ecflow-4.10.0/tools/ecflow_standalone.c 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/tools/ecflow_standalone.c 2018-10-23 11:41:34.000000000 +0000 @@ -1,5 +1,5 @@ /* -## Copyright 2009-2017 ECMWF. +## Copyright 2009-2019 ECMWF. ## This software is licensed under the terms of the Apache Licence version 2.0 ## which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. ## In applying this licence, ECMWF does not waive the privileges and immunities @@ -13,7 +13,37 @@ * standard out, and duplicate standard out as standard error. The next fopen() * is then used as standard out/error. i.e output file. * -* test using: +# Build stand alone to test +gcc -g -Dlinux ecflow_standalone.c -o ecflow_standalone + +# Create file exe.sh use in the test below. +cat > $(pwd)/exe.sh <<\!! +xxx="hello worlds from /home/ma/ma0" +#printenv +echo $SHELL +fred="ma0@ecmwf.int" +mail -s "$xxx" $fred <<@@ +$xxx +@@ +!! + +# Both these tests must work. +ssh localhost $(pwd)/ecflow_standalone -s /bin/bash -o $(pwd)/out.txt < $(pwd)/exe.sh # EXPECT non empty out.txt, and mail +ssh localhost $(pwd)/ecflow_standalone -s /bin/bash -o $(pwd)/out.txt -i $(pwd)/exe.sh # EXPECT non empty out.txt, and mail + +# expected out.txt ++ xxx='hello worlds from /home/ma/map' ++ printenv ++ echo /bin/ksh ++ fred=ma0@ecmwf.int ++ mail -s 'hello worlds from /home/ma/map' ma0@ecmwf.int + +std=/usr/local/apps/sms/bin/standalone +ssh eurus.ecmwf.int $std -s /bin/bash -o $(pwd)/out.txt < $(pwd)/exe.sh # OK +ssh localhost $std -s /bin/bash -o $(pwd)/out.txt -i $(pwd)/exe.sh # OK + +* +* Other test using: * echo "xxx=\"hello worlds from $HOME\"\nfred=$USER" | ./ecflow_standalone -i in.txt -o out.txt * * in.txt @@ -35,6 +65,7 @@ #include #include #include +#include /* for PATH_MAX */ #ifndef TRUE # define TRUE 1 @@ -53,13 +84,14 @@ int main(argc,argv) int argc; char **argv; { + char buff[MAXLEN]; /* Temp buffer to read in lines */ + char fname[PATH_MAX]; char *infile = NULL; /* Temporary input file */ char *outfile= "/dev/null"; /* Output file (def /dev/null) */ char *shell= "/bin/sh"; /* default shell */ /* int keep_file=FALSE;*/ /* Flag to keep the input file */ FILE *fp; /* Temp to write the input file */ - char buff[MAXLEN]; /* Temp buffer to read in lines */ int option; extern char *optarg; /* Needed for the getopt */ @@ -88,15 +120,33 @@ } /* Copy standard input to infile */ - if( !infile ) infile=(char *)tmpnam(NULL); - if( !(fp=fopen(infile,"w")) ) { - perror("STANDALONE-INPUT-FILE"); - exit(1); + if( !infile ) { + /* printf("!infile\n"); */ + static char template[] = "/tmp/tmp_ecflowXXXXXX"; + strcpy(fname, template); /* Copy template */ + + int fd = mkstemp(fname); + /* printf("input Filename is %s\n", fname); Print it for information */ + infile = fname; + close(fd); + + if (!(fp = fopen(infile, "w"))) { + perror("ecflow_standalone.c, temp file creation error"); + exit(1); + } + while( fgets(buff, MAXLEN-1, stdin)) { + /* fprintf(stderr, "%s", buff); */ + fputs(buff,fp); + } + } + else { + if( !(fp=fopen(infile,"r")) ) { + perror("STANDALONE-INPUT-FILE cannot open"); + exit(1); + } } - while( fgets( buff,MAXLEN-1,stdin) ) fputs(buff,fp); fclose(fp); - /* fork child process, closing the parent */ switch(fork()) { case -1: perror(*argv); exit(1); @@ -122,7 +172,7 @@ perror("STANDALONE-INPUT-FILE-FOR-SHELL"); exit(1); } - fclose(fp); + /* fclose(fp); */ /* if( !keep_file ) unlink(infile); for (n=3; n<65535 ;n++) fclose(n); */ @@ -139,8 +189,7 @@ } execl(shell,nameof(shell),"-x",infile,(char *)0); - /* if( !keep_file ) unlink(infile); */ - - fclose(fout); /* must be closed last */ + /* if( !keep_file ) unlink(infile); + fclose(fout); */ exit(1); } diff -Nru ecflow-4.10.0/tools/ecflow_start.sh ecflow-4.11.1/tools/ecflow_start.sh --- ecflow-4.10.0/tools/ecflow_start.sh 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/tools/ecflow_start.sh 2018-10-23 11:41:34.000000000 +0000 @@ -122,6 +122,7 @@ if [[ $THERE == OK ]]; then echo "server is already started" res="$(ps -lf -u $USER | grep ecflow_server | grep -v grep)" + # which netstat && res="$(netstat -lnptu 2>/dev/null | grep ecflow | grep $ECF_PORT)" echo "$res $(ecflow_client --stats)" if [ "$res" == "" ] ; then mail $USER -s "server is already started - server hijack?" <name()); + } + if (maximum_ < 30) { + maximum_ = 30; + gui::error("%s: maximum reset to 30!", this->name()); + } frequency(timeout_); } @@ -366,6 +372,7 @@ void host::run() { if (!poll_) return; + if(_input != 0) { scripting::run(_input); } update(); if (drift_) drift(5, maximum_ * 60); } @@ -952,7 +959,13 @@ void host::changed( resource& r ) { - if (&r == &timeout_) frequency(timeout_); + if (&r == &timeout_) { + if (timeout_ < 30) { + timeout_ = 30; + gui::error("%s: timeout reset to 30!", this->name()); + } + frequency(timeout_); + } } void ehost::changed( resource& r ) @@ -1749,6 +1762,8 @@ gui::message("host::news-error: %s", e.what()); XECFDEBUG std::cerr << "# host::news-error: " << e.what() << "\n"; } + + // if(_input != 0) { scripting::run(_input); } return err; } @@ -1917,3 +1932,24 @@ catch ( std::exception& e ) { } } + +/* +ECFLOWVIEW_INPUT=/tmp/ecflowview_listen +mkfifo $ECFLOWVIEW_INPUT +./bin/ecflowview & +echo "\nselect eod /law/main" >> $ECFLOWVIEW_INPUT +echo "\nselect eod /law" >> $ECFLOWVIEW_INPUT +echo "\norder eod4:/era5eda_7 alpha" >> $ECFLOWVIEW_INPUT + +echo "\nselect eod /law/main/12/euroshelf/wamrun" >> $ECFLOWVIEW_INPUT +echo "\nwindow -d -f Script" >> $ECFLOWVIEW_INPUT +echo "\nwindow -d -f Manual" >> $ECFLOWVIEW_INPUT + +echo "\nlogin eod2" >> $ECFLOWVIEW_INPUT +echo "\nlogout eod2" >> $ECFLOWVIEW_INPUT +echo "\nquit" >> $ECFLOWVIEW_INPUT + +WINDOW: +Check Collector Edit History Info Job Jobstatus Manual Messages +Options Output Script Suites Timeline Triggers Variables Why Zombies +*/ diff -Nru ecflow-4.10.0/view/src/host.h ecflow-4.11.1/view/src/host.h --- ecflow-4.10.0/view/src/host.h 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/view/src/host.h 2018-10-23 11:41:34.000000000 +0000 @@ -267,6 +267,8 @@ bool updating_; // SUP-423 option jobfile_length_; + + const char* _input; public: void updating(bool b) { updating_ = b; } virtual void stats(std::ostream& f) { }; diff -Nru ecflow-4.10.0/view/src/scripting.cc ecflow-4.11.1/view/src/scripting.cc --- ecflow-4.10.0/view/src/scripting.cc 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/view/src/scripting.cc 2018-10-23 11:41:34.000000000 +0000 @@ -90,17 +90,18 @@ } int process_command(const char *cmd) { - if (!cmd) return 1; + if (!cmd) return False; if (!strncmp("select", cmd, 6)) { char host[80] = { 0, }; char node[1024] = { 0, }; sscanf(cmd, "select %s %s", host, node); if (host[0] != 0 && node[0] != 0) { + std::cout << "#CMD (scripting): " << cmd << "\n"; select_cmd(host, node); } else { std::cerr << "#CMD (scripting): err: " << cmd << "\n"; - return 1; + return False; } } else if (!strncmp("order", cmd, 5)) { @@ -108,16 +109,16 @@ char node[1024] = { 0, }; sscanf(cmd, "order %s %s", node, kind); if (kind[0] != 0 && node[0] != 0) { + std::cout << "#CMD (scripting): " << cmd << "\n"; order_cmd(node, kind); } else { std::cerr << "#CMD (scripting): err: " << cmd << "\n"; - return 1; + return False; } } else if (!strncmp("menu", cmd, 4)) { menu_cmd(cmd); - } else if (!strncmp("quit", cmd, 4)) { quit_cmd(); @@ -128,7 +129,6 @@ login_cmd(host); } - } else if (!strncmp("output", cmd, 6)) { char node[2048] = { 0, }; char path[2048] = { 0, }; @@ -165,23 +165,24 @@ if (!strncmp("-f", name, 2)) frozen = 1; if (*ptr != ' ') { break; /* skip separator */ } ptr++; - std::cerr << "#CMD (scripting): process: " << name << "\n"; + std::cout << "#CMD (scripting): process: " << name << "\n"; } if (name[0] != 0) { + std::cout << "#CMD (scripting): process: " << name << "\n"; window_cmd(name, detached, frozen); } else { std::cerr << "#CMD (scripting): err: " << cmd << "\n"; - return 1; + return False; } } else if (!strncmp("\n", cmd, 1)) { } else { std::cerr << "#CMD (scripting): ignored: " << cmd << "\n"; - return 1; + return False; } std::cout << "#CMD (scripting): " << cmd << "\n"; - return 0; + return True; } #undef SCRIPT_PYTHON @@ -216,8 +217,8 @@ class ecflowview_input { std::string name_; - XtInputId id_; - int fd_; + XtInputId id_; + int fd_; std::string line_; public: @@ -402,7 +403,7 @@ scripting* s = find(argv[0]); if(s) return s->execute(argc,argv); fprintf(stderr,"cannot find command %s\n",argv[0]); - return 1; + return False; } IMP(scripting) diff -Nru ecflow-4.10.0/Viewer/ecflowUI/images/add_variable_column.svg ecflow-4.11.1/Viewer/ecflowUI/images/add_variable_column.svg --- ecflow-4.10.0/Viewer/ecflowUI/images/add_variable_column.svg 1970-01-01 00:00:00.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/images/add_variable_column.svg 2018-10-23 11:41:34.000000000 +0000 @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + V + + + diff -Nru ecflow-4.10.0/Viewer/ecflowUI/images/diag.svg ecflow-4.11.1/Viewer/ecflowUI/images/diag.svg --- ecflow-4.10.0/Viewer/ecflowUI/images/diag.svg 1970-01-01 00:00:00.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/images/diag.svg 2018-10-23 11:41:34.000000000 +0000 @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + ECMWF + + + en-GB + + + Metview icon + + + Metview icon + + + + + + + + + + + D + + diff -Nru ecflow-4.10.0/Viewer/ecflowUI/images/dock_add_variable_column.svg ecflow-4.11.1/Viewer/ecflowUI/images/dock_add_variable_column.svg --- ecflow-4.10.0/Viewer/ecflowUI/images/dock_add_variable_column.svg 1970-01-01 00:00:00.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/images/dock_add_variable_column.svg 2018-10-23 11:41:34.000000000 +0000 @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + V + + + diff -Nru ecflow-4.10.0/Viewer/ecflowUI/images/icon_clock_free.svg ecflow-4.11.1/Viewer/ecflowUI/images/icon_clock_free.svg --- ecflow-4.10.0/Viewer/ecflowUI/images/icon_clock_free.svg 1970-01-01 00:00:00.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/images/icon_clock_free.svg 2018-10-23 11:41:34.000000000 +0000 @@ -0,0 +1,283 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + ECMWF + + + en-GB + + + Metview icon + + + Metview icon + + + + + + + + + + + + + + + + + + + + + + diff -Nru ecflow-4.10.0/Viewer/ecflowUI/scripts/CMakeLists.txt ecflow-4.11.1/Viewer/ecflowUI/scripts/CMakeLists.txt --- ecflow-4.10.0/Viewer/ecflowUI/scripts/CMakeLists.txt 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/scripts/CMakeLists.txt 2018-10-23 11:41:34.000000000 +0000 @@ -1,7 +1,6 @@ # the list of files we want to install -set (files ecflow_ui ecflow_test_ui.sh) - +set (files ecflow_ui ecflow_test_ui.sh ecflow_ui_node_state_diag.sh) # set variables which will be expanded in the startup script diff -Nru ecflow-4.10.0/Viewer/ecflowUI/scripts/ecflow_ui.in ecflow-4.11.1/Viewer/ecflowUI/scripts/ecflow_ui.in --- ecflow-4.10.0/Viewer/ecflowUI/scripts/ecflow_ui.in 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/scripts/ecflow_ui.in 2018-10-23 11:41:34.000000000 +0000 @@ -23,6 +23,7 @@ cleanup(){ status=$? trap "" EXIT ERR + set +e # do not exit on errors during cleanup # restore stdout/stderr if [ x$ECFLOWUI_SLOG != xyes ] @@ -40,62 +41,73 @@ if [ -e $ECFLOWUI_LOGFILE ] ; then - TAILNUM=50 - UI_TAILNUM=50 - - if [ $ECFLOWUI_BT != "no" ] ; then - # find the backtrace tag if there - btline=$(grep -n "Backtrace:" $ECFLOWUI_LOGFILE | cut -f1 --delimiter=':') - gret=$? - if [ "$gret" = "0" -a "x$btline" != "x" ] ; then - nlines=$(wc -l $ECFLOWUI_LOGFILE | cut -f1 --delimiter=' ') - TAILNUM=$(expr $nlines - $btline + 100) + # if the error message is something that's not really a crash, then we should + # not send a crash report + hhh=$(grep "The X11 connection broke" $ECFLOWUI_LOGFILE) # 0 if x11 broke, 1 if not + x11notbroke=$? + + if [ "$x11notbroke" = "1" ] ; then + + TAILNUM=50 + UI_TAILNUM=50 + + if [ $ECFLOWUI_BT != "no" ] ; then + # find the backtrace tag if there + btline=$(grep -n "Backtrace:" $ECFLOWUI_LOGFILE | cut -f1 --delimiter=':') + gret=$? + if [ "$gret" = "0" -a "x$btline" != "x" ] ; then + nlines=$(wc -l $ECFLOWUI_LOGFILE | cut -f1 --delimiter=' ') + TAILNUM=$(expr $nlines - $btline + 100) + fi fi - fi - # Logic: ECFLOWUI_BT_EMAIL_ADDRESS_FILE is not set, then the log/backtrace - # will go to stdout; otherwise it will be e-mailed to the - # addresses instead (the user will not see the backtrace). - - if [ $ECFLOWUI_BT_EMAIL_ADDRESS_FILE != "x" ] ; then - if [ -e $ECFLOWUI_BT_EMAIL_ADDRESS_FILE ] ; then - EFLOWUI_LOGTAIL="${ECFLOWUI_LOGFILE}.tail" - ecfuimsg="ecFlowUI backtrace from user $USER" - echo "Sending crash report by e-mail..." - echo "user/host : $USER/$HOST" > $EFLOWUI_LOGTAIL - echo "ecflow version : $ECFLOWUI_VERSION" >> $EFLOWUI_LOGTAIL - echo "ecflow install dir : $ECFLOWUI_INSTALLDIR" >> $EFLOWUI_LOGTAIL - echo "start time : $ECFLOWUI_STARTTIME" >> $EFLOWUI_LOGTAIL - echo "stop time : $(date)" >> $EFLOWUI_LOGTAIL - echo "" >> $EFLOWUI_LOGTAIL - echo $status_message >> $EFLOWUI_LOGTAIL - tail -$TAILNUM $ECFLOWUI_LOGFILE >> $EFLOWUI_LOGTAIL + + # Logic: ECFLOWUI_BT_EMAIL_ADDRESS_FILE is not set, then the log/backtrace + # will go to stdout; otherwise it will be e-mailed to the + # addresses instead (the user will not see the backtrace). + + if [ $ECFLOWUI_BT_EMAIL_ADDRESS_FILE != "x" ] ; then + if [ -e $ECFLOWUI_BT_EMAIL_ADDRESS_FILE ] ; then + EFLOWUI_LOGTAIL="${ECFLOWUI_LOGFILE}.tail" + ecfuimsg="ecFlowUI backtrace from user $USER" + echo "Sending crash report by e-mail..." + echo "user/host : $USER/$HOST" > $EFLOWUI_LOGTAIL + echo "ecflow version : $ECFLOWUI_VERSION" >> $EFLOWUI_LOGTAIL + echo "ecflow install dir : $ECFLOWUI_INSTALLDIR" >> $EFLOWUI_LOGTAIL + echo "start time : $ECFLOWUI_STARTTIME" >> $EFLOWUI_LOGTAIL + echo "stop time : $(date)" >> $EFLOWUI_LOGTAIL + echo "" >> $EFLOWUI_LOGTAIL + echo $status_message >> $EFLOWUI_LOGTAIL + tail -$TAILNUM $ECFLOWUI_LOGFILE >> $EFLOWUI_LOGTAIL + + #Add the last lines from the user interaction log file + if [ -e $ECFLOWUI_LOGFILE ] ; then + echo "" >> $EFLOWUI_LOGTAIL + echo "Last $UI_TAILNUM lines of user interaction log file:" >> $EFLOWUI_LOGTAIL + tail -${UI_TAILNUM} $ECFLOWUI_LOGFILE >> $EFLOWUI_LOGTAIL + fi + + addr=$(head -1 $ECFLOWUI_BT_EMAIL_ADDRESS_FILE) + mail -s "$ecfuimsg" $addr < $EFLOWUI_LOGTAIL + rm -f $EFLOWUI_LOGTAIL + echo "Report sent" + else + echo "No report sent because e-mail address file does not exist: $ECFLOWUI_BT_EMAIL_ADDRESS_FILE" + fi + else + echo "Last $TAILNUM lines of log file:" + tail -$TAILNUM $ECFLOWUI_LOGFILE #Add the last lines from the user interaction log file if [ -e $ECFLOWUI_LOGFILE ] ; then - echo "" >> $EFLOWUI_LOGTAIL - echo "Last $UI_TAILNUM lines of user interaction log file:" >> $EFLOWUI_LOGTAIL - tail -${UI_TAILNUM} $ECFLOWUI_LOGFILE >> $EFLOWUI_LOGTAIL + echo "" + echo "Last $UI_TAILNUM lines of user interaction log file:" + tail -${UI_TAILNUM} $ECFLOWUI_LOGFILE fi - - addr=$(head -1 $ECFLOWUI_BT_EMAIL_ADDRESS_FILE) - mail -s "$ecfuimsg" $addr < $EFLOWUI_LOGTAIL - rm -f $EFLOWUI_LOGTAIL - echo "Report sent" - else - echo "No report sent because e-mail address file does not exist: $ECFLOWUI_BT_EMAIL_ADDRESS_FILE" fi else - echo "Last $TAILNUM lines of log file:" - tail -$TAILNUM $ECFLOWUI_LOGFILE - - #Add the last lines from the user interaction log file - if [ -e $ECFLOWUI_LOGFILE ] ; then - echo "" - echo "Last $UI_TAILNUM lines of user interaction log file:" - tail -${UI_TAILNUM} $ECFLOWUI_LOGFILE - fi - fi + echo "X11 Connection broke - no report sent to developers" + fi # $x11notbroke fi fi diff -Nru ecflow-4.10.0/Viewer/ecflowUI/scripts/ecflow_ui_node_state_diag.sh.in ecflow-4.11.1/Viewer/ecflowUI/scripts/ecflow_ui_node_state_diag.sh.in --- ecflow-4.10.0/Viewer/ecflowUI/scripts/ecflow_ui_node_state_diag.sh.in 1970-01-01 00:00:00.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/scripts/ecflow_ui_node_state_diag.sh.in 2018-10-23 11:41:34.000000000 +0000 @@ -0,0 +1,30 @@ +#!/bin/bash + +#============================================================================ +# Copyright 2009-2018 ECMWF. +# This software is licensed under the terms of the Apache Licence version 2.0 +# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +# In applying this licence, ECMWF does not waive the privileges and immunities +# granted to it by virtue of its status as an intergovernmental organisation +# nor does it submit to any jurisdiction. +#============================================================================ + +if [[ $# -ne 5 ]] ; then + echo "Error: wrong number of arguments = $# (must be 5)" + exit 1 +fi + +uiDefs=$1 +host=$2 +port=$3 +nodePath=$4 +serverDefs=$5 + +echo "Get defs via ecflow_client:" +echo "ecflow_client --host=${host} --port=${port} --migrate ${nodePath} > ${serverDefs}" +ecflow_client --host=${host} --port=${port} --migrate ${nodePath} > ${serverDefs} + +echo "Compare defs with meld:" +echo "meld ${uiDefs} ${serverDefs} &" +meld ${uiDefs} ${serverDefs} & + diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/AboutDialog.cpp ecflow-4.11.1/Viewer/ecflowUI/src/AboutDialog.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/AboutDialog.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/AboutDialog.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -10,11 +10,14 @@ #include "AboutDialog.hpp" +#include "DirectoryHandler.hpp" #include "Version.hpp" #include "WidgetNameProvider.hpp" #include +#include #include +#include AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent) { @@ -57,7 +60,7 @@ if(!ecfVersionTxt.isEmpty()) { logoTxt+="

ecflow version: " + ecfVersionTxt + "
"; - logoTxt+="Copyright 2009-2017 ECMWF

"; + logoTxt+="Copyright 2009-" + QString::number(QDate::currentDate().year()) + " ECMWF

"; } logoTxt+=""; @@ -75,4 +78,38 @@ licenseLabel_->setText(licenseText); WidgetNameProvider::nameChildren(this); + + //Paths + std::string pathText="Log file: "; + + if(DirectoryHandler::uiLogFileName().empty()) + pathText+= "not defined (log is written to stdout)
"; + else + pathText+=DirectoryHandler::uiLogFileName() + "
"; + + pathText+="UI event log file: " + DirectoryHandler::uiEventLogFileName() +"
"; + pathText+="Socket directory: " + DirectoryHandler::socketDir() +"
"; + + pathLabel_->setText(QString::fromStdString(pathText)); + + //Env vars + envTree_->setRootIsDecorated(false); + envTree_->setColumnCount(2); + QStringList envCols; + envCols << "Variable" << "Value"; + envTree_->setHeaderLabels(envCols); + + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + Q_FOREACH(QString envKey,env.keys()) + { + if(envKey.startsWith("ECFLOWUI_")) + { + QString envVal=env.value(envKey); + QTreeWidgetItem* item=new QTreeWidgetItem(envTree_); + item->setText(0,envKey); + item->setText(1,envVal); + } + } + + envTree_->resizeColumnToContents(0); } diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/AboutDialog.ui ecflow-4.11.1/Viewer/ecflowUI/src/AboutDialog.ui --- ecflow-4.10.0/Viewer/ecflowUI/src/AboutDialog.ui 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/AboutDialog.ui 2018-10-23 11:41:34.000000000 +0000 @@ -7,7 +7,7 @@ 0 0 538 - 251 + 312 @@ -109,7 +109,7 @@ - 0 + 2 @@ -148,8 +148,41 @@ 10 - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + Paths + + + + + + pathLabel_ + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + Environment + + + + + + + 1 + + diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/AbstractNodeModel.hpp ecflow-4.11.1/Viewer/ecflowUI/src/AbstractNodeModel.hpp --- ecflow-4.10.0/Viewer/ecflowUI/src/AbstractNodeModel.hpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/AbstractNodeModel.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -41,7 +41,7 @@ AttributeLineRole = Qt::UserRole+11, AbortedReasonRole = Qt::UserRole + 12, NodeTypeRole = Qt::UserRole + 13, NodeTypeForegroundRole = Qt::UserRole + 14, ServerPointerRole = Qt::UserRole + 15, SortRole = Qt::UserRole + 16, - NodePointerRole = Qt::UserRole + 17}; + NodePointerRole = Qt::UserRole + 17, VariableRole = Qt::UserRole + 18}; void dataIsAboutToChange(); virtual VInfo_ptr nodeInfo(const QModelIndex& index)=0; diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/AbstractNodeView.cpp ecflow-4.11.1/Viewer/ecflowUI/src/AbstractNodeView.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/AbstractNodeView.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/AbstractNodeView.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -44,9 +44,11 @@ expandConnectorLenght_(20), connectorColour_(Qt::black), drawConnector_(true), + autoExpandLeafNode_(true), indentation_(0), lastViewedItem_(0), - noSelectionOnMousePress_(false) + noSelectionOnMousePress_(false), + autoScroll_(true) { expandConnectorLenght_=itemGap_-2*connectorGap_; @@ -193,12 +195,22 @@ if(index.isValid()) { + bool autoScroll=autoScroll_; + autoScroll_=false; selectionModel_->setCurrentIndex(index, QItemSelectionModel::NoUpdate); + autoScroll_=autoScroll; QPoint p1=pressedRefPosition; QRect rect(p1,QSize(pos.x()-p1.x(),pos.y()-p1.y())); #ifdef _UI_QABSTRACTNODEVIEW_DEBUG UiLog().dbg() << " rect=" << rect << " p1=" << p1 << " p2=" << pos ; #endif +#if 0 + if (command.testFlag(QItemSelectionModel::Toggle)) + { + command &= ~QItemSelectionModel::Toggle; + command |= selectionModel_->isSelected(index) ? QItemSelectionModel::Deselect : QItemSelectionModel::Select; + } +#endif setSelection(rect, command); } else @@ -689,6 +701,20 @@ storeExpanded(idx); viewItems_[item].expanded = true; + if(autoExpandLeafNode_) + { + int count=model_->rowCount(idx); + for(int i=0; i < count; i++) + { + QModelIndex chIdx=model_->index(i,0,idx); + if(model_->isFlatNode(chIdx)) + { + if(!isIndexExpanded(chIdx)) + storeExpanded(chIdx); + } + } + } + //The total number items to be inserted int total=0; totalNumOfExpandedChildren(idx,total); @@ -1063,7 +1089,29 @@ for (int i = 0; i < rangeStack.count(); ++i) selection.append(rangeStack.at(i)); +#if 0 + UiLog().dbg() << "before"; + Q_FOREACH(QModelIndex idx,selectionModel_->selectedIndexes()) + { + UiLog().dbg() << " " << idx.data().toString(); + } + + UiLog().dbg() << "selection"; + Q_FOREACH(QModelIndex idx,selection.indexes()) + { + UiLog().dbg() << " " << idx.data().toString(); + } +#endif + selectionModel_->select(selection, command); + +#if 0 + UiLog().dbg() << "after"; + Q_FOREACH(QModelIndex idx,selectionModel_->selectedIndexes()) + { + UiLog().dbg() << " " << idx.data().toString(); + } +#endif } @@ -1256,7 +1304,10 @@ if(current.isValid()) { - scrollTo(current); + if(autoScroll_) + { + scrollTo(current); + } update(current); } } diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/AbstractNodeView.hpp ecflow-4.11.1/Viewer/ecflowUI/src/AbstractNodeView.hpp --- ecflow-4.10.0/Viewer/ecflowUI/src/AbstractNodeView.hpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/AbstractNodeView.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -155,6 +155,7 @@ void setExpectedBg(QColor c) {expectedBg_=c;} void setConnectorColour(QColor c) {connectorColour_=c;} void setDrawConnector(bool b) {drawConnector_=b;} + void setAutoExpandLeafNode(bool b) {autoExpandLeafNode_=b;} void insertViewItems(int pos, int count, const TreeNodeViewItem &viewItem); void removeViewItems(int pos, int count); @@ -187,6 +188,7 @@ QColor connectorColour_; bool drawConnector_; int indentation_; + bool autoExpandLeafNode_; private: void expand(int item); @@ -197,7 +199,8 @@ QPoint pressedPosition_; QPersistentModelIndex pressedIndex_; QPersistentModelIndex pressedRefIndex_; - bool noSelectionOnMousePress_; + bool noSelectionOnMousePress_; + bool autoScroll_; QBasicTimer delayedWidth_; inline bool storeExpanded(const QPersistentModelIndex &idx) diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/ActionHandler.cpp ecflow-4.11.1/Viewer/ecflowUI/src/ActionHandler.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/ActionHandler.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/ActionHandler.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -37,6 +37,8 @@ #include "UserMessage.hpp" #include "VConfig.hpp" #include "VNodeMover.hpp" +#include "VNodeStateDiag.hpp" +#include "VReportMaker.hpp" #define _UI_ACTIONHANDLER_DEBUG @@ -141,6 +143,28 @@ #endif } + else if(item->command() == "create_jsd_ticket") + { + if(filteredNodes.size() == 1) + { + if(filteredNodes[0] && filteredNodes[0]->node()) + { + VReportMaker::sendReport(filteredNodes[0]); + } + } + } + + else if(item->command() == "check_ui_node_state") + { + if(filteredNodes.size() == 1) + { + if(filteredNodes[0] && filteredNodes[0]->node()) + { + VNodeStateDiag diag(filteredNodes[0]); + } + } + } + else if(item->command() == "mark_for_move") { if(filteredNodes.size() > 1) diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/AddModelColumnDialog.cpp ecflow-4.11.1/Viewer/ecflowUI/src/AddModelColumnDialog.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/AddModelColumnDialog.cpp 1970-01-01 00:00:00.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/AddModelColumnDialog.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -0,0 +1,105 @@ +//============================================================================ +// Copyright 2009-2018 ECMWF. +// This software is licensed under the terms of the Apache Licence version 2.0 +// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +// In applying this licence, ECMWF does not waive the privileges and immunities +// granted to it by virtue of its status as an intergovernmental organisation +// nor does it submit to any jurisdiction. +//============================================================================ + +#include "AddModelColumnDialog.hpp" +#include "ModelColumn.hpp" + +#include +#include + +#include "ui_AddModelColumnDialog.h" + +AddModelColumnDialog::AddModelColumnDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::AddModelColumnDialog) +{ + ui->setupUi(this); +} + +AddModelColumnDialog::~AddModelColumnDialog() +{ + delete ui; +} + +void AddModelColumnDialog::init(ModelColumn* mc,const std::set& vars,QString defaultText) +{ + modelColumn_=mc; + QStringList varLst; + for(std::set::const_iterator it=vars.begin(); + it != vars.end(); ++it) + { + int idx=-1; + bool ok=true; + QString n=QString::fromStdString(*it); + if((idx=modelColumn_->indexOf(n)) != -1) + ok=!modelColumn_->isExtra(idx); + + if(ok) + varLst << n; + } + + QCompleter *c=new QCompleter(varLst,this); + c->setCaseSensitivity(Qt::CaseInsensitive); + ui->variableLe->setCompleter(c); + ui->variableLe->setText(defaultText); +} + +void AddModelColumnDialog::accept() +{ + QString name=ui->variableLe->text(); + if(modelColumn_->indexOf(name) == -1) + { + modelColumn_->addExtraItem(name,name); + } + else + { + QMessageBox::warning(this,"Column already defined",tr("Column \'") + name + + tr("\' is already added to table view. Please choose another variable!"), + QMessageBox::Ok,QMessageBox::NoButton); + return; + } + + QDialog::accept(); +} + +ChangeModelColumnDialog::ChangeModelColumnDialog(QWidget *parent) : + AddModelColumnDialog(parent) +{ + setWindowTitle(tr("Change column in table view")); +} + + +void ChangeModelColumnDialog::setColumn(QString cname) +{ + columnName_=cname; + ui->variableLe->setText(columnName_); + setWindowTitle(tr("Change column ") + columnName_ + tr(" in table view")); +} + +void ChangeModelColumnDialog::accept() +{ + QString name=ui->variableLe->text(); + if(modelColumn_->indexOf(name) == -1) + { + int colIdx=modelColumn_->indexOf(columnName_); + if(colIdx != -1) + { + modelColumn_->changeExtraItem(colIdx,name,name); + } + } + else + { + QMessageBox::warning(this,"Column already defined",tr("Column ") + name + + tr(" is already added to table view. Please choose another variable!"), + QMessageBox::Ok,QMessageBox::NoButton); + return; + } + + QDialog::accept(); +} diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/AddModelColumnDialog.hpp ecflow-4.11.1/Viewer/ecflowUI/src/AddModelColumnDialog.hpp --- ecflow-4.10.0/Viewer/ecflowUI/src/AddModelColumnDialog.hpp 1970-01-01 00:00:00.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/AddModelColumnDialog.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -0,0 +1,59 @@ +//============================================================================ +// Copyright 2009-2018 ECMWF. +// This software is licensed under the terms of the Apache Licence version 2.0 +// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +// In applying this licence, ECMWF does not waive the privileges and immunities +// granted to it by virtue of its status as an intergovernmental organisation +// nor does it submit to any jurisdiction. +//============================================================================ + +#ifndef ADDMODELCOLUMNDIALOG_HPP +#define ADDMODELCOLUMNDIALOG_HPP + +#include +#include +#include +#include + +class ModelColumn; + +namespace Ui { +class AddModelColumnDialog; +} + +class AddModelColumnDialog : public QDialog +{ + Q_OBJECT + +public: + explicit AddModelColumnDialog(QWidget *parent = 0); + virtual ~AddModelColumnDialog(); + + void init(ModelColumn* mc,const std::set&,QString defaultText = QString("")); + +public Q_SLOTS: + void accept(); + +protected: + Ui::AddModelColumnDialog *ui; + ModelColumn* modelColumn_; +}; + +class ChangeModelColumnDialog : public AddModelColumnDialog +{ + Q_OBJECT + +public: + explicit ChangeModelColumnDialog(QWidget *parent = 0); + + void setColumn(QString); + +public Q_SLOTS: + void accept(); + +protected: + QString columnName_; +}; + + +#endif // ADDMODELCOLUMNDIALOG_HPP diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/AddModelColumnDialog.ui ecflow-4.11.1/Viewer/ecflowUI/src/AddModelColumnDialog.ui --- ecflow-4.10.0/Viewer/ecflowUI/src/AddModelColumnDialog.ui 1970-01-01 00:00:00.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/AddModelColumnDialog.ui 2018-10-23 11:41:34.000000000 +0000 @@ -0,0 +1,78 @@ + + + AddModelColumnDialog + + + + 0 + 0 + 402 + 89 + + + + Add new column to table view + + + + + + + + Variable name: + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + AddModelColumnDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + AddModelColumnDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/CMakeLists.txt ecflow-4.11.1/Viewer/ecflowUI/src/CMakeLists.txt --- ecflow-4.10.0/Viewer/ecflowUI/src/CMakeLists.txt 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/CMakeLists.txt 2018-10-23 11:41:34.000000000 +0000 @@ -7,6 +7,7 @@ AbstractSearchLine.cpp AbstractTextEditSearchInterface.cpp ActionHandler.cpp + AddModelColumnDialog.cpp Animation.cpp AstCollateVNodesVisitor.cpp AttributeEditor.cpp @@ -37,6 +38,7 @@ DashboardDock.cpp DashboardTitle.cpp DashboardWidget.cpp + DiagData.cpp EditItemWidget.cpp EditProvider.cpp EditorInfoLabel.cpp @@ -192,13 +194,16 @@ VNode.cpp VNodeList.cpp VNodeMover.cpp + VNodeStateDiag.cpp VNState.cpp VParam.cpp VProperty.cpp VRepeatAttr.cpp VReply.cpp + VReportMaker.cpp VServerSettings.cpp VSettings.cpp + VSettingsLoader.cpp VSState.cpp VTask.cpp VTaskNode.cpp @@ -241,6 +246,7 @@ AbstractNodeView.hpp AbstractSearchLine.hpp ActionHandler.hpp + AddModelColumnDialog.hpp Animation.hpp AttributeEditor.hpp CaseSensitiveButton.hpp @@ -278,6 +284,7 @@ MenuConfigDialog.hpp MessageItemWidget.hpp MeterEditor.hpp + ModelColumn.hpp NodeFilterDialog.hpp NodePanel.hpp NodePathWidget.hpp @@ -361,6 +368,7 @@ set(viewer_wrap_ui_files AboutDialog.ui + AddModelColumnDialog.ui AttributeEditorDialog.ui ChangeNotifyDialog.ui ChangeNotifyDialogWidget.ui diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/CompactView.cpp ecflow-4.11.1/Viewer/ecflowUI/src/CompactView.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/CompactView.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/CompactView.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -521,7 +521,7 @@ painter->setPen(connectorColour_); - //If not a top level item (e.i. not a server) + //If not a top level item (i.e. not a server) if(item->parentItem >=0) { //The parent item. It is always a node. diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/DiagData.cpp ecflow-4.11.1/Viewer/ecflowUI/src/DiagData.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/DiagData.cpp 1970-01-01 00:00:00.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/DiagData.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -0,0 +1,247 @@ +//============================================================================ +// Copyright 2009-2018 ECMWF. +// This software is licensed under the terms of the Apache Licence version 2.0 +// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +// In applying this licence, ECMWF does not waive the privileges and immunities +// granted to it by virtue of its status as an intergovernmental organisation +// nor does it submit to any jurisdiction. +//============================================================================ + +#include "DiagData.hpp" + +#include "File_r.hpp" +#include "File.hpp" +#include "ModelColumn.hpp" +#include "NodePath.hpp" +#include "ServerHandler.hpp" +#include "Str.hpp" +#include "UiLog.hpp" +#include "UIDebug.hpp" +#include "VNode.hpp" +#include "VItemPathParser.hpp" + +#include +#include + +DiagData* DiagData::instance_=NULL; + +DiagDataServerItem::DiagDataServerItem(const std::string& host,const std::string& port, size_t colNum) : + host_(host), port_(port) +{ + for(size_t i=0; i < colNum; i++) + data_.push_back(std::vector()); +} + +const std::string& DiagDataServerItem::dataAt(int row,int column) const +{ + return data_[column][row]; + //static std::string emptyStr; + //return emptyStr; +} + +int DiagDataServerItem::findRowByPath(const std::string& path) const +{ + for(size_t i=0; i < pathData_.size(); i++) + if(pathData_[i] == path) + return i; + + return -1; +} + +bool DiagDataServerItem::checkSizes() const +{ + size_t num=pathData_.size(); + for(size_t i=0; i < data_.size(); i++) + { + if(data_[i].size() != num) + return false; + } + return true; +} + +DiagData::DiagData() +{ +} + +DiagData* DiagData::instance() +{ + if(!instance_) + instance_=new DiagData(); + + return instance_; +} + +const std::string& DiagData::columnName(int i) const +{ + if(i >=0 && i < static_cast(columnNames_.size())) + return columnNames_[i]; + + static std::string emptyStr; + return emptyStr; +} + +const std::string& DiagData::dataAt(VNode* vn,int column) const +{ + static std::string emptyStr; + if(!vn) + return emptyStr; + + if(ServerHandler* sh=vn->server()) + { + if(DiagDataServerItem *d=findServerData(sh->host(),sh->port())) + { + int row=d->findRowByPath(vn->absNodePath()); + if(row > -1) + return d->dataAt(row,column); + } + } + + return emptyStr; +} + +DiagDataServerItem* DiagData::findServerData(const std::string& host,const std::string& port) const +{ + if(host.empty() || port.empty()) + return NULL; + + for(size_t i=0; i < serverData_.size(); i++) + { + if(serverData_[i]->host_ == host && serverData_[i]->port_ == port) + return serverData_[i]; + } + + return NULL; +} + + +void DiagData::clear() +{ + fileName_.clear(); + columnNames_.clear(); + for(size_t i=0; i < serverData_.size(); i++) + { + delete serverData_[i]; + } + serverData_.clear(); +} + +void DiagData::load() +{ + if(const char *df=getenv("ECFLOWUI_DIAG_FILE")) + loadFile(std::string(df)); +} + +void DiagData::loadFile(const std::string& fileName) +{ + clear(); + + fileName_=fileName; + + /// The log file can be massive > 50Mb + ecf::File_r diag_file(fileName_); + if( !diag_file.ok() ) + { + UiLog().warn() << "DiagData::loadFile: Could not open diagnostics file " + fileName; + return; + } + + std::string line; + + //The first line is the header + diag_file.getline(line); // default delimiter is /n + + //No header, no diag data can be read + if(line.empty()) + return; + + QString headerLine=QString::fromStdString(line); + if(headerLine.startsWith("#")) + headerLine=headerLine.mid(1); + + QStringList headerLst=headerLine.split(","); + int pathColumnIndex=-1; + for(int i=0; i < headerLst.count(); i++) + { + if(headerLst[i].compare("path",Qt::CaseInsensitive) == 0) + pathColumnIndex=i; + else + columnNames_.push_back(headerLst[i].toStdString()); + } + + if(pathColumnIndex == -1) + { + UiLog().warn() << "DiagData::loadFile: could not find node path column in file. Diagnostics cannot be loaded!"; + return; + } + + while ( diag_file.good() ) + { + diag_file.getline(line); // default delimiter is /n + + if(line.size() <= 1) + continue; + + if(line[0] == '#') + line=line.substr(1); + + //split by comma + QStringList lst=QString::fromStdString(line).split(","); + + //When number of items does not match expected number we skip the line + if(lst.count() != static_cast(columnNames_.size()) + 1) + continue; + + std::string path=lst[pathColumnIndex].toStdString(); + std::string host, port; + DiagDataServerItem* data=NULL; + VItemPathParser parser(path,VItemPathParser::DiagFormat); + if(parser.itemType() != VItemPathParser::NoType) + { + data=findServerData(parser.host(),parser.port()); + if(!data) + { + data=new DiagDataServerItem(parser.host(),parser.port(),columnNames_.size()); + serverData_.push_back(data); + } + } + else + { + continue; + } + + data->pathData_.push_back(parser.node()); + assert(data->data_.size() == columnNames_.size()); + + for(int i=0; i < lst.count(); i++) + { + QString val=lst[i]; +#if 0 + QStringList vals=lst[i].split(":"); + QString val=lst[i]; + if(vals.count() == 2) + columnData_[i].push_back(vals[1].toStdString()); + else + columnData_[i].push_back(lst[i].toStdString()); +#endif + + int idx=i; + if(idx > pathColumnIndex) + idx--; + + + if(i != pathColumnIndex) + data->data_[idx].push_back(val.toStdString()); + } + + } + + updateTableModelColumn(); +} + +void DiagData::updateTableModelColumn() +{ + if(ModelColumn* mc=ModelColumn::def("table_columns")) + { + mc->setDiagData(this); + } +} diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/DiagData.hpp ecflow-4.11.1/Viewer/ecflowUI/src/DiagData.hpp --- ecflow-4.10.0/Viewer/ecflowUI/src/DiagData.hpp 1970-01-01 00:00:00.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/DiagData.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -0,0 +1,59 @@ +//============================================================================ +// Copyright 2009-2018 ECMWF. +// This software is licensed under the terms of the Apache Licence version 2.0 +// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +// In applying this licence, ECMWF does not waive the privileges and immunities +// granted to it by virtue of its status as an intergovernmental organisation +// nor does it submit to any jurisdiction. +//============================================================================ + +#ifndef DIAGDATA_HPP +#define DIAGDATA_HPP + +#include +#include + +class VNode; +class DiagData; + +class DiagDataServerItem +{ + friend class DiagData; + +public: + DiagDataServerItem(const std::string& host,const std::string& port,size_t); + const std::string& dataAt(int row,int column) const; + int findRowByPath(const std::string& path) const; + +protected: + bool checkSizes() const; + std::string host_; + std::string port_; + std::vector pathData_; + std::vector > data_; +}; + +class DiagData +{ +public: + static DiagData* instance(); + + void load(); + void loadFile(const std::string&); + int count() const {return static_cast(columnNames_.size());} + const std::string& columnName(int i) const; + const std::string& dataAt(VNode*,int column) const; + +protected: + DiagData(); + void clear(); + void updateTableModelColumn(); + DiagDataServerItem* findServerData(const std::string& host,const std::string& port) const; + + static DiagData* instance_; + std::string fileName_; + std::vector columnNames_; + std::vector serverData_; +}; + +#endif // DIAGDATA_HPP diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/HistoryItemWidget.cpp ecflow-4.11.1/Viewer/ecflowUI/src/HistoryItemWidget.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/HistoryItemWidget.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/HistoryItemWidget.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -41,7 +41,8 @@ //make the horizontal scrollbar work treeView_->header()->setStretchLastSection(false); -#ifdef EFLOW_QT5 + +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) treeView_->header()->setSectionResizeMode(QHeaderView::ResizeToContents); #endif diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/ManualItemWidget.cpp ecflow-4.11.1/Viewer/ecflowUI/src/ManualItemWidget.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/ManualItemWidget.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/ManualItemWidget.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -104,6 +104,10 @@ { QString s=QString::fromStdString(reply->errorText()); messageLabel_->showError(s); + textEdit_->setPlainText( +"# You can create a man page with " +"a file .man located in or as " +"/.man"); reloadTb_->setEnabled(true); } diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/MessageItemWidget.cpp ecflow-4.11.1/Viewer/ecflowUI/src/MessageItemWidget.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/MessageItemWidget.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/MessageItemWidget.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -40,7 +40,7 @@ //make the horizontal scrollbar work treeView_->header()->setStretchLastSection(false); -#ifdef EFLOW_QT5 +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) treeView_->header()->setSectionResizeMode(QHeaderView::ResizeToContents); #endif diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/ModelColumn.cpp ecflow-4.11.1/Viewer/ecflowUI/src/ModelColumn.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/ModelColumn.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/ModelColumn.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -1,5 +1,5 @@ //============================================================================ -// Copyright 2009-2017 ECMWF. +// Copyright 2009-2018 ECMWF. // This software is licensed under the terms of the Apache Licence version 2.0 // which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. // In applying this licence, ECMWF does not waive the privileges and immunities @@ -13,12 +13,15 @@ #include +#include "DiagData.hpp" +#include "VConfig.hpp" #include "VConfigLoader.hpp" #include "VProperty.hpp" +#include "VSettingsLoader.hpp" static std::map defs; -ModelColumn::ModelColumn(const std::string& id) : id_(id) +ModelColumn::ModelColumn(const std::string& id) : id_(id), diagStart_(-1), diagEnd_(-1) { defs[id_]=this; } @@ -31,38 +34,254 @@ return NULL; } +ModelColumn* ModelColumn::tableModelColumn() +{ + return ModelColumn::def("table_columns"); +} + +//int ModelColumn::indexOf(const std::string& id) const +//{ +// return indexOf(QString::fromStdString(id)); +//} + +int ModelColumn::indexOf(QString id) const +{ + for(int i=0; i< items_.count(); i++) + { + if(items_.at(i)->id_ == id) + return i; + } + return -1; +} + +void ModelColumn::loadItem(VProperty *p) +{ + ModelColumnItem* obj=new ModelColumnItem(p->strName()); + obj->label_=p->param("label"); + obj->tooltip_=p->param("tooltip"); + obj->icon_=p->param("icon"); + obj->index_=items_.count(); + items_ << obj; +} + +void ModelColumn::loadExtraItem(QString name,QString label) +{ + ModelColumnItem* obj=new ModelColumnItem(name.toStdString(),true); + obj->label_=label; + obj->tooltip_=obj->label_; + //obj->icon_=p->param("icon"); + obj->index_=items_.count(); + obj->editable_=true; + + if(hasDiag()) + { + items_.insert(diagStart_,obj); + diagStart_++; + diagEnd_++; + } + else + { + items_ << obj; + } +} + +void ModelColumn::loadDiagItem(QString name,QString label) +{ + ModelColumnItem* obj=new ModelColumnItem(name.toStdString(),true); + obj->label_=label; + obj->tooltip_=obj->label_; + //obj->icon_=p->param("icon"); + obj->index_=items_.count(); + obj->editable_=false; + items_ << obj; +} + +void ModelColumn::addExtraItem(QString name,QString label) +{ + if(indexOf(name) != -1) + return; + + //Editable extra items are always inserted in front of the diag items + int pos=items_.count(); + if(hasDiag()) + { + pos=diagStart_; + Q_ASSERT(pos >=0); + } + + Q_EMIT addItemsBegin(pos,pos); + //Q_EMIT appendItemBegin(); + loadExtraItem(name,label); + //Q_EMIT appendItemEnd(); + Q_EMIT addItemsEnd(pos,pos); + + save(); +} + +void ModelColumn::changeExtraItem(int idx, QString name,QString label) +{ + if(indexOf(name) != -1) + return; + + if(!isExtra(idx) || !isEditable(idx)) + return; + + Q_EMIT changeItemBegin(idx); + + items_[idx]->id_=name; + items_[idx]->label_=label; + + Q_EMIT changeItemEnd(idx); -int ModelColumn::indexOf(const std::string& id) const + save(); +} + +void ModelColumn::removeExtraItem(QString name) +{ + int idx=indexOf(name); + if(idx != -1 && + items_[idx]->isExtra() && items_[idx]->isEditable()) + { + Q_EMIT removeItemsBegin(idx,idx); + + ModelColumnItem* obj=items_[idx]; + items_.removeAt(idx); + delete obj; + + if(hasDiag()) + { + diagStart_--; + diagEnd_--; + Q_ASSERT(diagStart_ >= 0); + } + + Q_EMIT removeItemsEnd(idx,idx); + + save(); + } +} + +bool ModelColumn::isSameDiag(DiagData *diag) const +{ + if(diagStart_ >=0 && diagEnd_ >=0 && diag->count() == diagEnd_-diagStart_+1) + { + for(int i=diagStart_; i <= diagEnd_; i++) + { + if(items_[i]->id_ != + QString::fromStdString(diag->columnName(i-diagStart_))) + { + return false; + } + } + return true; + } + return false; +} + +void ModelColumn::setDiagData(DiagData *diag) +{ + if(isSameDiag(diag)) + return; + + //Remove the current diag items + if(diagStart_ >=0 && diagEnd_ >=0) + { + Q_EMIT removeItemsBegin(diagStart_,diagEnd_); + for(int i=diagStart_; i <= diagEnd_; i++) + { + ModelColumnItem* obj=items_[diagStart_]; + items_.removeAt(diagStart_); + delete obj; + } + Q_EMIT removeItemsEnd(diagStart_,diagEnd_); + diagStart_=-1; + diagEnd_=-1; + } + + //Add the current diag items to the back of the items + if(diag->count() <=0) + return; + + diagStart_=items_.count(); + diagEnd_=items_.count()+diag->count()-1; + Q_ASSERT(diagStart_ >= 0); + Q_ASSERT(diagStart_ <= diagEnd_); + Q_EMIT addItemsBegin(diagStart_,diagEnd_); + + for(int i=0; i < diag->count(); i++) + { + QString n=QString::fromStdString(diag->columnName(i)); + loadDiagItem(n,n);// these are not editable items!!! + } + Q_EMIT addItemsEnd(diagStart_,diagEnd_); +} + +void ModelColumn::save() { - QString idStr=QString::fromStdString(id); - for(int i=0; i< items_.count(); i++) - { - if(items_.at(i)->id_ == idStr) - return i; - } - return -1; + if(!configPath_.empty()) + { + if(VProperty* prop=VConfig::instance()->find(configPath_)) + { + QStringList lst; + for(int i=0; i < items_.count(); i++) + { + if(items_[i]->isExtra() && items_[i]->isEditable()) + lst << items_[i]->id_; + } + if(lst.isEmpty()) + prop->setValue(prop->defaultValue()); + else + prop->setValue(lst.join("/")); + } + } } void ModelColumn::load(VProperty* group) { - ModelColumn* m=new ModelColumn(group->strName()); + Q_ASSERT(group); + ModelColumn* m=new ModelColumn(group->strName()); for(int i=0; i < group->children().size(); i++) { - VProperty *p=group->children().at(i); + VProperty *p=group->children().at(i); + m->loadItem(p); + } - ModelColumnItem* obj=new ModelColumnItem(p->strName()); - obj->label_=p->param("label"); - obj->tooltip_=p->param("tooltip"); - obj->icon_=p->param("icon"); - obj->index_=i; + //Define extra config property + m->configPath_=group->param("__config__").toStdString(); +} - m->items_ << obj; +//Called via VSettingsLoader after the users settings are read +void ModelColumn::loadSettings() +{ + for(std::map::iterator it=defs.begin(); it != defs.end(); ++it) + { + it->second->loadUserSettings(); + } +} +//Load user defined settings +void ModelColumn::loadUserSettings() +{ + //Load extra config + if(!configPath_.empty()) + { + if(VProperty* p=VConfig::instance()->find(configPath_)) + { + QString pval=p->valueAsString(); + if(!pval.isEmpty() && pval != "__none__") + { + Q_FOREACH(QString s,pval.split("/")) + { + loadExtraItem(s,s); + } + } + } } } -ModelColumnItem::ModelColumnItem(const std::string& id) : index_(-1) +ModelColumnItem::ModelColumnItem(const std::string& id, bool extra) : + index_(-1), extra_(extra), editable_(extra) { id_=QString::fromStdString(id); } @@ -72,3 +291,5 @@ static SimpleLoader loaderZombie("zombie_columns"); static SimpleLoader loaderTriggerGraph("trigger_graph_columns"); static SimpleLoader loaderOutput("output_columns"); + +static SimpleSettingsLoader settingsLoader; diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/ModelColumn.hpp ecflow-4.11.1/Viewer/ecflowUI/src/ModelColumn.hpp --- ecflow-4.10.0/Viewer/ecflowUI/src/ModelColumn.hpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/ModelColumn.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -1,5 +1,5 @@ //============================================================================ -// Copyright 2009-2017 ECMWF. +// Copyright 2009-2018 ECMWF. // This software is licensed under the terms of the Apache Licence version 2.0 // which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. // In applying this licence, ECMWF does not waive the privileges and immunities @@ -11,18 +11,21 @@ #define MODELCOLUMN_H class VProperty; +class DiagData; #include #include +#include #include - class ModelColumnItem { friend class ModelColumn; public: - explicit ModelColumnItem(const std::string& id); + explicit ModelColumnItem(const std::string& id,bool extra=false); + bool isExtra() const {return extra_;} + bool isEditable() const {return editable_;} protected: QString label_; @@ -30,29 +33,65 @@ int index_; QString icon_; QString tooltip_; + bool extra_; + bool editable_; }; - -class ModelColumn +class ModelColumn : public QObject { + Q_OBJECT public: explicit ModelColumn(const std::string& id); int count() const {return items_.size();} - int indexOf(const std::string&) const; + int indexOf(QString) const; QString id(int i) const {assert(i>=0 && i < count()); return items_.at(i)->id_;} QString label(int i) const {assert(i>=0 && i < count()); return items_.at(i)->label_;} QString tooltip(int i) const {assert(i>=0 && i < count()); return items_.at(i)->tooltip_;} + bool isExtra(int i) const {assert(i>=0 && i < count()); return items_.at(i)->isExtra();} + bool isEditable(int i) const {assert(i>=0 && i < count()); return items_.at(i)->isEditable();} + bool hasDiag() const {return diagStart_ >=0 && diagEnd_ > diagStart_;} + int diagStartIndex() const {return diagStart_;} + int diagEndIndex() const {return diagEnd_;} + + void addExtraItem(QString,QString); + void changeExtraItem(int,QString,QString); + void removeExtraItem(QString); + + void setDiagData(DiagData*); static ModelColumn* def(const std::string& id); + static ModelColumn* tableModelColumn(); //Called from VConfigLoader static void load(VProperty* group); + //Called from VSettingsLoader + static void loadSettings(); + +Q_SIGNALS: + void appendItemBegin(); + void appendItemEnd(); + void addItemsBegin(int,int); + void addItemsEnd(int,int); + void changeItemBegin(int); + void changeItemEnd(int); + void removeItemsBegin(int,int); + void removeItemsEnd(int,int); + protected: + void save(); + void loadItem(VProperty*); + void loadExtraItem(QString,QString); + void loadDiagItem(QString,QString); + void loadUserSettings(); + bool isSameDiag(DiagData *diag) const; + std::string id_; - QList items_; + QList items_; + std::string configPath_; + int diagStart_; + int diagEnd_; }; - #endif diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/NodeExpression.cpp ecflow-4.11.1/Viewer/ecflowUI/src/NodeExpression.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/NodeExpression.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/NodeExpression.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -101,7 +101,15 @@ bool NodeExpressionParser::isMenuMode(const std::string &str) const { - if (str == "oper" || str == "admin") + if (str == "oper" || str == "admin" || str == "defStatusMenuModeControl") + return true; + + return false; +} + +bool NodeExpressionParser::isEnvVar(const std::string &str) const +{ + if (str == "ECFLOWUI_ECMWF_OPERATOR_MODE" || str == "ECFLOWUI_DEVELOP_MODE") return true; return false; @@ -301,7 +309,7 @@ updatedOperands = true; } - // node mneu mode + // node menu mode else if (isMenuMode(*i_)) { NodeMenuModeCondition *userCond = new NodeMenuModeCondition(QString::fromStdString(*i_)); @@ -353,6 +361,15 @@ updatedOperands = true; } + // env var + else if (isEnvVar(*i_)) + { + EnvVarCondition *envCond = new EnvVarCondition(QString::fromStdString(*i_)); + operandStack.push_back(envCond); + result = envCond; + updatedOperands = true; + } + else if (isWhatToSearchIn(*i_, attr)) { WhatToSearchInOperand *searchCond = new WhatToSearchInOperand(*i_, attr); @@ -672,7 +689,7 @@ //========================================================================= // -// UserMenuModeCondition +// NodeMenuModeCondition // //========================================================================= @@ -680,11 +697,46 @@ { if(item) { - return (item->nodeMenuMode() == menuModeName_); + if(menuModeName_ == "defStatusMenuModeControl") + { + Q_FOREACH(QString s,item->defStatusNodeMenuMode().split("/")) + { + if(item->nodeMenuMode() == s) + return true; + } + + } + else + { + return (item->nodeMenuMode() == menuModeName_); + } } return false; } +//========================================================================= +// +// NodeMenuModeCondition +// +//========================================================================= + +bool EnvVarCondition::execute(VItem* item) +{ + if(item) + { + if(defined_ == -1) + { + defined_=0; + if(const char* ch=getenv(envVarName_.toStdString().c_str())) + { + defined_=(strcmp(ch,"1") == 0)?1:0; + } + } + + return defined_ == 1; + } + return false; +} //========================================================================= // diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/NodeExpression.hpp ecflow-4.11.1/Viewer/ecflowUI/src/NodeExpression.hpp --- ecflow-4.10.0/Viewer/ecflowUI/src/NodeExpression.hpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/NodeExpression.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -50,6 +50,7 @@ NodeExpressionParser(); bool isMenuMode(const std::string &str) const; + bool isEnvVar(const std::string &str) const; bool isNodeHasAttribute(const std::string &str) const; bool isNodeFlag(const std::string &str) const; bool isWhatToSearchIn(const std::string &str, bool &isAttribute) const; @@ -313,6 +314,27 @@ // ----------------------------------------------------------------- // -------------------- +// Envvar condition +// -------------------- + +class EnvVarCondition : public BaseNodeCondition +{ +public: + explicit EnvVarCondition(QString envVarName) : envVarName_(envVarName), defined_(-1) {} + ~EnvVarCondition() {} + + bool execute(VItem*); + std::string print() {return envVarName_.toStdString();} + +private: + QString envVarName_; + int defined_; +}; + +// ----------------------------------------------------------------- + + +// -------------------- // UI state condition // -------------------- diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/OutputBrowser.cpp ecflow-4.11.1/Viewer/ecflowUI/src/OutputBrowser.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/OutputBrowser.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/OutputBrowser.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -456,7 +456,8 @@ if(stacked_->currentIndex() == HtmlIndex) return; - assert(file_); + if(!file_) + return; if(oriFile_) file_=oriFile_; diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/OutputItemWidget.cpp ecflow-4.11.1/Viewer/ecflowUI/src/OutputItemWidget.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/OutputItemWidget.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/OutputItemWidget.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -88,7 +88,9 @@ dirView_->setUniformRowHeights(true); dirView_->setAlternatingRowColors(true); dirView_->setSortingEnabled(true); - dirView_->sortByColumn(3, Qt::DescendingOrder); // sort with latest files first (0-based) + + //Sort by column "modifiied (ago)", latest files first + dirView_->sortByColumn(3, Qt::AscendingOrder); //The models dirModel_=new OutputModel(this); diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/OutputModel.cpp ecflow-4.11.1/Viewer/ecflowUI/src/OutputModel.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/OutputModel.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/OutputModel.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -94,25 +94,25 @@ if(!item || !dir) return QVariant(); - if(role == Qt::DisplayRole) - { - switch(index.column()) - { - case 0: - return QString::fromStdString(item->name_); - case 1: - return QString::fromStdString(dir->path()); - case 2: - return formatSize(item->size_); - case 3: - return formatAgo(item->mtime_); - case 4: - return formatDate(item->mtime_); - case 5: - return QString::fromStdString(dir->fetchModeStr()); - default: - break; - } + if(role == Qt::DisplayRole) + { + switch(index.column()) + { + case 0: + return QString::fromStdString(item->name_); + case 1: + return QString::fromStdString(dir->path()); + case 2: + return formatSize(item->size_); + case 3: + return formatAgo(item->mtime_); + case 4: + return formatDate(item->mtime_); + case 5: + return QString::fromStdString(dir->fetchModeStr()); + default: + break; + } } else if(role == Qt::ForegroundRole) { @@ -165,11 +165,11 @@ QVariant OutputModel::headerData( const int section, const Qt::Orientation orient , const int role ) const { - if ( orient != Qt::Horizontal || role != Qt::DisplayRole ) - return QAbstractItemModel::headerData( section, orient, role ); + if ( orient != Qt::Horizontal || role != Qt::DisplayRole ) + return QAbstractItemModel::headerData( section, orient, role ); - switch ( section ) - { + switch ( section ) + { case 0: return tr("Name"); case 1: return tr("Path"); case 2: return tr("Size"); @@ -177,7 +177,7 @@ case 4: return tr("Modified"); case 5: return tr("Source"); default: return QVariant(); - } + } return QVariant(); } diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/PropertyLine.cpp ecflow-4.11.1/Viewer/ecflowUI/src/PropertyLine.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/PropertyLine.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/PropertyLine.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -1,5 +1,5 @@ //============================================================================ -// Copyright 2009-2017 ECMWF. +// Copyright 2009-2018 ECMWF. // This software is licensed under the terms of the Apache Licence version 2.0 // which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. // In applying this licence, ECMWF does not waive the privileges and immunities @@ -27,6 +27,7 @@ #include "ComboMulti.hpp" #include "Sound.hpp" +#include "UiLog.hpp" #include @@ -213,7 +214,7 @@ if(enabled_) { - if(prop_->defaultValue() != currentValue()) + if(prop_->defaultValue() != currentValue()) defaultTb_->setEnabled(true); else defaultTb_->setEnabled(false); @@ -884,8 +885,8 @@ cb_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - connect(cb_,SIGNAL(currentIndexChanged(int)), - this,SLOT(slotCurrentChanged(int))); + connect(cb_,SIGNAL(selectionChanged()), + this,SLOT(slotSelectionChanged())); QStringList lst=prop_->param("values_label").split("/"); QStringList lstData=prop_->param("values").split("/"); @@ -937,12 +938,12 @@ QVariant ComboMultiPropertyLine::currentValue() { - QStringList lst=cb_->selection(); + QStringList lst=cb_->selectionData(); return lst.join("/"); } -void ComboMultiPropertyLine::slotCurrentChanged(int) +void ComboMultiPropertyLine::slotSelectionChanged() { PropertyLine::checkState(); valueChanged(); diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/PropertyLine.hpp ecflow-4.11.1/Viewer/ecflowUI/src/PropertyLine.hpp --- ecflow-4.10.0/Viewer/ecflowUI/src/PropertyLine.hpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/PropertyLine.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -1,5 +1,5 @@ //============================================================================ -// Copyright 2009-2017 ECMWF. +// Copyright 2009-2018 ECMWF. // This software is licensed under the terms of the Apache Licence version 2.0 // which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. // In applying this licence, ECMWF does not waive the privileges and immunities @@ -323,7 +323,7 @@ bool canExpand() const {return true;} public Q_SLOTS: - void slotCurrentChanged(int); + void slotSelectionChanged(); void slotReset(QVariant); protected: diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/ServerComThread.cpp ecflow-4.11.1/Viewer/ecflowUI/src/ServerComThread.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/ServerComThread.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/ServerComThread.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -316,16 +316,17 @@ //Detach the defs and the nodes from the observer detach(defsAccess.defs()); - //We drop all the handles belonging to the current user to have a proper clean-up! - //Other running instances of ecflow_ui under the same user will properly react - //to these changes and reset their handles! So it is a safe operation!!! - try + //We drop the handle belonging to the current client! + if(ci_->client_handle() > 0) { - ci_->ch_drop_user(); - } - catch (std::exception &e) - { - UiLog(serverName_).warn() << " cannot drop handle for current user: " << e.what(); + try + { + ci_->ch1_drop(); + } + catch (std::exception &e) + { + UiLog(serverName_).warn() << " cannot drop handle for client: " << e.what(); + } } if(hasSuiteFilter_) diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/ServerComThread.hpp ecflow-4.11.1/Viewer/ecflowUI/src/ServerComThread.hpp --- ecflow-4.10.0/Viewer/ecflowUI/src/ServerComThread.hpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/ServerComThread.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -87,6 +87,7 @@ std::vector filteredSuites_; bool autoAddNewSuites_; int maxLineNum_; + bool initialResetDone_; }; #endif diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/ServerHandler.cpp ecflow-4.11.1/Viewer/ecflowUI/src/ServerHandler.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/ServerHandler.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/ServerHandler.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -1467,6 +1467,11 @@ return conf_->stringValue(VServerSettings::NodeMenuMode); } +QString ServerHandler::defStatusNodeMenuMode() const +{ + return conf_->stringValue(VServerSettings::NodeMenuModeForDefStatus); +} + void ServerHandler::confChanged(VServerSettings::Param par,VProperty* prop) { switch(par) @@ -1558,6 +1563,39 @@ conf_->loadSettings(); } +void ServerHandler::writeDefs(const std::string& fileName) +{ + comQueue_->suspend(true); + ServerDefsAccess defsAccess(this); // will reliquish its resources on destruction + defs_ptr defs = defsAccess.defs(); + if(defs) + { + defs->save_as_filename(fileName,PrintStyle::MIGRATE); + } + comQueue_->start(); +} + +void ServerHandler::writeDefs(VInfo_ptr info,const std::string& fileName) +{ + if(!info || !info->node()) + return; + + comQueue_->suspend(true); + ServerDefsAccess defsAccess(this); // will reliquish its resources on destruction + defs_ptr defs = defsAccess.defs(); + if(defs) + { + PrintStyle style(PrintStyle::MIGRATE); + std::ofstream out(fileName.c_str()); + out << "defs_state MIGRATE" << std::endl; + info->node()->node()->print(out); + out << std::endl; + out.close(); + } + comQueue_->start(); +} + + //-------------------------------------------- // Other //-------------------------------------------- diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/ServerHandler.hpp ecflow-4.11.1/Viewer/ecflowUI/src/ServerHandler.hpp --- ecflow-4.10.0/Viewer/ecflowUI/src/ServerHandler.hpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/ServerHandler.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -65,6 +65,7 @@ bool readFromDisk() const; SuiteFilter* suiteFilter() const {return suiteFilter_;} QString nodeMenuMode() const; + QString defStatusNodeMenuMode() const; void setSuiteFilterWithOne(VNode*); void updateSuiteFilter(SuiteFilter*); @@ -115,6 +116,9 @@ static ServerHandler* find(const std::string& name); + void writeDefs(const std::string& fileName); + void writeDefs(VInfo_ptr info,const std::string& fileName); + protected: ServerHandler(const std::string& name,const std::string& host,const std::string& port); ~ServerHandler(); diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/ShellCommand.cpp ecflow-4.11.1/Viewer/ecflowUI/src/ShellCommand.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/ShellCommand.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/ShellCommand.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -64,8 +64,10 @@ //If the shell command runs ecflow_client it has to be in the PATH env variable. //When we develop the ui it is not the case so we need to add its path to PATH - //whenever is possible. - if(command_.contains("ecflow_client") && envHasToBeSet_) + //whenever is possible. The same is true for node_state_diag.sh. + if((command_.contains("ecflow_client") || + command_.contains("ecflow_ui_node_state_diag.sh") || command_.contains("ecflow_ui_create_jira_issue.sh")) && + envHasToBeSet_) { QString exeDir=QString::fromStdString(DirectoryHandler::exeDir()); Q_ASSERT(!exeDir.isEmpty()); @@ -100,6 +102,11 @@ void ShellCommand::procFinished(int exitCode, QProcess::ExitStatus exitStatus) { + if(!item_ && exitCode !=0) + { + item_=CommandOutputHandler::instance()->addItem(command_,commandDef_,startTime_); + } + if(item_) { if(exitCode == 0 && exitStatus == QProcess::NormalExit) diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/TableNodeModel.cpp ecflow-4.11.1/Viewer/ecflowUI/src/TableNodeModel.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/TableNodeModel.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/TableNodeModel.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -11,11 +11,14 @@ #include +#include "DiagData.hpp" +#include "IconProvider.hpp" #include "ModelColumn.hpp" #include "ServerHandler.hpp" #include "UiLog.hpp" #include "VAttribute.hpp" #include "VAttributeType.hpp" +#include "VConfig.hpp" #include "VFilter.hpp" #include "VIcon.hpp" #include "VModelData.hpp" @@ -49,11 +52,11 @@ data_(0), columns_(0) { - columns_=ModelColumn::def("table_columns"); + columns_=ModelColumn::def("table_columns"); Q_ASSERT(columns_); - //Check the mapping between the enum and column ids + //Check the mapping between the enum and column ids (only for the non-extra columns!) Q_ASSERT(columns_->id(PathColumn) == "path"); Q_ASSERT(columns_->id(StatusColumn) == "status"); Q_ASSERT(columns_->id(TypeColumn) == "type"); @@ -79,6 +82,34 @@ data_=new VTableModelData(filterDef,this); data_->reset(serverFilter); + + //We need to react to changes in the extra columns! + connect(columns_,SIGNAL(appendItemBegin()), + this,SLOT(slotAppendColumnBegin())); + + connect(columns_,SIGNAL(appendItemEnd()), + this,SLOT(slotAppendColumnEnd())); + + connect(columns_,SIGNAL(addItemsBegin(int,int)), + this,SLOT(slotAddColumnsBegin(int,int))); + + connect(columns_,SIGNAL(addItemsEnd(int,int)), + this,SLOT(slotAddColumnsEnd(int,int))); + + connect(columns_,SIGNAL(changeItemBegin(int)), + this,SLOT(slotChangeColumnBegin(int))); + + connect(columns_,SIGNAL(changeItemEnd(int)), + this,SLOT(slotChangeColumnEnd(int))); + + connect(columns_,SIGNAL(removeItemsBegin(int,int)), + this,SLOT(slotRemoveColumnsBegin(int,int))); + + connect(columns_,SIGNAL(removeItemsEnd(int,int)), + this,SLOT(slotRemoveColumnsEnd(int,int))); + + //pixmap + diagPixId_=IconProvider::add(":/viewer/diag.svg","diag.svg"); } VModelData* TableNodeModel::data() const @@ -148,7 +179,14 @@ if(!vnode || !vnode->node()) return QVariant(); - ColumnType id=static_cast(index.column()); + if(index.column() < 0) + return QVariant(); + + ColumnType id=ExtraColumn; + if(index.column() < ExtraColumn) + { + id=static_cast(index.column()); + } if(role == Qt::DisplayRole) { @@ -179,9 +217,26 @@ vnode->statusChangeTime(s); return s; } - - //else if(id == "icon") - // return VIcon::pixmapList(vnode,0); + //Extra columns added by the user - they all represent ecflow variables!!! + else if(id == ExtraColumn) + { + Q_ASSERT(columns_->isExtra(index.column())); + QString n=columns_->id(index.column()); + if(!n.isEmpty()) + { + //Standard variable column + if(columns_->isEditable(index.column())) + return QString::fromStdString(vnode->findInheritedVariable(n.toStdString())); + //extra diagnostic column + else + { + DiagData* diag=DiagData::instance(); + int diagCol=index.column()-columns_->diagStartIndex(); + if(diagCol >= 0) + return QString::fromStdString(diag->dataAt(vnode,diagCol)); + } + } + } } else if(role == Qt::BackgroundRole) { @@ -196,7 +251,17 @@ } else if(role == SortRole) { - if(id == StatusChangeColumn) + if(id == MeterColumn) + { + if(VAttribute* a=vnode->attributeForType(0,columnToAttrType(id))) + { + std::string val; + if(a->value("meter_value",val)) + return QString::fromStdString(val).toInt(); + } + return -9999; + } + else if(id == StatusChangeColumn) { return vnode->statusChangeTime(); } @@ -207,16 +272,47 @@ QVariant TableNodeModel::headerData( const int section, const Qt::Orientation orient , const int role ) const { - if ( orient != Qt::Horizontal || (role != Qt::DisplayRole && role != Qt::UserRole )) + if ( orient != Qt::Horizontal) return QAbstractItemModel::headerData( section, orient, role ); if (section < 0 || section >= columns_->count()) // this can happen during a server reset return QVariant(); if(role == Qt::DisplayRole) - return columns_->label(section); - else if(role == Qt::UserRole) - return columns_->id(section); + { + return columns_->label(section); + } + //the id of the column + else if(role == Qt::UserRole) + { + return columns_->id(section); + } + else if(role == Qt::ToolTipRole) + { + if(section < ExtraColumn) + { + return columns_->tooltip(section); + } + else if(columns_->isEditable(section)) + { + return tr("Displays the value of the given ecFlow variable (can be changed or removed)"); + } + else + { + return tr("Extra diagnostic"); + } + } + else if(role == VariableRole) + { + return (section >= ExtraColumn && columns_->isEditable(section))?true:false; + } + else if(role == Qt::DecorationRole) + { + if(section >= ExtraColumn && !columns_->isEditable(section)) + { + return IconProvider::pixmap(diagPixId_,12); + } + } return QVariant(); } @@ -447,3 +543,53 @@ if(num >0) endRemoveRows(); } + +//======================================= +// Column management +//======================================= + +void TableNodeModel::removeColumn(QString name) +{ + Q_ASSERT(columns_); + columns_->removeExtraItem(name); +} + +void TableNodeModel::slotAppendColumnBegin() +{ + int col=columnCount(); + beginInsertColumns(QModelIndex(),col,col); +} + +void TableNodeModel::slotAppendColumnEnd() +{ + endInsertColumns(); +} + +void TableNodeModel::slotAddColumnsBegin(int idxStart,int idxEnd) +{ + beginInsertColumns(QModelIndex(),idxStart,idxEnd); +} + +void TableNodeModel::slotAddColumnsEnd(int idxStart,int idxEnd) +{ + endInsertColumns(); +} + +void TableNodeModel::slotChangeColumnBegin(int /*idx*/) +{ +} + +void TableNodeModel::slotChangeColumnEnd(int idx) +{ + Q_EMIT dataChanged(index(0,idx),index(rowCount(),idx)); +} + +void TableNodeModel::slotRemoveColumnsBegin(int idxStart,int idxEnd) +{ + beginRemoveColumns(QModelIndex(),idxStart,idxEnd); +} + +void TableNodeModel::slotRemoveColumnsEnd(int idxStart,int idxEnd) +{ + endRemoveColumns(); +} diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/TableNodeModel.hpp ecflow-4.11.1/Viewer/ecflowUI/src/TableNodeModel.hpp --- ecflow-4.10.0/Viewer/ecflowUI/src/TableNodeModel.hpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/TableNodeModel.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -27,68 +27,80 @@ { Q_OBJECT - friend class TableNodeSortModel; - + friend class TableNodeSortModel; + public: - TableNodeModel(ServerFilter* serverFilter,NodeFilterDef* filterDef,QObject *parent=0); - - int columnCount (const QModelIndex& parent = QModelIndex() ) const; - int rowCount (const QModelIndex& parent = QModelIndex() ) const; - - QVariant data (const QModelIndex& , int role = Qt::DisplayRole ) const; - QVariant headerData(int,Qt::Orientation,int role = Qt::DisplayRole ) const; - - QModelIndex index (int, int, const QModelIndex& parent = QModelIndex() ) const; - QModelIndex parent (const QModelIndex & ) const; - - VInfo_ptr nodeInfo(const QModelIndex&); - void selectionChanged(QModelIndexList lst); - - VModelData* data() const; - ModelColumn* columns() const {return columns_;} - - //To speed up identifying a column. The mapping here must match the definition of - //"table_columns" in ecflowview_view_conf.json !!! - enum ColumnType {PathColumn=0,StatusColumn=1,TypeColumn=2,TriggerColumn=3, - LabelColumn=4, EventColumn=5, MeterColumn=6, StatusChangeColumn=7}; + TableNodeModel(ServerFilter* serverFilter,NodeFilterDef* filterDef,QObject *parent=0); + int columnCount (const QModelIndex& parent = QModelIndex() ) const; + int rowCount (const QModelIndex& parent = QModelIndex() ) const; + + QVariant data (const QModelIndex& , int role = Qt::DisplayRole ) const; + QVariant headerData(int,Qt::Orientation,int role = Qt::DisplayRole ) const; + + QModelIndex index (int, int, const QModelIndex& parent = QModelIndex() ) const; + QModelIndex parent (const QModelIndex & ) const; + + VInfo_ptr nodeInfo(const QModelIndex&); + void selectionChanged(QModelIndexList lst); + + VModelData* data() const; + void removeColumn(QString); + ModelColumn* columns() const {return columns_;} + + //To speed up identifying a column. The mapping here must match the definition of + //"table_columns" in ecflowview_view_conf.json !!! + enum ColumnType {InvalidColumn=-1, PathColumn=0,StatusColumn=1,TypeColumn=2,TriggerColumn=3, + LabelColumn=4, EventColumn=5, MeterColumn=6, StatusChangeColumn=7, + ExtraColumn = 8 }; + public Q_SLOTS: - void slotServerAddBegin(int); - void slotServerAddEnd(); - void slotServerRemoveBegin(VModelServer* server,int); - void slotServerRemoveEnd(int); - - void slotDataChanged(VModelServer*) {} - void slotNodeChanged(VTableServer*,const VNode*); - void slotAttributesChanged(VModelServer*,const VNode*) {} - void slotBeginAddRemoveAttributes(VModelServer*,const VNode*,int,int) {} - void slotEndAddRemoveAttributes(VModelServer*,const VNode*,int,int) {} - - void slotBeginServerScan(VModelServer* server,int); - void slotEndServerScan(VModelServer* server,int); - void slotBeginServerClear(VModelServer* server,int); - void slotEndServerClear(VModelServer* server,int); + void slotServerAddBegin(int); + void slotServerAddEnd(); + void slotServerRemoveBegin(VModelServer* server,int); + void slotServerRemoveEnd(int); + + void slotDataChanged(VModelServer*) {} + void slotNodeChanged(VTableServer*,const VNode*); + void slotAttributesChanged(VModelServer*,const VNode*) {} + void slotBeginAddRemoveAttributes(VModelServer*,const VNode*,int,int) {} + void slotEndAddRemoveAttributes(VModelServer*,const VNode*,int,int) {} + + void slotBeginServerScan(VModelServer* server,int); + void slotEndServerScan(VModelServer* server,int); + void slotBeginServerClear(VModelServer* server,int); + void slotEndServerClear(VModelServer* server,int); + + void slotAppendColumnBegin(); + void slotAppendColumnEnd(); + void slotAddColumnsBegin(int,int); + void slotAddColumnsEnd(int,int); + void slotChangeColumnBegin(int idx); + void slotChangeColumnEnd(int idx); + void slotRemoveColumnsBegin(int,int); + void slotRemoveColumnsEnd(int,int); Q_SIGNALS: - void filterChangeBegun(); - void filterChangeEnded(); + void filterChangeBegun(); + void filterChangeEnded(); protected: - bool isServer(const QModelIndex & index) const {return false;} - ServerHandler* indexToRealServer(const QModelIndex & index) const {return NULL;} - VModelServer* indexToServer(const QModelIndex & index) const {return NULL;} - QModelIndex serverToIndex(ServerHandler*) const {return QModelIndex();} - - QModelIndex nodeToIndex(VTableServer* server,const VNode* node, int column) const; - QModelIndex nodeToIndex(const VNode*,int column=0) const; - VNode* indexToNode( const QModelIndex & index) const; - - QModelIndex attributeToIndex(const VAttribute* a, int column=0) const; - - QVariant nodeData(const QModelIndex& index,int role) const; - - VTableModelData* data_; - ModelColumn* columns_; + bool isServer(const QModelIndex & index) const {return false;} + ServerHandler* indexToRealServer(const QModelIndex & index) const {return NULL;} + VModelServer* indexToServer(const QModelIndex & index) const {return NULL;} + QModelIndex serverToIndex(ServerHandler*) const {return QModelIndex();} + + QModelIndex nodeToIndex(VTableServer* server,const VNode* node, int column) const; + QModelIndex nodeToIndex(const VNode*,int column=0) const; + VNode* indexToNode( const QModelIndex & index) const; + + QModelIndex attributeToIndex(const VAttribute* a, int column=0) const; + + QVariant nodeData(const QModelIndex& index,int role) const; + + VTableModelData* data_; + ModelColumn* columns_; + int diagPixId_; }; #endif diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/TableNodeSortModel.cpp ecflow-4.11.1/Viewer/ecflowUI/src/TableNodeSortModel.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/TableNodeSortModel.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/TableNodeSortModel.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -17,6 +17,7 @@ nodeModel_(nodeModel), skipSort_(false) { + Q_ASSERT(nodeModel_); //connect(nodeModel_,SIGNAL(filterChanged()), // this,SLOT(slotFilterChanged())); @@ -65,6 +66,12 @@ if(id == TableNodeModel::PathColumn) return left.row() < right.row(); + else if(id == TableNodeModel::MeterColumn) + { + return left.data(AbstractNodeModel::SortRole).toInt() < + right.data(AbstractNodeModel::SortRole).toInt(); + } + else if(id == TableNodeModel::StatusChangeColumn) { return left.data(AbstractNodeModel::SortRole).toUInt() < @@ -76,3 +83,15 @@ return leftData.toString() < rightData.toString(); } + +void TableNodeSortModel::removeColumn(QString name) +{ + nodeModel_->removeColumn(name); +} + +ModelColumn* TableNodeSortModel::columns() const +{ + nodeModel_->columns(); +} + + diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/TableNodeSortModel.hpp ecflow-4.11.1/Viewer/ecflowUI/src/TableNodeSortModel.hpp --- ecflow-4.10.0/Viewer/ecflowUI/src/TableNodeSortModel.hpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/TableNodeSortModel.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -16,6 +16,7 @@ class TableNodeModel; class NodeFilterDef; +class ModelColumn; class TableNodeSortModel : public QSortFilterProxyModel { @@ -32,10 +33,11 @@ QModelIndex nodeToIndex(const VNode *node); void selectionChanged(QModelIndexList lst); void setSkipSort(bool b) {skipSort_=b;} + void removeColumn(QString); + ModelColumn* columns() const; protected: - bool lessThan(const QModelIndex &left, - const QModelIndex &right) const; + bool lessThan(const QModelIndex &left, const QModelIndex &right) const; TableNodeModel* nodeModel_; bool skipSort_; diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/TableNodeView.cpp ecflow-4.11.1/Viewer/ecflowUI/src/TableNodeView.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/TableNodeView.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/TableNodeView.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,7 @@ #include #include "ActionHandler.hpp" +#include "AddModelColumnDialog.hpp" #include "FilterWidget.hpp" #include "IconProvider.hpp" #include "TableNodeSortModel.hpp" @@ -29,6 +31,7 @@ #include "TableNodeViewDelegate.hpp" #include "UiLog.hpp" #include "VFilter.hpp" +#include "VNode.hpp" #include "VSettings.hpp" #define _UI_TABLENODEVIEW_DEBUG @@ -308,10 +311,60 @@ // Header //========================================= +void TableNodeView::collectVariableNames(std::set& vars) +{ + Q_ASSERT(model_); + + //collect the list of avialable variables using the selected node + //or if it is not valid the first row in the table + QModelIndex idx=currentIndex(); + if(!idx.isValid()) + { + idx=model_->index(0,0); + } + + if(idx.isValid()) + { + VInfo_ptr info=model_->nodeInfo(idx); + if(info) + { + if(VNode* vn=info->node()) + { + vn->collectInheritedVariableNames(vars); + } + } + } +} + + +void TableNodeView::slotAddVariableColumn() +{ + Q_ASSERT(model_); + + std::set vars; + collectVariableNames(vars); + + AddModelColumnDialog d(this); + d.init(model_->columns(),vars); + d.exec(); +} + +void TableNodeView::changeVariableColumn(QString varName) +{ + Q_ASSERT(model_); + + std::set vars; + collectVariableNames(vars); + + ChangeModelColumnDialog d(this); + d.init(model_->columns(),vars,varName); + d.setColumn(varName); + d.exec(); +} + void TableNodeView::slotHeaderContextMenu(const QPoint &position) { int section=header_->logicalIndexAt(position); - if(section< 0 || section >= header_->count()) return; @@ -326,35 +379,96 @@ QMenu *menu=new QMenu(this); QAction *ac; + //Show/hide current columns + QString name=header_->model()->headerData(section,Qt::Horizontal).toString(); + ac=new QAction(menu); + ac->setData("show_current"); + bool vis=!header_->isSectionHidden(section); + ac->setText(((!vis)?"Show column \'":"Hide column \'") + name + "\'"); + if(vis && visCnt <=1) + { + ac->setEnabled(false); + } + menu->addAction(ac); + + menu->addSeparator(); + + //Add special menu for variable columns + bool varColumn=header_->model()->headerData(section,Qt::Horizontal,AbstractNodeModel::VariableRole).toBool(); + QString varName; + + if(varColumn) + { + varName=header_->model()->headerData(section,Qt::Horizontal).toString(); + + ac=new QAction(menu); + ac->setText(tr("Change column \'") + varName + "\'"); + ac->setData("change"); + menu->addAction(ac); + + ac=new QAction(menu); + ac->setText(tr("Remove column \'") + varName + "\'"); + ac->setIcon(QPixmap(":viewer/remove.svg")); + ac->setData("remove"); + menu->addAction(ac); + + menu->addSeparator(); + } + + //Submenu to control the visibility of other columns + QMenu *visMenu=menu->addMenu("Show/hide other columns"); for(int i=0; i count(); i++) { - QString name=header_->model()->headerData(i,Qt::Horizontal).toString(); - ac=new QAction(menu); - ac->setText(name); - ac->setCheckable(true); - ac->setData(i); + if(i != section) + { + name=header_->model()->headerData(i,Qt::Horizontal).toString(); + ac=new QAction(visMenu); + ac->setText(name); + ac->setCheckable(true); + ac->setData(i); - bool vis=!header_->isSectionHidden(i); - ac->setChecked(vis); + bool vis=!header_->isSectionHidden(i); + ac->setChecked(vis); - if(vis && visCnt <=1) - { - ac->setEnabled(false); - } + if(vis && visCnt <=1) + { + ac->setEnabled(false); + } - menu->addAction(ac); + visMenu->addAction(ac); + } } - //stateFilterMenu_=new StateFilterMenu(menuState,filter_->menu()); - //VParamFilterMenu stateFilterMenu(menu,filterDef_->nodeState(),VParamFilterMenu::ColourDecor); - + //Show the context menu and check selected action ac=menu->exec(header_->mapToGlobal(position)); - if(ac && ac->isEnabled() && ac->isCheckable()) + if(ac && ac->isEnabled()) { - int i=ac->data().toInt(); - header_->setSectionHidden(i,!ac->isChecked()); + if(ac->data().toString() == "change") + { + changeVariableColumn(varName); + } + else if(ac->data().toString() == "remove") + { + delete menu; + if(QMessageBox::question(0,tr("Confirm: remove column"), + tr("Are you sure that you want to remove column ") + varName + "?", + QMessageBox::Ok | QMessageBox::Cancel,QMessageBox::Cancel) == QMessageBox::Ok) + { + model_->removeColumn(varName); + } + return; + } + else if(ac->data().toString() == "show_current") + { + header_->setSectionHidden(section,!header_->isSectionHidden(section)); + } + else if(ac->isCheckable()) + { + int i=ac->data().toInt(); + header_->setSectionHidden(i,!ac->isChecked()); + } } - delete menu; + delete menu; } void TableNodeView::readSettings(VSettings* vs) @@ -618,13 +732,14 @@ if(isSortIndicatorShown() && sortIndicatorSection() == logicalIndex) opt.sortIndicator = (sortIndicatorOrder() == Qt::AscendingOrder) ? QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp; - if (opt.sortIndicator != QStyleOptionHeader::None) - { - QStyleOptionHeader subopt = opt; - subopt.rect = style()->subElementRect(QStyle::SE_HeaderArrow, &opt, this); - rightPos=subopt.rect.left(); - style()->drawPrimitive(QStyle::PE_IndicatorHeaderArrow, &subopt, painter, this); - } + + if (opt.sortIndicator != QStyleOptionHeader::None) + { + QStyleOptionHeader subopt = opt; + subopt.rect = style()->subElementRect(QStyle::SE_HeaderArrow, &opt, this); + rightPos=subopt.rect.left(); + style()->drawPrimitive(QStyle::PE_IndicatorHeaderArrow, &subopt, painter, this); + } QMap::iterator it=customButton_.find(logicalIndex); @@ -649,12 +764,32 @@ it.value().setRect(optButton.rect); } + //Text is left aligned, a decoration icon might be added to left just before the text QString text=model()->headerData(logicalIndex,Qt::Horizontal).toString(); QRect textRect=rect; - textRect.setRight(rightPos-5); + textRect.setRight(rightPos-5); + textRect.adjust(2,0,0,0); + + //Draw icon to the left of the text + QVariant pixVa=model()->headerData(logicalIndex,Qt::Horizontal,Qt::DecorationRole); + if(pixVa.type() == QVariant::Pixmap) + { + QPixmap pix=pixVa.value(); + int pixH=qMin(pix.height(),rect.height()-2); - painter->drawText(textRect,Qt::AlignHCenter | Qt::AlignVCenter,text); + QFont f; + QFontMetrics fm(f); + int textLeft=textRect.x(); + QRect pixRect=QRect(rect.x()+3,rect.center().y()-pixH/2, + pix.width(),pix.height()); + if(pixRect.x()+pixRect.width() + fm.width(text) + 4 < textRect.x() + textRect.width()) + { + painter->drawPixmap(pixRect,pix); + textRect.setX(pixRect.x()+pixRect.width() + 3); + } + } + painter->drawText(textRect,Qt::AlignLeft | Qt::AlignVCenter,text); //style()->drawControl(QStyle::CE_PushButton, &optButton,painter,this); } diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/TableNodeView.hpp ecflow-4.11.1/Viewer/ecflowUI/src/TableNodeView.hpp --- ecflow-4.10.0/Viewer/ecflowUI/src/TableNodeView.hpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/TableNodeView.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -13,6 +13,7 @@ #include #include +#include #include "NodeViewBase.hpp" @@ -31,9 +32,7 @@ class TableNodeView : public QTreeView, public NodeViewBase, public VPropertyObserver { Q_OBJECT - public: - explicit TableNodeView(TableNodeSortModel* model,NodeFilterDef* filterDef,QWidget *parent=0); ~TableNodeView(); @@ -58,6 +57,7 @@ void slotHeaderContextMenu(const QPoint &position); void slotSizeHintChangedGlobal(); void slotRerender(); + void slotAddVariableColumn(); Q_SIGNALS: void selectionChanged(VInfo_ptr); @@ -71,6 +71,8 @@ void adjustBackground(QColor col); void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); void setSortingEnabledNoExec(bool b); + void collectVariableNames(std::set& vars); + void changeVariableColumn(QString varName); TableNodeSortModel* model_; ActionHandler* actionHandler_; diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/TableNodeWidget.cpp ecflow-4.11.1/Viewer/ecflowUI/src/TableNodeWidget.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/TableNodeWidget.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/TableNodeWidget.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -137,6 +137,8 @@ //tw->slotUpdateTitle("Table"); QList acLst; + + //Edit filter QAction* acFilterEdit=new QAction(this); acFilterEdit->setIcon(QPixmap(":viewer/filter_edit.svg")); acFilterEdit->setToolTip("Edit filter ..."); @@ -145,6 +147,15 @@ connect(acFilterEdit,SIGNAL(triggered()), filterW_,SLOT(slotEdit())); + //Add variable column + QAction* acVar=new QAction(this); + acVar->setIcon(QPixmap(":viewer/dock_add_variable_column.svg")); + acVar->setToolTip("Add variable column ..."); + acLst << acVar; + + connect(acVar,SIGNAL(triggered()), + view_->realWidget(),SLOT(slotAddVariableColumn())); + tw->addActions(acLst); } diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/TreeNodeModel.cpp ecflow-4.11.1/Viewer/ecflowUI/src/TreeNodeModel.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/TreeNodeModel.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/TreeNodeModel.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -503,6 +503,36 @@ return (indexToNode(index) != NULL); } +// A node is a flat node when: +// -there are no child nodes (only attributes) +// or +// -any child node does not have children or attributes +bool TreeNodeModel::isFlatNode(const QModelIndex& index) const +{ + if(VTreeNode *node=indexToNode(index)) + { + if(node->numOfChildren() == 0) + return true; + else + { + for(int i=0; i < node->numOfChildren(); i++) + { + if(node->childAt(i)->numOfChildren() == 0) + { + if(node->childAt(i)->attrNum(atts_) > 0) + return false; + } + else + { + return false; + } + } + return true; + } + } + return false; +} + bool TreeNodeModel::isAttribute(const QModelIndex & index) const { return (index.isValid() && !isServer(index) && !isNode(index)); @@ -1386,3 +1416,4 @@ else return VIcon::pixmapNum(n,icons_); } + diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/TreeNodeModel.hpp ecflow-4.11.1/Viewer/ecflowUI/src/TreeNodeModel.hpp --- ecflow-4.10.0/Viewer/ecflowUI/src/TreeNodeModel.hpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/TreeNodeModel.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -56,6 +56,7 @@ QModelIndex attributeToIndex(const VAttribute* a, int column=0) const; + bool isFlatNode(const QModelIndex& index) const; VInfo_ptr nodeInfo(const QModelIndex& index); void setForceShow(VInfo_ptr); void selectionChanged(QModelIndexList lst); diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/TreeNodeView.cpp ecflow-4.11.1/Viewer/ecflowUI/src/TreeNodeView.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/TreeNodeView.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/TreeNodeView.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -79,6 +79,7 @@ std::vector propVec; propVec.push_back("view.tree.indentation"); propVec.push_back("view.tree.background"); + propVec.push_back("view.tree.autoExpandLeafNode"); propVec.push_back("view.tree.drawBranchLine"); propVec.push_back("view.tree.branchLineColour"); propVec.push_back("view.tree.serverToolTip"); @@ -99,6 +100,10 @@ adjustBackground(prop->value().value()); //Init branch line status (on/off) + prop=prop_->find("view.tree.autoExpandLeafNode",true); + adjustAutoExpandLeafNode(prop->value().toBool()); + + //Init branch line status (on/off) prop=prop_->find("view.tree.drawBranchLine",true); adjustDrawBranchLine(prop->value().toBool()); @@ -689,6 +694,11 @@ } } +void TreeNodeView::adjustAutoExpandLeafNode(bool b) +{ + view_->setAutoExpandLeafNode(b); +} + void TreeNodeView::adjustDrawBranchLine(bool b) { view_->setDrawConnector(b); @@ -724,6 +734,10 @@ { adjustIndentation(p->value().toInt()); } + else if(p->path() == "view.tree.autoExpandLeafNode") + { + adjustAutoExpandLeafNode(p->value().toBool()); + } else if(p->path() == "view.tree.drawBranchLine") { adjustDrawBranchLine(p->value().toBool()); diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/TreeNodeView.hpp ecflow-4.11.1/Viewer/ecflowUI/src/TreeNodeView.hpp --- ecflow-4.10.0/Viewer/ecflowUI/src/TreeNodeView.hpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/TreeNodeView.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -86,6 +86,7 @@ void adjustBackground(QColor col); void adjustIndentation(int); + void adjustAutoExpandLeafNode(bool b); void adjustDrawBranchLine(bool b); void adjustBranchLineColour(QColor col); void adjustServerToolTip(bool); diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/VariableItemWidget.cpp ecflow-4.11.1/Viewer/ecflowUI/src/VariableItemWidget.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/VariableItemWidget.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/VariableItemWidget.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -19,6 +19,7 @@ #include "IconProvider.hpp" #include "LineEdit.hpp" +#include "ModelColumn.hpp" #include "SessionHandler.hpp" #include "UiLog.hpp" #include "UserMessage.hpp" @@ -626,7 +627,8 @@ VariableItemWidget::VariableItemWidget(QWidget *parent) : shadowProp_(0), - canSaveLastSelection_(true) + canSaveLastSelection_(true), + tableViewColumns_(0) { //This item displays all the ancestors of the info object useAncestors_=true; @@ -635,6 +637,13 @@ data_=new VariableModelDataHandler(); + //table view columns + tableViewColumns_=ModelColumn::def("table_columns"); + if(!tableViewColumns_) + { + UiLog().warn() << "Cannot find ModelColumn object for \"table_columns\""; + } + //The model and the sort-filter model model_=new VariableModel(data_,this); sortModel_= new VariableSortModel(model_,this); @@ -704,7 +713,9 @@ QAction* sep2=new QAction(this); sep2->setSeparator(true); QAction* sep3=new QAction(this); - sep3->setSeparator(true); + sep3->setSeparator(true); + QAction* sep4=new QAction(this); + sep4->setSeparator(true); //Build context menu varView->addAction(actionAdd); @@ -716,6 +727,8 @@ varView->addAction(actionDelete); varView->addAction(sep3); varView->addAction(actionProp); + varView->addAction(sep4); + varView->addAction(actionAddToTableView); //Add actions for the toolbuttons addTb->setDefaultAction(actionAdd); @@ -835,6 +848,7 @@ actionDelete->setEnabled(false); actionCopy->setEnabled(false); actionCopyFull->setEnabled(false); + actionAddToTableView->setEnabled(false); return; } @@ -845,6 +859,7 @@ actionDelete->setEnabled(false); actionCopy->setEnabled(false); actionCopyFull->setEnabled(false); + actionAddToTableView->setEnabled(false); } else { @@ -871,6 +886,16 @@ actionProp->setEnabled(true); actionCopy->setEnabled(true); actionCopyFull->setEnabled(true); + + if(tableViewColumns_) + { + QString varName=model_->data(index).toString(); + actionAddToTableView->setEnabled(tableViewColumns_->indexOf(varName) == -1); + } + else + { + actionAddToTableView->setEnabled(false); + } } //Server or nodes else @@ -886,7 +911,8 @@ actionProp->setEnabled(false); actionCopy->setEnabled(false); actionCopyFull->setEnabled(false); - } + actionAddToTableView->setEnabled(false); + } } if(frozen_) @@ -1138,6 +1164,16 @@ } } +void VariableItemWidget::on_actionAddToTableView_triggered() +{ + if(tableViewColumns_) + { + QModelIndex idx=sortModel_->mapToSource(varView->currentIndex()); + QString name=model_->data(idx).toString(); + tableViewColumns_->addExtraItem(name,name); + } +} + void VariableItemWidget::on_shadowTb_clicked(bool showShadowed) { if(shadowProp_) diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/VariableItemWidget.hpp ecflow-4.11.1/Viewer/ecflowUI/src/VariableItemWidget.hpp --- ecflow-4.10.0/Viewer/ecflowUI/src/VariableItemWidget.hpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/VariableItemWidget.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -20,6 +20,7 @@ #include "VInfo.hpp" class LineEdit; +class ModelColumn; class VariableModel; class VariableModelData; class VariableModelDataHandler; @@ -127,7 +128,8 @@ void on_actionSearch_triggered(); void on_actionCopy_triggered(); void on_actionCopyFull_triggered(); - void on_shadowTb_clicked(bool showShadowed); + void on_actionAddToTableView_triggered(); + void on_shadowTb_clicked(bool showShadowed); void slotVariableEdited(); void slotVariableAdded(); @@ -160,6 +162,7 @@ VInfo_ptr lastSelection_; bool canSaveLastSelection_; QList expanded_; + ModelColumn *tableViewColumns_; }; #endif diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/VariableItemWidget.ui ecflow-4.11.1/Viewer/ecflowUI/src/VariableItemWidget.ui --- ecflow-4.10.0/Viewer/ecflowUI/src/VariableItemWidget.ui 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/VariableItemWidget.ui 2018-10-23 11:41:34.000000000 +0000 @@ -248,6 +248,15 @@ Copy variable's name and value + + + + :/viewer/add_variable_column.svg:/viewer/add_variable_column.svg + + + Add variable to table view + + diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/VariableModel.cpp ecflow-4.11.1/Viewer/ecflowUI/src/VariableModel.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/VariableModel.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/VariableModel.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -9,6 +9,7 @@ #include "VariableModel.hpp" +#include #include #include "ServerHandler.hpp" @@ -247,17 +248,28 @@ QVariant VariableModel::headerData( const int section, const Qt::Orientation orient , const int role ) const { - if ( orient != Qt::Horizontal || role != Qt::DisplayRole ) - return QAbstractItemModel::headerData( section, orient, role ); + if ( orient != Qt::Horizontal || (role != Qt::DisplayRole && role != Qt::ToolTipRole)) + return QAbstractItemModel::headerData( section, orient, role ); + if(role == Qt::DisplayRole) + { switch ( section ) { case 0: return tr("Name"); - case 1: return tr("Value"); + case 1: return tr("Value"); default: return QVariant(); } - - return QVariant(); + } + else if(role== Qt::ToolTipRole) + { + switch ( section ) + { + case 0: return tr("Name"); + case 1: return tr("Value"); + default: return QVariant(); + } + } + return QVariant(); } QModelIndex VariableModel::index( int row, int column, const QModelIndex & parent ) const @@ -270,7 +282,7 @@ //When parent is the root this index refers to a node or server if(!parent.isValid()) { -#ifdef ECFLOW_QT5 +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) return createIndex(row,column,quintptr(0)); #else return createIndex(row,column,0); @@ -323,7 +335,7 @@ int id=index.internalId(); if(id >=0 && id < 1000) { - return 1; + return 1; } return 2; } diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/VariableSearchLine.cpp ecflow-4.11.1/Viewer/ecflowUI/src/VariableSearchLine.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/VariableSearchLine.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/VariableSearchLine.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -8,7 +8,7 @@ //============================================================================ #include - +#include #include #include #include diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/VIcon.cpp ecflow-4.11.1/Viewer/ecflowUI/src/VIcon.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/VIcon.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/VIcon.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -79,6 +79,13 @@ bool show(VNode*); }; +class VTimeFreeIcon : public VIcon +{ +public: + explicit VTimeFreeIcon(const std::string& name) : VIcon(name) {} + bool show(VNode*); +}; + class VDateIcon : public VIcon { public: @@ -133,6 +140,7 @@ static VCompleteIcon completeIcon("complete"); static VLateIcon lateIcon("late"); static VTimeIcon timeIcon("time"); +static VTimeFreeIcon timeFreeIcon("time_free"); static VDateIcon dateIcon("date"); static VWaitIcon waitIcon("wait"); static VZombieIcon zombieIcon("zombie"); @@ -431,25 +439,43 @@ } //========================================================== -// Time +// Time - hasTimeHolding in ecflowview //========================================================== //Node only? -bool VTimeIcon::show(VNode *n) +bool VTimeIcon::show(VNode *n) { if(!n || n->isServer()) return false; node_ptr node=n->node(); + if(TimeDepAttrs *attr = node->get_time_dep_attrs()) + return !attr->time_today_cron_is_free(); + + return false; +} + + +//========================================================== +// TimeFree - hasTime in ecflowview +//========================================================== + +//Node only? +bool VTimeFreeIcon::show(VNode *n) +{ + if(!n || n->isServer()) + return false; + + if(timeIcon.show(n)) + return false; + + node_ptr node=n->node(); if(node->timeVec().size() > 0 || node->todayVec().size() > 0 || node->crons().size() > 0) { - //if(TimeDepAttrs *attr = node->get_time_dep_attrs()) - // return !attr->time_today_cron_is_free(); return true; - } return false; } diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/ViewerMain.cpp ecflow-4.11.1/Viewer/ecflowUI/src/ViewerMain.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/ViewerMain.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/ViewerMain.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -18,6 +18,7 @@ #include #include "File.hpp" +#include "DiagData.hpp" #include "MainWindow.hpp" #include "ServerHandler.hpp" #include "MenuHandler.hpp" @@ -32,6 +33,7 @@ #include "VConfig.hpp" #include "VIcon.hpp" #include "VServerSettings.hpp" +#include "VSettingsLoader.hpp" #include "SessionHandler.hpp" #include "SessionDialog.hpp" #include "UiLog.hpp" @@ -135,6 +137,9 @@ VServerSettings::importRcFiles(); } + //Update objects with saved user settings (these are now stored in VConfig!!) + VSettingsLoader::process(); + //Initialise highlighter Highlighter::init(DirectoryHandler::concatenate(DirectoryHandler::etcDir(), "ecflowview_highlighter.json")); @@ -161,6 +166,9 @@ //Enable (daily) truncation for ui log UiLog::enableTruncation(); + //Load extra diagnostic data + DiagData::instance()->load(); + return app.exec(); } else diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/viewer.qrc ecflow-4.11.1/Viewer/ecflowUI/src/viewer.qrc --- ecflow-4.10.0/Viewer/ecflowUI/src/viewer.qrc 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/viewer.qrc 2018-10-23 11:41:34.000000000 +0000 @@ -12,7 +12,8 @@ ../images/add_tree.svg ../images/icon_calendar.svg ../images/icon_clock.svg - ../images/icon_complete.svg + ../images/icon_clock_free.svg + ../images/icon_complete.svg ../images/icon_killed.svg ../images/icon_late.svg ../images/icon_children_hidden.svg @@ -27,6 +28,7 @@ ../images/configure.svg ../images/exit.svg ../images/add_tab.svg + ../images/add_variable_column.svg ../images/attribute.svg ../images/chain.svg ../images/chain_open.svg @@ -42,7 +44,9 @@ ../images/copy_path.svg ../images/dependency.svg ../images/dependency_detail.svg + ../images/diag.svg ../images/directory_arrow.svg + ../images/dock_add_variable_column.svg ../images/dock_chain_closed.svg ../images/dock_chain_open.svg ../images/dock_config.svg diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/VItem.hpp ecflow-4.11.1/Viewer/ecflowUI/src/VItem.hpp --- ecflow-4.10.0/Viewer/ecflowUI/src/VItem.hpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/VItem.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -49,6 +49,7 @@ virtual bool sameContents(VItem*) const=0; virtual bool isAncestor(const VItem*) const; virtual QString nodeMenuMode() const {return QString();} + virtual QString defStatusNodeMenuMode() const {return QString();} protected: VNode* parent_; diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/VItemPathParser.cpp ecflow-4.11.1/Viewer/ecflowUI/src/VItemPathParser.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/VItemPathParser.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/VItemPathParser.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -11,62 +11,87 @@ #include "VItemPathParser.hpp" #include "VAttributeType.hpp" -VItemPathParser::VItemPathParser(const std::string& path) : itemType_(NoType) +//format: +// [type]server://nodepath:atttibutename + +VItemPathParser::VItemPathParser(const std::string& path,PathFormat format) : itemType_(NoType) { if(path.empty()) return; size_t pos; std::string p=path; - if(p.find("[") == 0) + + if(format== DefaultFormat) { - pos=p.find("]"); - if(pos != std::string::npos) - { - type_=path.substr(1,pos-1); - p=path.substr(pos+1); - } - else - return; - } + if(p.find("[") == 0) + { + pos=p.find("]"); + if(pos != std::string::npos) + { + type_=path.substr(1,pos-1); + p=path.substr(pos+1); + } + else + return; + } - pos=p.find("://"); + pos=p.find("://"); - if(pos != std::string::npos) - { - server_=p.substr(0,pos); - p=p.substr(pos+2); - } + if(pos != std::string::npos) + { + server_=p.substr(0,pos); + p=p.substr(pos+2); + } - if(p.size() == 1 && p.find("/") == 0) - { - itemType_=ServerType; - return; - } + if(p.size() == 1 && p.find("/") == 0) + { + itemType_=ServerType; + return; + } - //Here we suppose that the node name cannot contain ":" - pos=p.find_first_of(":"); - if(pos != std::string::npos) - { - node_=p.substr(0,pos); - attribute_=p.substr(pos+1); - itemType_=AttributeType; - - if(type_ == "gen-variable") - type_="genvar"; - else if(type_ == "user-variable") - type_="var"; + //Here we suppose that the node name cannot contain ":" + pos=p.find_first_of(":"); + if(pos != std::string::npos) + { + node_=p.substr(0,pos); + attribute_=p.substr(pos+1); + itemType_=AttributeType; + + if(type_ == "gen-variable") + type_="genvar"; + else if(type_ == "user-variable") + type_="var"; - if(!VAttributeType::find(type_)) + if(!VAttributeType::find(type_)) + { + itemType_=NoType; + type_.clear(); + } + } + else { - itemType_=NoType; - type_.clear(); + node_=p; + itemType_=NodeType; } } - else + else if(format == DiagFormat) { - node_=p; - itemType_=NodeType; + pos=p.find(":/"); + if(pos != std::string::npos) + { + server_=p.substr(0,pos); + extractHostPort(server_); + if(p.length() > pos+1) + { + node_=p.substr(pos+1); + itemType_=NodeType; + } + else + { + itemType_=ServerType; + } + } } } @@ -125,3 +150,14 @@ return std::string(); } + +void VItemPathParser::extractHostPort(const std::string& server) +{ + size_t pos=server.find("@"); + if(pos != std::string::npos) + { + host_=server.substr(0,pos); + if(server.length() > pos +1) + port_=server.substr(pos+1); + } +} diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/VItemPathParser.hpp ecflow-4.11.1/Viewer/ecflowUI/src/VItemPathParser.hpp --- ecflow-4.10.0/Viewer/ecflowUI/src/VItemPathParser.hpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/VItemPathParser.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -16,13 +16,19 @@ class VItemPathParser { public: - VItemPathParser(const std::string& path); + enum PathFormat {DefaultFormat, // [type]server://nodepath:atttibutename + DiagFormat //host@port:/nodepath + }; + + VItemPathParser(const std::string& path,PathFormat format=DefaultFormat); enum ItemType {ServerType,NodeType,AttributeType,NoType}; ItemType itemType() const {return itemType_;} const std::string type() const {return type_;} const std::string server() const {return server_;} + const std::string host() const {return host_;} + const std::string port() const {return port_;} const std::string node() const {return node_;} const std::string attribute() const {return attribute_;} std::string parent() const; @@ -33,9 +39,13 @@ static std::string encodeAttribute(const std::string& parentPath,const std::string& attrName,const std::string& attrType); protected: + void extractHostPort(const std::string& server); + ItemType itemType_; std::string type_; std::string server_; + std::string host_; + std::string port_; std::string node_; std::string attribute_; }; diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/VNode.cpp ecflow-4.11.1/Viewer/ecflowUI/src/VNode.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/VNode.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/VNode.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -553,6 +553,33 @@ return val; } +void VNode::collectInheritedVariableNames(std::set& vars) const +{ + if(!node_) + return; + + std::vector v,gv; + variables(v); + genVariables(gv); + + for(size_t i=0; i < v.size(); i++) + { + vars.insert(v[i].name()); + } + + for(size_t i=0; i < gv.size(); i++) + { + vars.insert(gv[i].name()); + } + + //Try to find it in the parent + if(parent()) + { + parent()->collectInheritedVariableNames(vars); + } +} + + int VNode::variablesNum() const { if(node_.get()) @@ -1135,6 +1162,13 @@ return s->nodeMenuMode(); } +QString VNode::defStatusNodeMenuMode() const +{ + ServerHandler* s=server(); + Q_ASSERT(s); + return s->defStatusNodeMenuMode(); +} + const std::string& VSuiteNode::typeName() const { static std::string t("suite"); diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/VNode.hpp ecflow-4.11.1/Viewer/ecflowUI/src/VNode.hpp --- ecflow-4.10.0/Viewer/ecflowUI/src/VNode.hpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/VNode.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -12,6 +12,7 @@ #define VNODE_HPP_ #include +#include #include #include @@ -137,6 +138,8 @@ virtual std::string genVariable(const std::string& key) const; virtual std::string findVariable(const std::string& key,bool substitute=false) const; + virtual void collectInheritedVariableNames(std::set& vars) const; + //Find a variable in the given node or in its ancestors. Both the variables and the //generated variables are searched. virtual std::string findInheritedVariable(const std::string& key,bool substitute=false) const; @@ -195,6 +198,7 @@ void addTriggeredData(VItem* a,VItem* n); QString nodeMenuMode() const; + QString defStatusNodeMenuMode() const; virtual void print(); diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/VNodeStateDiag.cpp ecflow-4.11.1/Viewer/ecflowUI/src/VNodeStateDiag.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/VNodeStateDiag.cpp 1970-01-01 00:00:00.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/VNodeStateDiag.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -0,0 +1,44 @@ +//============================================================================ +// Copyright 2009-2018 ECMWF. +// This software is licensed under the terms of the Apache Licence version 2.0 +// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +// In applying this licence, ECMWF does not waive the privileges and immunities +// granted to it by virtue of its status as an intergovernmental organisation +// nor does it submit to any jurisdiction. +// +//============================================================================ + +#include "VNodeStateDiag.hpp" + +#include "ServerHandler.hpp" + +#include "DirectoryHandler.hpp" +#include "UiLog.hpp" +#include "VFile.hpp" +#include "VNode.hpp" +#include "ShellCommand.hpp" + +VNodeStateDiag::VNodeStateDiag(VInfo_ptr info) +{ + if(!info) + return; + + if(info->isNode() && info->node()) + { + VNode *node=info->node(); + ServerHandler* s=info->server(); + + if(node && s) + { + VFile_ptr tmpFile=VFile::createTmpFile(false); + VFile_ptr tmpFile2=VFile::createTmpFile(false); + + s->writeDefs(info,tmpFile->path()); + std::string cmd="sh ecflow_ui_node_state_diag.sh \'" + tmpFile->path() + "\' " + + s->host() + " " + s->port() + " \'" + + info->nodePath() + "\' \'" + tmpFile2->path() + "\'"; + + ShellCommand::run(cmd,""); + } + } +} diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/VNodeStateDiag.hpp ecflow-4.11.1/Viewer/ecflowUI/src/VNodeStateDiag.hpp --- ecflow-4.10.0/Viewer/ecflowUI/src/VNodeStateDiag.hpp 1970-01-01 00:00:00.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/VNodeStateDiag.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -0,0 +1,22 @@ +//============================================================================ +// Copyright 2009-2018 ECMWF. +// This software is licensed under the terms of the Apache Licence version 2.0 +// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +// In applying this licence, ECMWF does not waive the privileges and immunities +// granted to it by virtue of its status as an intergovernmental organisation +// nor does it submit to any jurisdiction. +// +//============================================================================ + +#ifndef VNODESTATEDIAG_HPP +#define VNODESTATEDIAG_HPP + +#include "VInfo.hpp" + +class VNodeStateDiag +{ +public: + VNodeStateDiag(VInfo_ptr); +}; + +#endif // VNODESTATEDIAG_HPP diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/VReportMaker.cpp ecflow-4.11.1/Viewer/ecflowUI/src/VReportMaker.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/VReportMaker.cpp 1970-01-01 00:00:00.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/VReportMaker.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -0,0 +1,112 @@ +//============================================================================ +// Copyright 2009-2018 ECMWF. +// This software is licensed under the terms of the Apache Licence version 2.0 +// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +// In applying this licence, ECMWF does not waive the privileges and immunities +// granted to it by virtue of its status as an intergovernmental organisation +// nor does it submit to any jurisdiction. +// +//============================================================================ + +#include "VReportMaker.hpp" + +#include "VNode.hpp" +#include "VReply.hpp" +#include "OutputFileProvider.hpp" +#include "UiLog.hpp" + +VReportMaker::VReportMaker(QObject *parent) : QObject(parent) +{ + infoProvider_=new OutputFileProvider(this); +} + +void VReportMaker::run(VInfo_ptr info) +{ + VNode *node=info->node(); + + info_=info; + + //Get file contents + infoProvider_->info(info); + + //Get job output +} + +void VReportMaker::infoReady(VReply* reply) +{ + OutputFileProvider* op=static_cast(infoProvider_); + + if(reply->fileName() == op->joboutFileName() && !op->isTryNoZero(reply->fileName()) && + info_ && info_->isNode() && info_->node() && info_->node()->isSubmitted()) + { +#if 0 + hasMessage=true; + submittedWarning_=true; + messageLabel_->showWarning("This is the current job output (as defined by variable ECF_JOBOUT), but \ + because the node status is submitted it may contain the ouput from a previous run!"); +#endif + } + else + { +#if 0 + if(reply->hasWarning()) + { + messageLabel_->showWarning(QString::fromStdString(reply->warningText())); + hasMessage=true; + } + else if(reply->hasInfo()) + { + messageLabel_->showInfo(QString::fromStdString(reply->infoText())); + hasMessage=true; + } +#endif + } + + VFile_ptr f=reply->tmpFile(); + if(f) + { + loadFile(f); + + //browser_->loadFile(f); + //if(f->storageMode() == VFile::DiskStorage) + // hasMessage=false; + + } + + deleteLater(); +} + +void VReportMaker::infoFailed(VReply*) +{ + deleteLater(); +} + +void VReportMaker::loadFile(VFile_ptr file) +{ + if(!file) + { + //clear(); + return; + } + + if(file->storageMode() == VFile::DiskStorage) + { + //loadFile(QString::fromStdString(file_->path())); + UiLog().dbg() << "REPORT " << file->path(); + } + else + { + QString s(file->data()); + //loadText(s,QString::fromStdString(file_->sourcePath()),true); + UiLog().dbg() << "REPORT " << s; + } +} + + + +void VReportMaker::sendReport(VInfo_ptr info) +{ + VReportMaker* maker=new VReportMaker(); + maker->run(info); + //maker will delete itself when the job is done! +} diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/VReportMaker.hpp ecflow-4.11.1/Viewer/ecflowUI/src/VReportMaker.hpp --- ecflow-4.10.0/Viewer/ecflowUI/src/VReportMaker.hpp 1970-01-01 00:00:00.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/VReportMaker.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -0,0 +1,43 @@ +//============================================================================ +// Copyright 2009-2018 ECMWF. +// This software is licensed under the terms of the Apache Licence version 2.0 +// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +// In applying this licence, ECMWF does not waive the privileges and immunities +// granted to it by virtue of its status as an intergovernmental organisation +// nor does it submit to any jurisdiction. +// +//============================================================================ + +#ifndef VREPORTMAKER_HPP +#define VREPORTMAKER_HPP + +#include + +#include "VFile.hpp" +#include "VInfo.hpp" +#include "InfoPresenter.hpp" + +class OutputFileProvider; + +class VReportMaker : public InfoPresenter, public QObject +{ +public: + static void sendReport(VInfo_ptr); + + //From VInfoPresenter + void infoReady(VReply*); + void infoFailed(VReply*); + //void infoProgress(VReply*); + //void infoProgressStart(const std::string& text,int max); + //void infoProgress(const std::string& text,int value); + +protected: + VReportMaker(QObject* parent=0); + void run(VInfo_ptr); + void loadFile(VFile_ptr file); + + OutputFileProvider *infoProvider_; +}; + + +#endif // VREPORTMAKER_HPP diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/VServerSettings.cpp ecflow-4.11.1/Viewer/ecflowUI/src/VServerSettings.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/VServerSettings.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/VServerSettings.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -49,6 +49,7 @@ parNames_[ReadFromDisk]="server.files.readFilesFromDisk"; parNames_[NodeMenuMode]="server.menu.nodeMenuMode"; + parNames_[NodeMenuModeForDefStatus]="server.menu.defStatusMenuModeControl"; parNames_[NotifyAbortedEnabled]="server.notification.aborted.enabled"; parNames_[NotifyAbortedPopup]="server.notification.aborted.popup"; diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/VServerSettings.hpp ecflow-4.11.1/Viewer/ecflowUI/src/VServerSettings.hpp --- ecflow-4.10.0/Viewer/ecflowUI/src/VServerSettings.hpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/VServerSettings.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -25,7 +25,7 @@ enum Param {AutoUpdate, UpdateRate, AdaptiveUpdate,AdaptiveUpdateIncrement,MaxAdaptiveUpdateRate,AdaptiveUpdateMode, MaxOutputFileLines,ReadFromDisk, - NodeMenuMode, + NodeMenuMode,NodeMenuModeForDefStatus, NotifyAbortedEnabled, NotifyAbortedPopup, NotifyAbortedSound, NotifyRestartedEnabled, NotifyRestartedPopup, NotifyRestartedSound, NotifyLateEnabled, NotifyLatePopup, NotifyLateSound, diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/VSettingsLoader.cpp ecflow-4.11.1/Viewer/ecflowUI/src/VSettingsLoader.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/VSettingsLoader.cpp 1970-01-01 00:00:00.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/VSettingsLoader.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -0,0 +1,36 @@ +//============================================================================ +// Copyright 2009-2018 ECMWF. +// This software is licensed under the terms of the Apache Licence version 2.0 +// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +// In applying this licence, ECMWF does not waive the privileges and immunities +// granted to it by virtue of its status as an intergovernmental organisation +// nor does it submit to any jurisdiction. +// +//============================================================================ + +#include "VSettingsLoader.hpp" + +#include + +typedef std::vector Vec; + +static Vec* makers = 0; + +VSettingsLoader::VSettingsLoader() +{ + if(makers == 0) + makers = new Vec(); + + makers->push_back(Vec::value_type(this)); +} + +void VSettingsLoader::process() +{ + if(!makers) + return; + + for(size_t i=0; i < makers->size(); i++) + { + makers->at(i)->loadSettings(); + } +} diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/VSettingsLoader.hpp ecflow-4.11.1/Viewer/ecflowUI/src/VSettingsLoader.hpp --- ecflow-4.10.0/Viewer/ecflowUI/src/VSettingsLoader.hpp 1970-01-01 00:00:00.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/VSettingsLoader.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -0,0 +1,43 @@ +//============================================================================ +// Copyright 2009-2018 ECMWF. +// This software is licensed under the terms of the Apache Licence version 2.0 +// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +// In applying this licence, ECMWF does not waive the privileges and immunities +// granted to it by virtue of its status as an intergovernmental organisation +// nor does it submit to any jurisdiction. +// +//============================================================================ + +#ifndef VSETTINGSLOADER_HPP +#define VSETTINGSLOADER_HPP + +#include + +//This class enables registered objects to read the settings updated with users settings via +//static function "loadSettings()" + +class VSettingsLoader +{ +public: + explicit VSettingsLoader(); + virtual ~VSettingsLoader() {} + + virtual void loadSettings() = 0; + static void process(); + +private: + // No copy allowed + explicit VSettingsLoader(const VSettingsLoader&); + VSettingsLoader& operator=(const VSettingsLoader&); +}; + +template +class SimpleSettingsLoader : public VSettingsLoader +{ +public: + explicit SimpleSettingsLoader() : VSettingsLoader() {} +protected: + void loadSettings() { T::loadSettings();} +}; + +#endif // VSETTINGSLOADER_HPP diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/ZombieItemWidget.cpp ecflow-4.11.1/Viewer/ecflowUI/src/ZombieItemWidget.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/ZombieItemWidget.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/ZombieItemWidget.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -38,6 +38,7 @@ sortModel_=new QSortFilterProxyModel(this); sortModel_->setSourceModel(model_); + sortModel_->setSortRole(Qt::UserRole); zombieView->setModel(sortModel_); diff -Nru ecflow-4.10.0/Viewer/ecflowUI/src/ZombieModel.cpp ecflow-4.11.1/Viewer/ecflowUI/src/ZombieModel.cpp --- ecflow-4.10.0/Viewer/ecflowUI/src/ZombieModel.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/ecflowUI/src/ZombieModel.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -127,7 +127,8 @@ QString id=columns_->id(index.column()); - if(role == Qt::DisplayRole) + //UserRole is used for sorting + if(role == Qt::DisplayRole || role == Qt::UserRole) { if(id == "path") return QString::fromStdString(data_[row].path_to_task()); @@ -136,14 +137,34 @@ else if(id == "tryno") return data_[row].try_no(); else if(id == "duration") - return QString::number(data_[row].duration()) + " s"; - else if(id == "creation") + { + if(role == Qt::DisplayRole) + { + return QString::number(data_[row].duration()) + " s"; + } + //sorting + else + { + return data_[row].duration(); + } + } + else if(id == "creation") { - const boost::posix_time::ptime& t= data_[row].creation_time(); + const boost::posix_time::ptime& t= data_[row].creation_time(); return QString::fromStdString(boost::posix_time::to_simple_string(t)); } else if(id == "allowed") - return QString::number(data_[row].allowed_age()) + " s"; + { + if(role == Qt::DisplayRole) + { + return QString::number(data_[row].allowed_age()) + " s"; + } + //sorting + else + { + return data_[row].allowed_age(); + } + } else if(id == "calls") return data_[row].calls(); else if(id == "action") @@ -156,7 +177,7 @@ return QString::fromStdString(data_[row].process_or_remote_id()); else return QVariant(); - } + } return QVariant(); } diff -Nru ecflow-4.10.0/Viewer/libViewer/src/LocalSocketServer.cpp ecflow-4.11.1/Viewer/libViewer/src/LocalSocketServer.cpp --- ecflow-4.10.0/Viewer/libViewer/src/LocalSocketServer.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/libViewer/src/LocalSocketServer.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -9,6 +9,7 @@ #include "LocalSocketServer.hpp" +#include #include #include #include @@ -29,7 +30,7 @@ //Create the server server_ = new QLocalServer(parent); -#ifdef EFLOW_QT5 +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) //Restrict access to the socket server_->setSocketOptions(QLocalServer::UserAccessOption); #endif diff -Nru ecflow-4.10.0/Viewer/libViewer/src/LogData.hpp ecflow-4.11.1/Viewer/libViewer/src/LogData.hpp --- ecflow-4.10.0/Viewer/libViewer/src/LogData.hpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/libViewer/src/LogData.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -42,9 +42,9 @@ bool isEmpty() const {return size() == 0;} void clear() { refTimeInMs_=0; fileName_.clear(); data_.clear();} - QDateTime date(int idx) const {return - QDateTime::fromMSecsSinceEpoch(refTimeInMs_ + - data_[idx].time_*1000); } + QDateTime date(int idx) const { + return QDateTime::fromMSecsSinceEpoch(refTimeInMs_ + + static_cast(data_[idx].time_)*1000); } QString entry(int idx) const {return QString::fromStdString(data_[idx].entry_);} LogDataItem::Type type(int idx) const {return data_[idx].type_;} diff -Nru ecflow-4.10.0/Viewer/libViewer/src/LogLoadData.cpp ecflow-4.11.1/Viewer/libViewer/src/LogLoadData.cpp --- ecflow-4.10.0/Viewer/libViewer/src/LogLoadData.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/libViewer/src/LogLoadData.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -366,15 +366,19 @@ } void LogLoadDataItem::computeStat(size_t startIndex,size_t endIndex) -{ +{ size_t max=0; size_t sum=0; - for(size_t i=startIndex; i <= endIndex; i++) + + if(childReq_.size() != 0) { - size_t tot=childReq_[i] + userReq_[i]; - sum+=tot; - if(max < tot) - max = tot; + for(size_t i=startIndex; i <= endIndex; i++) + { + size_t tot=childReq_[i] + userReq_[i]; + sum+=tot; + if(max < tot) + max = tot; + } } periodStat_.sumTotal_=sum; @@ -858,7 +862,7 @@ void LogLoadData::computeStat() { - size_t endIndex=(time_.empty())?0:(time_.size()-1); + size_t endIndex=(time_.empty())?-1:(time_.size()-1); computeStat(0,endIndex); } @@ -966,15 +970,16 @@ maxNumOfRows_=numOfRows; numOfRows_=0; + startPos_=getStartPos(logFile,numOfRows); - /// The log file can be massive > 50Mb - ecf::File_r log_file(logFile); - if( !log_file.ok() ) - throw std::runtime_error("LogLoadData::loadLogFile: Could not open log file " + logFile ); - - std::string line; +#if 0 if(numOfRows < 0) { + /// The log file can be massive > 50Mb + ecf::File_r log_file(logFile); + if( !log_file.ok() ) + throw std::runtime_error("LogLoadData::loadLogFile: Could not open log file " + logFile ); + int maxNum=-numOfRows; int cnt=0; std::vector posVec(maxNum,0); @@ -1015,7 +1020,16 @@ } startPos_=posVec[cnt % maxNum]; - log_file.setPos(startPos_); + //log_file.setPos(startPos_); + } +#endif + + /// The log file can be massive > 50Mb + ecf::File_r log_file(logFile); + if( !log_file.ok() ) + { + UiLog().warn() << "LogLoadData::loadLogFile: Could not open log file " << logFile; + return; } //A collector total counts @@ -1031,6 +1045,7 @@ std::vector old_time_stamp; std::map uidCnt; + std::string line; while ( log_file.good() ) { @@ -1094,7 +1109,7 @@ if ( first_open_bracket == std::string::npos) { //std::cout << line << "\n"; - assert(false); + //assert(false); continue; } line.erase(0,first_open_bracket+1); @@ -1103,7 +1118,7 @@ if ( first_closed_bracket == std::string::npos) { //std::cout << line << "\n"; - assert(false); + //assert(false); continue; } std::string time_stamp = line.substr(0, first_closed_bracket); @@ -1216,6 +1231,60 @@ UiLog().dbg() << "REQCNT " << REQCNT; } +std::streamoff LogLoadData::getStartPos(const std::string& logFile, int numOfRows) +{ + std::streamoff startPos=0; + std::string line; + + if(numOfRows < 0) + { + /// The log file can be massive > 50Mb + ecf::File_r log_file(logFile); + if( !log_file.ok() ) + { + UiLog().warn() << "LogLoadData::getStartPos: Could not open log file " << logFile; + return startPos; + } + + int maxNum=-numOfRows; + int cnt=0; + std::vector posVec(maxNum,0); + while(log_file.good()) + { + std::streamoff currentPos=log_file.pos(); + + log_file.getline(line); // default delimiter is /n + + /// We are only interested in Commands (i.e MSG:), and not state changes + if (line.size() < 4) + continue; + + if (line[0] != 'M' || line[1] != 'S' || line[2] != 'G' || line[3] != ':') + continue; + + bool child_cmd = false; + bool user_cmd = false; + if (line.find(ecf::Str::CHILD_CMD()) != std::string::npos) + { + child_cmd = true; + } + else if (line.find(ecf::Str::USER_CMD()) != std::string::npos) + { + user_cmd = true; + } + + if(!child_cmd && !user_cmd) + continue; + + posVec[cnt % maxNum]=currentPos; + cnt++; + } + startPos=posVec[cnt % maxNum]; + } + + return startPos; +} + bool LogLoadData::extract_uid_data(const std::string& line,std::vector& uid_vec) { diff -Nru ecflow-4.10.0/Viewer/libViewer/src/LogLoadData.hpp ecflow-4.11.1/Viewer/libViewer/src/LogLoadData.hpp --- ecflow-4.10.0/Viewer/libViewer/src/LogLoadData.hpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/libViewer/src/LogLoadData.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -192,6 +192,7 @@ std::streamoff startPos() const { return startPos_;} private: + std::streamoff getStartPos(const std::string& logFile, int numOfRows); void getSeries(QLineSeries& series,const LogRequestItem& item,int& maxVal); void getSeries(QLineSeries& series,const std::vector& vals,int& maxVal); void getSeries(QLineSeries& series,const std::vector& vals1, diff -Nru ecflow-4.10.0/Viewer/libViewer/src/LogLoadWidget.cpp ecflow-4.11.1/Viewer/libViewer/src/LogLoadWidget.cpp --- ecflow-4.10.0/Viewer/libViewer/src/LogLoadWidget.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/libViewer/src/LogLoadWidget.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -654,6 +654,23 @@ Q_EMIT dataChanged(startIdx,endIdx); } +void LogLoadRequestModel::selectFirstItem() +{ + unselectAll(); + for(int i=0; i < data_.size(); i++) + { + if(data_[i].rank_ ==0) + { + data_[i].checked_=true; + Q_EMIT checkStateChanged(i,true); + } + } + + QModelIndex startIdx=index(0,0); + QModelIndex endIdx=index(rowCount(),columnCount()-1); + Q_EMIT dataChanged(startIdx,endIdx); +} + void LogLoadRequestModel::setShowColour(bool b) { showColour_=b; @@ -2369,6 +2386,9 @@ //Total addTotal(); + + if(!cmdCtl_.isAnySet()) + cmdCtl_.model_->selectFirstItem(); } void LogCmdSuiteRequestView::buildScanTable(QString& txt,int idx) @@ -2629,6 +2649,9 @@ //Total addTotal(); + + if(!suiteCtl_.isAnySet()) + suiteCtl_.model_->selectFirstItem(); } void LogSuiteCmdRequestView::buildScanTable(QString& txt,int idx) @@ -2892,6 +2915,9 @@ //Total addTotal(); + + if(!uidCtl_.isAnySet()) + uidCtl_.model_->selectFirstItem(); } void LogUidCmdRequestView::buildScanTable(QString& txt,int idx) @@ -3065,7 +3091,6 @@ } } - void LogCmdUidRequestView::addUid(int uidIdx) { QString id=uidChartId(uidIdx); @@ -3151,6 +3176,9 @@ //Total addTotal(); + + if(!cmdCtl_.isAnySet()) + cmdCtl_.model_->selectFirstItem(); } void LogCmdUidRequestView::buildScanTable(QString& txt,int idx) diff -Nru ecflow-4.10.0/Viewer/libViewer/src/LogLoadWidget.hpp ecflow-4.11.1/Viewer/libViewer/src/LogLoadWidget.hpp --- ecflow-4.10.0/Viewer/libViewer/src/LogLoadWidget.hpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/libViewer/src/LogLoadWidget.hpp 2018-10-23 11:41:34.000000000 +0000 @@ -160,6 +160,7 @@ void unselectAll(); void selectAll(); void selectFirstFourItems(); + void selectFirstItem(); protected: QString formatPrecentage(float perc) const; @@ -288,6 +289,7 @@ LogRequestViewControlItem() : model_(0), sortModel_(0), tree_(0) {} void adjustColumnWidth(); + bool isAnySet() const {return plotState_.contains(true);} LogLoadRequestModel* model_; QSortFilterProxyModel* sortModel_; diff -Nru ecflow-4.10.0/Viewer/libViewer/src/LogModel.cpp ecflow-4.11.1/Viewer/libViewer/src/LogModel.cpp --- ecflow-4.10.0/Viewer/libViewer/src/LogModel.cpp 2018-07-24 08:04:37.000000000 +0000 +++ ecflow-4.11.1/Viewer/libViewer/src/LogModel.cpp 2018-10-23 11:41:34.000000000 +0000 @@ -311,7 +311,7 @@ QVariant LogModel::headerData( const int section, const Qt::Orientation orient , const int role ) const { if ( orient != Qt::Horizontal || (role != Qt::DisplayRole && role != Qt::ToolTipRole)) - return QAbstractItemModel::headerData( section, orient, role ); + return QAbstractItemModel::headerData( section, orient, role ); if(role == Qt::DisplayRole) {