From: abn Date: Tue, 15 Jan 2019 13:24:23 +0000 (+0100) Subject: Merge 'oscar/porting_to_V9' branch. X-Git-Tag: V9_4_0rc1~4 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=52070c15a44138cd16c0545bec9e52c11993f544;p=modules%2Fgui.git Merge 'oscar/porting_to_V9' branch. --- diff --git a/src/LightApp/LightApp_OBSelector.cxx b/src/LightApp/LightApp_OBSelector.cxx index 75d1a1621..b2e84dfde 100644 --- a/src/LightApp/LightApp_OBSelector.cxx +++ b/src/LightApp/LightApp_OBSelector.cxx @@ -105,7 +105,9 @@ void LightApp_OBSelector::onSelectionChanged() mySelectedList.clear(); selectionChanged(); QTime t2 = QTime::currentTime(); +#ifdef _DEBUG_ qDebug( QString( "selection time = %1 msecs" ).arg( t1.msecsTo( t2 ) ).toLatin1().constData() ); +#endif } /*! diff --git a/src/SUIT/SUIT_TreeSync.h b/src/SUIT/SUIT_TreeSync.h index 5a0779009..a52b07ee5 100644 --- a/src/SUIT/SUIT_TreeSync.h +++ b/src/SUIT/SUIT_TreeSync.h @@ -131,7 +131,11 @@ TrgItem synchronize( const SrcItem& r1, const TrgItem& r2, const TreeData& td ) const DiffItem& item = *anIt; if ( item.mySrc == td.nullSrc() ) { if ( item.myTrg == td.nullTrg() ) + { +#ifdef _DEBUG_ qDebug( "error: both null" ); +#endif + } else // delete item td.deleteItemWithChildren( item.myTrg ); diff --git a/tools/CurvePlot/CMakeLists.txt b/tools/CurvePlot/CMakeLists.txt index 22c1fb0cd..45c12f8f1 100644 --- a/tools/CurvePlot/CMakeLists.txt +++ b/tools/CurvePlot/CMakeLists.txt @@ -29,12 +29,12 @@ CMAKE_POLICY(SET CMP0003 NEW) # Project name, upper case STRING(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UC) -SET(${PROJECT_NAME_UC}_MAJOR_VERSION 7) -SET(${PROJECT_NAME_UC}_MINOR_VERSION 6) +SET(${PROJECT_NAME_UC}_MAJOR_VERSION 9) +SET(${PROJECT_NAME_UC}_MINOR_VERSION 2) SET(${PROJECT_NAME_UC}_PATCH_VERSION 0) SET(${PROJECT_NAME_UC}_VERSION ${${PROJECT_NAME_UC}_MAJOR_VERSION}.${${PROJECT_NAME_UC}_MINOR_VERSION}.${${PROJECT_NAME_UC}_PATCH_VERSION}) -SET(${PROJECT_NAME_UC}_VERSION_DEV 1) +SET(${PROJECT_NAME_UC}_VERSION_DEV 0) # User options # ============ @@ -106,20 +106,11 @@ FIND_PACKAGE(SalomePythonInterp REQUIRED) FIND_PACKAGE(SalomePythonLibs REQUIRED) FIND_PACKAGE(SalomeNumPySciPy REQUIRED) -# Qt4 -FIND_PACKAGE(SalomeQt4 REQUIRED COMPONENTS QtCore QtGui) -INCLUDE(${QT_USE_FILE}) +# Qt +FIND_PACKAGE(SalomeQt5 REQUIRED) +FIND_PACKAGE(SalomePyQt5 REQUIRED) # Optional products: - -IF(SALOME_BUILD_DOC) -# FIND_PACKAGE(SalomeDoxygen) -# FIND_PACKAGE(SalomeSphinx) -# SALOME_LOG_OPTIONAL_PACKAGE(Doxygen SALOME_BUILD_DOC) -# SALOME_LOG_OPTIONAL_PACKAGE(Sphinx SALOME_BUILD_DOC) -# ADD_DEFINITIONS(-DDOXYGEN_IS_OK) -ENDIF() - IF(SALOME_BUILD_TESTS) ENABLE_TESTING() ENDIF() @@ -155,12 +146,15 @@ ENDIF() # Specific to CURVEPLOT: SET(SALOME_CURVEPLOT_INSTALL_RES_DATA "${SALOME_INSTALL_RES}/curveplot" CACHE PATH "Install path: SALOME CURVEPLOT specific data") -# Package installation path (lib/python2.7/...) +# Package installation path (lib/python/...) SET(SALOME_CURVEPLOT_INSTALL_PYTHON ${SALOME_INSTALL_PYTHON}/curveplot CACHE INTERNAL "Install path: SALOME CURVEPLOT Python packages" FORCE) SET(SALOME_CURVEPLOT_INSTALL_SCRIPT_PYTHON ${SALOME_INSTALL_SCRIPT_PYTHON} CACHE INTERNAL "Install path: SALOME CURVEPLOT Python main entry points" FORCE) +SET(CRVPLOT_TEST_INSTALL ${CMAKE_BINARY_DIR}/local/curveplot) +SET(PYQTSIDE_TEST_INSTALL ${CMAKE_BINARY_DIR}/local/pyqtside) + # Sources # ======== ADD_SUBDIRECTORY(src) @@ -192,25 +186,25 @@ EXPORT(TARGETS ${_${PROJECT_NAME}_exposed_targets} # Ensure the variables are always defined for the configure: SET(KERNEL_ROOT_DIR "${KERNEL_ROOT_DIR}") SET(GUI_ROOT_DIR "${GUI_ROOT_DIR}") -SET(QT4_ROOT_DIR "${QT4_ROOT_DIR}") -SET(PYQT4_ROOT_DIR "${PYQT4_ROOT_DIR}") +SET(QT5_ROOT_DIR "${QT5_ROOT_DIR}") +SET(PYQT5_ROOT_DIR "${PYQT5_ROOT_DIR}") SET(PYTHON_ROOT_DIR "${PYTHON_ROOT_DIR}") SET(CONF_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/include" "${PROJECT_BINARY_DIR}/include") # Build variables that will be expanded when configuring SalomeConfig.cmake: -SALOME_CONFIGURE_PREPARE(PyQt4 Qt4 Python) +SALOME_CONFIGURE_PREPARE(PyQt5 Qt5 Python) CONFIGURE_PACKAGE_CONFIG_FILE(${PROJECT_NAME}Config.cmake.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake INSTALL_DESTINATION "${SALOME_INSTALL_CMAKE_LOCAL}" PATH_VARS CONF_INCLUDE_DIRS SALOME_INSTALL_CMAKE_LOCAL CMAKE_INSTALL_PREFIX - KERNEL_ROOT_DIR GUI_ROOT_DIR QT4_ROOT_DIR PYQT4_ROOT_DIR PYTHON_ROOT_DIR) + KERNEL_ROOT_DIR GUI_ROOT_DIR QT5_ROOT_DIR PYQT5_ROOT_DIR PYTHON_ROOT_DIR) WRITE_BASIC_PACKAGE_VERSION_FILE(${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake VERSION ${${PROJECT_NAME_UC}_VERSION} COMPATIBILITY AnyNewerVersion) - + # Install the CMake configuration files: INSTALL(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" @@ -222,4 +216,4 @@ IF(NOT SALOME_CURVEPLOT_STANDALONE) INSTALL(EXPORT ${PROJECT_NAME}TargetGroup DESTINATION "${SALOME_INSTALL_CMAKE_LOCAL}" FILE ${PROJECT_NAME}Targets.cmake) ENDIF() - + diff --git a/tools/CurvePlot/SalomeCURVEPLOTConfig.cmake.in b/tools/CurvePlot/SalomeCURVEPLOTConfig.cmake.in index 9fbef2ed0..0a6858505 100644 --- a/tools/CurvePlot/SalomeCURVEPLOTConfig.cmake.in +++ b/tools/CurvePlot/SalomeCURVEPLOTConfig.cmake.in @@ -53,8 +53,8 @@ IF(SALOME_CURVEPLOT_STANDALONE) SET_AND_CHECK(GUI_ROOT_DIR_EXP "@PACKAGE_GUI_ROOT_DIR@") ENDIF() -SET_AND_CHECK(QT4_ROOT_DIR_EXP "@PACKAGE_QT4_ROOT_DIR@") -SET_AND_CHECK(PYQT4_ROOT_DIR_EXP "@PACKAGE_PYQT4_ROOT_DIR@") +SET_AND_CHECK(QT5_ROOT_DIR_EXP "@PACKAGE_QT5_ROOT_DIR@") +SET_AND_CHECK(PYQT5_ROOT_DIR_EXP "@PACKAGE_PYQT5_ROOT_DIR@") SET_AND_CHECK(PYTHON_ROOT_DIR_EXP "@PACKAGE_PYTHON_ROOT_DIR@") diff --git a/tools/CurvePlot/src/cpp/CurvePlot.cxx b/tools/CurvePlot/src/cpp/CurvePlot.cxx index 0d54792e5..d1a37150e 100644 --- a/tools/CurvePlot/src/cpp/CurvePlot.cxx +++ b/tools/CurvePlot/src/cpp/CurvePlot.cxx @@ -21,7 +21,9 @@ #include -#define PY_ARRAY_UNIQUE_SYMBOL CURVEPLOT_ARRAY_API // see initializeCurvePlot() +// see https://docs.scipy.org/doc/numpy/reference/c-api.array.html?highlight=import_array +// and https://docs.scipy.org/doc/numpy-1.15.0/reference/c-api.deprecations.html +#define PY_ARRAY_UNIQUE_SYMBOL CURVEPLOT_ARRAY_API #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION #include #include @@ -52,12 +54,13 @@ namespace CURVEPLOT /** * To be called before doing anything */ - void InitializeCurvePlot() + void* InitializeCurvePlot() { PyLockWrapper lock; // TODO: discuss where the below should really happen: // doc: http://docs.scipy.org/doc/numpy/reference/c-api.array.html#importing-the-api - import_array(); // a macro really! + import_array(); // a macro really which contains a return + return NULL; } class ColumnVector::Internal @@ -153,9 +156,11 @@ namespace CURVEPLOT PyObject_CallMethod((PyObject *)_impl->_npArray, (char *)"__str__", NULL) ); // Now extract the returned string - if(!PyString_Check(ret_py)) + if(!PyUnicode_Check(ret_py)) throw Exception("CurvePlot::toStdString(): Unexpected returned type!"); - ret_str = std::string(PyString_AsString(ret_py)); + Py_ssize_t size; + char *ptr = PyUnicode_AsUTF8AndSize(ret_py, &size); + ret_str = std::string(ptr); } return ret_str; } @@ -188,13 +193,13 @@ namespace CURVEPLOT CurvePlot::CurvePlot(bool test_mode) { - // TODO: do use an intermediate variable '__cont', but use directly Py***CallMethod() + // TODO: do not use an intermediate variable '__cont', but use directly Py***CallMethod() _impl = new Internal(); { PyLockWrapper lock; std::string code; if (test_mode) - code = std::string("import curveplot; from SalomePyQt_MockUp import SalomePyQt;") + + code = std::string("import curveplot; from curveplot.SalomePyQt_MockUp import SalomePyQt;") + std::string("__cont=curveplot.PlotController.GetInstance(sgPyQt=SalomePyQt())"); else code = std::string("import curveplot;")+ @@ -266,13 +271,13 @@ namespace CURVEPLOT if(!PyTuple_Check(ret)) throw Exception("CurvePlot::AddCurve(): Unexpected returned type!"); PyObject * o1 = PyTuple_GetItem(ret, 0); - if (!PyInt_Check(o1)) + if (!PyLong_Check(o1)) throw Exception("CurvePlot::AddCurve(): Unexpected returned type!"); - PlotID curveId = PyInt_AsLong(o1); + PlotID curveId = PyLong_AsLong(o1); PyObject * o2 = PyTuple_GetItem(ret, 1); - if (!PyInt_Check(o2)) + if (!PyLong_Check(o2)) throw Exception("CurvePlot::AddCurve(): Unexpected returned type!"); - plot_set_id = PyInt_AsLong(o2); + plot_set_id = PyLong_AsLong(o2); return curveId; } diff --git a/tools/CurvePlot/src/cpp/CurvePlot.hxx b/tools/CurvePlot/src/cpp/CurvePlot.hxx index aad744708..92b86802b 100644 --- a/tools/CurvePlot/src/cpp/CurvePlot.hxx +++ b/tools/CurvePlot/src/cpp/CurvePlot.hxx @@ -32,7 +32,7 @@ namespace CURVEPLOT /** * This function should be called before doing anything in the CURVEPLOT namespace. */ - void InitializeCurvePlot(); + void* InitializeCurvePlot(); class ColumnVector { diff --git a/tools/CurvePlot/src/cpp/test/CMakeLists.txt b/tools/CurvePlot/src/cpp/test/CMakeLists.txt index 436ffa7ff..77d01edb7 100644 --- a/tools/CurvePlot/src/cpp/test/CMakeLists.txt +++ b/tools/CurvePlot/src/cpp/test/CMakeLists.txt @@ -44,7 +44,7 @@ SET(_other_SOURCES # --- rules --- # sources / moc wrappings -QT4_WRAP_CPP(_moc_SOURCES ${_moc_HEADERS}) +QT5_WRAP_CPP(_moc_SOURCES ${_moc_HEADERS}) ADD_EXECUTABLE(test_curveplot ${_other_SOURCES} ${_moc_SOURCES}) TARGET_LINK_LIBRARIES(test_curveplot ${_link_LIBRARIES}) diff --git a/tools/CurvePlot/src/cpp/test/test_curveplot.cxx b/tools/CurvePlot/src/cpp/test/test_curveplot.cxx index 1114fd614..26b2d2ee8 100644 --- a/tools/CurvePlot/src/cpp/test/test_curveplot.cxx +++ b/tools/CurvePlot/src/cpp/test/test_curveplot.cxx @@ -19,9 +19,10 @@ // Author : Adrien BRUNETON // +#include // GUI - must come first to avoid conflict on the token "slots" defined in both Qt and Python ... + #include "test_curveplot.hxx" -#include // GUI #include #include #include "CurvePlot.hxx" @@ -70,14 +71,20 @@ void TestCurvePlot::onClicked() std::cout << "setting X label " << CurvePlot::SetXLabel("tôtô") << std::endl; } +/*! + * Similar to: SUIT_PYTHON::init_python() from GUI + * or KERNEL_PYTHON::init_python() from KERNEL + */ void initPython() { if (!Py_IsInitialized()){ // Python is not initialized Py_Initialize(); // Initialize the interpreter - PyEval_InitThreads(); // Create (and acquire) the Python global interpreter lock (GIL) - PyEval_ReleaseLock(); + PyRun_SimpleString("import threading\n"); + + PyThreadState *pts = PyGILState_GetThisThreadState(); + PyEval_ReleaseThread(pts); } } @@ -107,7 +114,7 @@ int main(int argc, char ** argv) mw.resize((int)(dw->width()*0.25), (int)(dw->height()*0.7)); mw.show(); - initPython(); + initPython(); // mimic SALOME Python's initialisation. InitializeCurvePlot(); { diff --git a/tools/CurvePlot/src/python/controller/CMakeLists.txt b/tools/CurvePlot/src/python/controller/CMakeLists.txt index e5636a8a8..b7e6bca21 100644 --- a/tools/CurvePlot/src/python/controller/CMakeLists.txt +++ b/tools/CurvePlot/src/python/controller/CMakeLists.txt @@ -17,12 +17,25 @@ # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # +SET(SALOME_CURVEPLOT_TEST_MODE "0") SALOME_CONFIGURE_FILE(utils.py.in ${CMAKE_CURRENT_BINARY_DIR}/utils.py) +# For test purposes: +SET(SALOME_CURVEPLOT_TEST_MODE "1") +SALOME_CONFIGURE_FILE(utils.py.in ${CMAKE_CURRENT_BINARY_DIR}/utils_test.py) +SET(SALOME_CURVEPLOT_TEST_MODE "0") + SET(_all_lib_SCRIPTS PlotController.py __init__.py - ${CMAKE_CURRENT_BINARY_DIR}/utils.py ) +SET(_util_SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/utils.py) + SALOME_INSTALL_SCRIPTS("${_all_lib_SCRIPTS}" ${SALOME_CURVEPLOT_INSTALL_PYTHON}) +SALOME_INSTALL_SCRIPTS("${_util_SCRIPT}" ${SALOME_CURVEPLOT_INSTALL_PYTHON}) + +# For test purposes +FILE(COPY ${_all_lib_SCRIPTS} DESTINATION ${CRVPLOT_TEST_INSTALL}) +FILE(COPY ${CMAKE_CURRENT_BINARY_DIR}/utils_test.py DESTINATION ${CRVPLOT_TEST_INSTALL}) +FILE(RENAME ${CRVPLOT_TEST_INSTALL}/utils_test.py ${CRVPLOT_TEST_INSTALL}/utils.py) diff --git a/tools/CurvePlot/src/python/controller/PlotController.py b/tools/CurvePlot/src/python/controller/PlotController.py index 4967fe6b1..267eb3acd 100644 --- a/tools/CurvePlot/src/python/controller/PlotController.py +++ b/tools/CurvePlot/src/python/controller/PlotController.py @@ -17,23 +17,23 @@ # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # -from CurveBrowserView import CurveBrowserView -from PlotManager import PlotManager -from CurveTabsView import CurveTabsView -from CurveModel import CurveModel -from TableModel import TableModel -from utils import Logger +from .CurveBrowserView import CurveBrowserView +from .PlotManager import PlotManager +from .CurveTabsView import CurveTabsView +from .CurveModel import CurveModel +from .TableModel import TableModel +from .utils import Logger import numpy as np class PlotController(object): """ Controller for 2D curve plotting functionalities. """ __UNIQUE_INSTANCE = None # my poor impl. of a singleton - + ## For testing purposes: WITH_CURVE_BROWSER = True WITH_CURVE_TABS = True - + def __init__(self, sgPyQt=None): if self.__UNIQUE_INSTANCE is None: self.__trueInit(sgPyQt) @@ -50,32 +50,32 @@ class PlotController(object): self._blockNotifications = False self._blockViewClosing = False self._callbacks = [] - + self._plotManager = PlotManager(self) - + if self.WITH_CURVE_BROWSER: self._curveBrowserView = CurveBrowserView(self) self.associate(self._plotManager, self._curveBrowserView) else: - self._curveBrowserView = None + self._curveBrowserView = None if self.WITH_CURVE_TABS: self._curveTabsView = CurveTabsView(self) self.associate(self._plotManager, self._curveTabsView) else: self._curveTabsView = None PlotController.__UNIQUE_INSTANCE = self - + @classmethod def GetInstance(cls, sgPyQt=None): if cls.__UNIQUE_INSTANCE is None: # First instanciation: PlotController(sgPyQt) return cls.__UNIQUE_INSTANCE - + @classmethod def Destroy(cls): cls.__UNIQUE_INSTANCE = None - + def setFixedSizeWidget(self): """ For testing purposes - ensure visible Qt widgets have a fixed size. """ @@ -83,7 +83,7 @@ class PlotController(object): self._curveBrowserView.treeWidget.resize(100,200) if self.WITH_CURVE_TABS: self._sgPyQt._tabWidget.resize(600,600) - + def associate(self, model, view): """ Associates a model to a view, and sets the view to listen to this model @@ -92,28 +92,28 @@ class PlotController(object): :param model: Model -- The model to be associated to the view. :param view: View -- The view. - """ + """ if model is None or view is None: return - + view.setModel(model) self.setModelListener(model, view) - + def setModelListener(self, model, view): """ Sets a view to listen to all changes of the given model """ l = self._modelViews.setdefault(model, []) if not view in l and view is not None: - l.append(view) - + l.append(view) + def removeModelListeners(self, model): """ Removes the given model from the list of listeners. All views previously connected to this model won't receive its update notification anymore. """ self._modelViews.pop(model) - + def notify(self, model, what=""): """ Notifies the view when model changes. @@ -122,10 +122,10 @@ class PlotController(object): """ if model is None or self._blockNotifications: return - + if model not in self._modelViews: return - + for view in self._modelViews[model]: method = "on%s" % what if what != "" and what is not None and hasattr(view, method): @@ -133,27 +133,27 @@ class PlotController(object): elif hasattr(view, "update"): # Generic update: view.update() - + def setBrowserContextualMenu(self, menu): """ Provide a menu to be contextually shown in the curve browser """ self._browserContextualMenu = menu - + def setCurvePlotRequestingClose(self, bool): self._blockViewClosing = bool - + def onCurrentCurveChange(self): ps = self._plotManager.getCurrentPlotSet() if not ps is None: crv = ps.getCurrentCurve() if crv is not None: - crv_id = crv.getID() + crv_id = crv.getID() for c in self._callbacks: c(crv_id) - + ##### ##### Public static API ##### - + @classmethod def AddCurve(cls, x, y, curve_label="", x_label="", y_label="", append=True): """ Add a new curve and make the plot set where it is drawn the active one. @@ -167,7 +167,7 @@ class PlotController(object): @param append whether to add the curve to the active plot set (default) or into a new one. @return the id of the created curve, and the id of the corresponding plot set. """ - from XYView import XYView + from .XYView import XYView control = cls.GetInstance() pm = control._plotManager t = TableModel(control) @@ -177,18 +177,18 @@ class PlotController(object): prevLock = pm.isRepaintLocked() if not prevLock: pm.lockRepaint() - curveID, plotSetID = control.plotCurveFromTable(t, x_col_index=0, y_col_index=1, + curveID, plotSetID = control.plotCurveFromTable(t, x_col_index=0, y_col_index=1, curve_label=curve_label, append=append) ps = pm._plotSets[plotSetID] if x_label != "": ps.setXLabel(x_label) - if y_label != "": + if y_label != "": ps.setYLabel(y_label) if not prevLock: pm.unlockRepaint() return curveID, plotSetID - @classmethod + @classmethod def ExtendCurve(cls, crv_id, x, y): """ Add new points to an already created curve @raise if invalid plot set ID is given @@ -200,7 +200,7 @@ class PlotController(object): crv_mod = ps._curves[crv_id] data = np.transpose(np.vstack([x, y])) crv_mod.extendData(data) - + @classmethod def ResetCurve(cls, crv_id): """ Reset a given curve: all data are cleared, but the curve is still @@ -214,7 +214,7 @@ class PlotController(object): raise ValueError("Curve ID (%d) not found for reset!" % crv_id) crv_mod = ps._curves[crv_id] crv_mod.resetData() - + @classmethod def AddPlotSet(cls, title=""): """ Creates a new plot set (a tab with several curves) and returns its ID. A title can be passed, @@ -229,7 +229,7 @@ class PlotController(object): if title != "": ps.setTitle(title) return ps.getID() - + @classmethod def CopyCurve(cls, curve_id, plot_set_id): """ Copy a given curve to a given plot set ID @@ -248,7 +248,7 @@ class PlotController(object): control.setModelListener(new_crv, control._curveBrowserView) plot_set_tgt.addCurve(new_crv) return new_crv.getID() - + @classmethod def DeleteCurve(cls, curve_id=-1): """ By default, delete the current curve, if any. Otherwise do nothing. @@ -261,8 +261,8 @@ class PlotController(object): curve_id = cls.GetCurrentCurveID() if curve_id == -1: # No current curve, do nothing - return -1 - + return -1 + psID = cls.GetPlotSetID(curve_id) if psID == -1: raise ValueError("Curve ID (%d) not found for deletion!" % curve_id) @@ -270,7 +270,7 @@ class PlotController(object): control._plotManager._plotSets[psID].removeCurve(curve_id) control.removeModelListeners(crv) return curve_id - + @classmethod def DeletePlotSet(cls, plot_set_id=-1): """ By default, delete the current plot set, if any. Otherwise do nothing. @@ -290,11 +290,11 @@ class PlotController(object): for _, crv in list(ps._curves.items()): control.removeModelListeners(crv) control.removeModelListeners(ps) - psets = control._plotManager._plotSets + psets = control._plotManager._plotSets if len(psets): control._plotManager.setCurrentPlotSet(list(psets.keys())[-1]) return plot_set_id - + @classmethod def usedMem(cls): import gc @@ -302,7 +302,7 @@ class PlotController(object): import resource m = resource.getrusage(resource.RUSAGE_SELF)[2]*resource.getpagesize()/1e6 print("** Used memory: %.2f Mb" % m) - + @classmethod def DeleteCurrentItem(cls): """ Delete currently active item, be it a plot set or a curve. @@ -315,7 +315,7 @@ class PlotController(object): if ps_id == -1: Logger.Info("PlotController.DeleteCurrentItem(): nothing selected, nothing to delete!") return True,-1 - # Do we delete a curve or a full plot set + # Do we delete a curve or a full plot set if c_id == -1: cls.DeletePlotSet(ps_id) ret = True, ps_id @@ -323,7 +323,7 @@ class PlotController(object): cls.DeleteCurve(c_id) ret = False, c_id return ret - + @classmethod def ClearPlotSet(cls, ps_id=-1): """ Clear all curves in a given plot set. By default clear the current plot set without deleting it, @@ -341,7 +341,7 @@ class PlotController(object): raise ValueError("Invalid plot set ID (%d)!" % ps_id) ps.eraseAll() return ps_id - + # @classmethod # def ClearAll(cls): # # TODO: optimize @@ -349,7 +349,7 @@ class PlotController(object): # ids = pm._plotSets.keys() # for i in ids: # cls.DeletePlotSet(i) - + @classmethod def SetXLabel(cls, x_label, plot_set_id=-1): """ By default set the X axis label for the current plot set, if any. Otherwise do nothing. @@ -360,14 +360,14 @@ class PlotController(object): plot_set_id = cls.GetCurrentPlotSetID() if plot_set_id == -1: # Do nothing - return False + return False ps = pm._plotSets.get(plot_set_id, None) if ps is None: raise Exception("Invalid plot set ID (%d)!" % plot_set_id) ps.setXLabel(x_label) return True - - @classmethod + + @classmethod def SetYLabel(cls, y_label, plot_set_id=-1): """ By default set the Y axis label for the current plot set, if any. Otherwise do nothing. @return True if the label was set @@ -377,14 +377,14 @@ class PlotController(object): plot_set_id = cls.GetCurrentPlotSetID() if plot_set_id == -1: # Do nothing - return False + return False ps = pm._plotSets.get(plot_set_id, None) if ps is None: raise Exception("Invalid plot set ID (%d)!" % plot_set_id) ps.setYLabel(y_label) return True - - @classmethod + + @classmethod def SetPlotSetTitle(cls, title, plot_set_id=-1): """ By default set the title for the current plot set, if any. Otherwise do nothing. @return True if the title was set @@ -394,13 +394,13 @@ class PlotController(object): plot_set_id = cls.GetCurrentPlotSetID() if plot_set_id == -1: # Do nothing - return False + return False ps = pm._plotSets.get(plot_set_id, None) if ps is None: raise Exception("Invalid plot set ID (%d)!" % plot_set_id) ps.setTitle(title) return True - + @classmethod def GetPlotSetID(cls, curve_id): """ @return plot set id for a given curve or -1 if invalid curve ID @@ -410,17 +410,17 @@ class PlotController(object): if cps is None: return -1 return cps.getID() - + @classmethod def GetPlotSetIDByName(cls, name): """ @return the first plot set whose name matches the provided name. Otherwise returns -1 - """ + """ pm = cls.GetInstance()._plotManager for _, ps in list(pm._plotSets.items()): if ps._title == name: return ps.getID() return -1 - + @classmethod def GetAllPlotSets(cls): """ @return two lists: plot set names, and corresponding plot set IDs @@ -428,12 +428,12 @@ class PlotController(object): pm = cls.GetInstance()._plotManager it = list(pm._plotSets.items()) ids, inst, titles = [], [], [] - if len(it): - ids, inst = list(zip(*it)) + if len(it): + ids, inst = list(zip(*it)) if len(inst): titles = [i.getTitle() for i in inst] return list(ids), titles - + @classmethod def GetCurrentCurveID(cls): """ @return current curve ID or -1 if no curve is currently active @@ -443,8 +443,8 @@ class PlotController(object): if crv is None: return -1 return crv.getID() - - @classmethod + + @classmethod def GetCurrentPlotSetID(cls): """ @return current plot set ID or -1 if no plot set is currently active """ @@ -452,7 +452,7 @@ class PlotController(object): cps = control._plotManager.getCurrentPlotSet() if cps is None: return -1 - return cps.getID() + return cps.getID() @classmethod def SetCurrentPlotSet(cls, ps_id): @@ -489,7 +489,7 @@ class PlotController(object): if cls.__UNIQUE_INSTANCE is not None: raise Exception("ToggleCurveBrowser() must be invoked before doing anything in plot2D!") cls.WITH_CURVE_BROWSER = active - + @classmethod def IsValidPlotSetID(cls, plot_set_id): """ @@ -548,11 +548,11 @@ class PlotController(object): ] @raise if invalid curve ID or marker """ - from XYView import XYView - from CurveView import CurveView + from .XYView import XYView + from .CurveView import CurveView if not marker in XYView.CURVE_MARKERS: raise ValueError("Invalid marker: '%s'" % marker) - + cont = cls.GetInstance() for mod, views in list(cont._modelViews.items()): if isinstance(mod, CurveModel) and mod.getID() == crv_id: @@ -563,7 +563,7 @@ class PlotController(object): v._parentXYView.repaint() v._parentXYView.showHideLegend() found = True - + if not found: raise Exception("Invalid curve ID or curve currently not displayed (curve_id=%d)!" % crv_id) @@ -581,9 +581,9 @@ class PlotController(object): @classmethod def __XYViewOperation(cls, func, ps_id, args, kwargs): """ Private. To factorize methods accessing the XYView to change a display element. """ - from XYPlotSetModel import XYPlotSetModel - from XYView import XYView - + from .XYPlotSetModel import XYPlotSetModel + from .XYView import XYView + cont = cls.GetInstance() for mod, views in list(cont._modelViews.items()): if isinstance(mod, XYPlotSetModel) and mod.getID() == ps_id: @@ -614,7 +614,7 @@ class PlotController(object): """ args, kwargs = [log], {} cls.__XYViewOperation("setYLog", ps_id, args, kwargs) - + @classmethod def SetXSciNotation(cls, ps_id, sciNotation=False): """ Change the format (scientific notation or not) of the X axis. @@ -624,7 +624,7 @@ class PlotController(object): """ args, kwargs = [sciNotation], {} cls.__XYViewOperation("setXSciNotation", ps_id, args, kwargs) - + @classmethod def SetYSciNotation(cls, ps_id, sciNotation=False): """ Change the format (scientific notation or not) of the Y axis. @@ -644,7 +644,7 @@ class PlotController(object): """ args, kwargs = [visible], {} cls.__XYViewOperation("setLegendVisible", ps_id, args, kwargs) - + ### ### More advanced functions @@ -653,28 +653,28 @@ class PlotController(object): def RegisterCallback(cls, callback): cont = cls.GetInstance() cont._callbacks.append(callback) - + @classmethod def ClearCallbacks(cls): cont = cls.GetInstance() cont._callbacks = [] - + @classmethod def LockRepaint(cls): control = cls.GetInstance() control._plotManager.lockRepaint() - + @classmethod def UnlockRepaint(cls): control = cls.GetInstance() - control._plotManager.unlockRepaint() - + control._plotManager.unlockRepaint() + def createTable(self, data, table_name="table"): t = TableModel(self) t.setData(data) t.setTitle(table_name) return t - + def plotCurveFromTable(self, table, x_col_index=0, y_col_index=1, curve_label="", append=True): """ :returns: a tuple containing the unique curve ID and the plot set ID @@ -690,15 +690,15 @@ class PlotController(object): cps_title = None cps = self._plotManager.getCurrentPlotSet() - + cm = CurveModel(self, table, y_col_index) cm.setXAxisIndex(x_col_index) - + # X axis label tix = table.getColumnTitle(x_col_index) if tix != "": cps.setXLabel(tix) - + # Curve label if curve_label != "": cm.setTitle(curve_label) @@ -709,21 +709,21 @@ class PlotController(object): # Plot set title if cps_title != "" and cps_title is not None: - Logger.Debug("about to set title to: " + cps_title) + Logger.Debug("about to set title to: " + cps_title) cps.setTitle(cps_title) - + cps.addCurve(cm) mp = self._curveTabsView.mapModId2ViewId() xyview_id = mp[cps.getID()] xyview = self._curveTabsView._XYViews[xyview_id] - + if cps_title is None: # no plot set was created above self._plotManager.setCurrentPlotSet(cps.getID()) - + # Make CurveBrowser and CurveView depend on changes in the curve itself: self.setModelListener(cm, self._curveBrowserView) self.setModelListener(cm, xyview._curveViews[cm.getID()]) # Upon change on the curve also update the full plot, notably for the auto-fit and the legend: self.setModelListener(cm, xyview) - + return cm.getID(),cps.getID() diff --git a/tools/CurvePlot/src/python/controller/__init__.py b/tools/CurvePlot/src/python/controller/__init__.py index 7c79ebaf3..611ba7ff8 100644 --- a/tools/CurvePlot/src/python/controller/__init__.py +++ b/tools/CurvePlot/src/python/controller/__init__.py @@ -25,19 +25,19 @@ try: # and the Bitstream font which is the first one by default. Try to use DejaVu which is more # comprehensive. ## !!Order of the sequence below is highly sensitive!! - import pyqtside # will trigger the PySide/PyQt4 switch + import pyqtside # will trigger the PySide/PyQt switch import matplotlib - matplotlib.use('Qt4Agg') - import matplotlib.pyplot as plt # must come after the PySide/PyQt4 switch! + matplotlib.use('Qt5Agg') + import matplotlib.pyplot as plt # must come after the PySide/PyQt switch! plt.rcParams['font.sans-serif'].insert(0, "DejaVu Sans") except: - print("Warning: could not switch matplotlib to 'Qt4agg' backend. Some characters might be displayed improperly!") + print("Warning: could not switch matplotlib to 'Qt5agg' backend. Some characters might be displayed improperly!") from .PlotController import PlotController -from TableModel import TableModel -from CurveModel import CurveModel -from PlotManager import PlotManager -from XYPlotSetModel import XYPlotSetModel +from .TableModel import TableModel +from .CurveModel import CurveModel +from .PlotManager import PlotManager +from .XYPlotSetModel import XYPlotSetModel ## The static API of PlotController is the main interface of the package and is hence exposed at package level: AddCurve = PlotController.AddCurve diff --git a/tools/CurvePlot/src/python/controller/utils.py.in b/tools/CurvePlot/src/python/controller/utils.py.in index e2f0d2778..f70feed06 100644 --- a/tools/CurvePlot/src/python/controller/utils.py.in +++ b/tools/CurvePlot/src/python/controller/utils.py.in @@ -78,20 +78,20 @@ class Logger(object): def trQ(tag, context="CURVEPLOT"): """ @return a QString read from the translation file """ - from pyqtside.QtGui import QApplication + from pyqtside.QtWidgets import QApplication return QApplication.translate(context, tag) def trU(tag, context="CURVEPLOT"): """ @return same as above, but returns a Python unicode string. """ qs = trQ(tag, context) - return unicode(qs, 'utf-8') + return str(qs, 'utf-8') def toUnicodeWithWarning(s, method_name): try: - s = unicode(s) + s = str(s) except: Logger.Warning("%s - warning, passing non-unicode, non-ASCII string '%s'! Trying to convert myself to UTF-8 ..." % (method_name, s)) - s = unicode(s, 'utf-8') + s = str(s, 'utf-8') return s def completeResPath(fileName): @@ -100,5 +100,7 @@ def completeResPath(fileName): rd = os.environ.get("CURVEPLOT_ROOT_DIR", None) if rd is None: raise Exception("CURVEPLOT_ROOT_DIR is not defined!") + if @SALOME_CURVEPLOT_TEST_MODE@: # do not remove automatically modified in CMake config + subPath = "@CRVPLOT_TEST_INSTALL@" filePath = os.path.join(rd, subPath, fileName) return filePath diff --git a/tools/CurvePlot/src/python/model/CMakeLists.txt b/tools/CurvePlot/src/python/model/CMakeLists.txt index 4ebc34f0a..7101e91aa 100644 --- a/tools/CurvePlot/src/python/model/CMakeLists.txt +++ b/tools/CurvePlot/src/python/model/CMakeLists.txt @@ -24,5 +24,8 @@ SET(_all_lib_SCRIPTS PlotManager.py XYPlotSetModel.py ) - + SALOME_INSTALL_SCRIPTS("${_all_lib_SCRIPTS}" ${SALOME_CURVEPLOT_INSTALL_PYTHON}) + +# For test purposes +FILE(COPY ${_all_lib_SCRIPTS} DESTINATION ${CRVPLOT_TEST_INSTALL}) diff --git a/tools/CurvePlot/src/python/model/CurveModel.py b/tools/CurvePlot/src/python/model/CurveModel.py index ce39144a0..73b2bdf5a 100644 --- a/tools/CurvePlot/src/python/model/CurveModel.py +++ b/tools/CurvePlot/src/python/model/CurveModel.py @@ -17,8 +17,8 @@ # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # -from Model import Model -from utils import toUnicodeWithWarning +from .Model import Model +from .utils import toUnicodeWithWarning class CurveModel(Model): def __init__(self, controller, table=None, index=-1): diff --git a/tools/CurvePlot/src/python/model/PlotManager.py b/tools/CurvePlot/src/python/model/PlotManager.py index 5d8187976..5bf00384d 100644 --- a/tools/CurvePlot/src/python/model/PlotManager.py +++ b/tools/CurvePlot/src/python/model/PlotManager.py @@ -17,9 +17,9 @@ # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # -from Model import Model -from XYPlotSetModel import XYPlotSetModel -from utils import Logger +from .Model import Model +from .XYPlotSetModel import XYPlotSetModel +from .utils import Logger class PlotManager(Model): def __init__(self, controller): @@ -30,52 +30,52 @@ class PlotManager(Model): # when removing elemetns, we can easily re-select the last-but-one. self._lockRepaint = False # if True, repaint routines are blocked. self._plotSetsRepaint = set() # plot waiting for repaint/update while repaint is locked - + def isEmpty(self): return len(self._plotSets) == 0 - + def setCurrentPlotSet(self, plotSetID, silent=False): if plotSetID not in self._plotSets and plotSetID != -1: raise ValueError("Invalid plot set ID (%d)!" % plotSetID) self._currentPlotSet = self._plotSets.get(plotSetID, None) if not silent: - self.notifyChange("CurrentPlotSetChange") - + self.notifyChange("CurrentPlotSetChange") + def getCurrentPlotSet(self): return self._currentPlotSet - + def getPlotSetContainingCurve(self, curveID): for ps in list(self._plotSets.values()): if curveID in ps._curves: return ps return None - + def setCurrentCurve(self, curveId): ps = self.getPlotSetContainingCurve(curveId) if ps is None and curveId != -1: raise ValueError("Invalid curve ID (%d)!" % curveId) self.clearAllCurrentCurve() - if curveId == -1: + if curveId == -1: return -1 ps_id = ps.getID() currPs = self.getCurrentPlotSet() - if currPs is None or currPs.getID() != ps_id: + if currPs is None or currPs.getID() != ps_id: self.setCurrentPlotSet(ps_id) ps.setCurrentCurve(curveId) return ps_id - + def getCurrentCurve(self): ps = self.getCurrentPlotSet() if ps is None: return None return ps.getCurrentCurve() - + def clearAllCurrentCurve(self, silent=False): for psID in self._plotSets: self._plotSets[psID].setCurrentCurve(-1) if not silent: self.notifyChange("CurrentCurveChange") - + def createXYPlotSet(self, silent=False): cv = XYPlotSetModel(self._controller) self._plotSets[cv.getID()] = cv @@ -83,7 +83,7 @@ class PlotManager(Model): if not silent: self.notifyChange("NewPlotSet") return cv - + def removeXYPlotSet(self, plotSetID): Logger.Debug("====> PlotManager::removeXYPlotSet() %d" % plotSetID) if plotSetID not in self._plotSets: @@ -94,25 +94,25 @@ class PlotManager(Model): self._currentPlotSet = None self.notifyChange("RemovePlotSet") return ps - + def clearAll(self): self._plotSets = {} self._currentPlotSet = None self.notifyChange("ClearAll") - + def lockRepaint(self): self._lockRepaint = True self._plotSetsRepaint = set() - + def isRepaintLocked(self): return self._lockRepaint - + def registerRepaint(self, ps_id): self._plotSetsRepaint.add(ps_id) - + def unlockRepaint(self): self._lockRepaint = False for obj in self._plotSetsRepaint: obj.notifyChange() self._plotSetsRepaint = set() - \ No newline at end of file + diff --git a/tools/CurvePlot/src/python/model/TableModel.py b/tools/CurvePlot/src/python/model/TableModel.py index 4f9f48cd5..8b371b352 100644 --- a/tools/CurvePlot/src/python/model/TableModel.py +++ b/tools/CurvePlot/src/python/model/TableModel.py @@ -18,8 +18,8 @@ # import numpy as np -from Model import Model -from utils import toUnicodeWithWarning, Logger +from .Model import Model +from .utils import toUnicodeWithWarning, Logger class TableModel(Model): def __init__(self, controller): diff --git a/tools/CurvePlot/src/python/model/XYPlotSetModel.py b/tools/CurvePlot/src/python/model/XYPlotSetModel.py index dc39ff026..e079758bc 100644 --- a/tools/CurvePlot/src/python/model/XYPlotSetModel.py +++ b/tools/CurvePlot/src/python/model/XYPlotSetModel.py @@ -17,8 +17,8 @@ # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # -from Model import Model -from utils import toUnicodeWithWarning +from .Model import Model +from .utils import toUnicodeWithWarning class XYPlotSetModel(Model): diff --git a/tools/CurvePlot/src/python/pyqtside/CMakeLists.txt b/tools/CurvePlot/src/python/pyqtside/CMakeLists.txt index 2879ed22c..3964034b7 100644 --- a/tools/CurvePlot/src/python/pyqtside/CMakeLists.txt +++ b/tools/CurvePlot/src/python/pyqtside/CMakeLists.txt @@ -21,8 +21,12 @@ SET(_pyqtside_SCRIPTS __init__.py QtCore.py QtGui.py + QtWidgets.py pyside_dynamic.py uic.py ) SALOME_INSTALL_SCRIPTS("${_pyqtside_SCRIPTS}" ${SALOME_INSTALL_PYTHON}/pyqtside) + +# For test purposes +FILE(COPY ${_pyqtside_SCRIPTS} DESTINATION ${PYQTSIDE_TEST_INSTALL}) diff --git a/tools/CurvePlot/src/python/pyqtside/QtCore.py b/tools/CurvePlot/src/python/pyqtside/QtCore.py index ccfe52c2c..fbd5e29f2 100644 --- a/tools/CurvePlot/src/python/pyqtside/QtCore.py +++ b/tools/CurvePlot/src/python/pyqtside/QtCore.py @@ -19,8 +19,8 @@ from . import _use_pyqt if _use_pyqt: - from PyQt4.QtCore import * - Slot = pyqtSlot - Signal = pyqtSignal + from PyQt5.QtCore import * + Slot = pyqtSlot + Signal = pyqtSignal else: from PySide.QtCore import * diff --git a/tools/CurvePlot/src/python/pyqtside/QtGui.py b/tools/CurvePlot/src/python/pyqtside/QtGui.py index 266a83903..0abe36df8 100644 --- a/tools/CurvePlot/src/python/pyqtside/QtGui.py +++ b/tools/CurvePlot/src/python/pyqtside/QtGui.py @@ -19,38 +19,38 @@ from . import _use_pyqt if _use_pyqt: - from PyQt4.QtGui import * - - # Make QVariant invisible in PyQt4 since they don't exist in + from PyQt5.QtGui import * + + # Make QVariant invisible in PyQt5 since they don't exist in # PySide ... - __original_itemData = QComboBox.itemData - def new_itemData(*args, **kargs): - from PyQt4.QtCore import QVariant - variant = __original_itemData(*args, **kargs) - funcS = lambda : (str(variant.toString()), True) - dico = {QVariant.Int: variant.toInt, QVariant.String: funcS, - QVariant.Bool: variant.toBool, QVariant.Double: variant.toDouble} - conv = dico.get(variant.type(), None) - if conv is None: - raise Exception("Unsupported variant type in pyqtside: '%s'!" % variant.typeName()) - return conv()[0] - - QComboBox.itemData = new_itemData +# __original_itemData = QComboBox.itemData +# def new_itemData(*args, **kargs): +# from PyQt5.QtCore import QVariant +# variant = __original_itemData(*args, **kargs) +# funcS = lambda : (str(variant.toString()), True) +# dico = {QVariant.Int: variant.toInt, QVariant.String: funcS, +# QVariant.Bool: variant.toBool, QVariant.Double: variant.toDouble} +# conv = dico.get(variant.type(), None) +# if conv is None: +# raise Exception("Unsupported variant type in pyqtside: '%s'!" % variant.typeName()) +# return conv()[0] +# +# QComboBox.itemData = new_itemData else: from PySide.QtGui import * - + __original_ofn = QFileDialog.getOpenFileName __original_sfn = QFileDialog.getSaveFileName - - # In PySide, getOpenFileName and co returns 2 values, and only one in PyQt4 ... + + # In PySide, getOpenFileName and co returns 2 values, and only one in PyQt ... def newOfn(cls,*args, **kargs): tup = __original_ofn(*args, **kargs) return tup[0] - + def newSfn(cls,*args, **kargs): tup = __original_sfn(*args, **kargs) return tup[0] - + QFileDialog.getOpenFileName = classmethod(newOfn) QFileDialog.getSaveFileName = classmethod(newSfn) diff --git a/tools/CurvePlot/src/python/pyqtside/QtWidgets.py b/tools/CurvePlot/src/python/pyqtside/QtWidgets.py new file mode 100644 index 000000000..dd00a92cc --- /dev/null +++ b/tools/CurvePlot/src/python/pyqtside/QtWidgets.py @@ -0,0 +1,5 @@ +from . import _use_pyqt +if _use_pyqt: + from PyQt5.QtWidgets import * +else: + from PySide.QtWidgets import * diff --git a/tools/CurvePlot/src/python/pyqtside/__init__.py b/tools/CurvePlot/src/python/pyqtside/__init__.py index d4f988fa7..4ab1737f1 100644 --- a/tools/CurvePlot/src/python/pyqtside/__init__.py +++ b/tools/CurvePlot/src/python/pyqtside/__init__.py @@ -18,31 +18,34 @@ # """ -Group under one hat PySide and PyQt4. PyQt4 is tried first. +Group under one hat PySide and PyQt5. PyQt5 is tried first. """ try: import os if os.getenv("CURVEPLOT_FORCE_PYSIDE") is not None: raise Exception - import PyQt4 + import PyQt5 _use_pyqt = True - print("Using PyQt4 run-time ...") + print("Using PyQt5 run-time ...") except: try: import PySide _use_pyqt = False print("Using PySide run-time ...") except: - raise Exception("Neither PyQt4 nor PySide could be imported!") + raise Exception("Neither PyQt5 nor PySide could be imported!") # Matplotlib has to be handled very early, otherwise it will switch to whatever it # finds first on the machine try: import matplotlib - if _use_pyqt: back = 'PyQt4' + if _use_pyqt: back = 'PyQt5' else: back = 'PySide' - matplotlib.rcParams['backend.qt4'] = back + # As advised by MatPlotlib: + # "The backend.qt5 rcParam was deprecated in version 2.2. In order to force the use of a specific Qt binding, either import that binding first, or set the QT_API environment variable. + # mplDeprecation)" + from matplotlib.backends import backend_qt5agg print("Matplotlib found - Set matplotlib backend to '%s'!" % back) except: # No matplotlib, silently discard err message. diff --git a/tools/CurvePlot/src/python/pyqtside/pyside_dynamic.py b/tools/CurvePlot/src/python/pyqtside/pyside_dynamic.py index a3ab6046d..38a82e3b6 100644 --- a/tools/CurvePlot/src/python/pyqtside/pyside_dynamic.py +++ b/tools/CurvePlot/src/python/pyqtside/pyside_dynamic.py @@ -14,7 +14,7 @@ class UiLoader(QUiLoader): create a new instance of the top-level widget, but creates the user interface in an existing instance of the top-level class. - This mimics the behaviour of :func:`PyQt4.uic.loadUi`. + This mimics the behaviour of :func:`PyQt5.uic.loadUi`. """ def __init__(self, baseinstance, customWidgets=None): """ diff --git a/tools/CurvePlot/src/python/pyqtside/uic.py b/tools/CurvePlot/src/python/pyqtside/uic.py index 44ac1b744..b37ffa493 100644 --- a/tools/CurvePlot/src/python/pyqtside/uic.py +++ b/tools/CurvePlot/src/python/pyqtside/uic.py @@ -19,8 +19,8 @@ from . import _use_pyqt if _use_pyqt: - from PyQt4.uic import loadUi as loadUiGen -else: + from PyQt5.uic import loadUi as loadUiGen +else: from .pyside_dynamic import loadUi as loadUiGen diff --git a/tools/CurvePlot/src/python/test/CMakeLists.txt b/tools/CurvePlot/src/python/test/CMakeLists.txt index 88afa57c2..6d5e13194 100644 --- a/tools/CurvePlot/src/python/test/CMakeLists.txt +++ b/tools/CurvePlot/src/python/test/CMakeLists.txt @@ -26,20 +26,23 @@ SET(_all_SCRIPTS TestDesktop.py ) +SET(_test_SCRIPTS + ${CMAKE_CURRENT_BINARY_DIR}/mockup/SalomePyQt_MockUp.py + PlotTestBase.py + TestDesktop.py +) + SALOME_INSTALL_SCRIPTS("${_all_SCRIPTS}" ${SALOME_INSTALL_SCRIPT_PYTHON}/tests) SALOME_INSTALL_SCRIPTS(${CMAKE_CURRENT_BINARY_DIR}/mockup/SalomePyQt_MockUp.py ${SALOME_INSTALL_SCRIPT_PYTHON}/tests) INSTALL(DIRECTORY baselines DESTINATION ${SALOME_INSTALL_SCRIPT_PYTHON}/tests) -SALOME_ACCUMULATE_ENVIRONMENT(PYTHONPATH ${CMAKE_CURRENT_SOURCE_DIR}/../model) -SALOME_ACCUMULATE_ENVIRONMENT(PYTHONPATH ${CMAKE_CURRENT_SOURCE_DIR}/../ui) -SALOME_ACCUMULATE_ENVIRONMENT(PYTHONPATH ${CMAKE_CURRENT_SOURCE_DIR}/../views) -SALOME_ACCUMULATE_ENVIRONMENT(PYTHONPATH ${CMAKE_CURRENT_SOURCE_DIR}/../controller) -SALOME_ACCUMULATE_ENVIRONMENT(PYTHONPATH ${CMAKE_CURRENT_SOURCE_DIR}/..) -SALOME_ACCUMULATE_ENVIRONMENT(PYTHONPATH ${PROJECT_BINARY_DIR}/src/python/ui) # for the generated PY files (from UI files) -SALOME_ACCUMULATE_ENVIRONMENT(PYTHONPATH ${PROJECT_BINARY_DIR}/src/python/controller) # for utils.py +SALOME_ACCUMULATE_ENVIRONMENT(PYTHONPATH ${CMAKE_BINARY_DIR}/local) # point to local curveplot package in BUILD dir SALOME_GENERATE_TESTS_ENVIRONMENT(tests_env) ADD_TEST(CurvePlotUnitTests ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/plot_test.py) SET_TESTS_PROPERTIES(CurvePlotUnitTests PROPERTIES ENVIRONMENT "${tests_env}") +# For test purposes +FILE(COPY ${_test_SCRIPTS} DESTINATION ${CRVPLOT_TEST_INSTALL}) +FILE(COPY baselines DESTINATION ${CRVPLOT_TEST_INSTALL}) diff --git a/tools/CurvePlot/src/python/test/PlotCurve_Standalone.py b/tools/CurvePlot/src/python/test/PlotCurve_Standalone.py index 92b3e1e06..1b57e8017 100755 --- a/tools/CurvePlot/src/python/test/PlotCurve_Standalone.py +++ b/tools/CurvePlot/src/python/test/PlotCurve_Standalone.py @@ -22,8 +22,8 @@ # # Author : A. Bruneton # -from pyqtside.QtGui import QApplication -from pyqtside.QtCore import SIGNAL, SLOT, QTimer, QTranslator +from pyqtside.QtWidgets import QApplication +from pyqtside.QtCore import QTimer, QTranslator from TestDesktop import TestDesktop import SalomePyQt_MockUp @@ -43,31 +43,23 @@ def activeViewChanged( viewID ): def main(args) : global desktop - + app = QApplication(args) - ts_files = ["/export/home/adrien/Projets/salome/modules/V7_main/CURVEPLOT_INSTALL/share/salome/resources/curveplot/CURVEPLOT_msg_fr.qm", - "/export/home/adrien/Projets/salome/modules/V7_main/CURVEPLOT_INSTALL/share/salome/resources/curveplot/CURVEPLOT_msg_en.qm" - ] - trans = QTranslator() - for f in ts_files: - if not trans.load(f): - print("could not load translation %s!" % f) - app.installTranslator(trans) dw = app.desktop() x, y = dw.width()*0.25, dw.height()*0.7 - + desktop = TestDesktop(None) sgPyQt = SalomePyQt_MockUp.SalomePyQt(desktop) sgPyQt.currentTabChanged.connect(activeViewChanged) - desktop._sgPyQt = sgPyQt + desktop._sgPyQt = sgPyQt desktop.initialize() desktop.resize(x,y) desktop.show() activate() # - QTimer.singleShot(200, desktop, SLOT("curveSameFig()")) + QTimer.singleShot(200, desktop.curveSameFig) # - app.connect(app,SIGNAL("lastWindowClosed()"),app,SLOT("quit()")) + app.lastWindowClosed.connect(app.quit) app.exec_() if __name__ == "__main__" : diff --git a/tools/CurvePlot/src/python/test/PlotTestBase.py b/tools/CurvePlot/src/python/test/PlotTestBase.py index d93f0a673..232e7b6bf 100644 --- a/tools/CurvePlot/src/python/test/PlotTestBase.py +++ b/tools/CurvePlot/src/python/test/PlotTestBase.py @@ -23,9 +23,13 @@ # Author : A. Bruneton # import unittest, sys, os, filecmp, shutil, tempfile -from pyqtside.QtGui import QApplication, QPixmap, QPainter -from PlotController import PlotController -from XYView import XYView +from pyqtside.QtWidgets import QApplication +from pyqtside.QtGui import QPixmap, QPainter +from pyqtside.QtCore import QTimer + +from curveplot.PlotController import PlotController +from curveplot.XYView import XYView +from PyQt5.Qt import QMainWindow def runOnly(func): func.__runOnly__ = True @@ -51,7 +55,7 @@ def processDecorator(mod_name): # Note the "not": if p.startswith("test") and not hasattr(obj.__dict__[p], "__runOnly__"): delattr(obj, p) - + class PlotTestBase(unittest.TestCase): """ Unit test suite for the curve plotter. This class deals with the set up and the screenshot generation/ comparison. The tests themselves are stored in the derived class PlotTest below. @@ -61,31 +65,30 @@ class PlotTestBase(unittest.TestCase): The baselines directory is set relative to the path of this script. """ REBUILD_BASELINES = False - + __BASE_LINE_DIR = "baselines" __FORMAT = "png" - + def __init__(self, methodName): unittest.TestCase.__init__(self, methodName) - + if self.REBUILD_BASELINES: self.tmpBaselineDir = os.path.join(tempfile.gettempdir(), "curveplot_baselines") if not os.path.isdir(self.tmpBaselineDir): os.mkdir(self.tmpBaselineDir) print("### Rebuilding base lines. Reference files will be saved to '%s'" % self.tmpBaselineDir) - + PlotController.WITH_CURVE_BROWSER = True XYView._DEFAULT_LEGEND_STATE = True # always show legend by default self._this_dir = os.path.dirname(os.path.realpath(__file__)) - -# import matplotlib as mpl -# mpl.use('Agg') - + def setUp(self): - from SalomePyQt_MockUp import SalomePyQt - from TableModel import TableModel - from CurveModel import CurveModel - from XYPlotSetModel import XYPlotSetModel + import sys + from curveplot.SalomePyQt_MockUp import SalomePyQt + from curveplot.TableModel import TableModel + from curveplot.CurveModel import CurveModel + from curveplot.XYPlotSetModel import XYPlotSetModel + from curveplot.TestDesktop import TestDesktop self.qpixmap = None self.keepDir = False @@ -93,21 +96,30 @@ class PlotTestBase(unittest.TestCase): self.tmpDir = tempfile.mkdtemp(prefix="curveplot_tests") else: self.tmpDir = None + # Minimal UI setup: - self.sgPyQt = SalomePyQt() - # Reinstanciate from scratch the PlotController: + self.app = QApplication(sys.argv) + desktop = TestDesktop(None) + self.sgPyQt = SalomePyQt(desktop) + desktop._sgPyQt = self.sgPyQt + desktop.initialize() self.plotController = PlotController.GetInstance(self.sgPyQt) - self.plotController.setFixedSizeWidget() + desktop.resize(800, 600) + desktop.show() + self._execQtWasCalled = False # Used to automatically finish Qt execution loop on tests not doing a screenshot + # Reset some class var to make sure IDs appearing in screenshots do not depend on test seq order: CurveModel.START_ID = -1 TableModel.START_ID = -1 XYPlotSetModel.START_ID = -1 - + def tearDown(self): if not self.REBUILD_BASELINES: # Clean up temp dir where the file comparison has been made: if not self.keepDir: shutil.rmtree(self.tmpDir, False) + if not self._execQtWasCalled: + self._execQt(withShot=False) PlotController.Destroy() def getTestName(self): @@ -118,7 +130,29 @@ class PlotTestBase(unittest.TestCase): self.qpixmap.save(fileName, self.__FORMAT) return fileName - def areScreenshotEqual(self, widget, suffix=""): + def _execQt(self, withShot=False): + if withShot: + QTimer.singleShot(50, self._shotEvent) # take picture + QTimer.singleShot(200, self.app.quit) # quit + self.app.exec_() # will hang till quit is fired + + # Important make sure previous app is properly killed before launching next test! + # Qt doesn't like multiple running instance + import gc + gc.collect() + + def areScreenshotEqual(self, widget): + """ Finish the launching of the Qt application so that the widgets and the curve have a chance to display + and trigger snapshot comparison """ + self.saveW = widget + self._execQtWasCalled = True + self._execQt(withShot=True) + return self.retValue + + def _shotEvent(self): + self.retValue = self._snapAndCompare(self.saveW) + + def _snapAndCompare(self, widget, suffix=""): """ Test equality between a reference file saved in the baseline directory, and whose name is built as ".png" and the file generated on the fly by taking a snapshot of the widget provided in argument. @@ -126,13 +160,16 @@ class PlotTestBase(unittest.TestCase): """ import glob # Smiiiile :-) - self.qpixmap = QPixmap.grabWidget(widget) - + self.qpixmap = QPixmap(widget.size()) + widget.repaint() + widget.render(self.qpixmap) + #self.qpixmap = widget.grab() + # Nothing to compare if rebuilding base lines, just saving file: if self.REBUILD_BASELINES: self.saveCurrentPix(self.tmpBaselineDir, suffix) return True - + gen_path = self.saveCurrentPix(self.tmpDir, suffix) base_ref = os.path.join(self._this_dir, self.__BASE_LINE_DIR, self.getTestName() + suffix) ret = False @@ -147,13 +184,13 @@ class PlotTestBase(unittest.TestCase): # Keep file if assert is false self.keepDir = True print("[%s] -- Failed screenshot equality, or unable to open baseline file - directory is kept alive: %s" % (self.getTestName(), self.tmpDir)) - return ret - + return ret + def showTabWidget(self): tabW = self.plotController._sgPyQt._tabWidget # No simpler way found so far: tabW.show() return tabW - + def getBrowserWidget(self): return self.plotController._curveBrowserView._treeWidget diff --git a/tools/CurvePlot/src/python/test/README.txt b/tools/CurvePlot/src/python/test/README.txt index bdb40251f..cbc22eaf7 100644 --- a/tools/CurvePlot/src/python/test/README.txt +++ b/tools/CurvePlot/src/python/test/README.txt @@ -1,4 +1,12 @@ -Unit tests are in plot_test.py +Unit tests are in plot_test.py. + +They should be run: + - without any install of CurvePlot, to be sure there is no conflict + - with the ctest command + +If anything is changed in the code, be sure to explicitely call + cmake . +in the build directory to update the local replica of the 'curveplot' package. PlotCurve_Standalone is a standalone Python executable that shows the various functionalities of the package. diff --git a/tools/CurvePlot/src/python/test/SalomePyQt_MockUp.py.in b/tools/CurvePlot/src/python/test/SalomePyQt_MockUp.py.in index 0d2bc0c75..98a5dd1fe 100644 --- a/tools/CurvePlot/src/python/test/SalomePyQt_MockUp.py.in +++ b/tools/CurvePlot/src/python/test/SalomePyQt_MockUp.py.in @@ -22,9 +22,10 @@ # Author : A. Bruneton # -from pyqtside.QtGui import QApplication, QTabWidget -from pyqtside.QtGui import QAction, QMenu, QIcon, QPixmap, QDesktopWidget, QFileDialog -from pyqtside.QtCore import SIGNAL, SLOT, QObject, Slot, Signal +from pyqtside.QtWidgets import QApplication, QTabWidget +from pyqtside.QtWidgets import QAction, QMenu, QDesktopWidget, QFileDialog +from pyqtside.QtGui import QIcon, QPixmap +from pyqtside.QtCore import QObject, pyqtSlot, pyqtSignal RESOURCE_DIR = "@SGPYQT_RES_DIR@" @@ -33,7 +34,7 @@ class SalomePyQt(QObject): This class can be used to mimick the true SALOME object without having to launch SALOME """ - currentTabChanged = Signal(int) + currentTabChanged = pyqtSignal(int) START_VIEW_ID = 0 @@ -47,7 +48,7 @@ class SalomePyQt(QObject): if self._mainWindow: self._menuBar = self._mainWindow.menuBar() self._mainWindow.setCentralWidget(self._tabWidget) - self.connect(self._tabWidget, SIGNAL("currentChanged(int)"), self, SLOT("onTabChanged(int)")) + self._tabWidget.currentChanged.connect(self.onTabChanged) self._blockSignal = False def getDesktop(self): @@ -58,12 +59,12 @@ class SalomePyQt(QObject): return QFileDialog.getSaveFileName(parent=parent_widget, caption=caption, directory=initial, filter=fil); - @Slot(int) + @pyqtSlot(int) def onTabChanged(self, index): if self._blockSignal: return invDict = dict([(v, k) for k,v in self._viewIDs.items()]) - if invDict.has_key(index): + if index in invDict: self._blockSignal = True self.currentTabChanged.emit(invDict[index]) self._blockSignal = False diff --git a/tools/CurvePlot/src/python/test/TestDesktop.py b/tools/CurvePlot/src/python/test/TestDesktop.py index 3fffbaf3a..11d777046 100644 --- a/tools/CurvePlot/src/python/test/TestDesktop.py +++ b/tools/CurvePlot/src/python/test/TestDesktop.py @@ -23,8 +23,8 @@ # Author : A. Bruneton # -from pyqtside.QtCore import SIGNAL, SLOT, Slot, Qt, QTimer -from pyqtside.QtGui import QMainWindow,QMenu +from pyqtside.QtCore import Qt, QTimer, pyqtSlot +from pyqtside.QtWidgets import QMainWindow,QMenu import numpy as np import curveplot @@ -70,15 +70,15 @@ class TestDesktop(QMainWindow): self.createMenus() self.createView() - self.connect(self.curveSameFigAction,SIGNAL("activated()"),self.curveSameFig) - self.connect(self.curveNewFigAction,SIGNAL("activated()"),self.curveNewFig) - self.connect(self.itemDelAction,SIGNAL("activated()"),self.itemDel) - self.connect(self.cpsAction,SIGNAL("activated()"),self.clearPlotSet) - self.connect(self.plotTableAction,SIGNAL("activated()"),self.plotTable) - self.connect(self.addPSAction,SIGNAL("activated()"),self.addPS) - self.connect(self.addTabAction,SIGNAL("activated()"),self.addTab) - self.connect(self.memAction,SIGNAL("activated()"),self.memPrint) - self.connect(self.perfTestAction,SIGNAL("activated()"),self.perfTest) + self.curveSameFigAction.triggered.connect(self.curveSameFig) + self.curveNewFigAction.triggered.connect(self.curveNewFig) + self.itemDelAction.triggered.connect(self.itemDel) + self.cpsAction.triggered.connect(self.clearPlotSet) + self.plotTableAction.triggered.connect(self.plotTable) + self.addPSAction.triggered.connect(self.addPS) + self.addTabAction.triggered.connect(self.addTab) + self.memAction.triggered.connect(self.memPrint) + self.perfTestAction.triggered.connect(self.perfTest) def generateID(self): self._currID += 1 @@ -152,7 +152,7 @@ class TestDesktop(QMainWindow): # y = x return x, y - @Slot() + @pyqtSlot() def curveSameFig(self): x, y = self.__generateRandomData() _, ps_id = curveplot.AddCurve(x, y, x_label="the x axis", y_label="the y axis", append=True) @@ -164,13 +164,13 @@ class TestDesktop(QMainWindow): x, y = self.__generateRandomData() curveplot.AddCurve(x, y, x_label="the x axis", y_label="the y axis", append=False) - @Slot() + @pyqtSlot() def itemDel(self): curveplot.DeleteCurrentItem() if self.cnt >= 0: QTimer.singleShot(self.timeLap, self, SLOT("memPrint()")) - @Slot() + @pyqtSlot() def perfTest(self): lx, ly = [], [] nC = 200 @@ -195,7 +195,7 @@ class TestDesktop(QMainWindow): def addTab(self): pass -# from PyQt4.QtGui import QPushButton +# from PyQt5.QtWidgets import QPushButton # self.qp = QPushButton("Hi!") # self._sgPyQt.createView("Dummy", self.qp) @@ -213,7 +213,7 @@ class TestDesktop(QMainWindow): cont.plotCurveFromTable(t, y_col_index=1, append=False) cont.plotCurveFromTable(t, y_col_index=2, append=True) - @Slot() + @pyqtSlot() def memPrint(self): i, t = curveplot.GetAllPlotSets() print(list(zip(i, t))) @@ -224,4 +224,4 @@ class TestDesktop(QMainWindow): print("** Used memory: %.2f Mb" % m) if self.cnt >= 0 and self.cnt < self.MAX_CNT: self.cnt += 1 - QTimer.singleShot(self.timeLap, self, SLOT("curveSameFig()")) + QTimer.singleShot(self.timeLap, self.curveSameFig) diff --git a/tools/CurvePlot/src/python/test/baselines/testAddCurveAppend_a.png b/tools/CurvePlot/src/python/test/baselines/testAddCurveAppend_a.png index be7de68bb..0f251a065 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testAddCurveAppend_a.png and b/tools/CurvePlot/src/python/test/baselines/testAddCurveAppend_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testAddCurve_a.png b/tools/CurvePlot/src/python/test/baselines/testAddCurve_a.png index 69de6919b..79645403b 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testAddCurve_a.png and b/tools/CurvePlot/src/python/test/baselines/testAddCurve_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testAddPlotSet_a.png b/tools/CurvePlot/src/python/test/baselines/testAddPlotSet_a.png index 4a7417bd8..6667d06d7 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testAddPlotSet_a.png and b/tools/CurvePlot/src/python/test/baselines/testAddPlotSet_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testClearPlotSet2_a.png b/tools/CurvePlot/src/python/test/baselines/testClearPlotSet2_a.png index 4a7417bd8..6667d06d7 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testClearPlotSet2_a.png and b/tools/CurvePlot/src/python/test/baselines/testClearPlotSet2_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testClearPlotSet_a.png b/tools/CurvePlot/src/python/test/baselines/testClearPlotSet_a.png index c9144c243..7e2f7abe3 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testClearPlotSet_a.png and b/tools/CurvePlot/src/python/test/baselines/testClearPlotSet_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testCopyCurve_a.png b/tools/CurvePlot/src/python/test/baselines/testCopyCurve_a.png index a08cf1b22..be7e36eab 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testCopyCurve_a.png and b/tools/CurvePlot/src/python/test/baselines/testCopyCurve_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testDeleteCurrentItem_curve_a.png b/tools/CurvePlot/src/python/test/baselines/testDeleteCurrentItem_curve_a.png index 2b16e2ce2..c896b6f07 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testDeleteCurrentItem_curve_a.png and b/tools/CurvePlot/src/python/test/baselines/testDeleteCurrentItem_curve_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testDeleteCurrentItem_plotSet_a.png b/tools/CurvePlot/src/python/test/baselines/testDeleteCurrentItem_plotSet_a.png index b84993bbb..43858fff8 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testDeleteCurrentItem_plotSet_a.png and b/tools/CurvePlot/src/python/test/baselines/testDeleteCurrentItem_plotSet_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testDeleteCurve1_a.png b/tools/CurvePlot/src/python/test/baselines/testDeleteCurve1_a.png index 1043c947d..744a6f5cc 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testDeleteCurve1_a.png and b/tools/CurvePlot/src/python/test/baselines/testDeleteCurve1_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testDeleteCurve2_a.png b/tools/CurvePlot/src/python/test/baselines/testDeleteCurve2_a.png index 1043c947d..744a6f5cc 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testDeleteCurve2_a.png and b/tools/CurvePlot/src/python/test/baselines/testDeleteCurve2_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testDeleteCurve3_a.png b/tools/CurvePlot/src/python/test/baselines/testDeleteCurve3_a.png index e9f8ed691..45ec73a43 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testDeleteCurve3_a.png and b/tools/CurvePlot/src/python/test/baselines/testDeleteCurve3_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testDeletePlotSet1_a.png b/tools/CurvePlot/src/python/test/baselines/testDeletePlotSet1_a.png index 24895028c..0d80b2384 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testDeletePlotSet1_a.png and b/tools/CurvePlot/src/python/test/baselines/testDeletePlotSet1_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testDeletePlotSet2_a.png b/tools/CurvePlot/src/python/test/baselines/testDeletePlotSet2_a.png index 24895028c..0d80b2384 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testDeletePlotSet2_a.png and b/tools/CurvePlot/src/python/test/baselines/testDeletePlotSet2_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testExtendCurve_a.png b/tools/CurvePlot/src/python/test/baselines/testExtendCurve_a.png index 1476e781b..ad04b34c2 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testExtendCurve_a.png and b/tools/CurvePlot/src/python/test/baselines/testExtendCurve_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testLockRepaint_a.png b/tools/CurvePlot/src/python/test/baselines/testLockRepaint_a.png index 98b167091..58fa9fcd9 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testLockRepaint_a.png and b/tools/CurvePlot/src/python/test/baselines/testLockRepaint_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testPlotCurveFromTable_a.png b/tools/CurvePlot/src/python/test/baselines/testPlotCurveFromTable_a.png index 91bfc4012..4ac74a111 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testPlotCurveFromTable_a.png and b/tools/CurvePlot/src/python/test/baselines/testPlotCurveFromTable_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testResetCurve_a.png b/tools/CurvePlot/src/python/test/baselines/testResetCurve_a.png index ba52552a1..2c1a0c30f 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testResetCurve_a.png and b/tools/CurvePlot/src/python/test/baselines/testResetCurve_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testSetCurrentCurve2_a.png b/tools/CurvePlot/src/python/test/baselines/testSetCurrentCurve2_a.png index 01ea93a6a..94d929b54 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testSetCurrentCurve2_a.png and b/tools/CurvePlot/src/python/test/baselines/testSetCurrentCurve2_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testSetCurrentCurve3_a.png b/tools/CurvePlot/src/python/test/baselines/testSetCurrentCurve3_a.png index 2b16e2ce2..c896b6f07 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testSetCurrentCurve3_a.png and b/tools/CurvePlot/src/python/test/baselines/testSetCurrentCurve3_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testSetCurrentCurve_a.png b/tools/CurvePlot/src/python/test/baselines/testSetCurrentCurve_a.png index 1d5c92196..bfb41d673 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testSetCurrentCurve_a.png and b/tools/CurvePlot/src/python/test/baselines/testSetCurrentCurve_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testSetCurrentPlotSet_a.png b/tools/CurvePlot/src/python/test/baselines/testSetCurrentPlotSet_a.png index e890d57d3..7b2ca2a0a 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testSetCurrentPlotSet_a.png and b/tools/CurvePlot/src/python/test/baselines/testSetCurrentPlotSet_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testSetCurveLabel_a.png b/tools/CurvePlot/src/python/test/baselines/testSetCurveLabel_a.png index 8d4ffb317..0ae41d138 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testSetCurveLabel_a.png and b/tools/CurvePlot/src/python/test/baselines/testSetCurveLabel_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testSetCurveMarker_a.png b/tools/CurvePlot/src/python/test/baselines/testSetCurveMarker_a.png index 9f6eebc49..a126ef86a 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testSetCurveMarker_a.png and b/tools/CurvePlot/src/python/test/baselines/testSetCurveMarker_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testSetLabelX_a.png b/tools/CurvePlot/src/python/test/baselines/testSetLabelX_a.png index f261e736d..08537dbf1 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testSetLabelX_a.png and b/tools/CurvePlot/src/python/test/baselines/testSetLabelX_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testSetLabelY_a.png b/tools/CurvePlot/src/python/test/baselines/testSetLabelY_a.png index 4a7417bd8..d917195d8 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testSetLabelY_a.png and b/tools/CurvePlot/src/python/test/baselines/testSetLabelY_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testSetLegendVisible_a.png b/tools/CurvePlot/src/python/test/baselines/testSetLegendVisible_a.png index 0dae71d25..55e35a945 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testSetLegendVisible_a.png and b/tools/CurvePlot/src/python/test/baselines/testSetLegendVisible_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testSetPlotSetTitle_a.png b/tools/CurvePlot/src/python/test/baselines/testSetPlotSetTitle_a.png index e805f17cd..6920c0117 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testSetPlotSetTitle_a.png and b/tools/CurvePlot/src/python/test/baselines/testSetPlotSetTitle_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testSetXSciNotation_a.png b/tools/CurvePlot/src/python/test/baselines/testSetXSciNotation_a.png index 336bbeb93..649579cd7 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testSetXSciNotation_a.png and b/tools/CurvePlot/src/python/test/baselines/testSetXSciNotation_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testSetYSciNotation_a.png b/tools/CurvePlot/src/python/test/baselines/testSetYSciNotation_a.png index 44e29e678..3dc38aa60 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testSetYSciNotation_a.png and b/tools/CurvePlot/src/python/test/baselines/testSetYSciNotation_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testSettingsCurveColor_a.png b/tools/CurvePlot/src/python/test/baselines/testSettingsCurveColor_a.png index 5dbdbd7e1..bdf2ac5b0 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testSettingsCurveColor_a.png and b/tools/CurvePlot/src/python/test/baselines/testSettingsCurveColor_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testSettingsCurveMarker_a.png b/tools/CurvePlot/src/python/test/baselines/testSettingsCurveMarker_a.png index e9df517a7..a5f8fe88f 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testSettingsCurveMarker_a.png and b/tools/CurvePlot/src/python/test/baselines/testSettingsCurveMarker_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testToggleXLog_a.png b/tools/CurvePlot/src/python/test/baselines/testToggleXLog_a.png index 5fb1fcdf9..96319afe4 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testToggleXLog_a.png and b/tools/CurvePlot/src/python/test/baselines/testToggleXLog_a.png differ diff --git a/tools/CurvePlot/src/python/test/baselines/testToggleYLog_a.png b/tools/CurvePlot/src/python/test/baselines/testToggleYLog_a.png index 0db30fb2b..cdfe1e728 100644 Binary files a/tools/CurvePlot/src/python/test/baselines/testToggleYLog_a.png and b/tools/CurvePlot/src/python/test/baselines/testToggleYLog_a.png differ diff --git a/tools/CurvePlot/src/python/test/plot_test.py b/tools/CurvePlot/src/python/test/plot_test.py index 39f9feb2d..b9878a791 100644 --- a/tools/CurvePlot/src/python/test/plot_test.py +++ b/tools/CurvePlot/src/python/test/plot_test.py @@ -22,16 +22,14 @@ # # Author : A. Bruneton # +from curveplot import * +from curveplot.PlotTestBase import PlotTestBase, processDecorator +from curveplot.PlotSettings import PlotSettings -from PlotTestBase import PlotTestBase, runOnly, processDecorator - -from PlotController import PlotController -from PlotSettings import PlotSettings - -from pyqtside.QtGui import QApplication +from pyqtside.QtWidgets import QApplication import sys -qapp = QApplication(sys.argv) - +qapp = QApplication(sys.argv) + class PlotTest(PlotTestBase): """ Unit test suite for the curve plotter. The tests themselves are stored in this class, the screenshot comparison logic is in PlotTestBase. @@ -43,10 +41,10 @@ class PlotTest(PlotTestBase): The decorator @runOnly can be used to run/rebuild a single test. """ REBUILD_BASELINES = False - + def __init__(self, methodName): PlotTestBase.__init__(self, methodName) - + ### ### Data generation ### @@ -55,24 +53,24 @@ class PlotTest(PlotTestBase): x = np.arange(100) y = np.sin(x*alpha/np.pi) return x, y - + def generateExp(self, alpha=1.0): import numpy as np x = np.arange(20) + 1.0 y = np.exp(x*alpha) return x, y - + ### ### The tests themselves ### - + # # Non GUI tests (some of them still need to show the widget to work properly but no # screenshot comparison is made). # def testTableModel(self): import numpy as np - from TableModel import TableModel + from curveplot.TableModel import TableModel t = TableModel(None) t.setTitle("coucou") t.addColumn([1.0,2.0,3.0,4.0]) @@ -85,25 +83,25 @@ class PlotTest(PlotTestBase): t.setColumnTitle(1, "a title") self.assertEqual("a title", t.getColumnTitle(1)) self.assertEqual("", t.getColumnTitle(0)) - + def testGetAllPlotSets(self): self.showTabWidget() ids, titles = PlotController.GetAllPlotSets() self.assertEqual([], ids) self.assertEqual([], titles) - + id1 = PlotController.AddPlotSet("toto") id2 = PlotController.AddPlotSet("tutu") id3 = PlotController.AddPlotSet("titi") ids, titles = PlotController.GetAllPlotSets() self.assertEqual([id1,id2,id3], ids) self.assertEqual(["toto","tutu","titi"], titles) - + def testGetCurrentXX(self): self.showTabWidget() self.assertEqual(-1, PlotController.GetCurrentCurveID()) self.assertEqual(-1, PlotController.GetCurrentPlotSetID()) - + x, y = self.generateSine() _, psID1 = PlotController.AddCurve(x, y, append=False) self.assertEqual(psID1, PlotController.GetCurrentPlotSetID()) @@ -116,7 +114,7 @@ class PlotTest(PlotTestBase): PlotController.DeletePlotSet(psID2) self.assertEqual(-1, PlotController.GetCurrentCurveID()) self.assertEqual(-1, PlotController.GetCurrentPlotSetID()) - + def testGetPlotSetID(self): self.showTabWidget() x, y = self.generateSine() @@ -125,7 +123,7 @@ class PlotTest(PlotTestBase): self.assertEqual(-1, PlotController.GetPlotSetID(145)) # invalid ID PlotController.DeletePlotSet(psID) self.assertEqual(-1, PlotController.GetPlotSetID(crvID)) # invalid ID - + def testGetPlotSetIDByName(self): self.showTabWidget() self.assertEqual(-1,PlotController.GetPlotSetIDByName("invalid")) @@ -133,7 +131,7 @@ class PlotTest(PlotTestBase): self.assertEqual(psID,PlotController.GetPlotSetIDByName("ps")) PlotController.DeletePlotSet(psID) self.assertEqual(-1,PlotController.GetPlotSetIDByName("ps")) - + def testIsValidPlotSetID(self): self.showTabWidget() self.assertEqual(False,PlotController.IsValidPlotSetID(0)) @@ -141,16 +139,16 @@ class PlotTest(PlotTestBase): self.assertEqual(True,PlotController.IsValidPlotSetID(psID)) PlotController.DeletePlotSet(psID) self.assertEqual(False,PlotController.IsValidPlotSetID(psID)) - + # # GUI tests - # + # def testAddCurve(self): x, y = self.generateSine() tw = self.showTabWidget() PlotController.AddCurve(x, y, curve_label="My curve", x_label="Lèés X (unicode!)", y_label="Et des ŷ", append=False) self.assertTrue(self.areScreenshotEqual(tw)) - + def testAddCurveAppend(self): x, y = self.generateSine() tw = self.showTabWidget() @@ -162,12 +160,12 @@ class PlotTest(PlotTestBase): tw = self.showTabWidget() PlotController.AddPlotSet("My plotset") self.assertTrue(self.areScreenshotEqual(tw)) - + def testClearPlotSet(self): x, y = self.generateSine() tw = self.showTabWidget() PlotController.AddCurve(x, y, curve_label="My curve", x_label="The X-s", y_label="The Y-s", append=False) - _, psID = PlotController.AddCurve(x, y, curve_label="My curve 2", append=True) + _, psID = PlotController.AddCurve(x, y, curve_label="My curve 2", append=True) clearedID = PlotController.ClearPlotSet() self.assertEqual(clearedID, psID) self.assertTrue(self.areScreenshotEqual(tw)) @@ -179,7 +177,7 @@ class PlotTest(PlotTestBase): clearedID = PlotController.ClearPlotSet(psID) self.assertEqual(psID, clearedID) self.assertTrue(self.areScreenshotEqual(tw)) - + def testCopyCurve(self): x, y = self.generateSine() tw = self.showTabWidget() @@ -189,7 +187,7 @@ class PlotTest(PlotTestBase): PlotController.SetCurrentPlotSet(psID) self.assertNotEqual(crvID, newID) self.assertTrue(self.areScreenshotEqual(tw)) - + def testDeleteCurrentItem_curve(self): x, y = self.generateSine() tw = self.showTabWidget() @@ -200,7 +198,7 @@ class PlotTest(PlotTestBase): self.assertFalse(b) self.assertEqual(crvID, anID) self.assertTrue(self.areScreenshotEqual(tw)) - + def testDeleteCurrentItem_plotSet(self): tw = self.showTabWidget() PlotController.AddPlotSet("tutu") @@ -209,13 +207,13 @@ class PlotTest(PlotTestBase): self.assertTrue(b) self.assertEqual(psID, anID) self.assertTrue(self.areScreenshotEqual(tw)) - + def testDeleteCurrentItem_void(self): self.showTabWidget() - b, anID = PlotController.DeleteCurrentItem() # nothing selected + b, anID = PlotController.DeleteCurrentItem() # nothing selected self.assertTrue(b) self.assertEqual(-1, anID) - + def testDeleteCurve1(self): tw = self.showTabWidget() x, y = self.generateSine() @@ -224,7 +222,7 @@ class PlotTest(PlotTestBase): cID = PlotController.DeleteCurve(crvID) self.assertEqual(crvID, cID) self.assertTrue(self.areScreenshotEqual(tw)) - + def testDeleteCurve2(self): tw = self.showTabWidget() x, y = self.generateSine() @@ -234,16 +232,16 @@ class PlotTest(PlotTestBase): cID = PlotController.DeleteCurve() # current curve self.assertEqual(crvID, cID) self.assertTrue(self.areScreenshotEqual(tw)) - + def testDeleteCurve3(self): """ resulting in an empty plot set, legend should be hidden """ tw = self.showTabWidget() x, y = self.generateSine() crvID, _ = PlotController.AddCurve(x, y, append=False) - cID = PlotController.DeleteCurve(crvID) + cID = PlotController.DeleteCurve(crvID) self.assertEqual(crvID, cID) self.assertTrue(self.areScreenshotEqual(tw)) - + def testDeletePlotSet1(self): tw = self.showTabWidget() psID = PlotController.AddPlotSet("tutu") @@ -251,7 +249,7 @@ class PlotTest(PlotTestBase): psID2 = PlotController.DeletePlotSet(psID) self.assertEqual(psID2, psID) self.assertTrue(self.areScreenshotEqual(tw)) - + def testDeletePlotSet2(self): tw = self.showTabWidget() psID1 = PlotController.DeletePlotSet() @@ -262,7 +260,7 @@ class PlotTest(PlotTestBase): psID3 = PlotController.DeletePlotSet() # current plot set self.assertEqual(psID3, psID2) self.assertTrue(self.areScreenshotEqual(tw)) - + def testSetCurrentCurve(self): tw = self.showTabWidget() self.assertRaises(ValueError, PlotController.SetCurrentCurve, 23) @@ -272,7 +270,7 @@ class PlotTest(PlotTestBase): psID2 = PlotController.SetCurrentCurve(crvID) self.assertEqual(psID, psID2) self.assertTrue(self.areScreenshotEqual(tw)) - + def testSetCurrentCurve2(self): tw = self.showTabWidget() x, y = self.generateSine() @@ -283,7 +281,7 @@ class PlotTest(PlotTestBase): # on first plot set curve should not be selected anymore PlotController.SetCurrentPlotSet(psID) self.assertTrue(self.areScreenshotEqual(tw)) - + def testSetCurrentCurve3(self): tw = self.showTabWidget() x, y = self.generateSine() @@ -292,7 +290,7 @@ class PlotTest(PlotTestBase): PlotController.SetCurrentCurve(crvID) PlotController.SetCurrentCurve(-1) self.assertTrue(self.areScreenshotEqual(tw)) - + def testSetCurrentPlotSet(self): tw = self.showTabWidget() psID = PlotController.AddPlotSet("tutu") @@ -300,7 +298,7 @@ class PlotTest(PlotTestBase): PlotController.SetCurrentPlotSet(psID) self.assertTrue(self.areScreenshotEqual(tw)) self.assertRaises(ValueError, PlotController.SetCurrentPlotSet, 124) # invalid ps_id - + def testSetLabelX(self): tw = self.showTabWidget() ps_id = PlotController.AddPlotSet("My plotset") @@ -321,14 +319,14 @@ class PlotTest(PlotTestBase): PlotController.SetPlotSetTitle("un titre àé", ps_id) PlotController.SetCurrentPlotSet(ps_id) self.assertTrue(self.areScreenshotEqual(tw)) - + # def testToggleCurveBrowser(self): # # hard to test ... # raise NotImplementedError - + def testPlotCurveFromTable(self): tw = self.showTabWidget() - from TableModel import TableModel + from curveplot.TableModel import TableModel t = TableModel(None) t.setTitle("coucou") t.addColumn([1.0,2.0,3.0,4.0]) @@ -352,21 +350,21 @@ class PlotTest(PlotTestBase): def fun(): dlg_test.setRGB(0,0,0) dlg_test.showLegendCheckBox.setChecked(True) - return True + return True dlg_test.exec_ = fun t = list(PlotController.GetInstance()._curveTabsView._XYViews.items()) - t[0][1].onSettings(dlg_test=dlg_test) + t[0][1].onSettings(dlg_test=dlg_test) self.assertTrue(self.areScreenshotEqual(tw)) - + def testExtendCurve(self): tw = self.showTabWidget() x, y = self.generateSine() crvID, _ = PlotController.AddCurve(x, y, append=False) PlotController.SetCurrentCurve(crvID) PlotController.ExtendCurve(crvID, x+100.0, y*2.0) - # Curve must remain blue, bold and with first marker: + # Curve must remain blue, bold and with first marker: self.assertTrue(self.areScreenshotEqual(tw)) - + def testResetCurve(self): tw = self.showTabWidget() x, y = self.generateSine() @@ -374,7 +372,7 @@ class PlotTest(PlotTestBase): PlotController.SetCurrentCurve(crvID) PlotController.ResetCurve(crvID) PlotController.ExtendCurve(crvID, x+100.0, y*x) - # Curve must remain blue, bold and with first marker: + # Curve must remain blue, bold and with first marker: self.assertTrue(self.areScreenshotEqual(tw)) def testSettingsCurveMarker(self): @@ -387,19 +385,19 @@ class PlotTest(PlotTestBase): def fun(): dlg_test.markerCurve.setCurrentIndex(2) dlg_test.showLegendCheckBox.setChecked(True) - return True + return True dlg_test.exec_ = fun t = list(PlotController.GetInstance()._curveTabsView._XYViews.items()) - t[0][1].onSettings(dlg_test=dlg_test) + t[0][1].onSettings(dlg_test=dlg_test) self.assertTrue(self.areScreenshotEqual(tw)) - + def testSetCurveMarker(self): tw = self.showTabWidget() x, y = self.generateSine() crvID, _ = PlotController.AddCurve(x, y, append=False) PlotController.SetCurveMarker(crvID, "v") self.assertTrue(self.areScreenshotEqual(tw)) - + def testSetCurveLabel(self): tw = self.showTabWidget() x, y = self.generateSine() @@ -408,7 +406,7 @@ class PlotTest(PlotTestBase): PlotController.SetCurrentCurve(crvID) PlotController.SetCurveLabel(crvID, "tata") self.assertTrue(self.areScreenshotEqual(tw)) - + def testToggleXLog(self): tw = self.showTabWidget() x, y = self.generateExp() @@ -424,7 +422,7 @@ class PlotTest(PlotTestBase): PlotController.SetYLog(psID, True) PlotController.SetYSciNotation(psID, True) self.assertTrue(self.areScreenshotEqual(tw)) - + def testSetXSciNotation(self): tw = self.showTabWidget() x, y = self.generateSine() @@ -438,7 +436,7 @@ class PlotTest(PlotTestBase): _, psID = PlotController.AddCurve(x*1.0e6, y*1.0e6, curve_label="titi", append=False) PlotController.SetYSciNotation(psID, True) self.assertTrue(self.areScreenshotEqual(tw)) - + def testRegisterCallback(self): global a_callb a_callb = 0 @@ -466,7 +464,7 @@ class PlotTest(PlotTestBase): PlotController.SetCurrentCurve(crvId) _, _ = PlotController.AddCurve(x, y) self.assertEqual(crvId, a_callb) - + def testAddCurveEmptyPs(self): """ Adding a curve when no ps was active was buggy """ self.showTabWidget() @@ -478,7 +476,7 @@ class PlotTest(PlotTestBase): PlotController.AddCurve(x, y, append=True) l, _ = PlotController.GetAllPlotSets() self.assertEqual(2, len(l)) - + def test_onCurrentCurveChange(self): self.showTabWidget() x, y = self.generateSine() @@ -517,10 +515,10 @@ class PlotTest(PlotTestBase): self.assertEqual(psID0, psID2) l, _ = PlotController.GetAllPlotSets() self.assertEqual(1, len(l)) - + # Even if not in main: processDecorator(__name__) if __name__ == "__main__": - import unittest + import unittest unittest.main() diff --git a/tools/CurvePlot/src/python/ui/CMakeLists.txt b/tools/CurvePlot/src/python/ui/CMakeLists.txt index 34cc77030..3c8f19ecd 100644 --- a/tools/CurvePlot/src/python/ui/CMakeLists.txt +++ b/tools/CurvePlot/src/python/ui/CMakeLists.txt @@ -36,5 +36,10 @@ SET(_all_lib_SCRIPTS # --- rules --- SALOME_INSTALL_SCRIPTS("${_pyuic_SCRIPTS}" ${SALOME_CURVEPLOT_INSTALL_PYTHON}) SALOME_INSTALL_SCRIPTS("${_all_lib_SCRIPTS}" ${SALOME_CURVEPLOT_INSTALL_PYTHON}) - INSTALL(FILES ${_pyuic_files} DESTINATION ${SALOME_CURVEPLOT_INSTALL_PYTHON}) + +# For test purposes +FILE(COPY ${_pyuic_SCRIPTS} DESTINATION ${CRVPLOT_TEST_INSTALL}) +FILE(COPY ${_pyuic_files} DESTINATION ${CRVPLOT_TEST_INSTALL}) +FILE(COPY ${_all_lib_SCRIPTS} DESTINATION ${CRVPLOT_TEST_INSTALL}) + diff --git a/tools/CurvePlot/src/python/ui/CurveTreeDockWidget.py b/tools/CurvePlot/src/python/ui/CurveTreeDockWidget.py index 7dfb994ae..251d13d4b 100644 --- a/tools/CurvePlot/src/python/ui/CurveTreeDockWidget.py +++ b/tools/CurvePlot/src/python/ui/CurveTreeDockWidget.py @@ -17,19 +17,19 @@ # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # -from pyqtside import QtGui, QtCore +from pyqtside import QtWidgets, QtCore from pyqtside.uic import loadUiGen -from utils import completeResPath +from .utils import completeResPath -class CurveTreeDockWidget(QtGui.QDockWidget): +class CurveTreeDockWidget(QtWidgets.QDockWidget): def __init__(self): - QtGui.QDockWidget.__init__(self) + QtWidgets.QDockWidget.__init__(self) loadUiGen(completeResPath("CurveTreeDockWidget.ui"), self) self.treeWidget.setHeaderLabel ("Plots") self.treeWidget.sortByColumn(0, QtCore.Qt.AscendingOrder) self.treeWidget.setSortingEnabled(True); self.treeWidget.setColumnHidden(1, True); - + def getTreeWidget(self): """ :returns: QTreeWidget -- the (curve) browser diff --git a/tools/CurvePlot/src/python/ui/PlotSettings.py b/tools/CurvePlot/src/python/ui/PlotSettings.py index b4623a5e3..530ea469c 100644 --- a/tools/CurvePlot/src/python/ui/PlotSettings.py +++ b/tools/CurvePlot/src/python/ui/PlotSettings.py @@ -17,13 +17,15 @@ # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # -from pyqtside import QtGui, QtCore +from pyqtside.QtWidgets import QDialog, QColorDialog, QMessageBox +from pyqtside.QtGui import QIcon, QPixmap, QColor +from pyqtside.QtCore import pyqtSlot from pyqtside.uic import loadUiGen -from utils import completeResPath +from .utils import completeResPath, Logger -class PlotSettings(QtGui.QDialog): +class PlotSettings(QDialog): def __init__(self): - QtGui.QDialog.__init__(self) + QDialog.__init__(self) loadUiGen(completeResPath("PlotSettings.ui"), self) self.initialize() @@ -33,41 +35,44 @@ class PlotSettings(QtGui.QDialog): self._r = 0 self._g = 0 self._b = 1 - - @QtCore.Slot(int) + + @pyqtSlot(int) def onShowLegend(self, index): if index > 0 : self.legendPositionComboBox.setEnabled(True) else : self.legendPositionComboBox.setEnabled(False) - - @QtCore.Slot() + + @pyqtSlot() def onChangeColor(self): - col = QtGui.QColorDialog.getColor() + col = QColorDialog.getColor() if col.isValid(): r, g, b = [c/255.0 for c in col.getRgb()[:3]] self.setRGB(r, g, b) - + def setSelectedCurveName(self, name): + self.nameCurve.setText(name) if name : + Logger.Debug("show curve panel") self.selectedCurvePanel.setTitle("Selected curve : " + name) self.selectedCurvePanel.show() else : + Logger.Debug("hide curve panel") self.selectedCurvePanel.hide() - + def setRGB(self, r, g, b): self._r = r self._g = g self._b = b - self.colorCurve.setIcon(QtGui.QIcon(self.drawColorPixmap(int(r*255), int(g*255), int(b*255)))) - + self.colorCurve.setIcon(QIcon(self.drawColorPixmap(int(r*255), int(g*255), int(b*255)))) + def getRGB(self): return self._r, self._g, self._b - + def drawColorPixmap(self, r, g, b): - pix = QtGui.QPixmap( 16, 16 ) - color = QtGui.QColor(r, g, b) + pix = QPixmap( 16, 16 ) + color = QColor(r, g, b) pix.fill(color) return pix @@ -77,32 +82,32 @@ class PlotSettings(QtGui.QDialog): yminText = str(self.axisYMinEdit.text()) ymaxText = str(self.axisYMaxEdit.text()) if (yminText == "" or ymaxText == "") : - QtGui.QMessageBox.critical(self, "Plot settings", "A field \"YMin\" or \"YMax\" is empty") + QMessageBox.critical(self, "Plot settings", "A field \"YMin\" or \"YMax\" is empty") else : try: xmin = float(xminText) except ValueError: - QtGui.QMessageBox.critical(self, "Plot settings", "It is not possible to convert XMin") + QMessageBox.critical(self, "Plot settings", "It is not possible to convert XMin") try: xmax = float(xmaxText) except ValueError: - QtGui.QMessageBox.critical(self, "Plot settings", "It is not possible to convert XMax") + QMessageBox.critical(self, "Plot settings", "It is not possible to convert XMax") try: ymin = float(yminText) except ValueError: - QtGui.QMessageBox.critical(self, "Plot settings", "It is not possible to convert YMin") + QMessageBox.critical(self, "Plot settings", "It is not possible to convert YMin") try: ymax = float(ymaxText) except ValueError: - QtGui.QMessageBox.critical(self, "Plot settings", "It is not possible to convert YMax") + QMessageBox.critical(self, "Plot settings", "It is not possible to convert YMax") if ((xmax-xmin) == 0) : - QtGui.QMessageBox.critical(self, "Plot settings", "XMax is is equal to XMin.") + QMessageBox.critical(self, "Plot settings", "XMax is is equal to XMin.") return if ((ymax-ymin) == 0) : - QtGui.QMessageBox.critical(self, "Plot settings", "YMax is is equal to YMin.") + QMessageBox.critical(self, "Plot settings", "YMax is is equal to YMin.") return if ((xmax-xmin) < 0) : - QtGui.QMessageBox.warning(self, "Plot settings", "XMax is less than XMin.") + QMessageBox.warning(self, "Plot settings", "XMax is less than XMin.") if ((ymax-ymin) < 0) : - QtGui.QMessageBox.warning(self, "Plot settings", "YMax is less than YMin.") + QMessageBox.warning(self, "Plot settings", "YMax is less than YMin.") super(PlotSettings, self).accept() diff --git a/tools/CurvePlot/src/python/ui/PlotSettings.ui b/tools/CurvePlot/src/python/ui/PlotSettings.ui index 687e47a20..0672d6f55 100644 --- a/tools/CurvePlot/src/python/ui/PlotSettings.ui +++ b/tools/CurvePlot/src/python/ui/PlotSettings.ui @@ -147,7 +147,7 @@ 11 35 291 - 57 + 74 @@ -162,72 +162,14 @@ - - - - - - - 145 - 145 - 145 - - - - - - - 105 - 105 - 105 - - - - - - - - - 145 - 145 - 145 - - - - - - - 105 - 105 - 105 - - - - - - - - - 149 - 151 - 153 - - - - - - - 158 - 158 - 158 - - - - - + + true + + + - true + false diff --git a/tools/CurvePlot/src/python/ui/PlotWidget.py b/tools/CurvePlot/src/python/ui/PlotWidget.py index aca4c80f3..82646fd62 100644 --- a/tools/CurvePlot/src/python/ui/PlotWidget.py +++ b/tools/CurvePlot/src/python/ui/PlotWidget.py @@ -17,15 +17,15 @@ # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # -from pyqtside import QtGui +from pyqtside import QtWidgets from pyqtside.uic import loadUiGen -from utils import completeResPath +from .utils import completeResPath -class PlotWidget(QtGui.QMainWindow): +class PlotWidget(QtWidgets.QMainWindow): def __init__(self): - QtGui.QMainWindow.__init__(self) + QtWidgets.QMainWindow.__init__(self) loadUiGen(completeResPath("PlotWidget.ui"), self) - + def clearAll(self): """ In test context, the PlotWidget is never fully deleted (because the PyQt binding of QTabWidget doesn't remove completly the references it holds). diff --git a/tools/CurvePlot/src/python/views/CMakeLists.txt b/tools/CurvePlot/src/python/views/CMakeLists.txt index 87c738233..2f5a17742 100644 --- a/tools/CurvePlot/src/python/views/CMakeLists.txt +++ b/tools/CurvePlot/src/python/views/CMakeLists.txt @@ -24,5 +24,8 @@ SET(_all_lib_SCRIPTS CurveView.py XYView.py ) - + SALOME_INSTALL_SCRIPTS("${_all_lib_SCRIPTS}" ${SALOME_CURVEPLOT_INSTALL_PYTHON}) + +# For test purposes +FILE(COPY ${_all_lib_SCRIPTS} DESTINATION ${CRVPLOT_TEST_INSTALL}) diff --git a/tools/CurvePlot/src/python/views/CurveBrowserView.py b/tools/CurvePlot/src/python/views/CurveBrowserView.py index c0c8f9215..68589a039 100644 --- a/tools/CurvePlot/src/python/views/CurveBrowserView.py +++ b/tools/CurvePlot/src/python/views/CurveBrowserView.py @@ -17,13 +17,13 @@ # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # -from pyqtside import QtGui -from pyqtside.QtGui import QMenu +from pyqtside import QtWidgets +from pyqtside.QtWidgets import QMenu from pyqtside.QtCore import Qt -from View import View -from CurveTreeDockWidget import CurveTreeDockWidget -from utils import Logger +from .View import View +from .CurveTreeDockWidget import CurveTreeDockWidget +from .utils import Logger class CurveBrowserView( View, CurveTreeDockWidget) : @@ -55,10 +55,10 @@ class CurveBrowserView( View, CurveTreeDockWidget) : # The second (hidden) column in the tree bares the ID of the object and its nature (plotset or curve) for p in list(plotSets.values()): - item = QtGui.QTreeWidgetItem([str(p.getTitle()), str(p.getID()) + '_set']) + item = QtWidgets.QTreeWidgetItem([str(p.getTitle()), str(p.getID()) + '_set']) treeWidget.addTopLevelItem(item) for c in list(p._curves.values()): - chld = QtGui.QTreeWidgetItem([str(c.getTitle()), str(c.getID()) + '_crv']) + chld = QtWidgets.QTreeWidgetItem([str(c.getTitle()), str(c.getID()) + '_crv']) item.addChild(chld) treeWidget.expandAll() diff --git a/tools/CurvePlot/src/python/views/CurveTabsView.py b/tools/CurvePlot/src/python/views/CurveTabsView.py index d58feff49..4f7870a2e 100644 --- a/tools/CurvePlot/src/python/views/CurveTabsView.py +++ b/tools/CurvePlot/src/python/views/CurveTabsView.py @@ -17,9 +17,9 @@ # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # -from View import View -from XYView import XYView -from utils import Logger +from .View import View +from .XYView import XYView +from .utils import Logger class CurveTabsView(View): def __init__(self, controller): diff --git a/tools/CurvePlot/src/python/views/CurveView.py b/tools/CurvePlot/src/python/views/CurveView.py index 0a1d50a4b..406e94338 100644 --- a/tools/CurvePlot/src/python/views/CurveView.py +++ b/tools/CurvePlot/src/python/views/CurveView.py @@ -17,8 +17,8 @@ # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # -from View import View -from utils import Logger +from .View import View +from .utils import Logger class CurveView(View): _PICKER_PRECISION = 20 #pts diff --git a/tools/CurvePlot/src/python/views/XYView.py b/tools/CurvePlot/src/python/views/XYView.py index 4714b7ebe..f0ba245ac 100644 --- a/tools/CurvePlot/src/python/views/XYView.py +++ b/tools/CurvePlot/src/python/views/XYView.py @@ -19,16 +19,16 @@ import matplotlib.pyplot as plt import matplotlib.colors as colors -from View import View -from CurveView import CurveView - -from utils import Logger, trQ -from PlotWidget import PlotWidget -from PlotSettings import PlotSettings -from pyqtside import QtGui, QtCore +from pyqtside import QtWidgets, QtCore from pyqtside.QtCore import QObject from matplotlib.figure import Figure -from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg, NavigationToolbar2QT +from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, NavigationToolbar2QT + +from .View import View +from .CurveView import CurveView +from .PlotWidget import PlotWidget +from .PlotSettings import PlotSettings +from .utils import Logger, trQ class EventHandler(QObject): """ Handle the right-click properly so that it only triggers the contextual menu """ @@ -201,7 +201,7 @@ class XYView(View): self._toolbar = self._plotWidget.toolBar self.populateToolbar() - self._popupMenu = QtGui.QMenu() + self._popupMenu = QtWidgets.QMenu() self._popupMenu.addAction(self._actionLegend) # Connect evenement for the graphic scene @@ -227,7 +227,7 @@ class XYView(View): self._panAction.setCheckable(True) self._toolbar.addSeparator() # Actions to change the representation of curves - self._curveActionGroup = QtGui.QActionGroup(self._plotWidget) + self._curveActionGroup = QtWidgets.QActionGroup(self._plotWidget) self._pointsAction = self.createAndAddLocalAction("draw_points.png", trQ("DRAW_POINTS_TXT")) self._pointsAction.setCheckable(True) self._linesAction = self.createAndAddLocalAction("draw_lines.png", trQ("DRAW_LINES_TXT")) @@ -239,7 +239,7 @@ class XYView(View): self._curveActionGroup.setExclusive(True) self._toolbar.addSeparator() # Actions to draw horizontal curves as linear or logarithmic - self._horActionGroup = QtGui.QActionGroup(self._plotWidget) + self._horActionGroup = QtWidgets.QActionGroup(self._plotWidget) self._horLinearAction = self.createAndAddLocalAction("hor_linear.png", trQ("HOR_LINEAR_TXT")) self._horLinearAction.setCheckable(True) self._horLogarithmicAction = self.createAndAddLocalAction("hor_logarithmic.png", trQ("HOR_LOGARITHMIC_TXT")) @@ -250,7 +250,7 @@ class XYView(View): self._horActionGroup.triggered.connect(self.onViewHorizontalMode) self._toolbar.addSeparator() # Actions to draw vertical curves as linear or logarithmic - self._verActionGroup = QtGui.QActionGroup(self._plotWidget) + self._verActionGroup = QtWidgets.QActionGroup(self._plotWidget) self._verLinearAction = self.createAndAddLocalAction("ver_linear.png", trQ("VER_LINEAR_TXT")) self._verLinearAction.setCheckable(True) self._verLogarithmicAction = self.createAndAddLocalAction("ver_logarithmic.png", trQ("VER_LOGARITHMIC_TXT")) @@ -289,12 +289,14 @@ class XYView(View): pass def autoFit(self, check=True, repaint=True): + import numpy as np if self.__repaintOK(): self._mplAxes.relim() xm, xM = self._mplAxes.xaxis.get_data_interval() ym, yM = self._mplAxes.yaxis.get_data_interval() i = yM-ym - self._mplAxes.axis([xm, xM, ym-i*self.AUTOFIT_MARGIN, yM+i*self.AUTOFIT_MARGIN]) + if np.isfinite(xm) and np.isfinite(xM) and np.isfinite(ym) and np.isfinite(yM): + self._mplAxes.axis([xm, xM, ym-i*self.AUTOFIT_MARGIN, yM+i*self.AUTOFIT_MARGIN]) if repaint: self.repaint() @@ -501,7 +503,7 @@ class XYView(View): dlg.colorCurve.setEnabled(True) dlg.markerCurve.setEnabled(True) name = curr_crv.getTitle() - dlg.nameCurve.setText(name) + dlg.setSelectedCurveName(name) view = self._curveViews[curr_crv.getID()] marker = view.getMarker() color = view.getColor() @@ -512,7 +514,7 @@ class XYView(View): else : dlg.colorCurve.setEnabled(False) dlg.markerCurve.setEnabled(False) - dlg.nameCurve.setText("") + dlg.setSelectedCurveName("") view = None if self._legend is None: dlg.showLegendCheckBox.setChecked(False) @@ -561,6 +563,10 @@ class XYView(View): if view: view.setColor(dlg.getRGB()) view.setMarker(self.CURVE_MARKERS[dlg.markerCurve.currentIndex()]) + crvModel = view._model + if dlg.nameCurve.text() != crvModel.getTitle(): + Logger.Debug("XYView : about to cahnge crv title after settings") + view._model.setTitle(dlg.nameCurve.text()) self.showHideLegend(repaint=True) self._mplCanvas.draw() pass @@ -577,6 +583,7 @@ class XYView(View): pass def onCurrentCurveChange(self): + Logger.Debug("XYView::onCurrentCurveChange()") curr_crv2 = self._model.getCurrentCurve() if curr_crv2 != self._currCrv: if self._currCrv is not None: @@ -628,7 +635,7 @@ class XYView(View): if not len(self._curveViews): # Reset color cycle - self._mplAxes.set_color_cycle(None) + self._mplAxes.set_prop_cycle(None) for a in added: self.appendCurve(a) @@ -645,7 +652,8 @@ class XYView(View): self.changeFormatAxis() # Redo auto-fit - self.autoFit(repaint=False) + if len(self._curveViews): + self.autoFit(repaint=False) self.repaint() def onDataChange(self):